summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/bearer/corewlan/qcorewlanengine.mm38
-rw-r--r--src/plugins/imageformats/jpeg/qjpeghandler.cpp6
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp27
-rw-r--r--src/plugins/platforms/android/androidjniinput.h4
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp368
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.h41
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro2
-rw-r--r--src/plugins/platforms/cocoa/main.mm2
-rw-r--r--src/plugins/platforms/cocoa/messages.cpp18
-rw-r--r--src/plugins/platforms/cocoa/messages.h10
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h9
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm86
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h16
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm18
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoaclipboard.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm31
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm20
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm12
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm71
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm62
-rw-r--r--src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm62
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h31
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm35
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm34
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintrospection.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm78
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm124
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm194
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.h36
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm164
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm27
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.h22
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.mm148
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintdevice.mm22
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm18
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemsettings.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm82
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm34
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h10
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm241
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.h4
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.mm14
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac.mm2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h99
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm1914
-rw-r--r--src/plugins/platforms/cocoa/qnsview_complextext.mm315
-rw-r--r--src/plugins/platforms/cocoa/qnsview_dragging.mm302
-rw-r--r--src/plugins/platforms/cocoa/qnsview_drawing.mm223
-rw-r--r--src/plugins/platforms/cocoa/qnsview_gestures.mm169
-rw-r--r--src/plugins/platforms/cocoa/qnsview_keys.mm262
-rw-r--r--src/plugins/platforms/cocoa/qnsview_menus.mm143
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm606
-rw-r--r--src/plugins/platforms/cocoa/qnsview_tablet.mm223
-rw-r--r--src/plugins/platforms/cocoa/qnsview_touch.mm100
-rw-r--r--src/plugins/platforms/cocoa/qnsviewaccessibility.mm10
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm15
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.h14
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm11
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac.mm56
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac_p.h8
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac.mm10
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac_p.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp111
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp5
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h6
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm14
-rw-r--r--src/plugins/platforms/ios/qiosclipboard.mm24
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.h15
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm96
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm15
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm7
-rw-r--r--src/plugins/platforms/ios/qiosmenu.mm32
-rw-r--r--src/plugins/platforms/ios/qiosoptionalplugininterface.h4
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm28
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm85
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.h10
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm42
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h2
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm36
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm6
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.h7
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.mm13
-rw-r--r--src/plugins/platforms/ios/quiview.h15
-rw-r--r--src/plugins/platforms/ios/quiview.mm75
-rw-r--r--src/plugins/platforms/ios/quiview_accessibility.mm7
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp134
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp19
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.h31
-rw-r--r--src/plugins/platforms/winrt/qwinrtcanvas.cpp146
-rw-r--r--src/plugins/platforms/winrt/qwinrtcanvas.h75
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp17
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.h3
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp22
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp106
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h64
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h72
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp182
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h117
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h108
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp160
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h78
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp135
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp88
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h74
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp779
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h124
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp112
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp149
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h80
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp99
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h77
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp167
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h80
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp214
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h78
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp158
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp141
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h75
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp167
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp232
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h83
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp497
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h95
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp104
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h75
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp182
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h83
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp136
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h77
-rw-r--r--src/plugins/platforms/winrt/uiautomation/uiautomation.pri45
-rw-r--r--src/plugins/platforms/winrt/winrt.pro4
-rw-r--r--src/plugins/platforms/xcb/README27
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp77
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h42
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp596
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp24
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp56
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h2
-rw-r--r--src/plugins/platforms/xcb/xcb-static/xcb-static.pro5
-rw-r--r--src/plugins/platforms/xcb/xcb_qpa_lib.pro8
-rw-r--r--src/plugins/printsupport/cups/qcupsprintengine.cpp13
-rw-r--r--src/plugins/printsupport/cups/qcupsprintengine_p.h1
-rw-r--r--src/plugins/printsupport/cups/qppdprintdevice.cpp80
-rw-r--r--src/plugins/printsupport/cups/qppdprintdevice.h2
-rw-r--r--src/plugins/sqldrivers/configure.json2
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm16
-rw-r--r--src/plugins/styles/windowsvista/qwindowsvistastyle.cpp28
-rw-r--r--src/plugins/styles/windowsvista/qwindowsxpstyle.cpp16
170 files changed, 10562 insertions, 3994 deletions
diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm
index 341d3bccf2..c3dd49ff3e 100644
--- a/src/plugins/bearer/corewlan/qcorewlanengine.mm
+++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm
@@ -62,33 +62,29 @@ extern "C" { // Otherwise it won't find CWKeychain* symbols at link time
#include <ifaddrs.h>
@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject <CWEventDelegate>
-{
- NSNotificationCenter *notificationCenter;
- CWWiFiClient *client;
- QCoreWlanEngine *engine;
- NSLock *locker;
-}
-- (void)powerStateDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName;
-- (void)remove;
-- (void)setEngine:(QCoreWlanEngine *)coreEngine;
-- (QCoreWlanEngine *)engine;
-- (void)dealloc;
@property (assign) QCoreWlanEngine* engine;
@end
-@implementation QT_MANGLE_NAMESPACE(QNSListener)
+@implementation QT_MANGLE_NAMESPACE(QNSListener) {
+ NSNotificationCenter *notificationCenter;
+ CWWiFiClient *client;
+ QCoreWlanEngine *engine;
+ NSLock *locker;
+}
-- (id) init
+- (instancetype)init
{
- [locker lock];
- QMacAutoReleasePool pool;
- notificationCenter = [NSNotificationCenter defaultCenter];
- client = [CWWiFiClient sharedWiFiClient];
- client.delegate = self;
- [client startMonitoringEventWithType:CWEventTypePowerDidChange error:nil];
- [locker unlock];
+ if ((self = [super init])) {
+ [locker lock];
+ QMacAutoReleasePool pool;
+ notificationCenter = [NSNotificationCenter defaultCenter];
+ client = [CWWiFiClient sharedWiFiClient];
+ client.delegate = self;
+ [client startMonitoringEventWithType:CWEventTypePowerDidChange error:nil];
+ [locker unlock];
+ }
return self;
}
@@ -300,7 +296,7 @@ void QScanThread::getUserConfigurations()
if(airportPlist != nil) {
NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"];
- NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"];
+ NSArray<NSString *> *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"];
for (NSString *ssidkey in thisSsidarray) {
QString thisSsid = QString::fromNSString(ssidkey);
if(!userProfiles.contains(thisSsid)) {
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
index 1cdc28c077..e52a19703c 100644
--- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp
+++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
@@ -493,10 +493,10 @@ static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QSt
{
const QMap<QString, QString> text = qt_getImageText(image, description);
for (auto it = text.begin(), end = text.end(); it != end; ++it) {
- QByteArray comment = it.key().toLatin1();
+ QByteArray comment = it.key().toUtf8();
if (!comment.isEmpty())
comment += ": ";
- comment += it.value().toLatin1();
+ comment += it.value().toUtf8();
if (comment.length() > 65530)
comment.truncate(65530);
jpeg_write_marker(cinfo, JPEG_COM, (const JOCTET *)comment.constData(), comment.size());
@@ -904,7 +904,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) {
if (marker->marker == JPEG_COM) {
QString key, value;
- QString s = QString::fromLatin1((const char *)marker->data, marker->data_length);
+ QString s = QString::fromUtf8((const char *)marker->data, marker->data_length);
int index = s.indexOf(QLatin1String(": "));
if (index == -1 || s.indexOf(QLatin1Char(' ')) < index) {
key = QLatin1String("Description");
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index dabab553c2..b36222502d 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -124,11 +124,12 @@ namespace QtAndroidInput
return m_softwareKeyboardRect;
}
- void updateHandles(int mode, QPoint cursor, QPoint anchor, bool rtl)
+ void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIZ)V",
- mode, cursor.x(), cursor.y(), anchor.x(),
- anchor.y(), rtl);
+ QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIIIIZ)V",
+ mode, editMenuPos.x(), editMenuPos.y(), editButtons,
+ cursor.x(), cursor.y(),
+ anchor.x(), anchor.y(), rtl);
}
static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
@@ -195,6 +196,20 @@ namespace QtAndroidInput
angleDelta);
}
+ void releaseMouse(int x, int y)
+ {
+ m_ignoreMouseEvents = true;
+ QPoint globalPos(x,y);
+ QWindow *tlw = topLevelWindowAt(globalPos);
+ QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
+
+ // Release left button
+ QWindowSystemInterface::handleMouseEvent(tlw,
+ localPos,
+ globalPos,
+ Qt::MouseButtons(Qt::NoButton));
+ }
+
static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
{
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
@@ -805,8 +820,10 @@ namespace QtAndroidInput
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp) {
inputContext->emitInputPanelVisibleChanged();
- if (!visibility)
+ if (!visibility) {
inputContext->emitKeyboardRectChanged();
+ QMetaObject::invokeMethod(inputContext, "hideSelectionHandles", Qt::QueuedConnection);
+ }
}
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
diff --git a/src/plugins/platforms/android/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h
index c09b426f49..2e2470ae8f 100644
--- a/src/plugins/platforms/android/androidjniinput.h
+++ b/src/plugins/platforms/android/androidjniinput.h
@@ -58,9 +58,11 @@ namespace QtAndroidInput
// Software keyboard support
// cursor/selection handles
- void updateHandles(int handleCount, QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
+ void updateHandles(int handleCount, QPoint editMenuPos = QPoint(), uint32_t editButtons = 0, QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
bool registerNatives(JNIEnv *env);
+
+ void releaseMouse(int x, int y);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index f548a1fa96..ea3e9c1441 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -63,6 +63,29 @@
QT_BEGIN_NAMESPACE
+template <typename T>
+class ScopedValueChangeBack
+{
+public:
+ ScopedValueChangeBack(T &variable, T newValue)
+ : m_oldValue(variable),
+ m_variable(variable)
+ {
+ m_variable = newValue;
+ }
+ inline void setOldValue()
+ {
+ m_variable = m_oldValue;
+ }
+ ~ScopedValueChangeBack()
+ {
+ setOldValue();
+ }
+private:
+ T m_oldValue;
+ T &m_variable;
+};
+
static QAndroidInputContext *m_androidInputContext = 0;
static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt5/android/QtNativeInputConnection";
static char const *const QtExtractedTextClassName = "org/qtproject/qt5/android/QtExtractedText";
@@ -75,6 +98,11 @@ static jfieldID m_selectionStartFieldID = 0;
static jfieldID m_startOffsetFieldID = 0;
static jfieldID m_textFieldID = 0;
+static void runOnQtThread(const std::function<void()> &func)
+{
+ QMetaObject::invokeMethod(m_androidInputContext, "safeCall", Qt::BlockingQueuedConnection, Q_ARG(std::function<void()>, func));
+}
+
static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
{
if (!m_androidInputContext)
@@ -83,10 +111,9 @@ static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ BEGINBATCH");
#endif
-
- return m_androidInputContext->beginBatchEdit();
-
- return JNI_TRUE;
+ jboolean res;
+ runOnQtThread([&res]{res = m_androidInputContext->beginBatchEdit();});
+ return res;
}
static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
@@ -98,9 +125,9 @@ static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
qDebug("@@@ ENDBATCH");
#endif
- return m_androidInputContext->endBatchEdit();
-
- return JNI_TRUE;
+ jboolean res;
+ runOnQtThread([&res]{res = m_androidInputContext->endBatchEdit();});
+ return res;
}
@@ -117,7 +144,9 @@ static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint new
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ COMMIT" << str << newCursorPosition;
#endif
- return m_androidInputContext->commitText(str, newCursorPosition);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->commitText(str, newCursorPosition);});
+ return res;
}
static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint leftLength, jint rightLength)
@@ -128,7 +157,9 @@ static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint le
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ DELETE" << leftLength << rightLength;
#endif
- return m_androidInputContext->deleteSurroundingText(leftLength, rightLength);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->deleteSurroundingText(leftLength, rightLength);});
+ return res;
}
static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
@@ -139,7 +170,9 @@ static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ FINISH");
#endif
- return m_androidInputContext->finishComposingText();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->finishComposingText();});
+ return res;
}
static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes)
@@ -147,7 +180,9 @@ static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes)
if (!m_androidInputContext)
return 0;
- return m_androidInputContext->getCursorCapsMode(reqModes);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->getCursorCapsMode(reqModes);});
+ return res;
}
static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars, int hintMaxLines, jint flags)
@@ -155,8 +190,8 @@ static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars,
if (!m_androidInputContext)
return 0;
- const QAndroidInputContext::ExtractedText &extractedText =
- m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);
+ QAndroidInputContext::ExtractedText extractedText;
+ runOnQtThread([&]{extractedText = m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);});
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ GETEX" << hintMaxChars << hintMaxLines << QString::fromLatin1("0x") + QString::number(flags,16) << extractedText.text << "partOff:" << extractedText.partialStartOffset << extractedText.partialEndOffset << "sel:" << extractedText.selectionStart << extractedText.selectionEnd << "offset:" << extractedText.startOffset;
@@ -181,7 +216,8 @@ static jstring getSelectedText(JNIEnv *env, jobject /*thiz*/, jint flags)
if (!m_androidInputContext)
return 0;
- const QString &text = m_androidInputContext->getSelectedText(flags);
+ QString text;
+ runOnQtThread([&]{text = m_androidInputContext->getSelectedText(flags);});
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ GETSEL" << text;
#endif
@@ -195,7 +231,8 @@ static jstring getTextAfterCursor(JNIEnv *env, jobject /*thiz*/, jint length, ji
if (!m_androidInputContext)
return 0;
- const QString &text = m_androidInputContext->getTextAfterCursor(length, flags);
+ QString text;
+ runOnQtThread([&]{text = m_androidInputContext->getTextAfterCursor(length, flags);});
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ GETA" << length << text;
#endif
@@ -207,7 +244,8 @@ static jstring getTextBeforeCursor(JNIEnv *env, jobject /*thiz*/, jint length, j
if (!m_androidInputContext)
return 0;
- const QString &text = m_androidInputContext->getTextBeforeCursor(length, flags);
+ QString text;
+ runOnQtThread([&]{text = m_androidInputContext->getTextBeforeCursor(length, flags);});
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ GETB" << length << text;
#endif
@@ -227,7 +265,9 @@ static jboolean setComposingText(JNIEnv *env, jobject /*thiz*/, jstring text, ji
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ SET" << str << newCursorPosition;
#endif
- return m_androidInputContext->setComposingText(str, newCursorPosition);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->setComposingText(str, newCursorPosition);});
+ return res;
}
static jboolean setComposingRegion(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint end)
@@ -238,7 +278,9 @@ static jboolean setComposingRegion(JNIEnv */*env*/, jobject /*thiz*/, jint start
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ SETR" << start << end;
#endif
- return m_androidInputContext->setComposingRegion(start, end);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->setComposingRegion(start, end);});
+ return res;
}
@@ -250,7 +292,10 @@ static jboolean setSelection(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ SETSEL" << start << end;
#endif
- return m_androidInputContext->setSelection(start, end);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->setSelection(start, end);});
+ return res;
+
}
static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
@@ -261,7 +306,9 @@ static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ SELALL");
#endif
- return m_androidInputContext->selectAll();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->selectAll();});
+ return res;
}
static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
@@ -272,7 +319,9 @@ static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@");
#endif
- return m_androidInputContext->cut();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->cut();});
+ return res;
}
static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
@@ -283,7 +332,9 @@ static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@");
#endif
- return m_androidInputContext->copy();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->copy();});
+ return res;
}
static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
@@ -294,7 +345,9 @@ static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@");
#endif
- return m_androidInputContext->copyURL();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->copyURL();});
+ return res;
}
static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
@@ -305,7 +358,9 @@ static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ PASTE");
#endif
- return m_androidInputContext->paste();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->paste();});
+ return res;
}
static jboolean updateCursorPosition(JNIEnv */*env*/, jobject /*thiz*/)
@@ -316,7 +371,8 @@ static jboolean updateCursorPosition(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ UPDATECURSORPOS");
#endif
- m_androidInputContext->updateCursorPosition();
+
+ runOnQtThread([&]{m_androidInputContext->updateCursorPosition();});
return true;
}
@@ -364,7 +420,7 @@ static QRect inputItemRectangle()
QAndroidInputContext::QAndroidInputContext()
: QPlatformInputContext(), m_composingTextStart(-1), m_blockUpdateSelection(false),
- m_cursorHandleShown(CursorHandleNotShown), m_batchEditNestingLevel(0), m_focusObject(0)
+ m_handleMode(Hidden), m_batchEditNestingLevel(0), m_focusObject(0)
{
jclass clazz = QJNIEnvironmentPrivate::findClass(QtNativeInputConnectionClassName);
if (Q_UNLIKELY(!clazz)) {
@@ -444,10 +500,17 @@ QAndroidInputContext::QAndroidInputContext()
auto im = qGuiApp->inputMethod();
if (!im->inputItemClipRectangle().contains(im->anchorRectangle()) ||
!im->inputItemClipRectangle().contains(im->cursorRectangle())) {
- m_cursorHandleShown = CursorHandleNotShown;
+ m_handleMode = Hidden;
updateSelectionHandles();
}
});
+ m_hideCursorHandleTimer.setInterval(4000);
+ m_hideCursorHandleTimer.setSingleShot(true);
+ m_hideCursorHandleTimer.setTimerType(Qt::VeryCoarseTimer);
+ connect(&m_hideCursorHandleTimer, &QTimer::timeout, this, [this]{
+ m_handleMode = Hidden;
+ updateSelectionHandles();
+ });
}
QAndroidInputContext::~QAndroidInputContext()
@@ -485,9 +548,9 @@ void QAndroidInputContext::reset()
{
clear();
m_batchEditNestingLevel = 0;
- m_cursorHandleShown = QAndroidInputContext::CursorHandleNotShown;
+ m_handleMode = Hidden;
if (qGuiApp->focusObject()) {
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe(Qt::ImEnabled);
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(Qt::ImEnabled);
if (!query.isNull() && query->value(Qt::ImEnabled).toBool()) {
QtAndroidInput::resetSoftwareKeyboard();
return;
@@ -503,7 +566,7 @@ void QAndroidInputContext::commit()
void QAndroidInputContext::updateCursorPosition()
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) {
const int cursorPos = getAbsoluteCursorPosition(query);
const int composeLength = m_composingText.length();
@@ -541,9 +604,9 @@ void QAndroidInputContext::updateSelectionHandles()
return;
auto im = qGuiApp->inputMethod();
- if (!m_focusObject || (m_cursorHandleShown == CursorHandleNotShown)) {
+ if (!m_focusObject || ((m_handleMode & 0xff) == Hidden)) {
// Hide the handles
- QtAndroidInput::updateHandles(0);
+ QtAndroidInput::updateHandles(Hidden);
return;
}
QWindow *window = qGuiApp->focusWindow();
@@ -551,25 +614,34 @@ void QAndroidInputContext::updateSelectionHandles()
? QHighDpiScaling::factor(window)
: QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen());
- QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled | Qt::ImCurrentSelection);
+ QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled | Qt::ImCurrentSelection | Qt::ImHints | Qt::ImSurroundingText);
QCoreApplication::sendEvent(m_focusObject, &query);
+
int cpos = query.value(Qt::ImCursorPosition).toInt();
int anchor = query.value(Qt::ImAnchorPosition).toInt();
if (cpos == anchor || im->anchorRectangle().isNull()) {
if (!query.value(Qt::ImEnabled).toBool()) {
- QtAndroidInput::updateHandles(0);
+ QtAndroidInput::updateHandles(Hidden);
return;
}
auto curRect = im->cursorRectangle();
QPoint cursorPoint(curRect.center().x(), curRect.bottom());
- QPoint editMenuPoint(curRect.center().x(), curRect.top());
- QtAndroidInput::updateHandles(m_cursorHandleShown, cursorPoint * pixelDensity,
- editMenuPoint * pixelDensity);
+ QPoint editMenuPoint(curRect.x(), curRect.y());
+ m_handleMode &= ShowEditPopup;
+ m_handleMode |= ShowCursor;
+ uint32_t buttons = EditContext::PasteButton;
+ if (!query.value(Qt::ImSurroundingText).toString().isEmpty())
+ buttons |= EditContext::SelectAllButton;
+ QtAndroidInput::updateHandles(m_handleMode, editMenuPoint * pixelDensity, buttons, cursorPoint * pixelDensity);
+ // The VK is hidden, reset the timer
+ if (m_hideCursorHandleTimer.isActive())
+ m_hideCursorHandleTimer.start();
return;
}
+ m_handleMode = ShowSelection | ShowEditPopup ;
auto leftRect = im->cursorRectangle();
auto rightRect = im->anchorRectangle();
if (cpos > anchor)
@@ -577,13 +649,10 @@ void QAndroidInputContext::updateSelectionHandles()
QPoint leftPoint(leftRect.bottomLeft().toPoint() * pixelDensity);
QPoint righPoint(rightRect.bottomRight().toPoint() * pixelDensity);
- QtAndroidInput::updateHandles(CursorHandleShowSelection, leftPoint, righPoint,
+ QPoint editPoint(leftRect.united(rightRect).topLeft().toPoint() * pixelDensity);
+ QtAndroidInput::updateHandles(m_handleMode, editPoint, EditContext::AllButtons, leftPoint, righPoint,
query.value(Qt::ImCurrentSelection).toString().isRightToLeft());
-
- if (m_cursorHandleShown == CursorHandleShowPopup) {
- // make sure the popup does not reappear when the selection menu closes
- m_cursorHandleShown = QAndroidInputContext::CursorHandleNotShown;
- }
+ m_hideCursorHandleTimer.stop();
}
/*
@@ -593,8 +662,10 @@ void QAndroidInputContext::updateSelectionHandles()
*/
void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y)
{
- if (m_batchEditNestingLevel.load() || m_blockUpdateSelection)
+ if (m_batchEditNestingLevel.load() || m_blockUpdateSelection) {
+ qWarning() << "QAndroidInputContext::handleLocationChanged returned";
return;
+ }
finishComposingText();
@@ -668,34 +739,86 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y)
void QAndroidInputContext::touchDown(int x, int y)
{
- if (m_focusObject && inputItemRectangle().contains(x, y) && !m_cursorHandleShown) {
+ if (m_focusObject && inputItemRectangle().contains(x, y)) {
// If the user touch the input rectangle, we can show the cursor handle
- m_cursorHandleShown = QAndroidInputContext::CursorHandleShowNormal;
+ m_handleMode = ShowCursor;
+ // The VK will appear in a moment, stop the timer
+ m_hideCursorHandleTimer.stop();
+ finishComposingText();
updateSelectionHandles();
}
}
void QAndroidInputContext::longPress(int x, int y)
{
+ static bool noHandles = qEnvironmentVariableIntValue("QT_QPA_NO_TEXT_HANDLES");
+ if (noHandles)
+ return;
+
if (m_focusObject && inputItemRectangle().contains(x, y)) {
- // Show the paste menu if there is something to paste.
- m_cursorHandleShown = QAndroidInputContext::CursorHandleShowPopup;
+ finishComposingText();
+
+ // Release left button, otherwise the following events will cancel the menu popup
+ QtAndroidInput::releaseMouse(x, y);
+
+ handleLocationChanged(1, x, y);
+ ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true);
+
+ QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor);
+ QCoreApplication::sendEvent(m_focusObject, &query);
+ int cursor = query.value(Qt::ImCursorPosition).toInt();
+ int anchor = cursor;
+ QString before = query.value(Qt::ImTextBeforeCursor).toString();
+ QString after = query.value(Qt::ImTextAfterCursor).toString();
+ for (const auto &ch : after) {
+ if (!ch.isLetterOrNumber())
+ break;
+ ++anchor;
+ }
+
+ for (auto itch = before.rbegin(); itch != after.rend(); ++itch) {
+ if (!itch->isLetterOrNumber())
+ break;
+ --cursor;
+ }
+ if (cursor == anchor || cursor < 0 || cursor - anchor > 500) {
+ m_handleMode = ShowCursor | ShowEditPopup;
+ updateSelectionHandles();
+ return;
+ }
+ QList<QInputMethodEvent::Attribute> imAttributes;
+ imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, 0, QVariant()));
+ imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, anchor, cursor - anchor, QVariant()));
+ QInputMethodEvent event(QString(), imAttributes);
+ QGuiApplication::sendEvent(m_focusObject, &event);
+
+ m_handleMode = ShowSelection | ShowEditPopup;
updateSelectionHandles();
}
}
void QAndroidInputContext::keyDown()
{
- if (m_cursorHandleShown) {
+ if (m_handleMode) {
// When the user enter text on the keyboard, we hide the cursor handle
- m_cursorHandleShown = QAndroidInputContext::CursorHandleNotShown;
+ m_handleMode = Hidden;
+ updateSelectionHandles();
+ }
+}
+
+void QAndroidInputContext::hideSelectionHandles()
+{
+ if (m_handleMode & ShowSelection) {
+ m_handleMode = Hidden;
updateSelectionHandles();
+ } else {
+ m_hideCursorHandleTimer.start();
}
}
void QAndroidInputContext::update(Qt::InputMethodQueries queries)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe(queries);
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(queries);
if (query.isNull())
return;
#warning TODO extract the needed data from query
@@ -727,7 +850,7 @@ void QAndroidInputContext::showInputPanel()
connect(qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(showInputPanelLater(Qt::ApplicationState)));
return;
}
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return;
@@ -751,6 +874,14 @@ void QAndroidInputContext::showInputPanelLater(Qt::ApplicationState state)
showInputPanel();
}
+void QAndroidInputContext::safeCall(const std::function<void()> &func, Qt::ConnectionType conType)
+{
+ if (qGuiApp->thread() == QThread::currentThread())
+ func();
+ else
+ QMetaObject::invokeMethod(this, "safeCall", conType, Q_ARG(std::function<void()>, func));
+}
+
void QAndroidInputContext::hideInputPanel()
{
QtAndroidInput::hideSoftwareKeyboard();
@@ -809,17 +940,15 @@ jboolean QAndroidInputContext::endBatchEdit()
*/
jboolean QAndroidInputContext::commitText(const QString &text, jint newCursorPosition)
{
- bool updateSelectionWasBlocked = m_blockUpdateSelection;
- m_blockUpdateSelection = true;
-
+ ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true);
QInputMethodEvent event;
event.setCommitString(text);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
clear();
// Qt has now put the cursor at the end of the text, corresponding to newCursorPosition == 1
if (newCursorPosition != 1) {
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (!query.isNull()) {
QList<QInputMethodEvent::Attribute> attributes;
const int localPos = query->value(Qt::ImCursorPosition).toInt();
@@ -831,15 +960,14 @@ jboolean QAndroidInputContext::commitText(const QString &text, jint newCursorPos
newLocalPos, 0));
}
}
- m_blockUpdateSelection = updateSelectionWasBlocked;
-
+ svcb.setOldValue();
updateCursorPosition();
return JNI_TRUE;
}
jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_TRUE;
@@ -853,7 +981,7 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right
QInputMethodEvent event;
event.setCommitString(QString(), -leftLength, leftLength+rightLength);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
clear();
return JNI_TRUE;
@@ -865,7 +993,7 @@ jboolean QAndroidInputContext::finishComposingText()
if (m_composingText.isEmpty())
return JNI_TRUE; // not composing
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_FALSE;
@@ -878,7 +1006,7 @@ jboolean QAndroidInputContext::finishComposingText()
QInputMethodEvent event(QString(), attributes);
event.setCommitString(m_composingText);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
clear();
return JNI_TRUE;
@@ -887,7 +1015,7 @@ jboolean QAndroidInputContext::finishComposingText()
jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/)
{
jint res = 0;
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return res;
@@ -910,7 +1038,7 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex
// updateExtractedText(View, int, ExtractedText) whenever you call
// updateSelection(View, int, int, int, int)." QTBUG-37980
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return m_extractedText;
@@ -955,7 +1083,7 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex
QString QAndroidInputContext::getSelectedText(jint /*flags*/)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return QString();
@@ -965,13 +1093,13 @@ QString QAndroidInputContext::getSelectedText(jint /*flags*/)
QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
{
//### the preedit text could theoretically be after the cursor
- QVariant textAfter = queryFocusObjectThreadSafe(Qt::ImTextAfterCursor, QVariant(length));
+ QVariant textAfter = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, QVariant(length));
if (textAfter.isValid()) {
return textAfter.toString().left(length);
}
//compatibility code for old controls that do not implement the new API
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return QString();
@@ -985,12 +1113,12 @@ QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
{
- QVariant textBefore = queryFocusObjectThreadSafe(Qt::ImTextBeforeCursor, QVariant(length));
+ QVariant textBefore = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, QVariant(length));
if (textBefore.isValid())
return textBefore.toString().rightRef(length) + m_composingText;
//compatibility code for old controls that do not implement the new API
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return QString();
@@ -1016,7 +1144,7 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_FALSE;
@@ -1038,7 +1166,7 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
QVariant(underlined)));
QInputMethodEvent event(m_composingText, attributes);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
QMetaObject::invokeMethod(this, "keyDown");
@@ -1062,7 +1190,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
if (wasComposing)
finishComposingText();
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_FALSE;
@@ -1083,8 +1211,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
int localStart = start - blockPosition; // Qt uses position inside block
int currentCursor = wasComposing ? m_composingCursor : blockPosition + localPos;
- bool updateSelectionWasBlocked = m_blockUpdateSelection;
- m_blockUpdateSelection = true;
+ ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true);
QString text = query->value(Qt::ImSurroundingText).toString();
@@ -1108,12 +1235,10 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
QInputMethodEvent event(m_composingText, attributes);
event.setCommitString(QString(), relativeStart, length);
- sendInputMethodEventThreadSafe(&event);
-
- m_blockUpdateSelection = updateSelectionWasBlocked;
+ sendInputMethodEvent(&event);
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- QSharedPointer<QInputMethodQueryEvent> query2 = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query2 = focusObjectInputMethodQuery();
if (!query2.isNull()) {
qDebug() << "Setting. Prev local cpos:" << localPos << "block pos:" <<blockPosition << "comp.start:" << m_composingTextStart << "rel.start:" << relativeStart << "len:" << length << "cpos attr:" << localPos - localStart;
qDebug() << "New cursor pos" << getAbsoluteCursorPosition(query2);
@@ -1125,7 +1250,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
jboolean QAndroidInputContext::setSelection(jint start, jint end)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_FALSE;
@@ -1156,26 +1281,31 @@ jboolean QAndroidInputContext::setSelection(jint start, jint end)
end - start));
}
QInputMethodEvent event(m_composingText, attributes);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
updateCursorPosition();
return JNI_TRUE;
}
jboolean QAndroidInputContext::selectAll()
{
+ finishComposingText();
+ m_handleMode = ShowCursor;
sendShortcut(QKeySequence::SelectAll);
return JNI_TRUE;
}
jboolean QAndroidInputContext::cut()
{
- m_cursorHandleShown = CursorHandleNotShown;
+ finishComposingText();
+ m_handleMode = ShowCursor;
sendShortcut(QKeySequence::Cut);
return JNI_TRUE;
}
jboolean QAndroidInputContext::copy()
{
+ finishComposingText();
+ m_handleMode = ShowCursor;
sendShortcut(QKeySequence::Copy);
return JNI_TRUE;
}
@@ -1189,7 +1319,7 @@ jboolean QAndroidInputContext::copyURL()
jboolean QAndroidInputContext::paste()
{
finishComposingText();
- m_cursorHandleShown = CursorHandleNotShown;
+ m_handleMode = ShowCursor;
sendShortcut(QKeySequence::Paste);
return JNI_TRUE;
}
@@ -1205,65 +1335,24 @@ void QAndroidInputContext::sendShortcut(const QKeySequence &sequence)
}
}
-Q_INVOKABLE QVariant QAndroidInputContext::queryFocusObjectUnsafe(Qt::InputMethodQuery query, QVariant argument)
-{
- return QInputMethod::queryFocusObject(query, argument);
-}
-
-QVariant QAndroidInputContext::queryFocusObjectThreadSafe(Qt::InputMethodQuery query, QVariant argument)
-{
- QVariant retval;
+QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQuery(Qt::InputMethodQueries queries) {
if (!qGuiApp)
- return retval;
- const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
- if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
- return retval;
- AndroidDeadlockProtector protector;
- if (!inMainThread && !protector.acquire())
- return retval;
-
- QMetaObject::invokeMethod(this, "queryFocusObjectUnsafe",
- inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(QVariant, retval),
- Q_ARG(Qt::InputMethodQuery, query),
- Q_ARG(QVariant, argument));
+ return {};
- return retval;
-}
-
-QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQueryThreadSafe(Qt::InputMethodQueries queries) {
- QSharedPointer<QInputMethodQueryEvent> retval;
- if (!qGuiApp)
- return QSharedPointer<QInputMethodQueryEvent>();
- const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
- if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
- return QSharedPointer<QInputMethodQueryEvent>();
- AndroidDeadlockProtector protector;
- if (!inMainThread && !protector.acquire())
- return QSharedPointer<QInputMethodQueryEvent>();
-
- QInputMethodQueryEvent *queryEvent = 0;
- QMetaObject::invokeMethod(this, "focusObjectInputMethodQueryUnsafe",
- inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(QInputMethodQueryEvent*, queryEvent),
- Q_ARG(Qt::InputMethodQueries, queries));
-
- return QSharedPointer<QInputMethodQueryEvent>(queryEvent);
-}
-
-QInputMethodQueryEvent *QAndroidInputContext::focusObjectInputMethodQueryUnsafe(Qt::InputMethodQueries queries)
-{
QObject *focusObject = qGuiApp->focusObject();
if (!focusObject)
- return 0;
+ return {};
QInputMethodQueryEvent *ret = new QInputMethodQueryEvent(queries);
QCoreApplication::sendEvent(focusObject, ret);
- return ret;
+ return QSharedPointer<QInputMethodQueryEvent>(ret);
}
-void QAndroidInputContext::sendInputMethodEventUnsafe(QInputMethodEvent *event)
+void QAndroidInputContext::sendInputMethodEvent(QInputMethodEvent *event)
{
+ if (!qGuiApp)
+ return;
+
QObject *focusObject = qGuiApp->focusObject();
if (!focusObject)
return;
@@ -1271,19 +1360,4 @@ void QAndroidInputContext::sendInputMethodEventUnsafe(QInputMethodEvent *event)
QCoreApplication::sendEvent(focusObject, event);
}
-void QAndroidInputContext::sendInputMethodEventThreadSafe(QInputMethodEvent *event)
-{
- if (!qGuiApp)
- return;
- const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
- if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
- return;
- AndroidDeadlockProtector protector;
- if (!inMainThread && !protector.acquire())
- return;
- QMetaObject::invokeMethod(this, "sendInputMethodEventUnsafe",
- inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
- Q_ARG(QInputMethodEvent*, event));
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h
index e7692bf720..bd3edb30f0 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.h
+++ b/src/plugins/platforms/android/qandroidinputcontext.h
@@ -42,8 +42,10 @@
#define ANDROIDINPUTCONTEXT_H
#include <qpa/qplatforminputcontext.h>
+#include <functional>
#include <jni.h>
#include <qevent.h>
+#include <QTimer>
QT_BEGIN_NAMESPACE
@@ -58,6 +60,22 @@ class QAndroidInputContext: public QPlatformInputContext
};
public:
+ enum EditContext : uint32_t {
+ CutButton = 1 << 0,
+ CopyButton = 1 << 1,
+ PasteButton = 1 << 2,
+ SelectAllButton = 1 << 3,
+ AllButtons = CutButton | CopyButton | PasteButton | SelectAllButton
+ };
+
+ enum HandleMode {
+ Hidden = 0,
+ ShowCursor = 1,
+ ShowSelection = 2,
+ ShowEditPopup = 0x100
+ };
+ Q_DECLARE_FLAGS(HandleModes, HandleMode)
+
struct ExtractedText
{
ExtractedText() { clear(); }
@@ -118,25 +136,21 @@ public:
jboolean paste();
public slots:
+ void safeCall(const std::function<void()> &func, Qt::ConnectionType conType = Qt::BlockingQueuedConnection);
void updateCursorPosition();
void updateSelectionHandles();
void handleLocationChanged(int handleId, int x, int y);
void touchDown(int x, int y);
void longPress(int x, int y);
void keyDown();
+ void hideSelectionHandles();
private slots:
void showInputPanelLater(Qt::ApplicationState);
private:
- void sendInputMethodEventThreadSafe(QInputMethodEvent *event);
- Q_INVOKABLE void sendInputMethodEventUnsafe(QInputMethodEvent *event);
-
- QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQueryThreadSafe(Qt::InputMethodQueries queries = Qt::ImQueryAll);
- Q_INVOKABLE QInputMethodQueryEvent *focusObjectInputMethodQueryUnsafe(Qt::InputMethodQueries queries);
-
- Q_INVOKABLE QVariant queryFocusObjectUnsafe(Qt::InputMethodQuery query, QVariant argument);
- QVariant queryFocusObjectThreadSafe(Qt::InputMethodQuery query, QVariant argument);
+ void sendInputMethodEvent(QInputMethodEvent *event);
+ QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQuery(Qt::InputMethodQueries queries = Qt::ImQueryAll);
private:
ExtractedText m_extractedText;
@@ -145,17 +159,12 @@ private:
int m_composingCursor;
QMetaObject::Connection m_updateCursorPosConnection;
bool m_blockUpdateSelection;
- enum CursorHandleShowMode {
- CursorHandleNotShown,
- CursorHandleShowNormal = 1,
- CursorHandleShowSelection = 2,
- CursorHandleShowPopup = 3
- };
- CursorHandleShowMode m_cursorHandleShown;
+ HandleModes m_handleMode;
QAtomicInt m_batchEditNestingLevel;
QObject *m_focusObject;
+ QTimer m_hideCursorHandleTimer;
};
-
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAndroidInputContext::HandleModes)
QT_END_NAMESPACE
#endif // ANDROIDINPUTCONTEXT_H
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index 2694cb3607..072012dee1 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -78,7 +78,7 @@ qtConfig(opengl.*) {
RESOURCES += qcocoaresources.qrc
-LIBS += -framework AppKit -framework Carbon -framework IOKit -framework QuartzCore -lcups
+LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework Metal -lcups
QT += \
core-private gui-private \
diff --git a/src/plugins/platforms/cocoa/main.mm b/src/plugins/platforms/cocoa/main.mm
index f9bfdc7dc7..89ecdf46f9 100644
--- a/src/plugins/platforms/cocoa/main.mm
+++ b/src/plugins/platforms/cocoa/main.mm
@@ -60,7 +60,7 @@ QPlatformIntegration * QCocoaIntegrationPlugin::create(const QString& system, co
if (system.compare(QLatin1String("cocoa"), Qt::CaseInsensitive) == 0)
return new QCocoaIntegration(paramList);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp
index 8eea1e654e..06e3dd454e 100644
--- a/src/plugins/platforms/cocoa/messages.cpp
+++ b/src/plugins/platforms/cocoa/messages.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -39,7 +39,8 @@
#include "messages.h"
-#include <QCoreApplication>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qregularexpression.h>
// Translatable messages should go into this .cpp file for them to be picked up by lupdate.
@@ -52,13 +53,13 @@ QString msgAboutQt()
static const char *application_menu_strings[] =
{
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1"),
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."),
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"),
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"),
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"),
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1"),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1")
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1")
};
QString qt_mac_applicationmenu_string(int type)
@@ -77,8 +78,13 @@ QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption)
QString captionNoAmpersand(caption);
captionNoAmpersand.remove(QLatin1Char('&'));
const QString aboutString = QCoreApplication::translate("QCocoaMenuItem", "About");
- if (captionNoAmpersand.startsWith(aboutString, Qt::CaseInsensitive) || caption.endsWith(aboutString, Qt::CaseInsensitive))
+ if (captionNoAmpersand.startsWith(aboutString, Qt::CaseInsensitive)
+ || captionNoAmpersand.endsWith(aboutString, Qt::CaseInsensitive)) {
+ static const QRegularExpression qtRegExp(QLatin1String("qt$"), QRegularExpression::CaseInsensitiveOption);
+ if (captionNoAmpersand.contains(qtRegExp))
+ return QPlatformMenuItem::AboutQtRole;
return QPlatformMenuItem::AboutRole;
+ }
if (captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Config"), Qt::CaseInsensitive)
|| captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Preference"), Qt::CaseInsensitive)
|| captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Options"), Qt::CaseInsensitive)
diff --git a/src/plugins/platforms/cocoa/messages.h b/src/plugins/platforms/cocoa/messages.h
index e41898fe59..3a9eaf604e 100644
--- a/src/plugins/platforms/cocoa/messages.h
+++ b/src/plugins/platforms/cocoa/messages.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -46,13 +46,13 @@
QT_BEGIN_NAMESPACE
enum {
- ServicesAppMenuItem = 0,
+ AboutAppMenuItem = 0,
+ PreferencesAppMenuItem,
+ ServicesAppMenuItem,
HideAppMenuItem,
HideOthersAppMenuItem,
ShowAllAppMenuItem,
- PreferencesAppMenuItem,
- QuitAppMenuItem,
- AboutAppMenuItem
+ QuitAppMenuItem
};
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
index e456364555..457c158ddc 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
@@ -46,6 +46,8 @@
#ifndef QT_NO_ACCESSIBILITY
+@class QT_MANGLE_NAMESPACE(QMacAccessibilityElement);
+
QT_BEGIN_NAMESPACE
class QCocoaAccessibility : public QPlatformAccessibility
@@ -82,9 +84,8 @@ namespace QCocoaAccessible {
NSString *macRole(QAccessibleInterface *interface);
NSString *macSubrole(QAccessibleInterface *interface);
bool shouldBeIgnored(QAccessibleInterface *interface);
-NSArray *unignoredChildren(QAccessibleInterface *interface);
+NSArray<QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *> *unignoredChildren(QAccessibleInterface *interface);
NSString *getTranslatedAction(const QString &qtAction);
-NSMutableArray *createTranslatedActionsList(const QStringList &qtActions);
QString translateAction(NSString *nsAction, QAccessibleInterface *interface);
bool hasValueAttribute(QAccessibleInterface *interface);
id getValueAttribute(QAccessibleInterface *interface);
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 654e6210c8..368cf56c80 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -256,12 +256,12 @@ bool shouldBeIgnored(QAccessibleInterface *interface)
return false;
}
-NSArray *unignoredChildren(QAccessibleInterface *interface)
+NSArray<QMacAccessibilityElement *> *unignoredChildren(QAccessibleInterface *interface)
{
int numKids = interface->childCount();
// qDebug() << "Children for: " << axid << iface << " are: " << numKids;
- NSMutableArray *kids = [NSMutableArray arrayWithCapacity:numKids];
+ NSMutableArray<QMacAccessibilityElement *> *kids = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:numKids];
for (int i = 0; i < numKids; ++i) {
QAccessibleInterface *child = interface->child(i);
if (!child || !child->isValid() || child->state().invalid || child->state().invisible)
@@ -310,7 +310,7 @@ NSString *getTranslatedAction(const QString &qtAction)
// NSAccessibilityCancelAction;
// NSAccessibilityDeleteAction;
- return 0;
+ return nil;
}
@@ -386,7 +386,7 @@ id getValueAttribute(QAccessibleInterface *interface)
}
if (interface->state().checkable) {
- return [NSNumber numberWithInt: (interface->state().checked ? 1 : 0)];
+ return interface->state().checked ? @(1) : @(0);
}
return nil;
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
index 07f3f3a99e..914aaa2b1b 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
@@ -52,13 +52,10 @@
@class QT_MANGLE_NAMESPACE(QMacAccessibilityElement);
-@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject {
- NSString *role;
- QAccessible::Id axid;
-}
+@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject
-- (id)initWithId:(QAccessible::Id)anId;
-+ (QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *)elementWithId:(QAccessible::Id)anId;
+- (instancetype)initWithId:(QAccessible::Id)anId;
++ (instancetype)elementWithId:(QAccessible::Id)anId;
@end
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index df2336d08b..03dc895ffb 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -99,9 +99,12 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
*end = curEnd;
}
-@implementation QMacAccessibilityElement
+@implementation QMacAccessibilityElement {
+ NSString *role;
+ QAccessible::Id axid;
+}
-- (id)initWithId:(QAccessible::Id)anId
+- (instancetype)initWithId:(QAccessible::Id)anId
{
Q_ASSERT((int)anId < 0);
self = [super init];
@@ -115,7 +118,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return self;
}
-+ (id)elementWithId:(QAccessible::Id)anId
++ (instancetype)elementWithId:(QAccessible::Id)anId
{
Q_ASSERT(anId);
if (!anId)
@@ -168,22 +171,15 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
{
QStringRef textBefore = QStringRef(&text, 0, index);
int newlines = textBefore.count(QLatin1Char('\n'));
- return [NSNumber numberWithInt: newlines];
+ return @(newlines);
}
- (BOOL) accessibilityNotifiesWhenDestroyed {
return YES;
}
-- (NSArray *)accessibilityAttributeNames {
- static NSArray *defaultAttributes = nil;
-
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return defaultAttributes;
-
- if (defaultAttributes == nil) {
- defaultAttributes = [[NSArray alloc] initWithObjects:
+- (NSArray<NSString *> *)accessibilityAttributeNames {
+ static NSArray<NSString *> *defaultAttributes = [@[
NSAccessibilityRoleAttribute,
NSAccessibilityRoleDescriptionAttribute,
NSAccessibilitySubroleAttribute,
@@ -196,35 +192,36 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
NSAccessibilitySizeAttribute,
NSAccessibilityTitleAttribute,
NSAccessibilityDescriptionAttribute,
- NSAccessibilityEnabledAttribute,
- nil];
- }
+ NSAccessibilityEnabledAttribute
+ ] retain];
+
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return defaultAttributes;
- NSMutableArray *attributes = [[NSMutableArray alloc] initWithCapacity : [defaultAttributes count]];
- [attributes addObjectsFromArray : defaultAttributes];
+ NSMutableArray<NSString *> *attributes = [[NSMutableArray<NSString *> alloc] initWithCapacity:defaultAttributes.count];
+ [attributes addObjectsFromArray:defaultAttributes];
if (QCocoaAccessible::hasValueAttribute(iface)) {
- [attributes addObject : NSAccessibilityValueAttribute];
+ [attributes addObject:NSAccessibilityValueAttribute];
}
if (iface->textInterface()) {
- [attributes addObjectsFromArray: [[NSArray alloc] initWithObjects:
+ [attributes addObjectsFromArray:@[
NSAccessibilityNumberOfCharactersAttribute,
NSAccessibilitySelectedTextAttribute,
NSAccessibilitySelectedTextRangeAttribute,
NSAccessibilityVisibleCharacterRangeAttribute,
- NSAccessibilityInsertionPointLineNumberAttribute,
- nil
+ NSAccessibilityInsertionPointLineNumberAttribute
]];
// TODO: multi-selection: NSAccessibilitySelectedTextRangesAttribute,
}
if (iface->valueInterface()) {
- [attributes addObjectsFromArray: [[NSArray alloc] initWithObjects:
+ [attributes addObjectsFromArray:@[
NSAccessibilityMinValueAttribute,
- NSAccessibilityMaxValueAttribute,
- nil
+ NSAccessibilityMaxValueAttribute
]];
}
@@ -261,13 +258,13 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
- (id) minValueAttribute:(QAccessibleInterface*)iface {
if (QAccessibleValueInterface *val = iface->valueInterface())
- return [NSNumber numberWithDouble: val->minimumValue().toDouble()];
+ return @(val->minimumValue().toDouble());
return nil;
}
- (id) maxValueAttribute:(QAccessibleInterface*)iface {
if (QAccessibleValueInterface *val = iface->valueInterface())
- return [NSNumber numberWithDouble: val->maximumValue().toDouble()];
+ return @(val->maximumValue().toDouble());
return nil;
}
@@ -289,7 +286,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
} else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
// Just check if the app thinks we're focused.
id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute];
- return [NSNumber numberWithBool:[focusedElement isEqual:self]];
+ return @([focusedElement isEqual:self]);
} else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
return NSAccessibilityUnignoredAncestor([self parentElement]);
} else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) {
@@ -312,7 +309,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
} else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
return iface->text(QAccessible::Description).toNSString();
} else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) {
- return [NSNumber numberWithBool:!iface->state().disabled];
+ return @(!iface->state().disabled);
} else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
// VoiceOver asks for the value attribute for all elements. Return nil
// if we don't want the element to have a value attribute.
@@ -323,7 +320,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
} else if ([attribute isEqualToString:NSAccessibilityNumberOfCharactersAttribute]) {
if (QAccessibleTextInterface *text = iface->textInterface())
- return [NSNumber numberWithInt: text->characterCount()];
+ return @(text->characterCount());
return nil;
} else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
if (QAccessibleTextInterface *text = iface->textInterface()) {
@@ -357,7 +354,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
int position = text->cursorPosition();
convertLineOffset(text, &line, &position);
}
- return [NSNumber numberWithInt: line];
+ return @(line);
}
return nil;
} else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) {
@@ -378,18 +375,17 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
if (iface->textInterface()) {
- return [[NSArray alloc] initWithObjects:
- NSAccessibilityStringForRangeParameterizedAttribute,
- NSAccessibilityLineForIndexParameterizedAttribute,
- NSAccessibilityRangeForLineParameterizedAttribute,
- NSAccessibilityRangeForPositionParameterizedAttribute,
-// NSAccessibilityRangeForIndexParameterizedAttribute,
- NSAccessibilityBoundsForRangeParameterizedAttribute,
-// NSAccessibilityRTFForRangeParameterizedAttribute,
- NSAccessibilityStyleRangeForIndexParameterizedAttribute,
- NSAccessibilityAttributedStringForRangeParameterizedAttribute,
- nil
- ];
+ return @[
+ NSAccessibilityStringForRangeParameterizedAttribute,
+ NSAccessibilityLineForIndexParameterizedAttribute,
+ NSAccessibilityRangeForLineParameterizedAttribute,
+ NSAccessibilityRangeForPositionParameterizedAttribute,
+// NSAccessibilityRangeForIndexParameterizedAttribute,
+ NSAccessibilityBoundsForRangeParameterizedAttribute,
+// NSAccessibilityRTFForRangeParameterizedAttribute,
+ NSAccessibilityStyleRangeForIndexParameterizedAttribute,
+ NSAccessibilityAttributedStringForRangeParameterizedAttribute
+ ];
}
return nil;
@@ -416,7 +412,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return nil;
int line = -1;
convertLineOffset(iface->textInterface(), &line, &index);
- return [NSNumber numberWithInt:line];
+ return @(line);
}
if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) {
int line = [parameter intValue];
@@ -573,7 +569,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return NSAccessibilityUnignoredAncestor(self);
// find the deepest child at the point
- QAccessibleInterface *childOfChildInterface = 0;
+ QAccessibleInterface *childOfChildInterface = nullptr;
do {
childOfChildInterface = childInterface->childAt(screenPoint.x(), screenPoint.y());
if (childOfChildInterface && childOfChildInterface->isValid())
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h
index 66a92686bc..15530d8281 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.h
@@ -89,8 +89,7 @@
#import <AppKit/AppKit.h>
-@interface QT_MANGLE_NAMESPACE(QNSApplication) : NSApplication {
-}
+@interface QT_MANGLE_NAMESPACE(QNSApplication) : NSApplication
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSApplication);
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm
index d0f27795b6..11f3bd0384 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm
@@ -113,7 +113,7 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE
static bool qt_filterEvent(NSEvent *event)
{
if (qApp && qApp->eventDispatcher()->
- filterNativeEvent(q_macLocalEventType, static_cast<void*>(event), 0))
+ filterNativeEvent(q_macLocalEventType, static_cast<void*>(event), nullptr))
return true;
if ([event type] == NSApplicationDefined) {
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
index 59c71017e3..3073cb6b44 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
@@ -92,18 +92,12 @@
@class QT_MANGLE_NAMESPACE(QCocoaMenuLoader);
-@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) : NSObject <NSApplicationDelegate> {
- bool startedQuit;
- NSMenu *dockMenu;
- NSObject <NSApplicationDelegate> *reflectionDelegate;
- bool inLaunch;
-}
-+ (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate;
+@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) : NSObject <NSApplicationDelegate>
++ (instancetype)sharedDelegate;
- (void)setDockMenu:(NSMenu *)newMenu;
-- (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate;
-- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
-- (void) removeAppleEventHandlers;
-- (bool) inLaunch;
+- (void)setReflectionDelegate:(NSObject<NSApplicationDelegate> *)oldDelegate;
+- (void)removeAppleEventHandlers;
+- (bool)inLaunch;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate);
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index a94e0dc517..53407d8b62 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -73,7 +73,6 @@
#import "qcocoaapplicationdelegate.h"
-#import "qnswindowdelegate.h"
#import "qcocoamenuloader.h"
#include "qcocoaintegration.h"
#include <qevent.h>
@@ -86,7 +85,12 @@
QT_USE_NAMESPACE
-@implementation QCocoaApplicationDelegate
+@implementation QCocoaApplicationDelegate {
+ bool startedQuit;
+ NSMenu *dockMenu;
+ NSObject <NSApplicationDelegate> *reflectionDelegate;
+ bool inLaunch;
+}
+ (instancetype)sharedDelegate
{
@@ -102,7 +106,7 @@ QT_USE_NAMESPACE
return shared;
}
-- (id)init
+- (instancetype)init
{
self = [super init];
if (self) {
@@ -151,7 +155,7 @@ QT_USE_NAMESPACE
return [[dockMenu retain] autorelease];
}
-- (BOOL) canQuit
+- (BOOL)canQuit
{
[[NSApp mainMenu] cancelTracking];
@@ -219,7 +223,7 @@ QT_USE_NAMESPACE
return NSTerminateCancel;
}
-- (void) applicationWillFinishLaunching:(NSNotification *)notification
+- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
Q_UNUSED(notification);
@@ -249,14 +253,14 @@ QT_USE_NAMESPACE
}
// called by QCocoaIntegration's destructor before resetting the application delegate to nil
-- (void) removeAppleEventHandlers
+- (void)removeAppleEventHandlers
{
NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
[eventManager removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEQuitApplication];
[eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
}
-- (bool) inLaunch
+- (bool)inLaunch
{
return inLaunch;
}
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 091453785e..5eb45be04a 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -44,7 +44,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcCocoaBackingStore, "qt.qpa.cocoa.backingstore");
+Q_LOGGING_CATEGORY(lcQpaBackingStore, "qt.qpa.backingstore");
QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
: QRasterBackingStore(window)
@@ -101,13 +101,13 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion &region, const QPo
QNSView *topLevelView = qnsview_cast(static_cast<QCocoaWindow *>(topLevelWindow->handle())->view());
QNSView *view = qnsview_cast(static_cast<QCocoaWindow *>(window->handle())->view());
- if (lcCocoaBackingStore().isDebugEnabled()) {
+ if (lcQpaBackingStore().isDebugEnabled()) {
QString targetViewDescription;
if (view != topLevelView) {
QDebug targetDebug(&targetViewDescription);
targetDebug << "onto" << topLevelView << "at" << offset;
}
- qCDebug(lcCocoaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription);
+ qCDebug(lcQpaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription);
}
// Prevent potentially costly color conversion by assigning the display color space
diff --git a/src/plugins/platforms/cocoa/qcocoaclipboard.mm b/src/plugins/platforms/cocoa/qcocoaclipboard.mm
index b4745900dc..a35c153084 100644
--- a/src/plugins/platforms/cocoa/qcocoaclipboard.mm
+++ b/src/plugins/platforms/cocoa/qcocoaclipboard.mm
@@ -56,13 +56,13 @@ QMimeData *QCocoaClipboard::mimeData(QClipboard::Mode mode)
pasteBoard->sync();
return pasteBoard->mimeData();
}
- return 0;
+ return nullptr;
}
void QCocoaClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
{
if (QMacPasteboard *pasteBoard = pasteboardForMode(mode)) {
- if (data == 0) {
+ if (!data) {
pasteBoard->clear();
}
@@ -90,7 +90,7 @@ QMacPasteboard *QCocoaClipboard::pasteboardForMode(QClipboard::Mode mode) const
else if (mode == QClipboard::FindBuffer)
return m_find.data();
else
- return 0;
+ return nullptr;
}
void QCocoaClipboard::handleApplicationStateChanged(Qt::ApplicationState state)
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
index aa6124507d..d7850b1481 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
@@ -50,7 +50,14 @@
QT_USE_NAMESPACE
@interface QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) : NSObject<NSWindowDelegate, QNSPanelDelegate>
-{
+- (void)restoreOriginalContentView;
+- (void)updateQtColor;
+- (void)finishOffWithCode:(NSInteger)code;
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
+
+@implementation QNSColorPanelDelegate {
@public
NSColorPanel *mColorPanel;
QCocoaColorDialogHelper *mHelper;
@@ -61,22 +68,14 @@ QT_USE_NAMESPACE
BOOL mDialogIsExecuting;
BOOL mResultSet;
BOOL mClosingDueToKnownButton;
-};
-- (void)restoreOriginalContentView;
-- (void)updateQtColor;
-- (void)finishOffWithCode:(NSInteger)code;
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
-
-@implementation QNSColorPanelDelegate
+}
-- (id)init
+- (instancetype)init
{
self = [super init];
mColorPanel = [NSColorPanel sharedColorPanel];
- mHelper = 0;
- mStolenContentView = 0;
+ mHelper = nullptr;
+ mStolenContentView = nil;
mPanelButtons = nil;
mResultCode = NSModalResponseCancel;
mDialogIsExecuting = false;
@@ -116,9 +115,9 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
[self restoreOriginalContentView];
} else if (!mStolenContentView) {
// steal the color panel's contents view
- mStolenContentView = [mColorPanel contentView];
+ mStolenContentView = mColorPanel.contentView;
[mStolenContentView retain];
- [mColorPanel setContentView:0];
+ mColorPanel.contentView = nil;
// create a new content view and add the stolen one as a subview
mPanelButtons = [[QNSPanelContentsWrapper alloc] initWithPanelDelegate:self];
@@ -310,7 +309,7 @@ public:
void cleanup(QCocoaColorDialogHelper *helper)
{
if (mDelegate->mHelper == helper)
- mDelegate->mHelper = 0;
+ mDelegate->mHelper = nullptr;
}
bool exec()
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index 8c98dc69f7..87a57c78c8 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -80,15 +80,15 @@ void QCocoaCursor::setPos(const QPoint &position)
pos.x = position.x();
pos.y = position.y();
- CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft);
+ CGEventRef e = CGEventCreateMouseEvent(nullptr, kCGEventMouseMoved, pos, kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
}
NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
{
- if (cursor == nullptr)
- return 0;
+ if (!cursor)
+ return nil;
const Qt::CursorShape newShape = cursor->shape();
NSCursor *cocoaCursor;
@@ -138,11 +138,11 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
cocoaCursor = m_cursors.value(newShape);
if (cocoaCursor && cursor->shape() == Qt::BitmapCursor) {
[cocoaCursor release];
- cocoaCursor = 0;
+ cocoaCursor = nil;
}
- if (cocoaCursor == 0) {
+ if (!cocoaCursor) {
cocoaCursor = createCursorData(cursor);
- if (cocoaCursor == 0)
+ if (!cocoaCursor)
return [NSCursor arrowCursor];
m_cursors.insert(newShape, cocoaCursor);
@@ -211,8 +211,8 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
0x07, 0xf0, 0x0f, 0xf8, 0x0f, 0xf8, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0 };
#endif
- const uchar *cursorData = 0;
- const uchar *cursorMaskData = 0;
+ const uchar *cursorData = nullptr;
+ const uchar *cursorMaskData = nullptr;
QPoint hotspot = cursor->hotSpot();
switch (cursor->shape()) {
@@ -269,7 +269,7 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
#endif
default:
qWarning("Qt: QCursor::update: Invalid cursor shape %d", cursor->shape());
- return 0;
+ return nil;
}
// Create an NSCursor from image data if this a self-provided cursor.
@@ -279,7 +279,7 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
return (createCursorFromBitmap(&bitmap, &mask, hotspot));
}
- return 0; // should not happen, all cases covered above
+ return nil; // should not happen, all cases covered above
}
NSCursor *QCocoaCursor::createCursorFromBitmap(const QBitmap *bitmap, const QBitmap *mask, const QPoint hotspot)
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index e1f36b47a1..09433194a6 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -50,10 +50,10 @@ QT_BEGIN_NAMESPACE
static const int dragImageMaxChars = 26;
QCocoaDrag::QCocoaDrag() :
- m_drag(0)
+ m_drag(nullptr)
{
- m_lastEvent = 0;
- m_lastView = 0;
+ m_lastEvent = nil;
+ m_lastView = nil;
}
QCocoaDrag::~QCocoaDrag()
@@ -73,7 +73,7 @@ QMimeData *QCocoaDrag::dragMimeData()
if (m_drag)
return m_drag->mimeData();
- return 0;
+ return nullptr;
}
Qt::DropAction QCocoaDrag::defaultAction(Qt::DropActions possibleActions,
@@ -140,7 +140,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
NSPoint event_location = [m_lastEvent locationInWindow];
NSWindow *theWindow = [m_lastEvent window];
- Q_ASSERT(theWindow != nil);
+ Q_ASSERT(theWindow);
event_location.x -= hotSpot.x();
CGFloat flippedY = pmDeviceIndependentSize.height() - hotSpot.y();
event_location.y -= flippedY;
@@ -157,7 +157,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
[nsimage release];
- m_drag = 0;
+ m_drag = nullptr;
return m_executed_drop_action;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index 2ffc1395ba..6d62447f33 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -110,8 +110,8 @@ class QCocoaEventDispatcher : public QAbstractEventDispatcher
Q_DECLARE_PRIVATE(QCocoaEventDispatcher)
public:
- QCocoaEventDispatcher(QAbstractEventDispatcherPrivate &priv, QObject *parent = 0);
- explicit QCocoaEventDispatcher(QObject *parent = 0);
+ QCocoaEventDispatcher(QAbstractEventDispatcherPrivate &priv, QObject *parent = nullptr);
+ explicit QCocoaEventDispatcher(QObject *parent = nullptr);
~QCocoaEventDispatcher();
bool processEvents(QEventLoop::ProcessEventsFlags flags);
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index bf9ba4eccf..611853642a 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -129,11 +129,11 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
{
if (timerInfoList.isEmpty()) {
// no active timers, so the CFRunLoopTimerRef should not be active either
- Q_ASSERT(runLoopTimerRef == 0);
+ Q_ASSERT(!runLoopTimerRef);
return;
}
- if (runLoopTimerRef == 0) {
+ if (!runLoopTimerRef) {
// start the CFRunLoopTimer
CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
CFTimeInterval interval;
@@ -150,11 +150,11 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
}
ttf += interval;
- CFRunLoopTimerContext info = { 0, this, 0, 0, 0 };
+ CFRunLoopTimerContext info = { 0, this, nullptr, nullptr, nullptr };
// create the timer with a large interval, as recommended by the CFRunLoopTimerSetNextFireDate()
// documentation, since we will adjust the timer's time-to-fire as needed to keep Qt timers working
- runLoopTimerRef = CFRunLoopTimerCreate(0, ttf, oneyear, 0, 0, QCocoaEventDispatcherPrivate::runLoopTimerCallback, &info);
- Q_ASSERT(runLoopTimerRef != 0);
+ runLoopTimerRef = CFRunLoopTimerCreate(nullptr, ttf, oneyear, 0, 0, QCocoaEventDispatcherPrivate::runLoopTimerCallback, &info);
+ Q_ASSERT(runLoopTimerRef);
CFRunLoopAddTimer(mainRunLoop(), runLoopTimerRef, kCFRunLoopCommonModes);
} else {
@@ -180,12 +180,12 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
void QCocoaEventDispatcherPrivate::maybeStopCFRunLoopTimer()
{
- if (runLoopTimerRef == 0)
+ if (!runLoopTimerRef)
return;
CFRunLoopTimerInvalidate(runLoopTimerRef);
CFRelease(runLoopTimerRef);
- runLoopTimerRef = 0;
+ runLoopTimerRef = nullptr;
}
void QCocoaEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj)
@@ -368,13 +368,13 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
break;
QMacAutoReleasePool pool;
- NSEvent* event = 0;
+ NSEvent* event = nil;
// First, send all previously excluded input events, if any:
if (!excludeUserEvents) {
while (!d->queuedUserInputEvents.isEmpty()) {
event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst());
- if (!filterNativeEvent("NSEvent", event, 0)) {
+ if (!filterNativeEvent("NSEvent", event, nullptr)) {
[NSApp sendEvent:event];
retVal = true;
}
@@ -432,7 +432,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
retVal = true;
} else {
int lastSerialCopy = d->lastSerial;
- bool hadModalSession = d->currentModalSessionCached != 0;
+ const bool hadModalSession = d->currentModalSessionCached;
// We cannot block the thread (and run in a tight loop).
// Instead we will process all current pending events and return.
d->ensureNSAppInitialized();
@@ -471,12 +471,12 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
d->queuedUserInputEvents.append(event);
continue;
}
- if (!filterNativeEvent("NSEvent", event, 0)) {
+ if (!filterNativeEvent("NSEvent", event, nullptr)) {
[NSApp sendEvent:event];
retVal = true;
}
}
- } while (!d->interrupt && event != nil);
+ } while (!d->interrupt && event);
} else do {
// INVARIANT: No modal window is executing.
event = [NSApp nextEventMatchingMask:NSAnyEventMask
@@ -492,12 +492,12 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
continue;
}
}
- if (!filterNativeEvent("NSEvent", event, 0)) {
+ if (!filterNativeEvent("NSEvent", event, nullptr)) {
[NSApp sendEvent:event];
retVal = true;
}
}
- } while (!d->interrupt && event != nil);
+ } while (!d->interrupt && event);
if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) {
// when called "manually", always send posted events and timers
@@ -514,7 +514,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// event recursion to ensure that we spin the correct modal session.
// We do the interruptLater at the end of the function to ensure that we don't
// disturb the 'wait for more events' below (as deleteLater will post an event):
- if (hadModalSession && d->currentModalSessionCached == 0)
+ if (hadModalSession && !d->currentModalSessionCached)
interruptLater = true;
}
bool canWait = (d->threadData->canWait
@@ -611,11 +611,11 @@ void QCocoaEventDispatcherPrivate::temporarilyStopAllModalSessions()
QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
if (info.session) {
[NSApp endModalSession:info.session];
- info.session = 0;
+ info.session = nullptr;
[(NSWindow*) info.nswindow release];
}
}
- currentModalSessionCached = 0;
+ currentModalSessionCached = nullptr;
}
NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
@@ -626,7 +626,7 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
return currentModalSessionCached;
if (cocoaModalSessionStack.isEmpty())
- return 0;
+ return nullptr;
int sessionCount = cocoaModalSessionStack.size();
for (int i=0; i<sessionCount; ++i) {
@@ -637,6 +637,8 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
if (!info.session) {
QMacAutoReleasePool pool;
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(info.window->handle());
+ if (!cocoaWindow)
+ continue;
NSWindow *nswindow = cocoaWindow->nativeWindow();
if (!nswindow)
continue;
@@ -647,6 +649,15 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
[(NSWindow*) info.nswindow retain];
QRect rect = cocoaWindow->geometry();
info.session = [NSApp beginModalSessionForWindow:nswindow];
+
+ // The call to beginModalSessionForWindow above processes events and may
+ // have deleted or destroyed the window. Check if it's still valid.
+ if (!info.window)
+ continue;
+ cocoaWindow = static_cast<QCocoaWindow *>(info.window->handle());
+ if (!cocoaWindow)
+ continue;
+
if (rect != cocoaWindow->geometry())
cocoaWindow->setGeometry(rect);
}
@@ -717,9 +728,9 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions()
currentModalSessionCached = info.session;
break;
}
- currentModalSessionCached = 0;
+ currentModalSessionCached = nullptr;
if (info.session) {
- Q_ASSERT(info.nswindow != 0);
+ Q_ASSERT(info.nswindow);
[NSApp endModalSession:info.session];
[(NSWindow *)info.nswindow release];
}
@@ -746,10 +757,10 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
// currentModalSession). A QCocoaModalSessionInfo is considered pending to be stopped if
// the window pointer is zero, and the session pointer is non-zero (it will be fully
// stopped in cleanupModalSessions()).
- QCocoaModalSessionInfo info = {window, 0, 0};
+ QCocoaModalSessionInfo info = {window, nullptr, nullptr};
cocoaModalSessionStack.push(info);
updateChildrenWorksWhenModal();
- currentModalSessionCached = 0;
+ currentModalSessionCached = nullptr;
}
void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
@@ -768,12 +779,12 @@ void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
if (!info.window)
endedSessions++;
if (info.window == window) {
- info.window = 0;
+ info.window = nullptr;
if (i + endedSessions == stackSize-1) {
// The top sessions ended. Interrupt the event dispatcher to
// start spinning the correct session immediately.
q->interrupt();
- currentModalSessionCached = 0;
+ currentModalSessionCached = nullptr;
cleanupModalSessionsNeeded = true;
}
}
@@ -782,13 +793,13 @@ void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
: processEventsFlags(0),
- runLoopTimerRef(0),
+ runLoopTimerRef(nullptr),
blockSendPostedEvents(false),
currentExecIsNSAppRun(false),
nsAppRunCalledByQt(false),
cleanupModalSessionsNeeded(false),
processEventsCalled(0),
- currentModalSessionCached(0),
+ currentModalSessionCached(nullptr),
lastSerial(-1),
interrupt(false)
{
@@ -926,7 +937,7 @@ void QCocoaEventDispatcherPrivate::cancelWaitForMoreEvents()
// events somewhere, we post a dummy event to wake it up:
QMacAutoReleasePool pool;
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint
- modifierFlags:0 timestamp:0. windowNumber:0 context:0
+ modifierFlags:0 timestamp:0. windowNumber:0 context:nil
subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO];
}
@@ -1008,7 +1019,7 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
CFRelease(d->firstTimeObserver);
}
-QtCocoaInterruptDispatcher* QtCocoaInterruptDispatcher::instance = 0;
+QtCocoaInterruptDispatcher* QtCocoaInterruptDispatcher::instance = nullptr;
QtCocoaInterruptDispatcher::QtCocoaInterruptDispatcher() : cancelled(false)
{
@@ -1025,7 +1036,7 @@ QtCocoaInterruptDispatcher::~QtCocoaInterruptDispatcher()
{
if (cancelled)
return;
- instance = 0;
+ instance = nullptr;
QCocoaEventDispatcher::instance()->interrupt();
}
@@ -1035,7 +1046,7 @@ void QtCocoaInterruptDispatcher::cancelInterruptLater()
return;
instance->cancelled = true;
delete instance;
- instance = 0;
+ instance = nullptr;
}
void QtCocoaInterruptDispatcher::interruptLater()
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 94f2125bad..dcc57daf11 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -50,7 +50,6 @@
#include <private/qguiapplication_p.h>
#include "qt_mac_p.h"
#include "qcocoahelpers.h"
-#include "qcocoamenubar.h"
#include "qcocoaeventdispatcher.h"
#include <qregexp.h>
#include <qbuffer.h>
@@ -81,23 +80,6 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
@interface QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
: NSObject<NSOpenSavePanelDelegate>
-{
- @public
- NSOpenPanel *mOpenPanel;
- NSSavePanel *mSavePanel;
- NSView *mAccessoryView;
- NSPopUpButton *mPopUpButton;
- NSTextField *mTextField;
- QCocoaFileDialogHelper *mHelper;
- NSString *mCurrentDir;
-
- int mReturnCode;
-
- SharedPointerFileDialogOptions mOptions;
- QString *mCurrentSelection;
- QStringList *mNameFilterDropDownList;
- QStringList *mSelectedNameFilter;
-}
- (NSString *)strip:(const QString &)label;
- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url;
@@ -117,12 +99,27 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
-@implementation QNSOpenSavePanelDelegate
+@implementation QNSOpenSavePanelDelegate {
+ @public
+ NSOpenPanel *mOpenPanel;
+ NSSavePanel *mSavePanel;
+ NSView *mAccessoryView;
+ NSPopUpButton *mPopUpButton;
+ NSTextField *mTextField;
+ QCocoaFileDialogHelper *mHelper;
+ NSString *mCurrentDir;
+
+ int mReturnCode;
+
+ SharedPointerFileDialogOptions mOptions;
+ QString *mCurrentSelection;
+ QStringList *mNameFilterDropDownList;
+ QStringList *mSelectedNameFilter;
+}
-- (id)initWithAcceptMode:
- (const QString &)selectFile
- options:(SharedPointerFileDialogOptions)options
- helper:(QCocoaFileDialogHelper *)helper
+- (instancetype)initWithAcceptMode:(const QString &)selectFile
+ options:(SharedPointerFileDialogOptions)options
+ helper:(QCocoaFileDialogHelper *)helper
{
self = [super init];
mOptions = options;
@@ -132,7 +129,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
} else {
mSavePanel = [NSSavePanel savePanel];
[mSavePanel setCanSelectHiddenExtension:YES];
- mOpenPanel = 0;
+ mOpenPanel = nil;
}
if ([mSavePanel respondsToSelector:@selector(setLevel:)])
@@ -222,7 +219,6 @@ static QString strippedText(QString s)
|| [self panel:nil shouldEnableURL:url];
[self updateProperties];
- QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
[mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""];
[mOpenPanel beginWithCompletionHandler:^(NSInteger result){
@@ -252,9 +248,7 @@ static QString strippedText(QString s)
// Make sure we don't interrupt the runModal call below.
QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
- QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
mReturnCode = [mSavePanel runModal];
- QCocoaMenuBar::resetKnownMenuItemsToQt();
QAbstractEventDispatcher::instance()->interrupt();
return (mReturnCode == NSModalResponseOK);
@@ -274,7 +268,6 @@ static QString strippedText(QString s)
|| [self panel:nil shouldEnableURL:url];
[self updateProperties];
- QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
[mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]];
[mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""];
@@ -292,7 +285,7 @@ static QString strippedText(QString s)
BOOL hidden = NO;
if (url) {
CFBooleanRef isHiddenProperty;
- if (CFURLCopyResourcePropertyForKey((__bridge CFURLRef)url, kCFURLIsHiddenKey, &isHiddenProperty, NULL)) {
+ if (CFURLCopyResourcePropertyForKey((__bridge CFURLRef)url, kCFURLIsHiddenKey, &isHiddenProperty, nullptr)) {
hidden = CFBooleanGetValue(isHiddenProperty);
CFRelease(isHiddenProperty);
}
@@ -406,9 +399,9 @@ static QString strippedText(QString s)
{
if (mOpenPanel) {
QList<QUrl> result;
- NSArray* array = [mOpenPanel URLs];
- for (NSUInteger i=0; i<[array count]; ++i) {
- QString path = QString::fromNSString([[array objectAtIndex:i] path]).normalized(QString::NormalizationForm_C);
+ NSArray<NSURL *> *array = [mOpenPanel URLs];
+ for (NSURL *url in array) {
+ QString path = QString::fromNSString(url.path).normalized(QString::NormalizationForm_C);
result << QUrl::fromLocalFile(path);
}
return result;
@@ -576,7 +569,7 @@ static QString strippedText(QString s)
QT_BEGIN_NAMESPACE
QCocoaFileDialogHelper::QCocoaFileDialogHelper()
- :mDelegate(0)
+ : mDelegate(nil)
{
}
@@ -586,7 +579,7 @@ QCocoaFileDialogHelper::~QCocoaFileDialogHelper()
return;
QMacAutoReleasePool pool;
[mDelegate release];
- mDelegate = 0;
+ mDelegate = nil;
}
void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath)
@@ -596,7 +589,6 @@ void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QSt
void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
{
- QCocoaMenuBar::resetKnownMenuItemsToQt();
if (accepted) {
emit accept();
} else {
diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
index 815882ab06..33b102f3eb 100644
--- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
@@ -74,7 +74,15 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
}
@interface QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) : NSObject<NSWindowDelegate, QNSPanelDelegate>
-{
+- (void)restoreOriginalContentView;
+- (void)updateQtFont;
+- (void)changeFont:(id)sender;
+- (void)finishOffWithCode:(NSInteger)code;
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
+
+@implementation QNSFontPanelDelegate {
@public
NSFontPanel *mFontPanel;
QCocoaFontDialogHelper *mHelper;
@@ -84,34 +92,26 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
NSInteger mResultCode;
BOOL mDialogIsExecuting;
BOOL mResultSet;
-};
-- (void)restoreOriginalContentView;
-- (void)updateQtFont;
-- (void)changeFont:(id)sender;
-- (void)finishOffWithCode:(NSInteger)code;
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
-
-@implementation QNSFontPanelDelegate
+}
-- (id)init
+- (instancetype)init
{
- self = [super init];
- mFontPanel = [NSFontPanel sharedFontPanel];
- mHelper = 0;
- mStolenContentView = 0;
- mPanelButtons = 0;
- mResultCode = NSModalResponseCancel;
- mDialogIsExecuting = false;
- mResultSet = false;
+ if ((self = [super init])) {
+ mFontPanel = [NSFontPanel sharedFontPanel];
+ mHelper = nullptr;
+ mStolenContentView = nil;
+ mPanelButtons = nil;
+ mResultCode = NSModalResponseCancel;
+ mDialogIsExecuting = false;
+ mResultSet = false;
- [mFontPanel setRestorable:NO];
- [mFontPanel setDelegate:self];
+ [mFontPanel setRestorable:NO];
+ [mFontPanel setDelegate:self];
- [NSFontManager sharedFontManager].target = self; // Action is changeFont:
+ [NSFontManager sharedFontManager].target = self; // Action is changeFont:
- [mFontPanel retain];
+ [mFontPanel retain];
+ }
return self;
}
@@ -135,9 +135,9 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
[self restoreOriginalContentView];
} else if (!mStolenContentView) {
// steal the font panel's contents view
- mStolenContentView = [mFontPanel contentView];
+ mStolenContentView = mFontPanel.contentView;
[mStolenContentView retain];
- [mFontPanel setContentView:0];
+ mFontPanel.contentView = nil;
// create a new content view and add the stolen one as a subview
mPanelButtons = [[QNSPanelContentsWrapper alloc] initWithPanelDelegate:self];
@@ -159,7 +159,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
// return stolen stuff to its rightful owner
[mStolenContentView removeFromSuperview];
[mFontPanel setContentView:mStolenContentView];
- mStolenContentView = 0;
+ mStolenContentView = nil;
[mPanelButtons release];
mPanelButtons = nil;
}
@@ -191,7 +191,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
// Get selected font
NSFontManager *fontManager = [NSFontManager sharedFontManager];
NSFont *selectedFont = [fontManager selectedFont];
- if (selectedFont == nil) {
+ if (!selectedFont) {
selectedFont = [NSFont systemFontOfSize:[NSFont systemFontSize]];
}
NSFont *panelFont = [fontManager convertFont:selectedFont];
@@ -295,7 +295,7 @@ public:
void cleanup(QCocoaFontDialogHelper *helper)
{
if (mDelegate->mHelper == helper)
- mDelegate->mHelper = 0;
+ mDelegate->mHelper = nullptr;
}
bool exec()
@@ -329,7 +329,7 @@ public:
void setCurrentFont(const QFont &font)
{
NSFontManager *mgr = [NSFontManager sharedFontManager];
- const NSFont *nsFont = 0;
+ NSFont *nsFont = nil;
int weight = 5;
NSFontTraitMask mask = 0;
@@ -347,7 +347,7 @@ public:
weight:weight
size:fontInfo.pointSize()];
- [mgr setSelectedFont:const_cast<NSFont *>(nsFont) isMultiple:NO];
+ [mgr setSelectedFont:nsFont isMultiple:NO];
mDelegate->mQtFont = font;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index b656025ec7..2493181bc5 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -386,7 +386,7 @@ void QCocoaGLContext::updateSurfaceFormat()
void QCocoaGLContext::doneCurrent()
{
if (m_currentWindow && m_currentWindow.data()->handle())
- static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0);
+ static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(nullptr);
m_currentWindow.clear();
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 84632c1487..516eac0503 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -62,25 +62,32 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSView));
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaWindow)
-Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaDrawing)
-Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaMouse)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaDrawing)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaMouse)
class QPixmap;
class QString;
// Conversion functions
-QStringList qt_mac_NSArrayToQStringList(void *nsarray);
-void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list);
-
-inline NSMutableArray *qt_mac_QStringListToNSMutableArray(const QStringList &qstrlist)
-{ return reinterpret_cast<NSMutableArray *>(qt_mac_QStringListToNSMutableArrayVoid(qstrlist)); }
+QStringList qt_mac_NSArrayToQStringList(NSArray<NSString *> *nsarray);
+NSMutableArray<NSString *> *qt_mac_QStringListToNSMutableArray(const QStringList &list);
NSDragOperation qt_mac_mapDropAction(Qt::DropAction action);
NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions);
Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions);
Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions);
+template <typename T>
+typename std::enable_if<std::is_pointer<T>::value, T>::type
+qt_objc_cast(id object)
+{
+ if ([object isKindOfClass:[typename std::remove_pointer<T>::type class]])
+ return static_cast<T>(object);
+
+ return nil;
+}
+
QT_MANGLE_NAMESPACE(QNSView) *qnsview_cast(NSView *view);
// Misc
@@ -170,12 +177,7 @@ QT_END_NAMESPACE
- (void)onCancelClicked;
@end
-@interface QT_MANGLE_NAMESPACE(QNSPanelContentsWrapper) : NSView {
- NSButton *_okButton;
- NSButton *_cancelButton;
- NSView *_panelContents;
- NSEdgeInsets _panelContentsMargins;
-}
+@interface QT_MANGLE_NAMESPACE(QNSPanelContentsWrapper) : NSView
@property (nonatomic, readonly) NSButton *okButton;
@property (nonatomic, readonly) NSButton *cancelButton;
@@ -187,6 +189,7 @@ QT_END_NAMESPACE
- (NSButton *)createButtonWithTitle:(const char *)title;
- (void)layout;
+
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSPanelContentsWrapper);
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index e5954f277c..a1cf1bc632 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -57,29 +57,27 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQpaCocoaWindow, "qt.qpa.cocoa.window");
-Q_LOGGING_CATEGORY(lcQpaCocoaDrawing, "qt.qpa.cocoa.drawing");
-Q_LOGGING_CATEGORY(lcQpaCocoaMouse, "qt.qpa.cocoa.mouse");
+Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
+Q_LOGGING_CATEGORY(lcQpaDrawing, "qt.qpa.drawing");
+Q_LOGGING_CATEGORY(lcQpaMouse, "qt.qpa.input.mouse");
//
// Conversion Functions
//
-QStringList qt_mac_NSArrayToQStringList(void *nsarray)
+QStringList qt_mac_NSArrayToQStringList(NSArray<NSString *> *array)
{
QStringList result;
- NSArray *array = static_cast<NSArray *>(nsarray);
- for (NSUInteger i=0; i<[array count]; ++i)
- result << QString::fromNSString([array objectAtIndex:i]);
+ for (NSString *string in array)
+ result << QString::fromNSString(string);
return result;
}
-void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list)
+NSMutableArray<NSString *> *qt_mac_QStringListToNSMutableArray(const QStringList &list)
{
- NSMutableArray *result = [NSMutableArray arrayWithCapacity:list.size()];
- for (int i=0; i<list.size(); ++i){
- [result addObject:list[i].toNSString()];
- }
+ NSMutableArray<NSString *> *result = [NSMutableArray<NSString *> arrayWithCapacity:list.size()];
+ for (const QString &string : list)
+ [result addObject:string.toNSString()];
return result;
}
@@ -93,6 +91,7 @@ struct dndenum_mapper
static dndenum_mapper dnd_enums[] = {
{ NSDragOperationLink, Qt::LinkAction, true },
{ NSDragOperationMove, Qt::MoveAction, true },
+ { NSDragOperationDelete, Qt::MoveAction, true },
{ NSDragOperationCopy, Qt::CopyAction, true },
{ NSDragOperationGeneric, Qt::CopyAction, false },
{ NSDragOperationEvery, Qt::ActionMask, false },
@@ -161,10 +160,7 @@ Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions)
*/
QNSView *qnsview_cast(NSView *view)
{
- if (![view isKindOfClass:[QNSView class]])
- return nil;
-
- return static_cast<QNSView *>(view);
+ return qt_objc_cast<QNSView *>(view);
}
//
@@ -298,7 +294,12 @@ QT_END_NAMESPACE
the target-action for the OK/Cancel buttons and making
sure the layout is consistent.
*/
-@implementation QNSPanelContentsWrapper
+@implementation QNSPanelContentsWrapper {
+ NSButton *_okButton;
+ NSButton *_cancelButton;
+ NSView *_panelContents;
+ NSEdgeInsets _panelContentsMargins;
+}
@synthesize okButton = _okButton;
@synthesize cancelButton = _cancelButton;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 55b3805df3..a4658271bb 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -94,11 +94,11 @@ static QCocoaIntegration::Options parseOptions(const QStringList &paramList)
return options;
}
-QCocoaIntegration *QCocoaIntegration::mInstance = 0;
+QCocoaIntegration *QCocoaIntegration::mInstance = nullptr;
QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
: mOptions(parseOptions(paramList))
- , mFontDb(0)
+ , mFontDb(nullptr)
#ifndef QT_NO_ACCESSIBILITY
, mAccessibility(new QCocoaAccessibility)
#endif
@@ -110,7 +110,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
, mServices(new QCocoaServices)
, mKeyboardMapper(new QCocoaKeyMapper)
{
- if (mInstance != 0)
+ if (mInstance)
qWarning("Creating multiple Cocoa platform integrations is not supported");
mInstance = this;
@@ -186,7 +186,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
QCocoaIntegration::~QCocoaIntegration()
{
- mInstance = 0;
+ mInstance = nullptr;
qt_resetNSApplicationSendEvent();
@@ -196,7 +196,7 @@ QCocoaIntegration::~QCocoaIntegration()
QCocoaApplicationDelegate *delegate = [QCocoaApplicationDelegate sharedDelegate];
[delegate removeAppleEventHandlers];
// reset the application delegate
- [[NSApplication sharedApplication] setDelegate: 0];
+ [[NSApplication sharedApplication] setDelegate:nil];
}
#ifndef QT_NO_CLIPBOARD
@@ -225,15 +225,15 @@ QCocoaIntegration::Options QCocoaIntegration::options() const
return mOptions;
}
-Q_LOGGING_CATEGORY(lcCocoaScreen, "qt.qpa.cocoa.screens");
+Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen");
/*!
\brief Synchronizes the screen list, adds new screens, removes deleted ones
*/
void QCocoaIntegration::updateScreens()
{
- NSArray *scrs = [NSScreen screens];
- NSMutableArray *screens = [NSMutableArray arrayWithArray:scrs];
+ NSArray<NSScreen *> *scrs = [NSScreen screens];
+ NSMutableArray<NSScreen *> *screens = [NSMutableArray<NSScreen *> arrayWithArray:scrs];
if ([screens count] == 0)
if ([NSScreen mainScreen])
[screens addObject:[NSScreen mainScreen]];
@@ -244,7 +244,7 @@ void QCocoaIntegration::updateScreens()
uint screenCount = [screens count];
for (uint i = 0; i < screenCount; i++) {
NSScreen* scr = [screens objectAtIndex:i];
- CGDirectDisplayID dpy = [[[scr deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
+ CGDirectDisplayID dpy = scr.qt_displayId;
// If this screen is a mirror and is not the primary one of the mirror set, ignore it.
// Exception: The NSScreen API has been observed to a return a screen list with one
// mirrored, non-primary screen when Qt is running as a startup item. Always use the
@@ -254,7 +254,7 @@ void QCocoaIntegration::updateScreens()
if (primary != kCGNullDirectDisplay && primary != dpy)
continue;
}
- QCocoaScreen* screen = NULL;
+ QCocoaScreen* screen = nullptr;
foreach (QCocoaScreen* existingScr, mScreens)
// NSScreen documentation says do not cache the array returned from [NSScreen screens].
// However in practice, we can identify a screen by its pointer: if resolution changes,
@@ -266,11 +266,11 @@ void QCocoaIntegration::updateScreens()
if (screen) {
remainingScreens.remove(screen);
screen->updateGeometry();
- qCDebug(lcCocoaScreen) << "Updated properties of" << screen;
+ qCDebug(lcQpaScreen) << "Updated properties of" << screen;
} else {
screen = new QCocoaScreen(i);
mScreens.append(screen);
- qCDebug(lcCocoaScreen) << "Adding" << screen;
+ qCDebug(lcQpaScreen) << "Adding" << screen;
screenAdded(screen);
}
siblings << screen;
@@ -287,7 +287,7 @@ void QCocoaIntegration::updateScreens()
mScreens.removeOne(screen);
// Prevent stale references to NSScreen during destroy
screen->m_screenIndex = -1;
- qCDebug(lcCocoaScreen) << "Removing" << screen;
+ qCDebug(lcQpaScreen) << "Removing" << screen;
destroyScreen(screen);
}
}
@@ -296,7 +296,7 @@ QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen)
{
NSUInteger index = [[NSScreen screens] indexOfObject:nsScreen];
if (index == NSNotFound)
- return 0;
+ return nullptr;
if (index >= unsigned(mScreens.count()))
updateScreens();
@@ -306,7 +306,7 @@ QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen)
return screen;
}
- return 0;
+ return nullptr;
}
bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -480,14 +480,14 @@ void QCocoaIntegration::pushPopupWindow(QCocoaWindow *window)
QCocoaWindow *QCocoaIntegration::popPopupWindow()
{
if (m_popupWindowStack.isEmpty())
- return 0;
+ return nullptr;
return m_popupWindowStack.takeLast();
}
QCocoaWindow *QCocoaIntegration::activePopupWindow() const
{
if (m_popupWindowStack.isEmpty())
- return 0;
+ return nullptr;
return m_popupWindowStack.front();
}
diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.h b/src/plugins/platforms/cocoa/qcocoaintrospection.h
index 1d984b9857..20001ac71d 100644
--- a/src/plugins/platforms/cocoa/qcocoaintrospection.h
+++ b/src/plugins/platforms/cocoa/qcocoaintrospection.h
@@ -76,7 +76,7 @@
QT_BEGIN_NAMESPACE
-void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class proxyClass, SEL replacementSel = 0, SEL backupSel = 0);
+void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class proxyClass, SEL replacementSel = nil, SEL backupSel = nil);
void qt_cocoa_change_back_implementation(Class baseClass, SEL originalSel, SEL backupSel);
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
index 80140505d1..5408178824 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
@@ -357,17 +357,17 @@ Qt::KeyboardModifiers QCocoaKeyMapper::queryKeyboardModifiers()
bool QCocoaKeyMapper::updateKeyboard()
{
- const UCKeyboardLayout *uchrData = 0;
+ const UCKeyboardLayout *uchrData = nullptr;
QCFType<TISInputSourceRef> source = TISCopyInputMethodKeyboardLayoutOverride();
if (!source)
source = TISCopyCurrentKeyboardInputSource();
if (keyboard_mode != NullMode && source == currentInputSource) {
return false;
}
- Q_ASSERT(source != 0);
+ Q_ASSERT(source);
CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(source,
kTISPropertyUnicodeKeyLayoutData));
- uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
+ uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : nullptr;
keyboard_kind = LMGetKbdType();
if (uchrData) {
@@ -386,7 +386,7 @@ void QCocoaKeyMapper::deleteLayouts()
for (int i = 0; i < 255; ++i) {
if (keyLayout[i]) {
delete keyLayout[i];
- keyLayout[i] = 0;
+ keyLayout[i] = nullptr;
}
}
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 6db4e04c61..34d8428188 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
** Contact: https://www.qt.io/licensing/
**
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index a788ac7d45..90e90b32b6 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
** Contact: https://www.qt.io/licensing/
**
@@ -53,7 +54,7 @@
QT_BEGIN_NAMESPACE
QCocoaMenu::QCocoaMenu() :
- m_attachedItem(0),
+ m_attachedItem(nil),
m_updateTimer(0),
m_enabled(true),
m_parentEnabled(true),
@@ -62,14 +63,14 @@ QCocoaMenu::QCocoaMenu() :
{
QMacAutoReleasePool pool;
- m_nativeMenu = [[QCocoaNSMenu alloc] initWithQPAMenu:this];
+ m_nativeMenu = [[QCocoaNSMenu alloc] initWithPlatformMenu:this];
}
QCocoaMenu::~QCocoaMenu()
{
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (item->menuParent() == this)
- item->setMenuParent(0);
+ item->setMenuParent(nullptr);
}
[m_nativeMenu release];
@@ -79,7 +80,7 @@ void QCocoaMenu::setText(const QString &text)
{
QMacAutoReleasePool pool;
QString stripped = qt_mac_removeAmpersandEscapes(text);
- [m_nativeMenu setTitle:stripped.toNSString()];
+ m_nativeMenu.title = stripped.toNSString();
}
void QCocoaMenu::setMinimumWidth(int width)
@@ -132,7 +133,7 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *
void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem)
{
- setItemTargetAction(item);
+ item->resolveTargetAction();
NSMenuItem *nativeItem = item->nsItem();
// Someone's adding new items after aboutToShow() was emitted
if (isOpen() && nativeItem && item->menu())
@@ -187,25 +188,25 @@ void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem)
}
if (cocoaItem->menuParent() == this)
- cocoaItem->setMenuParent(0);
+ cocoaItem->setMenuParent(nullptr);
// Ignore any parent enabled state
cocoaItem->setParentEnabled(true);
m_menuItems.removeOne(cocoaItem);
if (!cocoaItem->isMerged()) {
- if (m_nativeMenu != [cocoaItem->nsItem() menu]) {
+ if (m_nativeMenu != cocoaItem->nsItem().menu) {
qWarning("Item to remove does not belong to this menu");
return;
}
- [m_nativeMenu removeItem: cocoaItem->nsItem()];
+ [m_nativeMenu removeItem:cocoaItem->nsItem()];
}
}
QCocoaMenuItem *QCocoaMenu::itemOrNull(int index) const
{
if ((index < 0) || (index >= m_menuItems.size()))
- return 0;
+ return nullptr;
return m_menuItems.at(index);
}
@@ -247,8 +248,8 @@ void QCocoaMenu::syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUp
// native item was changed for some reason
if (oldItem) {
if (wasMerged) {
- [oldItem setEnabled:NO];
- [oldItem setHidden:YES];
+ oldItem.enabled = NO;
+ oldItem.hidden = YES;
} else {
[m_nativeMenu removeItem:oldItem];
}
@@ -278,31 +279,27 @@ void QCocoaMenu::syncSeparatorsCollapsible(bool enable)
bool previousIsSeparator = true; // setting to true kills all the separators placed at the top.
NSMenuItem *previousItem = nil;
- NSArray *itemArray = [m_nativeMenu itemArray];
- for (unsigned int i = 0; i < [itemArray count]; ++i) {
- NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]);
- if ([item isSeparatorItem]) {
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]);
- if (cocoaItem)
+ for (NSMenuItem *item in m_nativeMenu.itemArray) {
+ if (item.separatorItem) {
+ if (auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem)
cocoaItem->setVisible(!previousIsSeparator);
- [item setHidden:previousIsSeparator];
+ item.hidden = previousIsSeparator;
}
- if (![item isHidden]) {
+ if (!item.hidden) {
previousItem = item;
- previousIsSeparator = ([previousItem isSeparatorItem]);
+ previousIsSeparator = previousItem.separatorItem;
}
}
// We now need to check the final item since we don't want any separators at the end of the list.
if (previousItem && previousIsSeparator) {
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([previousItem tag]);
- if (cocoaItem)
+ if (auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(previousItem).platformMenuItem)
cocoaItem->setVisible(false);
- [previousItem setHidden:YES];
+ previousItem.hidden = YES;
}
} else {
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (!item->isSeparator())
continue;
@@ -324,7 +321,7 @@ void QCocoaMenu::setEnabled(bool enabled)
bool QCocoaMenu::isEnabled() const
{
- return m_attachedItem ? [m_attachedItem isEnabled] : m_enabled && m_parentEnabled;
+ return m_attachedItem ? m_attachedItem.enabled : m_enabled && m_parentEnabled;
}
void QCocoaMenu::setVisible(bool visible)
@@ -337,11 +334,11 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
QMacAutoReleasePool pool;
QPoint pos = QPoint(targetRect.left(), targetRect.top() + targetRect.height());
- QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : 0;
+ QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : nullptr;
NSView *view = cocoaWindow ? cocoaWindow->view() : nil;
NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;
- QScreen *screen = 0;
+ QScreen *screen = nullptr;
if (parentWindow)
screen = parentWindow->screen();
if (!screen && !QGuiApplication::screens().isEmpty())
@@ -360,9 +357,9 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
// respect the menu's minimum width.
NSPopUpButtonCell *popupCell = [[[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]
autorelease];
- [popupCell setAltersStateOfSelectedItem:NO];
- [popupCell setTransparent:YES];
- [popupCell setMenu:m_nativeMenu];
+ popupCell.altersStateOfSelectedItem = NO;
+ popupCell.transparent = YES;
+ popupCell.menu = m_nativeMenu;
[popupCell selectItem:nsItem];
QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen *>(screen->handle());
@@ -405,7 +402,7 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
pressure:1.0];
[NSMenu popUpContextMenu:m_nativeMenu withEvent:menuEvent forView:view];
} else {
- [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:0];
+ [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:nil];
}
}
@@ -425,17 +422,17 @@ QPlatformMenuItem *QCocoaMenu::menuItemAt(int position) const
if (0 <= position && position < m_menuItems.count())
return m_menuItems.at(position);
- return 0;
+ return nullptr;
}
QPlatformMenuItem *QCocoaMenu::menuItemForTag(quintptr tag) const
{
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (item->tag() == tag)
return item;
}
- return 0;
+ return nullptr;
}
QList<QCocoaMenuItem *> QCocoaMenu::items() const
@@ -446,7 +443,7 @@ QList<QCocoaMenuItem *> QCocoaMenu::items() const
QList<QCocoaMenuItem *> QCocoaMenu::merged() const
{
QList<QCocoaMenuItem *> result;
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (item->menu()) { // recurse into submenus
result.append(item->menu()->merged());
continue;
@@ -467,7 +464,7 @@ void QCocoaMenu::propagateEnabledState(bool enabled)
if (!m_enabled && enabled) // Some ancestor was enabled, but this menu is not
return;
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (QCocoaMenu *menu = item->menu())
menu->propagateEnabledState(enabled);
else
@@ -495,11 +492,4 @@ NSMenuItem *QCocoaMenu::attachedItem() const
return m_attachedItem;
}
-void QCocoaMenu::setItemTargetAction(QCocoaMenuItem *item) const
-{
- auto *nsItem = item->nsItem();
- nsItem.target = m_nativeMenu;
- nsItem.action = @selector(qt_itemFired:);
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h
index 6f3aca3a51..0ed653911a 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.h
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
** Contact: https://www.qt.io/licensing/
**
@@ -65,12 +65,10 @@ public:
inline NSMenu *nsMenu() const
{ return m_nativeMenu; }
- static void redirectKnownMenuItemsToFirstResponder();
- static void resetKnownMenuItemsToQt();
static void updateMenuBarImmediately();
QList<QCocoaMenuItem*> merged() const;
- NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole r);
+ NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole role);
QCocoaWindow *cocoaWindow() const;
void syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate);
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index 61ac5eb7f0..3564f0176e 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
** Contact: https://www.qt.io/licensing/
**
@@ -67,7 +68,7 @@ QCocoaMenuBar::~QCocoaMenuBar()
#ifdef QT_COCOA_ENABLE_MENU_DEBUG
qDebug() << "~QCocoaMenuBar" << this;
#endif
- foreach (QCocoaMenu *menu, m_menus) {
+ for (auto menu : qAsConst(m_menus)) {
if (!menu)
continue;
NSMenuItem *item = nativeItemForMenu(menu);
@@ -79,14 +80,13 @@ QCocoaMenuBar::~QCocoaMenuBar()
static_menubars.removeOne(this);
if (!m_window.isNull() && m_window->menubar() == this) {
- m_window->setMenubar(0);
+ m_window->setMenubar(nullptr);
// Delete the children first so they do not cause
// the native menu items to be hidden after
// the menu bar was updated
qDeleteAll(children());
updateMenuBarImmediately();
- resetKnownMenuItemsToQt();
}
}
@@ -199,8 +199,8 @@ void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate)
// If the NSMenu has no visble items, or only separators, we should hide it
// on the menubar. This can happen after syncing the menu items since they
// can be moved to other menus.
- for (NSMenuItem *item in [cocoaMenu->nsMenu() itemArray])
- if (![item isSeparatorItem] && ![item isHidden]) {
+ for (NSMenuItem *item in cocoaMenu->nsMenu().itemArray)
+ if (!item.separatorItem && !item.hidden) {
shouldHide = NO;
break;
}
@@ -230,7 +230,7 @@ void QCocoaMenuBar::handleReparent(QWindow *newParentWindow)
if (!m_window.isNull())
m_window->setMenubar(nullptr);
- if (newParentWindow == nullptr) {
+ if (!newParentWindow) {
m_window.clear();
} else {
newParentWindow->create();
@@ -246,77 +246,17 @@ QCocoaWindow *QCocoaMenuBar::findWindowForMenubar()
if (qApp->focusWindow())
return static_cast<QCocoaWindow*>(qApp->focusWindow()->handle());
- return NULL;
+ return nullptr;
}
QCocoaMenuBar *QCocoaMenuBar::findGlobalMenubar()
{
- foreach (QCocoaMenuBar *mb, static_menubars) {
- if (mb->m_window.isNull())
- return mb;
+ for (auto *menubar : qAsConst(static_menubars)) {
+ if (menubar->m_window.isNull())
+ return menubar;
}
- return NULL;
-}
-
-void QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder()
-{
- // QTBUG-17291: http://forums.macrumors.com/showthread.php?t=1249452
- // When a dialog is opened, shortcuts for actions inside the dialog (cut, paste, ...)
- // continue to go through the same menu items which claimed those shortcuts.
- // They are not keystrokes which we can intercept in any other way; the OS intercepts them.
- // The menu items had to be created by the application. That's why we need roles
- // to identify those "special" menu items which can be useful even when non-Qt
- // native widgets are in focus. When the native widget is focused it will be the
- // first responder, so the menu item needs to have its target be the first responder;
- // this is done by setting it to nil.
-
- // This function will find all menu items on all menus which have
- // "special" roles, set the target and also set the standard actions which
- // apply to those roles. But afterwards it is necessary to call
- // resetKnownMenuItemsToQt() to put back the target and action so that
- // those menu items will go back to invoking their associated QActions.
- foreach (QCocoaMenuBar *mb, static_menubars)
- foreach (QCocoaMenu *m, mb->m_menus)
- foreach (QCocoaMenuItem *i, m->items()) {
- bool known = true;
- switch (i->effectiveRole()) {
- case QPlatformMenuItem::CutRole:
- [i->nsItem() setAction:@selector(cut:)];
- break;
- case QPlatformMenuItem::CopyRole:
- [i->nsItem() setAction:@selector(copy:)];
- break;
- case QPlatformMenuItem::PasteRole:
- [i->nsItem() setAction:@selector(paste:)];
- break;
- case QPlatformMenuItem::SelectAllRole:
- [i->nsItem() setAction:@selector(selectAll:)];
- break;
- // We may discover later that there are other roles/actions which
- // are meaningful to standard native widgets; they can be added.
- default:
- known = false;
- break;
- }
- if (known)
- [i->nsItem() setTarget:nil];
- }
-}
-
-void QCocoaMenuBar::resetKnownMenuItemsToQt()
-{
- // Undo the effect of redirectKnownMenuItemsToFirstResponder():
- // reset the menu items' target/action.
- foreach (QCocoaMenuBar *mb, static_menubars) {
- foreach (QCocoaMenu *m, mb->m_menus) {
- foreach (QCocoaMenuItem *i, m->items()) {
- if (i->effectiveRole() >= QPlatformMenuItem::ApplicationSpecificRole) {
- m->setItemTargetAction(i);
- }
- }
- }
- }
+ return nullptr;
}
void QCocoaMenuBar::updateMenuBarImmediately()
@@ -325,7 +265,7 @@ void QCocoaMenuBar::updateMenuBarImmediately()
QCocoaMenuBar *mb = findGlobalMenubar();
QCocoaWindow *cw = findWindowForMenubar();
- QWindow *win = cw ? cw->window() : 0;
+ QWindow *win = cw ? cw->window() : nullptr;
if (win && (win->flags() & Qt::Popup) == Qt::Popup) {
// context menus, comboboxes, etc. don't need to update the menubar,
// but if an application has only Qt::Tool window(s) on start,
@@ -353,7 +293,7 @@ void QCocoaMenuBar::updateMenuBarImmediately()
#endif
bool disableForModal = mb->shouldDisable(cw);
- foreach (QCocoaMenu *menu, mb->m_menus) {
+ for (auto menu : qAsConst(mb->m_menus)) {
if (!menu)
continue;
NSMenuItem *item = mb->nativeItemForMenu(menu);
@@ -368,16 +308,16 @@ void QCocoaMenuBar::updateMenuBarImmediately()
[loader ensureAppMenuInMenu:mb->nsMenu()];
NSMutableSet *mergedItems = [[NSMutableSet setWithCapacity:mb->merged().count()] retain];
- foreach (QCocoaMenuItem *m, mb->merged()) {
- [mergedItems addObject:m->nsItem()];
- m->syncMerged();
+ for (auto mergedItem : mb->merged()) {
+ [mergedItems addObject:mergedItem->nsItem()];
+ mergedItem->syncMerged();
}
// hide+disable all mergeable items we're not currently using
for (NSMenuItem *mergeable in [loader mergeable]) {
if (![mergedItems containsObject:mergeable]) {
- [mergeable setHidden:YES];
- [mergeable setEnabled:NO];
+ mergeable.hidden = YES;
+ mergeable.enabled = NO;
}
}
@@ -389,7 +329,7 @@ void QCocoaMenuBar::updateMenuBarImmediately()
QList<QCocoaMenuItem*> QCocoaMenuBar::merged() const
{
QList<QCocoaMenuItem*> r;
- foreach (QCocoaMenu* menu, m_menus)
+ for (auto menu : qAsConst(m_menus))
r.append(menu->merged());
return r;
@@ -409,11 +349,11 @@ bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const
// When there is an application modal window on screen, the entries of
// the menubar should be disabled. The exception in Qt is that if the
// modal window is the only window on screen, then we enable the menu bar.
- foreach (QWindow *w, topWindows) {
- if (w->isVisible() && w->modality() == Qt::ApplicationModal) {
+ for (auto *window : qAsConst(topWindows)) {
+ if (window->isVisible() && window->modality() == Qt::ApplicationModal) {
// check for other visible windows
- foreach (QWindow *other, topWindows) {
- if ((w != other) && (other->isVisible())) {
+ for (auto *other : qAsConst(topWindows)) {
+ if ((window != other) && (other->isVisible())) {
// INVARIANT: we found another visible window
// on screen other than our modalWidget. We therefore
// disable the menu bar to follow normal modality logic:
@@ -433,21 +373,21 @@ bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const
QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const
{
- foreach (QCocoaMenu *menu, m_menus) {
+ for (auto menu : qAsConst(m_menus))
if (menu->tag() == tag)
return menu;
- }
- return 0;
+ return nullptr;
}
-NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole r)
+NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole role)
{
- foreach (QCocoaMenu *m, m_menus)
- foreach (QCocoaMenuItem *i, m->items())
- if (i->effectiveRole() == r)
- return i->nsItem();
- return nullptr;
+ for (auto menu : qAsConst(m_menus))
+ for (auto *item : menu->items())
+ if (item->effectiveRole() == role)
+ return item->nsItem();
+
+ return nil;
}
QCocoaWindow *QCocoaMenuBar::cocoaWindow() const
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index 2b598ee3a0..20fc741fb8 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
** Contact: https://www.qt.io/licensing/
**
@@ -108,6 +108,7 @@ public:
QCocoaMenu *menu() const { return m_menu; }
MenuRole effectiveRole() const;
+ void resolveTargetAction();
private:
QString mergeText();
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index f8f9648822..e1572e1800 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
** Contact: https://www.qt.io/licensing/
**
@@ -41,6 +42,7 @@
#include "qcocoamenuitem.h"
+#include "qcocoansmenu.h"
#include "qcocoamenu.h"
#include "qcocoamenubar.h"
#include "messages.h"
@@ -49,7 +51,6 @@
#include "qcocoaapplication.h" // for custom application category
#include "qcocoamenuloader.h"
#include <QtGui/private/qcoregraphics_p.h>
-#include <QtCore/qregularexpression.h>
#include <QtCore/QDebug>
@@ -92,9 +93,9 @@ NSUInteger keySequenceModifierMask(const QKeySequence &accel)
#endif
QCocoaMenuItem::QCocoaMenuItem() :
- m_native(NULL),
+ m_native(nil),
m_itemView(nil),
- m_menu(NULL),
+ m_menu(nullptr),
m_role(NoRole),
m_iconSize(16),
m_textSynced(false),
@@ -112,9 +113,9 @@ QCocoaMenuItem::~QCocoaMenuItem()
QMacAutoReleasePool pool;
if (m_menu && m_menu->menuParent() == this)
- m_menu->setMenuParent(0);
+ m_menu->setMenuParent(nullptr);
if (m_merged) {
- [m_native setHidden:YES];
+ m_native.hidden = YES;
} else {
if (m_menu && m_menu->attachedItem() == m_native)
m_menu->setAttachedItem(nil);
@@ -140,7 +141,7 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
return;
if (m_menu && m_menu->menuParent() == this) {
- m_menu->setMenuParent(0);
+ m_menu->setMenuParent(nullptr);
// Free the menu from its parent's influence
m_menu->propagateEnabledState(true);
if (m_native && m_menu->attachedItem() == m_native)
@@ -210,82 +211,75 @@ void QCocoaMenuItem::setNativeContents(WId item)
return;
[m_itemView release];
m_itemView = [itemView retain];
- [m_itemView setAutoresizesSubviews:YES];
- [m_itemView setAutoresizingMask:NSViewWidthSizable];
- [m_itemView setHidden:NO];
- [m_itemView setNeedsDisplay:YES];
+ m_itemView.autoresizesSubviews = YES;
+ m_itemView.autoresizingMask = NSViewWidthSizable;
+ m_itemView.hidden = NO;
+ m_itemView.needsDisplay = YES;
}
NSMenuItem *QCocoaMenuItem::sync()
{
- if (m_isSeparator != [m_native isSeparatorItem]) {
+ if (m_isSeparator != m_native.separatorItem) {
[m_native release];
- if (m_isSeparator) {
- m_native = [[NSMenuItem separatorItem] retain];
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
- } else
+ if (m_isSeparator)
+ m_native = [[QCocoaNSMenuItem separatorItemWithPlatformMenuItem:this] retain];
+ else
m_native = nil;
}
if ((m_role != NoRole && !m_textSynced) || m_merged) {
- NSMenuItem *mergeItem = nil;
+ QCocoaMenuBar *menubar = nullptr;
+ if (m_role == TextHeuristicRole) {
+ // Recognized menu roles are only found in the first menus below the menubar
+ QObject *p = menuParent();
+ int depth = 1;
+ while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) {
+ ++depth;
+ QCocoaMenuObject *menuObject = dynamic_cast<QCocoaMenuObject *>(p);
+ Q_ASSERT(menuObject);
+ p = menuObject->menuParent();
+ }
+
+ if (menubar && depth < 3)
+ m_detectedRole = detectMenuRole(m_text);
+ else
+ m_detectedRole = NoRole;
+ }
+
QCocoaMenuLoader *loader = [QCocoaMenuLoader sharedMenuLoader];
- switch (m_role) {
- case ApplicationSpecificRole:
- mergeItem = [loader appSpecificMenuItem:reinterpret_cast<NSInteger>(this)];
- break;
+ NSMenuItem *mergeItem = nil;
+ const auto role = effectiveRole();
+ switch (role) {
case AboutRole:
mergeItem = [loader aboutMenuItem];
break;
case AboutQtRole:
mergeItem = [loader aboutQtMenuItem];
break;
+ case PreferencesRole:
+ mergeItem = [loader preferencesMenuItem];
+ break;
+ case ApplicationSpecificRole:
+ mergeItem = [loader appSpecificMenuItem:this];
+ break;
case QuitRole:
mergeItem = [loader quitMenuItem];
break;
- case PreferencesRole:
- mergeItem = [loader preferencesMenuItem];
+ case CutRole:
+ case CopyRole:
+ case PasteRole:
+ case SelectAllRole:
+ if (menubar)
+ mergeItem = menubar->itemForRole(role);
break;
- case TextHeuristicRole: {
- QObject *p = menuParent();
- int depth = 1;
- QCocoaMenuBar *menubar = 0;
- while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) {
- ++depth;
- QCocoaMenuObject *menuObject = dynamic_cast<QCocoaMenuObject *>(p);
- Q_ASSERT(menuObject);
- p = menuObject->menuParent();
- }
- if (depth == 3 || !menubar)
- break; // Menu item too deep in the hierarchy, or not connected to any menubar
-
- m_detectedRole = detectMenuRole(m_text);
- switch (m_detectedRole) {
- case QPlatformMenuItem::AboutRole:
- if (m_text.indexOf(QRegularExpression(QString::fromLatin1("qt$"),
- QRegularExpression::CaseInsensitiveOption)) == -1)
- mergeItem = [loader aboutMenuItem];
- else
- mergeItem = [loader aboutQtMenuItem];
- break;
- case QPlatformMenuItem::PreferencesRole:
- mergeItem = [loader preferencesMenuItem];
- break;
- case QPlatformMenuItem::QuitRole:
- mergeItem = [loader quitMenuItem];
- break;
- default:
- if (m_detectedRole >= CutRole && m_detectedRole < RoleCount && menubar)
- mergeItem = menubar->itemForRole(m_detectedRole);
- if (!m_text.isEmpty())
- m_textSynced = true;
- break;
- }
+ case NoRole:
+ // The heuristic couldn't resolve the menu role
+ m_textSynced = false;
break;
- }
-
default:
- qWarning() << "Menu item" << m_text << "has unsupported role" << m_role;
+ if (!m_text.isEmpty())
+ m_textSynced = true;
+ break;
}
if (mergeItem) {
@@ -294,7 +288,8 @@ NSMenuItem *QCocoaMenuItem::sync()
[mergeItem retain];
[m_native release];
m_native = mergeItem;
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
+ if (auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(m_native))
+ nativeItem.platformMenuItem = this;
} else if (m_merged) {
// was previously merged, but no longer
[m_native release];
@@ -306,14 +301,14 @@ NSMenuItem *QCocoaMenuItem::sync()
}
if (!m_native) {
- m_native = [[NSMenuItem alloc] initWithTitle:m_text.toNSString()
- action:nil
- keyEquivalent:@""];
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
+ m_native = [[QCocoaNSMenuItem alloc] initWithPlatformMenuItem:this];
+ m_native.title = m_text.toNSString();
}
- [m_native setHidden: !m_isVisible];
- [m_native setView:m_itemView];
+ resolveTargetAction();
+
+ m_native.hidden = !m_isVisible;
+ m_native.view = m_itemView;
QString text = mergeText();
#ifndef QT_NO_SHORTCUT
@@ -331,39 +326,35 @@ NSMenuItem *QCocoaMenuItem::sync()
NSFont *customMenuFont = [NSFont fontWithName:m_font.family().toNSString()
size:m_font.pointSize()];
if (customMenuFont) {
- NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil];
- NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil];
- NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSAttributedString *str = [[[NSAttributedString alloc] initWithString:finalString.toNSString()
- attributes:attributes] autorelease];
- [m_native setAttributedTitle: str];
+ attributes:@{NSFontAttributeName: customMenuFont}] autorelease];
+ m_native.attributedTitle = str;
useAttributedTitle = true;
}
}
- if (!useAttributedTitle) {
- [m_native setTitle:finalString.toNSString()];
- }
+ if (!useAttributedTitle)
+ m_native.title = finalString.toNSString();
#ifndef QT_NO_SHORTCUT
if (accel.count() == 1) {
- [m_native setKeyEquivalent:keySequenceToKeyEqivalent(accel)];
- [m_native setKeyEquivalentModifierMask:keySequenceModifierMask(accel)];
+ m_native.keyEquivalent = keySequenceToKeyEqivalent(accel);
+ m_native.keyEquivalentModifierMask = keySequenceModifierMask(accel);
} else
#endif
{
- [m_native setKeyEquivalent:@""];
- [m_native setKeyEquivalentModifierMask:NSCommandKeyMask];
+ m_native.keyEquivalent = @"";
+ m_native.keyEquivalentModifierMask = NSCommandKeyMask;
}
NSImage *img = nil;
if (!m_icon.isNull()) {
img = qt_mac_create_nsimage(m_icon, m_iconSize);
- [img setSize:NSMakeSize(m_iconSize, m_iconSize)];
+ img.size = CGSizeMake(m_iconSize, m_iconSize);
}
- [m_native setImage:img];
+ m_native.image = img;
[img release];
- [m_native setState:m_checked ? NSOnState : NSOffState];
+ m_native.state = m_checked ? NSOnState : NSOffState;
return m_native;
}
@@ -408,8 +399,8 @@ void QCocoaMenuItem::syncMerged()
qWarning("Trying to sync a non-merged item");
return;
}
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
- [m_native setHidden: !m_isVisible];
+
+ m_native.hidden = !m_isVisible;
}
void QCocoaMenuItem::setParentEnabled(bool enabled)
@@ -434,4 +425,39 @@ void QCocoaMenuItem::setIconSize(int size)
m_iconSize = size;
}
+void QCocoaMenuItem::resolveTargetAction()
+{
+ if (m_native.separatorItem)
+ return;
+
+ // Some items created by QCocoaMenuLoader are not
+ // instances of QCocoaNSMenuItem and have their
+ // target/action set as Interface Builder would.
+ if (![m_native isMemberOfClass:[QCocoaNSMenuItem class]])
+ return;
+
+ // Use the responder chain and ensure native modal dialogs
+ // continue receiving cut/copy/paste/etc. key equivalents.
+ SEL roleAction;
+ switch (effectiveRole()) {
+ case CutRole:
+ roleAction = @selector(cut:);
+ break;
+ case CopyRole:
+ roleAction = @selector(copy:);
+ break;
+ case PasteRole:
+ roleAction = @selector(paste:);
+ break;
+ case SelectAllRole:
+ roleAction = @selector(selectAll:);
+ break;
+ default:
+ roleAction = @selector(qt_itemFired:);
+ }
+
+ m_native.action = roleAction;
+ m_native.target = nil;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.h b/src/plugins/platforms/cocoa/qcocoamenuloader.h
index 95f347646c..5e83327854 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -54,42 +54,20 @@
#import <AppKit/AppKit.h>
#include <QtCore/private/qcore_mac_p.h>
-@interface QT_MANGLE_NAMESPACE(QCocoaMenuLoader) : NSResponder
-{
- IBOutlet NSMenu *theMenu;
- IBOutlet NSMenu *appMenu;
- IBOutlet NSMenuItem *quitItem;
- IBOutlet NSMenuItem *preferencesItem;
- IBOutlet NSMenuItem *aboutItem;
- IBOutlet NSMenuItem *aboutQtItem;
- IBOutlet NSMenuItem *hideItem;
- NSMenuItem *lastAppSpecificItem;
- NSMenuItem *servicesItem;
- NSMenuItem *hideAllOthersItem;
- NSMenuItem *showAllItem;
-}
+QT_FORWARD_DECLARE_CLASS(QCocoaMenuItem);
+
+@interface QT_MANGLE_NAMESPACE(QCocoaMenuLoader) : NSObject
+ (instancetype)sharedMenuLoader;
-- (instancetype)init;
-- (void)ensureAppMenuInMenu:(NSMenu *)menu;
-- (void)removeActionsFromAppMenu;
-- (NSMenu *)applicationMenu;
- (NSMenu *)menu;
+- (void)ensureAppMenuInMenu:(NSMenu *)menu;
- (NSMenuItem *)quitMenuItem;
- (NSMenuItem *)preferencesMenuItem;
- (NSMenuItem *)aboutMenuItem;
- (NSMenuItem *)aboutQtMenuItem;
- (NSMenuItem *)hideMenuItem;
-- (NSMenuItem *)appSpecificMenuItem:(NSInteger)tag;
-- (IBAction)terminate:(id)sender;
-- (IBAction)orderFrontStandardAboutPanel:(id)sender;
-- (IBAction)hideOtherApplications:(id)sender;
-- (IBAction)unhideAllApplications:(id)sender;
-- (IBAction)hide:(id)sender;
-- (IBAction)qtDispatcherToQPAMenuItem:(id)sender;
-- (void)orderFrontCharacterPalette:(id)sender;
-- (BOOL)validateMenuItem:(NSMenuItem*)menuItem;
+- (NSMenuItem *)appSpecificMenuItem:(QCocoaMenuItem *)platformItem;
- (void)qtTranslateApplicationMenu;
-- (NSArray *)mergeable;
+- (NSArray<NSMenuItem *> *)mergeable;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuLoader);
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index cd597da71c..345b370826 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -41,6 +41,7 @@
#include "messages.h"
#include "qcocoahelpers.h"
+#include "qcocoansmenu.h"
#include "qcocoamenubar.h"
#include "qcocoamenuitem.h"
#include "qcocoaintegration.h"
@@ -50,7 +51,19 @@
#include <QtCore/qcoreapplication.h>
#include <QtGui/private/qguiapplication_p.h>
-@implementation QCocoaMenuLoader
+@implementation QCocoaMenuLoader {
+ NSMenu *theMenu;
+ NSMenu *appMenu;
+ NSMenuItem *quitItem;
+ NSMenuItem *preferencesItem;
+ NSMenuItem *aboutItem;
+ NSMenuItem *aboutQtItem;
+ NSMenuItem *hideItem;
+ NSMenuItem *lastAppSpecificItem;
+ NSMenuItem *servicesItem;
+ NSMenuItem *hideAllOthersItem;
+ NSMenuItem *showAllItem;
+}
+ (instancetype)sharedMenuLoader
{
@@ -83,17 +96,19 @@
appItem.submenu = appMenu;
// About Application
- aboutItem = [[NSMenuItem alloc] initWithTitle:[@"About " stringByAppendingString:appName]
- action:@selector(orderFrontStandardAboutPanel:)
- keyEquivalent:@""];
+ aboutItem = [[QCocoaNSMenuItem alloc] init];
+ aboutItem.title = [@"About " stringByAppendingString:appName];
+ // FIXME This seems useless since barely adding a QAction
+ // with AboutRole role will reset the target/action
aboutItem.target = self;
+ aboutItem.action = @selector(orderFrontStandardAboutPanel:);
// Disable until a QAction is associated
aboutItem.enabled = NO;
aboutItem.hidden = YES;
[appMenu addItem:aboutItem];
// About Qt (shameless self-promotion)
- aboutQtItem = [[NSMenuItem alloc] init];
+ aboutQtItem = [[QCocoaNSMenuItem alloc] init];
aboutQtItem.title = @"About Qt";
// Disable until a QAction is associated
aboutQtItem.enabled = NO;
@@ -103,15 +118,19 @@
[appMenu addItem:[NSMenuItem separatorItem]];
// Preferences
- preferencesItem = [[NSMenuItem alloc] initWithTitle:@"Preferences…"
- action:@selector(qtDispatcherToQPAMenuItem:)
- keyEquivalent:@","];
- preferencesItem.target = self;
+ preferencesItem = [[QCocoaNSMenuItem alloc] init];
+ preferencesItem.title = @"Preferences…";
+ preferencesItem.keyEquivalent = @",";
// Disable until a QAction is associated
preferencesItem.enabled = NO;
preferencesItem.hidden = YES;
[appMenu addItem:preferencesItem];
+ // We'll be adding app specific items after this. The macOS HIG state that,
+ // "In general, a Preferences menu item should be the first app-specific menu item."
+ // https://developer.apple.com/macos/human-interface-guidelines/menus/menu-bar-menus/
+ lastAppSpecificItem = preferencesItem;
+
[appMenu addItem:[NSMenuItem separatorItem]];
// Services item and menu
@@ -149,10 +168,13 @@
[appMenu addItem:[NSMenuItem separatorItem]];
// Quit Application
- quitItem = [[NSMenuItem alloc] initWithTitle:[@"Quit " stringByAppendingString:appName]
- action:@selector(terminate:)
- keyEquivalent:@"q"];
- quitItem.target = self;
+ quitItem = [[QCocoaNSMenuItem alloc] init];
+ quitItem.title = [@"Quit " stringByAppendingString:appName];
+ quitItem.keyEquivalent = @"q";
+ // This will remain true until synced with a QCocoaMenuItem.
+ // This way, we will always have a functional Quit menu item
+ // even if no QAction is added.
+ quitItem.action = @selector(terminate:);
[appMenu addItem:quitItem];
}
@@ -184,18 +206,18 @@
// windows with different menu bars), we never recreate this menu, but
// instead pull it out the current menu bar and place into the new one:
NSMenu *mainMenu = [NSApp mainMenu];
- if ([NSApp mainMenu] == menu)
+ if (mainMenu == menu)
return; // nothing to do (menu is the current menu bar)!
#ifndef QT_NAMESPACE
Q_ASSERT(mainMenu);
#endif
// Grab the app menu out of the current menu.
- int numItems = [mainMenu numberOfItems];
- NSMenuItem *oldAppMenuItem = 0;
+ const int numItems = mainMenu.numberOfItems;
+ NSMenuItem *oldAppMenuItem = nil;
for (int i = 0; i < numItems; ++i) {
NSMenuItem *item = [mainMenu itemAtIndex:i];
- if ([item submenu] == appMenu) {
+ if (item.submenu == appMenu) {
oldAppMenuItem = item;
[oldAppMenuItem retain];
[mainMenu removeItemAtIndex:i];
@@ -204,21 +226,15 @@
}
if (oldAppMenuItem) {
- [oldAppMenuItem setSubmenu:nil];
+ oldAppMenuItem.submenu = nil;
[oldAppMenuItem release];
NSMenuItem *appMenuItem = [[NSMenuItem alloc] initWithTitle:@"Apple"
- action:nil keyEquivalent:@""];
- [appMenuItem setSubmenu:appMenu];
+ action:nil keyEquivalent:@""];
+ appMenuItem.submenu = appMenu;
[menu insertItem:appMenuItem atIndex:0];
}
}
-- (void)removeActionsFromAppMenu
-{
- for (NSMenuItem *item in [appMenu itemArray])
- [item setTag:0];
-}
-
- (NSMenu *)menu
{
return [[theMenu retain] autorelease];
@@ -254,41 +270,32 @@
return [[hideItem retain] autorelease];
}
-- (NSMenuItem *)appSpecificMenuItem:(NSInteger)tag
+- (NSMenuItem *)appSpecificMenuItem:(QCocoaMenuItem *)platformItem
{
- NSMenuItem *item = [appMenu itemWithTag:tag];
-
- // No reason to create the item if it already exists. See QTBUG-27202.
- if (item)
- return [[item retain] autorelease];
+ // No reason to create the item if it already exists.
+ for (NSMenuItem *item in appMenu.itemArray)
+ if (qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem == platformItem)
+ return [[item retain] autorelease];
// Create an App-Specific menu item, insert it into the menu and return
// it as an autorelease item.
- item = [[NSMenuItem alloc] init];
+ QCocoaNSMenuItem *item;
+ if (platformItem->isSeparator())
+ item = [[QCocoaNSMenuItem separatorItemWithPlatformMenuItem:platformItem] retain];
+ else
+ item = [[QCocoaNSMenuItem alloc] initWithPlatformMenuItem:platformItem];
+
+ const auto location = [appMenu indexOfItem:lastAppSpecificItem];
- NSInteger location;
- if (lastAppSpecificItem == nil) {
- location = [appMenu indexOfItem:aboutQtItem];
- } else {
- location = [appMenu indexOfItem:lastAppSpecificItem];
+ if (!lastAppSpecificItem.separatorItem)
[lastAppSpecificItem release];
- }
lastAppSpecificItem = item; // Keep track of this for later (i.e., don't release it)
+
[appMenu insertItem:item atIndex:location + 1];
return [[item retain] autorelease];
}
-- (BOOL) acceptsFirstResponder
-{
- return YES;
-}
-
-- (void)terminate:(id)sender
-{
- [NSApp terminate:sender];
-}
-
- (void)orderFrontStandardAboutPanel:(id)sender
{
[NSApp orderFrontStandardAboutPanel:sender];
@@ -311,61 +318,36 @@
- (void)qtTranslateApplicationMenu
{
-
#ifndef QT_NO_TRANSLATION
- [servicesItem setTitle:qt_mac_applicationmenu_string(ServicesAppMenuItem).toNSString()];
- [hideItem setTitle:qt_mac_applicationmenu_string(HideAppMenuItem).arg(qt_mac_applicationName()).toNSString()];
- [hideAllOthersItem setTitle:qt_mac_applicationmenu_string(HideOthersAppMenuItem).toNSString()];
- [showAllItem setTitle:qt_mac_applicationmenu_string(ShowAllAppMenuItem).toNSString()];
- [preferencesItem setTitle:qt_mac_applicationmenu_string(PreferencesAppMenuItem).toNSString()];
- [quitItem setTitle:qt_mac_applicationmenu_string(QuitAppMenuItem).arg(qt_mac_applicationName()).toNSString()];
- [aboutItem setTitle:qt_mac_applicationmenu_string(AboutAppMenuItem).arg(qt_mac_applicationName()).toNSString()];
+ aboutItem.title = qt_mac_applicationmenu_string(AboutAppMenuItem).arg(qt_mac_applicationName()).toNSString();
+ preferencesItem.title = qt_mac_applicationmenu_string(PreferencesAppMenuItem).toNSString();
+ servicesItem.title = qt_mac_applicationmenu_string(ServicesAppMenuItem).toNSString();
+ hideItem.title = qt_mac_applicationmenu_string(HideAppMenuItem).arg(qt_mac_applicationName()).toNSString();
+ hideAllOthersItem.title = qt_mac_applicationmenu_string(HideOthersAppMenuItem).toNSString();
+ showAllItem.title = qt_mac_applicationmenu_string(ShowAllAppMenuItem).toNSString();
+ quitItem.title = qt_mac_applicationmenu_string(QuitAppMenuItem).arg(qt_mac_applicationName()).toNSString();
#endif
}
-- (IBAction)qtDispatcherToQPAMenuItem:(id)sender
-{
- NSMenuItem *item = static_cast<NSMenuItem *>(sender);
- if (item == quitItem) {
- // We got here because someone was once the quitItem, but it has been
- // abandoned (e.g., the menubar was deleted). In the meantime, just do
- // normal QApplication::quit().
- qApp->quit();
- return;
- }
-
- if ([item tag]) {
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]);
- QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
- cocoaItem->activated();
- }
-}
-
-- (void)orderFrontCharacterPalette:(id)sender
-{
- [NSApp orderFrontCharacterPalette:sender];
-}
-
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
{
- if ([menuItem action] == @selector(hideOtherApplications:)
- || [menuItem action] == @selector(unhideAllApplications:)) {
+ if (menuItem.action == @selector(hideOtherApplications:)
+ || menuItem.action == @selector(unhideAllApplications:))
return [NSApp validateMenuItem:menuItem];
- } else if ([menuItem action] == @selector(hide:)) {
+
+ if (menuItem.action == @selector(hide:)) {
if (QCocoaIntegration::instance()->activePopupWindow())
return NO;
return [NSApp validateMenuItem:menuItem];
- } else if ([menuItem tag]) {
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([menuItem tag]);
- return cocoaItem->isEnabled();
- } else {
- return [menuItem isEnabled];
}
+
+ return menuItem.enabled;
}
-- (NSArray*) mergeable
+- (NSArray<NSMenuItem *> *)mergeable
{
- // don't include the quitItem here, since we want it always visible and enabled regardless
+ // Don't include the quitItem here, since we want it always visible and enabled regardless
+ // Note that lastAppSpecificItem may be nil, so we can't use @[] here.
return [NSArray arrayWithObjects:preferencesItem, aboutItem, aboutQtItem, lastAppSpecificItem, nil];
}
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
index 955b147bfd..b4af4a6e01 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
@@ -81,20 +81,20 @@ QCocoaNativeInterface::QCocoaNativeInterface()
void *QCocoaNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context)
{
if (!context)
- return 0;
+ return nullptr;
if (resourceString.toLower() == "nsopenglcontext")
return nsOpenGLContextForContext(context);
if (resourceString.toLower() == "cglcontextobj")
return cglContextForContext(context);
- return 0;
+ return nullptr;
}
#endif
void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window)
{
if (!window->handle())
- return 0;
+ return nullptr;
if (resourceString == "nsview") {
return static_cast<QCocoaWindow *>(window->handle())->m_view;
@@ -105,7 +105,7 @@ void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceS
} else if (resourceString == "nswindow") {
return static_cast<QCocoaWindow *>(window->handle())->nativeWindow();
}
- return 0;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInterface::nativeResourceFunctionForIntegration(const QByteArray &resource)
@@ -143,7 +143,7 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter
if (resource.toLower() == "testcontentborderposition")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::testContentBorderPosition);
- return 0;
+ return nullptr;
}
QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport()
@@ -152,7 +152,7 @@ QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport()
return new QCocoaPrinterSupport();
#else
qFatal("Printing is not supported when Qt is configured with -no-widgets");
- return 0;
+ return nullptr;
#endif
}
@@ -166,7 +166,7 @@ void *QCocoaNativeInterface::NSPrintInfoForPrintEngine(QPrintEngine *printEngine
#else
Q_UNUSED(printEngine);
qFatal("Printing is not supported when Qt is configured with -no-widgets");
- return 0;
+ return nullptr;
#endif
}
@@ -180,10 +180,10 @@ QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard()
CFURLRef url = (CFURLRef)CFArrayGetValueAtIndex(urls, 0);
QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, url);
if (bundle) {
- url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("png"), 0);
+ url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("png"), nullptr);
if (url) {
- QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithURL(url, 0);
- QCFType<CGImageRef> image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0);
+ QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithURL(url, nullptr);
+ QCFType<CGImageRef> image = CGImageSourceCreateImageAtIndex(imageSource, 0, nullptr);
if (image) {
int width = CGImageGetWidth(image);
int height = CGImageGetHeight(image);
@@ -213,7 +213,7 @@ void *QCocoaNativeInterface::cglContextForContext(QOpenGLContext* context)
NSOpenGLContext *nsOpenGLContext = static_cast<NSOpenGLContext*>(nsOpenGLContextForContext(context));
if (nsOpenGLContext)
return [nsOpenGLContext CGLContextObj];
- return 0;
+ return nullptr;
}
void *QCocoaNativeInterface::nsOpenGLContextForContext(QOpenGLContext* context)
@@ -224,7 +224,7 @@ void *QCocoaNativeInterface::nsOpenGLContextForContext(QOpenGLContext* context)
return cocoaGLContext->nsOpenGLContext();
}
}
- return 0;
+ return nullptr;
}
#endif
@@ -285,8 +285,9 @@ QImage QCocoaNativeInterface::cgImageToQImage(CGImageRef image)
void QCocoaNativeInterface::setEmbeddedInForeignView(QPlatformWindow *window, bool embedded)
{
+ Q_UNUSED(embedded); // "embedded" state is now automatically detected
QCocoaWindow *cocoaPlatformWindow = static_cast<QCocoaWindow *>(window);
- cocoaPlatformWindow->setEmbeddedInForeignView(embedded);
+ cocoaPlatformWindow->setEmbeddedInForeignView();
}
void QCocoaNativeInterface::registerTouchWindow(QWindow *window, bool enable)
diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.h b/src/plugins/platforms/cocoa/qcocoansmenu.h
index a9c3e4fff9..6cbb6e4a01 100644
--- a/src/plugins/platforms/cocoa/qcocoansmenu.h
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -53,12 +53,10 @@
#import <AppKit/AppKit.h>
-#include <QtCore/qpointer.h>
#include <qcocoahelpers.h>
QT_FORWARD_DECLARE_CLASS(QCocoaMenu);
-typedef QPointer<QCocoaMenu> QCocoaMenuPointer;
-
+QT_FORWARD_DECLARE_CLASS(QCocoaMenuItem);
@interface QT_MANGLE_NAMESPACE(QCocoaNSMenuDelegate) : NSObject <NSMenuDelegate>
@@ -72,18 +70,24 @@ typedef QPointer<QCocoaMenu> QCocoaMenuPointer;
@interface QT_MANGLE_NAMESPACE(QCocoaNSMenu) : NSMenu
-@property (readonly, nonatomic) QCocoaMenuPointer qpaMenu;
+@property (readonly, nonatomic) QCocoaMenu *platformMenu;
+
+- (instancetype)initWithPlatformMenu:(QCocoaMenu *)menu;
+
+@end
-- (instancetype)initWithQPAMenu:(QCocoaMenu *)menu;
+@interface QT_MANGLE_NAMESPACE(QCocoaNSMenuItem) : NSMenuItem
-- (void)qt_itemFired:(NSMenuItem *)item;
+@property (nonatomic) QCocoaMenuItem *platformMenuItem;
-- (BOOL)worksWhenModal;
-- (BOOL)validateMenuItem:(NSMenuItem*)item; // NSMenuValidation
++ (instancetype)separatorItemWithPlatformMenuItem:(QCocoaMenuItem *)menuItem;
+- (instancetype)initWithPlatformMenuItem:(QCocoaMenuItem *)menuItem;
+- (instancetype)init;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaNSMenu);
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaNSMenuItem);
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaNSMenuDelegate);
#endif // QCOCOANSMENU_H
diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.mm b/src/plugins/platforms/cocoa/qcocoansmenu.mm
index 19a0f950e4..752f38d68d 100644
--- a/src/plugins/platforms/cocoa/qcocoansmenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.mm
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -44,17 +44,15 @@
#include "qcocoawindow.h"
#import "qnsview.h"
-#include <QtCore/qmetaobject.h>
-#include <QtCore/private/qthread_p.h>
-#include <QtGui/private/qguiapplication_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcoreevent.h>
-static NSString *qt_mac_removePrivateUnicode(NSString* string)
+static NSString *qt_mac_removePrivateUnicode(NSString *string)
{
- int len = [string length];
- if (len) {
- QVarLengthArray <unichar, 10> characters(len);
+ if (const int len = string.length) {
+ QVarLengthArray<unichar, 10> characters(len);
bool changed = false;
- for (int i = 0; i<len; i++) {
+ for (int i = 0; i < len; i++) {
characters[i] = [string characterAtIndex:i];
// check if they belong to key codes in private unicode range
// currently we need to handle only the NSDeleteFunctionKey
@@ -70,11 +68,14 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
}
@implementation QCocoaNSMenu
+{
+ QPointer<QCocoaMenu> _platformMenu;
+}
-- (instancetype)initWithQPAMenu:(QCocoaMenu *)menu
+- (instancetype)initWithPlatformMenu:(QCocoaMenu *)menu
{
if ((self = [super initWithTitle:@"Untitled"])) {
- _qpaMenu = menu;
+ _platformMenu = menu;
self.autoenablesItems = YES;
self.delegate = [QCocoaNSMenuDelegate sharedMenuDelegate];
}
@@ -82,46 +83,58 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
return self;
}
-// Cocoa will query the menu item's target for the worksWhenModal selector.
-// So we need to implement this to allow the items to be handled correctly
-// when a modal dialog is visible. See documentation for NSMenuItem.target.
-- (BOOL)worksWhenModal
+- (QCocoaMenu *)platformMenu
{
- if (!QGuiApplication::modalWindow())
- return YES;
- if (const auto *mb = qobject_cast<QCocoaMenuBar *>(self.qpaMenu->menuParent()))
- return QGuiApplication::modalWindow()->handle() == mb->cocoaWindow() ? YES : NO;
- return YES;
+ return _platformMenu.data();
}
-- (void)qt_itemFired:(NSMenuItem *)item
+@end
+
+@implementation QCocoaNSMenuItem
{
- auto *qpaItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
- // Menu-holding items also get a target to play nicely
- // with NSMenuValidation but should not trigger.
- if (!qpaItem || qpaItem->menu())
- return;
+ QPointer<QCocoaMenuItem> _platformMenuItem;
+}
- QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
- QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
++ (instancetype)separatorItemWithPlatformMenuItem:(QCocoaMenuItem *)menuItem
+{
+ // Safe because +[NSMenuItem separatorItem] invokes [[self alloc] init]
+ auto *item = qt_objc_cast<QCocoaNSMenuItem *>([self separatorItem]);
+ Q_ASSERT_X(item, qPrintable(__FUNCTION__),
+ "Did +[NSMenuItem separatorItem] not invoke [[self alloc] init]?");
+ if (item)
+ item.platformMenuItem = menuItem;
+
+ return item;
+}
- static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
- activatedSignal.invoke(qpaItem, Qt::QueuedConnection);
+- (instancetype)initWithPlatformMenuItem:(QCocoaMenuItem *)menuItem
+{
+ if ((self = [super initWithTitle:@"" action:nil keyEquivalent:@""])) {
+ _platformMenuItem = menuItem;
+ }
+
+ return self;
}
-- (BOOL)validateMenuItem:(NSMenuItem*)item
+- (instancetype)init
{
- auto *qpaItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
- // Menu-holding items are always enabled, as it's conventional in Cocoa
- if (!qpaItem || qpaItem->menu())
- return YES;
+ return [self initWithPlatformMenuItem:nullptr];
+}
- return qpaItem->isEnabled();
+- (QCocoaMenuItem *)platformMenuItem
+{
+ return _platformMenuItem.data();
+}
+
+- (void)setPlatformMenuItem:(QCocoaMenuItem *)menuItem
+{
+ _platformMenuItem = menuItem;
}
@end
-#define CHECK_MENU_CLASS(menu) Q_ASSERT([menu isMemberOfClass:[QCocoaNSMenu class]])
+#define CHECK_MENU_CLASS(menu) Q_ASSERT_X([menu isMemberOfClass:[QCocoaNSMenu class]], \
+ __FUNCTION__, "Menu is not a QCocoaNSMenu")
@implementation QCocoaNSMenuDelegate
@@ -153,14 +166,15 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
if (shouldCancel)
return NO;
- const auto &qpaMenu = static_cast<QCocoaNSMenu *>(menu).qpaMenu;
- if (qpaMenu.isNull())
+ const auto &platformMenu = static_cast<QCocoaNSMenu *>(menu).platformMenu;
+ if (!platformMenu)
return YES;
- auto *menuItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
- if (qpaMenu->items().contains(menuItem)) {
- if (QCocoaMenu *itemSubmenu = menuItem->menu())
- itemSubmenu->setAttachedItem(item);
+ if (auto *platformItem = qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem) {
+ if (platformMenu->items().contains(platformItem)) {
+ if (auto *itemSubmenu = platformItem->menu())
+ itemSubmenu->setAttachedItem(item);
+ }
}
return YES;
@@ -169,32 +183,31 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
- (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item
{
CHECK_MENU_CLASS(menu);
- auto *qpaItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
- if (qpaItem)
- qpaItem->hovered();
+ if (auto *platformItem = qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem)
+ emit platformItem->hovered();
}
- (void)menuWillOpen:(NSMenu *)menu
{
CHECK_MENU_CLASS(menu);
- const auto &qpaMenu = static_cast<QCocoaNSMenu *>(menu).qpaMenu;
- if (qpaMenu.isNull())
+ auto *platformMenu = static_cast<QCocoaNSMenu *>(menu).platformMenu;
+ if (!platformMenu)
return;
- qpaMenu->setIsOpen(true);
- emit qpaMenu->aboutToShow();
+ platformMenu->setIsOpen(true);
+ emit platformMenu->aboutToShow();
}
- (void)menuDidClose:(NSMenu *)menu
{
CHECK_MENU_CLASS(menu);
- const auto &qpaMenu = static_cast<QCocoaNSMenu *>(menu).qpaMenu;
- if (qpaMenu.isNull())
+ auto *platformMenu = static_cast<QCocoaNSMenu *>(menu).platformMenu;
+ if (!platformMenu)
return;
- qpaMenu->setIsOpen(false);
+ platformMenu->setIsOpen(false);
// wrong, but it's the best we can do
- emit qpaMenu->aboutToHide();
+ emit platformMenu->aboutToHide();
}
- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action
@@ -229,30 +242,17 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
}
if (keyEquivalentItem) {
- if (!keyEquivalentItem.target) {
- // This item was modified by QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder
- // and it looks like we're running a modal session for NSOpenPanel/NSSavePanel.
- // QCocoaFileDialogHelper is actually the only place we use this and we run NSOpenPanel modal
- // (modal sheet, window modal, application modal).
- // Whatever the current first responder is, let's give it a chance
- // and do not touch the Qt's focusObject (which is different from some native view
- // having a focus inside NSSave/OpenPanel.
- *target = nil;
- *action = keyEquivalentItem.action;
- return YES;
- }
-
QObject *object = qApp->focusObject();
if (object) {
QChar ch;
int keyCode;
- ulong nativeModifiers = [event modifierFlags];
- Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers];
- NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers];
- NSString *characters = [event characters];
+ ulong nativeModifiers = event.modifierFlags;
+ Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers:nativeModifiers];
+ NSString *charactersIgnoringModifiers = event.charactersIgnoringModifiers;
+ NSString *characters = event.characters;
- if ([charactersIgnoringModifiers length] > 0) { // convert the first character into a key code
- if ((modifiers & Qt::ControlModifier) && ([characters length] != 0)) {
+ if (charactersIgnoringModifiers.length > 0) { // convert the first character into a key code
+ if ((modifiers & Qt::ControlModifier) && characters.length > 0) {
ch = QChar([characters characterAtIndex:0]);
} else {
ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
@@ -269,7 +269,7 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
accel_ev.ignore();
QCoreApplication::sendEvent(object, &accel_ev);
if (accel_ev.isAccepted()) {
- [[NSApp keyWindow] sendEvent: event];
+ [[NSApp keyWindow] sendEvent:event];
*target = nil;
*action = nil;
return YES;
diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
index bfe6cd09b6..24ec7ca9a4 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
+++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
@@ -67,17 +67,17 @@ static QPrint::DuplexMode macToDuplexMode(const PMDuplexMode &mode)
QCocoaPrintDevice::QCocoaPrintDevice()
: QPlatformPrintDevice(),
- m_printer(0),
- m_session(0),
- m_ppd(0)
+ m_printer(nullptr),
+ m_session(nullptr),
+ m_ppd(nullptr)
{
}
QCocoaPrintDevice::QCocoaPrintDevice(const QString &id)
: QPlatformPrintDevice(id),
- m_printer(0),
- m_session(0),
- m_ppd(0)
+ m_printer(nullptr),
+ m_session(nullptr),
+ m_ppd(nullptr)
{
if (!id.isEmpty()) {
m_printer = PMPrinterCreateFromPrinterID(id.toCFString());
@@ -411,7 +411,7 @@ QPrint::ColorMode QCocoaPrintDevice::defaultColorMode() const
ppd_option_t *colorModel = ppdFindOption(m_ppd, "DefaultColorModel");
if (!colorModel)
colorModel = ppdFindOption(m_ppd, "ColorModel");
- if (!colorModel || (colorModel && !qstrcmp(colorModel->defchoice, "Gray")))
+ if (!colorModel || qstrcmp(colorModel->defchoice, "Gray") != 0)
return QPrint::Color;
}
return QPrint::GrayScale;
@@ -443,11 +443,11 @@ bool QCocoaPrintDevice::openPpdFile()
{
if (m_ppd)
ppdClose(m_ppd);
- m_ppd = 0;
- CFURLRef ppdURL = NULL;
+ m_ppd = nullptr;
+ CFURLRef ppdURL = nullptr;
char ppdPath[MAXPATHLEN];
if (PMPrinterCopyDescriptionURL(m_printer, kPMPPDDescriptionType, &ppdURL) == noErr
- && ppdURL != NULL) {
+ && ppdURL) {
if (CFURLGetFileSystemRepresentation(ppdURL, true, (UInt8*)ppdPath, sizeof(ppdPath)))
m_ppd = ppdOpenFile(ppdPath);
CFRelease(ppdURL);
@@ -470,7 +470,7 @@ PMPaper QCocoaPrintDevice::macPaper(const QPageSize &pageSize) const
if (m_macPapers.contains(pageSize.key()))
return m_macPapers.value(pageSize.key());
// For any other page size, whether custom or just unsupported, needs to be a custom PMPaper
- PMPaper paper = 0;
+ PMPaper paper = nullptr;
PMPaperMargins paperMargins;
paperMargins.left = m_customMargins.left();
paperMargins.right = m_customMargins.right();
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h
index 3d59c3de79..850ccaad7a 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.h
+++ b/src/plugins/platforms/cocoa/qcocoascreen.h
@@ -104,5 +104,9 @@ QDebug operator<<(QDebug debug, const QCocoaScreen *screen);
QT_END_NAMESPACE
+@interface NSScreen (QtExtras)
+@property(readonly) CGDirectDisplayID qt_displayId;
+@end
+
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
index a17a02b629..d639b56064 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.mm
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -66,7 +66,7 @@ QCocoaScreen::~QCocoaScreen()
NSScreen *QCocoaScreen::nativeScreen() const
{
- NSArray *screens = [NSScreen screens];
+ NSArray<NSScreen *> *screens = [NSScreen screens];
// Stale reference, screen configuration has changed
if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count])
@@ -121,8 +121,7 @@ void QCocoaScreen::updateGeometry()
m_format = QImage::Format_RGB32;
m_depth = NSBitsPerPixelFromDepth([nsScreen depth]);
- NSDictionary *devDesc = [nsScreen deviceDescription];
- CGDirectDisplayID dpy = [[devDesc objectForKey:@"NSScreenNumber"] unsignedIntValue];
+ CGDirectDisplayID dpy = nsScreen.qt_displayId;
CGSize size = CGDisplayScreenSize(dpy);
m_physicalSize = QSizeF(size.width, size.height);
m_logicalDpi.first = 72;
@@ -165,7 +164,7 @@ QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
// belowWindowWithWindowNumber] may return windows that are not interesting
// to Qt. The search iterates until a suitable window or no window is found.
NSInteger topWindowNumber = 0;
- QWindow *window = 0;
+ QWindow *window = nullptr;
do {
// Get the top-most window, below any previously rejected window.
topWindowNumber = [NSWindow windowNumberAtPoint:screenPoint
@@ -173,7 +172,7 @@ QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
// Continue the search if the window does not belong to this process.
NSWindow *nsWindow = [NSApp windowWithWindowNumber:topWindowNumber];
- if (nsWindow == 0)
+ if (!nsWindow)
continue;
// Continue the search if the window does not belong to Qt.
@@ -310,3 +309,12 @@ QDebug operator<<(QDebug debug, const QCocoaScreen *screen)
#endif // !QT_NO_DEBUG_STREAM
QT_END_NAMESPACE
+
+@implementation NSScreen (QtExtras)
+
+- (CGDirectDisplayID)qt_displayId
+{
+ return [self.deviceDescription[@"NSScreenNumber"] unsignedIntValue];
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
index bad91a2d5d..65a9a214a2 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
@@ -131,7 +131,7 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
QColor qc;
for (int i = 0; i < mac_widget_colors_count; i++) {
QPalette &pal = *qt_mac_createSystemPalette();
- if (mac_widget_colors[i].active != 0) {
+ if (mac_widget_colors[i].active) {
qc = qt_mac_toQColor(mac_widget_colors[i].active);
pal.setColor(QPalette::Active, QPalette::Text, qc);
pal.setColor(QPalette::Inactive, QPalette::Text, qc);
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
index 2f1a1e42a9..d831612c22 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
@@ -55,7 +55,7 @@ class QSystemTrayIconSys;
class Q_GUI_EXPORT QCocoaSystemTrayIcon : public QPlatformSystemTrayIcon
{
public:
- QCocoaSystemTrayIcon() : m_sys(0) {}
+ QCocoaSystemTrayIcon() : m_sys(nullptr) {}
void init() override;
void cleanup() override;
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 5e6913a89a..773f4b833f 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -95,31 +95,16 @@ QT_USE_NAMESPACE
@class QT_MANGLE_NAMESPACE(QNSImageView);
@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject <NSUserNotificationCenterDelegate>
-{
-@public
- QCocoaSystemTrayIcon *systray;
- NSStatusItem *item;
- QCocoaMenu *menu;
- QIcon icon;
- QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
-}
--(id)initWithSysTray:(QCocoaSystemTrayIcon *)systray;
--(void)dealloc;
--(NSStatusItem*)item;
--(QRectF)geometry;
+@property (nonatomic, assign) QCocoaMenu *menu;
+@property (nonatomic, assign) QIcon icon;
+@property (nonatomic, readonly) NSStatusItem *item;
+@property (nonatomic, readonly) QRectF geometry;
+- (instancetype)initWithSysTray:(QCocoaSystemTrayIcon *)systray;
- (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton;
- (void)doubleClickSelector:(id)sender;
-- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification;
-- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
@end
-@interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView {
- BOOL down;
- QT_MANGLE_NAMESPACE(QNSStatusItem) *parent;
-}
--(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent;
--(void)menuTrackingDone:(NSNotification*)notification;
--(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton;
+@interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem);
@@ -162,7 +147,7 @@ QRect QCocoaSystemTrayIcon::geometry() const
void QCocoaSystemTrayIcon::cleanup()
{
delete m_sys;
- m_sys = 0;
+ m_sys = nullptr;
}
static bool heightCompareFunction (QSize a, QSize b) { return (a.height() < b.height()); }
@@ -178,7 +163,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
if (!m_sys)
return;
- m_sys->item->icon = icon;
+ m_sys->item.icon = icon;
// The reccomended maximum title bar icon height is 18 points
// (device independent pixels). The menu height on past and
@@ -249,8 +234,8 @@ void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu)
if (!m_sys)
return;
- m_sys->item->menu = static_cast<QCocoaMenu *>(menu);
- if (menu && [m_sys->item->menu->nsMenu() numberOfItems] > 0) {
+ m_sys->item.menu = static_cast<QCocoaMenu *>(menu);
+ if (menu && [m_sys->item.menu->nsMenu() numberOfItems] > 0) {
[[m_sys->item item] setHighlightMode:YES];
} else {
[[m_sys->item item] setHighlightMode:NO];
@@ -289,23 +274,29 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess
}
QT_END_NAMESPACE
-@implementation QNSImageView
--(id)initWithParent:(QNSStatusItem*)myParent {
+@implementation NSStatusItem (Qt)
+@end
+
+@implementation QNSImageView {
+ BOOL down;
+ QT_MANGLE_NAMESPACE(QNSStatusItem) *parent;
+}
+
+- (instancetype)initWithParent:(QNSStatusItem *)myParent {
self = [super init];
parent = myParent;
down = NO;
return self;
}
--(void)menuTrackingDone:(NSNotification*)notification
+- (void)menuTrackingDone:(NSNotification *)__unused notification
{
- Q_UNUSED(notification);
down = NO;
[self setNeedsDisplay:YES];
}
--(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton
+- (void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton
{
down = YES;
int clickCount = [mouseEvent clickCount];
@@ -319,12 +310,12 @@ QT_END_NAMESPACE
}
}
--(void)mouseDown:(NSEvent *)mouseEvent
+- (void)mouseDown:(NSEvent *)mouseEvent
{
[self mousePressed:mouseEvent button:Qt::LeftButton];
}
--(void)mouseUp:(NSEvent *)mouseEvent
+- (void)mouseUp:(NSEvent *)mouseEvent
{
Q_UNUSED(mouseEvent);
[self menuTrackingDone:nil];
@@ -335,7 +326,7 @@ QT_END_NAMESPACE
[self mousePressed:mouseEvent button:Qt::RightButton];
}
--(void)rightMouseUp:(NSEvent *)mouseEvent
+- (void)rightMouseUp:(NSEvent *)mouseEvent
{
Q_UNUSED(mouseEvent);
[self menuTrackingDone:nil];
@@ -346,26 +337,33 @@ QT_END_NAMESPACE
[self mousePressed:mouseEvent button:cocoaButton2QtButton([mouseEvent buttonNumber])];
}
--(void)otherMouseUp:(NSEvent *)mouseEvent
+- (void)otherMouseUp:(NSEvent *)mouseEvent
{
Q_UNUSED(mouseEvent);
[self menuTrackingDone:nil];
}
--(void)drawRect:(NSRect)rect {
+- (void)drawRect:(NSRect)rect {
[[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down];
[super drawRect:rect];
}
@end
-@implementation QNSStatusItem
+@implementation QNSStatusItem {
+ QCocoaSystemTrayIcon *systray;
+ NSStatusItem *item;
+ QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
+}
+
+@synthesize menu = menu;
+@synthesize icon = icon;
--(id)initWithSysTray:(QCocoaSystemTrayIcon *)sys
+- (instancetype)initWithSysTray:(QCocoaSystemTrayIcon *)sys
{
self = [super init];
if (self) {
item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
- menu = 0;
+ menu = nullptr;
systray = sys;
imageCell = [[QNSImageView alloc] initWithParent:self];
[item setView: imageCell];
@@ -373,19 +371,19 @@ QT_END_NAMESPACE
return self;
}
--(void)dealloc {
+- (void)dealloc {
[[NSStatusBar systemStatusBar] removeStatusItem:item];
[[NSNotificationCenter defaultCenter] removeObserver:imageCell];
[imageCell release];
[item release];
[super dealloc];
-
}
--(NSStatusItem*)item {
+- (NSStatusItem *)item {
return item;
}
--(QRectF)geometry {
+
+- (QRectF)geometry {
if (NSWindow *window = [[item view] window]) {
if (QCocoaScreen *screen = QCocoaIntegration::instance()->screenForNSScreen([window screen]))
return screen->mapFromNative([window frame]);
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index 93f0400916..0f1bfea7b5 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -75,28 +75,26 @@
#endif
#endif
-#include <Carbon/Carbon.h>
+#include <CoreServices/CoreServices.h>
-@interface QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) : NSObject {
-QCocoaTheme *mPrivate;
-}
-- (id)initWithPrivate:(QCocoaTheme *)priv;
-- (void)systemColorsDidChange:(NSNotification *)notification;
+@interface QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) : NSObject
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeNotificationReceiver);
-@implementation QCocoaThemeNotificationReceiver
-- (id)initWithPrivate:(QCocoaTheme *)priv
+@implementation QCocoaThemeNotificationReceiver {
+ QCocoaTheme *mPrivate;
+}
+
+- (instancetype)initWithPrivate:(QCocoaTheme *)priv
{
- self = [super init];
- mPrivate = priv;
+ if ((self = [self init]))
+ mPrivate = priv;
return self;
}
-- (void)systemColorsDidChange:(NSNotification *)notification
+- (void)systemColorsDidChange:(NSNotification *)__unused notification
{
- Q_UNUSED(notification);
mPrivate->reset();
QWindowSystemInterface::handleThemeChange(nullptr);
}
@@ -107,7 +105,7 @@ QT_BEGIN_NAMESPACE
const char *QCocoaTheme::name = "cocoa";
QCocoaTheme::QCocoaTheme()
- :m_systemPalette(0)
+ : m_systemPalette(nullptr)
{
m_notificationReceiver = [[QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) alloc] initWithPrivate:this];
[[NSNotificationCenter defaultCenter] addObserver:m_notificationReceiver
@@ -147,7 +145,7 @@ bool QCocoaTheme::usePlatformNativeDialog(DialogType dialogType) const
return false;
}
-QPlatformDialogHelper * QCocoaTheme::createPlatformDialogHelper(DialogType dialogType) const
+QPlatformDialogHelper *QCocoaTheme::createPlatformDialogHelper(DialogType dialogType) const
{
switch (dialogType) {
#if defined(QT_WIDGETS_LIB) && QT_CONFIG(filedialog)
@@ -163,7 +161,7 @@ QPlatformDialogHelper * QCocoaTheme::createPlatformDialogHelper(DialogType dialo
return new QCocoaFontDialogHelper();
#endif
default:
- return 0;
+ return nullptr;
}
}
@@ -183,9 +181,9 @@ const QPalette *QCocoaTheme::palette(Palette type) const
} else {
if (m_palettes.isEmpty())
m_palettes = qt_mac_createRolePalettes();
- return m_palettes.value(type, 0);
+ return m_palettes.value(type, nullptr);
}
- return 0;
+ return nullptr;
}
QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts()
@@ -199,7 +197,7 @@ const QFont *QCocoaTheme::font(Font type) const
if (m_fonts.isEmpty()) {
m_fonts = qt_mac_createRoleFonts();
}
- return m_fonts.value(type, 0);
+ return m_fonts.value(type, nullptr);
}
//! \internal
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index fb91c53a7a..feaade1bd6 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -112,6 +112,7 @@ public:
void raise() override;
void lower() override;
bool isExposed() const override;
+ bool isEmbedded() const override;
bool isOpaque() const;
void propagateSizeHints() override;
void setOpacity(qreal level) override;
@@ -124,6 +125,8 @@ public:
bool isForeignWindow() const override;
void requestUpdate() override;
+ void deliverUpdateRequest() override;
+
void requestActivateWindow() override;
WId winId() const override;
@@ -132,7 +135,7 @@ public:
NSView *view() const;
NSWindow *nativeWindow() const;
- void setEmbeddedInForeignView(bool subwindow);
+ void setEmbeddedInForeignView();
Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame();
Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame();
@@ -237,11 +240,6 @@ public: // for QNSView
NSView *m_view;
QCocoaNSWindow *m_nsWindow;
- // TODO merge to one variable if possible
- bool m_viewIsEmbedded; // true if the m_view is actually embedded in a "foreign" NSView hiearchy
- bool m_viewIsToBeEmbedded; // true if the m_view is intended to be embedded in a "foreign" NSView hiearchy
-
- Qt::WindowFlags m_windowFlags;
Qt::WindowStates m_lastReportedWindowState;
Qt::WindowModality m_windowModality;
QPointer<QWindow> m_enterLeaveTargetWindow;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 1e311ed388..7e7740527f 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -117,24 +117,19 @@ static void qRegisterNotificationCallbacks()
return;
}
- if (lcCocoaNotifications().isDebugEnabled()) {
- if (cocoaWindows.isEmpty()) {
- qCDebug(lcCocoaNotifications) << "Could not find forwarding target for" <<
- qPrintable(notificationName) << "from" << notification.object;
- } else {
- QVector<QCocoaWindow *> debugWindows;
- for (QCocoaWindow *cocoaWindow : cocoaWindows)
- debugWindows += cocoaWindow;
- qCDebug(lcCocoaNotifications) << "Forwarding" << qPrintable(notificationName) <<
- "to" << debugWindows;
- }
+ if (lcCocoaNotifications().isDebugEnabled() && !cocoaWindows.isEmpty()) {
+ QVector<QCocoaWindow *> debugWindows;
+ for (QCocoaWindow *cocoaWindow : cocoaWindows)
+ debugWindows += cocoaWindow;
+ qCDebug(lcCocoaNotifications) << "Forwarding" << qPrintable(notificationName) <<
+ "to" << debugWindows;
}
// FIXME: Could be a foreign window, look up by iterating top level QWindows
for (QCocoaWindow *cocoaWindow : cocoaWindows) {
if (!method.invoke(cocoaWindow, Qt::DirectConnection)) {
- qCWarning(lcQpaCocoaWindow) << "Failed to invoke NSNotification callback for"
+ qCWarning(lcQpaWindow) << "Failed to invoke NSNotification callback for"
<< notification.name << "on" << cocoaWindow;
}
}
@@ -148,9 +143,7 @@ const int QCocoaWindow::NoAlertRequest = -1;
QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
: QPlatformWindow(win)
, m_view(nil)
- , m_nsWindow(0)
- , m_viewIsEmbedded(false)
- , m_viewIsToBeEmbedded(false)
+ , m_nsWindow(nil)
, m_lastReportedWindowState(Qt::WindowNoState)
, m_windowModality(Qt::NonModal)
, m_windowUnderMouse(false)
@@ -159,9 +152,9 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
, m_inSetGeometry(false)
, m_inSetStyleMask(false)
#ifndef QT_NO_OPENGL
- , m_glContext(0)
+ , m_glContext(nullptr)
#endif
- , m_menubar(0)
+ , m_menubar(nullptr)
, m_needsInvalidateShadow(false)
, m_hasModalSession(false)
, m_frameStrutEventsEnabled(false)
@@ -173,7 +166,7 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
, m_topContentBorderThickness(0)
, m_bottomContentBorderThickness(0)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::QCocoaWindow" << window();
if (nativeHandle) {
m_view = reinterpret_cast<NSView *>(nativeHandle);
@@ -183,7 +176,7 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
void QCocoaWindow::initialize()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::initialize" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::initialize" << window();
QMacAutoReleasePool pool;
@@ -200,9 +193,6 @@ void QCocoaWindow::initialize()
[m_view setWantsBestResolutionOpenGLSurface:enable];
// See also QCocoaGLContext::makeCurrent for software renderer workarounds.
}
- BOOL enable = qt_mac_resolveOption(NO, window(), "_q_mac_wantsLayer",
- "QT_MAC_WANTS_LAYER");
- [m_view setWantsLayer:enable];
}
setGeometry(initialGeometry(window(), windowGeometry(), defaultWindowWidth, defaultWindowHeight));
@@ -217,7 +207,7 @@ void QCocoaWindow::initialize()
QCocoaWindow::~QCocoaWindow()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::~QCocoaWindow" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::~QCocoaWindow" << window();
QMacAutoReleasePool pool;
[m_nsWindow makeFirstResponder:nil];
@@ -255,7 +245,7 @@ QSurfaceFormat QCocoaWindow::format() const
void QCocoaWindow::setGeometry(const QRect &rectIn)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setGeometry" << window() << rectIn;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setGeometry" << window() << rectIn;
QBoolBlocker inSetGeometry(m_inSetGeometry, true);
@@ -283,7 +273,7 @@ QRect QCocoaWindow::geometry() const
// QWindows that are embedded in a NSView hiearchy may be considered
// top-level from Qt's point of view but are not from Cocoa's point
// of view. Embedded QWindows get global (screen) geometry.
- if (m_viewIsEmbedded) {
+ if (isEmbedded()) {
NSPoint windowPoint = [m_view convertPoint:NSMakePoint(0, 0) toView:nil];
NSRect screenRect = [[m_view window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
NSPoint screenPoint = screenRect.origin;
@@ -297,12 +287,12 @@ QRect QCocoaWindow::geometry() const
void QCocoaWindow::setCocoaGeometry(const QRect &rect)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setCocoaGeometry" << window() << rect;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setCocoaGeometry" << window() << rect;
QMacAutoReleasePool pool;
QPlatformWindow::setGeometry(rect);
- if (m_viewIsEmbedded) {
+ if (isEmbedded()) {
if (!isForeignWindow()) {
[m_view setFrame:NSMakeRect(0, 0, rect.width(), rect.height())];
}
@@ -321,12 +311,12 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
void QCocoaWindow::setVisible(bool visible)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setVisible" << window() << visible;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setVisible" << window() << visible;
m_inSetVisible = true;
QMacAutoReleasePool pool;
- QCocoaWindow *parentCocoaWindow = 0;
+ QCocoaWindow *parentCocoaWindow = nullptr;
if (window()->transientParent())
parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle());
@@ -378,13 +368,13 @@ void QCocoaWindow::setVisible(bool visible)
} else if (window()->modality() != Qt::NonModal) {
// show the window as application modal
QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
- Q_ASSERT(cocoaEventDispatcher != 0);
+ Q_ASSERT(cocoaEventDispatcher);
QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
cocoaEventDispatcherPrivate->beginModalSession(window());
m_hasModalSession = true;
} else if ([m_view.window canBecomeKeyWindow]) {
QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
- QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = 0;
+ QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = nullptr;
if (cocoaEventDispatcher)
cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
@@ -425,7 +415,7 @@ void QCocoaWindow::setVisible(bool visible)
m_glContext->windowWasHidden();
#endif
QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
- QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = 0;
+ QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = nullptr;
if (cocoaEventDispatcher)
cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
if (isContentView()) {
@@ -493,7 +483,8 @@ NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags)
// Any "special" window should be in at least the same level as its parent.
if (type != Qt::Window) {
const QWindow * const transientParent = window()->transientParent();
- const QCocoaWindow * const transientParentWindow = transientParent ? static_cast<QCocoaWindow *>(transientParent->handle()) : 0;
+ const QCocoaWindow * const transientParentWindow = transientParent ?
+ static_cast<QCocoaWindow *>(transientParent->handle()) : nullptr;
if (transientParentWindow)
windowLevel = qMax([transientParentWindow->nativeWindow() level], windowLevel);
}
@@ -557,46 +548,49 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags)
void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
{
- if (isContentView()) {
- // While setting style mask we can have handleGeometryChange calls on a content
- // view with null geometry, reporting an invalid coordinates as a result.
- m_inSetStyleMask = true;
- m_view.window.styleMask = windowStyleMask(flags);
- m_inSetStyleMask = false;
- m_view.window.level = this->windowLevel(flags);
-
- m_view.window.hasShadow = !(flags & Qt::NoDropShadowWindowHint);
-
- if (!(flags & Qt::FramelessWindowHint))
- setWindowTitle(window()->title());
-
- Qt::WindowType type = window()->type();
- if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) {
- NSWindowCollectionBehavior behavior = m_view.window.collectionBehavior;
- if (flags & Qt::WindowFullscreenButtonHint) {
- behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
- behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
- } else {
- behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
- behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
- }
- m_view.window.collectionBehavior = behavior;
+ if (!isContentView())
+ return;
+
+ // While setting style mask we can have handleGeometryChange calls on a content
+ // view with null geometry, reporting an invalid coordinates as a result.
+ m_inSetStyleMask = true;
+ m_view.window.styleMask = windowStyleMask(flags);
+ m_inSetStyleMask = false;
+
+ Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
+ if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) {
+ NSWindowCollectionBehavior behavior = m_view.window.collectionBehavior;
+ if (flags & Qt::WindowFullscreenButtonHint) {
+ behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
+ behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
+ } else {
+ behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
+ behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
}
- setWindowZoomButton(flags);
-
- // Make window ignore mouse events if WindowTransparentForInput is set.
- // Note that ignoresMouseEvents has a special initial state where events
- // are ignored (passed through) based on window transparency, and that
- // setting the property to false does not return us to that state. Instead,
- // this makes the window capture all mouse events. Take care to only
- // set the property if needed. FIXME: recreate window if needed or find
- // some other way to implement WindowTransparentForInput.
- bool ignoreMouse = flags & Qt::WindowTransparentForInput;
- if (m_view.window.ignoresMouseEvents != ignoreMouse)
- m_view.window.ignoresMouseEvents = ignoreMouse;
+ m_view.window.collectionBehavior = behavior;
}
- m_windowFlags = flags;
+ // Set styleMask and collectionBehavior before applying window level, as
+ // the window level change will trigger verification of the two properties.
+ m_view.window.level = this->windowLevel(flags);
+
+ m_view.window.hasShadow = !(flags & Qt::NoDropShadowWindowHint);
+
+ if (!(flags & Qt::FramelessWindowHint))
+ setWindowTitle(window()->title());
+
+ setWindowZoomButton(flags);
+
+ // Make window ignore mouse events if WindowTransparentForInput is set.
+ // Note that ignoresMouseEvents has a special initial state where events
+ // are ignored (passed through) based on window transparency, and that
+ // setting the property to false does not return us to that state. Instead,
+ // this makes the window capture all mouse events. Take care to only
+ // set the property if needed. FIXME: recreate window if needed or find
+ // some other way to implement WindowTransparentForInput.
+ bool ignoreMouse = flags & Qt::WindowTransparentForInput;
+ if (m_view.window.ignoresMouseEvents != ignoreMouse)
+ m_view.window.ignoresMouseEvents = ignoreMouse;
}
void QCocoaWindow::setWindowState(Qt::WindowStates state)
@@ -675,7 +669,7 @@ bool QCocoaWindow::isAlertState() const
void QCocoaWindow::raise()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::raise" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::raise" << window();
// ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm)
if (!isContentView())
@@ -700,7 +694,7 @@ void QCocoaWindow::raise()
void QCocoaWindow::lower()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::lower" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::lower" << window();
if (!isContentView())
return;
@@ -713,6 +707,22 @@ bool QCocoaWindow::isExposed() const
return !m_exposedRect.isEmpty();
}
+bool QCocoaWindow::isEmbedded() const
+{
+ // Child QWindows are not embedded
+ if (window()->parent())
+ return false;
+
+ // Top-level QWindows with non-Qt NSWindows are embedded
+ if (m_view.window)
+ return !([m_view.window isKindOfClass:[QNSWindow class]] ||
+ [m_view.window isKindOfClass:[QNSPanel class]]);
+
+ // The window has no QWindow parent but also no NSWindow,
+ // conservatively reuturn false.
+ return false;
+}
+
bool QCocoaWindow::isOpaque() const
{
// OpenGL surfaces can be ordered either above(default) or below the NSWindow.
@@ -732,7 +742,7 @@ void QCocoaWindow::propagateSizeHints()
if (!isContentView())
return;
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::propagateSizeHints" << window()
+ qCDebug(lcQpaWindow) << "QCocoaWindow::propagateSizeHints" << window()
<< "min:" << windowMinimumSize() << "max:" << windowMaximumSize()
<< "increment:" << windowSizeIncrement()
<< "base:" << windowBaseSize();
@@ -749,7 +759,7 @@ void QCocoaWindow::propagateSizeHints()
window.contentMaxSize = NSSizeFromCGSize(windowMaximumSize().toCGSize());
// The window may end up with a fixed size; in this case the zoom button should be disabled.
- setWindowZoomButton(m_windowFlags);
+ setWindowZoomButton(this->window()->flags());
// sizeIncrement is observed to take values of (-1, -1) and (0, 0) for windows that should be
// resizable and that have no specific size increment set. Cocoa expects (1.0, 1.0) in this case.
@@ -766,7 +776,7 @@ void QCocoaWindow::propagateSizeHints()
void QCocoaWindow::setOpacity(qreal level)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setOpacity" << level;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setOpacity" << level;
if (!isContentView())
return;
@@ -775,7 +785,7 @@ void QCocoaWindow::setOpacity(qreal level)
void QCocoaWindow::setMask(const QRegion &region)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setMask" << window() << region;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setMask" << window() << region;
if (m_view.layer) {
if (!region.isEmpty()) {
@@ -809,7 +819,7 @@ void QCocoaWindow::setMask(const QRegion &region)
bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setKeyboardGrabEnabled" << window() << grab;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setKeyboardGrabEnabled" << window() << grab;
if (!isContentView())
return false;
@@ -821,7 +831,7 @@ bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
bool QCocoaWindow::setMouseGrabEnabled(bool grab)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setMouseGrabEnabled" << window() << grab;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setMouseGrabEnabled" << window() << grab;
if (!isContentView())
return false;
@@ -838,10 +848,10 @@ WId QCocoaWindow::winId() const
void QCocoaWindow::setParent(const QPlatformWindow *parentWindow)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setParent" << window() << (parentWindow ? parentWindow->window() : 0);
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setParent" << window() << (parentWindow ? parentWindow->window() : 0);
// recreate the window for compatibility
- bool unhideAfterRecreate = parentWindow && !m_viewIsToBeEmbedded && ![m_view isHidden];
+ bool unhideAfterRecreate = parentWindow && !isEmbedded() && ![m_view isHidden];
recreateWindowIfNeeded();
if (unhideAfterRecreate)
[m_view setHidden:NO];
@@ -858,9 +868,8 @@ NSWindow *QCocoaWindow::nativeWindow() const
return m_view.window;
}
-void QCocoaWindow::setEmbeddedInForeignView(bool embedded)
+void QCocoaWindow::setEmbeddedInForeignView()
{
- m_viewIsToBeEmbedded = embedded;
// Release any previosly created NSWindow.
[m_nsWindow closeAndRelease];
m_nsWindow = 0;
@@ -943,8 +952,8 @@ void QCocoaWindow::windowDidBecomeKey()
QWindowSystemInterface::handleEnterEvent(m_enterLeaveTargetWindow, windowPoint, screenPoint);
}
- if (!windowIsPopupType() && !qnsview_cast(m_view).isMenuView)
- QWindowSystemInterface::handleWindowActivated(window());
+ if (!windowIsPopupType())
+ QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(window());
}
void QCocoaWindow::windowDidResignKey()
@@ -961,8 +970,8 @@ void QCocoaWindow::windowDidResignKey()
NSWindow *keyWindow = [NSApp keyWindow];
if (!keyWindow || keyWindow == m_view.window) {
// No new key window, go ahead and set the active window to zero
- if (!windowIsPopupType() && !qnsview_cast(m_view).isMenuView)
- QWindowSystemInterface::handleWindowActivated(0);
+ if (!windowIsPopupType())
+ QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(0);
}
}
@@ -1002,7 +1011,7 @@ void QCocoaWindow::windowDidEnterFullScreen()
"FullScreen category processes window notifications first");
// Reset to original styleMask
- setWindowFlags(m_windowFlags);
+ setWindowFlags(window()->flags());
handleWindowStateChanged();
}
@@ -1026,7 +1035,7 @@ void QCocoaWindow::windowDidExitFullScreen()
"FullScreen category processes window notifications first");
// Reset to original styleMask
- setWindowFlags(m_windowFlags);
+ setWindowFlags(window()->flags());
Qt::WindowState requestedState = window()->windowState();
@@ -1078,7 +1087,7 @@ void QCocoaWindow::windowWillClose()
bool QCocoaWindow::windowShouldClose()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::windowShouldClose" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::windowShouldClose" << window();
// This callback should technically only determine if the window
// should (be allowed to) close, but since our QPA API to determine
// that also involves actually closing the window we do both at the
@@ -1099,22 +1108,14 @@ void QCocoaWindow::handleGeometryChange()
if (!m_initialized)
return;
- // Don't send the geometry change if the QWindow is designated to be
- // embedded in a foreign view hierarchy but has not actually been
- // embedded yet - it's too early.
- if (m_viewIsToBeEmbedded && !m_viewIsEmbedded)
- return;
-
// It can happen that the current NSWindow is nil (if we are changing styleMask
// from/to borderless, and the content view is being re-parented), which results
// in invalid coordinates.
if (m_inSetStyleMask && !m_view.window)
return;
- const bool isEmbedded = m_viewIsToBeEmbedded || m_viewIsEmbedded;
-
QRect newGeometry;
- if (isContentView() && !isEmbedded) {
+ if (isContentView() && !isEmbedded()) {
// Content views are positioned at (0, 0) in the window, so we resolve via the window
CGRect contentRect = [m_view.window contentRectForFrameRect:m_view.window.frame];
@@ -1125,7 +1126,7 @@ void QCocoaWindow::handleGeometryChange()
newGeometry = QRectF::fromCGRect(m_view.frame).toRect();
}
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleGeometryChange" << window()
+ qCDebug(lcQpaWindow) << "QCocoaWindow::handleGeometryChange" << window()
<< "current" << geometry() << "new" << newGeometry;
QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
@@ -1157,7 +1158,7 @@ void QCocoaWindow::handleExposeEvent(const QRegion &region)
m_exposedRect = QRect();
}
- qCDebug(lcQpaCocoaDrawing) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed();
+ qCDebug(lcQpaDrawing) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed();
QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(window(), region);
}
@@ -1167,7 +1168,7 @@ void QCocoaWindow::handleWindowStateChanged(HandleFlags flags)
if (!(flags & HandleUnconditionally) && currentState == m_lastReportedWindowState)
return;
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleWindowStateChanged" <<
+ qCDebug(lcQpaWindow) << "QCocoaWindow::handleWindowStateChanged" <<
m_lastReportedWindowState << "-->" << currentState;
QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(
@@ -1225,6 +1226,7 @@ void QCocoaWindow::recreateWindowIfNeeded()
QPlatformWindow *parentWindow = QPlatformWindow::parent();
+ const bool isEmbeddedView = isEmbedded();
RecreationReasons recreateReason = RecreationNotNeeded;
QCocoaWindow *oldParentCocoaWindow = nullptr;
@@ -1241,7 +1243,7 @@ void QCocoaWindow::recreateWindowIfNeeded()
if (m_windowModality != window()->modality())
recreateReason |= WindowModalityChanged;
- const bool shouldBeContentView = !parentWindow && !(m_viewIsToBeEmbedded || m_viewIsEmbedded);
+ const bool shouldBeContentView = !parentWindow && !isEmbeddedView;
if (isContentView() != shouldBeContentView)
recreateReason |= ContentViewChanged;
@@ -1253,7 +1255,7 @@ void QCocoaWindow::recreateWindowIfNeeded()
if (isPanel != shouldBePanel)
recreateReason |= PanelChanged;
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::recreateWindowIfNeeded" << window() << recreateReason;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::recreateWindowIfNeeded" << window() << recreateReason;
if (recreateReason == RecreationNotNeeded)
return;
@@ -1263,33 +1265,28 @@ void QCocoaWindow::recreateWindowIfNeeded()
// Remove current window (if any)
if ((isContentView() && !shouldBeContentView) || (recreateReason & PanelChanged)) {
if (m_nsWindow) {
- qCDebug(lcQpaCocoaWindow) << "Getting rid of existing window" << m_nsWindow;
+ qCDebug(lcQpaWindow) << "Getting rid of existing window" << m_nsWindow;
if (m_nsWindow.observationInfo) {
- qCCritical(lcQpaCocoaWindow) << m_nsWindow << "has active key-value observers (KVO)!"
+ qCCritical(lcQpaWindow) << m_nsWindow << "has active key-value observers (KVO)!"
<< "These will stop working now that the window is recreated, and will result in exceptions"
<< "when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.";
}
[m_nsWindow closeAndRelease];
- if (isContentView()) {
+ if (isContentView() && !isEmbeddedView) {
// We explicitly disassociate m_view from the window's contentView,
// as AppKit does not automatically do this in response to removing
// the view from the NSThemeFrame subview list, so we might end up
// with a NSWindow contentView pointing to a deallocated NSView.
m_view.window.contentView = nil;
}
- m_nsWindow = 0;
+ m_nsWindow = nil;
}
}
- if (shouldBeContentView) {
- bool noPreviousWindow = m_nsWindow == 0;
- QCocoaNSWindow *newWindow = nullptr;
- if (noPreviousWindow)
- newWindow = createNSWindow(shouldBePanel);
-
+ if (shouldBeContentView && !m_nsWindow) {
// Move view to new NSWindow if needed
- if (newWindow) {
- qCDebug(lcQpaCocoaWindow) << "Ensuring that" << m_view << "is content view for" << newWindow;
+ if (auto *newWindow = createNSWindow(shouldBePanel)) {
+ qCDebug(lcQpaWindow) << "Ensuring that" << m_view << "is content view for" << newWindow;
[m_view setPostsFrameChangedNotifications:NO];
[newWindow setContentView:m_view];
[m_view setPostsFrameChangedNotifications:YES];
@@ -1299,7 +1296,7 @@ void QCocoaWindow::recreateWindowIfNeeded()
}
}
- if (m_viewIsToBeEmbedded) {
+ if (isEmbeddedView) {
// An embedded window doesn't have its own NSWindow.
} else if (!parentWindow) {
// QPlatformWindow subclasses must sync up with QWindow on creation:
@@ -1329,16 +1326,22 @@ void QCocoaWindow::recreateWindowIfNeeded()
// top-level QWindows may have an attached NSToolBar, call
// update function which will attach to the NSWindow.
- if (!parentWindow)
+ if (!parentWindow && !isEmbeddedView)
updateNSToolbar();
}
void QCocoaWindow::requestUpdate()
{
- qCDebug(lcQpaCocoaDrawing) << "QCocoaWindow::requestUpdate" << window();
+ qCDebug(lcQpaDrawing) << "QCocoaWindow::requestUpdate" << window();
QPlatformWindow::requestUpdate();
}
+void QCocoaWindow::deliverUpdateRequest()
+{
+ qCDebug(lcQpaDrawing) << "Delivering update request to" << window();
+ QPlatformWindow::deliverUpdateRequest();
+}
+
void QCocoaWindow::requestActivateWindow()
{
NSWindow *window = [m_view window];
@@ -1361,7 +1364,7 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
}
if (!targetScreen) {
- qCWarning(lcQpaCocoaWindow) << "Window position outside any known screen, using primary screen";
+ qCWarning(lcQpaWindow) << "Window position outside any known screen, using primary screen";
targetScreen = QGuiApplication::primaryScreen();
}
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.h b/src/plugins/platforms/cocoa/qmacclipboard.h
index 1d229a55d2..f2f460c048 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.h
+++ b/src/plugins/platforms/cocoa/qmacclipboard.h
@@ -54,7 +54,7 @@ public:
enum DataRequestType { EagerRequest, LazyRequest };
private:
struct Promise {
- Promise() : itemId(0), convertor(0) { }
+ Promise() : itemId(0), convertor(nullptr) { }
static Promise eagerPromise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *d, int o = 0);
static Promise lazyPromise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *d, int o = 0);
@@ -79,7 +79,7 @@ private:
public:
QMacPasteboard(PasteboardRef p, uchar mime_type=0);
QMacPasteboard(uchar mime_type);
- QMacPasteboard(CFStringRef name=0, uchar mime_type=0);
+ QMacPasteboard(CFStringRef name=nullptr, uchar mime_type=0);
~QMacPasteboard();
bool hasFlavor(QString flavor) const;
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm
index f3467fdc73..5939003c64 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.mm
+++ b/src/plugins/platforms/cocoa/qmacclipboard.mm
@@ -75,7 +75,7 @@ QMacPasteboard::Promise::Promise(int itemId, QMacInternalPasteboardMime *c, QStr
// Request the data from the application immediately for eager requests.
if (dataRequestType == QMacPasteboard::EagerRequest) {
variantData = md->variantData(m);
- mimeData = 0;
+ mimeData = nullptr;
} else {
mimeData = md;
}
@@ -94,8 +94,8 @@ QMacPasteboard::QMacPasteboard(uchar mt)
{
mac_mime_source = false;
mime_type = mt ? mt : uchar(QMacInternalPasteboardMime::MIME_ALL);
- paste = 0;
- OSStatus err = PasteboardCreate(0, &paste);
+ paste = nullptr;
+ OSStatus err = PasteboardCreate(nullptr, &paste);
if (err == noErr) {
PasteboardSetPromiseKeeper(paste, promiseKeeper, this);
} else {
@@ -108,7 +108,7 @@ QMacPasteboard::QMacPasteboard(CFStringRef name, uchar mt)
{
mac_mime_source = false;
mime_type = mt ? mt : uchar(QMacInternalPasteboardMime::MIME_ALL);
- paste = 0;
+ paste = nullptr;
OSStatus err = PasteboardCreate(name, &paste);
if (err == noErr) {
PasteboardSetPromiseKeeper(paste, promiseKeeper, this);
@@ -165,7 +165,7 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
// we have promised this data, but won't be able to convert, so return null data.
// This helps in making the application/x-qt-mime-type-name hidden from normal use.
QByteArray ba;
- QCFType<CFDataRef> data = CFDataCreate(0, (UInt8*)ba.constData(), ba.size());
+ QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags);
return noErr;
}
@@ -196,7 +196,7 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
if (md.size() <= promise.offset)
return cantGetFlavorErr;
const QByteArray &ba = md[promise.offset];
- QCFType<CFDataRef> data = CFDataCreate(0, (UInt8*)ba.constData(), ba.size());
+ QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags);
return noErr;
}
@@ -553,7 +553,7 @@ QMacPasteboard::sync() const
const bool fromGlobal = PasteboardSynchronize(paste) & kPasteboardModified;
if (fromGlobal)
- const_cast<QMacPasteboard *>(this)->setMimeData(0);
+ const_cast<QMacPasteboard *>(this)->setMimeData(nullptr);
#ifdef DEBUG_PASTEBOARD
if (fromGlobal)
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac.mm b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
index 9eca4d2d43..10652dc6a1 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac.mm
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
@@ -107,7 +107,7 @@ QCocoaTouch *QCocoaTouch::findQCocoaTouch(NSTouch *nstouch)
qint64 identity = qint64([nstouch identity]);
if (_currentTouches.contains(identity))
return _currentTouches.value(identity);
- return 0;
+ return nullptr;
}
Qt::TouchPointState QCocoaTouch::toTouchPointState(NSTouchPhase nsState)
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index e2ea862cd5..f7ca41d3be 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -41,111 +41,52 @@
#define QNSVIEW_H
#include <AppKit/AppKit.h>
-
-#include <QtCore/QPointer>
-#include <QtCore/QSet>
-#include <QtGui/QImage>
-#include <QtGui/QAccessible>
+#include <MetalKit/MetalKit.h>
#include "private/qcore_mac_p.h"
QT_BEGIN_NAMESPACE
class QCocoaWindow;
class QCocoaGLContext;
+class QPointF;
QT_END_NAMESPACE
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
+Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaNSMenuItem));
-@interface QT_MANGLE_NAMESPACE(QNSView) : NSView <NSTextInputClient> {
- QPointer<QCocoaWindow> m_platformWindow;
- NSTrackingArea *m_trackingArea;
- Qt::MouseButtons m_buttons;
- Qt::MouseButtons m_acceptedMouseDowns;
- Qt::MouseButtons m_frameStrutButtons;
- QString m_composingText;
- QPointer<QObject> m_composingFocusObject;
- bool m_sendKeyEvent;
- QStringList *currentCustomDragTypes;
- bool m_dontOverrideCtrlLMB;
- bool m_sendUpAsRightButton;
- Qt::KeyboardModifiers currentWheelModifiers;
-#ifndef QT_NO_OPENGL
- QCocoaGLContext *m_glContext;
- bool m_shouldSetGLContextinDrawRect;
-#endif
- NSString *m_inputSource;
- QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) *m_mouseMoveHelper;
- bool m_resendKeyEvent;
- bool m_scrolling;
- bool m_updatingDrag;
- NSEvent *m_currentlyInterpretedKeyEvent;
- bool m_isMenuView;
- QSet<quint32> m_acceptedKeyDowns;
- bool m_updateRequested;
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) : NSView
@property (nonatomic, retain) NSCursor *cursor;
-- (id)init;
-- (id)initWithCocoaWindow:(QCocoaWindow *)platformWindow;
-#ifndef QT_NO_OPENGL
-- (void)setQCocoaGLContext:(QCocoaGLContext *)context;
-#endif
-- (void)drawRect:(NSRect)dirtyRect;
-- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification;
-- (void)viewDidHide;
-- (void)removeFromSuperview;
-- (void)cancelComposingText;
-
-- (BOOL)isFlipped;
-- (BOOL)acceptsFirstResponder;
-- (BOOL)becomeFirstResponder;
-- (BOOL)isOpaque;
+- (instancetype)initWithCocoaWindow:(QCocoaWindow *)platformWindow;
- (void)convertFromScreen:(NSPoint)mouseLocation toWindowPoint:(QPointF *)qtWindowPoint andScreenPoint:(QPointF *)qtScreenPoint;
-- (void)resetMouseButtons;
+@end
+@interface QT_MANGLE_NAMESPACE(QNSView) (DrawingAPI)
- (void)requestUpdate;
-
-- (void)handleMouseEvent:(NSEvent *)theEvent;
-- (bool)handleMouseDownEvent:(NSEvent *)theEvent withButton:(int)buttonNumber;
-- (bool)handleMouseDraggedEvent:(NSEvent *)theEvent withButton:(int)buttonNumber;
-- (bool)handleMouseUpEvent:(NSEvent *)theEvent withButton:(int)buttonNumber;
-- (void)mouseDown:(NSEvent *)theEvent;
-- (void)mouseDragged:(NSEvent *)theEvent;
-- (void)mouseUp:(NSEvent *)theEvent;
-- (void)mouseMovedImpl:(NSEvent *)theEvent;
-- (void)mouseEnteredImpl:(NSEvent *)theEvent;
-- (void)mouseExitedImpl:(NSEvent *)theEvent;
-- (void)rightMouseDown:(NSEvent *)theEvent;
-- (void)rightMouseDragged:(NSEvent *)theEvent;
-- (void)rightMouseUp:(NSEvent *)theEvent;
-- (void)otherMouseDown:(NSEvent *)theEvent;
-- (void)otherMouseDragged:(NSEvent *)theEvent;
-- (void)otherMouseUp:(NSEvent *)theEvent;
-- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent;
-
-#ifndef QT_NO_TABLETEVENT
-- (bool)handleTabletEvent: (NSEvent *)theEvent;
-- (void)tabletPoint: (NSEvent *)theEvent;
-- (void)tabletProximity: (NSEvent *)theEvent;
+#ifndef QT_NO_OPENGL
+- (void)setQCocoaGLContext:(QCocoaGLContext *)context;
#endif
+@end
-- (int) convertKeyCode : (QChar)keyCode;
-+ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags;
-- (bool)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType;
-- (void)keyDown:(NSEvent *)theEvent;
-- (void)keyUp:(NSEvent *)theEvent;
+@interface QT_MANGLE_NAMESPACE(QNSView) (MouseAPI)
+- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent;
+- (void)resetMouseButtons;
+@end
-- (void)registerDragTypes;
-- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender;
+@interface QT_MANGLE_NAMESPACE(QNSView) (KeysAPI)
++ (Qt::KeyboardModifiers)convertKeyModifiers:(ulong)modifierFlags;
+@end
+@interface QT_MANGLE_NAMESPACE(QNSView) (ComplexTextAPI)
+- (void)unmarkText;
+- (void)cancelComposingText;
@end
@interface QT_MANGLE_NAMESPACE(QNSView) (QtExtras)
@property (nonatomic, readonly) QCocoaWindow *platformWindow;
-@property (nonatomic, readonly) BOOL isMenuView;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSView);
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index c88ffc76d7..c30c6c7386 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -51,7 +51,11 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QTextFormat>
#include <QtCore/QDebug>
+#include <QtCore/QPointer>
+#include <QtCore/QSet>
#include <QtCore/qsysinfo.h>
+#include <QtGui/QAccessible>
+#include <QtGui/QImage>
#include <private/qguiapplication_p.h>
#include <private/qcoregraphics_p.h>
#include <private/qwindow_p.h>
@@ -65,87 +69,97 @@
#include <accessibilityinspector.h>
#endif
-Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
-#ifndef QT_NO_GESTURES
-Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
-#endif
-Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
-
-@interface QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) : NSObject
-{
- QNSView *view;
-}
+// Private interface
+@interface QT_MANGLE_NAMESPACE(QNSView) ()
+- (BOOL)isTransparentForUserInput;
+@end
-- (id)initWithView:(QNSView *)theView;
+@interface QT_MANGLE_NAMESPACE(QNSView) (Drawing) <CALayerDelegate>
+@end
+@interface QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) : NSObject
+- (instancetype)initWithView:(QNSView *)theView;
- (void)mouseMoved:(NSEvent *)theEvent;
- (void)mouseEntered:(NSEvent *)theEvent;
- (void)mouseExited:(NSEvent *)theEvent;
- (void)cursorUpdate:(NSEvent *)theEvent;
-
@end
-@implementation QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)
-
-- (id)initWithView:(QNSView *)theView
-{
- self = [super init];
- if (self) {
- view = theView;
- }
- return self;
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) (Mouse)
+- (NSPoint)screenMousePoint:(NSEvent *)theEvent;
+- (void)mouseMovedImpl:(NSEvent *)theEvent;
+- (void)mouseEnteredImpl:(NSEvent *)theEvent;
+- (void)mouseExitedImpl:(NSEvent *)theEvent;
+@end
-- (void)mouseMoved:(NSEvent *)theEvent
-{
- [view mouseMovedImpl:theEvent];
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) (Touch)
+@end
-- (void)mouseEntered:(NSEvent *)theEvent
-{
- [view mouseEnteredImpl:theEvent];
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) (Tablet)
+- (bool)handleTabletEvent:(NSEvent *)theEvent;
+@end
-- (void)mouseExited:(NSEvent *)theEvent
-{
- [view mouseExitedImpl:theEvent];
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) (Gestures)
+@end
-- (void)cursorUpdate:(NSEvent *)theEvent
-{
- [view cursorUpdate:theEvent];
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) (Dragging)
+-(void)registerDragTypes;
+@end
+@interface QT_MANGLE_NAMESPACE(QNSView) (Keys)
@end
-// Private interface
-@interface QT_MANGLE_NAMESPACE(QNSView) ()
-- (BOOL)isTransparentForUserInput;
+@interface QT_MANGLE_NAMESPACE(QNSView) (ComplexText) <NSTextInputClient>
+- (void)textInputContextKeyboardSelectionDidChangeNotification:(NSNotification *)textInputContextKeyboardSelectionDidChangeNotification;
@end
-@implementation QT_MANGLE_NAMESPACE(QNSView)
+@implementation QT_MANGLE_NAMESPACE(QNSView) {
+ QPointer<QCocoaWindow> m_platformWindow;
+ NSTrackingArea *m_trackingArea;
+ Qt::MouseButtons m_buttons;
+ Qt::MouseButtons m_acceptedMouseDowns;
+ Qt::MouseButtons m_frameStrutButtons;
+ QString m_composingText;
+ QPointer<QObject> m_composingFocusObject;
+ bool m_sendKeyEvent;
+ QStringList *currentCustomDragTypes;
+ bool m_dontOverrideCtrlLMB;
+ bool m_sendUpAsRightButton;
+ Qt::KeyboardModifiers currentWheelModifiers;
+#ifndef QT_NO_OPENGL
+ QCocoaGLContext *m_glContext;
+ bool m_shouldSetGLContextinDrawRect;
+#endif
+ NSString *m_inputSource;
+ QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) *m_mouseMoveHelper;
+ bool m_resendKeyEvent;
+ bool m_scrolling;
+ bool m_updatingDrag;
+ NSEvent *m_currentlyInterpretedKeyEvent;
+ QSet<quint32> m_acceptedKeyDowns;
+ bool m_updateRequested;
+}
-- (id) init
+- (instancetype)init
{
- if (self = [super initWithFrame:NSZeroRect]) {
+ if ((self = [super initWithFrame:NSZeroRect])) {
m_buttons = Qt::NoButton;
m_acceptedMouseDowns = Qt::NoButton;
m_frameStrutButtons = Qt::NoButton;
m_sendKeyEvent = false;
#ifndef QT_NO_OPENGL
- m_glContext = 0;
+ m_glContext = nullptr;
m_shouldSetGLContextinDrawRect = false;
#endif
- currentCustomDragTypes = 0;
+ currentCustomDragTypes = nullptr;
m_dontOverrideCtrlLMB = false;
m_sendUpAsRightButton = false;
- m_inputSource = 0;
+ m_inputSource = nil;
m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self];
m_resendKeyEvent = false;
m_scrolling = false;
m_updatingDrag = false;
- m_currentlyInterpretedKeyEvent = 0;
- m_isMenuView = false;
+ m_currentlyInterpretedKeyEvent = nil;
self.focusRingType = NSFocusRingTypeNone;
self.cursor = nil;
m_updateRequested = false;
@@ -168,38 +182,36 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
[super dealloc];
}
-- (id)initWithCocoaWindow:(QCocoaWindow *)platformWindow
+- (instancetype)initWithCocoaWindow:(QCocoaWindow *)platformWindow
{
- self = [self init];
- if (!self)
- return 0;
-
- m_platformWindow = platformWindow;
- m_sendKeyEvent = false;
- m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, platformWindow->window(), "_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
- m_trackingArea = nil;
+ if ((self = [self init])) {
+ m_platformWindow = platformWindow;
+ m_sendKeyEvent = false;
+ m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, platformWindow->window(), "_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
+ m_trackingArea = nil;
#ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
- // prevent rift in space-time continuum, disable
- // accessibility for the accessibility inspector's windows.
- static bool skipAccessibilityForInspectorWindows = false;
- if (!skipAccessibilityForInspectorWindows) {
+ // prevent rift in space-time continuum, disable
+ // accessibility for the accessibility inspector's windows.
+ static bool skipAccessibilityForInspectorWindows = false;
+ if (!skipAccessibilityForInspectorWindows) {
- // m_accessibleRoot = window->accessibleRoot();
+ // m_accessibleRoot = window->accessibleRoot();
- AccessibilityInspector *inspector = new AccessibilityInspector(window);
- skipAccessibilityForInspectorWindows = true;
- inspector->inspectWindow(window);
- skipAccessibilityForInspectorWindows = false;
- }
+ AccessibilityInspector *inspector = new AccessibilityInspector(window);
+ skipAccessibilityForInspectorWindows = true;
+ inspector->inspectWindow(window);
+ skipAccessibilityForInspectorWindows = false;
+ }
#endif
- [self registerDragTypes];
+ [self registerDragTypes];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(textInputContextKeyboardSelectionDidChangeNotification:)
- name:NSTextInputContextKeyboardSelectionDidChangeNotification
- object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(textInputContextKeyboardSelectionDidChangeNotification:)
+ name:NSTextInputContextKeyboardSelectionDidChangeNotification
+ object:nil];
+ }
return self;
}
@@ -220,33 +232,18 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return description;
}
-#ifndef QT_NO_OPENGL
-- (void) setQCocoaGLContext:(QCocoaGLContext *)context
-{
- m_glContext = context;
- [m_glContext->nsOpenGLContext() setView:self];
- if (![m_glContext->nsOpenGLContext() view]) {
- //was unable to set view
- m_shouldSetGLContextinDrawRect = true;
- }
-}
-#endif
-
- (void)viewDidMoveToSuperview
{
if (!m_platformWindow)
return;
- if (!(m_platformWindow->m_viewIsToBeEmbedded))
+ if (!m_platformWindow->isEmbedded())
return;
if ([self superview]) {
- m_platformWindow->m_viewIsEmbedded = true;
QWindowSystemInterface::handleGeometryChange(m_platformWindow->window(), m_platformWindow->geometry());
[self setNeedsDisplay:YES];
QWindowSystemInterface::flushWindowSystemEvents();
- } else {
- m_platformWindow->m_viewIsEmbedded = false;
}
}
@@ -268,15 +265,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return focusWindow;
}
-- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification
-{
- Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification)
- if (([NSApp keyWindow] == [self window]) && [[self window] firstResponder] == self) {
- QCocoaInputContext *ic = qobject_cast<QCocoaInputContext *>(QCocoaIntegration::instance()->inputContext());
- ic->updateLocale();
- }
-}
-
- (void)viewDidHide
{
if (!m_platformWindow->isExposed())
@@ -294,107 +282,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
[super removeFromSuperview];
}
-- (BOOL) isOpaque
-{
- if (!m_platformWindow)
- return true;
- return m_platformWindow->isOpaque();
-}
-
-- (void)requestUpdate
-{
- if (self.needsDisplay) {
- // If the view already has needsDisplay set it means that there may be code waiting for
- // a real expose event, so we can't issue setNeedsDisplay now as a way to trigger an
- // update request. We will re-trigger requestUpdate from drawRect.
- return;
- }
-
- [self setNeedsDisplay:YES];
- m_updateRequested = true;
-}
-
-- (void)setNeedsDisplayInRect:(NSRect)rect
-{
- [super setNeedsDisplayInRect:rect];
- m_updateRequested = false;
-}
-
-- (void)drawRect:(NSRect)dirtyRect
-{
- Q_UNUSED(dirtyRect);
-
- if (!m_platformWindow)
- return;
-
- QRegion exposedRegion;
- const NSRect *dirtyRects;
- NSInteger numDirtyRects;
- [self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
- for (int i = 0; i < numDirtyRects; ++i)
- exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
-
- qCDebug(lcQpaCocoaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
- [self updateRegion:exposedRegion];
-}
-
-- (void)updateRegion:(QRegion)dirtyRegion
-{
-#ifndef QT_NO_OPENGL
- if (m_glContext && m_shouldSetGLContextinDrawRect) {
- [m_glContext->nsOpenGLContext() setView:self];
- m_shouldSetGLContextinDrawRect = false;
- }
-#endif
-
- QWindowPrivate *windowPrivate = qt_window_private(m_platformWindow->window());
-
- if (m_updateRequested) {
- Q_ASSERT(windowPrivate->updateRequestPending);
- qCDebug(lcQpaCocoaWindow) << "Delivering update request to" << m_platformWindow->window();
- windowPrivate->deliverUpdateRequest();
- m_updateRequested = false;
- } else {
- m_platformWindow->handleExposeEvent(dirtyRegion);
- }
-
- if (m_updateRequested && windowPrivate->updateRequestPending) {
- // A call to QWindow::requestUpdate was issued during event delivery above,
- // but AppKit will reset the needsDisplay state of the view after completing
- // the current display cycle, so we need to defer the request to redisplay.
- // FIXME: Perhaps this should be a trigger to enable CADisplayLink?
- qCDebug(lcQpaCocoaDrawing) << "[QNSView drawRect:] issuing deferred setNeedsDisplay due to pending update request";
- dispatch_async(dispatch_get_main_queue (), ^{ [self requestUpdate]; });
- }
-}
-
-- (BOOL)wantsUpdateLayer
-{
- return YES;
-}
-
-- (void)updateLayer
-{
- if (!m_platformWindow)
- return;
-
- qCDebug(lcQpaCocoaDrawing) << "[QNSView updateLayer]" << m_platformWindow->window();
-
- // FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
- [self updateRegion:QRectF::fromCGRect(self.bounds).toRect()];
-}
-
-- (void)viewDidChangeBackingProperties
-{
- if (self.layer)
- self.layer.contentsScale = self.window.backingScaleFactor;
-}
-
-- (BOOL)isFlipped
-{
- return YES;
-}
-
- (BOOL)isTransparentForUserInput
{
return m_platformWindow->window() &&
@@ -407,7 +294,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return NO;
if ([self isTransparentForUserInput])
return NO;
- if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
+ if (!m_platformWindow->windowIsPopupType())
QWindowSystemInterface::handleWindowActivated([self topLevelWindow]);
return YES;
}
@@ -416,8 +303,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
{
if (!m_platformWindow)
return NO;
- if (m_isMenuView)
- return NO;
if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder())
return NO;
if ([self isTransparentForUserInput])
@@ -427,16 +312,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return YES;
}
-- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
-{
- Q_UNUSED(theEvent)
- if (!m_platformWindow)
- return NO;
- if ([self isTransparentForUserInput])
- return NO;
- return YES;
-}
-
- (NSView *)hitTest:(NSPoint)aPoint
{
NSView *candidate = [super hitTest:aPoint];
@@ -476,1607 +351,19 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
*qtScreenPoint = QCocoaScreen::mapFromNative(mouseLocation);
}
-- (void)resetMouseButtons
-{
- m_buttons = Qt::NoButton;
- m_frameStrutButtons = Qt::NoButton;
-}
-
-- (NSPoint) screenMousePoint:(NSEvent *)theEvent
-{
- NSPoint screenPoint;
- if (theEvent) {
- NSPoint windowPoint = [theEvent locationInWindow];
- if (qIsNaN(windowPoint.x) || qIsNaN(windowPoint.y)) {
- screenPoint = [NSEvent mouseLocation];
- } else {
- NSRect screenRect = [[theEvent window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
- screenPoint = screenRect.origin;
- }
- } else {
- screenPoint = [NSEvent mouseLocation];
- }
- return screenPoint;
-}
-
-- (void)handleMouseEvent:(NSEvent *)theEvent
-{
- if (!m_platformWindow)
- return;
-
-#ifndef QT_NO_TABLETEVENT
- // Tablet events may come in via the mouse event handlers,
- // check if this is a valid tablet event first.
- if ([self handleTabletEvent: theEvent])
- return;
-#endif
-
- QPointF qtWindowPoint;
- QPointF qtScreenPoint;
- QNSView *targetView = self;
- if (!targetView.platformWindow)
- return;
-
- // Popups implicitly grap mouse events; forward to the active popup if there is one
- if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) {
- // Tooltips must be transparent for mouse events
- // The bug reference is QTBUG-46379
- if (!popup->m_windowFlags.testFlag(Qt::ToolTip)) {
- if (QNSView *popupView = qnsview_cast(popup->view()))
- targetView = popupView;
- }
- }
-
- [targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
- ulong timestamp = [theEvent timestamp] * 1000;
-
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- nativeDrag->setLastMouseEvent(theEvent, self);
-
- Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
- QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint,
- m_buttons, keyboardModifiers, Qt::MouseEventNotSynthesized);
-}
-
-- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent
-{
- if (!m_platformWindow)
- return;
-
- // get m_buttons in sync
- // Don't send frme strut events if we are in the middle of a mouse drag.
- if (m_buttons != Qt::NoButton)
- return;
-
- NSEventType ty = [theEvent type];
- switch (ty) {
- case NSLeftMouseDown:
- m_frameStrutButtons |= Qt::LeftButton;
- break;
- case NSLeftMouseUp:
- m_frameStrutButtons &= ~Qt::LeftButton;
- break;
- case NSRightMouseDown:
- m_frameStrutButtons |= Qt::RightButton;
- break;
- case NSLeftMouseDragged:
- m_frameStrutButtons |= Qt::LeftButton;
- break;
- case NSRightMouseDragged:
- m_frameStrutButtons |= Qt::RightButton;
- break;
- case NSRightMouseUp:
- m_frameStrutButtons &= ~Qt::RightButton;
- break;
- case NSOtherMouseDown:
- m_frameStrutButtons |= cocoaButton2QtButton([theEvent buttonNumber]);
- break;
- case NSOtherMouseUp:
- m_frameStrutButtons &= ~cocoaButton2QtButton([theEvent buttonNumber]);
- default:
- break;
- }
-
- NSWindow *window = [self window];
- NSPoint windowPoint = [theEvent locationInWindow];
-
- int windowScreenY = [window frame].origin.y + [window frame].size.height;
- NSPoint windowCoord = [self convertPoint:[self frame].origin toView:nil];
- int viewScreenY = [window convertRectToScreen:NSMakeRect(windowCoord.x, windowCoord.y, 0, 0)].origin.y;
- int titleBarHeight = windowScreenY - viewScreenY;
-
- NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil];
- QPoint qtWindowPoint = QPoint(nsViewPoint.x, titleBarHeight + nsViewPoint.y);
- NSPoint screenPoint = [window convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 0, 0)].origin;
- QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
-
- ulong timestamp = [theEvent timestamp] * 1000;
- QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons);
-}
-
-- (bool)handleMouseDownEvent:(NSEvent *)theEvent withButton:(int)buttonNumber
-{
- if ([self isTransparentForUserInput])
- return false;
-
- Qt::MouseButton button = cocoaButton2QtButton(buttonNumber);
-
- QPointF qtWindowPoint;
- QPointF qtScreenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
- Q_UNUSED(qtScreenPoint);
-
- // Maintain masked state for the button for use by MouseDragged and MouseUp.
- QRegion mask = m_platformWindow->window()->mask();
- const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
- if (masked)
- m_acceptedMouseDowns &= ~button;
- else
- m_acceptedMouseDowns |= button;
-
- // Forward masked out events to the next responder
- if (masked)
- return false;
-
- m_buttons |= button;
-
- [self handleMouseEvent:theEvent];
- return true;
-}
-
-- (bool)handleMouseDraggedEvent:(NSEvent *)theEvent withButton:(int)buttonNumber
-{
- if ([self isTransparentForUserInput])
- return false;
-
- Qt::MouseButton button = cocoaButton2QtButton(buttonNumber);
-
- // Forward the event to the next responder if Qt did not accept the
- // corresponding mouse down for this button
- if (!(m_acceptedMouseDowns & button) == button)
- return false;
-
- [self handleMouseEvent:theEvent];
- return true;
-}
-
-- (bool)handleMouseUpEvent:(NSEvent *)theEvent withButton:(int)buttonNumber
-{
- if ([self isTransparentForUserInput])
- return false;
-
- Qt::MouseButton button = cocoaButton2QtButton(buttonNumber);
-
- // Forward the event to the next responder if Qt did not accept the
- // corresponding mouse down for this button
- if (!(m_acceptedMouseDowns & button) == button)
- return false;
-
- if (m_sendUpAsRightButton && button == Qt::LeftButton)
- button = Qt::RightButton;
- if (button == Qt::RightButton)
- m_sendUpAsRightButton = false;
-
- m_buttons &= ~button;
-
- [self handleMouseEvent:theEvent];
- return true;
-}
-
-- (void)mouseDown:(NSEvent *)theEvent
-{
- if ([self isTransparentForUserInput])
- return [super mouseDown:theEvent];
- m_sendUpAsRightButton = false;
-
- // Handle any active poup windows; clicking outisde them should close them
- // all. Don't do anything or clicks inside one of the menus, let Cocoa
- // handle that case. Note that in practice many windows of the Qt::Popup type
- // will actually close themselves in this case using logic implemented in
- // that particular poup type (for example context menus). However, Qt expects
- // that plain popup QWindows will also be closed, so we implement the logic
- // here as well.
- QList<QCocoaWindow *> *popups = QCocoaIntegration::instance()->popupWindowStack();
- if (!popups->isEmpty()) {
- // Check if the click is outside all popups.
- bool inside = false;
- QPointF qtScreenPoint = QCocoaScreen::mapFromNative([self screenMousePoint:theEvent]);
- for (QList<QCocoaWindow *>::const_iterator it = popups->begin(); it != popups->end(); ++it) {
- if ((*it)->geometry().contains(qtScreenPoint.toPoint())) {
- inside = true;
- break;
- }
- }
- // Close the popups if the click was outside.
- if (!inside) {
- Qt::WindowType type = QCocoaIntegration::instance()->activePopupWindow()->window()->type();
- while (QCocoaWindow *popup = QCocoaIntegration::instance()->popPopupWindow()) {
- QWindowSystemInterface::handleCloseEvent(popup->window());
- QWindowSystemInterface::flushWindowSystemEvents();
- }
- // Consume the mouse event when closing the popup, except for tool tips
- // were it's expected that the event is processed normally.
- if (type != Qt::ToolTip)
- return;
- }
- }
-
- QPointF qtWindowPoint;
- QPointF qtScreenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
- Q_UNUSED(qtScreenPoint);
-
- QRegion mask = m_platformWindow->window()->mask();
- const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
- // Maintain masked state for the button for use by MouseDragged and Up.
- if (masked)
- m_acceptedMouseDowns &= ~Qt::LeftButton;
- else
- m_acceptedMouseDowns |= Qt::LeftButton;
-
- // Forward masked out events to the next responder
- if (masked) {
- [super mouseDown:theEvent];
- return;
- }
-
- if ([self hasMarkedText]) {
- [[NSTextInputContext currentInputContext] handleEvent:theEvent];
- } else {
- auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier;
- if (!m_dontOverrideCtrlLMB && [QNSView convertKeyModifiers:[theEvent modifierFlags]] & ctrlOrMetaModifier) {
- m_buttons |= Qt::RightButton;
- m_sendUpAsRightButton = true;
- } else {
- m_buttons |= Qt::LeftButton;
- }
- [self handleMouseEvent:theEvent];
- }
-}
-
-- (void)mouseDragged:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseDraggedEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super mouseDragged:theEvent];
-}
-
-- (void)mouseUp:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseUpEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super mouseUp:theEvent];
-}
-
-- (void)rightMouseDown:(NSEvent *)theEvent
-{
- // Wacom tablet might not return the correct button number for NSEvent buttonNumber
- // on right clicks. Decide here that the button is the "right" button and forward
- // the button number to the mouse (and tablet) handler.
- const bool accepted = [self handleMouseDownEvent:theEvent withButton:1];
- if (!accepted)
- [super rightMouseDown:theEvent];
-}
-
-- (void)rightMouseDragged:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseDraggedEvent:theEvent withButton:1];
- if (!accepted)
- [super rightMouseDragged:theEvent];
-}
-
-- (void)rightMouseUp:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseUpEvent:theEvent withButton:1];
- if (!accepted)
- [super rightMouseUp:theEvent];
-}
-
-- (void)otherMouseDown:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseDownEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super otherMouseDown:theEvent];
-}
-
-- (void)otherMouseDragged:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseDraggedEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super otherMouseDragged:theEvent];
-}
-
-- (void)otherMouseUp:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseUpEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super otherMouseUp:theEvent];
-}
-
-- (void)updateTrackingAreas
-{
- [super updateTrackingAreas];
-
- QMacAutoReleasePool pool;
-
- // NSTrackingInVisibleRect keeps care of updating once the tracking is set up, so bail out early
- if (m_trackingArea && [[self trackingAreas] containsObject:m_trackingArea])
- return;
-
- // Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should
- // only be turned on if mouseTracking, hover is on or a tool tip is set.
- // Unfortunately, Qt will send "tooltip" events on mouse moves, so we need to
- // turn it on in ALL case. That means EVERY QWindow gets to pay the cost of
- // mouse moves delivered to it (Apple recommends keeping it OFF because there
- // is a performance hit). So it goes.
- NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
- | NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate;
- [m_trackingArea release];
- m_trackingArea = [[NSTrackingArea alloc] initWithRect:[self frame]
- options:trackingOptions
- owner:m_mouseMoveHelper
- userInfo:nil];
- [self addTrackingArea:m_trackingArea];
-}
-
-- (void)cursorUpdate:(NSEvent *)theEvent
-{
- qCDebug(lcQpaCocoaMouse) << "[QNSView cursorUpdate:]" << self.cursor;
-
- // Note: We do not get this callback when moving from a subview that
- // uses the legacy cursorRect API, so the cursor is reset to the arrow
- // cursor. See rdar://34183708
-
- if (self.cursor)
- [self.cursor set];
- else
- [super cursorUpdate:theEvent];
-}
-
-- (void)mouseMovedImpl:(NSEvent *)theEvent
-{
- if (!m_platformWindow)
- return;
-
- if ([self isTransparentForUserInput])
- return;
-
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
-
- // Top-level windows generate enter-leave events for sub-windows.
- // Qt wants to know which window (if any) will be entered at the
- // the time of the leave. This is dificult to accomplish by
- // handling mouseEnter and mouseLeave envents, since they are sent
- // individually to different views.
- if (m_platformWindow->isContentView() && childWindow) {
- if (childWindow != m_platformWindow->m_enterLeaveTargetWindow) {
- QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
- m_platformWindow->m_enterLeaveTargetWindow = childWindow;
- }
- }
-
- // Cocoa keeps firing mouse move events for obscured parent views. Qt should not
- // send those events so filter them out here.
- if (childWindow != m_platformWindow->window())
- return;
-
- [self handleMouseEvent: theEvent];
-}
-
-- (void)mouseEnteredImpl:(NSEvent *)theEvent
-{
- Q_UNUSED(theEvent)
- if (!m_platformWindow)
- return;
-
- m_platformWindow->m_windowUnderMouse = true;
-
- if ([self isTransparentForUserInput])
- return;
-
- // Top-level windows generate enter events for sub-windows.
- if (!m_platformWindow->isContentView())
- return;
-
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- m_platformWindow->m_enterLeaveTargetWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
- QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
-}
-
-- (void)mouseExitedImpl:(NSEvent *)theEvent
-{
- Q_UNUSED(theEvent);
- if (!m_platformWindow)
- return;
-
- m_platformWindow->m_windowUnderMouse = false;
-
- if ([self isTransparentForUserInput])
- return;
-
- // Top-level windows generate leave events for sub-windows.
- if (!m_platformWindow->isContentView())
- return;
-
- QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_enterLeaveTargetWindow);
- m_platformWindow->m_enterLeaveTargetWindow = 0;
-}
-
-#ifndef QT_NO_TABLETEVENT
-struct QCocoaTabletDeviceData
-{
- QTabletEvent::TabletDevice device;
- QTabletEvent::PointerType pointerType;
- uint capabilityMask;
- qint64 uid;
-};
-
-typedef QHash<uint, QCocoaTabletDeviceData> QCocoaTabletDeviceDataHash;
-Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
-
-- (bool)handleTabletEvent: (NSEvent *)theEvent
-{
- static bool ignoreButtonMapping = qEnvironmentVariableIsSet("QT_MAC_TABLET_IGNORE_BUTTON_MAPPING");
-
- if (!m_platformWindow)
- return false;
-
- NSEventType eventType = [theEvent type];
- if (eventType != NSTabletPoint && [theEvent subtype] != NSTabletPointEventSubtype)
- return false; // Not a tablet event.
-
- ulong timestamp = [theEvent timestamp] * 1000;
-
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint: &windowPoint andScreenPoint: &screenPoint];
-
- uint deviceId = [theEvent deviceID];
- if (!tabletDeviceDataHash->contains(deviceId)) {
- // Error: Unknown tablet device. Qt also gets into this state
- // when running on a VM. This appears to be harmless; don't
- // print a warning.
- return false;
- }
- const QCocoaTabletDeviceData &deviceData = tabletDeviceDataHash->value(deviceId);
-
- bool down = (eventType != NSMouseMoved);
-
- qreal pressure;
- if (down) {
- pressure = [theEvent pressure];
- } else {
- pressure = 0.0;
- }
-
- NSPoint tilt = [theEvent tilt];
- int xTilt = qRound(tilt.x * 60.0);
- int yTilt = qRound(tilt.y * -60.0);
- qreal tangentialPressure = 0;
- qreal rotation = 0;
- int z = 0;
- if (deviceData.capabilityMask & 0x0200)
- z = [theEvent absoluteZ];
-
- if (deviceData.capabilityMask & 0x0800)
- tangentialPressure = ([theEvent tangentialPressure] * 2.0) - 1.0;
-
- rotation = 360.0 - [theEvent rotation];
- if (rotation > 180.0)
- rotation -= 360.0;
-
- Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
- Qt::MouseButtons buttons = ignoreButtonMapping ? static_cast<Qt::MouseButtons>(static_cast<uint>([theEvent buttonMask])) : m_buttons;
-
- qCDebug(lcQpaTablet, "event on tablet %d with tool %d type %d unique ID %lld pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf",
- deviceId, deviceData.device, deviceData.pointerType, deviceData.uid,
- windowPoint.x(), windowPoint.y(), screenPoint.x(), screenPoint.y(),
- static_cast<uint>(buttons), pressure, xTilt, yTilt, rotation);
-
- QWindowSystemInterface::handleTabletEvent(m_platformWindow->window(), timestamp, windowPoint, screenPoint,
- deviceData.device, deviceData.pointerType, buttons, pressure, xTilt, yTilt,
- tangentialPressure, rotation, z, deviceData.uid,
- keyboardModifiers);
- return true;
-}
-
-- (void)tabletPoint:(NSEvent *)theEvent
-{
- if ([self isTransparentForUserInput])
- return [super tabletPoint:theEvent];
-
- [self handleTabletEvent: theEvent];
-}
-
-static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
-{
- qint64 uid = [theEvent uniqueID];
- uint bits = [theEvent vendorPointingDeviceType];
- if (bits == 0 && uid != 0) {
- // Fallback. It seems that the driver doesn't always include all the information.
- // High-End Wacom devices store their "type" in the uper bits of the Unique ID.
- // I'm not sure how to handle it for consumer devices, but I'll test that in a bit.
- bits = uid >> 32;
- }
-
- QTabletEvent::TabletDevice device;
- // Defined in the "EN0056-NxtGenImpGuideX"
- // on Wacom's Developer Website (www.wacomeng.com)
- if (((bits & 0x0006) == 0x0002) && ((bits & 0x0F06) != 0x0902)) {
- device = QTabletEvent::Stylus;
- } else {
- switch (bits & 0x0F06) {
- case 0x0802:
- device = QTabletEvent::Stylus;
- break;
- case 0x0902:
- device = QTabletEvent::Airbrush;
- break;
- case 0x0004:
- device = QTabletEvent::FourDMouse;
- break;
- case 0x0006:
- device = QTabletEvent::Puck;
- break;
- case 0x0804:
- device = QTabletEvent::RotationStylus;
- break;
- default:
- device = QTabletEvent::NoDevice;
- }
- }
- return device;
-}
-
-- (void)tabletProximity:(NSEvent *)theEvent
-{
- if ([self isTransparentForUserInput])
- return [super tabletProximity:theEvent];
-
- ulong timestamp = [theEvent timestamp] * 1000;
-
- QCocoaTabletDeviceData deviceData;
- deviceData.uid = [theEvent uniqueID];
- deviceData.capabilityMask = [theEvent capabilityMask];
-
- switch ([theEvent pointingDeviceType]) {
- case NSUnknownPointingDevice:
- default:
- deviceData.pointerType = QTabletEvent::UnknownPointer;
- break;
- case NSPenPointingDevice:
- deviceData.pointerType = QTabletEvent::Pen;
- break;
- case NSCursorPointingDevice:
- deviceData.pointerType = QTabletEvent::Cursor;
- break;
- case NSEraserPointingDevice:
- deviceData.pointerType = QTabletEvent::Eraser;
- break;
- }
-
- deviceData.device = wacomTabletDevice(theEvent);
-
- // The deviceID is "unique" while in the proximity, it's a key that we can use for
- // linking up QCocoaTabletDeviceData to an event (especially if there are two devices in action).
- bool entering = [theEvent isEnteringProximity];
- uint deviceId = [theEvent deviceID];
- if (entering) {
- tabletDeviceDataHash->insert(deviceId, deviceData);
- } else {
- tabletDeviceDataHash->remove(deviceId);
- }
-
- qCDebug(lcQpaTablet, "proximity change on tablet %d: current tool %d type %d unique ID %lld",
- deviceId, deviceData.device, deviceData.pointerType, deviceData.uid);
-
- if (entering) {
- QWindowSystemInterface::handleTabletEnterProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
- } else {
- QWindowSystemInterface::handleTabletLeaveProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
- }
-}
-#endif
-
-- (bool)shouldSendSingleTouch
-{
- if (!m_platformWindow)
- return true;
-
- // QtWidgets expects single-point touch events, QtDeclarative does not.
- // Until there is an API we solve this by looking at the window class type.
- return m_platformWindow->window()->inherits("QWidgetWindow");
-}
-
-- (void)touchesBeganWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
-}
-
-- (void)touchesMovedWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
-}
-
-- (void)touchesEndedWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
-}
-
-- (void)touchesCancelledWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
-}
-
-#ifndef QT_NO_GESTURES
-
-- (bool)handleGestureAsBeginEnd:(NSEvent *)event
-{
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXElCapitan)
- return false;
-
- if ([event phase] == NSEventPhaseBegan) {
- [self beginGestureWithEvent:event];
- return true;
- }
-
- if ([event phase] == NSEventPhaseEnded) {
- [self endGestureWithEvent:event];
- return true;
- }
-
- return false;
-}
-- (void)magnifyWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- if ([self handleGestureAsBeginEnd:event])
- return;
-
- qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification] << "from device" << hex << [event deviceID];
- const NSTimeInterval timestamp = [event timestamp];
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::ZoomNativeGesture,
- [event magnification], windowPoint, screenPoint);
-}
-
-- (void)smartMagnifyWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- static bool zoomIn = true;
- qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn << "from device" << hex << [event deviceID];
- const NSTimeInterval timestamp = [event timestamp];
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::SmartZoomNativeGesture,
- zoomIn ? 1.0f : 0.0f, windowPoint, screenPoint);
- zoomIn = !zoomIn;
-}
-
-- (void)rotateWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- if ([self handleGestureAsBeginEnd:event])
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::RotateNativeGesture,
- -[event rotation], windowPoint, screenPoint);
-}
-
-- (void)swipeWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY] << "from device" << hex << [event deviceID];
- const NSTimeInterval timestamp = [event timestamp];
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
-
- qreal angle = 0.0f;
- if ([event deltaX] == 1)
- angle = 180.0f;
- else if ([event deltaX] == -1)
- angle = 0.0f;
- else if ([event deltaY] == 1)
- angle = 90.0f;
- else if ([event deltaY] == -1)
- angle = 270.0f;
-
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::SwipeNativeGesture,
- angle, windowPoint, screenPoint);
-}
-
-- (void)beginGestureWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::BeginNativeGesture,
- windowPoint, screenPoint);
-}
-
-- (void)endGestureWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- qCDebug(lcQpaGestures) << "endGestureWithEvent" << "from device" << hex << [event deviceID];
- const NSTimeInterval timestamp = [event timestamp];
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::EndNativeGesture,
- windowPoint, screenPoint);
-}
-#endif // QT_NO_GESTURES
-
-#if QT_CONFIG(wheelevent)
-- (void)scrollWheel:(NSEvent *)theEvent
-{
- if (!m_platformWindow)
- return;
-
- if ([self isTransparentForUserInput])
- return [super scrollWheel:theEvent];
-
- QPoint angleDelta;
- Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
- if ([theEvent hasPreciseScrollingDeltas]) {
- // The mouse device contains pixel scroll wheel support (Mighty Mouse, Trackpad).
- // Since deviceDelta is delivered as pixels rather than degrees, we need to
- // convert from pixels to degrees in a sensible manner.
- // It looks like 1/4 degrees per pixel behaves most native.
- // (NB: Qt expects the unit for delta to be 8 per degree):
- const int pixelsToDegrees = 2; // 8 * 1/4
- angleDelta.setX([theEvent scrollingDeltaX] * pixelsToDegrees);
- angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees);
- source = Qt::MouseEventSynthesizedBySystem;
- } else {
- // Remove acceleration, and use either -120 or 120 as delta:
- angleDelta.setX(qBound(-120, int([theEvent deltaX] * 10000), 120));
- angleDelta.setY(qBound(-120, int([theEvent deltaY] * 10000), 120));
- }
-
- QPoint pixelDelta;
- if ([theEvent hasPreciseScrollingDeltas]) {
- pixelDelta.setX([theEvent scrollingDeltaX]);
- pixelDelta.setY([theEvent scrollingDeltaY]);
- } else {
- // docs: "In the case of !hasPreciseScrollingDeltas, multiply the delta with the line width."
- // scrollingDeltaX seems to return a minimum value of 0.1 in this case, map that to two pixels.
- const CGFloat lineWithEstimate = 20.0;
- pixelDelta.setX([theEvent scrollingDeltaX] * lineWithEstimate);
- pixelDelta.setY([theEvent scrollingDeltaY] * lineWithEstimate);
- }
-
- QPointF qt_windowPoint;
- QPointF qt_screenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qt_windowPoint andScreenPoint:&qt_screenPoint];
- NSTimeInterval timestamp = [theEvent timestamp];
- ulong qt_timestamp = timestamp * 1000;
-
- // Prevent keyboard modifier state from changing during scroll event streams.
- // A two-finger trackpad flick generates a stream of scroll events. We want
- // the keyboard modifier state to be the state at the beginning of the
- // flick in order to avoid changing the interpretation of the events
- // mid-stream. One example of this happening would be when pressing cmd
- // after scrolling in Qt Creator: not taking the phase into account causes
- // the end of the event stream to be interpreted as font size changes.
- NSEventPhase momentumPhase = [theEvent momentumPhase];
- if (momentumPhase == NSEventPhaseNone) {
- currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
- }
-
- NSEventPhase phase = [theEvent phase];
- Qt::ScrollPhase ph = Qt::ScrollUpdate;
-
- // MayBegin is likely to happen. We treat it the same as an actual begin.
- if (phase == NSEventPhaseMayBegin) {
- m_scrolling = true;
- ph = Qt::ScrollBegin;
- } else if (phase == NSEventPhaseBegan) {
- // If MayBegin did not happen, Began is the actual beginning.
- if (!m_scrolling)
- ph = Qt::ScrollBegin;
- m_scrolling = true;
- } else if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled ||
- momentumPhase == NSEventPhaseEnded || momentumPhase == NSEventPhaseCancelled) {
- ph = Qt::ScrollEnd;
- m_scrolling = false;
- } else if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
- ph = Qt::NoScrollPhase;
- }
- // "isInverted": natural OS X scrolling, inverted from the Qt/other platform/Jens perspective.
- bool isInverted = [theEvent isDirectionInvertedFromDevice];
-
- qCDebug(lcQpaCocoaMouse) << "scroll wheel @ window pos" << qt_windowPoint << "delta px" << pixelDelta << "angle" << angleDelta << "phase" << ph << (isInverted ? "inverted" : "");
- QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph, source, isInverted);
-}
-#endif // QT_CONFIG(wheelevent)
-
-- (int) convertKeyCode : (QChar)keyChar
-{
- return qt_mac_cocoaKey2QtKey(keyChar);
-}
-
-+ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags
-{
- const bool dontSwapCtrlAndMeta = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
- Qt::KeyboardModifiers qtMods =Qt::NoModifier;
- if (modifierFlags & NSShiftKeyMask)
- qtMods |= Qt::ShiftModifier;
- if (modifierFlags & NSControlKeyMask)
- qtMods |= dontSwapCtrlAndMeta ? Qt::ControlModifier : Qt::MetaModifier;
- if (modifierFlags & NSAlternateKeyMask)
- qtMods |= Qt::AltModifier;
- if (modifierFlags & NSCommandKeyMask)
- qtMods |= dontSwapCtrlAndMeta ? Qt::MetaModifier : Qt::ControlModifier;
- if (modifierFlags & NSNumericPadKeyMask)
- qtMods |= Qt::KeypadModifier;
- return qtMods;
-}
-
-- (bool)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType
-{
- ulong timestamp = [nsevent timestamp] * 1000;
- ulong nativeModifiers = [nsevent modifierFlags];
- Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers];
- NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers];
- NSString *characters = [nsevent characters];
- if (m_inputSource != characters) {
- [m_inputSource release];
- m_inputSource = [characters retain];
- }
-
- // There is no way to get the scan code from carbon/cocoa. But we cannot
- // use the value 0, since it indicates that the event originates from somewhere
- // else than the keyboard.
- quint32 nativeScanCode = 1;
- quint32 nativeVirtualKey = [nsevent keyCode];
-
- QChar ch = QChar::ReplacementCharacter;
- int keyCode = Qt::Key_unknown;
-
- // If a dead key occurs as a result of pressing a key combination then
- // characters will have 0 length, but charactersIgnoringModifiers will
- // have a valid character in it. This enables key combinations such as
- // ALT+E to be used as a shortcut with an English keyboard even though
- // pressing ALT+E will give a dead key while doing normal text input.
- if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) {
- auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier;
- if (((modifiers & ctrlOrMetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0))
- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
- else if ([characters length] != 0)
- ch = QChar([characters characterAtIndex:0]);
- keyCode = [self convertKeyCode:ch];
- }
-
- // we will send a key event unless the input method sets m_sendKeyEvent to false
- m_sendKeyEvent = true;
- QString text;
- // ignore text for the U+F700-U+F8FF range. This is used by Cocoa when
- // delivering function keys (e.g. arrow keys, backspace, F1-F35, etc.)
- if (!(modifiers & (Qt::ControlModifier | Qt::MetaModifier)) && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff))
- text = QString::fromNSString(characters);
-
- QWindow *window = [self topLevelWindow];
-
- // Popups implicitly grab key events; forward to the active popup if there is one.
- // This allows popups to e.g. intercept shortcuts and close the popup in response.
- if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) {
- if (!popup->m_windowFlags.testFlag(Qt::ToolTip))
- window = popup->window();
- }
-
- if (eventType == QEvent::KeyPress) {
-
- if (m_composingText.isEmpty()) {
- m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode,
- modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
-
- // Handling a shortcut may result in closing the window
- if (!m_platformWindow)
- return true;
- }
-
- QObject *fo = m_platformWindow->window()->focusObject();
- if (m_sendKeyEvent && fo) {
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints);
- if (QCoreApplication::sendEvent(fo, &queryEvent)) {
- bool imEnabled = queryEvent.value(Qt::ImEnabled).toBool();
- Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt());
- if (imEnabled && !(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhHiddenText)) {
- // pass the key event to the input method. note that m_sendKeyEvent may be set to false during this call
- m_currentlyInterpretedKeyEvent = nsevent;
- [self interpretKeyEvents:[NSArray arrayWithObject:nsevent]];
- m_currentlyInterpretedKeyEvent = 0;
- }
- }
- }
- if (m_resendKeyEvent)
- m_sendKeyEvent = true;
- }
-
- bool accepted = true;
- if (m_sendKeyEvent && m_composingText.isEmpty()) {
- QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, QEvent::Type(eventType), keyCode, modifiers,
- nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1, false);
- accepted = QWindowSystemInterface::flushWindowSystemEvents();
- }
- m_sendKeyEvent = false;
- m_resendKeyEvent = false;
- return accepted;
-}
-
-- (void)keyDown:(NSEvent *)nsevent
-{
- if ([self isTransparentForUserInput])
- return [super keyDown:nsevent];
-
- const bool accepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
-
- // When Qt is used to implement a plugin for a native application we
- // want to propagate unhandled events to other native views. However,
- // Qt does not always set the accepted state correctly (in particular
- // for return key events), so do this for plugin applications only
- // to prevent incorrect forwarding in the general case.
- const bool shouldPropagate = QCoreApplication::testAttribute(Qt::AA_PluginApplication) && !accepted;
-
- // Track keyDown acceptance/forward state for later acceptance of the keyUp.
- if (!shouldPropagate)
- m_acceptedKeyDowns.insert([nsevent keyCode]);
-
- if (shouldPropagate)
- [super keyDown:nsevent];
-}
-
-- (void)keyUp:(NSEvent *)nsevent
-{
- if ([self isTransparentForUserInput])
- return [super keyUp:nsevent];
-
- const bool keyUpAccepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
-
- // Propagate the keyUp if neither Qt accepted it nor the corresponding KeyDown was
- // accepted. Qt text controls wil often not use and ignore keyUp events, but we
- // want to avoid propagating unmatched keyUps.
- const bool keyDownAccepted = m_acceptedKeyDowns.remove([nsevent keyCode]);
- if (!keyUpAccepted && !keyDownAccepted)
- [super keyUp:nsevent];
-}
-
-- (void)cancelOperation:(id)sender
-{
- Q_UNUSED(sender);
-
- NSEvent *currentEvent = [NSApp currentEvent];
- if (!currentEvent || currentEvent.type != NSKeyDown)
- return;
-
- // Handling the key event may recurse back here through interpretKeyEvents
- // (when IM is enabled), so we need to guard against that.
- if (currentEvent == m_currentlyInterpretedKeyEvent)
- return;
-
- // Send Command+Key_Period and Escape as normal keypresses so that
- // the key sequence is delivered through Qt. That way clients can
- // intercept the shortcut and override its effect.
- [self handleKeyEvent:currentEvent eventType:int(QEvent::KeyPress)];
-}
-
-- (void)flagsChanged:(NSEvent *)nsevent
-{
- ulong timestamp = [nsevent timestamp] * 1000;
- ulong modifiers = [nsevent modifierFlags];
- Qt::KeyboardModifiers qmodifiers = [QNSView convertKeyModifiers:modifiers];
-
- // calculate the delta and remember the current modifiers for next time
- static ulong m_lastKnownModifiers;
- ulong lastKnownModifiers = m_lastKnownModifiers;
- ulong delta = lastKnownModifiers ^ modifiers;
- m_lastKnownModifiers = modifiers;
-
- struct qt_mac_enum_mapper
- {
- ulong mac_mask;
- Qt::Key qt_code;
- };
- static qt_mac_enum_mapper modifier_key_symbols[] = {
- { NSShiftKeyMask, Qt::Key_Shift },
- { NSControlKeyMask, Qt::Key_Meta },
- { NSCommandKeyMask, Qt::Key_Control },
- { NSAlternateKeyMask, Qt::Key_Alt },
- { NSAlphaShiftKeyMask, Qt::Key_CapsLock },
- { 0ul, Qt::Key_unknown } };
- for (int i = 0; modifier_key_symbols[i].mac_mask != 0u; ++i) {
- uint mac_mask = modifier_key_symbols[i].mac_mask;
- if ((delta & mac_mask) == 0u)
- continue;
-
- Qt::Key qtCode = modifier_key_symbols[i].qt_code;
- if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
- if (qtCode == Qt::Key_Meta)
- qtCode = Qt::Key_Control;
- else if (qtCode == Qt::Key_Control)
- qtCode = Qt::Key_Meta;
- }
- QWindowSystemInterface::handleKeyEvent(m_platformWindow->window(),
- timestamp,
- (lastKnownModifiers & mac_mask) ? QEvent::KeyRelease : QEvent::KeyPress,
- qtCode,
- qmodifiers ^ [QNSView convertKeyModifiers:mac_mask]);
- }
-}
-
-- (void) insertNewline:(id)sender
-{
- Q_UNUSED(sender);
- m_resendKeyEvent = true;
-}
-
-- (void) doCommandBySelector:(SEL)aSelector
-{
- [self tryToPerform:aSelector with:self];
-}
-
-- (void) insertText:(id)aString replacementRange:(NSRange)replacementRange
-{
- Q_UNUSED(replacementRange)
-
- if (m_sendKeyEvent && m_composingText.isEmpty() && [aString isEqualToString:m_inputSource]) {
- // don't send input method events for simple text input (let handleKeyEvent send key events instead)
- return;
- }
-
- QString commitString;
- if ([aString length]) {
- if ([aString isKindOfClass:[NSAttributedString class]]) {
- commitString = QString::fromCFString(reinterpret_cast<CFStringRef>([aString string]));
- } else {
- commitString = QString::fromCFString(reinterpret_cast<CFStringRef>(aString));
- };
- }
- if (QObject *fo = m_platformWindow->window()->focusObject()) {
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (QCoreApplication::sendEvent(fo, &queryEvent)) {
- if (queryEvent.value(Qt::ImEnabled).toBool()) {
- QInputMethodEvent e;
- e.setCommitString(commitString);
- QCoreApplication::sendEvent(fo, &e);
- // prevent handleKeyEvent from sending a key event
- m_sendKeyEvent = false;
- }
- }
- }
-
- m_composingText.clear();
- m_composingFocusObject = nullptr;
-}
-
-- (void) setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
-{
- Q_UNUSED(replacementRange)
- QString preeditString;
-
- QList<QInputMethodEvent::Attribute> attrs;
- attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, selectedRange.location + selectedRange.length, 1, QVariant());
-
- if ([aString isKindOfClass:[NSAttributedString class]]) {
- // Preedit string has attribution
- preeditString = QString::fromCFString(reinterpret_cast<CFStringRef>([aString string]));
- int composingLength = preeditString.length();
- int index = 0;
- // Create attributes for individual sections of preedit text
- while (index < composingLength) {
- NSRange effectiveRange;
- NSRange range = NSMakeRange(index, composingLength-index);
- NSDictionary *attributes = [aString attributesAtIndex:index
- longestEffectiveRange:&effectiveRange
- inRange:range];
- NSNumber *underlineStyle = [attributes objectForKey:NSUnderlineStyleAttributeName];
- if (underlineStyle) {
- QColor clr (Qt::black);
- NSColor *color = [attributes objectForKey:NSUnderlineColorAttributeName];
- if (color) {
- clr = qt_mac_toQColor(color);
- }
- QTextCharFormat format;
- format.setFontUnderline(true);
- format.setUnderlineColor(clr);
- attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
- effectiveRange.location,
- effectiveRange.length,
- format);
- }
- index = effectiveRange.location + effectiveRange.length;
- }
- } else {
- // No attributes specified, take only the preedit text.
- preeditString = QString::fromCFString(reinterpret_cast<CFStringRef>(aString));
- }
-
- if (attrs.isEmpty()) {
- QTextCharFormat format;
- format.setFontUnderline(true);
- attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
- 0, preeditString.length(), format);
- }
-
- m_composingText = preeditString;
-
- if (QObject *fo = m_platformWindow->window()->focusObject()) {
- m_composingFocusObject = fo;
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (QCoreApplication::sendEvent(fo, &queryEvent)) {
- if (queryEvent.value(Qt::ImEnabled).toBool()) {
- QInputMethodEvent e(preeditString, attrs);
- QCoreApplication::sendEvent(fo, &e);
- // prevent handleKeyEvent from sending a key event
- m_sendKeyEvent = false;
- }
- }
- }
-}
-
-- (void)cancelComposingText
-{
- if (m_composingText.isEmpty())
- return;
-
- if (m_composingFocusObject) {
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (QCoreApplication::sendEvent(m_composingFocusObject, &queryEvent)) {
- if (queryEvent.value(Qt::ImEnabled).toBool()) {
- QInputMethodEvent e;
- QCoreApplication::sendEvent(m_composingFocusObject, &e);
- }
- }
- }
-
- m_composingText.clear();
- m_composingFocusObject = nullptr;
-}
-
-- (void) unmarkText
-{
- if (!m_composingText.isEmpty()) {
- if (QObject *fo = m_platformWindow->window()->focusObject()) {
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (QCoreApplication::sendEvent(fo, &queryEvent)) {
- if (queryEvent.value(Qt::ImEnabled).toBool()) {
- QInputMethodEvent e;
- e.setCommitString(m_composingText);
- QCoreApplication::sendEvent(fo, &e);
- }
- }
- }
- }
- m_composingText.clear();
- m_composingFocusObject = nullptr;
-}
-
-- (BOOL) hasMarkedText
-{
- return (m_composingText.isEmpty() ? NO: YES);
-}
-
-- (NSAttributedString *) attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
-{
- Q_UNUSED(actualRange)
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return nil;
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImCurrentSelection);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return nil;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return nil;
-
- QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString();
- if (selectedText.isEmpty())
- return nil;
-
- QCFString string(selectedText.mid(aRange.location, aRange.length));
- const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string);
- return [[[NSAttributedString alloc] initWithString:const_cast<NSString *>(tmpString)] autorelease];
-}
-
-- (NSRange) markedRange
-{
- NSRange range;
- if (!m_composingText.isEmpty()) {
- range.location = 0;
- range.length = m_composingText.length();
- } else {
- range.location = NSNotFound;
- range.length = 0;
- }
- return range;
-}
-
-- (NSRange) selectedRange
-{
- NSRange selectedRange = {0, 0};
-
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return selectedRange;
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImCurrentSelection);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return selectedRange;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return selectedRange;
-
- QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString();
-
- if (!selectedText.isEmpty()) {
- selectedRange.location = 0;
- selectedRange.length = selectedText.length();
- }
- return selectedRange;
-}
-
-- (NSRect) firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
-{
- Q_UNUSED(aRange)
- Q_UNUSED(actualRange)
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return NSZeroRect;
-
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return NSZeroRect;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return NSZeroRect;
-
- if (!m_platformWindow->window())
- return NSZeroRect;
-
- // The returned rect is always based on the internal cursor.
- QRect mr = qApp->inputMethod()->cursorRectangle().toRect();
- mr.moveBottomLeft(m_platformWindow->window()->mapToGlobal(mr.bottomLeft()));
- return QCocoaScreen::mapToNative(mr);
-}
-
-- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
-{
- // We don't support cursor movements using mouse while composing.
- Q_UNUSED(aPoint);
- return NSNotFound;
-}
-
-- (NSArray*)validAttributesForMarkedText
-{
- if (!m_platformWindow)
- return nil;
-
- if (m_platformWindow->window() != QGuiApplication::focusWindow())
- return nil;
-
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return nil;
-
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return nil;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return nil;
-
- // Support only underline color/style.
- return [NSArray arrayWithObjects:NSUnderlineColorAttributeName,
- NSUnderlineStyleAttributeName, nil];
-}
-
--(void)registerDragTypes
-{
- QMacAutoReleasePool pool;
- QStringList customTypes = qt_mac_enabledDraggedTypes();
- if (currentCustomDragTypes == 0 || *currentCustomDragTypes != customTypes) {
- if (currentCustomDragTypes == 0)
- currentCustomDragTypes = new QStringList();
- *currentCustomDragTypes = customTypes;
- const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
- NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
- NSFilenamesPboardType, NSStringPboardType,
- NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
- NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
- NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
- NSRTFDPboardType, NSHTMLPboardType,
- NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
- NSFilesPromisePboardType, NSInkTextPboardType,
- NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
- // Add custom types supported by the application.
- for (int i = 0; i < customTypes.size(); i++) {
- [supportedTypes addObject:customTypes[i].toNSString()];
- }
- [self registerForDraggedTypes:supportedTypes];
- }
-}
-
-static QWindow *findEventTargetWindow(QWindow *candidate)
-{
- while (candidate) {
- if (!(candidate->flags() & Qt::WindowTransparentForInput))
- return candidate;
- candidate = candidate->parent();
- }
- return candidate;
-}
-
-static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint point)
-{
- return target->mapFromGlobal(source->mapToGlobal(point));
-}
-
-- (NSDragOperation)draggingSession:(NSDraggingSession *)session
- sourceOperationMaskForDraggingContext:(NSDraggingContext)context
-{
- Q_UNUSED(session);
- Q_UNUSED(context);
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- return qt_mac_mapDropActions(nativeDrag->currentDrag()->supportedActions());
-}
-
-- (BOOL)ignoreModifierKeysForDraggingSession:(NSDraggingSession *)session
-{
- Q_UNUSED(session);
- // According to the "Dragging Sources" chapter on Cocoa DnD Programming
- // (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DragandDrop/Concepts/dragsource.html),
- // if the control, option, or command key is pressed, the source’s
- // operation mask is filtered to only contain a reduced set of operations.
- //
- // Since Qt already takes care of tracking the keyboard modifiers, we
- // don't need (or want) Cocoa to filter anything. Instead, we'll let
- // the application do the actual filtering.
- return YES;
-}
-
-- (BOOL)wantsPeriodicDraggingUpdates
-{
- // From the documentation:
- //
- // "If the destination returns NO, these messages are sent only when the mouse moves
- // or a modifier flag changes. Otherwise the destination gets the default behavior,
- // where it receives periodic dragging-updated messages even if nothing changes."
- //
- // We do not want these constant drag update events while mouse is stationary,
- // since we do all animations (autoscroll) with timers.
- return NO;
-}
-
-
-- (BOOL)wantsPeriodicDraggingUpdates:(void *)dummy
-{
- // This method never gets called. It's a workaround for Apple's
- // bug: they first respondsToSelector : @selector(wantsPeriodicDraggingUpdates:)
- // (note ':') and then call -wantsPeriodicDraggingUpdate (without colon).
- // So, let's make them happy.
- Q_UNUSED(dummy);
-
- return NO;
-}
-
-- (void)updateCursorFromDragResponse:(QPlatformDragQtResponse)response drag:(QCocoaDrag *)drag
-{
- const QPixmap pixmapCursor = drag->currentDrag()->dragCursor(response.acceptedAction());
- NSCursor *nativeCursor = nil;
-
- if (pixmapCursor.isNull()) {
- switch (response.acceptedAction()) {
- case Qt::CopyAction:
- nativeCursor = [NSCursor dragCopyCursor];
- break;
- case Qt::LinkAction:
- nativeCursor = [NSCursor dragLinkCursor];
- break;
- case Qt::IgnoreAction:
- // Uncomment the next lines if forbiden cursor wanted on non droppable targets.
- /*nativeCursor = [NSCursor operationNotAllowedCursor];
- break;*/
- case Qt::MoveAction:
- default:
- nativeCursor = [NSCursor arrowCursor];
- break;
- }
- }
- else {
- NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor);
- nsimage.size = NSSizeFromCGSize((pixmapCursor.size() / pixmapCursor.devicePixelRatioF()).toCGSize());
- nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint];
- [nsimage release];
- }
-
- // change the cursor
- [nativeCursor set];
-
- // Make sure the cursor is updated correctly if the mouse does not move and window is under cursor
- // by creating a fake move event
- if (m_updatingDrag)
- return;
-
- const QPoint mousePos(QCursor::pos());
- CGEventRef moveEvent(CGEventCreateMouseEvent(
- NULL, kCGEventMouseMoved,
- CGPointMake(mousePos.x(), mousePos.y()),
- kCGMouseButtonLeft // ignored
- ));
- CGEventPost(kCGHIDEventTap, moveEvent);
- CFRelease(moveEvent);
-}
-
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
-{
- return [self handleDrag : sender];
-}
-
-- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
-{
- m_updatingDrag = true;
- const NSDragOperation ret([self handleDrag : sender]);
- m_updatingDrag = false;
-
- return ret;
-}
-
-// Sends drag update to Qt, return the action
-- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender
-{
- if (!m_platformWindow)
- return NSDragOperationNone;
-
- NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
- QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
- Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
-
- QWindow *target = findEventTargetWindow(m_platformWindow->window());
- if (!target)
- return NSDragOperationNone;
-
- // update these so selecting move/copy/link works
- QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]];
-
- QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect());
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- if (nativeDrag->currentDrag()) {
- // The drag was started from within the application
- response = QWindowSystemInterface::handleDrag(target, nativeDrag->dragMimeData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
- [self updateCursorFromDragResponse:response drag:nativeDrag];
- } else {
- QCocoaDropData mimeData([sender draggingPasteboard]);
- response = QWindowSystemInterface::handleDrag(target, &mimeData, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
- }
-
- return qt_mac_mapDropAction(response.acceptedAction());
-}
-
-- (void)draggingExited:(id <NSDraggingInfo>)sender
-{
- if (!m_platformWindow)
- return;
-
- QWindow *target = findEventTargetWindow(m_platformWindow->window());
- if (!target)
- return;
-
- NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
- QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
-
- // Send 0 mime data to indicate drag exit
- QWindowSystemInterface::handleDrag(target, 0, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), Qt::IgnoreAction);
-}
-
-// called on drop, send the drop to Qt and return if it was accepted.
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
-{
- if (!m_platformWindow)
- return false;
-
- QWindow *target = findEventTargetWindow(m_platformWindow->window());
- if (!target)
- return false;
-
- NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
- QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
- Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
-
- QPlatformDropQtResponse response(false, Qt::IgnoreAction);
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- if (nativeDrag->currentDrag()) {
- // The drag was started from within the application
- response = QWindowSystemInterface::handleDrop(target, nativeDrag->dragMimeData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
- } else {
- QCocoaDropData mimeData([sender draggingPasteboard]);
- response = QWindowSystemInterface::handleDrop(target, &mimeData, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
- }
- if (response.isAccepted()) {
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- nativeDrag->setAcceptedAction(response.acceptedAction());
- }
- return response.isAccepted();
-}
-
-- (void)draggingSession:(NSDraggingSession *)session
- endedAtPoint:(NSPoint)screenPoint
- operation:(NSDragOperation)operation
-{
- Q_UNUSED(session);
- Q_UNUSED(operation);
-
- if (!m_platformWindow)
- return;
-
- QWindow *target = findEventTargetWindow(m_platformWindow->window());
- if (!target)
- return;
-
- // keep our state, and QGuiApplication state (buttons member) in-sync,
- // or future mouse events will be processed incorrectly
- NSUInteger pmb = [NSEvent pressedMouseButtons];
- for (int buttonNumber = 0; buttonNumber < 32; buttonNumber++) { // see cocoaButton2QtButton() for the 32 value
- if (!(pmb & (1 << buttonNumber)))
- m_buttons &= ~cocoaButton2QtButton(buttonNumber);
- }
-
- NSPoint windowPoint = [self.window convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 1, 1)].origin;
- NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil]; // NSView/QWindow coordinates
- QPoint qtWindowPoint(nsViewPoint.x, nsViewPoint.y);
- QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
+@end
- QWindowSystemInterface::handleMouseEvent(target, mapWindowCoordinates(m_platformWindow->window(), target, qtWindowPoint), qtScreenPoint, m_buttons);
-}
+#include "qnsview_drawing.mm"
+#include "qnsview_mouse.mm"
+#include "qnsview_touch.mm"
+#include "qnsview_gestures.mm"
+#include "qnsview_tablet.mm"
+#include "qnsview_dragging.mm"
+#include "qnsview_keys.mm"
+#include "qnsview_complextext.mm"
+#include "qnsview_menus.mm"
-@end
+// -----------------------------------------------------
@implementation QT_MANGLE_NAMESPACE(QNSView) (QtExtras)
@@ -2085,9 +372,4 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
return m_platformWindow.data();;
}
-- (BOOL)isMenuView
-{
- return m_isMenuView;
-}
-
@end
diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm
new file mode 100644
index 0000000000..d357082d33
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (ComplexTextAPI)
+
+- (void)cancelComposingText
+{
+ if (m_composingText.isEmpty())
+ return;
+
+ if (m_composingFocusObject) {
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
+ if (QCoreApplication::sendEvent(m_composingFocusObject, &queryEvent)) {
+ if (queryEvent.value(Qt::ImEnabled).toBool()) {
+ QInputMethodEvent e;
+ QCoreApplication::sendEvent(m_composingFocusObject, &e);
+ }
+ }
+ }
+
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
+}
+
+- (void)unmarkText
+{
+ if (!m_composingText.isEmpty()) {
+ if (QObject *fo = m_platformWindow->window()->focusObject()) {
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
+ if (QCoreApplication::sendEvent(fo, &queryEvent)) {
+ if (queryEvent.value(Qt::ImEnabled).toBool()) {
+ QInputMethodEvent e;
+ e.setCommitString(m_composingText);
+ QCoreApplication::sendEvent(fo, &e);
+ }
+ }
+ }
+ }
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
+}
+
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (ComplexText)
+
+- (void)insertNewline:(id)sender
+{
+ Q_UNUSED(sender);
+ m_resendKeyEvent = true;
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+ [self tryToPerform:aSelector with:self];
+}
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
+{
+ Q_UNUSED(replacementRange)
+
+ if (m_sendKeyEvent && m_composingText.isEmpty() && [aString isEqualToString:m_inputSource]) {
+ // don't send input method events for simple text input (let handleKeyEvent send key events instead)
+ return;
+ }
+
+ QString commitString;
+ if ([aString length]) {
+ if ([aString isKindOfClass:[NSAttributedString class]]) {
+ commitString = QString::fromCFString(reinterpret_cast<CFStringRef>([aString string]));
+ } else {
+ commitString = QString::fromCFString(reinterpret_cast<CFStringRef>(aString));
+ };
+ }
+ if (QObject *fo = m_platformWindow->window()->focusObject()) {
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
+ if (QCoreApplication::sendEvent(fo, &queryEvent)) {
+ if (queryEvent.value(Qt::ImEnabled).toBool()) {
+ QInputMethodEvent e;
+ e.setCommitString(commitString);
+ QCoreApplication::sendEvent(fo, &e);
+ // prevent handleKeyEvent from sending a key event
+ m_sendKeyEvent = false;
+ }
+ }
+ }
+
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
+{
+ Q_UNUSED(replacementRange)
+ QString preeditString;
+
+ QList<QInputMethodEvent::Attribute> attrs;
+ attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, selectedRange.location + selectedRange.length, 1, QVariant());
+
+ if ([aString isKindOfClass:[NSAttributedString class]]) {
+ // Preedit string has attribution
+ preeditString = QString::fromCFString(reinterpret_cast<CFStringRef>([aString string]));
+ int composingLength = preeditString.length();
+ int index = 0;
+ // Create attributes for individual sections of preedit text
+ while (index < composingLength) {
+ NSRange effectiveRange;
+ NSRange range = NSMakeRange(index, composingLength-index);
+ NSDictionary *attributes = [aString attributesAtIndex:index
+ longestEffectiveRange:&effectiveRange
+ inRange:range];
+ NSNumber *underlineStyle = [attributes objectForKey:NSUnderlineStyleAttributeName];
+ if (underlineStyle) {
+ QColor clr (Qt::black);
+ NSColor *color = [attributes objectForKey:NSUnderlineColorAttributeName];
+ if (color) {
+ clr = qt_mac_toQColor(color);
+ }
+ QTextCharFormat format;
+ format.setFontUnderline(true);
+ format.setUnderlineColor(clr);
+ attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
+ effectiveRange.location,
+ effectiveRange.length,
+ format);
+ }
+ index = effectiveRange.location + effectiveRange.length;
+ }
+ } else {
+ // No attributes specified, take only the preedit text.
+ preeditString = QString::fromCFString(reinterpret_cast<CFStringRef>(aString));
+ }
+
+ if (attrs.isEmpty()) {
+ QTextCharFormat format;
+ format.setFontUnderline(true);
+ attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
+ 0, preeditString.length(), format);
+ }
+
+ m_composingText = preeditString;
+
+ if (QObject *fo = m_platformWindow->window()->focusObject()) {
+ m_composingFocusObject = fo;
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
+ if (QCoreApplication::sendEvent(fo, &queryEvent)) {
+ if (queryEvent.value(Qt::ImEnabled).toBool()) {
+ QInputMethodEvent e(preeditString, attrs);
+ QCoreApplication::sendEvent(fo, &e);
+ // prevent handleKeyEvent from sending a key event
+ m_sendKeyEvent = false;
+ }
+ }
+ }
+}
+
+- (BOOL)hasMarkedText
+{
+ return (m_composingText.isEmpty() ? NO: YES);
+}
+
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ Q_UNUSED(actualRange)
+ QObject *fo = m_platformWindow->window()->focusObject();
+ if (!fo)
+ return nil;
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImCurrentSelection);
+ if (!QCoreApplication::sendEvent(fo, &queryEvent))
+ return nil;
+ if (!queryEvent.value(Qt::ImEnabled).toBool())
+ return nil;
+
+ QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString();
+ if (selectedText.isEmpty())
+ return nil;
+
+ QCFString string(selectedText.mid(aRange.location, aRange.length));
+ const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string);
+ return [[[NSAttributedString alloc] initWithString:const_cast<NSString *>(tmpString)] autorelease];
+}
+
+- (NSRange)markedRange
+{
+ NSRange range;
+ if (!m_composingText.isEmpty()) {
+ range.location = 0;
+ range.length = m_composingText.length();
+ } else {
+ range.location = NSNotFound;
+ range.length = 0;
+ }
+ return range;
+}
+
+- (NSRange)selectedRange
+{
+ NSRange selectedRange = {0, 0};
+
+ QObject *fo = m_platformWindow->window()->focusObject();
+ if (!fo)
+ return selectedRange;
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImCurrentSelection);
+ if (!QCoreApplication::sendEvent(fo, &queryEvent))
+ return selectedRange;
+ if (!queryEvent.value(Qt::ImEnabled).toBool())
+ return selectedRange;
+
+ QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString();
+
+ if (!selectedText.isEmpty()) {
+ selectedRange.location = 0;
+ selectedRange.length = selectedText.length();
+ }
+ return selectedRange;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ Q_UNUSED(aRange)
+ Q_UNUSED(actualRange)
+
+ QObject *fo = m_platformWindow->window()->focusObject();
+ if (!fo)
+ return NSZeroRect;
+
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
+ if (!QCoreApplication::sendEvent(fo, &queryEvent))
+ return NSZeroRect;
+ if (!queryEvent.value(Qt::ImEnabled).toBool())
+ return NSZeroRect;
+
+ // The returned rect is always based on the internal cursor.
+ QRect mr = qApp->inputMethod()->cursorRectangle().toRect();
+ mr.moveBottomLeft(m_platformWindow->window()->mapToGlobal(mr.bottomLeft()));
+ return QCocoaScreen::mapToNative(mr);
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+{
+ // We don't support cursor movements using mouse while composing.
+ Q_UNUSED(aPoint);
+ return NSNotFound;
+}
+
+- (NSArray<NSString *> *)validAttributesForMarkedText
+{
+ if (!m_platformWindow)
+ return nil;
+
+ if (m_platformWindow->window() != QGuiApplication::focusWindow())
+ return nil;
+
+ QObject *fo = m_platformWindow->window()->focusObject();
+ if (!fo)
+ return nil;
+
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
+ if (!QCoreApplication::sendEvent(fo, &queryEvent))
+ return nil;
+ if (!queryEvent.value(Qt::ImEnabled).toBool())
+ return nil;
+
+ // Support only underline color/style.
+ return @[NSUnderlineColorAttributeName, NSUnderlineStyleAttributeName];
+}
+
+- (void)textInputContextKeyboardSelectionDidChangeNotification:(NSNotification *)textInputContextKeyboardSelectionDidChangeNotification
+{
+ Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification)
+ if (([NSApp keyWindow] == self.window) && self.window.firstResponder == self) {
+ QCocoaInputContext *ic = qobject_cast<QCocoaInputContext *>(QCocoaIntegration::instance()->inputContext());
+ ic->updateLocale();
+ }
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm
new file mode 100644
index 0000000000..e77a26eed0
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm
@@ -0,0 +1,302 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Dragging)
+
+-(void)registerDragTypes
+{
+ QMacAutoReleasePool pool;
+ QStringList customTypes = qt_mac_enabledDraggedTypes();
+ if (currentCustomDragTypes == 0 || *currentCustomDragTypes != customTypes) {
+ if (currentCustomDragTypes == 0)
+ currentCustomDragTypes = new QStringList();
+ *currentCustomDragTypes = customTypes;
+ NSString * const mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
+ NSMutableArray<NSString *> *supportedTypes = [NSMutableArray<NSString *> arrayWithArray:@[
+ NSColorPboardType,
+ NSFilenamesPboardType, NSStringPboardType,
+ NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
+ NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
+ NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
+ NSRTFDPboardType, NSHTMLPboardType,
+ NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
+ NSFilesPromisePboardType, NSInkTextPboardType,
+ NSMultipleTextSelectionPboardType, mimeTypeGeneric]];
+ // Add custom types supported by the application.
+ for (int i = 0; i < customTypes.size(); i++) {
+ [supportedTypes addObject:customTypes[i].toNSString()];
+ }
+ [self registerForDraggedTypes:supportedTypes];
+ }
+}
+
+static QWindow *findEventTargetWindow(QWindow *candidate)
+{
+ while (candidate) {
+ if (!(candidate->flags() & Qt::WindowTransparentForInput))
+ return candidate;
+ candidate = candidate->parent();
+ }
+ return candidate;
+}
+
+static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint point)
+{
+ return target->mapFromGlobal(source->mapToGlobal(point));
+}
+
+- (NSDragOperation)draggingSession:(NSDraggingSession *)session
+ sourceOperationMaskForDraggingContext:(NSDraggingContext)context
+{
+ Q_UNUSED(session);
+ Q_UNUSED(context);
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ return qt_mac_mapDropActions(nativeDrag->currentDrag()->supportedActions());
+}
+
+- (BOOL)ignoreModifierKeysForDraggingSession:(NSDraggingSession *)session
+{
+ Q_UNUSED(session);
+ // According to the "Dragging Sources" chapter on Cocoa DnD Programming
+ // (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DragandDrop/Concepts/dragsource.html),
+ // if the control, option, or command key is pressed, the source’s
+ // operation mask is filtered to only contain a reduced set of operations.
+ //
+ // Since Qt already takes care of tracking the keyboard modifiers, we
+ // don't need (or want) Cocoa to filter anything. Instead, we'll let
+ // the application do the actual filtering.
+ return YES;
+}
+
+- (BOOL)wantsPeriodicDraggingUpdates
+{
+ // From the documentation:
+ //
+ // "If the destination returns NO, these messages are sent only when the mouse moves
+ // or a modifier flag changes. Otherwise the destination gets the default behavior,
+ // where it receives periodic dragging-updated messages even if nothing changes."
+ //
+ // We do not want these constant drag update events while mouse is stationary,
+ // since we do all animations (autoscroll) with timers.
+ return NO;
+}
+
+
+- (BOOL)wantsPeriodicDraggingUpdates:(void *)dummy
+{
+ // This method never gets called. It's a workaround for Apple's
+ // bug: they first respondsToSelector : @selector(wantsPeriodicDraggingUpdates:)
+ // (note ':') and then call -wantsPeriodicDraggingUpdate (without colon).
+ // So, let's make them happy.
+ Q_UNUSED(dummy);
+
+ return NO;
+}
+
+- (void)updateCursorFromDragResponse:(QPlatformDragQtResponse)response drag:(QCocoaDrag *)drag
+{
+ const QPixmap pixmapCursor = drag->currentDrag()->dragCursor(response.acceptedAction());
+ NSCursor *nativeCursor = nil;
+
+ if (pixmapCursor.isNull()) {
+ switch (response.acceptedAction()) {
+ case Qt::CopyAction:
+ nativeCursor = [NSCursor dragCopyCursor];
+ break;
+ case Qt::LinkAction:
+ nativeCursor = [NSCursor dragLinkCursor];
+ break;
+ case Qt::IgnoreAction:
+ // Uncomment the next lines if forbiden cursor wanted on non droppable targets.
+ /*nativeCursor = [NSCursor operationNotAllowedCursor];
+ break;*/
+ case Qt::MoveAction:
+ default:
+ nativeCursor = [NSCursor arrowCursor];
+ break;
+ }
+ }
+ else {
+ NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor);
+ nsimage.size = NSSizeFromCGSize((pixmapCursor.size() / pixmapCursor.devicePixelRatioF()).toCGSize());
+ nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint];
+ [nsimage release];
+ }
+
+ // change the cursor
+ [nativeCursor set];
+
+ // Make sure the cursor is updated correctly if the mouse does not move and window is under cursor
+ // by creating a fake move event
+ if (m_updatingDrag)
+ return;
+
+ const QPoint mousePos(QCursor::pos());
+ CGEventRef moveEvent(CGEventCreateMouseEvent(
+ NULL, kCGEventMouseMoved,
+ CGPointMake(mousePos.x(), mousePos.y()),
+ kCGMouseButtonLeft // ignored
+ ));
+ CGEventPost(kCGHIDEventTap, moveEvent);
+ CFRelease(moveEvent);
+}
+
+- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return [self handleDrag : sender];
+}
+
+- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ m_updatingDrag = true;
+ const NSDragOperation ret([self handleDrag : sender]);
+ m_updatingDrag = false;
+
+ return ret;
+}
+
+// Sends drag update to Qt, return the action
+- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender
+{
+ if (!m_platformWindow)
+ return NSDragOperationNone;
+
+ NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
+ QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
+ Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
+
+ QWindow *target = findEventTargetWindow(m_platformWindow->window());
+ if (!target)
+ return NSDragOperationNone;
+
+ // update these so selecting move/copy/link works
+ QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]];
+
+ QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect());
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ if (nativeDrag->currentDrag()) {
+ // The drag was started from within the application
+ response = QWindowSystemInterface::handleDrag(target, nativeDrag->dragMimeData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
+ [self updateCursorFromDragResponse:response drag:nativeDrag];
+ } else {
+ QCocoaDropData mimeData([sender draggingPasteboard]);
+ response = QWindowSystemInterface::handleDrag(target, &mimeData, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
+ }
+
+ return qt_mac_mapDropAction(response.acceptedAction());
+}
+
+- (void)draggingExited:(id <NSDraggingInfo>)sender
+{
+ if (!m_platformWindow)
+ return;
+
+ QWindow *target = findEventTargetWindow(m_platformWindow->window());
+ if (!target)
+ return;
+
+ NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
+ QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
+
+ // Send 0 mime data to indicate drag exit
+ QWindowSystemInterface::handleDrag(target, 0, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), Qt::IgnoreAction);
+}
+
+// called on drop, send the drop to Qt and return if it was accepted.
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ if (!m_platformWindow)
+ return false;
+
+ QWindow *target = findEventTargetWindow(m_platformWindow->window());
+ if (!target)
+ return false;
+
+ NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
+ QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
+ Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
+
+ QPlatformDropQtResponse response(false, Qt::IgnoreAction);
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ if (nativeDrag->currentDrag()) {
+ // The drag was started from within the application
+ response = QWindowSystemInterface::handleDrop(target, nativeDrag->dragMimeData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
+ } else {
+ QCocoaDropData mimeData([sender draggingPasteboard]);
+ response = QWindowSystemInterface::handleDrop(target, &mimeData, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
+ }
+ return response.isAccepted();
+}
+
+- (void)draggingSession:(NSDraggingSession *)session
+ endedAtPoint:(NSPoint)screenPoint
+ operation:(NSDragOperation)operation
+{
+ Q_UNUSED(session);
+ Q_UNUSED(operation);
+
+ if (!m_platformWindow)
+ return;
+
+ QWindow *target = findEventTargetWindow(m_platformWindow->window());
+ if (!target)
+ return;
+
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation));
+
+ // keep our state, and QGuiApplication state (buttons member) in-sync,
+ // or future mouse events will be processed incorrectly
+ NSUInteger pmb = [NSEvent pressedMouseButtons];
+ for (int buttonNumber = 0; buttonNumber < 32; buttonNumber++) { // see cocoaButton2QtButton() for the 32 value
+ if (!(pmb & (1 << buttonNumber)))
+ m_buttons &= ~cocoaButton2QtButton(buttonNumber);
+ }
+
+ NSPoint windowPoint = [self.window convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 1, 1)].origin;
+ NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil]; // NSView/QWindow coordinates
+ QPoint qtWindowPoint(nsViewPoint.x, nsViewPoint.y);
+ QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
+
+ QWindowSystemInterface::handleMouseEvent(target, mapWindowCoordinates(m_platformWindow->window(), target, qtWindowPoint), qtScreenPoint, m_buttons);
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm
new file mode 100644
index 0000000000..3bba68b0cf
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (DrawingAPI)
+
+- (void)requestUpdate
+{
+ if (self.needsDisplay) {
+ // If the view already has needsDisplay set it means that there may be code waiting for
+ // a real expose event, so we can't issue setNeedsDisplay now as a way to trigger an
+ // update request. We will re-trigger requestUpdate from drawRect.
+ return;
+ }
+
+ [self setNeedsDisplay:YES];
+ m_updateRequested = true;
+}
+
+#ifndef QT_NO_OPENGL
+- (void)setQCocoaGLContext:(QCocoaGLContext *)context
+{
+ m_glContext = context;
+ [m_glContext->nsOpenGLContext() setView:self];
+ if (![m_glContext->nsOpenGLContext() view]) {
+ //was unable to set view
+ m_shouldSetGLContextinDrawRect = true;
+ }
+}
+#endif
+
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Drawing)
+
+- (BOOL)isOpaque
+{
+ if (!m_platformWindow)
+ return true;
+ return m_platformWindow->isOpaque();
+}
+
+- (BOOL)isFlipped
+{
+ return YES;
+}
+
+- (void)setNeedsDisplayInRect:(NSRect)rect
+{
+ [super setNeedsDisplayInRect:rect];
+ m_updateRequested = false;
+}
+
+- (void)drawRect:(NSRect)dirtyRect
+{
+ Q_UNUSED(dirtyRect);
+
+ if (!m_platformWindow)
+ return;
+
+ QRegion exposedRegion;
+ const NSRect *dirtyRects;
+ NSInteger numDirtyRects;
+ [self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
+ for (int i = 0; i < numDirtyRects; ++i)
+ exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
+
+ qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
+ [self updateRegion:exposedRegion];
+}
+
+- (void)updateRegion:(QRegion)dirtyRegion
+{
+#ifndef QT_NO_OPENGL
+ if (m_glContext && m_shouldSetGLContextinDrawRect) {
+ [m_glContext->nsOpenGLContext() setView:self];
+ m_shouldSetGLContextinDrawRect = false;
+ }
+#endif
+
+ if (m_updateRequested) {
+ Q_ASSERT(m_platformWindow->hasPendingUpdateRequest());
+ m_platformWindow->deliverUpdateRequest();
+ m_updateRequested = false;
+ } else {
+ m_platformWindow->handleExposeEvent(dirtyRegion);
+ }
+
+ if (m_updateRequested && m_platformWindow->hasPendingUpdateRequest()) {
+ // A call to QWindow::requestUpdate was issued during event delivery above,
+ // but AppKit will reset the needsDisplay state of the view after completing
+ // the current display cycle, so we need to defer the request to redisplay.
+ // FIXME: Perhaps this should be a trigger to enable CADisplayLink?
+ qCDebug(lcQpaDrawing) << "[QNSView drawRect:] issuing deferred setNeedsDisplay due to pending update request";
+ dispatch_async(dispatch_get_main_queue (), ^{ [self requestUpdate]; });
+ }
+}
+
+- (BOOL)wantsLayer
+{
+ Q_ASSERT(m_platformWindow);
+
+ // Toggling the private QWindow property or the environment variable
+ // on and off is not a supported use-case, so this code is effectively
+ // returning a constant for the lifetime of our QSNSView, which means
+ // we don't care about emitting KVO signals for @"wantsLayer".
+ return qt_mac_resolveOption(false, m_platformWindow->window(),
+ "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER");
+}
+
+- (CALayer *)makeBackingLayer
+{
+ bool makeMetalLayer = false; // TODO: Add/implement enabling API
+ if (makeMetalLayer) {
+ // Check if Metal is supported. If it isn't then it's most likely
+ // too late at this point and the QWindow will be non-functional,
+ // but we can at least print a warning.
+ if (![MTLCreateSystemDefaultDevice() autorelease]) {
+ qWarning() << "QWindow initialization error: Metal is not supported";
+ return [super makeBackingLayer];
+ }
+
+ CAMetalLayer *layer = [CAMetalLayer layer];
+
+ // Set the contentsScale for the layer. This is normally done in
+ // viewDidChangeBackingProperties, however on startup that function
+ // is called before the layer is created here. The layer's drawableSize
+ // is updated from layoutSublayersOfLayer as usual.
+ layer.contentsScale = self.window.backingScaleFactor;
+
+ return layer;
+ }
+
+ return [super makeBackingLayer];
+}
+
+- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
+{
+ // We need to set this this excplicitly since the super implementation
+ // returns LayerContentsRedrawNever for custom layers like CAMetalLayer.
+ return NSViewLayerContentsRedrawDuringViewResize;
+}
+
+- (void)updateMetalLayerDrawableSize:(CAMetalLayer *)layer
+{
+ CGSize drawableSize = layer.bounds.size;
+ drawableSize.width *= layer.contentsScale;
+ drawableSize.height *= layer.contentsScale;
+ layer.drawableSize = drawableSize;
+}
+
+- (void)layoutSublayersOfLayer:(CALayer *)layer
+{
+ if ([layer isKindOfClass:CAMetalLayer.class])
+ [self updateMetalLayerDrawableSize:static_cast<CAMetalLayer* >(layer)];
+}
+
+- (void)displayLayer:(CALayer *)layer
+{
+ Q_ASSERT(layer == self.layer);
+
+ if (!m_platformWindow)
+ return;
+
+ qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window();
+
+ // FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
+ [self updateRegion:QRectF::fromCGRect(self.bounds).toRect()];
+}
+
+- (void)viewDidChangeBackingProperties
+{
+ CALayer *layer = self.layer;
+ if (!layer)
+ return;
+
+ layer.contentsScale = self.window.backingScaleFactor;
+
+ // Metal layers must be manually updated on e.g. screen change
+ if ([layer isKindOfClass:CAMetalLayer.class]) {
+ [self updateMetalLayerDrawableSize:static_cast<CAMetalLayer* >(layer)];
+ [self setNeedsDisplay:YES];
+ }
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_gestures.mm b/src/plugins/platforms/cocoa/qnsview_gestures.mm
new file mode 100644
index 0000000000..61d551ee0e
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_gestures.mm
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+#ifndef QT_NO_GESTURES
+
+Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Gestures)
+
+- (bool)handleGestureAsBeginEnd:(NSEvent *)event
+{
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXElCapitan)
+ return false;
+
+ if ([event phase] == NSEventPhaseBegan) {
+ [self beginGestureWithEvent:event];
+ return true;
+ }
+
+ if ([event phase] == NSEventPhaseEnded) {
+ [self endGestureWithEvent:event];
+ return true;
+ }
+
+ return false;
+}
+- (void)magnifyWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ if ([self handleGestureAsBeginEnd:event])
+ return;
+
+ qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification] << "from device" << hex << [event deviceID];
+ const NSTimeInterval timestamp = [event timestamp];
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::ZoomNativeGesture,
+ [event magnification], windowPoint, screenPoint);
+}
+
+- (void)smartMagnifyWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ static bool zoomIn = true;
+ qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn << "from device" << hex << [event deviceID];
+ const NSTimeInterval timestamp = [event timestamp];
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::SmartZoomNativeGesture,
+ zoomIn ? 1.0f : 0.0f, windowPoint, screenPoint);
+ zoomIn = !zoomIn;
+}
+
+- (void)rotateWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ if ([self handleGestureAsBeginEnd:event])
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::RotateNativeGesture,
+ -[event rotation], windowPoint, screenPoint);
+}
+
+- (void)swipeWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY] << "from device" << hex << [event deviceID];
+ const NSTimeInterval timestamp = [event timestamp];
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+
+ qreal angle = 0.0f;
+ if ([event deltaX] == 1)
+ angle = 180.0f;
+ else if ([event deltaX] == -1)
+ angle = 0.0f;
+ else if ([event deltaY] == 1)
+ angle = 90.0f;
+ else if ([event deltaY] == -1)
+ angle = 270.0f;
+
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::SwipeNativeGesture,
+ angle, windowPoint, screenPoint);
+}
+
+- (void)beginGestureWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::BeginNativeGesture,
+ windowPoint, screenPoint);
+}
+
+- (void)endGestureWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ qCDebug(lcQpaGestures) << "endGestureWithEvent" << "from device" << hex << [event deviceID];
+ const NSTimeInterval timestamp = [event timestamp];
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::EndNativeGesture,
+ windowPoint, screenPoint);
+}
+
+@end
+
+#endif // QT_NO_GESTURES
diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm
new file mode 100644
index 0000000000..57ce6a009f
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_keys.mm
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (KeysAPI)
+
++ (Qt::KeyboardModifiers)convertKeyModifiers:(ulong)modifierFlags
+{
+ const bool dontSwapCtrlAndMeta = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
+ Qt::KeyboardModifiers qtMods =Qt::NoModifier;
+ if (modifierFlags & NSShiftKeyMask)
+ qtMods |= Qt::ShiftModifier;
+ if (modifierFlags & NSControlKeyMask)
+ qtMods |= dontSwapCtrlAndMeta ? Qt::ControlModifier : Qt::MetaModifier;
+ if (modifierFlags & NSAlternateKeyMask)
+ qtMods |= Qt::AltModifier;
+ if (modifierFlags & NSCommandKeyMask)
+ qtMods |= dontSwapCtrlAndMeta ? Qt::MetaModifier : Qt::ControlModifier;
+ if (modifierFlags & NSNumericPadKeyMask)
+ qtMods |= Qt::KeypadModifier;
+ return qtMods;
+}
+
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Keys)
+
+- (int)convertKeyCode:(QChar)keyChar
+{
+ return qt_mac_cocoaKey2QtKey(keyChar);
+}
+
+- (bool)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType
+{
+ ulong timestamp = [nsevent timestamp] * 1000;
+ ulong nativeModifiers = [nsevent modifierFlags];
+ Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers];
+ NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers];
+ NSString *characters = [nsevent characters];
+ if (m_inputSource != characters) {
+ [m_inputSource release];
+ m_inputSource = [characters retain];
+ }
+
+ // There is no way to get the scan code from carbon/cocoa. But we cannot
+ // use the value 0, since it indicates that the event originates from somewhere
+ // else than the keyboard.
+ quint32 nativeScanCode = 1;
+ quint32 nativeVirtualKey = [nsevent keyCode];
+
+ QChar ch = QChar::ReplacementCharacter;
+ int keyCode = Qt::Key_unknown;
+
+ // If a dead key occurs as a result of pressing a key combination then
+ // characters will have 0 length, but charactersIgnoringModifiers will
+ // have a valid character in it. This enables key combinations such as
+ // ALT+E to be used as a shortcut with an English keyboard even though
+ // pressing ALT+E will give a dead key while doing normal text input.
+ if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) {
+ auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier;
+ if (((modifiers & ctrlOrMetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0))
+ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
+ else if ([characters length] != 0)
+ ch = QChar([characters characterAtIndex:0]);
+ keyCode = [self convertKeyCode:ch];
+ }
+
+ // we will send a key event unless the input method sets m_sendKeyEvent to false
+ m_sendKeyEvent = true;
+ QString text;
+ // ignore text for the U+F700-U+F8FF range. This is used by Cocoa when
+ // delivering function keys (e.g. arrow keys, backspace, F1-F35, etc.)
+ if (!(modifiers & (Qt::ControlModifier | Qt::MetaModifier)) && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff))
+ text = QString::fromNSString(characters);
+
+ QWindow *window = [self topLevelWindow];
+
+ // Popups implicitly grab key events; forward to the active popup if there is one.
+ // This allows popups to e.g. intercept shortcuts and close the popup in response.
+ if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) {
+ if (!popup->window()->flags().testFlag(Qt::ToolTip))
+ window = popup->window();
+ }
+
+ if (eventType == QEvent::KeyPress) {
+
+ if (m_composingText.isEmpty()) {
+ m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode,
+ modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
+
+ // Handling a shortcut may result in closing the window
+ if (!m_platformWindow)
+ return true;
+ }
+
+ QObject *fo = m_platformWindow->window()->focusObject();
+ if (m_sendKeyEvent && fo) {
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints);
+ if (QCoreApplication::sendEvent(fo, &queryEvent)) {
+ bool imEnabled = queryEvent.value(Qt::ImEnabled).toBool();
+ Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt());
+ if (imEnabled && !(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhHiddenText)) {
+ // pass the key event to the input method. note that m_sendKeyEvent may be set to false during this call
+ m_currentlyInterpretedKeyEvent = nsevent;
+ [self interpretKeyEvents:@[nsevent]];
+ m_currentlyInterpretedKeyEvent = 0;
+ }
+ }
+ }
+ if (m_resendKeyEvent)
+ m_sendKeyEvent = true;
+ }
+
+ bool accepted = true;
+ if (m_sendKeyEvent && m_composingText.isEmpty()) {
+ QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, QEvent::Type(eventType), keyCode, modifiers,
+ nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1, false);
+ accepted = QWindowSystemInterface::flushWindowSystemEvents();
+ }
+ m_sendKeyEvent = false;
+ m_resendKeyEvent = false;
+ return accepted;
+}
+
+- (void)keyDown:(NSEvent *)nsevent
+{
+ if ([self isTransparentForUserInput])
+ return [super keyDown:nsevent];
+
+ const bool accepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
+
+ // When Qt is used to implement a plugin for a native application we
+ // want to propagate unhandled events to other native views. However,
+ // Qt does not always set the accepted state correctly (in particular
+ // for return key events), so do this for plugin applications only
+ // to prevent incorrect forwarding in the general case.
+ const bool shouldPropagate = QCoreApplication::testAttribute(Qt::AA_PluginApplication) && !accepted;
+
+ // Track keyDown acceptance/forward state for later acceptance of the keyUp.
+ if (!shouldPropagate)
+ m_acceptedKeyDowns.insert([nsevent keyCode]);
+
+ if (shouldPropagate)
+ [super keyDown:nsevent];
+}
+
+- (void)keyUp:(NSEvent *)nsevent
+{
+ if ([self isTransparentForUserInput])
+ return [super keyUp:nsevent];
+
+ const bool keyUpAccepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
+
+ // Propagate the keyUp if neither Qt accepted it nor the corresponding KeyDown was
+ // accepted. Qt text controls wil often not use and ignore keyUp events, but we
+ // want to avoid propagating unmatched keyUps.
+ const bool keyDownAccepted = m_acceptedKeyDowns.remove([nsevent keyCode]);
+ if (!keyUpAccepted && !keyDownAccepted)
+ [super keyUp:nsevent];
+}
+
+- (void)cancelOperation:(id)sender
+{
+ Q_UNUSED(sender);
+
+ NSEvent *currentEvent = [NSApp currentEvent];
+ if (!currentEvent || currentEvent.type != NSKeyDown)
+ return;
+
+ // Handling the key event may recurse back here through interpretKeyEvents
+ // (when IM is enabled), so we need to guard against that.
+ if (currentEvent == m_currentlyInterpretedKeyEvent)
+ return;
+
+ // Send Command+Key_Period and Escape as normal keypresses so that
+ // the key sequence is delivered through Qt. That way clients can
+ // intercept the shortcut and override its effect.
+ [self handleKeyEvent:currentEvent eventType:int(QEvent::KeyPress)];
+}
+
+- (void)flagsChanged:(NSEvent *)nsevent
+{
+ ulong timestamp = [nsevent timestamp] * 1000;
+ ulong modifiers = [nsevent modifierFlags];
+ Qt::KeyboardModifiers qmodifiers = [QNSView convertKeyModifiers:modifiers];
+
+ // calculate the delta and remember the current modifiers for next time
+ static ulong m_lastKnownModifiers;
+ ulong lastKnownModifiers = m_lastKnownModifiers;
+ ulong delta = lastKnownModifiers ^ modifiers;
+ m_lastKnownModifiers = modifiers;
+
+ struct qt_mac_enum_mapper
+ {
+ ulong mac_mask;
+ Qt::Key qt_code;
+ };
+ static qt_mac_enum_mapper modifier_key_symbols[] = {
+ { NSShiftKeyMask, Qt::Key_Shift },
+ { NSControlKeyMask, Qt::Key_Meta },
+ { NSCommandKeyMask, Qt::Key_Control },
+ { NSAlternateKeyMask, Qt::Key_Alt },
+ { NSAlphaShiftKeyMask, Qt::Key_CapsLock },
+ { 0ul, Qt::Key_unknown } };
+ for (int i = 0; modifier_key_symbols[i].mac_mask != 0u; ++i) {
+ uint mac_mask = modifier_key_symbols[i].mac_mask;
+ if ((delta & mac_mask) == 0u)
+ continue;
+
+ Qt::Key qtCode = modifier_key_symbols[i].qt_code;
+ if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
+ if (qtCode == Qt::Key_Meta)
+ qtCode = Qt::Key_Control;
+ else if (qtCode == Qt::Key_Control)
+ qtCode = Qt::Key_Meta;
+ }
+ QWindowSystemInterface::handleKeyEvent(m_platformWindow->window(),
+ timestamp,
+ (lastKnownModifiers & mac_mask) ? QEvent::KeyRelease : QEvent::KeyPress,
+ qtCode,
+ qmodifiers ^ [QNSView convertKeyModifiers:mac_mask]);
+ }
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_menus.mm b/src/plugins/platforms/cocoa/qnsview_menus.mm
new file mode 100644
index 0000000000..db3d356f2e
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_menus.mm
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+#include <qcocoansmenu.h>
+#include <qcocoamenuitem.h>
+#include <qcocoamenu.h>
+#include <qcocoamenubar.h>
+
+static bool selectorIsCutCopyPaste(SEL selector)
+{
+ return (selector == @selector(cut:)
+ || selector == @selector(copy:)
+ || selector == @selector(paste:)
+ || selector == @selector(selectAll:));
+}
+
+@interface QT_MANGLE_NAMESPACE(QNSView) (Menus)
+- (void)qt_itemFired:(QCocoaNSMenuItem *)item;
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Menus)
+
+- (BOOL)validateMenuItem:(NSMenuItem*)item
+{
+ auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
+ if (!nativeItem)
+ return item.enabled; // FIXME Test with with Qt as plugin or embedded QWindow.
+
+ auto *platformItem = nativeItem.platformMenuItem;
+ if (!platformItem)
+ return NO;
+
+ // Menu-holding items are always enabled, as it's conventional in Cocoa
+ if (platformItem->menu())
+ return YES;
+
+ // Check if a modal dialog is active. Validate only menu
+ // items belonging to this view's window own menu bar.
+ if (QGuiApplication::modalWindow()) {
+ QCocoaMenuBar *menubar = nullptr;
+
+ QObject *menuParent = platformItem->menuParent();
+ while (menuParent && !(menubar = qobject_cast<QCocoaMenuBar *>(menuParent))) {
+ auto *menuObject = dynamic_cast<QCocoaMenuObject *>(menuParent);
+ menuParent = menuObject->menuParent();
+ }
+
+ if (menubar && menubar->cocoaWindow() != self.platformWindow)
+ return NO;
+ }
+
+ return platformItem->isEnabled();
+}
+
+- (BOOL)respondsToSelector:(SEL)selector
+{
+ // Not exactly true. Both copy: and selectAll: can work on non key views.
+ if (selectorIsCutCopyPaste(selector))
+ return ([NSApp keyWindow] == self.window) && (self.window.firstResponder == self);
+
+ return [super respondsToSelector:selector];
+}
+
+- (void)qt_itemFired:(QCocoaNSMenuItem *)item
+{
+ auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
+ Q_ASSERT_X(nativeItem, qPrintable(__FUNCTION__), "Triggered menu item is not a QCocoaNSMenuItem.");
+ auto *platformItem = nativeItem.platformMenuItem;
+ // Menu-holding items also get a target to play nicely
+ // with NSMenuValidation but should not trigger.
+ if (!platformItem || platformItem->menu())
+ return;
+
+ QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
+ QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
+
+ static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
+ activatedSignal.invoke(platformItem, Qt::QueuedConnection);
+}
+
+- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
+{
+ if (selectorIsCutCopyPaste(selector)) {
+ NSMethodSignature *itemFiredSign = [super methodSignatureForSelector:@selector(qt_itemFired:)];
+ return itemFiredSign;
+ }
+
+ return [super methodSignatureForSelector:selector];
+}
+
+- (void)forwardInvocation:(NSInvocation *)invocation
+{
+ if (selectorIsCutCopyPaste(invocation.selector)) {
+ NSObject *sender;
+ [invocation getArgument:&sender atIndex:2];
+ if (auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(sender)) {
+ [self qt_itemFired:nativeItem];
+ return;
+ }
+ }
+
+ [super forwardInvocation:invocation];
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
new file mode 100644
index 0000000000..a101b5ab6f
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -0,0 +1,606 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) {
+ QNSView *view;
+}
+
+- (instancetype)initWithView:(QNSView *)theView
+{
+ if ((self = [super init]))
+ view = theView;
+
+ return self;
+}
+
+- (void)mouseMoved:(NSEvent *)theEvent
+{
+ [view mouseMovedImpl:theEvent];
+}
+
+- (void)mouseEntered:(NSEvent *)theEvent
+{
+ [view mouseEnteredImpl:theEvent];
+}
+
+- (void)mouseExited:(NSEvent *)theEvent
+{
+ [view mouseExitedImpl:theEvent];
+}
+
+- (void)cursorUpdate:(NSEvent *)theEvent
+{
+ [view cursorUpdate:theEvent];
+}
+
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (MouseAPI)
+
+- (void)resetMouseButtons
+{
+ m_buttons = Qt::NoButton;
+ m_frameStrutButtons = Qt::NoButton;
+}
+
+- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent
+{
+ if (!m_platformWindow)
+ return;
+
+ // get m_buttons in sync
+ // Don't send frme strut events if we are in the middle of a mouse drag.
+ if (m_buttons != Qt::NoButton)
+ return;
+
+ NSEventType ty = [theEvent type];
+ switch (ty) {
+ case NSLeftMouseDown:
+ m_frameStrutButtons |= Qt::LeftButton;
+ break;
+ case NSLeftMouseUp:
+ m_frameStrutButtons &= ~Qt::LeftButton;
+ break;
+ case NSRightMouseDown:
+ m_frameStrutButtons |= Qt::RightButton;
+ break;
+ case NSLeftMouseDragged:
+ m_frameStrutButtons |= Qt::LeftButton;
+ break;
+ case NSRightMouseDragged:
+ m_frameStrutButtons |= Qt::RightButton;
+ break;
+ case NSRightMouseUp:
+ m_frameStrutButtons &= ~Qt::RightButton;
+ break;
+ case NSOtherMouseDown:
+ m_frameStrutButtons |= cocoaButton2QtButton([theEvent buttonNumber]);
+ break;
+ case NSOtherMouseUp:
+ m_frameStrutButtons &= ~cocoaButton2QtButton([theEvent buttonNumber]);
+ default:
+ break;
+ }
+
+ NSWindow *window = [self window];
+ NSPoint windowPoint = [theEvent locationInWindow];
+
+ int windowScreenY = [window frame].origin.y + [window frame].size.height;
+ NSPoint windowCoord = [self convertPoint:[self frame].origin toView:nil];
+ int viewScreenY = [window convertRectToScreen:NSMakeRect(windowCoord.x, windowCoord.y, 0, 0)].origin.y;
+ int titleBarHeight = windowScreenY - viewScreenY;
+
+ NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil];
+ QPoint qtWindowPoint = QPoint(nsViewPoint.x, titleBarHeight + nsViewPoint.y);
+ NSPoint screenPoint = [window convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 0, 0)].origin;
+ QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
+
+ ulong timestamp = [theEvent timestamp] * 1000;
+ QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons);
+}
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Mouse)
+
+- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
+{
+ Q_UNUSED(theEvent)
+ if (!m_platformWindow)
+ return NO;
+ if ([self isTransparentForUserInput])
+ return NO;
+ return YES;
+}
+
+- (NSPoint)screenMousePoint:(NSEvent *)theEvent
+{
+ NSPoint screenPoint;
+ if (theEvent) {
+ NSPoint windowPoint = [theEvent locationInWindow];
+ if (qIsNaN(windowPoint.x) || qIsNaN(windowPoint.y)) {
+ screenPoint = [NSEvent mouseLocation];
+ } else {
+ NSRect screenRect = [[theEvent window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
+ screenPoint = screenRect.origin;
+ }
+ } else {
+ screenPoint = [NSEvent mouseLocation];
+ }
+ return screenPoint;
+}
+
+- (void)handleMouseEvent:(NSEvent *)theEvent
+{
+ if (!m_platformWindow)
+ return;
+
+#ifndef QT_NO_TABLETEVENT
+ // Tablet events may come in via the mouse event handlers,
+ // check if this is a valid tablet event first.
+ if ([self handleTabletEvent: theEvent])
+ return;
+#endif
+
+ QPointF qtWindowPoint;
+ QPointF qtScreenPoint;
+ QNSView *targetView = self;
+ if (!targetView.platformWindow)
+ return;
+
+ // Popups implicitly grap mouse events; forward to the active popup if there is one
+ if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) {
+ // Tooltips must be transparent for mouse events
+ // The bug reference is QTBUG-46379
+ if (!popup->window()->flags().testFlag(Qt::ToolTip)) {
+ if (QNSView *popupView = qnsview_cast(popup->view()))
+ targetView = popupView;
+ }
+ }
+
+ [targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ ulong timestamp = [theEvent timestamp] * 1000;
+
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ nativeDrag->setLastMouseEvent(theEvent, self);
+
+ Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
+ QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint,
+ m_buttons, keyboardModifiers, Qt::MouseEventNotSynthesized);
+}
+
+- (bool)handleMouseDownEvent:(NSEvent *)theEvent withButton:(int)buttonNumber
+{
+ if ([self isTransparentForUserInput])
+ return false;
+
+ Qt::MouseButton button = cocoaButton2QtButton(buttonNumber);
+
+ QPointF qtWindowPoint;
+ QPointF qtScreenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ Q_UNUSED(qtScreenPoint);
+
+ // Maintain masked state for the button for use by MouseDragged and MouseUp.
+ QRegion mask = m_platformWindow->window()->mask();
+ const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
+ if (masked)
+ m_acceptedMouseDowns &= ~button;
+ else
+ m_acceptedMouseDowns |= button;
+
+ // Forward masked out events to the next responder
+ if (masked)
+ return false;
+
+ m_buttons |= button;
+
+ [self handleMouseEvent:theEvent];
+ return true;
+}
+
+- (bool)handleMouseDraggedEvent:(NSEvent *)theEvent withButton:(int)buttonNumber
+{
+ if ([self isTransparentForUserInput])
+ return false;
+
+ Qt::MouseButton button = cocoaButton2QtButton(buttonNumber);
+
+ // Forward the event to the next responder if Qt did not accept the
+ // corresponding mouse down for this button
+ if (!(m_acceptedMouseDowns & button) == button)
+ return false;
+
+ [self handleMouseEvent:theEvent];
+ return true;
+}
+
+- (bool)handleMouseUpEvent:(NSEvent *)theEvent withButton:(int)buttonNumber
+{
+ if ([self isTransparentForUserInput])
+ return false;
+
+ Qt::MouseButton button = cocoaButton2QtButton(buttonNumber);
+
+ // Forward the event to the next responder if Qt did not accept the
+ // corresponding mouse down for this button
+ if (!(m_acceptedMouseDowns & button) == button)
+ return false;
+
+ if (m_sendUpAsRightButton && button == Qt::LeftButton)
+ button = Qt::RightButton;
+ if (button == Qt::RightButton)
+ m_sendUpAsRightButton = false;
+
+ m_buttons &= ~button;
+
+ [self handleMouseEvent:theEvent];
+ return true;
+}
+
+- (void)mouseDown:(NSEvent *)theEvent
+{
+ if ([self isTransparentForUserInput])
+ return [super mouseDown:theEvent];
+ m_sendUpAsRightButton = false;
+
+ // Handle any active poup windows; clicking outisde them should close them
+ // all. Don't do anything or clicks inside one of the menus, let Cocoa
+ // handle that case. Note that in practice many windows of the Qt::Popup type
+ // will actually close themselves in this case using logic implemented in
+ // that particular poup type (for example context menus). However, Qt expects
+ // that plain popup QWindows will also be closed, so we implement the logic
+ // here as well.
+ QList<QCocoaWindow *> *popups = QCocoaIntegration::instance()->popupWindowStack();
+ if (!popups->isEmpty()) {
+ // Check if the click is outside all popups.
+ bool inside = false;
+ QPointF qtScreenPoint = QCocoaScreen::mapFromNative([self screenMousePoint:theEvent]);
+ for (QList<QCocoaWindow *>::const_iterator it = popups->begin(); it != popups->end(); ++it) {
+ if ((*it)->geometry().contains(qtScreenPoint.toPoint())) {
+ inside = true;
+ break;
+ }
+ }
+ // Close the popups if the click was outside.
+ if (!inside) {
+ Qt::WindowType type = QCocoaIntegration::instance()->activePopupWindow()->window()->type();
+ while (QCocoaWindow *popup = QCocoaIntegration::instance()->popPopupWindow()) {
+ QWindowSystemInterface::handleCloseEvent(popup->window());
+ QWindowSystemInterface::flushWindowSystemEvents();
+ }
+ // Consume the mouse event when closing the popup, except for tool tips
+ // were it's expected that the event is processed normally.
+ if (type != Qt::ToolTip)
+ return;
+ }
+ }
+
+ QPointF qtWindowPoint;
+ QPointF qtScreenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ Q_UNUSED(qtScreenPoint);
+
+ QRegion mask = m_platformWindow->window()->mask();
+ const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
+ // Maintain masked state for the button for use by MouseDragged and Up.
+ if (masked)
+ m_acceptedMouseDowns &= ~Qt::LeftButton;
+ else
+ m_acceptedMouseDowns |= Qt::LeftButton;
+
+ // Forward masked out events to the next responder
+ if (masked) {
+ [super mouseDown:theEvent];
+ return;
+ }
+
+ if ([self hasMarkedText]) {
+ [[NSTextInputContext currentInputContext] handleEvent:theEvent];
+ } else {
+ auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier;
+ if (!m_dontOverrideCtrlLMB && [QNSView convertKeyModifiers:[theEvent modifierFlags]] & ctrlOrMetaModifier) {
+ m_buttons |= Qt::RightButton;
+ m_sendUpAsRightButton = true;
+ } else {
+ m_buttons |= Qt::LeftButton;
+ }
+ [self handleMouseEvent:theEvent];
+ }
+}
+
+- (void)mouseDragged:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDraggedEvent:theEvent withButton:[theEvent buttonNumber]];
+ if (!accepted)
+ [super mouseDragged:theEvent];
+}
+
+- (void)mouseUp:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseUpEvent:theEvent withButton:[theEvent buttonNumber]];
+ if (!accepted)
+ [super mouseUp:theEvent];
+}
+
+- (void)rightMouseDown:(NSEvent *)theEvent
+{
+ // Wacom tablet might not return the correct button number for NSEvent buttonNumber
+ // on right clicks. Decide here that the button is the "right" button and forward
+ // the button number to the mouse (and tablet) handler.
+ const bool accepted = [self handleMouseDownEvent:theEvent withButton:1];
+ if (!accepted)
+ [super rightMouseDown:theEvent];
+}
+
+- (void)rightMouseDragged:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDraggedEvent:theEvent withButton:1];
+ if (!accepted)
+ [super rightMouseDragged:theEvent];
+}
+
+- (void)rightMouseUp:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseUpEvent:theEvent withButton:1];
+ if (!accepted)
+ [super rightMouseUp:theEvent];
+}
+
+- (void)otherMouseDown:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDownEvent:theEvent withButton:[theEvent buttonNumber]];
+ if (!accepted)
+ [super otherMouseDown:theEvent];
+}
+
+- (void)otherMouseDragged:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDraggedEvent:theEvent withButton:[theEvent buttonNumber]];
+ if (!accepted)
+ [super otherMouseDragged:theEvent];
+}
+
+- (void)otherMouseUp:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseUpEvent:theEvent withButton:[theEvent buttonNumber]];
+ if (!accepted)
+ [super otherMouseUp:theEvent];
+}
+
+- (void)updateTrackingAreas
+{
+ [super updateTrackingAreas];
+
+ QMacAutoReleasePool pool;
+
+ // NSTrackingInVisibleRect keeps care of updating once the tracking is set up, so bail out early
+ if (m_trackingArea && [[self trackingAreas] containsObject:m_trackingArea])
+ return;
+
+ // Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should
+ // only be turned on if mouseTracking, hover is on or a tool tip is set.
+ // Unfortunately, Qt will send "tooltip" events on mouse moves, so we need to
+ // turn it on in ALL case. That means EVERY QWindow gets to pay the cost of
+ // mouse moves delivered to it (Apple recommends keeping it OFF because there
+ // is a performance hit). So it goes.
+ NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
+ | NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate;
+ [m_trackingArea release];
+ m_trackingArea = [[NSTrackingArea alloc] initWithRect:[self frame]
+ options:trackingOptions
+ owner:m_mouseMoveHelper
+ userInfo:nil];
+ [self addTrackingArea:m_trackingArea];
+}
+
+- (void)cursorUpdate:(NSEvent *)theEvent
+{
+ qCDebug(lcQpaMouse) << "[QNSView cursorUpdate:]" << self.cursor;
+
+ // Note: We do not get this callback when moving from a subview that
+ // uses the legacy cursorRect API, so the cursor is reset to the arrow
+ // cursor. See rdar://34183708
+
+ if (self.cursor)
+ [self.cursor set];
+ else
+ [super cursorUpdate:theEvent];
+}
+
+- (void)mouseMovedImpl:(NSEvent *)theEvent
+{
+ if (!m_platformWindow)
+ return;
+
+ if ([self isTransparentForUserInput])
+ return;
+
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
+
+ // Top-level windows generate enter-leave events for sub-windows.
+ // Qt wants to know which window (if any) will be entered at the
+ // the time of the leave. This is dificult to accomplish by
+ // handling mouseEnter and mouseLeave envents, since they are sent
+ // individually to different views.
+ if (m_platformWindow->isContentView() && childWindow) {
+ if (childWindow != m_platformWindow->m_enterLeaveTargetWindow) {
+ QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
+ m_platformWindow->m_enterLeaveTargetWindow = childWindow;
+ }
+ }
+
+ // Cocoa keeps firing mouse move events for obscured parent views. Qt should not
+ // send those events so filter them out here.
+ if (childWindow != m_platformWindow->window())
+ return;
+
+ [self handleMouseEvent: theEvent];
+}
+
+- (void)mouseEnteredImpl:(NSEvent *)theEvent
+{
+ Q_UNUSED(theEvent)
+ if (!m_platformWindow)
+ return;
+
+ m_platformWindow->m_windowUnderMouse = true;
+
+ if ([self isTransparentForUserInput])
+ return;
+
+ // Top-level windows generate enter events for sub-windows.
+ if (!m_platformWindow->isContentView())
+ return;
+
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ m_platformWindow->m_enterLeaveTargetWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
+ QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
+}
+
+- (void)mouseExitedImpl:(NSEvent *)theEvent
+{
+ Q_UNUSED(theEvent);
+ if (!m_platformWindow)
+ return;
+
+ m_platformWindow->m_windowUnderMouse = false;
+
+ if ([self isTransparentForUserInput])
+ return;
+
+ // Top-level windows generate leave events for sub-windows.
+ if (!m_platformWindow->isContentView())
+ return;
+
+ QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_enterLeaveTargetWindow);
+ m_platformWindow->m_enterLeaveTargetWindow = 0;
+}
+
+#if QT_CONFIG(wheelevent)
+- (void)scrollWheel:(NSEvent *)theEvent
+{
+ if (!m_platformWindow)
+ return;
+
+ if ([self isTransparentForUserInput])
+ return [super scrollWheel:theEvent];
+
+ QPoint angleDelta;
+ Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
+ if ([theEvent hasPreciseScrollingDeltas]) {
+ // The mouse device contains pixel scroll wheel support (Mighty Mouse, Trackpad).
+ // Since deviceDelta is delivered as pixels rather than degrees, we need to
+ // convert from pixels to degrees in a sensible manner.
+ // It looks like 1/4 degrees per pixel behaves most native.
+ // (NB: Qt expects the unit for delta to be 8 per degree):
+ const int pixelsToDegrees = 2; // 8 * 1/4
+ angleDelta.setX([theEvent scrollingDeltaX] * pixelsToDegrees);
+ angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees);
+ source = Qt::MouseEventSynthesizedBySystem;
+ } else {
+ // Remove acceleration, and use either -120 or 120 as delta:
+ angleDelta.setX(qBound(-120, int([theEvent deltaX] * 10000), 120));
+ angleDelta.setY(qBound(-120, int([theEvent deltaY] * 10000), 120));
+ }
+
+ QPoint pixelDelta;
+ if ([theEvent hasPreciseScrollingDeltas]) {
+ pixelDelta.setX([theEvent scrollingDeltaX]);
+ pixelDelta.setY([theEvent scrollingDeltaY]);
+ } else {
+ // docs: "In the case of !hasPreciseScrollingDeltas, multiply the delta with the line width."
+ // scrollingDeltaX seems to return a minimum value of 0.1 in this case, map that to two pixels.
+ const CGFloat lineWithEstimate = 20.0;
+ pixelDelta.setX([theEvent scrollingDeltaX] * lineWithEstimate);
+ pixelDelta.setY([theEvent scrollingDeltaY] * lineWithEstimate);
+ }
+
+ QPointF qt_windowPoint;
+ QPointF qt_screenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qt_windowPoint andScreenPoint:&qt_screenPoint];
+ NSTimeInterval timestamp = [theEvent timestamp];
+ ulong qt_timestamp = timestamp * 1000;
+
+ // Prevent keyboard modifier state from changing during scroll event streams.
+ // A two-finger trackpad flick generates a stream of scroll events. We want
+ // the keyboard modifier state to be the state at the beginning of the
+ // flick in order to avoid changing the interpretation of the events
+ // mid-stream. One example of this happening would be when pressing cmd
+ // after scrolling in Qt Creator: not taking the phase into account causes
+ // the end of the event stream to be interpreted as font size changes.
+ NSEventPhase momentumPhase = [theEvent momentumPhase];
+ if (momentumPhase == NSEventPhaseNone) {
+ currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
+ }
+
+ NSEventPhase phase = [theEvent phase];
+ Qt::ScrollPhase ph = Qt::ScrollUpdate;
+
+ // MayBegin is likely to happen. We treat it the same as an actual begin.
+ if (phase == NSEventPhaseMayBegin) {
+ m_scrolling = true;
+ ph = Qt::ScrollBegin;
+ } else if (phase == NSEventPhaseBegan) {
+ // If MayBegin did not happen, Began is the actual beginning.
+ if (!m_scrolling)
+ ph = Qt::ScrollBegin;
+ m_scrolling = true;
+ } else if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled ||
+ momentumPhase == NSEventPhaseEnded || momentumPhase == NSEventPhaseCancelled) {
+ ph = Qt::ScrollEnd;
+ m_scrolling = false;
+ } else if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
+ ph = Qt::NoScrollPhase;
+ }
+ // "isInverted": natural OS X scrolling, inverted from the Qt/other platform/Jens perspective.
+ bool isInverted = [theEvent isDirectionInvertedFromDevice];
+
+ qCDebug(lcQpaMouse) << "scroll wheel @ window pos" << qt_windowPoint << "delta px" << pixelDelta << "angle" << angleDelta << "phase" << ph << (isInverted ? "inverted" : "");
+ QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph, source, isInverted);
+}
+#endif // QT_CONFIG(wheelevent)
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_tablet.mm b/src/plugins/platforms/cocoa/qnsview_tablet.mm
new file mode 100644
index 0000000000..0b56123955
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_tablet.mm
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+#ifndef QT_NO_TABLETEVENT
+
+Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
+
+struct QCocoaTabletDeviceData
+{
+ QTabletEvent::TabletDevice device;
+ QTabletEvent::PointerType pointerType;
+ uint capabilityMask;
+ qint64 uid;
+};
+
+typedef QHash<uint, QCocoaTabletDeviceData> QCocoaTabletDeviceDataHash;
+Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Tablet)
+
+- (bool)handleTabletEvent:(NSEvent *)theEvent
+{
+ static bool ignoreButtonMapping = qEnvironmentVariableIsSet("QT_MAC_TABLET_IGNORE_BUTTON_MAPPING");
+
+ if (!m_platformWindow)
+ return false;
+
+ NSEventType eventType = [theEvent type];
+ if (eventType != NSTabletPoint && [theEvent subtype] != NSTabletPointEventSubtype)
+ return false; // Not a tablet event.
+
+ ulong timestamp = [theEvent timestamp] * 1000;
+
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint: &windowPoint andScreenPoint: &screenPoint];
+
+ uint deviceId = [theEvent deviceID];
+ if (!tabletDeviceDataHash->contains(deviceId)) {
+ // Error: Unknown tablet device. Qt also gets into this state
+ // when running on a VM. This appears to be harmless; don't
+ // print a warning.
+ return false;
+ }
+ const QCocoaTabletDeviceData &deviceData = tabletDeviceDataHash->value(deviceId);
+
+ bool down = (eventType != NSMouseMoved);
+
+ qreal pressure;
+ if (down) {
+ pressure = [theEvent pressure];
+ } else {
+ pressure = 0.0;
+ }
+
+ NSPoint tilt = [theEvent tilt];
+ int xTilt = qRound(tilt.x * 60.0);
+ int yTilt = qRound(tilt.y * -60.0);
+ qreal tangentialPressure = 0;
+ qreal rotation = 0;
+ int z = 0;
+ if (deviceData.capabilityMask & 0x0200)
+ z = [theEvent absoluteZ];
+
+ if (deviceData.capabilityMask & 0x0800)
+ tangentialPressure = ([theEvent tangentialPressure] * 2.0) - 1.0;
+
+ rotation = 360.0 - [theEvent rotation];
+ if (rotation > 180.0)
+ rotation -= 360.0;
+
+ Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
+ Qt::MouseButtons buttons = ignoreButtonMapping ? static_cast<Qt::MouseButtons>(static_cast<uint>([theEvent buttonMask])) : m_buttons;
+
+ qCDebug(lcQpaTablet, "event on tablet %d with tool %d type %d unique ID %lld pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf",
+ deviceId, deviceData.device, deviceData.pointerType, deviceData.uid,
+ windowPoint.x(), windowPoint.y(), screenPoint.x(), screenPoint.y(),
+ static_cast<uint>(buttons), pressure, xTilt, yTilt, rotation);
+
+ QWindowSystemInterface::handleTabletEvent(m_platformWindow->window(), timestamp, windowPoint, screenPoint,
+ deviceData.device, deviceData.pointerType, buttons, pressure, xTilt, yTilt,
+ tangentialPressure, rotation, z, deviceData.uid,
+ keyboardModifiers);
+ return true;
+}
+
+- (void)tabletPoint:(NSEvent *)theEvent
+{
+ if ([self isTransparentForUserInput])
+ return [super tabletPoint:theEvent];
+
+ [self handleTabletEvent: theEvent];
+}
+
+static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
+{
+ qint64 uid = [theEvent uniqueID];
+ uint bits = [theEvent vendorPointingDeviceType];
+ if (bits == 0 && uid != 0) {
+ // Fallback. It seems that the driver doesn't always include all the information.
+ // High-End Wacom devices store their "type" in the uper bits of the Unique ID.
+ // I'm not sure how to handle it for consumer devices, but I'll test that in a bit.
+ bits = uid >> 32;
+ }
+
+ QTabletEvent::TabletDevice device;
+ // Defined in the "EN0056-NxtGenImpGuideX"
+ // on Wacom's Developer Website (www.wacomeng.com)
+ if (((bits & 0x0006) == 0x0002) && ((bits & 0x0F06) != 0x0902)) {
+ device = QTabletEvent::Stylus;
+ } else {
+ switch (bits & 0x0F06) {
+ case 0x0802:
+ device = QTabletEvent::Stylus;
+ break;
+ case 0x0902:
+ device = QTabletEvent::Airbrush;
+ break;
+ case 0x0004:
+ device = QTabletEvent::FourDMouse;
+ break;
+ case 0x0006:
+ device = QTabletEvent::Puck;
+ break;
+ case 0x0804:
+ device = QTabletEvent::RotationStylus;
+ break;
+ default:
+ device = QTabletEvent::NoDevice;
+ }
+ }
+ return device;
+}
+
+- (void)tabletProximity:(NSEvent *)theEvent
+{
+ if ([self isTransparentForUserInput])
+ return [super tabletProximity:theEvent];
+
+ ulong timestamp = [theEvent timestamp] * 1000;
+
+ QCocoaTabletDeviceData deviceData;
+ deviceData.uid = [theEvent uniqueID];
+ deviceData.capabilityMask = [theEvent capabilityMask];
+
+ switch ([theEvent pointingDeviceType]) {
+ case NSUnknownPointingDevice:
+ default:
+ deviceData.pointerType = QTabletEvent::UnknownPointer;
+ break;
+ case NSPenPointingDevice:
+ deviceData.pointerType = QTabletEvent::Pen;
+ break;
+ case NSCursorPointingDevice:
+ deviceData.pointerType = QTabletEvent::Cursor;
+ break;
+ case NSEraserPointingDevice:
+ deviceData.pointerType = QTabletEvent::Eraser;
+ break;
+ }
+
+ deviceData.device = wacomTabletDevice(theEvent);
+
+ // The deviceID is "unique" while in the proximity, it's a key that we can use for
+ // linking up QCocoaTabletDeviceData to an event (especially if there are two devices in action).
+ bool entering = [theEvent isEnteringProximity];
+ uint deviceId = [theEvent deviceID];
+ if (entering) {
+ tabletDeviceDataHash->insert(deviceId, deviceData);
+ } else {
+ tabletDeviceDataHash->remove(deviceId);
+ }
+
+ qCDebug(lcQpaTablet, "proximity change on tablet %d: current tool %d type %d unique ID %lld",
+ deviceId, deviceData.device, deviceData.pointerType, deviceData.uid);
+
+ if (entering) {
+ QWindowSystemInterface::handleTabletEnterProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
+ } else {
+ QWindowSystemInterface::handleTabletLeaveProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
+ }
+}
+@end
+
+#endif
diff --git a/src/plugins/platforms/cocoa/qnsview_touch.mm b/src/plugins/platforms/cocoa/qnsview_touch.mm
new file mode 100644
index 0000000000..e789213f70
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_touch.mm
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Touch)
+
+- (bool)shouldSendSingleTouch
+{
+ if (!m_platformWindow)
+ return true;
+
+ // QtWidgets expects single-point touch events, QtDeclarative does not.
+ // Until there is an API we solve this by looking at the window class type.
+ return m_platformWindow->window()->inherits("QWidgetWindow");
+}
+
+- (void)touchesBeganWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+}
+
+- (void)touchesMovedWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+}
+
+- (void)touchesEndedWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+}
+
+- (void)touchesCancelledWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
index 645a93edf7..ab0036e175 100644
--- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
@@ -53,14 +53,12 @@
@implementation QNSView (QNSViewAccessibility)
- (id)childAccessibleElement {
- if (m_platformWindow.isNull())
+ QCocoaWindow *platformWindow = self.platformWindow;
+ if (!platformWindow || !platformWindow->window()->accessibleRoot())
return nil;
- if (!m_platformWindow->window()->accessibleRoot())
- return nil;
-
- QAccessible::Id childId = QAccessible::uniqueId(m_platformWindow->window()->accessibleRoot());
- return [QMacAccessibilityElement elementWithId: childId];
+ QAccessible::Id childId = QAccessible::uniqueId(platformWindow->window()->accessibleRoot());
+ return [QMacAccessibilityElement elementWithId:childId];
}
// The QNSView is a container that the user does not interact directly with:
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index cb13b7d184..c959fdd917 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -38,7 +38,6 @@
****************************************************************************/
#include "qnswindow.h"
-#include "qnswindowdelegate.h"
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
#include "qcocoaeventdispatcher.h"
@@ -46,7 +45,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <qoperatingsystemversion.h>
-Q_LOGGING_CATEGORY(lcCocoaEvents, "qt.qpa.cocoa.events");
+Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events");
static bool isMouseEvent(NSEvent *ev)
{
@@ -72,7 +71,7 @@ static bool isMouseEvent(NSEvent *ev)
[center addObserverForName:NSWindowDidEnterFullScreenNotification object:nil queue:nil
usingBlock:^(NSNotification *notification) {
objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
- [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN);
+ @(YES), OBJC_ASSOCIATION_RETAIN);
}
];
[center addObserverForName:NSWindowDidExitFullScreenNotification object:nil queue:nil
@@ -202,7 +201,7 @@ static bool isMouseEvent(NSEvent *ev)
- (void)sendEvent:(NSEvent*)theEvent
{
- qCDebug(lcCocoaEvents) << "Sending" << theEvent << "to" << self;
+ qCDebug(lcQpaEvents) << "Sending" << theEvent << "to" << self;
// We might get events for a NSWindow after the corresponding platform
// window has been deleted, as the NSWindow can outlive the QCocoaWindow
@@ -239,7 +238,7 @@ static bool isMouseEvent(NSEvent *ev)
- (void)closeAndRelease
{
- qCDebug(lcQpaCocoaWindow) << "closeAndRelease" << self;
+ qCDebug(lcQpaWindow) << "closeAndRelease" << self;
[self.delegate release];
self.delegate = nil;
@@ -252,7 +251,7 @@ static bool isMouseEvent(NSEvent *ev)
#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
- (void)dealloc
{
- qCDebug(lcQpaCocoaWindow) << "dealloc" << self;
+ qCDebug(lcQpaWindow) << "dealloc" << self;
qt_objcDynamicSuper();
}
#pragma clang diagnostic pop
@@ -267,14 +266,14 @@ static bool isMouseEvent(NSEvent *ev)
if (__builtin_available(macOS 10.12, *)) {
// Unfortunately there's no NSWindowListOrderedBackToFront,
// so we have to manually reverse the order using an array.
- NSMutableArray *windows = [[[NSMutableArray alloc] init] autorelease];
+ NSMutableArray<NSWindow *> *windows = [NSMutableArray<NSWindow *> new];
[application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
usingBlock:^(NSWindow *window, BOOL *) {
// For some reason AppKit will give us nil-windows, skip those
if (!window)
return;
- [(NSMutableArray*)windows addObject:window];
+ [windows addObject:window];
}
];
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h
index d2078b5786..e71afcbb2a 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.h
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h
@@ -41,20 +41,16 @@
#define QNSWINDOWDELEGATE_H
#include <AppKit/AppKit.h>
+#include <QtCore/private/qcore_mac_p.h>
-#include "qcocoawindow.h"
+QT_BEGIN_NAMESPACE
+class QCocoaWindow;
+QT_END_NAMESPACE
@interface QT_MANGLE_NAMESPACE(QNSWindowDelegate) : NSObject <NSWindowDelegate>
-{
- QCocoaWindow *m_cocoaWindow;
-}
-- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow;
+- (instancetype)initWithQCocoaWindow:(QT_PREPEND_NAMESPACE(QCocoaWindow) *)cocoaWindow;
-- (BOOL)windowShouldClose:(NSNotification *)notification;
-
-- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu;
-- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindowDelegate);
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index 6e5623d679..1888dc1c90 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -39,20 +39,23 @@
#include "qnswindowdelegate.h"
#include "qcocoahelpers.h"
+#include "qcocoawindow.h"
#include <QDebug>
+#include <QtCore/private/qcore_mac_p.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface.h>
static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*"));
-@implementation QNSWindowDelegate
+@implementation QNSWindowDelegate {
+ QCocoaWindow *m_cocoaWindow;
+}
-- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow
+- (instancetype)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow
{
- if (self = [super init])
+ if ((self = [self init]))
m_cocoaWindow = cocoaWindow;
-
return self;
}
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
index 3f363b62d5..96506c67fa 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
@@ -98,8 +98,8 @@ CGImageRef qt_mac_create_imagemask(const QPixmap &pixmap, const QRectF &sr)
for (int x = sx; x < sw; ++x)
*(dptr+(offset++)) = (*(srow+x) & mask) ? 255 : 0;
}
- QCFType<CGDataProviderRef> provider = CGDataProviderCreateWithData(0, dptr, nbytes, qt_mac_cgimage_data_free);
- return CGImageMaskCreate(sw, sh, 8, 8, nbytes / sh, provider, 0, 0);
+ QCFType<CGDataProviderRef> provider = CGDataProviderCreateWithData(nullptr, dptr, nbytes, qt_mac_cgimage_data_free);
+ return CGImageMaskCreate(sw, sh, 8, 8, nbytes / sh, provider, nullptr, false);
}
//conversion
@@ -287,16 +287,16 @@ static void qt_mac_draw_pattern(void *info, CGContextRef c)
Q_ASSERT(pat->data.bytes);
w = h = 8;
#if (QMACPATTERN_MASK_MULTIPLIER == 1)
- CGDataProviderRef provider = CGDataProviderCreateWithData(0, pat->data.bytes, w*h, 0);
- pat->image = CGImageMaskCreate(w, h, 1, 1, 1, provider, 0, false);
+ CGDataProviderRef provider = CGDataProviderCreateWithData(nullptr, pat->data.bytes, w*h, nullptr);
+ pat->image = CGImageMaskCreate(w, h, 1, 1, 1, provider, nullptr, false);
CGDataProviderRelease(provider);
#else
const int numBytes = (w*h)/sizeof(uchar);
uchar xor_bytes[numBytes];
for (int i = 0; i < numBytes; ++i)
xor_bytes[i] = pat->data.bytes[i] ^ 0xFF;
- CGDataProviderRef provider = CGDataProviderCreateWithData(0, xor_bytes, w*h, 0);
- CGImageRef swatch = CGImageMaskCreate(w, h, 1, 1, 1, provider, 0, false);
+ CGDataProviderRef provider = CGDataProviderCreateWithData(nullptr, xor_bytes, w*h, nullptr);
+ CGImageRef swatch = CGImageMaskCreate(w, h, 1, 1, 1, provider, nullptr, false);
CGDataProviderRelease(provider);
const QColor c0(0, 0, 0, 0), c1(255, 255, 255, 255);
@@ -399,9 +399,9 @@ QCoreGraphicsPaintEngine::begin(QPaintDevice *pdev)
d->orig_xform = CGContextGetCTM(d->hd);
if (d->shading) {
CGShadingRelease(d->shading);
- d->shading = 0;
+ d->shading = nullptr;
}
- d->setClip(0); //clear the context's clipping
+ d->setClip(nullptr); //clear the context's clipping
}
setActive(true);
@@ -445,12 +445,12 @@ QCoreGraphicsPaintEngine::end()
CGShadingRelease(d->shading);
d->shading = 0;
}
- d->pdev = 0;
+ d->pdev = nullptr;
if (d->hd) {
d->restoreGraphicsState();
CGContextSynchronize(d->hd);
CGContextRelease(d->hd);
- d->hd = 0;
+ d->hd = nullptr;
}
return true;
}
@@ -545,7 +545,7 @@ QCoreGraphicsPaintEngine::updateBrush(const QBrush &brush, const QPointF &brushO
if (d->shading) {
CGShadingRelease(d->shading);
- d->shading = 0;
+ d->shading = nullptr;
}
d->setFillBrush(brushOrigin);
}
@@ -592,7 +592,7 @@ QCoreGraphicsPaintEngine::updateClipPath(const QPainterPath &p, Qt::ClipOperatio
if (d->current.clipEnabled) {
d->current.clipEnabled = false;
d->current.clip = QRegion();
- d->setClip(0);
+ d->setClip(nullptr);
}
} else {
if (!d->current.clipEnabled)
@@ -601,7 +601,7 @@ QCoreGraphicsPaintEngine::updateClipPath(const QPainterPath &p, Qt::ClipOperatio
QRegion clipRegion(p.toFillPolygon().toPolygon(), p.fillRule());
if (op == Qt::ReplaceClip) {
d->current.clip = clipRegion;
- d->setClip(0);
+ d->setClip(nullptr);
if (p.isEmpty()) {
CGRect rect = CGRectMake(0, 0, 0, 0);
CGContextClipToRect(d->hd, rect);
@@ -630,7 +630,7 @@ QCoreGraphicsPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOp
if (op == Qt::NoClip) {
d->current.clipEnabled = false;
d->current.clip = QRegion();
- d->setClip(0);
+ d->setClip(nullptr);
} else {
if (!d->current.clipEnabled)
op = Qt::ReplaceClip;
@@ -676,7 +676,7 @@ QCoreGraphicsPaintEngine::drawRects(const QRectF *rects, int rectCount)
QRectF r = rects[i];
CGMutablePathRef path = CGPathCreateMutable();
- CGPathAddRect(path, 0, qt_mac_compose_rect(r));
+ CGPathAddRect(path, nullptr, qt_mac_compose_rect(r));
d->drawPath(QCoreGraphicsPaintEnginePrivate::CGFill|QCoreGraphicsPaintEnginePrivate::CGStroke,
path);
CGPathRelease(path);
@@ -698,8 +698,8 @@ QCoreGraphicsPaintEngine::drawPoints(const QPointF *points, int pointCount)
CGMutablePathRef path = CGPathCreateMutable();
for (int i=0; i < pointCount; i++) {
float x = points[i].x(), y = points[i].y();
- CGPathMoveToPoint(path, 0, x, y);
- CGPathAddLineToPoint(path, 0, x+0.001, y);
+ CGPathMoveToPoint(path, nullptr, x, y);
+ CGPathAddLineToPoint(path, nullptr, x+0.001, y);
}
bool doRestore = false;
@@ -745,11 +745,11 @@ QCoreGraphicsPaintEngine::drawPolygon(const QPointF *points, int pointCount, Pol
return;
CGMutablePathRef path = CGPathCreateMutable();
- CGPathMoveToPoint(path, 0, points[0].x(), points[0].y());
+ CGPathMoveToPoint(path, nullptr, points[0].x(), points[0].y());
for (int x = 1; x < pointCount; ++x)
- CGPathAddLineToPoint(path, 0, points[x].x(), points[x].y());
+ CGPathAddLineToPoint(path, nullptr, points[x].x(), points[x].y());
if (mode != PolylineMode && points[0] != points[pointCount-1])
- CGPathAddLineToPoint(path, 0, points[0].x(), points[0].y());
+ CGPathAddLineToPoint(path, nullptr, points[0].x(), points[0].y());
uint op = QCoreGraphicsPaintEnginePrivate::CGStroke;
if (mode != PolylineMode)
op |= mode == OddEvenMode ? QCoreGraphicsPaintEnginePrivate::CGEOFill
@@ -770,8 +770,8 @@ QCoreGraphicsPaintEngine::drawLines(const QLineF *lines, int lineCount)
CGMutablePathRef path = CGPathCreateMutable();
for (int i = 0; i < lineCount; i++) {
const QPointF start = lines[i].p1(), end = lines[i].p2();
- CGPathMoveToPoint(path, 0, start.x(), start.y());
- CGPathAddLineToPoint(path, 0, end.x(), end.y());
+ CGPathMoveToPoint(path, nullptr, start.x(), start.y());
+ CGPathAddLineToPoint(path, nullptr, end.x(), end.y());
}
d->drawPath(QCoreGraphicsPaintEnginePrivate::CGStroke, path);
CGPathRelease(path);
@@ -870,7 +870,7 @@ QCoreGraphicsPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap
CGPatternRef pat = CGPatternCreate(qpattern, CGRectMake(0, 0, width, height),
trans, width, height,
kCGPatternTilingNoDistortion, true, &callbks);
- CGColorSpaceRef cs = CGColorSpaceCreatePattern(0);
+ CGColorSpaceRef cs = CGColorSpaceCreatePattern(nullptr);
CGContextSetFillColorSpace(d->hd, cs);
CGFloat component = 1.0; //just one
CGContextSetFillPattern(d->hd, pat, &component);
@@ -1198,9 +1198,9 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
Q_ASSERT(grad->spread() == QGradient::PadSpread);
static const CGFloat domain[] = { 0.0f, +1.0f };
- static const CGFunctionCallbacks callbacks = { 0, qt_mac_color_gradient_function, 0 };
+ static const CGFunctionCallbacks callbacks = { 0, qt_mac_color_gradient_function, nullptr };
CGFunctionRef fill_func = CGFunctionCreate(reinterpret_cast<void *>(&current.brush),
- 1, domain, 4, 0, &callbacks);
+ 1, domain, 4, nullptr, &callbacks);
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB)
if (bs == Qt::LinearGradientPattern) {
@@ -1233,7 +1233,7 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
QMacPattern *qpattern = new QMacPattern;
qpattern->pdev = pdev;
CGFloat components[4] = { 1.0, 1.0, 1.0, 1.0 };
- CGColorSpaceRef base_colorspace = 0;
+ CGColorSpaceRef base_colorspace = nullptr;
if (bs == Qt::TexturePattern) {
qpattern->data.pixmap = current.brush.texture();
if (qpattern->data.pixmap.isQBitmap()) {
@@ -1291,7 +1291,7 @@ QCoreGraphicsPaintEnginePrivate::setClip(const QRegion *rgn)
if (!sysClip.isEmpty())
qt_mac_clip_cg(hd, sysClip, &orig_xform);
if (rgn)
- qt_mac_clip_cg(hd, *rgn, 0);
+ qt_mac_clip_cg(hd, *rgn, nullptr);
}
}
@@ -1404,7 +1404,7 @@ void QCoreGraphicsPaintEnginePrivate::drawPath(uchar ops, CGMutablePathRef path)
t.transform = qt_mac_convert_transform_to_cg(current.transform);
t.path = CGPathCreateMutable();
CGPathApply(path, &t, qt_mac_cg_transform_path_apply); //transform the path
- setTransform(0); //unset the context transform
+ setTransform(nullptr); //unset the context transform
CGContextSetLineWidth(hd, cosmeticPenSize);
CGContextAddPath(hd, t.path);
CGPathRelease(t.path);
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
index c9519ac827..1416386745 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
@@ -135,7 +135,7 @@ class QCoreGraphicsPaintEnginePrivate : public QPaintEnginePrivate
Q_DECLARE_PUBLIC(QCoreGraphicsPaintEngine)
public:
QCoreGraphicsPaintEnginePrivate()
- : hd(0), shading(0), stackCount(0), complexXForm(false), disabledSmoothFonts(false)
+ : hd(nullptr), shading(nullptr), stackCount(0), complexXForm(false), disabledSmoothFonts(false)
{
}
@@ -164,8 +164,8 @@ public:
//internal functions
enum { CGStroke=0x01, CGEOFill=0x02, CGFill=0x04 };
- void drawPath(uchar ops, CGMutablePathRef path = 0);
- void setClip(const QRegion *rgn=0);
+ void drawPath(uchar ops, CGMutablePathRef path = nullptr);
+ void setClip(const QRegion *rgn = nullptr);
void resetClip();
void setFillBrush(const QPointF &origin=QPoint());
void setStrokePen(const QPen &pen);
@@ -174,7 +174,7 @@ public:
float penOffset();
QPointF devicePixelSize(CGContextRef context);
float adjustPenWidth(float penWidth);
- inline void setTransform(const QTransform *matrix=0)
+ inline void setTransform(const QTransform *matrix = nullptr)
{
CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
CGAffineTransform xform = orig_xform;
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm
index eade407500..f2f29b26ee 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm
@@ -117,7 +117,7 @@ bool QMacPrintEngine::end()
if (d->paintEngine->type() == QPaintEngine::CoreGraphics) {
// We don't need the paint engine to call restoreGraphicsState()
static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->stackCount = 0;
- static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->hd = 0;
+ static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->hd = nullptr;
}
d->paintEngine->end();
if (d->state != QPrinter::Idle)
@@ -271,7 +271,7 @@ void QMacPrintEnginePrivate::releaseSession()
PMSessionEndPageNoDialog(session());
PMSessionEndDocumentNoDialog(session());
[printInfo release];
- printInfo = 0;
+ printInfo = nil;
}
bool QMacPrintEnginePrivate::newPage_helper()
@@ -291,7 +291,7 @@ bool QMacPrintEnginePrivate::newPage_helper()
while (cgEngine->d_func()->stackCount > 0)
cgEngine->d_func()->restoreGraphicsState();
- OSStatus status = PMSessionBeginPageNoDialog(session(), format(), 0);
+ OSStatus status = PMSessionBeginPageNoDialog(session(), format(), nullptr);
if (status != noErr) {
state = QPrinter::Error;
return false;
@@ -318,7 +318,7 @@ bool QMacPrintEnginePrivate::newPage_helper()
if (m_pageLayout.mode() != QPageLayout::FullPageMode)
CGContextTranslateCTM(cgContext, page.x() - paper.x(), page.y() - paper.y());
cgEngine->d_func()->orig_xform = CGContextGetCTM(cgContext);
- cgEngine->d_func()->setClip(0);
+ cgEngine->d_func()->setClip(nullptr);
cgEngine->state->dirtyFlags = QPaintEngine::DirtyFlag(QPaintEngine::AllDirty
& ~(QPaintEngine::DirtyClipEnabled
| QPaintEngine::DirtyClipRegion
@@ -340,7 +340,7 @@ void QMacPrintEnginePrivate::setPageSize(const QPageSize &pageSize)
// Get the PMPaper and check it is valid
PMPaper macPaper = m_printDevice->macPaper(usePageSize);
- if (macPaper == 0) {
+ if (!macPaper) {
qWarning() << "QMacPrintEngine: Invalid PMPaper returned for " << pageSize;
return;
}
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
index 9514f3e691..3d94227ae4 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
@@ -134,7 +134,7 @@ public:
QMacPrintEnginePrivate() : mode(QPrinter::ScreenResolution), state(QPrinter::Idle),
m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0))),
- printInfo(0), paintEngine(0), embedFonts(true) {}
+ printInfo(nullptr), paintEngine(nullptr), embedFonts(true) {}
~QMacPrintEnginePrivate();
void initialize();
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 4742143121..c3151e1fd0 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -47,6 +47,7 @@
#include <QtCore/QLoggingCategory>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qtguiglobal_p.h>
#include <QtFbSupport/private/qfbvthandler_p.h>
#include <errno.h>
@@ -210,17 +211,29 @@ void QEglFSKmsGbmScreen::ensureModeSet(uint32_t fb)
if (doModeSet) {
qCDebug(qLcEglfsKmsDebug, "Setting mode for screen %s", qPrintable(name()));
- int ret = drmModeSetCrtc(fd,
- op.crtc_id,
- fb,
- 0, 0,
- &op.connector_id, 1,
- &op.modes[op.mode]);
-
- if (ret == 0)
- setPowerState(PowerStateOn);
- else
- qErrnoWarning(errno, "Could not set DRM mode for screen %s", qPrintable(name()));
+
+ if (device()->hasAtomicSupport()) {
+#if QT_CONFIG(drm_atomic)
+ drmModeAtomicReq *request = device()->atomic_request();
+ if (request) {
+ drmModeAtomicAddProperty(request, op.connector_id, op.crtcIdPropertyId, op.crtc_id);
+ drmModeAtomicAddProperty(request, op.crtc_id, op.modeIdPropertyId, op.mode_blob_id);
+ drmModeAtomicAddProperty(request, op.crtc_id, op.activePropertyId, 1);
+ }
+#endif
+ } else {
+ int ret = drmModeSetCrtc(fd,
+ op.crtc_id,
+ fb,
+ 0, 0,
+ &op.connector_id, 1,
+ &op.modes[op.mode]);
+
+ if (ret == 0)
+ setPowerState(PowerStateOn);
+ else
+ qErrnoWarning(errno, "Could not set DRM mode for screen %s", qPrintable(name()));
+ }
}
}
}
@@ -243,6 +256,11 @@ void QEglFSKmsGbmScreen::waitForFlip()
drmEvent.page_flip_handler = pageFlipHandler;
drmHandleEvent(device()->fd(), &drmEvent);
}
+
+#if QT_CONFIG(drm_atomic)
+ if (device()->hasAtomicSupport())
+ device()->atomicReset();
+#endif
}
void QEglFSKmsGbmScreen::flip()
@@ -274,34 +292,75 @@ void QEglFSKmsGbmScreen::flip()
QKmsOutput &op(output());
const int fd = device()->fd();
m_flipPending = true;
- int ret = drmModePageFlip(fd,
+
+ if (device()->hasAtomicSupport()) {
+#if QT_CONFIG(drm_atomic)
+ drmModeAtomicReq *request = device()->atomic_request();
+ if (request) {
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->framebufferPropertyId, fb->fb);
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcPropertyId, op.crtc_id);
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcwidthPropertyId,
+ output().size.width() << 16);
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcXPropertyId, 0);
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcYPropertyId, 0);
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcheightPropertyId,
+ output().size.height() << 16);
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcXPropertyId, 0);
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcYPropertyId, 0);
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcwidthPropertyId,
+ m_output.modes[m_output.mode].hdisplay);
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcheightPropertyId,
+ m_output.modes[m_output.mode].vdisplay);
+ }
+#endif
+ } else {
+ int ret = drmModePageFlip(fd,
op.crtc_id,
fb->fb,
DRM_MODE_PAGE_FLIP_EVENT,
this);
- if (ret) {
- qErrnoWarning("Could not queue DRM page flip on screen %s", qPrintable(name()));
- m_flipPending = false;
- gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next);
- m_gbm_bo_next = nullptr;
- return;
+ if (ret) {
+ qErrnoWarning("Could not queue DRM page flip on screen %s", qPrintable(name()));
+ m_flipPending = false;
+ gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next);
+ m_gbm_bo_next = nullptr;
+ return;
+ }
}
for (CloneDestination &d : m_cloneDests) {
if (d.screen != this) {
d.screen->ensureModeSet(fb->fb);
d.cloneFlipPending = true;
- int ret = drmModePageFlip(fd,
- d.screen->output().crtc_id,
- fb->fb,
- DRM_MODE_PAGE_FLIP_EVENT,
- d.screen);
- if (ret) {
- qErrnoWarning("Could not queue DRM page flip for clone screen %s", qPrintable(name()));
- d.cloneFlipPending = false;
+
+ if (device()->hasAtomicSupport()) {
+#if QT_CONFIG(drm_atomic)
+ drmModeAtomicReq *request = device()->atomic_request();
+ if (request) {
+ drmModeAtomicAddProperty(request, d.screen->output().eglfs_plane->id,
+ d.screen->output().eglfs_plane->framebufferPropertyId, fb->fb);
+ drmModeAtomicAddProperty(request, d.screen->output().eglfs_plane->id,
+ d.screen->output().eglfs_plane->crtcPropertyId, op.crtc_id);
+ }
+#endif
+ } else {
+ int ret = drmModePageFlip(fd,
+ d.screen->output().crtc_id,
+ fb->fb,
+ DRM_MODE_PAGE_FLIP_EVENT,
+ d.screen);
+ if (ret) {
+ qErrnoWarning("Could not queue DRM page flip for clone screen %s", qPrintable(name()));
+ d.cloneFlipPending = false;
+ }
}
}
}
+
+#if QT_CONFIG(drm_atomic)
+ if (device()->hasAtomicSupport())
+ device()->atomicCommit(this);
+#endif
}
void QEglFSKmsGbmScreen::pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
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 531b73d1dc..1626c86239 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
@@ -112,7 +112,7 @@ void QEglFSKmsEglDeviceScreen::waitForFlip()
qCDebug(qLcEglfsKmsDebug, "Setting plane %u", op.forced_plane_id);
int ret = drmModeSetPlane(fd, op.forced_plane_id, op.crtc_id, uint32_t(-1), 0,
0, 0, w, h,
- 0 << 16, 0 << 16, w << 16, h << 16);
+ 0 << 16, 0 << 16, op.size.width() << 16, op.size.height() << 16);
if (ret == -1)
qErrnoWarning(errno, "drmModeSetPlane failed");
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
index 06bc272050..a6aac61506 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
@@ -138,6 +138,10 @@ void *QEglFSKmsIntegration::nativeResourceForIntegration(const QByteArray &name)
if (name == QByteArrayLiteral("dri_fd") && m_device)
return (void *) (qintptr) m_device->fd();
+#if QT_CONFIG(drm_atomic)
+ if (name == QByteArrayLiteral("dri_atomic_request") && m_device)
+ return (void *) (qintptr) m_device->atomic_request();
+#endif
return nullptr;
}
@@ -147,6 +151,8 @@ void *QEglFSKmsIntegration::nativeResourceForScreen(const QByteArray &resource,
if (s) {
if (resource == QByteArrayLiteral("dri_crtcid"))
return (void *) (qintptr) s->output().crtc_id;
+ if (resource == QByteArrayLiteral("dri_connectorid"))
+ return (void *) (qintptr) s->output().connector_id;
}
return nullptr;
}
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 5e45b42abe..e5354d97bd 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
@@ -113,10 +113,9 @@ QRect QEglFSKmsScreen::rawGeometry() const
if (m_headless)
return QRect(QPoint(0, 0), m_device->screenConfig()->headlessSize());
- const int mode = m_output.mode;
return QRect(m_pos.x(), m_pos.y(),
- m_output.modes[mode].hdisplay,
- m_output.modes[mode].vdisplay);
+ m_output.size.width(),
+ m_output.size.height());
}
int QEglFSKmsScreen::depth() const
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
index c52d498cd4..201b277494 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
@@ -41,8 +41,6 @@
#include "../../qiosfiledialog.h"
-@interface QIOSImagePickerController : UIImagePickerController <UIImagePickerControllerDelegate, UINavigationControllerDelegate> {
- QIOSFileDialog *m_fileDialog;
-}
-- (id)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog;
+@interface QIOSImagePickerController : UIImagePickerController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
+- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog;
@end
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
index 78e0f00ab4..79d4ecf83f 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
@@ -41,15 +41,17 @@
#include "qiosimagepickercontroller.h"
-@implementation QIOSImagePickerController
+@implementation QIOSImagePickerController {
+ QIOSFileDialog *m_fileDialog;
+}
-- (id)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog
+- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog
{
self = [super init];
if (self) {
m_fileDialog = fileDialog;
- [self setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
- [self setDelegate:self];
+ self.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
+ self.delegate = self;
}
return self;
}
@@ -57,8 +59,8 @@
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
Q_UNUSED(picker);
- NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
- QUrl fileUrl = QUrl::fromLocalFile(QString::fromNSString([url description]));
+ NSURL *url = info[UIImagePickerControllerReferenceURL];
+ QUrl fileUrl = QUrl::fromLocalFile(QString::fromNSString(url.description));
m_fileDialog->selectedFilesChanged(QList<QUrl>() << fileUrl);
emit m_fileDialog->accept();
}
diff --git a/src/plugins/platforms/ios/qiosclipboard.mm b/src/plugins/platforms/ios/qiosclipboard.mm
index 9a975eadc9..6bdbf94d3f 100644
--- a/src/plugins/platforms/ios/qiosclipboard.mm
+++ b/src/plugins/platforms/ios/qiosclipboard.mm
@@ -46,11 +46,11 @@
#include <QtGui/QGuiApplication>
@interface UIPasteboard (QUIPasteboard)
- + (UIPasteboard *)pasteboardWithQClipboardMode:(QClipboard::Mode)mode;
++ (instancetype)pasteboardWithQClipboardMode:(QClipboard::Mode)mode;
@end
@implementation UIPasteboard (QUIPasteboard)
-+ (UIPasteboard *)pasteboardWithQClipboardMode:(QClipboard::Mode)mode
++ (instancetype)pasteboardWithQClipboardMode:(QClipboard::Mode)mode
{
NSString *name = (mode == QClipboard::Clipboard) ? UIPasteboardNameGeneral : UIPasteboardNameFind;
return [UIPasteboard pasteboardWithName:name create:NO];
@@ -60,17 +60,15 @@
// --------------------------------------------------------------------
@interface QUIClipboard : NSObject
-{
-@public
+@end
+
+@implementation QUIClipboard {
QIOSClipboard *m_qiosClipboard;
NSInteger m_changeCountClipboard;
NSInteger m_changeCountFindBuffer;
}
-@end
-
-@implementation QUIClipboard
-- (id)initWithQIOSClipboard:(QIOSClipboard *)qiosClipboard
+- (instancetype)initWithQIOSClipboard:(QIOSClipboard *)qiosClipboard
{
self = [super init];
if (self) {
@@ -149,7 +147,7 @@ QStringList QIOSMimeData::formats() const
{
QStringList foundMimeTypes;
UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode];
- NSArray *pasteboardTypes = [pb pasteboardTypes];
+ NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
for (NSUInteger i = 0; i < [pasteboardTypes count]; ++i) {
QString uti = QString::fromNSString([pasteboardTypes objectAtIndex:i]);
@@ -164,7 +162,7 @@ QStringList QIOSMimeData::formats() const
QVariant QIOSMimeData::retrieveData(const QString &mimeType, QVariant::Type) const
{
UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode];
- NSArray *pasteboardTypes = [pb pasteboardTypes];
+ NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
foreach (QMacInternalPasteboardMime *converter,
QMacInternalPasteboardMime::all(QMacInternalPasteboardMime::MIME_ALL)) {
@@ -213,12 +211,12 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:mode];
if (!mimeData) {
- pb.items = [NSArray array];
+ pb.items = [NSArray<NSDictionary<NSString *, id> *> array];
return;
}
mimeData->deleteLater();
- NSMutableDictionary *pbItem = [NSMutableDictionary dictionaryWithCapacity:mimeData->formats().size()];
+ NSMutableDictionary<NSString *, id> *pbItem = [NSMutableDictionary<NSString *, id> dictionaryWithCapacity:mimeData->formats().size()];
foreach (const QString &mimeType, mimeData->formats()) {
foreach (QMacInternalPasteboardMime *converter,
@@ -246,7 +244,7 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
}
}
- pb.items = [NSArray arrayWithObject:pbItem];
+ pb.items = @[pbItem];
}
bool QIOSClipboard::supportsMode(QClipboard::Mode mode) const
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h
index 62133b9510..1f4c78dc74 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.h
+++ b/src/plugins/platforms/ios/qioseventdispatcher.h
@@ -49,18 +49,29 @@ class QIOSEventDispatcher : public QEventDispatcherCoreFoundation
Q_OBJECT
public:
+ static QIOSEventDispatcher* create();
+ bool processPostedEvents() override;
+
+protected:
explicit QIOSEventDispatcher(QObject *parent = 0);
+};
+
+class QIOSJumpingEventDispatcher : public QIOSEventDispatcher
+{
+ Q_OBJECT
+public:
+ QIOSJumpingEventDispatcher(QObject *parent = 0);
bool processEvents(QEventLoop::ProcessEventsFlags flags) override;
- bool processPostedEvents() override;
+ // Public since we can't friend Objective-C methods
void handleRunLoopExit(CFRunLoopActivity activity);
void interruptEventLoopExec();
private:
uint m_processEventLevel;
- RunLoopObserver<QIOSEventDispatcher> m_runLoopExitObserver;
+ RunLoopObserver<QIOSJumpingEventDispatcher> m_runLoopExitObserver;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
index a6f6a7aac9..6a6e1bd618 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -204,6 +204,11 @@ namespace
jmp_buf applicationWillTerminateJumpPoint;
bool debugStackUsage = false;
+
+ struct {
+ QAppleLogActivity UIApplicationMain;
+ QAppleLogActivity applicationDidFinishLaunching;
+ } logActivity;
}
extern "C" int qt_main_wrapper(int argc, char *argv[])
@@ -228,6 +233,9 @@ extern "C" int qt_main_wrapper(int argc, char *argv[])
}
}
+ logActivity.UIApplicationMain = QT_APPLE_LOG_ACTIVITY(
+ lcEventDispatcher().isDebugEnabled(), "UIApplicationMain").enter();
+
qCDebug(lcEventDispatcher) << "Running UIApplicationMain";
return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSApplicationDelegate class]));
}
@@ -245,7 +253,7 @@ extern "C" int main(int argc, char *argv[]);
static void __attribute__((noinline, noreturn)) user_main_trampoline()
{
- NSArray *arguments = [[NSProcessInfo processInfo] arguments];
+ NSArray<NSString *> *arguments = [[NSProcessInfo processInfo] arguments];
int argc = arguments.count;
char **argv = new char*[argc];
@@ -263,11 +271,14 @@ static void __attribute__((noinline, noreturn)) user_main_trampoline()
int exitCode = main(argc, argv);
delete[] argv;
+ logActivity.applicationDidFinishLaunching.enter();
qCDebug(lcEventDispatcher) << "Returned from main with exit code " << exitCode;
if (Q_UNLIKELY(debugStackUsage))
userMainStack.printUsage();
+ logActivity.applicationDidFinishLaunching.leave();
+
if (applicationAboutToTerminate)
longjmp(applicationWillTerminateJumpPoint, kJumpedFromUserMainTrampoline);
@@ -322,6 +333,9 @@ static bool rootLevelRunLoopIntegration()
+ (void)applicationDidFinishLaunching:(NSNotification *)notification
{
+ logActivity.applicationDidFinishLaunching = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
+ lcEventDispatcher().isDebugEnabled(), "applicationDidFinishLaunching", logActivity.UIApplicationMain).enter();
+
qCDebug(lcEventDispatcher) << "Application launched with options" << notification.userInfo;
if (!isQtApplication())
@@ -339,10 +353,11 @@ static bool rootLevelRunLoopIntegration()
return;
}
-
switch (setjmp(processEventEnterJumpPoint)) {
- case kJumpPointSetSuccessfully:
+ case kJumpPointSetSuccessfully: {
qCDebug(lcEventDispatcher) << "Running main() on separate stack";
+ QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "main()");
+
// Redirect the stack pointer to the start of the reserved stack. This ensures
// that when we longjmp out of the event dispatcher and continue execution, the
// 'Qt main' call-stack will not be smashed, as it lives in a part of the stack
@@ -357,9 +372,11 @@ static bool rootLevelRunLoopIntegration()
Q_UNREACHABLE();
break;
+ }
case kJumpedFromEventDispatcherProcessEvents:
// We've returned from the longjmp in the event dispatcher,
// and the stack has been restored to its old self.
+ logActivity.UIApplicationMain.enter();
qCDebug(lcEventDispatcher) << "↳ Jumped from processEvents due to exec";
if (Q_UNLIKELY(debugStackUsage))
@@ -378,6 +395,10 @@ static const char kApplicationWillTerminateExitCode = char(SIGTERM | 0x80);
+ (void)applicationWillTerminate
{
+ QAppleLogActivity applicationWillTerminateActivity = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
+ lcEventDispatcher().isDebugEnabled(), "applicationWillTerminate", logActivity.UIApplicationMain).enter();
+ qCDebug(lcEventDispatcher) << "Application about to be terminated by iOS";
+
if (!isQtApplication())
return;
@@ -403,11 +424,14 @@ static const char kApplicationWillTerminateExitCode = char(SIGTERM | 0x80);
// so we'll never see the exit activity and have a chance to return from
// QEventLoop::exec(). We initiate the return manually as a workaround.
qCDebug(lcEventDispatcher) << "Manually triggering return from event loop exec";
- static_cast<QIOSEventDispatcher *>(qApp->eventDispatcher())->interruptEventLoopExec();
+ applicationWillTerminateActivity.leave();
+ static_cast<QIOSJumpingEventDispatcher *>(qApp->eventDispatcher())->interruptEventLoopExec();
break;
case kJumpedFromUserMainTrampoline:
+ applicationWillTerminateActivity.enter();
// The user's main has returned, so we're ready to let iOS terminate the application
qCDebug(lcEventDispatcher) << "kJumpedFromUserMainTrampoline, allowing iOS to terminate";
+ applicationWillTerminateActivity.leave();
break;
default:
qFatal("Unexpected jump result in event loop integration");
@@ -419,20 +443,49 @@ static const char kApplicationWillTerminateExitCode = char(SIGTERM | 0x80);
QT_BEGIN_NAMESPACE
QT_USE_NAMESPACE
+QIOSEventDispatcher *QIOSEventDispatcher::create()
+{
+ if (isQtApplication() && rootLevelRunLoopIntegration())
+ return new QIOSJumpingEventDispatcher;
+
+ return new QIOSEventDispatcher;
+}
+
QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
: QEventDispatcherCoreFoundation(parent)
- , m_processEventLevel(0)
- , m_runLoopExitObserver(this, &QIOSEventDispatcher::handleRunLoopExit, kCFRunLoopExit)
{
// We want all delivery of events from the system to be handled synchronously
QWindowSystemInterface::setSynchronousWindowSystemEvents(true);
}
-bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
+/*!
+ Override of the CoreFoundation posted events runloop source callback
+ so that we can send window system (QPA) events in addition to sending
+ normal Qt events.
+*/
+bool QIOSEventDispatcher::processPostedEvents()
{
- if (!rootLevelRunLoopIntegration())
- return QEventDispatcherCoreFoundation::processEvents(flags);
+ // Don't send window system events if the base CF dispatcher has determined
+ // that events should not be sent for this pass of the runloop source.
+ if (!QEventDispatcherCoreFoundation::processPostedEvents())
+ return false;
+
+ QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "sendWindowSystemEvents");
+ qCDebug(lcEventDispatcher) << "Sending window system events for" << m_processEvents.flags;
+ QWindowSystemInterface::sendWindowSystemEvents(m_processEvents.flags);
+
+ return true;
+}
+
+QIOSJumpingEventDispatcher::QIOSJumpingEventDispatcher(QObject *parent)
+ : QIOSEventDispatcher(parent)
+ , m_processEventLevel(0)
+ , m_runLoopExitObserver(this, &QIOSJumpingEventDispatcher::handleRunLoopExit, kCFRunLoopExit)
+{
+}
+bool __attribute__((returns_twice)) QIOSJumpingEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
if (applicationAboutToTerminate) {
qCDebug(lcEventDispatcher) << "Detected QEventLoop exec after application termination";
// Re-issue exit, and return immediately
@@ -441,6 +494,7 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo
}
if (!m_processEventLevel && (flags & QEventLoop::EventLoopExec)) {
+ QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "processEvents");
qCDebug(lcEventDispatcher) << "Processing events with flags" << flags;
++m_processEventLevel;
@@ -475,25 +529,7 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo
return processedEvents;
}
-/*!
- Override of the CoreFoundation posted events runloop source callback
- so that we can send window system (QPA) events in addition to sending
- normal Qt events.
-*/
-bool QIOSEventDispatcher::processPostedEvents()
-{
- // Don't send window system events if the base CF dispatcher has determined
- // that events should not be sent for this pass of the runloop source.
- if (!QEventDispatcherCoreFoundation::processPostedEvents())
- return false;
-
- qCDebug(lcEventDispatcher) << "Sending window system events for" << m_processEvents.flags;
- QWindowSystemInterface::sendWindowSystemEvents(m_processEvents.flags);
-
- return true;
-}
-
-void QIOSEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
+void QIOSJumpingEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
{
Q_UNUSED(activity);
Q_ASSERT(activity == kCFRunLoopExit);
@@ -502,7 +538,7 @@ void QIOSEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
interruptEventLoopExec();
}
-void QIOSEventDispatcher::interruptEventLoopExec()
+void QIOSJumpingEventDispatcher::interruptEventLoopExec()
{
Q_ASSERT(m_processEventLevel == 1);
@@ -516,10 +552,12 @@ void QIOSEventDispatcher::interruptEventLoopExec()
switch (setjmp(processEventEnterJumpPoint)) {
case kJumpPointSetSuccessfully:
qCDebug(lcEventDispatcher) << "Jumping into processEvents due to system runloop exit ⇢";
+ logActivity.UIApplicationMain.leave();
longjmp(processEventExitJumpPoint, kJumpedFromEventLoopExecInterrupt);
break;
case kJumpedFromEventDispatcherProcessEvents:
// QEventLoop was re-executed
+ logActivity.UIApplicationMain.enter();
qCDebug(lcEventDispatcher) << "↳ Jumped from processEvents due to re-exec";
break;
default:
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index 050c592aca..3e22634071 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -67,7 +67,7 @@ static QUIView *focusView()
@implementation QIOSLocaleListener
-- (id)init
+- (instancetype)init
{
if (self = [super init]) {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
@@ -95,16 +95,15 @@ static QUIView *focusView()
// -------------------------------------------------------------------------
-@interface QIOSKeyboardListener : UIGestureRecognizer <UIGestureRecognizerDelegate> {
- @private
- QT_PREPEND_NAMESPACE(QIOSInputContext) *m_context;
-}
+@interface QIOSKeyboardListener : UIGestureRecognizer <UIGestureRecognizerDelegate>
@property BOOL hasDeferredScrollToCursor;
@end
-@implementation QIOSKeyboardListener
+@implementation QIOSKeyboardListener {
+ QT_PREPEND_NAMESPACE(QIOSInputContext) *m_context;
+}
-- (id)initWithQIOSInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context
+- (instancetype)initWithQIOSInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context
{
if (self = [super initWithTarget:self action:@selector(gestureStateChanged:)]) {
@@ -574,7 +573,7 @@ void QIOSInputContext::scroll(int y)
// Raise all known windows to above the status-bar if we're scrolling the screen,
// while keeping the relative window level between the windows the same.
- NSArray *applicationWindows = [[UIApplication sharedApplication] windows];
+ NSArray<UIWindow *> *applicationWindows = [[UIApplication sharedApplication] windows];
static QHash<UIWindow *, UIWindowLevel> originalWindowLevels;
for (UIWindow *window in applicationWindows) {
if (keyboardScrollIsActive && !originalWindowLevels.contains(window))
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 2e657b3798..eae0530fbe 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -100,7 +100,7 @@ QIOSIntegration::QIOSIntegration()
void QIOSIntegration::initialize()
{
UIScreen *mainScreen = [UIScreen mainScreen];
- NSMutableArray *screens = [[[UIScreen screens] mutableCopy] autorelease];
+ NSMutableArray<UIScreen *> *screens = [[[UIScreen screens] mutableCopy] autorelease];
if (![screens containsObject:mainScreen]) {
// Fallback for iOS 7.1 (QTBUG-42345)
[screens insertObject:mainScreen atIndex:0];
@@ -217,10 +217,7 @@ QPlatformOffscreenSurface *QIOSIntegration::createPlatformOffscreenSurface(QOffs
QAbstractEventDispatcher *QIOSIntegration::createEventDispatcher() const
{
- if (isQtApplication())
- return new QIOSEventDispatcher;
- else
- return new QEventDispatcherCoreFoundation;
+ return QIOSEventDispatcher::create();
}
QPlatformFontDatabase * QIOSIntegration::fontDatabase() const
diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm
index 6c70676a31..74a77de757 100644
--- a/src/plugins/platforms/ios/qiosmenu.mm
+++ b/src/plugins/platforms/ios/qiosmenu.mm
@@ -60,14 +60,14 @@ QIOSMenu *QIOSMenu::m_currentMenu = 0;
static NSString *const kSelectorPrefix = @"_qtMenuItem_";
-@interface QUIMenuController : UIResponder {
- QIOSMenuItemList m_visibleMenuItems;
-}
+@interface QUIMenuController : UIResponder
@end
-@implementation QUIMenuController
+@implementation QUIMenuController {
+ QIOSMenuItemList m_visibleMenuItems;
+}
-- (id)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems
+- (instancetype)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems
{
if (self = [super init]) {
[self setVisibleMenuItems:visibleMenuItems];
@@ -80,7 +80,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
return self;
}
--(void)dealloc
+- (void)dealloc
{
[[NSNotificationCenter defaultCenter]
removeObserver:self
@@ -91,7 +91,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
- (void)setVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems
{
m_visibleMenuItems = visibleMenuItems;
- NSMutableArray *menuItemArray = [NSMutableArray arrayWithCapacity:m_visibleMenuItems.size()];
+ NSMutableArray<UIMenuItem *> *menuItemArray = [NSMutableArray<UIMenuItem *> arrayWithCapacity:m_visibleMenuItems.size()];
// Create an array of UIMenuItems, one for each visible QIOSMenuItem. Each
// UIMenuItem needs a callback assigned, so we assign one of the placeholder methods
// added to UIWindow (QIOSMenuActionTargets) below. Each method knows its own index, which
@@ -107,7 +107,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
[[UIMenuController sharedMenuController] setMenuVisible:YES animated:NO];
}
--(void)menuClosed
+- (void)menuClosed
{
QIOSMenu::currentMenu()->dismiss();
}
@@ -141,19 +141,19 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
// -------------------------------------------------------------------------
-@interface QUIPickerView : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource> {
- QIOSMenuItemList m_visibleMenuItems;
- QPointer<QObject> m_focusObjectWithPickerView;
- NSInteger m_selectedRow;
-}
+@interface QUIPickerView : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource>
@property(retain) UIToolbar *toolbar;
@end
-@implementation QUIPickerView
+@implementation QUIPickerView {
+ QIOSMenuItemList m_visibleMenuItems;
+ QPointer<QObject> m_focusObjectWithPickerView;
+ NSInteger m_selectedRow;
+}
-- (id)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems selectItem:(const QIOSMenuItem *)selectItem
+- (instancetype)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems selectItem:(const QIOSMenuItem *)selectItem
{
if (self = [super init]) {
[self setVisibleMenuItems:visibleMenuItems selectItem:selectItem];
@@ -172,7 +172,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
UIBarButtonItem *doneButton = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:@selector(closeMenu)] autorelease];
- [self.toolbar setItems:[NSArray arrayWithObjects:cancelButton, spaceButton, doneButton, nil]];
+ [self.toolbar setItems:@[cancelButton, spaceButton, doneButton]];
[self setDelegate:self];
[self setDataSource:self];
diff --git a/src/plugins/platforms/ios/qiosoptionalplugininterface.h b/src/plugins/platforms/ios/qiosoptionalplugininterface.h
index 660c74e856..bae9e5a0d8 100644
--- a/src/plugins/platforms/ios/qiosoptionalplugininterface.h
+++ b/src/plugins/platforms/ios/qiosoptionalplugininterface.h
@@ -44,10 +44,10 @@
#include "qiosfiledialog.h"
-QT_BEGIN_NAMESPACE
-
Q_FORWARD_DECLARE_OBJC_CLASS(UIViewController);
+QT_BEGIN_NAMESPACE
+
#define QIosOptionalPluginInterface_iid "org.qt-project.Qt.QPA.ios.optional"
class QIosOptionalPluginInterface
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index c394592d76..96679eaccd 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -130,16 +130,14 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
// -------------------------------------------------------------------------
-@interface QIOSOrientationListener : NSObject {
- @public
- QIOSScreen *m_screen;
-}
-- (id)initWithQIOSScreen:(QIOSScreen *)screen;
+@interface QIOSOrientationListener : NSObject
@end
-@implementation QIOSOrientationListener
+@implementation QIOSOrientationListener {
+ QIOSScreen *m_screen;
+}
-- (id)initWithQIOSScreen:(QIOSScreen *)screen
+- (instancetype)initWithQIOSScreen:(QIOSScreen *)screen
{
self = [super init];
if (self) {
@@ -193,7 +191,7 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
@implementation QUIWindow
-- (id)initWithFrame:(CGRect)frame
+- (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
self->_sendingEvent = NO;
@@ -392,17 +390,21 @@ void QIOSScreen::deliverUpdateRequests() const
QList<QWindow*> windows = QGuiApplication::allWindows();
for (int i = 0; i < windows.size(); ++i) {
- if (platformScreenForWindow(windows.at(i)) != this)
+ QWindow *window = windows.at(i);
+ if (platformScreenForWindow(window) != this)
+ continue;
+
+ QPlatformWindow *platformWindow = window->handle();
+ if (!platformWindow)
continue;
- QWindowPrivate *wp = static_cast<QWindowPrivate *>(QObjectPrivate::get(windows.at(i)));
- if (!wp->updateRequestPending)
+ if (!platformWindow->hasPendingUpdateRequest())
continue;
- wp->deliverUpdateRequest();
+ platformWindow->deliverUpdateRequest();
// Another update request was triggered, keep the display link running
- if (wp->updateRequestPending)
+ if (platformWindow->hasPendingUpdateRequest())
pauseUpdates = false;
}
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
index fe3c29d037..ff696f5b7f 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.mm
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -96,7 +96,7 @@ static void executeBlockWithoutAnimation(Block block)
@implementation QIOSEditMenu
-- (id)init
+- (instancetype)init
{
if (self = [super init]) {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
@@ -160,7 +160,13 @@ static void executeBlockWithoutAnimation(Block block)
// -------------------------------------------------------------------------
-@interface QIOSLoupeLayer : CALayer {
+@interface QIOSLoupeLayer : CALayer
+@property (nonatomic, retain) UIView *targetView;
+@property (nonatomic, assign) CGPoint focalPoint;
+@property (nonatomic, assign) BOOL visible;
+@end
+
+@implementation QIOSLoupeLayer {
UIView *_snapshotView;
BOOL _pendingSnapshotUpdate;
UIView *_loupeImageView;
@@ -168,14 +174,8 @@ static void executeBlockWithoutAnimation(Block block)
CGFloat _loupeOffset;
QTimer _updateTimer;
}
-@property (nonatomic, retain) UIView *targetView;
-@property (nonatomic, assign) CGPoint focalPoint;
-@property (nonatomic, assign) BOOL visible;
-@end
-@implementation QIOSLoupeLayer
-
-- (id)initWithSize:(CGSize)size cornerRadius:(CGFloat)cornerRadius bottomOffset:(CGFloat)bottomOffset
+- (instancetype)initWithSize:(CGSize)size cornerRadius:(CGFloat)cornerRadius bottomOffset:(CGFloat)bottomOffset
{
if (self = [super init]) {
_loupeOffset = bottomOffset + (size.height / 2);
@@ -301,26 +301,22 @@ static void executeBlockWithoutAnimation(Block block)
// -------------------------------------------------------------------------
-#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_10_0)
-@interface QIOSHandleLayer : CALayer <CAAnimationDelegate> {
-#else
-@interface QIOSHandleLayer : CALayer {
-#endif
- CALayer *_handleCursorLayer;
- CALayer *_handleKnobLayer;
- Qt::Edge _selectionEdge;
-}
+@interface QIOSHandleLayer : CALayer <CAAnimationDelegate>
@property (nonatomic, assign) CGRect cursorRectangle;
@property (nonatomic, assign) CGFloat handleScale;
@property (nonatomic, assign) BOOL visible;
@property (nonatomic, copy) Block onAnimationDidStop;
@end
-@implementation QIOSHandleLayer
+@implementation QIOSHandleLayer {
+ CALayer *_handleCursorLayer;
+ CALayer *_handleKnobLayer;
+ Qt::Edge _selectionEdge;
+}
@dynamic handleScale;
-- (id)initWithKnobAtEdge:(Qt::Edge)selectionEdge
+- (instancetype)initWithKnobAtEdge:(Qt::Edge)selectionEdge
{
if (self = [super init]) {
CGColorRef bgColor = [UIColor colorWithRed:0.1 green:0.4 blue:0.9 alpha:1].CGColor;
@@ -355,16 +351,8 @@ static void executeBlockWithoutAnimation(Block block)
// The handle should "bounce" in when becoming visible
CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:key];
[animation setDuration:0.5];
- animation.values = [NSArray arrayWithObjects:
- [NSNumber numberWithFloat:0],
- [NSNumber numberWithFloat:1.3],
- [NSNumber numberWithFloat:1.3],
- [NSNumber numberWithFloat:1], nil];
- animation.keyTimes = [NSArray arrayWithObjects:
- [NSNumber numberWithFloat:0],
- [NSNumber numberWithFloat:0.3],
- [NSNumber numberWithFloat:0.9],
- [NSNumber numberWithFloat:1], nil];
+ animation.values = @[@(0.0f), @(1.3f), @(1.3f), @(1.0f)];
+ animation.keyTimes = @[@(0.0f), @(0.3f), @(0.9f), @(1.0f)];
return animation;
} else {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key];
@@ -436,8 +424,13 @@ static void executeBlockWithoutAnimation(Block block)
below will inherit. It takes care of creating and showing a magnifier
glass depending on the current gesture state.
*/
-@interface QIOSLoupeRecognizer : UIGestureRecognizer <UIGestureRecognizerDelegate> {
-@public
+@interface QIOSLoupeRecognizer : UIGestureRecognizer <UIGestureRecognizerDelegate>
+@property (nonatomic, assign) QPointF focalPoint;
+@property (nonatomic, assign) BOOL dragTriggersGesture;
+@property (nonatomic, readonly) UIView *focusView;
+@end
+
+@implementation QIOSLoupeRecognizer {
QIOSLoupeLayer *_loupeLayer;
UIView *_desktopView;
CGPoint _firstTouchPoint;
@@ -445,14 +438,8 @@ static void executeBlockWithoutAnimation(Block block)
QTimer _triggerStateBeganTimer;
int _originalCursorFlashTime;
}
-@property (nonatomic, assign) QPointF focalPoint;
-@property (nonatomic, assign) BOOL dragTriggersGesture;
-@property (nonatomic, readonly) UIView *focusView;
-@end
-@implementation QIOSLoupeRecognizer
-
-- (id)init
+- (instancetype)init
{
if (self = [super initWithTarget:self action:@selector(gestureStateChanged)]) {
self.enabled = NO;
@@ -657,7 +644,10 @@ static void executeBlockWithoutAnimation(Block block)
on the sides. If the user starts dragging on a handle (or do a press and
hold), it will show a magnifier glass that follows the handle as it moves.
*/
-@interface QIOSSelectionRecognizer : QIOSLoupeRecognizer {
+@interface QIOSSelectionRecognizer : QIOSLoupeRecognizer
+@end
+
+@implementation QIOSSelectionRecognizer {
CALayer *_clipRectLayer;
QIOSHandleLayer *_cursorLayer;
QIOSHandleLayer *_anchorLayer;
@@ -669,11 +659,8 @@ static void executeBlockWithoutAnimation(Block block)
QMetaObject::Connection _anchorConnection;
QMetaObject::Connection _clipRectConnection;
}
-@end
-
-@implementation QIOSSelectionRecognizer
-- (id)init
+- (instancetype)init
{
if (self = [super init]) {
self.delaysTouchesBegan = YES;
@@ -889,15 +876,15 @@ static void executeBlockWithoutAnimation(Block block)
visibility of the edit menu will be toggled. Otherwise, if there's a selection, a
first tap will close the edit menu (if any), and a second tap will remove the selection.
*/
-@interface QIOSTapRecognizer : UITapGestureRecognizer {
+@interface QIOSTapRecognizer : UITapGestureRecognizer
+@end
+
+@implementation QIOSTapRecognizer {
int _cursorPosOnPress;
UIView *_focusView;
}
-@end
-
-@implementation QIOSTapRecognizer
-- (id)init
+- (instancetype)init
{
if (self = [super initWithTarget:self action:@selector(gestureStateChanged)]) {
self.enabled = NO;
diff --git a/src/plugins/platforms/ios/qiostextresponder.h b/src/plugins/platforms/ios/qiostextresponder.h
index 77be2cf2fe..074598c1c3 100644
--- a/src/plugins/platforms/ios/qiostextresponder.h
+++ b/src/plugins/platforms/ios/qiostextresponder.h
@@ -49,16 +49,8 @@ class QIOSInputContext;
QT_END_NAMESPACE
@interface QIOSTextInputResponder : UIResponder <UITextInputTraits, UIKeyInput, UITextInput>
-{
- @private
- QT_PREPEND_NAMESPACE(QIOSInputContext) *m_inputContext;
- QT_PREPEND_NAMESPACE(QInputMethodQueryEvent) *m_configuredImeState;
- QString m_markedText;
- BOOL m_inSendEventToFocusObject;
- BOOL m_inSelectionChange;
-}
-- (id)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context;
+- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context;
- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties;
- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties;
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index b029c49a67..91a088ede1 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -55,13 +55,13 @@
@interface QUITextPosition : UITextPosition
@property (nonatomic) NSUInteger index;
-+ (QUITextPosition *)positionWithIndex:(NSUInteger)index;
++ (instancetype)positionWithIndex:(NSUInteger)index;
@end
@implementation QUITextPosition
-+ (QUITextPosition *)positionWithIndex:(NSUInteger)index
++ (instancetype)positionWithIndex:(NSUInteger)index
{
QUITextPosition *pos = [[QUITextPosition alloc] init];
pos.index = index;
@@ -75,15 +75,15 @@
@interface QUITextRange : UITextRange
@property (nonatomic) NSRange range;
-+ (QUITextRange *)rangeWithNSRange:(NSRange)range;
++ (instancetype)rangeWithNSRange:(NSRange)range;
@end
@implementation QUITextRange
-+ (QUITextRange *)rangeWithNSRange:(NSRange)nsrange
++ (instancetype)rangeWithNSRange:(NSRange)nsrange
{
- QUITextRange *range = [[QUITextRange alloc] init];
+ QUITextRange *range = [[self alloc] init];
range.range = nsrange;
return [range autorelease];
}
@@ -117,7 +117,7 @@
@implementation WrapperView
-- (id)initWithView:(UIView *)view
+- (instancetype)initWithView:(UIView *)view
{
if (self = [self init]) {
[self addSubview:view];
@@ -132,7 +132,7 @@
- (void)layoutSubviews
{
- UIView* view = [self.subviews firstObject];
+ UIView *view = [self.subviews firstObject];
view.frame = self.bounds;
// FIXME: During orientation changes the size and position
@@ -161,9 +161,15 @@
// -------------------------------------------------------------------------
-@implementation QIOSTextInputResponder
+@implementation QIOSTextInputResponder {
+ QT_PREPEND_NAMESPACE(QIOSInputContext) *m_inputContext;
+ QT_PREPEND_NAMESPACE(QInputMethodQueryEvent) *m_configuredImeState;
+ QString m_markedText;
+ BOOL m_inSendEventToFocusObject;
+ BOOL m_inSelectionChange;
+}
-- (id)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)inputContext
+- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)inputContext
{
if (!(self = [self init]))
return self;
@@ -548,7 +554,7 @@
[self sendKeyPressRelease:key modifiers:modifiers];
}
-- (void)addKeyCommandsToArray:(NSMutableArray *)array key:(NSString *)key
+- (void)addKeyCommandsToArray:(NSMutableArray<UIKeyCommand *> *)array key:(NSString *)key
{
SEL s = @selector(keyCommandTriggered:);
[array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:0 action:s]];
@@ -559,19 +565,19 @@
[array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand|UIKeyModifierShift action:s]];
}
-- (NSArray *)keyCommands
+- (NSArray<UIKeyCommand *> *)keyCommands
{
// Since keyCommands is called for every key
// press/release, we cache the result
static dispatch_once_t once;
- static NSMutableArray *array;
+ static NSMutableArray<UIKeyCommand *> *array;
dispatch_once(&once, ^{
// We let Qt move the cursor around when the arrow keys are being used. This
// is normally implemented through UITextInput, but since IM in Qt have poor
// support for moving the cursor vertically, and even less support for selecting
// text across multiple paragraphs, we do this through key events.
- array = [NSMutableArray new];
+ array = [NSMutableArray<UIKeyCommand *> new];
[self addKeyCommandsToArray:array key:UIKeyInputUpArrow];
[self addKeyCommandsToArray:array key:UIKeyInputDownArrow];
[self addKeyCommandsToArray:array key:UIKeyInputLeftArrow];
@@ -825,13 +831,13 @@
return startRect.united(endRect).toCGRect();
}
-- (NSArray *)selectionRectsForRange:(UITextRange *)range
+- (NSArray<UITextSelectionRect *> *)selectionRectsForRange:(UITextRange *)range
{
Q_UNUSED(range);
// This method is supposed to return a rectangle for each line with selection. Since we don't
// expose an API in Qt/IM for getting this information, and since we never seems to be getting
// a call from UIKit for this, we return an empty array until a need arise.
- return [[NSArray new] autorelease];
+ return [[NSArray<UITextSelectionRect *> new] autorelease];
}
- (CGRect)caretRectForPosition:(UITextPosition *)position
@@ -916,7 +922,7 @@
QObject *focusObject = QGuiApplication::focusObject();
if (!focusObject)
- return [NSDictionary dictionary];
+ return @{};
// Assume position is the same as the cursor for now. QInputMethodQueryEvent with Qt::ImFont
// needs to be extended to take an extra position argument before this can be fully correct.
@@ -925,8 +931,8 @@
QFont qfont = qvariant_cast<QFont>(e.value(Qt::ImFont));
UIFont *uifont = [UIFont fontWithName:qfont.family().toNSString() size:qfont.pointSize()];
if (!uifont)
- return [NSDictionary dictionary];
- return [NSDictionary dictionaryWithObject:uifont forKey:NSFontAttributeName];
+ return @{};
+ return @{NSFontAttributeName: uifont};
}
#endif
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h
index 07d5535e1a..7af4c83b48 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.h
+++ b/src/plugins/platforms/ios/qiosviewcontroller.h
@@ -48,7 +48,7 @@ QT_END_NAMESPACE
@interface QIOSViewController : UIViewController
-- (id)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen;
+- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen;
- (void)updateProperties;
#ifndef Q_OS_TVOS
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index d7db6ba856..f254a8692d 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -56,12 +56,8 @@
// -------------------------------------------------------------------------
-@interface QIOSViewController () {
- @public
- QPointer<QT_PREPEND_NAMESPACE(QIOSScreen)> m_screen;
- BOOL m_updatingProperties;
- QMetaObject::Connection m_focusWindowChangeConnection;
-}
+@interface QIOSViewController ()
+@property (nonatomic, assign) QPointer<QT_PREPEND_NAMESPACE(QIOSScreen)> platformScreen;
@property (nonatomic, assign) BOOL changingOrientation;
@end
@@ -72,7 +68,7 @@
@implementation QIOSDesktopManagerView
-- (id)init
+- (instancetype)init
{
if (!(self = [super init]))
return nil;
@@ -125,7 +121,7 @@
{
Q_UNUSED(subview);
- QT_PREPEND_NAMESPACE(QIOSScreen) *screen = self.qtViewController->m_screen;
+ QT_PREPEND_NAMESPACE(QIOSScreen) *screen = self.qtViewController.platformScreen;
// The 'window' property of our view is not valid until the window
// has been shown, so we have to access it through the QIOSScreen.
@@ -170,7 +166,7 @@
// here. iOS will still use the latest rendered frame to create the
// application switcher thumbnail, but it will be based on the last
// active orientation of the application.
- QIOSScreen *screen = self.qtViewController->m_screen;
+ QIOSScreen *screen = self.qtViewController.platformScreen;
qCDebug(lcQpaWindow) << "ignoring layout of subviews while suspended,"
<< "likely system snapshot of" << screen->screen()->primaryOrientation();
return;
@@ -246,7 +242,10 @@
// -------------------------------------------------------------------------
-@implementation QIOSViewController
+@implementation QIOSViewController {
+ BOOL m_updatingProperties;
+ QMetaObject::Connection m_focusWindowChangeConnection;
+}
#ifndef Q_OS_TVOS
@synthesize prefersStatusBarHidden;
@@ -254,11 +253,10 @@
@synthesize preferredStatusBarStyle;
#endif
-- (id)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen
+- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen
{
if (self = [self init]) {
- m_screen = screen;
-
+ self.platformScreen = screen;
self.changingOrientation = NO;
#ifndef Q_OS_TVOS
@@ -330,7 +328,7 @@
- (BOOL)shouldAutorotate
{
#ifndef Q_OS_TVOS
- return m_screen && m_screen->uiScreen() == [UIScreen mainScreen] && !self.lockedOrientation;
+ return self.platformScreen && self.platformScreen->uiScreen() == [UIScreen mainScreen] && !self.lockedOrientation;
#else
return NO;
#endif
@@ -410,8 +408,8 @@
if (!QCoreApplication::instance())
return;
- if (m_screen)
- m_screen->updateProperties();
+ if (self.platformScreen)
+ self.platformScreen->updateProperties();
}
// -------------------------------------------------------------------------
@@ -421,12 +419,12 @@
if (!isQtApplication())
return;
- if (!m_screen || !m_screen->screen())
+ if (!self.platformScreen || !self.platformScreen->screen())
return;
// For now we only care about the main screen, as both the statusbar
// visibility and orientation is only appropriate for the main screen.
- if (m_screen->uiScreen() != [UIScreen mainScreen])
+ if (self.platformScreen->uiScreen() != [UIScreen mainScreen])
return;
// Prevent recursion caused by updating the status bar appearance (position
@@ -448,7 +446,7 @@
return;
// We only care about changes to focusWindow that involves our screen
- if (!focusWindow->screen() || focusWindow->screen()->handle() != m_screen)
+ if (!focusWindow->screen() || focusWindow->screen()->handle() != self.platformScreen)
return;
// All decisions are based on the the top level window
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 6ee258e363..cdec57de71 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -96,7 +96,7 @@ QIOSWindow::~QIOSWindow()
[m_view touchesCancelled:[NSSet set] withEvent:0];
clearAccessibleCache();
- m_view->m_qioswindow = 0;
+ m_view.platformWindow = 0;
[m_view removeFromSuperview];
[m_view release];
}
@@ -139,7 +139,7 @@ void QIOSWindow::setVisible(bool visible)
} else if (!visible && [m_view isActiveWindow]) {
// Our window was active/focus window but now hidden, so relinquish
// focus to the next possible window in the stack.
- NSArray *subviews = m_view.viewController.view.subviews;
+ NSArray<UIView *> *subviews = m_view.viewController.view.subviews;
for (int i = int(subviews.count) - 1; i >= 0; --i) {
UIView *view = [subviews objectAtIndex:i];
if (view.hidden)
@@ -301,7 +301,7 @@ void QIOSWindow::raiseOrLower(bool raise)
if (!isQtApplication())
return;
- NSArray *subviews = m_view.superview.subviews;
+ NSArray<UIView *> *subviews = m_view.superview.subviews;
if (subviews.count == 1)
return;
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.h b/src/plugins/platforms/ios/quiaccessibilityelement.h
index 03abf5407e..6b8efdcede 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.h
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.h
@@ -45,13 +45,12 @@
#ifndef QT_NO_ACCESSIBILITY
-@interface QMacAccessibilityElement : UIAccessibilityElement
-{}
+@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : UIAccessibilityElement
@property (readonly) QAccessible::Id axid;
-- (id)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
-+ (QMacAccessibilityElement *)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
+- (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
++ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
@end
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm
index a26ba61b3c..3154536aad 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.mm
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm
@@ -42,20 +42,23 @@
#ifndef QT_NO_ACCESSIBILITY
#include "private/qaccessiblecache_p.h"
+#include "private/qcore_mac_p.h"
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
@implementation QMacAccessibilityElement
-- (id)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
+- (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
{
Q_ASSERT((int)anId < 0);
- self = [super initWithAccessibilityContainer: view];
+ self = [super initWithAccessibilityContainer:view];
if (self)
_axid = anId;
return self;
}
-+ (id)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
++ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
{
Q_ASSERT(anId);
if (!anId)
@@ -63,10 +66,10 @@
QAccessibleCache *cache = QAccessibleCache::instance();
- QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *element = cache->elementForId(anId);
+ QMacAccessibilityElement *element = cache->elementForId(anId);
if (!element) {
Q_ASSERT(QAccessible::accessibleInterface(anId));
- element = [[self alloc] initWithId:anId withAccessibilityContainer: view];
+ element = [[self alloc] initWithId:anId withAccessibilityContainer:view];
cache->insertElement(anId, element);
}
return element;
diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h
index 3e3c579075..e1d5d5af0c 100644
--- a/src/plugins/platforms/ios/quiview.h
+++ b/src/plugins/platforms/ios/quiview.h
@@ -53,21 +53,10 @@ QT_END_NAMESPACE
@class QIOSViewController;
@interface QUIView : UIView
-{
- @public
- QT_PREPEND_NAMESPACE(QIOSWindow) *m_qioswindow;
- @private
- QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches;
- UITouch *m_activePencilTouch;
- int m_nextTouchId;
-
- @private
- NSMutableArray *m_accessibleElements;
-};
-
-- (id)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window;
+- (instancetype)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window;
- (void)sendUpdatedExposeEvent;
- (BOOL)isActiveWindow;
+@property (nonatomic, assign) QT_PREPEND_NAMESPACE(QIOSWindow) *platformWindow;
@end
@interface QUIView (Accessibility)
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index 29afae7176..de60bd7c36 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -55,7 +55,12 @@
Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
-@implementation QUIView
+@implementation QUIView {
+ QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches;
+ UITouch *m_activePencilTouch;
+ int m_nextTouchId;
+ NSMutableArray<UIAccessibilityElement *> *m_accessibleElements;
+}
+ (void)load
{
@@ -82,25 +87,26 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return [CAEAGLLayer class];
}
-- (id)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window
+- (instancetype)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window
{
if (self = [self initWithFrame:window->geometry().toCGRect()]) {
- m_qioswindow = window;
- m_accessibleElements = [[NSMutableArray alloc] init];
+ self.platformWindow = window;
+ m_accessibleElements = [[NSMutableArray<UIAccessibilityElement *> alloc] init];
}
return self;
}
-- (id)initWithFrame:(CGRect)frame
+- (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
// Set up EAGL layer
CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer);
eaglLayer.opaque = TRUE;
- eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
- kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
+ eaglLayer.drawableProperties = @{
+ kEAGLDrawablePropertyRetainedBacking: @(YES),
+ kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
+ };
if (isQtApplication())
self.hidden = YES;
@@ -156,7 +162,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
#ifndef QT_NO_DEBUG_STREAM
QString platformWindowDescription;
QDebug debug(&platformWindowDescription);
- debug.nospace() << "; " << m_qioswindow << ">";
+ debug.nospace() << "; " << self.platformWindow << ">";
NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1];
[description replaceCharactersInRange:lastCharacter withString:platformWindowDescription.toNSString()];
#endif
@@ -210,10 +216,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
if (!CGAffineTransformIsIdentity(self.transform))
qWarning() << self << "has a transform set. This is not supported.";
- QWindow *window = m_qioswindow->window();
+ QWindow *window = self.platformWindow->window();
QRect lastReportedGeometry = qt_window_private(window)->geometry;
QRect currentGeometry = QRectF::fromCGRect(self.frame).toRect();
- qCDebug(lcQpaWindow) << m_qioswindow << "new geometry is" << currentGeometry;
+ qCDebug(lcQpaWindow) << self.platformWindow << "new geometry is" << currentGeometry;
QWindowSystemInterface::handleGeometryChange(window, currentGeometry);
if (currentGeometry.size() != lastReportedGeometry.size()) {
@@ -237,29 +243,29 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
{
QRegion region;
- if (m_qioswindow->isExposed()) {
+ if (self.platformWindow->isExposed()) {
QSize bounds = QRectF::fromCGRect(self.layer.bounds).toRect().size();
- Q_ASSERT(m_qioswindow->geometry().size() == bounds);
- Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible());
+ Q_ASSERT(self.platformWindow->geometry().size() == bounds);
+ Q_ASSERT(self.hidden == !self.platformWindow->window()->isVisible());
region = QRect(QPoint(), bounds);
}
- qCDebug(lcQpaWindow) << m_qioswindow << region << "isExposed" << m_qioswindow->isExposed();
- QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region);
+ qCDebug(lcQpaWindow) << self.platformWindow << region << "isExposed" << self.platformWindow->isExposed();
+ QWindowSystemInterface::handleExposeEvent(self.platformWindow->window(), region);
}
- (void)safeAreaInsetsDidChange
{
- QWindowSystemInterface::handleSafeAreaMarginsChanged(m_qioswindow->window());
+ QWindowSystemInterface::handleSafeAreaMarginsChanged(self.platformWindow->window());
}
// -------------------------------------------------------------------------
- (BOOL)canBecomeFirstResponder
{
- return !(m_qioswindow->window()->flags() & Qt::WindowDoesNotAcceptFocus);
+ return !(self.platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus);
}
- (BOOL)becomeFirstResponder
@@ -280,10 +286,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
qImDebug() << self << "became first responder";
}
- if (qGuiApp->focusWindow() != m_qioswindow->window())
- QWindowSystemInterface::handleWindowActivated(m_qioswindow->window());
+ if (qGuiApp->focusWindow() != self.platformWindow->window())
+ QWindowSystemInterface::handleWindowActivated(self.platformWindow->window());
else
- qImDebug() << m_qioswindow->window() << "already active, not sending window activation";
+ qImDebug() << self.platformWindow->window() << "already active, not sending window activation";
return YES;
}
@@ -361,7 +367,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
- if (m_qioswindow->window()->flags() & Qt::WindowTransparentForInput)
+ if (self.platformWindow->window()->flags() & Qt::WindowTransparentForInput)
return NO;
return [super pointInside:point withEvent:event];
}
@@ -378,7 +384,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
for (UITouch *cTouch in cTouches) {
QPointF localViewPosition = QPointF::fromCGPoint([cTouch preciseLocationInView:self]);
QPoint localViewPositionI = localViewPosition.toPoint();
- QPointF globalScreenPosition = m_qioswindow->mapToGlobal(localViewPositionI) +
+ QPointF globalScreenPosition = self.platformWindow->mapToGlobal(localViewPositionI) +
(localViewPosition - localViewPositionI);
qreal pressure = cTouch.force / cTouch.maximumPossibleForce;
// azimuth unit vector: +x to the right, +y going downwards
@@ -391,7 +397,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
qCDebug(lcQpaTablet) << i << ":" << timeStamp << localViewPosition << pressure << state << "azimuth" << azimuth.dx << azimuth.dy
<< "angle" << azimuthAngle << "altitude" << cTouch.altitudeAngle
<< "xTilt" << qBound(-60.0, altitudeAngle * azimuth.dx, 60.0) << "yTilt" << qBound(-60.0, altitudeAngle * azimuth.dy, 60.0);
- QWindowSystemInterface::handleTabletEvent(m_qioswindow->window(), timeStamp, localViewPosition, globalScreenPosition,
+ QWindowSystemInterface::handleTabletEvent(self.platformWindow->window(), timeStamp, localViewPosition, globalScreenPosition,
// device, pointerType, buttons
QTabletEvent::RotationStylus, QTabletEvent::Pen, state == Qt::TouchPointReleased ? Qt::NoButton : Qt::LeftButton,
// pressure, xTilt, yTilt
@@ -415,12 +421,12 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
// just map from the local view position to global coordinates.
// tvOS: all touches start at the center of the screen and move from there.
QPoint localViewPosition = QPointF::fromCGPoint([uiTouch locationInView:self]).toPoint();
- QPoint globalScreenPosition = m_qioswindow->mapToGlobal(localViewPosition);
+ QPoint globalScreenPosition = self.platformWindow->mapToGlobal(localViewPosition);
touchPoint.area = QRectF(globalScreenPosition, QSize(0, 0));
// FIXME: Do we really need to support QTouchDevice::NormalizedPosition?
- QSize screenSize = m_qioswindow->screen()->geometry().size();
+ QSize screenSize = self.platformWindow->screen()->geometry().size();
touchPoint.normalPosition = QPointF(globalScreenPosition.x() / screenSize.width(),
globalScreenPosition.y() / screenSize.height());
@@ -440,7 +446,8 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
if (m_activeTouches.isEmpty())
return;
- if (!static_cast<QUIWindow *>(self.window).sendingEvent) {
+ if ([self.window isKindOfClass:[QUIWindow class]] &&
+ !static_cast<QUIWindow *>(self.window).sendingEvent) {
// The event is likely delivered as part of delayed touch delivery, via
// _UIGestureEnvironmentSortAndSendDelayedTouches, due to one of the two
// _UISystemGestureGateGestureRecognizer instances on the top level window
@@ -450,10 +457,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
// alert dialog, will fail to recognize. To be on the safe side, we deliver
// the event asynchronously.
QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>(
- m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
+ self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
} else {
QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
- m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
+ self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
}
}
@@ -481,8 +488,8 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
#endif
}
- if (m_qioswindow->shouldAutoActivateWindow() && m_activeTouches.size() == 1) {
- QPlatformWindow *topLevel = m_qioswindow;
+ if (self.platformWindow->shouldAutoActivateWindow() && m_activeTouches.size() == 1) {
+ QPlatformWindow *topLevel = self.platformWindow;
while (QPlatformWindow *p = topLevel->parent())
topLevel = p;
if (topLevel->window() != QGuiApplication::focusWindow())
@@ -552,7 +559,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime];
QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
- QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice());
+ QWindowSystemInterface::handleTouchCancelEvent(self.platformWindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice());
}
- (int)mapPressTypeToKey:(UIPress*)press
@@ -580,7 +587,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
int key = [self mapPressTypeToKey:press];
if (key == Qt::Key_unknown)
continue;
- if (QWindowSystemInterface::handleKeyEvent(m_qioswindow->window(), type, key, Qt::NoModifier))
+ if (QWindowSystemInterface::handleKeyEvent(self.platformWindow->window(), type, key, Qt::NoModifier))
handled = true;
}
@@ -634,7 +641,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (QWindow *)qwindow
{
if ([self isKindOfClass:[QUIView class]]) {
- if (QT_PREPEND_NAMESPACE(QIOSWindow) *w = static_cast<QUIView *>(self)->m_qioswindow)
+ if (QT_PREPEND_NAMESPACE(QIOSWindow) *w = static_cast<QUIView *>(self).platformWindow)
return w->window();
}
return nil;
diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm
index 69a4d375bd..a3f4156a59 100644
--- a/src/plugins/platforms/ios/quiview_accessibility.mm
+++ b/src/plugins/platforms/ios/quiview_accessibility.mm
@@ -49,8 +49,9 @@
if (!iface || iface->state().invisible || (iface->text(QAccessible::Name).isEmpty() && iface->text(QAccessible::Value).isEmpty() && iface->text(QAccessible::Description).isEmpty()))
return;
QAccessible::Id accessibleId = QAccessible::uniqueId(iface);
- UIAccessibilityElement *elem = [[QMacAccessibilityElement alloc] initWithId: accessibleId withAccessibilityContainer: self];
- [m_accessibleElements addObject:[elem autorelease]];
+ UIAccessibilityElement *elem = [[QT_MANGLE_NAMESPACE(QMacAccessibilityElement) alloc] initWithId:accessibleId withAccessibilityContainer:self];
+ [m_accessibleElements addObject:elem];
+ [elem release];
}
- (void)createAccessibleContainer:(QAccessibleInterface *)iface
@@ -73,7 +74,7 @@
if ([m_accessibleElements count])
return;
- QWindow *win = m_qioswindow->window();
+ QWindow *win = self.platformWindow->window();
QAccessibleInterface *iface = win->accessibleRoot();
if (iface)
[self createAccessibleContainer: iface];
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index 814291c54a..0dd1f40b71 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -178,6 +178,85 @@ Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
return result;
}
+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:
+ return {QEvent::MouseButtonDblClick, Qt::LeftButton};
+ case WM_MBUTTONDOWN:
+ return {QEvent::MouseButtonPress, Qt::MidButton};
+ case WM_MBUTTONUP:
+ return {QEvent::MouseButtonRelease, Qt::MidButton};
+ case WM_MBUTTONDBLCLK:
+ return {QEvent::MouseButtonDblClick, Qt::MidButton};
+ case WM_RBUTTONDOWN:
+ return {QEvent::MouseButtonPress, Qt::RightButton};
+ case WM_RBUTTONUP:
+ return {QEvent::MouseButtonRelease, Qt::RightButton};
+ case WM_RBUTTONDBLCLK:
+ return {QEvent::MouseButtonDblClick, 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::MouseButtonDblClick, 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::NonClientAreaMouseButtonDblClick, Qt::LeftButton};
+ case WM_NCMBUTTONDOWN:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
+ case WM_NCMBUTTONUP:
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton};
+ case WM_NCMBUTTONDBLCLK:
+ return {QEvent::NonClientAreaMouseButtonDblClick, Qt::MidButton};
+ case WM_NCRBUTTONDOWN:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
+ case WM_NCRBUTTONUP:
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton};
+ case WM_NCRBUTTONDBLCLK:
+ return {QEvent::NonClientAreaMouseButtonDblClick, 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)
@@ -192,8 +271,33 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
if (et == QtWindows::MouseWheelEvent)
return translateMouseWheelEvent(window, hwnd, msg, result);
+ const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ QPoint clientPosition;
+ QPoint globalPosition;
+ if (et & QtWindows::NonClientEventFlag) {
+ globalPosition = winEventPosition;
+ clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
+ } else {
+ clientPosition = winEventPosition;
+ globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
+ }
+
+ // 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 MouseEvent mouseEvent = eventFromMsg(msg);
+
// Check for events synthesized from touch. Lower byte is touch index, 0 means pen.
static const bool passSynthesizedMouseEvents =
!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch);
@@ -210,13 +314,11 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
}
}
- const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
- if (et & QtWindows::NonClientEventFlag) {
- const QPoint globalPosition = winEventPosition;
- const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
+ if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons();
QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition,
globalPosition, buttons,
+ mouseEvent.button, mouseEvent.type,
QWindowsKeyMapper::queryKeyboardModifiers(),
source);
return false; // Allow further event processing (dragging of windows).
@@ -224,7 +326,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
*result = 0;
if (msg.message == WM_MOUSELEAVE) {
- qCDebug(lcQpaEvents) << "WM_MOUSELEAVE for " << window << " previous window under mouse = " << m_windowUnderMouse << " tracked window =" << m_trackedWindow;
+ 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
@@ -269,7 +372,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
}
}
- const QPoint globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
// 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() ?
@@ -290,10 +392,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
// Qt expects the platform plugin to capture the mouse on
// any button press until release.
if (!platformWindow->hasMouseCapture()
- && (msg.message == WM_LBUTTONDOWN || msg.message == WM_MBUTTONDOWN
- || msg.message == WM_RBUTTONDOWN || msg.message == WM_XBUTTONDOWN
- || msg.message == WM_LBUTTONDBLCLK || msg.message == WM_MBUTTONDBLCLK
- || msg.message == WM_RBUTTONDBLCLK || msg.message == WM_XBUTTONDBLCLK)) {
+ && (mouseEvent.type == QEvent::MouseButtonPress || mouseEvent.type == QEvent::MouseButtonDblClick)) {
platformWindow->setMouseGrabEnabled(true);
platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
qCDebug(lcQpaEvents) << "Automatic mouse capture " << window;
@@ -302,8 +401,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
window->requestActivate();
} else if (platformWindow->hasMouseCapture()
&& platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
- && (msg.message == WM_LBUTTONUP || msg.message == WM_MBUTTONUP
- || msg.message == WM_RBUTTONUP || msg.message == WM_XBUTTONUP)
+ && mouseEvent.type == QEvent::MouseButtonRelease
&& !buttons) {
platformWindow->setMouseGrabEnabled(false);
qCDebug(lcQpaEvents) << "Releasing automatic mouse capture " << window;
@@ -369,9 +467,12 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
m_windowUnderMouse = currentWindowUnderMouse;
}
- QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons,
- QWindowsKeyMapper::queryKeyboardModifiers(),
- source);
+ if (!discardEvent && mouseEvent.type != QEvent::None) {
+ QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons,
+ mouseEvent.button, mouseEvent.type,
+ QWindowsKeyMapper::queryKeyboardModifiers(),
+ source);
+ }
m_previousCaptureWindow = hasCapture ? window : 0;
// QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND
// is sent for unhandled WM_XBUTTONDOWN.
@@ -397,9 +498,10 @@ static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int del
{
// If a window is blocked by modality, it can't get the event.
if (isValidWheelReceiver(window)) {
+ const QPoint point = (orientation == Qt::Vertical) ? QPoint(0, delta) : QPoint(delta, 0);
QWindowSystemInterface::handleWheelEvent(window,
QWindowsGeometryHint::mapFromGlobal(window, globalPos),
- globalPos, delta, orientation, mods);
+ globalPos, QPoint(), point, mods);
}
}
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
index 280519d39d..00561c9fa1 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -135,9 +135,9 @@ QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t)
d.nospace();
d << "TabletDevice id:" << t.uniqueId << " pressure: " << t.minPressure
<< ".." << t.maxPressure << " tan pressure: " << t.minTanPressure << ".."
- << t.maxTanPressure << " area:" << t.minX << t.minY <<t.minZ
- << ".." << t.maxX << t.maxY << t.maxZ << " device " << t.currentDevice
- << " pointer " << t.currentPointerType;
+ << t.maxTanPressure << " area: (" << t.minX << ',' << t.minY << ',' << t.minZ
+ << ")..(" << t.maxX << ',' << t.maxY << ',' << t.maxZ << ") device "
+ << t.currentDevice << " pointer " << t.currentPointerType;
return d;
}
@@ -211,9 +211,6 @@ bool QWindowsWinTab32DLL::init()
QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context)
: m_window(window)
, m_context(context)
- , m_absoluteRange(20)
- , m_tiltSupport(false)
- , m_currentDevice(-1)
{
AXIS orientation[3];
// Some tablets don't support tilt, check if it is possible,
@@ -230,13 +227,13 @@ QWindowsTabletSupport::~QWindowsTabletSupport()
QWindowsTabletSupport *QWindowsTabletSupport::create()
{
if (!m_winTab32DLL.init())
- return 0;
+ return nullptr;
const HWND window = QWindowsContext::instance()->createDummyWindow(QStringLiteral("TabletDummyWindow"),
L"TabletDummyWindow",
qWindowsTabletSupportWndProc);
if (!window) {
qCWarning(lcQpaTablet) << __FUNCTION__ << "Unable to create window for tablet.";
- return 0;
+ return nullptr;
}
LOGCONTEXT lcMine;
// build our context from the default context
@@ -255,7 +252,7 @@ QWindowsTabletSupport *QWindowsTabletSupport::create()
if (!context) {
qCDebug(lcQpaTablet) << __FUNCTION__ << "Unable to open tablet.";
DestroyWindow(window);
- return 0;
+ return nullptr;
}
// Set the size of the Packet Queue to the correct size
@@ -266,7 +263,7 @@ QWindowsTabletSupport *QWindowsTabletSupport::create()
qWarning("Unable to set queue size on tablet. The tablet will not work.");
QWindowsTabletSupport::m_winTab32DLL.wTClose(context);
DestroyWindow(window);
- return 0;
+ return nullptr;
} // cannot restore old size
} // cannot set
} // mismatch
@@ -285,7 +282,7 @@ unsigned QWindowsTabletSupport::options() const
QString QWindowsTabletSupport::description() const
{
- const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0);
+ const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, nullptr);
if (!size)
return QString();
QVarLengthArray<TCHAR> winTabId(size + 1);
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h
index 340818c3f7..0075216d8e 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.h
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.h
@@ -83,22 +83,23 @@ struct QWindowsWinTab32DLL
struct QWindowsTabletDeviceData
{
- QWindowsTabletDeviceData() : minPressure(0), maxPressure(0), minTanPressure(0),
- maxTanPressure(0), minX(0), maxX(0), minY(0), maxY(0), minZ(0), maxZ(0),
- uniqueId(0), currentDevice(0), currentPointerType(0) {}
-
QPointF scaleCoordinates(int coordX, int coordY,const QRect &targetArea) const;
qreal scalePressure(qreal p) const { return p / qreal(maxPressure - minPressure); }
qreal scaleTangentialPressure(qreal p) const { return p / qreal(maxTanPressure - minTanPressure); }
- int minPressure;
- int maxPressure;
- int minTanPressure;
- int maxTanPressure;
- int minX, maxX, minY, maxY, minZ, maxZ;
- qint64 uniqueId;
- int currentDevice;
- int currentPointerType;
+ int minPressure = 0;
+ int maxPressure = 0;
+ int minTanPressure = 0;
+ int maxTanPressure = 0;
+ int minX = 0;
+ int maxX = 0;
+ int minY = 0;
+ int maxY = 0;
+ int minZ = 0;
+ int maxZ = 0;
+ qint64 uniqueId = 0;
+ int currentDevice = 0;
+ int currentPointerType = 0;
};
#ifndef QT_NO_DEBUG_STREAM
@@ -145,10 +146,10 @@ private:
static QWindowsWinTab32DLL m_winTab32DLL;
const HWND m_window;
const HCTX m_context;
- int m_absoluteRange;
- bool m_tiltSupport;
+ int m_absoluteRange = 20;
+ bool m_tiltSupport = false;
QVector<QWindowsTabletDeviceData> m_devices;
- int m_currentDevice;
+ int m_currentDevice = -1;
QPointF m_oldGlobalPosF;
Mode m_mode = PenMode;
State m_state = PenUp;
diff --git a/src/plugins/platforms/winrt/qwinrtcanvas.cpp b/src/plugins/platforms/winrt/qwinrtcanvas.cpp
new file mode 100644
index 0000000000..ad77d811e6
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtcanvas.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwinrtcanvas.h"
+#include "uiautomation/qwinrtuiaaccessibility.h"
+#include "uiautomation/qwinrtuiamainprovider.h"
+#include "uiautomation/qwinrtuiametadatacache.h"
+#include "uiautomation/qwinrtuiautils.h"
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/qfunctions_winrt.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::System;
+using namespace ABI::Windows::UI;
+using namespace ABI::Windows::UI::Core;
+using namespace ABI::Windows::UI::Xaml;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+
+QT_BEGIN_NAMESPACE
+
+QWinRTCanvas::QWinRTCanvas(const std::function<QWindow*()> &delegateWindow)
+{
+ ComPtr<Xaml::Controls::ICanvasFactory> factory;
+ HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), IID_PPV_ARGS(&factory));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = factory->CreateInstance(this, &m_base, &m_core);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ delegate = delegateWindow;
+}
+
+QWinRTCanvas::~QWinRTCanvas()
+{
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTCanvas::QueryInterface(REFIID iid, LPVOID *iface)
+{
+ if (!iface)
+ return E_POINTER;
+ *iface = nullptr;
+
+ if (iid == IID_IUnknown) {
+ *iface = static_cast<Xaml::IUIElementOverrides *>(this);
+ AddRef();
+ return S_OK;
+ } else if (iid == Xaml::IID_IUIElementOverrides) {
+ *iface = static_cast<Xaml::IUIElementOverrides *>(this);
+ AddRef();
+ return S_OK;
+ } else {
+ return m_base.CopyTo(iid, iface);
+ }
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTCanvas::GetIids(ULONG *iidCount, IID **iids)
+{
+ *iidCount = 0;
+ *iids = nullptr;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTCanvas::GetRuntimeClassName(HSTRING *className)
+{
+ const wchar_t *name = L"QWinRTCanvas";
+ return ::WindowsCreateString(name, static_cast<UINT32>(::wcslen(name)), className);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTCanvas::GetTrustLevel(TrustLevel *trustLevel)
+{
+ *trustLevel = TrustLevel::BaseTrust;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTCanvas::OnCreateAutomationPeer(Xaml::Automation::Peers::IAutomationPeer **returnValue)
+{
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+
+ if (delegate) {
+ if (QWindow *window = delegate()) {
+ QWinRTUiaAccessibility::activate();
+ if (QAccessibleInterface *accessible = window->accessibleRoot()) {
+ QAccessible::Id accid = QWinRTUiAutomation::idForAccessible(accessible);
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ if (ComPtr<QWinRTUiaMainProvider> provider = QWinRTUiaMainProvider::providerForAccessibleId(accid))
+ return provider.CopyTo(returnValue);
+ }
+ }
+ }
+ return m_base->OnCreateAutomationPeer(returnValue);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTCanvas::OnDisconnectVisualChildren()
+{
+ return m_base->OnDisconnectVisualChildren();
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTCanvas::FindSubElementsForTouchTargeting(Point point, Rect boundingRect, IIterable<IIterable<ABI::Windows::Foundation::Point>*> **returnValue)
+{
+ return m_base->FindSubElementsForTouchTargeting(point, boundingRect, returnValue);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/winrt/qwinrtcanvas.h b/src/plugins/platforms/winrt/qwinrtcanvas.h
new file mode 100644
index 0000000000..68c15c7602
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtcanvas.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTCANVAS_H
+#define QWINRTCANVAS_H
+
+#include <QtCore/qglobal.h>
+#include <QtGui/QWindow>
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+class QWinRTCanvas:
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::IUIElementOverrides>
+{
+public:
+ QWinRTCanvas(const std::function<QWindow*()> &delegateWindow);
+ virtual ~QWinRTCanvas();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *iface) override;
+ HRESULT STDMETHODCALLTYPE GetIids(ULONG *iidCount, IID **iids) override;
+ HRESULT STDMETHODCALLTYPE GetRuntimeClassName(HSTRING *className) override;
+ HRESULT STDMETHODCALLTYPE GetTrustLevel(TrustLevel *trustLevel) override;
+ HRESULT STDMETHODCALLTYPE OnCreateAutomationPeer(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **returnValue) override;
+ HRESULT STDMETHODCALLTYPE OnDisconnectVisualChildren() override;
+ HRESULT STDMETHODCALLTYPE FindSubElementsForTouchTargeting(ABI::Windows::Foundation::Point point, ABI::Windows::Foundation::Rect boundingRect, ABI::Windows::Foundation::Collections::IIterable<ABI::Windows::Foundation::Collections::IIterable<ABI::Windows::Foundation::Point>*> **returnValue) override;
+
+private:
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElementOverrides> m_base;
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Controls::ICanvas> m_core;
+ std::function<QWindow*()> delegate;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINRTCANVAS_H
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
index 7a30c8d98b..eae043f3a7 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp
@@ -50,6 +50,9 @@
#ifndef QT_NO_DRAGANDDROP
#include "qwinrtdrag.h"
#endif
+#if QT_CONFIG(accessibility)
+# include "uiautomation/qwinrtuiaaccessibility.h"
+#endif
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>
@@ -119,6 +122,9 @@ public:
QPlatformClipboard *clipboard;
QWinRTScreen *mainScreen;
QScopedPointer<QWinRTInputContext> inputContext;
+#if QT_CONFIG(accessibility)
+ QWinRTUiaAccessibility *accessibility;
+#endif
ComPtr<ICoreApplication> application;
QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens;
@@ -198,6 +204,9 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate)
screenAdded(d->mainScreen);
d->platformServices = new QWinRTServices;
d->clipboard = new QWinRTClipboard;
+#if QT_CONFIG(accessibility)
+ d->accessibility = new QWinRTUiaAccessibility;
+#endif
}
QWinRTIntegration::~QWinRTIntegration()
@@ -315,6 +324,14 @@ QPlatformDrag *QWinRTIntegration::drag() const
}
#endif // QT_NO_DRAGANDDROP
+#if QT_CONFIG(accessibility)
+QPlatformAccessibility *QWinRTIntegration::accessibility() const
+{
+ Q_D(const QWinRTIntegration);
+ return d->accessibility;
+}
+#endif // QT_CONFIG(accessibility)
+
Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const
{
Q_D(const QWinRTIntegration);
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h
index e22532a266..adc7620727 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.h
+++ b/src/plugins/platforms/winrt/qwinrtintegration.h
@@ -100,6 +100,9 @@ public:
#ifndef QT_NO_DRAGANDDROP
QPlatformDrag *drag() const override;
#endif
+#if QT_CONFIG(accessibility)
+ QPlatformAccessibility *accessibility() const override;
+#endif
Qt::KeyboardModifiers queryKeyboardModifiers() const override;
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
index e37aeb0bc5..a325d6f817 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp
@@ -46,6 +46,7 @@
#include "qwinrtdrag.h"
#endif
#include "qwinrtwindow.h"
+#include "qwinrtcanvas.h"
#include <private/qeventdispatcher_winrt_p.h>
#include <private/qhighdpiscaling_p.h>
@@ -463,7 +464,7 @@ public:
QTouchDevice *touchDevice;
ComPtr<ICoreWindow> coreWindow;
ComPtr<ICorePointerRedirector> redirect;
- ComPtr<Xaml::IDependencyObject> canvas;
+ ComPtr<QWinRTCanvas> canvas;
ComPtr<IApplicationView> view;
ComPtr<IDisplayInformation> displayInformation;
@@ -553,27 +554,25 @@ QWinRTScreen::QWinRTScreen()
hr = applicationViewStatics->GetForCurrentView(&d->view);
RETURN_VOID_IF_FAILED("Could not access currentView");
- // Create a canvas and set it as the window content. Eventually, this should have its own method so multiple "screens" can be added
- ComPtr<Xaml::Controls::ICanvas> canvas;
- hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), &canvas);
- Q_ASSERT_SUCCEEDED(hr);
+ d->canvas = Make<QWinRTCanvas>([this]() { return topWindow(); });
+
ComPtr<Xaml::IFrameworkElement> frameworkElement;
- hr = canvas.As(&frameworkElement);
+ hr = d->canvas.As(&frameworkElement);
Q_ASSERT_SUCCEEDED(hr);
hr = frameworkElement->put_Width(d->logicalRect.width());
Q_ASSERT_SUCCEEDED(hr);
hr = frameworkElement->put_Height(d->logicalRect.height());
Q_ASSERT_SUCCEEDED(hr);
+
ComPtr<Xaml::IUIElement> uiElement;
- hr = canvas.As(&uiElement);
+ hr = d->canvas.As(&uiElement);
Q_ASSERT_SUCCEEDED(hr);
+
#ifndef QT_NO_DRAGANDDROP
QWinRTDrag::instance()->setUiElement(uiElement);
#endif
hr = window->put_Content(uiElement.Get());
Q_ASSERT_SUCCEEDED(hr);
- hr = canvas.As(&d->canvas);
- Q_ASSERT_SUCCEEDED(hr);
d->cursor.reset(new QWinRTCursor);
@@ -723,7 +722,10 @@ ICoreWindow *QWinRTScreen::coreWindow() const
Xaml::IDependencyObject *QWinRTScreen::canvas() const
{
Q_D(const QWinRTScreen);
- return d->canvas.Get();
+ Xaml::IDependencyObject *depCanvas;
+ if (SUCCEEDED(d->canvas.CopyTo(&depCanvas)))
+ return depCanvas;
+ return nullptr;
}
void QWinRTScreen::initialize()
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp
new file mode 100644
index 0000000000..878fcd0f96
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiaaccessibility.h"
+#include "qwinrtuiamainprovider.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QWindow>
+#include <QtGui/QGuiApplication>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtCore/qt_windows.h>
+#include <qpa/qplatformintegration.h>
+
+QT_BEGIN_NAMESPACE
+
+QWinRTUiaAccessibility::QWinRTUiaAccessibility()
+{
+}
+
+QWinRTUiaAccessibility::~QWinRTUiaAccessibility()
+{
+}
+
+// Handles UI Automation window messages.
+void QWinRTUiaAccessibility::activate()
+{
+ // Start handling accessibility internally
+ QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true);
+}
+
+// Handles accessibility update notifications.
+void QWinRTUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
+{
+ if (!event)
+ return;
+
+ QAccessibleInterface *accessible = event->accessibleInterface();
+ if (!isActive() || !accessible || !accessible->isValid())
+ return;
+
+ switch (event->type()) {
+ case QAccessible::Focus:
+ QWinRTUiaMainProvider::notifyFocusChange(event);
+ break;
+ case QAccessible::StateChanged:
+ QWinRTUiaMainProvider::notifyStateChange(static_cast<QAccessibleStateChangeEvent *>(event));
+ break;
+ case QAccessible::ValueChanged:
+ QWinRTUiaMainProvider::notifyValueChange(static_cast<QAccessibleValueChangeEvent *>(event));
+ break;
+ case QAccessible::TextAttributeChanged:
+ case QAccessible::TextColumnChanged:
+ case QAccessible::TextInserted:
+ case QAccessible::TextRemoved:
+ case QAccessible::TextUpdated:
+ case QAccessible::TextSelectionChanged:
+ case QAccessible::TextCaretMoved:
+ QWinRTUiaMainProvider::notifyTextChange(event);
+ break;
+ default:
+ break;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h
new file mode 100644
index 0000000000..b966271e21
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAACCESSIBILITY_H
+#define QWINRTUIAACCESSIBILITY_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include <qpa/qplatformaccessibility.h>
+
+QT_BEGIN_NAMESPACE
+
+// WinRT platform accessibility implemented over UI Automation.
+class QWinRTUiaAccessibility : public QPlatformAccessibility
+{
+public:
+ explicit QWinRTUiaAccessibility();
+ virtual ~QWinRTUiaAccessibility();
+ static void activate();
+ void notifyAccessibilityUpdate(QAccessibleEvent *event) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAACCESSIBILITY_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp
new file mode 100644
index 0000000000..ee53714caa
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+
+QWinRTUiaBaseProvider::QWinRTUiaBaseProvider(QAccessible::Id id) :
+ m_id(id)
+{
+}
+
+QWinRTUiaBaseProvider::~QWinRTUiaBaseProvider()
+{
+}
+
+QAccessibleInterface *QWinRTUiaBaseProvider::accessibleInterface() const
+{
+ QAccessibleInterface *accessible = QAccessible::accessibleInterface(m_id);
+ if (accessible && accessible->isValid())
+ return accessible;
+ return nullptr;
+}
+
+QAccessible::Id QWinRTUiaBaseProvider::id() const
+{
+ return m_id;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h
new file mode 100644
index 0000000000..d8837354dc
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIABASEPROVIDER_H
+#define QWINRTUIABASEPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+// Base class for UI Automation providers.
+class QWinRTUiaBaseProvider : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaBaseProvider)
+public:
+ explicit QWinRTUiaBaseProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaBaseProvider();
+
+ QAccessibleInterface *accessibleInterface() const;
+ QAccessible::Id id() const;
+
+private:
+ QAccessible::Id m_id;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIABASEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp
new file mode 100644
index 0000000000..4e406a3545
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiacontrolmetadata.h"
+#include "qwinrtuiautils.h"
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+
+QWinRTUiaControlMetadata::QWinRTUiaControlMetadata()
+{
+}
+
+QWinRTUiaControlMetadata::QWinRTUiaControlMetadata(QAccessible::Id id)
+{
+ update(id);
+}
+
+void QWinRTUiaControlMetadata::update(QAccessible::Id id)
+{
+ if (QAccessibleInterface *accessible = accessibleForId(id)) {
+ m_automationId = generateAutomationId(accessible);
+ m_className = generateClassName(accessible);
+ m_controlName = generateControlName(accessible);
+ m_role = generateRole(accessible);
+ m_state = accessible->state();
+ m_accelerator = accessible->text(QAccessible::Accelerator);
+ m_access = accessible->text(QAccessible::Accelerator);
+ m_help = accessible->text(QAccessible::Help);
+ m_description = accessible->text(QAccessible::Description);
+ m_value = accessible->text(QAccessible::Value);
+ m_boundingRect = accessible->rect();
+ updateValueData(accessible);
+ updateTableData(accessible);
+ updateTextData(accessible);
+ }
+}
+
+QString QWinRTUiaControlMetadata::generateControlName(QAccessibleInterface *accessible)
+{
+ const bool clientTopLevel = (accessible->role() == QAccessible::Client)
+ && accessible->parent() && (accessible->parent()->role() == QAccessible::Application);
+
+ QString name = accessible->text(QAccessible::Name);
+ if (name.isEmpty() && clientTopLevel)
+ name = QCoreApplication::applicationName();
+ return name;
+}
+
+QString QWinRTUiaControlMetadata::generateClassName(QAccessibleInterface *accessible)
+{
+ QString name;
+
+ if (QObject *obj = accessible->object())
+ name = QLatin1String(obj->metaObject()->className());
+ return name;
+}
+
+// Generates an ID based on the name of the controls and their parents.
+QString QWinRTUiaControlMetadata::generateAutomationId(QAccessibleInterface *accessible)
+{
+ QString autid;
+ QObject *obj = accessible->object();
+ while (obj) {
+ QString name = obj->objectName();
+ if (name.isEmpty()) {
+ autid = QStringLiteral("");
+ break;
+ }
+ if (!autid.isEmpty())
+ autid.prepend(QLatin1Char('.'));
+ autid.prepend(name);
+ obj = obj->parent();
+ }
+ return autid;
+}
+
+QAccessible::Role QWinRTUiaControlMetadata::generateRole(QAccessibleInterface *accessible)
+{
+ const bool clientTopLevel = (accessible->role() == QAccessible::Client)
+ && accessible->parent() && (accessible->parent()->role() == QAccessible::Application);
+
+ if (clientTopLevel) {
+ // Reports a top-level widget as a window.
+ return QAccessible::Window;
+ } else {
+ return accessible->role();
+ }
+}
+
+void QWinRTUiaControlMetadata::updateValueData(QAccessibleInterface *accessible)
+{
+ if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
+ m_minimumValue = valueInterface->minimumValue().toDouble();
+ m_maximumValue = valueInterface->maximumValue().toDouble();
+ m_currentValue = valueInterface->currentValue().toDouble();
+ m_minimumStepSize = valueInterface->minimumStepSize().toDouble();
+ } else {
+ m_minimumValue = 0.0;
+ m_maximumValue = 0.0;
+ m_currentValue = 0.0;
+ m_minimumStepSize = 0.0;
+ }
+}
+
+void QWinRTUiaControlMetadata::updateTableData(QAccessibleInterface *accessible)
+{
+ if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
+ m_rowIndex = 0;
+ m_columnIndex = 0;
+ m_rowCount = tableInterface->rowCount();
+ m_columnCount = tableInterface->columnCount();
+ } else if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
+ m_rowIndex = tableCellInterface->rowIndex();
+ m_columnIndex = tableCellInterface->columnIndex();
+ m_rowCount = tableCellInterface->rowExtent();
+ m_columnCount = tableCellInterface->columnExtent();
+ } else {
+ m_rowIndex = 0;
+ m_columnIndex = 0;
+ m_rowCount = 0;
+ m_columnCount = 0;
+ }
+}
+
+void QWinRTUiaControlMetadata::updateTextData(QAccessibleInterface *accessible)
+{
+ if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
+ m_cursorPosition = textInterface->cursorPosition();
+ m_text = textInterface->text(0, textInterface->characterCount());
+ } else {
+ m_cursorPosition = 0;
+ m_text = QStringLiteral("");
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h
new file mode 100644
index 0000000000..769f073a1b
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIACONTROLMETADATA_H
+#define QWINRTUIACONTROLMETADATA_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include <QString>
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+
+QT_BEGIN_NAMESPACE
+
+// Cacheable control metadata
+class QWinRTUiaControlMetadata
+{
+public:
+ QWinRTUiaControlMetadata();
+ QWinRTUiaControlMetadata(QAccessible::Id id);
+ void update(QAccessible::Id id);
+ QString automationId() const { return m_automationId; }
+ QString className() const { return m_className; }
+ QString controlName() const { return m_controlName; }
+ QString accelerator() const { return m_accelerator; }
+ QString access() const { return m_access; }
+ QString help() const { return m_help; }
+ QString description() const { return m_description; }
+ QString value() const { return m_value; }
+ QString text() const { return m_text; }
+ QAccessible::Role role() const { return m_role; }
+ QAccessible::State state() const { return m_state; }
+ QRect boundingRect() const { return m_boundingRect; }
+ double minimumValue() const { return m_minimumValue; }
+ double maximumValue() const { return m_maximumValue; }
+ double currentValue() const { return m_currentValue; }
+ double minimumStepSize() const { return m_minimumStepSize; }
+ int rowIndex() const { return m_rowIndex; }
+ int columnIndex() const { return m_columnIndex; }
+ int rowCount() const { return m_rowCount; }
+ int columnCount() const { return m_columnCount; }
+ int characterCount() const { return m_text.length(); }
+ int cursorPosition() const { return m_cursorPosition; }
+
+private:
+ QString generateControlName(QAccessibleInterface *accessible);
+ QString generateClassName(QAccessibleInterface *accessible);
+ QString generateAutomationId(QAccessibleInterface *accessible);
+ QAccessible::Role generateRole(QAccessibleInterface *accessible);
+ void updateValueData(QAccessibleInterface *accessible);
+ void updateTableData(QAccessibleInterface *accessible);
+ void updateTextData(QAccessibleInterface *accessible);
+ QString m_automationId;
+ QString m_className;
+ QString m_controlName;
+ QString m_accelerator;
+ QString m_access;
+ QString m_help;
+ QString m_description;
+ QString m_value;
+ QString m_text;
+ QAccessible::Role m_role = QAccessible::NoRole;
+ QAccessible::State m_state;
+ QRect m_boundingRect;
+ double m_minimumValue = 0.0;
+ double m_maximumValue = 0.0;
+ double m_currentValue = 0.0;
+ double m_minimumStepSize = 0.0;
+ int m_rowIndex = 0;
+ int m_columnIndex = 0;
+ int m_rowCount = 0;
+ int m_columnCount = 0;
+ int m_cursorPosition = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIACONTROLMETADATA_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h
new file mode 100644
index 0000000000..35e4df75fc
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAEMPTYPROPERTYVALUE_H
+#define QWINRTUIAEMPTYPROPERTYVALUE_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements an empty property value.
+class QWinRTUiaEmptyPropertyValue :
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::Foundation::IPropertyValue>
+{
+ InspectableClass(L"QWinRTUiaEmptyPropertyValue", BaseTrust);
+public:
+
+ HRESULT STDMETHODCALLTYPE get_Type(ABI::Windows::Foundation::PropertyType *value)
+ {
+ *value = ABI::Windows::Foundation::PropertyType_Empty;
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE get_IsNumericScalar(boolean*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetUInt8(BYTE*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetInt16(INT16*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetUInt16(UINT16*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetInt32(INT32*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetUInt32(UINT32*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetInt64(INT64*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetUInt64(UINT64*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetSingle(FLOAT*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetDouble(DOUBLE*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetChar16(WCHAR*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetBoolean(boolean*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetString(HSTRING*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetGuid(GUID*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetDateTime(ABI::Windows::Foundation::DateTime*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetTimeSpan(ABI::Windows::Foundation::TimeSpan*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetPoint(ABI::Windows::Foundation::Point*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetSize(ABI::Windows::Foundation::Size*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetRect(ABI::Windows::Foundation::Rect*) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetUInt8Array(UINT32*, BYTE**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetInt16Array(UINT32*, INT16**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetUInt16Array(UINT32*, UINT16**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetInt32Array(UINT32*, INT32**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetUInt32Array(UINT32*, UINT32**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetInt64Array(UINT32*, INT64**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetUInt64Array(UINT32*, UINT64**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetSingleArray(UINT32*, FLOAT**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetDoubleArray(UINT32*, DOUBLE**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetChar16Array(UINT32*, WCHAR**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetBooleanArray(UINT32*, boolean**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetStringArray(UINT32*, HSTRING**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetInspectableArray(UINT32*, IInspectable***) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetGuidArray(UINT32*, GUID**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetDateTimeArray(UINT32*, ABI::Windows::Foundation::DateTime**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetTimeSpanArray(UINT32*, ABI::Windows::Foundation::TimeSpan**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetPointArray(UINT32*, ABI::Windows::Foundation::Point**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetSizeArray(UINT32*, ABI::Windows::Foundation::Size**) { return E_FAIL; }
+ HRESULT STDMETHODCALLTYPE GetRectArray(UINT32*, ABI::Windows::Foundation::Rect**) { return E_FAIL; }
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAEMPTYPROPERTYVALUE_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp
new file mode 100644
index 0000000000..524000b618
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiagriditemprovider.h"
+#include "qwinrtuiamainprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+using namespace ABI::Windows::UI::Xaml::Automation::Peers;
+
+QWinRTUiaGridItemProvider::QWinRTUiaGridItemProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaGridItemProvider::~QWinRTUiaGridItemProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+// Returns the column index of the item.
+HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_Column(INT32 *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->columnIndex();
+ return S_OK;
+}
+
+// Returns the number of columns occupied by the item.
+HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_ColumnSpan(INT32 *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->columnCount();
+ return S_OK;
+}
+
+// Returns the provider for the containing table/tree.
+HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_ContainingGrid(IIRawElementProviderSimple **value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+ *value = nullptr;
+
+ auto accid = id();
+ auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
+ auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
+ if (QAccessibleInterface *table = tableCellInterface->table()) {
+ **ptrElementId = idForAccessible(table);
+ QWinRTUiaMetadataCache::instance()->load(**ptrElementId);
+ }
+ }
+ }
+ delete ptrElementId;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ if (!*elementId)
+ return S_OK;
+
+ return QWinRTUiaMainProvider::rawProviderForAccessibleId(*elementId, value);
+}
+
+// Returns the row index of the item.
+HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_Row(INT32 *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->rowIndex();
+ return S_OK;
+}
+
+// Returns the number of rows occupied by the item.
+HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_RowSpan(INT32 *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->rowCount();
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h
new file mode 100644
index 0000000000..70504fc555
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAGRIDITEMPROVIDER_H
+#define QWINRTUIAGRIDITEMPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Grid Item control pattern provider. Used by items within a table/tree.
+class QWinRTUiaGridItemProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IGridItemProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaGridItemProvider)
+ InspectableClass(L"QWinRTUiaGridItemProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaGridItemProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaGridItemProvider();
+
+ // IGridItemProvider
+ HRESULT STDMETHODCALLTYPE get_Column(INT32 *value) override;
+ HRESULT STDMETHODCALLTYPE get_ColumnSpan(INT32 *value) override;
+ HRESULT STDMETHODCALLTYPE get_ContainingGrid(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **value) override;
+ HRESULT STDMETHODCALLTYPE get_Row(INT32 *value) override;
+ HRESULT STDMETHODCALLTYPE get_RowSpan(INT32 *value) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAGRIDITEMPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp
new file mode 100644
index 0000000000..e469991de2
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiagridprovider.h"
+#include "qwinrtuiamainprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+using namespace ABI::Windows::UI::Xaml::Automation::Peers;
+
+QWinRTUiaGridProvider::QWinRTUiaGridProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaGridProvider::~QWinRTUiaGridProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+// Returns the number of columns.
+HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::get_ColumnCount(INT32 *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->columnCount();
+ return S_OK;
+}
+
+// Returns the number of rows.
+HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::get_RowCount(INT32 *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->rowCount();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::GetItem(INT32 row, INT32 column, IIRawElementProviderSimple **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+
+ auto accid = id();
+ auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
+ auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, row, column, ptrElementId]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
+ if ((row >= 0) && (row < tableInterface->rowCount()) && (column >= 0) && (column < tableInterface->columnCount())) {
+ if (QAccessibleInterface *cell = tableInterface->cellAt(row, column)) {
+ **ptrElementId = idForAccessible(cell);
+ QWinRTUiaMetadataCache::instance()->load(**ptrElementId);
+ }
+ }
+ }
+ }
+ delete ptrElementId;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ if (!*elementId)
+ return E_FAIL;
+
+ return QWinRTUiaMainProvider::rawProviderForAccessibleId(*elementId, returnValue);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h
new file mode 100644
index 0000000000..d6dfaed315
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAGRIDPROVIDER_H
+#define QWINRTUIAGRIDPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Grid control pattern provider. Used by tables/trees.
+class QWinRTUiaGridProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IGridProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaGridProvider)
+ InspectableClass(L"QWinRTUiaGridProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaGridProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaGridProvider();
+
+ // IGridProvider
+ HRESULT STDMETHODCALLTYPE get_ColumnCount(INT32 *value) override;
+ HRESULT STDMETHODCALLTYPE get_RowCount(INT32 *value) override;
+ HRESULT STDMETHODCALLTYPE GetItem(INT32 row, INT32 column, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAGRIDPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp
new file mode 100644
index 0000000000..e2cf7bc107
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiainvokeprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+
+QWinRTUiaInvokeProvider::QWinRTUiaInvokeProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaInvokeProvider::~QWinRTUiaInvokeProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaInvokeProvider::Invoke()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+
+ QEventDispatcherWinRT::runOnMainThread([accid]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid))
+ if (QAccessibleActionInterface *actionInterface = accessible->actionInterface())
+ actionInterface->doAction(QAccessibleActionInterface::pressAction());
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ return S_OK;
+ }, 0);
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h
new file mode 100644
index 0000000000..dfe7917a16
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAINVOKEPROVIDER_H
+#define QWINRTUIAINVOKEPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Invoke control pattern provider.
+class QWinRTUiaInvokeProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IInvokeProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaInvokeProvider)
+ InspectableClass(L"QWinRTUiaInvokeProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaInvokeProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaInvokeProvider();
+
+ // IInvokeProvider
+ HRESULT STDMETHODCALLTYPE Invoke() override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAINVOKEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp
new file mode 100644
index 0000000000..99efe27c34
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp
@@ -0,0 +1,779 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiamainprovider.h"
+#include "qwinrtuiaprovidercache.h"
+#include "qwinrtuiavalueprovider.h"
+#include "qwinrtuiarangevalueprovider.h"
+#include "qwinrtuiatextprovider.h"
+#include "qwinrtuiatoggleprovider.h"
+#include "qwinrtuiainvokeprovider.h"
+#include "qwinrtuiaselectionprovider.h"
+#include "qwinrtuiaselectionitemprovider.h"
+#include "qwinrtuiatableprovider.h"
+#include "qwinrtuiatableitemprovider.h"
+#include "qwinrtuiagridprovider.h"
+#include "qwinrtuiagriditemprovider.h"
+#include "qwinrtuiapeervector.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiaemptypropertyvalue.h"
+#include "qwinrtuiautils.h"
+
+#include <QCoreApplication>
+#include <QSemaphore>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/qfunctions_winrt.h>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+using namespace QWinRTUiAutomation;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::System;
+using namespace ABI::Windows::UI;
+using namespace ABI::Windows::UI::Core;
+using namespace ABI::Windows::UI::Xaml;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+using namespace ABI::Windows::UI::Xaml::Automation::Peers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+
+QT_BEGIN_NAMESPACE
+
+QWinRTUiaMainProvider::QWinRTUiaMainProvider(QAccessible::Id id)
+ : QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ ComPtr<IAutomationPeerFactory> factory;
+ HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Automation_Peers_AutomationPeer).Get(), IID_PPV_ARGS(&factory));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = factory->CreateInstance(this, &m_base, &m_core);
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+QWinRTUiaMainProvider::~QWinRTUiaMainProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!iface)
+ return E_POINTER;
+ *iface = nullptr;
+
+ if (iid == IID_IUnknown) {
+ *iface = static_cast<IAutomationPeerOverrides *>(this);
+ AddRef();
+ return S_OK;
+ } else if (iid == IID_IAutomationPeerOverrides) {
+ *iface = static_cast<IAutomationPeerOverrides *>(this);
+ AddRef();
+ return S_OK;
+ } else {
+ return m_base.CopyTo(iid, iface);
+ }
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetIids(ULONG *iidCount, IID **iids)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ *iidCount = 0;
+ *iids = nullptr;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetRuntimeClassName(HSTRING *className)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ return qHString(QStringLiteral("QWinRTUiaMainProvider"), className);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetTrustLevel(TrustLevel *trustLevel)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ *trustLevel = TrustLevel::BaseTrust;
+ return S_OK;
+}
+
+// Returns a cached instance of the provider for a specific accessible interface.
+QWinRTUiaMainProvider *QWinRTUiaMainProvider::providerForAccessibleId(QAccessible::Id id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ QWinRTUiaProviderCache *providerCache = QWinRTUiaProviderCache::instance();
+ QWinRTUiaMainProvider *provider = qobject_cast<QWinRTUiaMainProvider *>(providerCache->providerForId(id));
+
+ if (provider) {
+ provider->AddRef();
+ } else {
+ ComPtr<QWinRTUiaMainProvider> p = Make<QWinRTUiaMainProvider>(id);
+ provider = p.Get();
+ provider->AddRef();
+ providerCache->insert(id, provider);
+ }
+ return provider;
+}
+
+// Returns an IIRawElementProviderSimple for a specific accessible interface.
+HRESULT QWinRTUiaMainProvider::rawProviderForAccessibleId(QAccessible::Id elementId,
+ IIRawElementProviderSimple **returnValue)
+{
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+
+ if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(elementId)) {
+ ComPtr<IAutomationPeer> automationPeer;
+ if (SUCCEEDED(provider.As(&automationPeer))) {
+ ComPtr<IAutomationPeerProtected> automationPeerProtected;
+ if (SUCCEEDED(provider.As(&automationPeerProtected))) {
+ return automationPeerProtected->ProviderFromPeer(automationPeer.Get(), returnValue);
+ }
+ }
+ }
+ return E_FAIL;
+}
+
+// Returns an array of IIRawElementProviderSimple instances for a list of accessible interface ids.
+HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QList<QAccessible::Id> &elementIds,
+ UINT32 *returnValueSize,
+ IIRawElementProviderSimple ***returnValue)
+{
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+ *returnValueSize = 0;
+ *returnValue = nullptr;
+
+ QList<IIRawElementProviderSimple *> rawProviderList;
+
+ for (auto elementId : qAsConst(elementIds)) {
+ IIRawElementProviderSimple *rawProvider;
+ if (SUCCEEDED(rawProviderForAccessibleId(elementId, &rawProvider)))
+ rawProviderList.append(rawProvider);
+ }
+
+ if (rawProviderList.size() == 0)
+ return S_OK;
+
+ *returnValue = static_cast<IIRawElementProviderSimple **>(CoTaskMemAlloc(rawProviderList.size() * sizeof(IIRawElementProviderSimple *)));
+ if (!*returnValue) {
+ for (auto rawProvider : qAsConst(rawProviderList))
+ rawProvider->Release();
+ return E_OUTOFMEMORY;
+ }
+
+ int index = 0;
+ for (auto rawProvider : qAsConst(rawProviderList))
+ (*returnValue)[index++] = rawProvider;
+ *returnValueSize = rawProviderList.size();
+ return S_OK;
+}
+
+void QWinRTUiaMainProvider::notifyFocusChange(QAccessibleEvent *event)
+{
+ if (QAccessibleInterface *accessible = event->accessibleInterface()) {
+ QAccessible::Id accid = idForAccessible(accessible);
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ QEventDispatcherWinRT::runOnXamlThread([accid]() {
+ if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
+ ComPtr<IAutomationPeer> automationPeer;
+ if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
+ automationPeer->RaiseAutomationEvent(AutomationEvents_AutomationFocusChanged);
+ }
+ }
+ return S_OK;
+ }, false);
+ }
+}
+
+void QWinRTUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *event)
+{
+ if (QAccessibleInterface *accessible = event->accessibleInterface()) {
+ QAccessible::Id accid = idForAccessible(accessible);
+ QWinRTUiaMetadataCache::instance()->load(accid);
+
+ if (event->changedStates().checked || event->changedStates().checkStateMixed) {
+ // Notifies states changes in checkboxes.
+ if (accessible->role() == QAccessible::CheckBox) {
+ QEventDispatcherWinRT::runOnXamlThread([accid]() {
+ if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
+ ComPtr<IAutomationPeer> automationPeer;
+ if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
+ ComPtr<ITogglePatternIdentifiersStatics> toggleStatics;
+ if (SUCCEEDED(RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Automation_TogglePatternIdentifiers).Get(), IID_PPV_ARGS(&toggleStatics)))) {
+ ComPtr<IAutomationProperty> toggleStateProperty;
+ if (SUCCEEDED(toggleStatics->get_ToggleStateProperty(&toggleStateProperty))) {
+ ComPtr<QWinRTUiaEmptyPropertyValue> emptyValue = Make<QWinRTUiaEmptyPropertyValue>();
+ // by sending an event with an empty value we force ui automation to refresh its state
+ automationPeer->RaisePropertyChangedEvent(toggleStateProperty.Get(), emptyValue.Get(), emptyValue.Get());
+ }
+ }
+ }
+ }
+ return S_OK;
+ }, false);
+ }
+ }
+ if (event->changedStates().active) {
+ if (accessible->role() == QAccessible::Window) {
+ // Notifies window opened/closed.
+ bool active = accessible->state().active;
+ QEventDispatcherWinRT::runOnXamlThread([accid, active]() {
+ if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
+ ComPtr<IAutomationPeer> automationPeer;
+ if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
+ if (active) {
+ automationPeer->RaiseAutomationEvent(AutomationEvents_WindowOpened);
+ } else {
+ automationPeer->RaiseAutomationEvent(AutomationEvents_WindowClosed);
+ }
+ }
+ }
+ return S_OK;
+ }, false);
+ }
+ }
+ }
+}
+
+void QWinRTUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event)
+{
+ if (QAccessibleInterface *accessible = event->accessibleInterface()) {
+ QAccessible::Id accid = idForAccessible(accessible);
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
+ // Notifies changes in values of controls supporting the value interface.
+ double value = valueInterface->currentValue().toDouble();
+ QEventDispatcherWinRT::runOnXamlThread([accid, value]() {
+ // For some reason RaisePropertyChangedEvent() does not seem to be
+ // forwarding notifications for any property types except empty,
+ // which would do nothing here. ToDo: find a workaround.
+ return S_OK;
+ }, false);
+ }
+ }
+}
+
+// Notifies changes in text content and selection state of text controls.
+void QWinRTUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
+{
+ if (QAccessibleInterface *accessible = event->accessibleInterface()) {
+ QAccessible::Id accid = idForAccessible(accessible);
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ bool readOnly = accessible->state().readOnly;
+ QAccessible::Event eventType = event->type();
+ if (accessible->textInterface()) {
+ QEventDispatcherWinRT::runOnXamlThread([accid, eventType, readOnly]() {
+ if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
+ ComPtr<IAutomationPeer> automationPeer;
+ if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
+ if (eventType == QAccessible::TextSelectionChanged) {
+ automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextSelectionChanged);
+ } else if (eventType == QAccessible::TextCaretMoved) {
+ if (!readOnly) {
+ automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextSelectionChanged);
+ }
+ } else {
+ automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextChanged);
+ }
+ }
+ }
+ return S_OK;
+ }, false);
+ }
+ }
+}
+
+// Return providers for specific control patterns
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPatternCore(PatternInterface patternInterface, IInspectable **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__ << patternInterface;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return E_FAIL;
+
+ switch (patternInterface) {
+ case PatternInterface_Text:
+ case PatternInterface_Text2: {
+ // All text controls.
+ if (accessible->textInterface()) {
+ ComPtr<QWinRTUiaTextProvider> provider = Make<QWinRTUiaTextProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ case PatternInterface_Value: {
+ // All accessible controls return text(QAccessible::Value) (which may be empty).
+ ComPtr<QWinRTUiaValueProvider> provider = Make<QWinRTUiaValueProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ case PatternInterface_RangeValue: {
+ // Controls providing a numeric value within a range (e.g., sliders, scroll bars, dials).
+ if (accessible->valueInterface()) {
+ ComPtr<QWinRTUiaRangeValueProvider> provider = Make<QWinRTUiaRangeValueProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ case PatternInterface_Toggle: {
+ // Checkbox controls.
+ if (accessible->role() == QAccessible::CheckBox) {
+ ComPtr<QWinRTUiaToggleProvider> provider = Make<QWinRTUiaToggleProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ case PatternInterface_Selection: {
+ // Lists of items.
+ if (accessible->role() == QAccessible::List) {
+ ComPtr<QWinRTUiaSelectionProvider> provider = Make<QWinRTUiaSelectionProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ case PatternInterface_SelectionItem: {
+ // Items within a list and radio buttons.
+ if ((accessible->role() == QAccessible::RadioButton)
+ || (accessible->role() == QAccessible::ListItem)) {
+ ComPtr<QWinRTUiaSelectionItemProvider> provider = Make<QWinRTUiaSelectionItemProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ case PatternInterface_Table: {
+ // Table/tree.
+ if (accessible->tableInterface()
+ && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) {
+ ComPtr<QWinRTUiaTableProvider> provider = Make<QWinRTUiaTableProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ case PatternInterface_TableItem: {
+ // Item within a table/tree.
+ if (accessible->tableCellInterface()
+ && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) {
+ ComPtr<QWinRTUiaTableItemProvider> provider = Make<QWinRTUiaTableItemProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ case PatternInterface_Grid: {
+ // Table/tree.
+ if (accessible->tableInterface()
+ && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) {
+ ComPtr<QWinRTUiaGridProvider> provider = Make<QWinRTUiaGridProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ case PatternInterface_GridItem: {
+ // Item within a table/tree.
+ if (accessible->tableCellInterface()
+ && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) {
+ ComPtr<QWinRTUiaGridItemProvider> provider = Make<QWinRTUiaGridItemProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ case PatternInterface_Invoke: {
+ // Things that have an invokable action (e.g., simple buttons).
+ if (accessible->actionInterface()) {
+ ComPtr<QWinRTUiaInvokeProvider> provider = Make<QWinRTUiaInvokeProvider>(id());
+ return provider.CopyTo(returnValue);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAcceleratorKeyCore(HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ return qHString(metadata->accelerator(), returnValue);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAccessKeyCore(HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ return qHString(metadata->access(), returnValue);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAutomationControlTypeCore(AutomationControlType *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *returnValue = roleToControlType(metadata->role());
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAutomationIdCore(HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ return qHString(metadata->automationId(), returnValue);
+}
+
+// Returns the bounding rectangle for the accessible control.
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetBoundingRectangleCore(ABI::Windows::Foundation::Rect *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+
+ QRect rect = metadata->boundingRect();
+ returnValue->X = rect.x();
+ returnValue->Y = rect.y();
+ returnValue->Width = rect.width();
+ returnValue->Height = rect.height();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<AutomationPeer *> **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+
+ auto accid = id();
+ auto children = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrChildren = new QSharedPointer<QList<QAccessible::Id>>(children);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrChildren]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ int childCount = accessible->childCount();
+ for (int i = 0; i < childCount; ++i) {
+ if (QAccessibleInterface *childAcc = accessible->child(i)) {
+ QAccessible::Id childId = idForAccessible(childAcc);
+ QWinRTUiaMetadataCache::instance()->load(childId);
+ (*ptrChildren)->append(childId);
+ }
+ }
+ }
+ delete ptrChildren;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ ComPtr<IVector<AutomationPeer *>> peerVector = Make<QWinRTUiaPeerVector>();
+
+ for (auto childId : qAsConst(*children)) {
+ if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(childId)) {
+ IAutomationPeer *peer;
+ if (SUCCEEDED(provider.CopyTo(&peer)))
+ peerVector->Append(peer);
+ }
+ }
+ return peerVector.CopyTo(returnValue);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetClassNameCore(HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ return qHString(metadata->className(), returnValue);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetClickablePointCore(ABI::Windows::Foundation::Point *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetHelpTextCore(HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ return qHString(metadata->help(), returnValue);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetItemStatusCore(HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetItemTypeCore(HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLabeledByCore(IAutomationPeer **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLocalizedControlTypeCore(HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetNameCore(HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ return qHString(metadata->controlName(), returnValue);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetOrientationCore(AutomationOrientation *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = AutomationOrientation_None;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::HasKeyboardFocusCore(boolean *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *returnValue = (metadata->state().focused != 0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsContentElementCore(boolean *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = true;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsControlElementCore(boolean *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = true;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsEnabledCore(boolean *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *returnValue = (metadata->state().disabled == 0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsKeyboardFocusableCore(boolean *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *returnValue = (metadata->state().focusable != 0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsOffscreenCore(boolean *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = false;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsPasswordCore(boolean *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *returnValue = (metadata->role() == QAccessible::EditableText) && (metadata->state().passwordEdit != 0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsRequiredForFormCore(boolean *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = false;
+ return S_OK;
+}
+
+// Sets focus to the control.
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::SetFocusCore()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return E_FAIL;
+
+ QAccessibleActionInterface *actionInterface = accessible->actionInterface();
+ if (!actionInterface)
+ return E_FAIL;
+
+ QEventDispatcherWinRT::runOnMainThread([actionInterface]() {
+ actionInterface->doAction(QAccessibleActionInterface::setFocusAction());
+ return S_OK;
+ });
+ return S_OK;
+}
+
+// Returns a provider for the UI element present at the specified screen coordinates.
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPeerFromPointCore(ABI::Windows::Foundation::Point point, IAutomationPeer **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+
+ // Scale coordinates from High DPI screens?
+
+ auto accid = id();
+ auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
+ auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId, point]() {
+ // Controls can be embedded within grouping elements. By default returns the innermost control.
+ QAccessibleInterface *target = accessibleForId(accid);
+ while (QAccessibleInterface *tmpacc = target->childAt(point.X, point.Y)) {
+ target = tmpacc;
+ // For accessibility tools it may be better to return the text element instead of its subcomponents.
+ if (target->textInterface()) break;
+ }
+ **ptrElementId = idForAccessible(target);
+ QWinRTUiaMetadataCache::instance()->load(**ptrElementId);
+ delete ptrElementId;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(*elementId))
+ return provider.CopyTo(returnValue);
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLiveSettingCore(AutomationLiveSetting *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ return E_NOTIMPL;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h
new file mode 100644
index 0000000000..3ae9d2759e
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAMAINPROVIDER_H
+#define QWINRTUIAMAINPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QPointer>
+#include <QtCore/QSharedPointer>
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// The main WinRT UI Automation class.
+class QWinRTUiaMainProvider:
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaMainProvider)
+
+public:
+ explicit QWinRTUiaMainProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaMainProvider();
+ static QWinRTUiaMainProvider *providerForAccessibleId(QAccessible::Id id);
+ static HRESULT rawProviderForAccessibleId(QAccessible::Id elementId, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue);
+ static HRESULT rawProviderArrayForAccessibleIdList(const QList<QAccessible::Id> &elementIds, UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue);
+ static void notifyFocusChange(QAccessibleEvent *event);
+ static void notifyStateChange(QAccessibleStateChangeEvent *event);
+ static void notifyValueChange(QAccessibleValueChangeEvent *event);
+ static void notifyTextChange(QAccessibleEvent *event);
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
+
+ // IInspectable
+ HRESULT STDMETHODCALLTYPE GetIids(ULONG *iidCount, IID **iids) override;
+ HRESULT STDMETHODCALLTYPE GetRuntimeClassName(HSTRING *className) override;
+ HRESULT STDMETHODCALLTYPE GetTrustLevel(TrustLevel *trustLevel) override;
+
+ // IAutomationPeerOverrides
+ HRESULT STDMETHODCALLTYPE GetPatternCore(ABI::Windows::UI::Xaml::Automation::Peers::PatternInterface patternInterface, IInspectable **returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetAcceleratorKeyCore(HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetAccessKeyCore(HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetAutomationControlTypeCore(ABI::Windows::UI::Xaml::Automation::Peers::AutomationControlType *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetAutomationIdCore(HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetBoundingRectangleCore(ABI::Windows::Foundation::Rect *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetChildrenCore(ABI::Windows::Foundation::Collections::IVector<ABI::Windows::UI::Xaml::Automation::Peers::AutomationPeer*> **returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetClassNameCore(HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetClickablePointCore(ABI::Windows::Foundation::Point *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetHelpTextCore(HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetItemStatusCore(HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetItemTypeCore(HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetLabeledByCore(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetLocalizedControlTypeCore(HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetNameCore(HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetOrientationCore(ABI::Windows::UI::Xaml::Automation::Peers::AutomationOrientation *returnValue) override;
+ HRESULT STDMETHODCALLTYPE HasKeyboardFocusCore(boolean *returnValue) override;
+ HRESULT STDMETHODCALLTYPE IsContentElementCore(boolean *returnValue) override;
+ HRESULT STDMETHODCALLTYPE IsControlElementCore(boolean *returnValue) override;
+ HRESULT STDMETHODCALLTYPE IsEnabledCore(boolean *returnValue) override;
+ HRESULT STDMETHODCALLTYPE IsKeyboardFocusableCore(boolean *returnValue) override;
+ HRESULT STDMETHODCALLTYPE IsOffscreenCore(boolean *returnValue) override;
+ HRESULT STDMETHODCALLTYPE IsPasswordCore(boolean *returnValue) override;
+ HRESULT STDMETHODCALLTYPE IsRequiredForFormCore(boolean *returnValue) override;
+ HRESULT STDMETHODCALLTYPE SetFocusCore() override;
+ HRESULT STDMETHODCALLTYPE GetPeerFromPointCore(ABI::Windows::Foundation::Point point, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetLiveSettingCore(ABI::Windows::UI::Xaml::Automation::Peers::AutomationLiveSetting *returnValue) override;
+
+private:
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides> m_base;
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer> m_core;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAMAINPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp
new file mode 100644
index 0000000000..442ff184a8
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+
+// Private constructor
+QWinRTUiaMetadataCache::QWinRTUiaMetadataCache()
+{
+}
+
+// shared instance
+QWinRTUiaMetadataCache *QWinRTUiaMetadataCache::instance()
+{
+ static QWinRTUiaMetadataCache metadataCache;
+ return &metadataCache;
+}
+
+// Returns the cached metadata associated with the ID, or an instance with default values.
+QSharedPointer<QWinRTUiaControlMetadata> QWinRTUiaMetadataCache::metadataForId(QAccessible::Id id)
+{
+ QSharedPointer<QWinRTUiaControlMetadata> metadata;
+
+ m_mutex.lock();
+ if (m_metadataTable.contains(id))
+ metadata = m_metadataTable[id];
+ else
+ metadata = QSharedPointer<QWinRTUiaControlMetadata>(new QWinRTUiaControlMetadata);
+ m_mutex.unlock();
+ return metadata;
+}
+
+// Caches metadata from the accessibility framework within the main thread.
+bool QWinRTUiaMetadataCache::load(QAccessible::Id id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([id]() {
+ QWinRTUiaMetadataCache::instance()->insert(id, QSharedPointer<QWinRTUiaControlMetadata>(new QWinRTUiaControlMetadata(id)));
+ return S_OK;
+ }))) {
+ return false;
+ }
+ return true;
+}
+
+// Inserts metadata in the cache and associates it with an accessibility ID.
+void QWinRTUiaMetadataCache::insert(QAccessible::Id id, const QSharedPointer<QWinRTUiaControlMetadata> &metadata)
+{
+ m_mutex.lock();
+ m_metadataTable[id] = metadata;
+ m_mutex.unlock();
+}
+
+// Removes metadata with a given id from the cache.
+void QWinRTUiaMetadataCache::remove(QAccessible::Id id)
+{
+ m_mutex.lock();
+ m_metadataTable.remove(id);
+ m_mutex.unlock();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h
new file mode 100644
index 0000000000..2d68d1b654
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAMETADATACACHE_H
+#define QWINRTUIAMETADATACACHE_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiacontrolmetadata.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QMutex>
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+
+QT_BEGIN_NAMESPACE
+
+// Singleton used to cache metadata using the accessibility ID as the key.
+class QWinRTUiaMetadataCache : public QObject
+{
+ QWinRTUiaMetadataCache();
+ Q_OBJECT
+public:
+ static QWinRTUiaMetadataCache *instance();
+ QSharedPointer<QWinRTUiaControlMetadata> metadataForId(QAccessible::Id id);
+ void insert(QAccessible::Id id, const QSharedPointer<QWinRTUiaControlMetadata> &metadata);
+ void remove(QAccessible::Id id);
+ bool load(QAccessible::Id id);
+
+private:
+ QHash<QAccessible::Id, QSharedPointer<QWinRTUiaControlMetadata>> m_metadataTable;
+ QMutex m_mutex;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAMETADATACACHE_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp
new file mode 100644
index 0000000000..e3d6bcae4b
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiapeervector.h"
+#include "qwinrtuiautils.h"
+
+using namespace ABI::Windows::UI::Xaml::Automation::Peers;
+using namespace ABI::Windows::Foundation::Collections;
+
+QT_BEGIN_NAMESPACE
+
+HRESULT QWinRTUiaPeerVector::GetAt(quint32 index, IAutomationPeer **item)
+{
+ if (index >= quint32(m_impl.size()))
+ return E_FAIL;
+ if ((*item = m_impl.at(index)))
+ (*item)->AddRef();
+ return S_OK;
+}
+
+HRESULT QWinRTUiaPeerVector::get_Size(quint32 *size)
+{
+ *size = m_impl.size();
+ return S_OK;
+}
+
+HRESULT QWinRTUiaPeerVector::GetView(IVectorView<AutomationPeer *> **view)
+{
+ *view = nullptr;
+ return E_NOTIMPL;
+}
+
+HRESULT QWinRTUiaPeerVector::IndexOf(IAutomationPeer *value, quint32 *index, boolean *found)
+{
+ int idx = m_impl.indexOf(value);
+ if (idx > -1) {
+ *index = quint32(idx);
+ *found = true;
+ } else {
+ *found = false;
+ }
+ return S_OK;
+}
+
+HRESULT QWinRTUiaPeerVector::SetAt(quint32 index, IAutomationPeer *item)
+{
+ if (index >= quint32(m_impl.size()))
+ return E_FAIL;
+ if (IAutomationPeer *elem = m_impl.at(index)) {
+ if (elem == item)
+ return S_OK;
+ else
+ elem->Release();
+ }
+ if (item)
+ item->AddRef();
+ m_impl[index] = item;
+ return S_OK;
+}
+
+HRESULT QWinRTUiaPeerVector::InsertAt(quint32 index, IAutomationPeer *item)
+{
+ if (index >= quint32(m_impl.size()))
+ return E_FAIL;
+ if (item)
+ item->AddRef();
+ m_impl.insert(index, item);
+ return S_OK;
+}
+
+HRESULT QWinRTUiaPeerVector::RemoveAt(quint32 index)
+{
+ if (index >= quint32(m_impl.size()))
+ return E_FAIL;
+ if (IAutomationPeer *elem = m_impl.at(index))
+ elem->Release();
+ m_impl.remove(index);
+ return S_OK;
+}
+
+HRESULT QWinRTUiaPeerVector::Append(IAutomationPeer *item)
+{
+ if (item)
+ item->AddRef();
+ m_impl.append(item);
+ return S_OK;
+}
+
+HRESULT QWinRTUiaPeerVector::RemoveAtEnd()
+{
+ if (m_impl.size() == 0)
+ return E_FAIL;
+ if (IAutomationPeer *elem = m_impl.last())
+ elem->Release();
+ m_impl.removeLast();
+ return S_OK;
+}
+
+HRESULT QWinRTUiaPeerVector::Clear()
+{
+ for (auto elem : qAsConst(m_impl))
+ if (elem)
+ elem->Release();
+ m_impl.clear();
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h
new file mode 100644
index 0000000000..265526de09
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAPEERVECTOR_H
+#define QWINRTUIAPEERVECTOR_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include <QtCore/QString>
+#include <QtCore/qt_windows.h>
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtGui/QWindow>
+#include <QVector>
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements IVector<AutomationPeer *>
+class QWinRTUiaPeerVector : public Microsoft::WRL::RuntimeClass<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::UI::Xaml::Automation::Peers::AutomationPeer *>>
+{
+public:
+ HRESULT STDMETHODCALLTYPE GetAt(quint32 index, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **item) override;
+ HRESULT STDMETHODCALLTYPE get_Size(quint32 *size) override;
+ HRESULT STDMETHODCALLTYPE GetView(ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::UI::Xaml::Automation::Peers::AutomationPeer *> **view) override;
+ HRESULT STDMETHODCALLTYPE IndexOf(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *value, quint32 *index, boolean *found) override;
+ HRESULT STDMETHODCALLTYPE SetAt(quint32 index, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *item) override;
+ HRESULT STDMETHODCALLTYPE InsertAt(quint32 index, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *item) override;
+ HRESULT STDMETHODCALLTYPE RemoveAt(quint32 index) override;
+ HRESULT STDMETHODCALLTYPE Append(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *item) override;
+ HRESULT STDMETHODCALLTYPE RemoveAtEnd() override;
+ HRESULT STDMETHODCALLTYPE Clear() override;
+private:
+ QVector<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *> m_impl;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAPEERVECTOR_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp
new file mode 100644
index 0000000000..06ff094c45
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiaprovidercache.h"
+
+QT_BEGIN_NAMESPACE
+
+// Private constructor
+QWinRTUiaProviderCache::QWinRTUiaProviderCache()
+{
+}
+
+// shared instance
+QWinRTUiaProviderCache *QWinRTUiaProviderCache::instance()
+{
+ static QWinRTUiaProviderCache providerCache;
+ return &providerCache;
+}
+
+// Returns the provider instance associated with the ID, or nullptr.
+QWinRTUiaBaseProvider *QWinRTUiaProviderCache::providerForId(QAccessible::Id id) const
+{
+ return m_providerTable.value(id);
+}
+
+// Inserts a provider in the cache and associates it with an accessibility ID.
+void QWinRTUiaProviderCache::insert(QAccessible::Id id, QWinRTUiaBaseProvider *provider)
+{
+ remove(id);
+ if (provider) {
+ m_providerTable[id] = provider;
+ m_inverseTable[provider] = id;
+ // Connects the destroyed signal to our slot, to remove deleted objects from the cache.
+ QObject::connect(provider, &QObject::destroyed, this, &QWinRTUiaProviderCache::objectDestroyed);
+ }
+}
+
+// Removes deleted provider objects from the cache.
+void QWinRTUiaProviderCache::objectDestroyed(QObject *obj)
+{
+ // We have to use the inverse table to map the object address back to its ID,
+ // since at this point (called from QObject destructor), it has already been
+ // partially destroyed and we cannot treat it as a provider.
+ auto it = m_inverseTable.find(obj);
+ if (it != m_inverseTable.end()) {
+ m_providerTable.remove(*it);
+ m_inverseTable.remove(obj);
+ }
+}
+
+// Removes a provider with a given id from the cache.
+void QWinRTUiaProviderCache::remove(QAccessible::Id id)
+{
+ m_inverseTable.remove(m_providerTable.value(id));
+ m_providerTable.remove(id);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h
new file mode 100644
index 0000000000..393ef7d562
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAPROVIDERCACHE_H
+#define QWINRTUIAPROVIDERCACHE_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <QtCore/QHash>
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+
+QT_BEGIN_NAMESPACE
+
+// Singleton used to cache provider instances using the accessibility ID as the key.
+class QWinRTUiaProviderCache : public QObject
+{
+ QWinRTUiaProviderCache();
+ Q_OBJECT
+public:
+ static QWinRTUiaProviderCache *instance();
+ QWinRTUiaBaseProvider *providerForId(QAccessible::Id id) const;
+ void insert(QAccessible::Id id, QWinRTUiaBaseProvider *provider);
+ void remove(QAccessible::Id id);
+
+private Q_SLOTS:
+ void objectDestroyed(QObject *obj);
+
+private:
+ QHash<QAccessible::Id, QWinRTUiaBaseProvider *> m_providerTable;
+ QHash<QObject *, QAccessible::Id> m_inverseTable;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAPROVIDERCACHE_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp
new file mode 100644
index 0000000000..4ac59c890a
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiarangevalueprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+
+QWinRTUiaRangeValueProvider::QWinRTUiaRangeValueProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaRangeValueProvider::~QWinRTUiaRangeValueProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_IsReadOnly(boolean *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = (metadata->state().readOnly != 0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_LargeChange(DOUBLE *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->minimumStepSize();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_Maximum(DOUBLE *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->maximumValue();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_Minimum(DOUBLE *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->minimumValue();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_SmallChange(DOUBLE *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->minimumStepSize();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_Value(DOUBLE *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = metadata->currentValue();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::SetValue(DOUBLE value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+
+ QEventDispatcherWinRT::runOnMainThread([accid, value]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
+ double minimum = valueInterface->minimumValue().toDouble();
+ double maximum = valueInterface->maximumValue().toDouble();
+ if ((value >= minimum) && (value <= maximum)) {
+ valueInterface->setCurrentValue(QVariant(value));
+ }
+ }
+ }
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ return S_OK;
+ }, 0);
+
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h
new file mode 100644
index 0000000000..4e98959526
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIARANGEVALUEPROVIDER_H
+#define QWINRTUIARANGEVALUEPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Range Value control pattern provider.
+class QWinRTUiaRangeValueProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IRangeValueProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaRangeValueProvider)
+ InspectableClass(L"QWinRTUiaRangeValueProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaRangeValueProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaRangeValueProvider();
+
+ // IRangeValueProvider
+ HRESULT STDMETHODCALLTYPE get_IsReadOnly(boolean *value) override;
+ HRESULT STDMETHODCALLTYPE get_LargeChange(DOUBLE *value) override;
+ HRESULT STDMETHODCALLTYPE get_Maximum(DOUBLE *value) override;
+ HRESULT STDMETHODCALLTYPE get_Minimum(DOUBLE *value) override;
+ HRESULT STDMETHODCALLTYPE get_SmallChange(DOUBLE *value) override;
+ HRESULT STDMETHODCALLTYPE get_Value(DOUBLE *value) override;
+ HRESULT STDMETHODCALLTYPE SetValue(DOUBLE value) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIARANGEVALUEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp
new file mode 100644
index 0000000000..9bc88272ba
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiaselectionitemprovider.h"
+#include "qwinrtuiamainprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+using namespace ABI::Windows::UI::Xaml::Automation::Peers;
+
+QWinRTUiaSelectionItemProvider::QWinRTUiaSelectionItemProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaSelectionItemProvider::~QWinRTUiaSelectionItemProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+// Returns true if element is currently selected.
+HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::get_IsSelected(boolean *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ if (metadata->role() == QAccessible::RadioButton)
+ *value = metadata->state().checked;
+ else
+ *value = metadata->state().selected;
+ return S_OK;
+}
+
+// Returns the provider for the container element (e.g., the list for the list item).
+HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::get_SelectionContainer(IIRawElementProviderSimple **value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+ *value = nullptr;
+
+ auto accid = id();
+ auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
+ auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ // Radio buttons do not require a container.
+ if (accessible->role() == QAccessible::ListItem) {
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ if (parent->role() == QAccessible::List) {
+ **ptrElementId = idForAccessible(parent);
+ }
+ }
+ }
+ }
+ delete ptrElementId;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ if (!*elementId)
+ return S_OK;
+
+ return QWinRTUiaMainProvider::rawProviderForAccessibleId(*elementId, value);
+}
+
+// Adds the element to the list of selected elements.
+HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::AddToSelection()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+
+ QEventDispatcherWinRT::runOnMainThread([accid]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) {
+ if (accessible->role() == QAccessible::RadioButton) {
+ // For radio buttons we invoke the selection action.
+ actionInterface->doAction(QAccessibleActionInterface::pressAction());
+ } else {
+ // Toggle list item if not already selected.
+ if (!accessible->state().selected) {
+ actionInterface->doAction(QAccessibleActionInterface::toggleAction());
+ }
+ }
+ }
+ }
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ return S_OK;
+ }, 0);
+ return S_OK;
+}
+
+// Removes a list item from selection.
+HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::RemoveFromSelection()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+
+ QEventDispatcherWinRT::runOnMainThread([accid]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) {
+ if (accessible->role() != QAccessible::RadioButton) {
+ if (accessible->state().selected) {
+ actionInterface->doAction(QAccessibleActionInterface::toggleAction());
+ }
+ }
+ }
+ }
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ return S_OK;
+ }, 0);
+ return S_OK;
+}
+
+// Selects the element (deselecting all others).
+HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::Select()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+
+ QEventDispatcherWinRT::runOnMainThread([accid]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) {
+ if (accessible->role() == QAccessible::RadioButton) {
+ // For radio buttons we just invoke the selection action; others are automatically deselected.
+ actionInterface->doAction(QAccessibleActionInterface::pressAction());
+ } else {
+ // Toggle list item if not already selected. It must be done first to support all selection modes.
+ if (!accessible->state().selected) {
+ actionInterface->doAction(QAccessibleActionInterface::toggleAction());
+ }
+ // Toggle selected siblings.
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ for (int i = 0; i < parent->childCount(); ++i) {
+ if (QAccessibleInterface *sibling = parent->child(i)) {
+ if ((sibling != accessible) && (sibling->state().selected)) {
+ if (QAccessibleActionInterface *siblingAction = sibling->actionInterface()) {
+ siblingAction->doAction(QAccessibleActionInterface::toggleAction());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ return S_OK;
+ }, 0);
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h
new file mode 100644
index 0000000000..1b3cce7495
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIASELECTIONITEMPROVIDER_H
+#define QWINRTUIASELECTIONITEMPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Selection Item control pattern provider. Used for List items and radio buttons.
+class QWinRTUiaSelectionItemProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ISelectionItemProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaSelectionItemProvider)
+ InspectableClass(L"QWinRTUiaSelectionItemProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaSelectionItemProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaSelectionItemProvider();
+
+ // ISelectionItemProvider
+ HRESULT STDMETHODCALLTYPE get_IsSelected(boolean *value) override;
+ HRESULT STDMETHODCALLTYPE get_SelectionContainer(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **value) override;
+ HRESULT STDMETHODCALLTYPE AddToSelection() override;
+ HRESULT STDMETHODCALLTYPE RemoveFromSelection() override;
+ HRESULT STDMETHODCALLTYPE Select() override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIASELECTIONITEMPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp
new file mode 100644
index 0000000000..9e61a8df61
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiaselectionprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiamainprovider.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+using namespace ABI::Windows::UI::Xaml::Automation::Peers;
+
+QWinRTUiaSelectionProvider::QWinRTUiaSelectionProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaSelectionProvider::~QWinRTUiaSelectionProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_CanSelectMultiple(boolean *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = (metadata->state().multiSelectable != 0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_IsSelectionRequired(boolean *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+ *value = false;
+
+ auto accid = id();
+ auto selectionRequired = QSharedPointer<bool>(new bool(false));
+ auto ptrSelectionRequired = new QSharedPointer<bool>(selectionRequired);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelectionRequired]() {
+ // Initially returns false if none are selected. After the first selection, it may be required.
+ bool anySelected = false;
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ int childCount = accessible->childCount();
+ for (int i = 0; i < childCount; ++i) {
+ if (QAccessibleInterface *childAcc = accessible->child(i)) {
+ if (childAcc->state().selected) {
+ anySelected = true;
+ break;
+ }
+ }
+ }
+ **ptrSelectionRequired = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable;
+ }
+ delete ptrSelectionRequired;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ *value = *selectionRequired;
+ return S_OK;
+}
+
+// Returns an array of providers with the selected items.
+HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::GetSelection(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+ *returnValueSize = 0;
+ *returnValue = nullptr;
+
+ auto accid = id();
+ auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ int childCount = accessible->childCount();
+ for (int i = 0; i < childCount; ++i) {
+ if (QAccessibleInterface *childAcc = accessible->child(i)) {
+ if (childAcc->state().selected) {
+ QAccessible::Id childId = idForAccessible(childAcc);
+ QWinRTUiaMetadataCache::instance()->load(childId);
+ (*ptrElementIds)->append(childId);
+ }
+ }
+ }
+ }
+ delete ptrElementIds;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h
new file mode 100644
index 0000000000..dcd286800f
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIASELECTIONPROVIDER_H
+#define QWINRTUIASELECTIONPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Selection control pattern provider. Used for Lists.
+class QWinRTUiaSelectionProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ISelectionProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaSelectionProvider)
+ InspectableClass(L"QWinRTUiaSelectionProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaSelectionProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaSelectionProvider();
+
+ // ISelectionProvider
+ HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(boolean *value) override;
+ HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(boolean *value) override;
+ HRESULT STDMETHODCALLTYPE GetSelection(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIASELECTIONPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp
new file mode 100644
index 0000000000..1af74a8b72
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiatableitemprovider.h"
+#include "qwinrtuiamainprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+
+QWinRTUiaTableItemProvider::QWinRTUiaTableItemProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaTableItemProvider::~QWinRTUiaTableItemProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+// Returns the providers for the column headers associated with the item.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetColumnHeaderItems(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+ *returnValueSize = 0;
+ *returnValue = nullptr;
+
+ auto accid = id();
+ auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
+ QList<QAccessibleInterface *> headers = tableCellInterface->columnHeaderCells();
+ for (auto header : qAsConst(headers)) {
+ QAccessible::Id headerId = idForAccessible(header);
+ QWinRTUiaMetadataCache::instance()->load(headerId);
+ (*ptrElementIds)->append(headerId);
+ }
+ }
+ }
+ delete ptrElementIds;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
+}
+
+// Returns the providers for the row headers associated with the item.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetRowHeaderItems(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+ *returnValueSize = 0;
+ *returnValue = nullptr;
+
+ auto accid = id();
+ auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
+ QList<QAccessibleInterface *> headers = tableCellInterface->rowHeaderCells();
+ for (auto header : qAsConst(headers)) {
+ QAccessible::Id headerId = idForAccessible(header);
+ QWinRTUiaMetadataCache::instance()->load(headerId);
+ (*ptrElementIds)->append(headerId);
+ }
+ }
+ }
+ delete ptrElementIds;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h
new file mode 100644
index 0000000000..cb759864ae
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIATABLEITEMPROVIDER_H
+#define QWINRTUIATABLEITEMPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Table Item control pattern provider. Used by items within a table/tree.
+class QWinRTUiaTableItemProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITableItemProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaTableItemProvider)
+ InspectableClass(L"QWinRTUiaTableItemProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaTableItemProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaTableItemProvider();
+
+ // ITableItemProvider
+ HRESULT STDMETHODCALLTYPE GetColumnHeaderItems(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetRowHeaderItems(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIATABLEITEMPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp
new file mode 100644
index 0000000000..e71ade3c1f
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiatableprovider.h"
+#include "qwinrtuiamainprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+using namespace ABI::Windows::UI::Xaml::Automation::Peers;
+
+QWinRTUiaTableProvider::QWinRTUiaTableProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaTableProvider::~QWinRTUiaTableProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+// Returns the primary direction of traversal for the table.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::get_RowOrColumnMajor(RowOrColumnMajor *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+ *value = RowOrColumnMajor_Indeterminate;
+ return S_OK;
+}
+
+// Gets the providers for all the column headers in the table.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetColumnHeaders(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+ *returnValueSize = 0;
+ *returnValue = nullptr;
+
+ auto accid = id();
+ auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
+ for (int i = 0; i < tableInterface->columnCount(); ++i) {
+ if (QAccessibleInterface *cell = tableInterface->cellAt(0, i)) {
+ QWinRTUiaMetadataCache::instance()->load(idForAccessible(cell));
+ if (QAccessibleTableCellInterface *tableCellInterface = cell->tableCellInterface()) {
+ QList<QAccessibleInterface *> headers = tableCellInterface->columnHeaderCells();
+ for (auto header : qAsConst(headers)) {
+ QAccessible::Id headerId = idForAccessible(header);
+ QWinRTUiaMetadataCache::instance()->load(headerId);
+ (*ptrElementIds)->append(headerId);
+ }
+ }
+ }
+ }
+ }
+ }
+ delete ptrElementIds;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
+}
+
+// Gets the providers for all the row headers in the table.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetRowHeaders(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+ *returnValueSize = 0;
+ *returnValue = nullptr;
+
+ auto accid = id();
+ auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
+ for (int i = 0; i < tableInterface->rowCount(); ++i) {
+ if (QAccessibleInterface *cell = tableInterface->cellAt(i, 0)) {
+ QWinRTUiaMetadataCache::instance()->load(idForAccessible(cell));
+ if (QAccessibleTableCellInterface *tableCellInterface = cell->tableCellInterface()) {
+ QList<QAccessibleInterface *> headers = tableCellInterface->rowHeaderCells();
+ for (auto header : qAsConst(headers)) {
+ QAccessible::Id headerId = idForAccessible(header);
+ QWinRTUiaMetadataCache::instance()->load(headerId);
+ (*ptrElementIds)->append(headerId);
+ }
+ }
+ }
+ }
+ }
+ }
+ delete ptrElementIds;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h
new file mode 100644
index 0000000000..0cd174e401
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIATABLEPROVIDER_H
+#define QWINRTUIATABLEPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Table control pattern provider. Used by tables/trees.
+class QWinRTUiaTableProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITableProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaTableProvider)
+ InspectableClass(L"QWinRTUiaTableProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaTableProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaTableProvider();
+
+ // ITableProvider
+ HRESULT STDMETHODCALLTYPE get_RowOrColumnMajor(ABI::Windows::UI::Xaml::Automation::RowOrColumnMajor *value) override;
+ HRESULT STDMETHODCALLTYPE GetColumnHeaders(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetRowHeaders(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIATABLEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp
new file mode 100644
index 0000000000..aa120377df
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiatextprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiatextrangeprovider.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+
+QWinRTUiaTextProvider::QWinRTUiaTextProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaTextProvider::~QWinRTUiaTextProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+// Returns a text range provider for the entire text.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::get_DocumentRange(ITextRangeProvider **value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), 0, metadata->characterCount());
+ return textRangeProvider.CopyTo(value);
+}
+
+// Currently supporting single selection.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::get_SupportedTextSelection(SupportedTextSelection *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!value)
+ return E_INVALIDARG;
+ *value = SupportedTextSelection_Single;
+ return S_OK;
+
+}
+
+// Returns an array of providers for the selected text ranges.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetSelection(UINT32 *returnValueSize, ITextRangeProvider ***returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+ *returnValueSize = 0;
+ *returnValue = nullptr;
+
+ auto accid = id();
+ auto selections = QSharedPointer<QList<QPair<int,int>>>(new QList<QPair<int,int>>);
+ auto ptrSelections = new QSharedPointer<QList<QPair<int,int>>>(selections);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelections]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
+ for (int i = 0; i < textInterface->selectionCount(); ++i) {
+ QPair<int,int> sel;
+ textInterface->selection(i, &sel.first, &sel.second);
+ (*ptrSelections)->append(sel);
+ }
+ if ((*ptrSelections)->size() == 0) {
+ // If there is no selection, we return an array with a single degenerate (empty) text range at the cursor position.
+ QPair<int,int> sel(textInterface->cursorPosition(), textInterface->cursorPosition());
+ (*ptrSelections)->append(sel);
+ }
+ }
+ }
+ delete ptrSelections;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ int selCount = selections->size();
+ if (selCount < 1)
+ return E_FAIL;
+
+ ITextRangeProvider **providerArray = static_cast<ITextRangeProvider **>(CoTaskMemAlloc(selCount * sizeof(ITextRangeProvider *)));
+ if (!providerArray)
+ return E_OUTOFMEMORY;
+
+ for (int i = 0; i < selCount; ++i) {
+ ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), (*selections)[i].first, (*selections)[i].second);
+ textRangeProvider.CopyTo(&providerArray[i]);
+ }
+ *returnValueSize = selCount;
+ *returnValue = providerArray;
+ return S_OK;
+}
+
+// Returns an array of providers for the visible text ranges.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetVisibleRanges(UINT32 *returnValueSize, ITextRangeProvider ***returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+
+ // Considering the entire text as visible.
+ ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), 0, metadata->characterCount());
+ textRangeProvider.CopyTo(*returnValue);
+ *returnValueSize = 1;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromChild(IIRawElementProviderSimple *childElement, ITextRangeProvider **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!childElement || !returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+ // No children supported.
+ return S_OK;
+}
+
+// Returns a degenerate text range at the specified point.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromPoint(ABI::Windows::Foundation::Point screenLocation, ITextRangeProvider **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+
+ const QPoint pt(screenLocation.X, screenLocation.Y);
+ auto accid = id();
+ auto offset = QSharedPointer<int>(new int);
+ auto ptrOffset = new QSharedPointer<int>(offset);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, pt, ptrOffset]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid))
+ if (QAccessibleTextInterface *textInterface = accessible->textInterface())
+ **ptrOffset = qBound(0, textInterface->offsetAtPoint(pt), textInterface->characterCount() - 1);
+ delete ptrOffset;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), *offset, *offset);
+ textRangeProvider.CopyTo(returnValue);
+ return S_OK;
+}
+
+// Not supporting annotations.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromAnnotation(IIRawElementProviderSimple *annotationElement, ITextRangeProvider **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!annotationElement || !returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetCaretRange(boolean *isActive, ITextRangeProvider **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!isActive || !returnValue)
+ return E_INVALIDARG;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *isActive = metadata->state().focused;
+
+ ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), metadata->cursorPosition(), metadata->cursorPosition());
+ return textRangeProvider.CopyTo(returnValue);
+}
+
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h
new file mode 100644
index 0000000000..80d88e4115
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIATEXTPROVIDER_H
+#define QWINRTUIATEXTPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Text control pattern provider. Used for text controls.
+class QWinRTUiaTextProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITextProvider, ABI::Windows::UI::Xaml::Automation::Provider::ITextProvider2>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaTextProvider)
+ InspectableClass(L"QWinRTUiaTextProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaTextProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaTextProvider();
+
+ // ITextProvider
+ HRESULT STDMETHODCALLTYPE get_DocumentRange(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **value) override;
+ HRESULT STDMETHODCALLTYPE get_SupportedTextSelection(ABI::Windows::UI::Xaml::Automation::SupportedTextSelection *value) override;
+ HRESULT STDMETHODCALLTYPE GetSelection(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider ***returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetVisibleRanges(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider ***returnValue) override;
+ HRESULT STDMETHODCALLTYPE RangeFromChild(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple *childElement, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
+ HRESULT STDMETHODCALLTYPE RangeFromPoint(ABI::Windows::Foundation::Point screenLocation, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
+
+ // ITextProvider2
+ HRESULT STDMETHODCALLTYPE RangeFromAnnotation(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple *annotationElement, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetCaretRange(boolean *isActive, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIATEXTPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp
new file mode 100644
index 0000000000..fc3778d652
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiatextrangeprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiamainprovider.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::UI::Xaml;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+using namespace ABI::Windows::UI::Xaml::Automation::Text;
+
+QWinRTUiaTextRangeProvider::QWinRTUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset) :
+ QWinRTUiaBaseProvider(id),
+ m_startOffset(startOffset),
+ m_endOffset(endOffset)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__ << startOffset << endOffset;
+}
+
+QWinRTUiaTextRangeProvider::~QWinRTUiaTextRangeProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Clone(ITextRangeProvider **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!returnValue)
+ return E_INVALIDARG;
+
+ ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), m_startOffset, m_endOffset);
+ textRangeProvider.CopyTo(returnValue);
+ return S_OK;
+}
+
+// Two ranges are considered equal if their start/end points are the same.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Compare(ITextRangeProvider *textRangeProvider, boolean *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!textRangeProvider || !returnValue)
+ return E_INVALIDARG;
+
+ QWinRTUiaTextRangeProvider *targetProvider = static_cast<QWinRTUiaTextRangeProvider *>(textRangeProvider);
+ *returnValue = ((targetProvider->m_startOffset == m_startOffset) && (targetProvider->m_endOffset == m_endOffset));
+ return S_OK;
+}
+
+// Compare different endpoinds between two providers.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::CompareEndpoints(TextPatternRangeEndpoint endpoint, ITextRangeProvider *textRangeProvider, TextPatternRangeEndpoint targetEndpoint, INT32 *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!textRangeProvider || !returnValue)
+ return E_INVALIDARG;
+
+ QWinRTUiaTextRangeProvider *targetProvider = static_cast<QWinRTUiaTextRangeProvider *>(textRangeProvider);
+
+ int point = (endpoint == TextPatternRangeEndpoint_Start) ? m_startOffset : m_endOffset;
+ int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ?
+ targetProvider->m_startOffset : targetProvider->m_endOffset;
+ *returnValue = point - targetPoint;
+ return S_OK;
+}
+
+// Expands/normalizes the range for a given text unit.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::ExpandToEnclosingUnit(TextUnit unit)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "unit=" << unit << "this: " << this;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+
+ int len = metadata->characterCount();
+ if (len < 1) {
+ m_startOffset = 0;
+ m_endOffset = 0;
+ } else {
+ if (unit == TextUnit_Character) {
+ m_startOffset = qBound(0, m_startOffset, len - 1);
+ m_endOffset = m_startOffset + 1;
+ } else {
+ QString text = metadata->text();
+ for (int t = m_startOffset; t >= 0; --t) {
+ if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) {
+ m_startOffset = t;
+ break;
+ }
+ }
+ for (int t = m_startOffset; t < len; ++t) {
+ if ((t == len - 1) || (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1])))) {
+ m_endOffset = t + 1;
+ break;
+ }
+ }
+ }
+ }
+ return S_OK;
+}
+
+// Not supported.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::FindAttribute(INT32 /*attributeId*/, IInspectable * /*value*/, boolean /*backward*/, ITextRangeProvider **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::FindText(HSTRING /*text*/, boolean /*backward*/, boolean /*ignoreCase*/, ITextRangeProvider **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+ return S_OK;
+}
+
+// Returns the value of a given attribute.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetAttributeValue(INT32 attributeId, IInspectable **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "attributeId=" << attributeId;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+
+ ComPtr<IPropertyValueStatics> propertyValueStatics;
+ if (FAILED(RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), IID_PPV_ARGS(&propertyValueStatics))))
+ return E_FAIL;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+
+ switch (attributeId) {
+ case AutomationTextAttributesEnum_IsReadOnlyAttribute:
+ return propertyValueStatics->CreateBoolean(metadata->state().readOnly, returnValue);
+ case AutomationTextAttributesEnum_CaretPositionAttribute:
+ if (metadata->cursorPosition() == 0)
+ return propertyValueStatics->CreateInt32(AutomationCaretPosition_BeginningOfLine, returnValue);
+ else if (metadata->cursorPosition() == metadata->characterCount())
+ return propertyValueStatics->CreateInt32(AutomationCaretPosition_EndOfLine, returnValue);
+ else
+ return propertyValueStatics->CreateInt32(AutomationCaretPosition_Unknown, returnValue);
+ default:
+ break;
+ }
+ return E_FAIL;
+}
+
+// Returns an array of bounding rectangles for text lines within the range.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT32 *returnValueSize, DOUBLE **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+ *returnValueSize = 0;
+ *returnValue = nullptr;
+
+ auto accid = id();
+ auto startOffset = m_startOffset;
+ auto endOffset = m_endOffset;
+ auto rects = QSharedPointer<QList<QRect>>(new QList<QRect>);
+ auto ptrRects = new QSharedPointer<QList<QRect>>(rects);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset, ptrRects]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
+ int len = textInterface->characterCount();
+ if ((startOffset >= 0) && (endOffset <= len) && (startOffset < endOffset)) {
+ int start, end;
+ textInterface->textAtOffset(startOffset, QAccessible::LineBoundary, &start, &end);
+ while ((start >= 0) && (end >= 0)) {
+ int startRange = qMax(start, startOffset);
+ int endRange = qMin(end, endOffset);
+ if (startRange < endRange) {
+ // Calculates a bounding rectangle for the line and adds it to the list.
+ const QRect startRect = textInterface->characterRect(startRange);
+ const QRect endRect = textInterface->characterRect(endRange - 1);
+ const QRect lineRect(qMin(startRect.x(), endRect.x()),
+ qMin(startRect.y(), endRect.y()),
+ qMax(startRect.x() + startRect.width(), endRect.x() + endRect.width()) - qMin(startRect.x(), endRect.x()),
+ qMax(startRect.y() + startRect.height(), endRect.y() + endRect.height()) - qMin(startRect.y(), endRect.y()));
+ (*ptrRects)->append(lineRect);
+ }
+ if (end >= len) break;
+ textInterface->textAfterOffset(end + 1, QAccessible::LineBoundary, &start, &end);
+ }
+ }
+ }
+ }
+ delete ptrRects;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ DOUBLE *doubleArray = static_cast<DOUBLE *>(CoTaskMemAlloc(4 * rects->size() * sizeof(DOUBLE)));
+ if (!doubleArray)
+ return E_OUTOFMEMORY;
+
+ for (int i = 0; i < rects->size(); ++i) {
+ doubleArray[i*4] = (*rects)[i].left();
+ doubleArray[i*4+1] = (*rects)[i].top();
+ doubleArray[i*4+2] = (*rects)[i].width();
+ doubleArray[i*4+3] = (*rects)[i].height();
+ }
+ *returnValue = doubleArray;
+ *returnValueSize = 4 * rects->size();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetEnclosingElement(IIRawElementProviderSimple **returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!returnValue)
+ return E_INVALIDARG;
+ return QWinRTUiaMainProvider::rawProviderForAccessibleId(id(), returnValue);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetText(INT32 maxLength, HSTRING *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = nullptr;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+
+ QString rangeText = metadata->text().mid(m_startOffset, m_endOffset - m_startOffset);
+
+ if ((maxLength > -1) && (rangeText.size() > maxLength))
+ rangeText.truncate(maxLength);
+ return qHString(rangeText, returnValue);
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Move(TextUnit unit, INT32 count, INT32 *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = 0;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+
+ int len = metadata->characterCount();
+ if (len < 1)
+ return S_OK;
+
+ if (unit == TextUnit_Character) {
+ // Moves the start point, ensuring it lies within the bounds.
+ int start = qBound(0, m_startOffset + count, len - 1);
+ // If range was initially empty, leaves it as is; otherwise, normalizes it to one char.
+ m_endOffset = (m_endOffset > m_startOffset) ? start + 1 : start;
+ *returnValue = start - m_startOffset; // Returns the actually moved distance.
+ m_startOffset = start;
+ } else {
+ if (count > 0) {
+ MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, returnValue);
+ MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, returnValue);
+ } else {
+ MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, returnValue);
+ MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, returnValue);
+ }
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, INT32 count, INT32 *returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!returnValue)
+ return E_INVALIDARG;
+ *returnValue = 0;
+
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+
+ int len = metadata->characterCount();
+ if (len < 1)
+ return S_OK;
+
+ if (unit == TextUnit_Character) {
+ if (endpoint == TextPatternRangeEndpoint_Start) {
+ int boundedValue = qBound(0, m_startOffset + count, len - 1);
+ *returnValue = boundedValue - m_startOffset;
+ m_startOffset = boundedValue;
+ m_endOffset = qBound(m_startOffset, m_endOffset, len);
+ } else {
+ int boundedValue = qBound(0, m_endOffset + count, len);
+ *returnValue = boundedValue - m_endOffset;
+ m_endOffset = boundedValue;
+ m_startOffset = qBound(0, m_startOffset, m_endOffset);
+ }
+ } else {
+ QString text = metadata->text();
+ int moved = 0;
+
+ if (endpoint == TextPatternRangeEndpoint_Start) {
+ if (count > 0) {
+ for (int t = m_startOffset; (t < len - 1) && (moved < count); ++t) {
+ if (isTextUnitSeparator(unit, text[t]) && !isTextUnitSeparator(unit, text[t + 1])) {
+ m_startOffset = t + 1;
+ ++moved;
+ }
+ }
+ m_endOffset = qBound(m_startOffset, m_endOffset, len);
+ } else {
+ for (int t = m_startOffset - 1; (t >= 0) && (moved > count); --t) {
+ if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) {
+ m_startOffset = t;
+ --moved;
+ }
+ }
+ }
+ } else {
+ if (count > 0) {
+ for (int t = m_endOffset; (t < len) && (moved < count); ++t) {
+ if ((t == len - 1) || (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1])))) {
+ m_endOffset = t + 1;
+ ++moved;
+ }
+ }
+ } else {
+ int end = 0;
+ for (int t = m_endOffset - 2; (t > 0) && (moved > count); --t) {
+ if (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1]))) {
+ end = t + 1;
+ --moved;
+ }
+ }
+ m_endOffset = end;
+ m_startOffset = qBound(0, m_startOffset, m_endOffset);
+ }
+ }
+ *returnValue = moved;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::MoveEndpointByRange(TextPatternRangeEndpoint endpoint, ITextRangeProvider *textRangeProvider, TextPatternRangeEndpoint targetEndpoint)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ if (!textRangeProvider)
+ return E_INVALIDARG;
+
+ QWinRTUiaTextRangeProvider *targetProvider = static_cast<QWinRTUiaTextRangeProvider *>(textRangeProvider);
+
+ int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ?
+ targetProvider->m_startOffset : targetProvider->m_endOffset;
+
+ // If the moved endpoint crosses the other endpoint, that one is moved too.
+ if (endpoint == TextPatternRangeEndpoint_Start) {
+ m_startOffset = targetPoint;
+ if (m_endOffset < m_startOffset)
+ m_endOffset = m_startOffset;
+ } else {
+ m_endOffset = targetPoint;
+ if (m_endOffset < m_startOffset)
+ m_startOffset = m_endOffset;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Select()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+ auto startOffset = m_startOffset;
+ auto endOffset = m_endOffset;
+
+ QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid))
+ if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
+ // unselects all and adds a new selection
+ for (int i = textInterface->selectionCount() - 1; i >= 0; --i)
+ textInterface->removeSelection(i);
+ textInterface->addSelection(startOffset, endOffset);
+ }
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ return S_OK;
+ }, 0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::AddToSelection()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ return Select();
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::RemoveFromSelection()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+
+ QEventDispatcherWinRT::runOnMainThread([accid]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid))
+ if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
+ // unselects all
+ for (int i = textInterface->selectionCount() - 1; i >= 0; --i)
+ textInterface->removeSelection(i);
+ }
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ return S_OK;
+ }, 0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::ScrollIntoView(boolean /*alignToTop*/)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+ auto startOffset = m_startOffset;
+ auto endOffset = m_endOffset;
+
+ QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid))
+ if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
+ textInterface->scrollToSubstring(startOffset, endOffset);
+ }
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ return S_OK;
+ }, 0);
+ return S_OK;
+}
+
+// Returns an array of children elements embedded within the range.
+HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetChildren(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!returnValue)
+ return E_INVALIDARG;
+ // Not supporting any children.
+ returnValueSize = 0;
+ *returnValue = nullptr;
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h
new file mode 100644
index 0000000000..81b5f0d400
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIATEXTRANGEPROVIDER_H
+#define QWINRTUIATEXTRANGEPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Text Range control pattern provider. Used for text controls.
+class QWinRTUiaTextRangeProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaTextRangeProvider)
+ InspectableClass(L"QWinRTUiaTextRangeProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset);
+ virtual ~QWinRTUiaTextRangeProvider();
+
+ // ITextRangeProvider
+ HRESULT STDMETHODCALLTYPE Clone(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
+ HRESULT STDMETHODCALLTYPE Compare(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider *textRangeProvider, boolean *returnValue) override;
+ HRESULT STDMETHODCALLTYPE CompareEndpoints(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider *textRangeProvider, ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint, INT32 *returnValue) override;
+ HRESULT STDMETHODCALLTYPE ExpandToEnclosingUnit(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit) override;
+ HRESULT STDMETHODCALLTYPE FindAttribute(INT32 attributeId, IInspectable *value, boolean backward, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
+ HRESULT STDMETHODCALLTYPE FindText(HSTRING text, boolean backward, boolean ignoreCase, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetAttributeValue(INT32 attributeId, IInspectable **returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetBoundingRectangles(UINT32 *returnValueSize, DOUBLE **returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetEnclosingElement(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue) override;
+ HRESULT STDMETHODCALLTYPE GetText(INT32 maxLength, HSTRING *returnValue) override;
+ HRESULT STDMETHODCALLTYPE Move(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit, INT32 count, INT32 *returnValue) override;
+ HRESULT STDMETHODCALLTYPE MoveEndpointByUnit(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint, ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit, INT32 count, INT32 *returnValue) override;
+ HRESULT STDMETHODCALLTYPE MoveEndpointByRange(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider *textRangeProvider, ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint) override;
+ HRESULT STDMETHODCALLTYPE Select() override;
+ HRESULT STDMETHODCALLTYPE AddToSelection() override;
+ HRESULT STDMETHODCALLTYPE RemoveFromSelection() override;
+ HRESULT STDMETHODCALLTYPE ScrollIntoView(boolean alignToTop) override;
+ HRESULT STDMETHODCALLTYPE GetChildren(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
+
+private:
+ int m_startOffset;
+ int m_endOffset;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIATEXTRANGEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp
new file mode 100644
index 0000000000..59f55eb422
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiatoggleprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+
+QWinRTUiaToggleProvider::QWinRTUiaToggleProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaToggleProvider::~QWinRTUiaToggleProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+// Gets the current toggle state.
+HRESULT STDMETHODCALLTYPE QWinRTUiaToggleProvider::get_ToggleState(ToggleState *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ if (metadata->state().checked)
+ *value = metadata->state().checkStateMixed ? ToggleState_Indeterminate : ToggleState_On;
+ else
+ *value = ToggleState_Off;
+ return S_OK;
+}
+
+// Toggles the state by invoking the toggle action.
+HRESULT STDMETHODCALLTYPE QWinRTUiaToggleProvider::Toggle()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+
+ QEventDispatcherWinRT::runOnMainThread([accid]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid))
+ if (QAccessibleActionInterface *actionInterface = accessible->actionInterface())
+ actionInterface->doAction(QAccessibleActionInterface::toggleAction());
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ return S_OK;
+ }, 0);
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h
new file mode 100644
index 0000000000..3d1740c0a1
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIATOGGLEPROVIDER_H
+#define QWINRTUIATOGGLEPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Toggle control pattern provider. Used for checkboxes.
+class QWinRTUiaToggleProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IToggleProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaToggleProvider)
+ InspectableClass(L"QWinRTUiaToggleProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaToggleProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaToggleProvider();
+
+ // IToggleProvider
+ HRESULT STDMETHODCALLTYPE get_ToggleState(ABI::Windows::UI::Xaml::Automation::ToggleState *value) override;
+ HRESULT STDMETHODCALLTYPE Toggle() override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIATOGGLEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp
new file mode 100644
index 0000000000..98483216c0
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiautils.h"
+
+using namespace ABI::Windows::UI::Xaml::Automation::Peers;
+using namespace ABI::Windows::UI::Xaml::Automation::Text;
+using namespace ABI::Windows::Foundation::Collections;
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQpaUiAutomation, "qt.qpa.uiautomation")
+
+namespace QWinRTUiAutomation {
+
+// Returns the window containing the element (usually the top window),
+QWindow *windowForAccessible(const QAccessibleInterface *accessible)
+{
+ QWindow *window = accessible->window();
+ if (!window) {
+ QAccessibleInterface *acc = accessible->parent();
+ while (acc && acc->isValid() && !window) {
+ window = acc->window();
+ QAccessibleInterface *par = acc->parent();
+ acc = par;
+ }
+ }
+ return window;
+}
+
+QAccessibleInterface *accessibleForId(QAccessible::Id id)
+{
+ QAccessibleInterface *accessible = QAccessible::accessibleInterface(id);
+ if (!accessible || !accessible->isValid())
+ return nullptr;
+ return accessible;
+}
+
+QAccessible::Id idForAccessible(QAccessibleInterface *accessible)
+{
+ if (!accessible)
+ return QAccessible::Id(0);
+ return QAccessible::uniqueId(accessible);
+}
+
+// Maps an accessibility role ID to an UI Automation control type ID.
+AutomationControlType roleToControlType(QAccessible::Role role)
+{
+ static const QHash<QAccessible::Role, AutomationControlType> mapping {
+ {QAccessible::TitleBar, AutomationControlType::AutomationControlType_TitleBar},
+ {QAccessible::MenuBar, AutomationControlType::AutomationControlType_MenuBar},
+ {QAccessible::ScrollBar, AutomationControlType::AutomationControlType_ScrollBar},
+ {QAccessible::Grip, AutomationControlType::AutomationControlType_Thumb},
+ {QAccessible::Sound, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Cursor, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Caret, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::AlertMessage, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Window, AutomationControlType::AutomationControlType_Window},
+ {QAccessible::Client, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::PopupMenu, AutomationControlType::AutomationControlType_Menu},
+ {QAccessible::MenuItem, AutomationControlType::AutomationControlType_MenuItem},
+ {QAccessible::ToolTip, AutomationControlType::AutomationControlType_ToolTip},
+ {QAccessible::Application, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Document, AutomationControlType::AutomationControlType_Document},
+ {QAccessible::Pane, AutomationControlType::AutomationControlType_Pane},
+ {QAccessible::Chart, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Dialog, AutomationControlType::AutomationControlType_Window},
+ {QAccessible::Border, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Grouping, AutomationControlType::AutomationControlType_Group},
+ {QAccessible::Separator, AutomationControlType::AutomationControlType_Separator},
+ {QAccessible::ToolBar, AutomationControlType::AutomationControlType_ToolBar},
+ {QAccessible::StatusBar, AutomationControlType::AutomationControlType_StatusBar},
+ {QAccessible::Table, AutomationControlType::AutomationControlType_Table},
+ {QAccessible::ColumnHeader, AutomationControlType::AutomationControlType_Header},
+ {QAccessible::RowHeader, AutomationControlType::AutomationControlType_Header},
+ {QAccessible::Column, AutomationControlType::AutomationControlType_HeaderItem},
+ {QAccessible::Row, AutomationControlType::AutomationControlType_HeaderItem},
+ {QAccessible::Cell, AutomationControlType::AutomationControlType_DataItem},
+ {QAccessible::Link, AutomationControlType::AutomationControlType_Hyperlink},
+ {QAccessible::HelpBalloon, AutomationControlType::AutomationControlType_ToolTip},
+ {QAccessible::Assistant, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::List, AutomationControlType::AutomationControlType_List},
+ {QAccessible::ListItem, AutomationControlType::AutomationControlType_ListItem},
+ {QAccessible::Tree, AutomationControlType::AutomationControlType_Tree},
+ {QAccessible::TreeItem, AutomationControlType::AutomationControlType_TreeItem},
+ {QAccessible::PageTab, AutomationControlType::AutomationControlType_TabItem},
+ {QAccessible::PropertyPage, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Indicator, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Graphic, AutomationControlType::AutomationControlType_Image},
+ {QAccessible::StaticText, AutomationControlType::AutomationControlType_Edit},
+ {QAccessible::EditableText, AutomationControlType::AutomationControlType_Edit},
+ {QAccessible::Button, AutomationControlType::AutomationControlType_Button},
+ {QAccessible::CheckBox, AutomationControlType::AutomationControlType_CheckBox},
+ {QAccessible::RadioButton, AutomationControlType::AutomationControlType_RadioButton},
+ {QAccessible::ComboBox, AutomationControlType::AutomationControlType_ComboBox},
+ {QAccessible::ProgressBar, AutomationControlType::AutomationControlType_ProgressBar},
+ {QAccessible::Dial, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::HotkeyField, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Slider, AutomationControlType::AutomationControlType_Slider},
+ {QAccessible::SpinBox, AutomationControlType::AutomationControlType_Spinner},
+ {QAccessible::Canvas, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Animation, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Equation, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::ButtonDropDown, AutomationControlType::AutomationControlType_Button},
+ {QAccessible::ButtonMenu, AutomationControlType::AutomationControlType_Button},
+ {QAccessible::ButtonDropGrid, AutomationControlType::AutomationControlType_Button},
+ {QAccessible::Whitespace, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::PageTabList, AutomationControlType::AutomationControlType_Tab},
+ {QAccessible::Clock, AutomationControlType::AutomationControlType_Custom},
+ {QAccessible::Splitter, AutomationControlType::AutomationControlType_Custom},
+ };
+
+ return mapping.value(role, AutomationControlType::AutomationControlType_Custom);
+}
+
+// True if a character can be a separator for a text unit.
+bool isTextUnitSeparator(TextUnit unit, const QChar &ch)
+{
+ return (((unit == TextUnit_Word) || (unit == TextUnit_Format)) && ch.isSpace())
+ || ((unit == TextUnit_Line) && (ch.toLatin1() == '\n'));
+}
+
+HRESULT qHString(const QString &str, HSTRING *returnValue)
+{
+ if (!returnValue)
+ return E_INVALIDARG;
+
+ const wchar_t *wstr = reinterpret_cast<const wchar_t *>(str.utf16());
+ return ::WindowsCreateString(wstr, static_cast<UINT32>(::wcslen(wstr)), returnValue);
+}
+
+QString hStrToQStr(const HSTRING &hStr)
+{
+ quint32 len;
+ const wchar_t *wstr = ::WindowsGetStringRawBuffer(hStr, &len);
+ return QString::fromWCharArray(wstr, len);
+}
+
+} // namespace QWinRTUiAutomation
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h
new file mode 100644
index 0000000000..9519cb4eb5
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAUTILS_H
+#define QWINRTUIAUTILS_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include <QtCore/QString>
+#include <QtCore/qt_windows.h>
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtGui/QWindow>
+#include <QtCore/QLoggingCategory>
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQpaUiAutomation)
+
+namespace QWinRTUiAutomation {
+
+QWindow *windowForAccessible(const QAccessibleInterface *accessible);
+
+QAccessibleInterface *accessibleForId(QAccessible::Id id);
+
+QAccessible::Id idForAccessible(QAccessibleInterface *accessible);
+
+ABI::Windows::UI::Xaml::Automation::Peers::AutomationControlType roleToControlType(QAccessible::Role role);
+
+bool isTextUnitSeparator(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit, const QChar &ch);
+
+HRESULT qHString(const QString &str, HSTRING *returnValue);
+
+QString hStrToQStr(const HSTRING &hStr);
+
+} // namespace QWinRTUiAutomation
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAUTILS_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp
new file mode 100644
index 0000000000..21389b74d2
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiavalueprovider.h"
+#include "qwinrtuiametadatacache.h"
+#include "qwinrtuiautils.h"
+
+#include <QtGui/QAccessible>
+#include <QtGui/QAccessibleInterface>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWinRTUiAutomation;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Automation::Provider;
+
+QWinRTUiaValueProvider::QWinRTUiaValueProvider(QAccessible::Id id) :
+ QWinRTUiaBaseProvider(id)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+QWinRTUiaValueProvider::~QWinRTUiaValueProvider()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+}
+
+// True for read-only controls.
+HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::get_IsReadOnly(boolean *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ *value = (metadata->state().readOnly != 0);
+ return S_OK;
+}
+
+// Returns the value in text form.
+HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::get_Value(HSTRING *value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!value)
+ return E_INVALIDARG;
+ QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
+ return qHString(metadata->value(), value);
+}
+
+// Sets the value associated with the control.
+HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::SetValue(HSTRING value)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ auto accid = id();
+ auto tmpValue = QSharedPointer<QString>(new QString);
+ auto ptrValue = new QSharedPointer<QString>(tmpValue);
+
+ *tmpValue = hStrToQStr(value);
+
+ QEventDispatcherWinRT::runOnMainThread([accid, ptrValue]() {
+
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+
+ // First sets the value as a text.
+ accessible->setText(QAccessible::Value, **ptrValue);
+
+ // Then, if the control supports the value interface (range value)
+ // and the supplied text can be converted to a number, and that number
+ // lies within the min/max limits, sets it as the control's current (numeric) value.
+ if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
+ bool ok = false;
+ double numval = (*ptrValue)->toDouble(&ok);
+ if (ok) {
+ double minimum = valueInterface->minimumValue().toDouble();
+ double maximum = valueInterface->maximumValue().toDouble();
+ if ((numval >= minimum) && (numval <= maximum)) {
+ valueInterface->setCurrentValue(QVariant(numval));
+ }
+ }
+ }
+ }
+ QWinRTUiaMetadataCache::instance()->load(accid);
+ delete ptrValue;
+ return S_OK;
+ }, 0);
+
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h
new file mode 100644
index 0000000000..d9cd5d200d
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTUIAVALUEPROVIDER_H
+#define QWINRTUIAVALUEPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwinrtuiabaseprovider.h"
+
+#include <wrl.h>
+#include <windows.ui.xaml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Value control pattern provider.
+// Supported for all controls that can return text(QAccessible::Value).
+class QWinRTUiaValueProvider :
+ public QWinRTUiaBaseProvider,
+ public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IValueProvider>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QWinRTUiaValueProvider)
+ InspectableClass(L"QWinRTUiaValueProvider", BaseTrust);
+
+public:
+ explicit QWinRTUiaValueProvider(QAccessible::Id id);
+ virtual ~QWinRTUiaValueProvider();
+
+ // IValueProvider
+ HRESULT STDMETHODCALLTYPE get_IsReadOnly(boolean *value) override;
+ HRESULT STDMETHODCALLTYPE get_Value(HSTRING *value) override;
+ HRESULT STDMETHODCALLTYPE SetValue(HSTRING value) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINRTUIAVALUEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/uiautomation.pri b/src/plugins/platforms/winrt/uiautomation/uiautomation.pri
new file mode 100644
index 0000000000..ca0dfae53f
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/uiautomation.pri
@@ -0,0 +1,45 @@
+
+SOURCES += \
+ $$PWD/qwinrtuiaaccessibility.cpp \
+ $$PWD/qwinrtuiabaseprovider.cpp \
+ $$PWD/qwinrtuiacontrolmetadata.cpp \
+ $$PWD/qwinrtuiagriditemprovider.cpp \
+ $$PWD/qwinrtuiagridprovider.cpp \
+ $$PWD/qwinrtuiainvokeprovider.cpp \
+ $$PWD/qwinrtuiamainprovider.cpp \
+ $$PWD/qwinrtuiametadatacache.cpp \
+ $$PWD/qwinrtuiapeervector.cpp \
+ $$PWD/qwinrtuiaprovidercache.cpp \
+ $$PWD/qwinrtuiarangevalueprovider.cpp \
+ $$PWD/qwinrtuiaselectionitemprovider.cpp \
+ $$PWD/qwinrtuiaselectionprovider.cpp \
+ $$PWD/qwinrtuiatableitemprovider.cpp \
+ $$PWD/qwinrtuiatableprovider.cpp \
+ $$PWD/qwinrtuiatextprovider.cpp \
+ $$PWD/qwinrtuiatextrangeprovider.cpp \
+ $$PWD/qwinrtuiatoggleprovider.cpp \
+ $$PWD/qwinrtuiautils.cpp \
+ $$PWD/qwinrtuiavalueprovider.cpp
+
+HEADERS += \
+ $$PWD/qwinrtuiaaccessibility.h \
+ $$PWD/qwinrtuiabaseprovider.h \
+ $$PWD/qwinrtuiacontrolmetadata.h \
+ $$PWD/qwinrtuiaemptypropertyvalue.h \
+ $$PWD/qwinrtuiagriditemprovider.h \
+ $$PWD/qwinrtuiagridprovider.h \
+ $$PWD/qwinrtuiainvokeprovider.h \
+ $$PWD/qwinrtuiamainprovider.h \
+ $$PWD/qwinrtuiametadatacache.h \
+ $$PWD/qwinrtuiapeervector.h \
+ $$PWD/qwinrtuiaprovidercache.h \
+ $$PWD/qwinrtuiarangevalueprovider.h \
+ $$PWD/qwinrtuiaselectionitemprovider.h \
+ $$PWD/qwinrtuiaselectionprovider.h \
+ $$PWD/qwinrtuiatableitemprovider.h \
+ $$PWD/qwinrtuiatableprovider.h \
+ $$PWD/qwinrtuiatextprovider.h \
+ $$PWD/qwinrtuiatextrangeprovider.h \
+ $$PWD/qwinrtuiatoggleprovider.h \
+ $$PWD/qwinrtuiautils.h \
+ $$PWD/qwinrtuiavalueprovider.h
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 042b270cff..167c5b0448 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -13,6 +13,7 @@ LIBS += -lws2_32 -ld3d11
SOURCES = \
main.cpp \
qwinrtbackingstore.cpp \
+ qwinrtcanvas.cpp \
qwinrtclipboard.cpp \
qwinrtcursor.cpp \
qwinrtdrag.cpp \
@@ -31,6 +32,7 @@ SOURCES = \
HEADERS = \
qwinrtbackingstore.h \
+ qwinrtcanvas.h \
qwinrtclipboard.h \
qwinrtcursor.h \
qwinrtdrag.h \
@@ -58,6 +60,8 @@ contains(DEFINES, QT_NO_DRAGANDDROP) {
HEADERS -= qwinrtdrag.h
}
+qtConfig(accessibility): include($$PWD/uiautomation/uiautomation.pri)
+
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin
!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README
index 8308db46dc..5f238ab261 100644
--- a/src/plugins/platforms/xcb/README
+++ b/src/plugins/platforms/xcb/README
@@ -1,32 +1,7 @@
-Requires libxcb >= 1.5.
-
-PACKAGE DEPENDENCIES
-
-Required packages:
-libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxcb-xinerama0-dev
-
-On Ubuntu 11.10 icccm1 is replaced by icccm4 and xcb-render-util is not available:
-libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxcb-xinerama0-dev
-The packages for xcb-render-util can be installed manually from http://packages.ubuntu.com/natty/libxcb-render-util0 and http://packages.ubuntu.com/natty/libxcb-render-util0-dev
-
-On Ubuntu 12.04 icccm1 is replaced by icccm4 and xcb-render-util can be installed automatically:
-libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-glx0-dev libxcb-xinerama0-dev
-
-
-On Fedora, the following packages are required:
-libxcb libxcb-devel libXrender libXrender-devel xcb-util-wm xcb-util-wm-devel xcb-util xcb-util-devel xcb-util-image xcb-util-image-devel xcb-util-keysyms xcb-util-keysyms-devel
+Requires libxcb >= 1.9.1.
REDUCING RUNTIME DEPENDENCIES
The '-qt-xcb' configure option can be used to get rid of most xcb- dependencies. Only libxcb will
still be linked dynamically, since it will be most likely be pulled in via other dependencies anyway.
This should allow for binaries that are portable across most modern Linux distributions.
-
-PACKAGE VERSION REQUIREMENTS
-
-When using touch input via XInput 2.2 or higher, there is a potential issue on systems that ship with
-a libXi older than 1.7.5. This is because XIAllowTouchEvents can deadlock with libXi 1.7.4 and earlier.
-When touch events are never received, this is not an issue, so plain mouse/keyboard systems are not affected.
-Qt versions before 5.8 attempted to recognize this scenario based on the pkg-config package version and skip
-the call. This has been removed starting from 5.8 since relying on pkg-config package versions is unsafe given
-that Qt must also support systems with limited or incomplete pkg-config setups.
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 444e3a7669..6f1a3e3c19 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -76,8 +76,8 @@
#include <X11/Xutil.h>
#endif
-#if QT_CONFIG(xinput2)
-#include <X11/extensions/XI2proto.h>
+#if QT_CONFIG(xcb_xinput)
+#include <xcb/xinput.h>
#endif
#if QT_CONFIG(xcb_render)
@@ -120,7 +120,7 @@ Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard")
#define XCB_GE_GENERIC 35
#endif
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed:
// - "pad0" became "extension"
// - "pad1" and "pad" became "pad0"
@@ -138,7 +138,7 @@ static inline bool isXIEvent(xcb_generic_event_t *event, int opCode)
qt_xcb_ge_event_t *e = reinterpret_cast<qt_xcb_ge_event_t *>(event);
return e->extension == opCode;
}
-#endif // QT_CONFIG(xinput2)
+#endif // QT_CONFIG(xcb_xinput)
#if QT_CONFIG(xcb_xlib)
static const char * const xcbConnectionErrors[] = {
@@ -573,6 +573,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
#if QT_CONFIG(xcb_render)
&xcb_render_id,
#endif
+#if QT_CONFIG(xcb_xinput)
+ &xcb_input_id,
+#endif
0
};
@@ -592,7 +595,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeScreens();
initializeXRender();
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2"))
initializeXInput2();
#endif
@@ -1105,13 +1108,13 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
handleClientMessageEvent((xcb_client_message_event_t *)event);
break;
case XCB_ENTER_NOTIFY:
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (hasXInput2() && !xi2MouseEventsDisabled())
break;
#endif
HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
case XCB_LEAVE_NOTIFY:
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (hasXInput2() && !xi2MouseEventsDisabled())
break;
#endif
@@ -1174,7 +1177,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
}
break;
}
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
case XCB_GE_GENERIC:
// Here the windowEventListener is invoked from xi2HandleEvent()
if (hasXInput2() && isXIEvent(event, m_xiOpCode))
@@ -1607,39 +1610,14 @@ xcb_window_t QXcbConnection::clientLeader()
return m_clientLeader;
}
-#if QT_CONFIG(xcb_xlib)
-void *QXcbConnection::xlib_display() const
-{
- return m_xlib_display;
-}
-
-void *QXcbConnection::createVisualInfoForDefaultVisualId() const
-{
- if (m_defaultVisualId == UINT_MAX)
- return 0;
- XVisualInfo info;
- memset(&info, 0, sizeof info);
- info.visualid = m_defaultVisualId;
-
- int count = 0;
- Display *dpy = static_cast<Display *>(connection()->xlib_display());
- XVisualInfo *retVisual = XGetVisualInfo(dpy, VisualIDMask, &info, &count);
- Q_ASSERT(count < 2);
- return retVisual;
-}
-
-#endif
-
-#if QT_CONFIG(xinput2)
-// it is safe to cast XI_* events here as long as we are only touching the first 32 bytes,
-// after that position event needs memmove, see xi2PrepareXIGenericDeviceEvent
+#if QT_CONFIG(xcb_xinput)
static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t type)
{
if (!isXIEvent(event, opCode))
return false;
- xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
- return xiEvent->evtype == type;
+ auto *e = reinterpret_cast<qt_xcb_ge_event_t *>(event);
+ return e->event_type == type;
}
#endif
static inline bool isValid(xcb_generic_event_t *event)
@@ -1675,16 +1653,16 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex,
}
return false;
}
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
// compress XI_* events
if (responseType == XCB_GE_GENERIC) {
if (!hasXInput2())
return false;
// compress XI_Motion, but not from tablet devices
- if (isXIType(event, m_xiOpCode, XI_Motion)) {
+ if (isXIType(event, m_xiOpCode, XCB_INPUT_MOTION)) {
#if QT_CONFIG(tabletevent)
- xXIDeviceEvent *xdev = reinterpret_cast<xXIDeviceEvent *>(event);
+ auto *xdev = reinterpret_cast<xcb_input_motion_event_t *>(event);
if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) &&
const_cast<QXcbConnection *>(this)->tabletDataForDevice(xdev->sourceid))
return false;
@@ -1693,29 +1671,27 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex,
xcb_generic_event_t *next = eventqueue->at(j);
if (!isValid(next))
continue;
- if (isXIType(next, m_xiOpCode, XI_Motion))
+ if (isXIType(next, m_xiOpCode, XCB_INPUT_MOTION))
return true;
}
return false;
}
-#ifdef XCB_USE_XINPUT22
// compress XI_TouchUpdate for the same touch point id
- if (isXIType(event, m_xiOpCode, XI_TouchUpdate)) {
- xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
- uint32_t id = xiDeviceEvent->detail % INT_MAX;
+ if (isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) {
+ auto *touchUpdateEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(event);
+ uint32_t id = touchUpdateEvent->detail % INT_MAX;
for (int j = nextIndex; j < eventqueue->size(); ++j) {
xcb_generic_event_t *next = eventqueue->at(j);
if (!isValid(next))
continue;
- if (isXIType(next, m_xiOpCode, XI_TouchUpdate)) {
- xXIDeviceEvent *xiDeviceNextEvent = reinterpret_cast<xXIDeviceEvent *>(next);
- if (id == xiDeviceNextEvent->detail % INT_MAX)
+ if (isXIType(next, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) {
+ auto *touchUpdateNextEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(next);
+ if (id == touchUpdateNextEvent->detail % INT_MAX)
return true;
}
}
return false;
}
-#endif
return false;
}
#endif
@@ -2032,10 +2008,7 @@ void QXcbConnection::initializeAllAtoms() {
++ptr;
}
- Q_ASSERT(i == QXcbAtom::NPredefinedAtoms);
-
- const QByteArray settings_atom_name = "_QT_SETTINGS_TIMESTAMP_" + m_displayName;
- names[i++] = settings_atom_name;
+ Q_ASSERT(i == QXcbAtom::NAtoms);
xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms];
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index d9321d94d0..3b42d7cf22 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -71,16 +71,6 @@
#include <QTabletEvent>
#endif
-#if QT_CONFIG(xinput2)
-#include <X11/extensions/XI2.h>
-#ifdef XIScrollClass
-#define XCB_USE_XINPUT21 // XI 2.1 adds smooth scrolling support
-#ifdef XI_TouchBeginMask
-#define XCB_USE_XINPUT22 // XI 2.2 adds multi-point touch support
-#endif
-#endif
-#endif // QT_CONFIG(xinput2)
-
struct xcb_randr_get_output_info_reply_t;
QT_BEGIN_NAMESPACE
@@ -303,9 +293,6 @@ namespace QXcbAtom {
_COMPIZ_TOOLKIT_ACTION,
_GTK_LOAD_ICONTHEMES,
- NPredefinedAtoms,
-
- _QT_SETTINGS_TIMESTAMP = NPredefinedAtoms,
NAtoms
};
}
@@ -362,7 +349,7 @@ public:
virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {}
virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {}
virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {}
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
virtual void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource = Qt::MouseEventNotSynthesized) {}
virtual void handleXIEnterLeave(xcb_ge_event_t *) {}
#endif
@@ -436,8 +423,7 @@ public:
xcb_visualid_t defaultVisualId() const { return m_defaultVisualId; }
#if QT_CONFIG(xcb_xlib)
- void *xlib_display() const;
- void *createVisualInfoForDefaultVisualId() const;
+ void *xlib_display() const { return m_xlib_display; }
#endif
void sync();
@@ -520,7 +506,7 @@ public:
static bool xEmbedSystemTrayAvailable();
static bool xEmbedSystemTrayVisualHasAlphaChannel();
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
void xi2SelectStateEvents();
void xi2SelectDeviceEvents(xcb_window_t window);
void xi2SelectDeviceEventsCompatibility(xcb_window_t window);
@@ -529,14 +515,10 @@ public:
bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; }
bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; }
Qt::MouseButton xiToQtMouseButton(uint32_t b);
-#ifdef XCB_USE_XINPUT21
void xi2UpdateScrollingDevices();
-#endif
-#ifdef XCB_USE_XINPUT22
bool startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner);
bool isTouchScreen(int id);
#endif
-#endif
QXcbEventReader *eventReader() const { return m_reader; }
bool canGrab() const { return m_canGrabServer; }
@@ -577,7 +559,7 @@ private:
bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const;
bool m_xi2Enabled = false;
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
int m_xi2Minor = -1;
void initializeXInput2();
void xi2SetupDevice(void *info, bool removeExisting = true);
@@ -605,10 +587,8 @@ private:
void xi2HandleEvent(xcb_ge_event_t *event);
void xi2HandleHierarchyEvent(void *event);
void xi2HandleDeviceChangedEvent(void *event);
- int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
-#ifdef XCB_USE_XINPUT22
+ int m_xiOpCode;
void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow);
-#endif // XCB_USE_XINPUT22
#if QT_CONFIG(tabletevent)
struct TabletData {
int deviceId = 0;
@@ -643,14 +623,11 @@ private:
QPointF lastScrollPosition;
};
QHash<int, ScrollingDevice> m_scrollingDevices;
-#ifdef XCB_USE_XINPUT21
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
void xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice);
ScrollingDevice *scrollingDeviceForId(int id);
-#endif
static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);
- static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event);
#endif
xcb_connection_t *m_connection = nullptr;
@@ -684,9 +661,8 @@ private:
#endif
QXcbEventReader *m_reader = nullptr;
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
QHash<int, TouchDeviceData> m_touchDevices;
-#ifdef XCB_USE_XINPUT22
struct StartSystemMoveResizeInfo {
xcb_window_t window = XCB_NONE;
uint16_t deviceid;
@@ -694,7 +670,6 @@ private:
int corner;
} m_startSystemMoveResizeInfo;
#endif
-#endif
WindowMapper m_mapper;
QVector<PeekFunc> m_peekFuncs;
@@ -702,6 +677,9 @@ private:
uint32_t xfixes_first_event = 0;
uint32_t xrandr_first_event = 0;
uint32_t xkb_first_event = 0;
+#if QT_CONFIG(xcb_xinput)
+ uint32_t xinput_first_event = 0;
+#endif
bool has_xfixes = false;
bool has_xinerama_extension = false;
@@ -737,7 +715,7 @@ private:
QHash<qint32, qint32> m_peekerToCachedIndex;
friend class QXcbEventReader;
};
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
#if QT_CONFIG(tabletevent)
Q_DECLARE_TYPEINFO(QXcbConnection::TabletData::ValuatorClassInfo, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE);
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 0302d585b5..475afa65db 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -47,59 +47,51 @@
#include <QDebug>
#include <cmath>
-#include <X11/extensions/XInput2.h>
-#include <X11/extensions/XI2proto.h>
+#include <xcb/xinput.h>
+
+using qt_xcb_input_device_event_t = xcb_input_button_press_event_t;
void QXcbConnection::initializeXInput2()
{
- Display *xDisplay = static_cast<Display *>(m_xlib_display);
- if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
- int xiMajor = 2;
-#if defined(XCB_USE_XINPUT22)
- m_xi2Minor = 2; // for touch support 2.2 is enough
-#elif defined(XCB_USE_XINPUT21)
- m_xi2Minor = 1; // for smooth scrolling 2.1 is enough
-#else
- m_xi2Minor = 0; // for tablet support 2.0 is enough
-#endif
- qCDebug(lcQpaXInput, "Plugin build with support for XInput 2 version up "
- "to %d.%d", xiMajor, m_xi2Minor);
-
- switch (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor)) {
- case Success:
- // Server's supported version can be lower than the version we have
- // announced to support. In this case Qt client will be limited by
- // X server's supported version.
- qCDebug(lcQpaXInput, "Using XInput version %d.%d", xiMajor, m_xi2Minor);
- m_xi2Enabled = true;
- xi2SetupDevices();
- xi2SelectStateEvents();
- break;
- case BadRequest: // Must be an X server with XInput 1
- qCDebug(lcQpaXInput, "X server does not support XInput 2");
- break;
- default: // BadValue
- qCDebug(lcQpaXInput, "Internal error");
- break;
- }
+ const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_input_id);
+ if (!reply || !reply->present) {
+ qCDebug(lcQpaXInput, "XInput extension is not present on the X server");
+ return;
+ }
+
+ m_xiOpCode = reply->major_opcode;
+ xinput_first_event = reply->first_event;
+
+ auto xinput_query = Q_XCB_REPLY(xcb_input_xi_query_version, m_connection, 2, 2);
+
+ if (!xinput_query || xinput_query->major_version != 2) {
+ qCWarning(lcQpaXInput, "X server does not support XInput 2");
+ } else {
+ qCDebug(lcQpaXInput, "Using XInput version %d.%d",
+ xinput_query->major_version, xinput_query->minor_version);
+ m_xi2Minor = xinput_query->minor_version;
+ m_xi2Enabled = true;
+ xi2SetupDevices();
+ xi2SelectStateEvents();
}
}
+struct qt_xcb_input_event_mask_t {
+ xcb_input_event_mask_t header;
+ uint32_t mask;
+};
+
void QXcbConnection::xi2SelectStateEvents()
{
// These state events do not depend on a specific X window, but are global
// for the X client's (application's) state.
- unsigned int bitMask = 0;
- unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask);
- XIEventMask xiEventMask;
- bitMask = XI_HierarchyChangedMask;
- bitMask |= XI_DeviceChangedMask;
- bitMask |= XI_PropertyEventMask;
- xiEventMask.deviceid = XIAllDevices;
- xiEventMask.mask_len = sizeof(bitMask);
- xiEventMask.mask = xiBitMask;
- Display *dpy = static_cast<Display *>(m_xlib_display);
- XISelectEvents(dpy, DefaultRootWindow(dpy), &xiEventMask, 1);
+ qt_xcb_input_event_mask_t xiEventMask;
+ xiEventMask.header.deviceid = XCB_INPUT_DEVICE_ALL;
+ xiEventMask.header.mask_len = 1;
+ xiEventMask.mask = XCB_INPUT_XI_EVENT_MASK_HIERARCHY;
+ xiEventMask.mask |= XCB_INPUT_XI_EVENT_MASK_DEVICE_CHANGED;
+ xiEventMask.mask |= XCB_INPUT_XI_EVENT_MASK_PROPERTY;
+ xcb_input_xi_select_events(m_connection, rootWindow(), 1, &xiEventMask.header);
}
void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
@@ -107,38 +99,42 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
if (window == rootWindow())
return;
- unsigned int bitMask = 0;
- unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask);
- bitMask |= XI_ButtonPressMask;
- bitMask |= XI_ButtonReleaseMask;
- bitMask |= XI_MotionMask;
+ uint32_t bitMask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_MOTION;
// There is a check for enter/leave events in plain xcb enter/leave event handler,
// core enter/leave events will be ignored in this case.
- bitMask |= XI_EnterMask;
- bitMask |= XI_LeaveMask;
-#ifdef XCB_USE_XINPUT22
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_ENTER;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_LEAVE;
if (isAtLeastXI22()) {
- bitMask |= XI_TouchBeginMask;
- bitMask |= XI_TouchUpdateMask;
- bitMask |= XI_TouchEndMask;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_END;
}
-#endif
- XIEventMask mask;
- mask.mask_len = sizeof(bitMask);
- mask.mask = xiBitMask;
- mask.deviceid = XIAllMasterDevices;
- Display *dpy = static_cast<Display *>(m_xlib_display);
- Status result = XISelectEvents(dpy, window, &mask, 1);
- if (result == Success)
+ qt_xcb_input_event_mask_t mask;
+ mask.header.deviceid = XCB_INPUT_DEVICE_ALL_MASTER;
+ mask.header.mask_len = 1;
+ mask.mask = bitMask;
+ xcb_void_cookie_t cookie =
+ xcb_input_xi_select_events_checked(m_connection, window, 1, &mask.header);
+ xcb_generic_error_t *error = xcb_request_check(m_connection, cookie);
+ if (error) {
+ qCDebug(lcQpaXInput, "failed to select events, window %x, error code %d", window, error->error_code);
+ free(error);
+ } else {
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
- else
- qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result);
+ }
+}
+
+static inline qreal fixed3232ToReal(xcb_input_fp3232_t val)
+{
+ return qreal(val.integral) + qreal(val.frac) / (1ULL << 32);
}
void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
{
- XIDeviceInfo *deviceInfo = reinterpret_cast<XIDeviceInfo *>(info);
+ auto *deviceInfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info);
if (removeExisting) {
#if QT_CONFIG(tabletevent)
for (int i = 0; i < m_tabletData.count(); ++i) {
@@ -152,53 +148,54 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
m_touchDevices.remove(deviceInfo->deviceid);
}
- qCDebug(lcQpaXInputDevices) << "input device " << deviceInfo->name << "ID" << deviceInfo->deviceid;
+ qCDebug(lcQpaXInputDevices) << "input device " << xcb_input_xi_device_info_name(deviceInfo) << "ID" << deviceInfo->deviceid;
#if QT_CONFIG(tabletevent)
TabletData tabletData;
#endif
ScrollingDevice scrollingDevice;
- for (int c = 0; c < deviceInfo->num_classes; ++c) {
- XIAnyClassInfo *classinfo = deviceInfo->classes[c];
+ auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
+ for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
+ xcb_input_device_class_t *classinfo = classes_it.data;
switch (classinfo->type) {
- case XIValuatorClass: {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo);
+ case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
+ auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
const int valuatorAtom = qatom(vci->label);
qCDebug(lcQpaXInputDevices) << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
#if QT_CONFIG(tabletevent)
if (valuatorAtom < QXcbAtom::NAtoms) {
TabletData::ValuatorClassInfo info;
- info.minVal = vci->min;
- info.maxVal = vci->max;
+ info.minVal = fixed3232ToReal(vci->min);
+ info.maxVal = fixed3232ToReal(vci->max);
info.number = vci->number;
tabletData.valuatorInfo[valuatorAtom] = info;
}
#endif // QT_CONFIG(tabletevent)
if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
- scrollingDevice.lastScrollPosition.setX(vci->value);
+ scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value));
else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
- scrollingDevice.lastScrollPosition.setY(vci->value);
+ scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value));
break;
}
-#ifdef XCB_USE_XINPUT21
- case XIScrollClass: {
- XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(classinfo);
- if (sci->scroll_type == XIScrollTypeVertical) {
+ case XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL: {
+ auto *sci = reinterpret_cast<xcb_input_scroll_class_t *>(classinfo);
+ if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL) {
scrollingDevice.orientations |= Qt::Vertical;
scrollingDevice.verticalIndex = sci->number;
- scrollingDevice.verticalIncrement = sci->increment;
- }
- else if (sci->scroll_type == XIScrollTypeHorizontal) {
+ scrollingDevice.verticalIncrement = fixed3232ToReal(sci->increment);
+ } else if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) {
scrollingDevice.orientations |= Qt::Horizontal;
scrollingDevice.horizontalIndex = sci->number;
- scrollingDevice.horizontalIncrement = sci->increment;
+ scrollingDevice.horizontalIncrement = fixed3232ToReal(sci->increment);
}
break;
}
- case XIButtonClass: {
- XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(classinfo);
+ case XCB_INPUT_DEVICE_CLASS_TYPE_BUTTON: {
+ auto *bci = reinterpret_cast<xcb_input_button_class_t *>(classinfo);
+ xcb_atom_t *labels = 0;
if (bci->num_buttons >= 5) {
- Atom label4 = bci->labels[3];
- Atom label5 = bci->labels[4];
+ labels = xcb_input_button_class_labels(bci);
+ xcb_atom_t label4 = labels[3];
+ xcb_atom_t label5 = labels[4];
// Some drivers have no labels on the wheel buttons, some have no label on just one and some have no label on
// button 4 and the wrong one on button 5. So we just check that they are not labelled with unrelated buttons.
if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp || qatom(label4) == QXcbAtom::ButtonWheelDown) &&
@@ -206,23 +203,20 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
scrollingDevice.legacyOrientations |= Qt::Vertical;
}
if (bci->num_buttons >= 7) {
- Atom label6 = bci->labels[5];
- Atom label7 = bci->labels[6];
+ xcb_atom_t label6 = labels[5];
+ xcb_atom_t label7 = labels[6];
if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight))
scrollingDevice.legacyOrientations |= Qt::Horizontal;
}
qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons);
break;
}
-#endif
- case XIKeyClass:
+ case XCB_INPUT_DEVICE_CLASS_TYPE_KEY:
qCDebug(lcQpaXInputDevices) << " it's a keyboard";
break;
-#ifdef XCB_USE_XINPUT22
- case XITouchClass:
+ case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH:
// will be handled in populateTouchDevices()
break;
-#endif
default:
qCDebug(lcQpaXInputDevices) << " has class" << classinfo->type;
break;
@@ -237,7 +231,8 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
isTablet = true;
// But we need to be careful not to take the touch and tablet-button devices as tablets.
- QByteArray name = QByteArray(deviceInfo->name).toLower();
+ QByteArray name = QByteArray(xcb_input_xi_device_info_name(deviceInfo),
+ xcb_input_xi_device_info_name_length(deviceInfo)).toLower();
QString dbgType = QLatin1String("UNKNOWN");
if (name.contains("eraser")) {
isTablet = true;
@@ -281,7 +276,6 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
}
#endif // QT_CONFIG(tabletevent)
-#ifdef XCB_USE_XINPUT21
if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) {
scrollingDevice.deviceId = deviceInfo->deviceid;
// Only use legacy wheel button events when we don't have real scroll valuators.
@@ -289,7 +283,6 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
qCDebug(lcQpaXInputDevices) << " it's a scrolling device";
}
-#endif
if (!isTablet) {
TouchDeviceData *dev = populateTouchDevices(deviceInfo);
@@ -315,23 +308,28 @@ void QXcbConnection::xi2SetupDevices()
#endif
m_scrollingDevices.clear();
m_touchDevices.clear();
-
- Display *xDisplay = static_cast<Display *>(m_xlib_display);
- int deviceCount = 0;
- XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
m_xiMasterPointerIds.clear();
- for (int i = 0; i < deviceCount; ++i) {
- XIDeviceInfo deviceInfo = devices[i];
- if (deviceInfo.use == XIMasterPointer) {
- m_xiMasterPointerIds.append(deviceInfo.deviceid);
+
+ auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, XCB_INPUT_DEVICE_ALL);
+ if (!reply) {
+ qCDebug(lcQpaXInputDevices) << "failed to query devices";
+ return;
+ }
+
+ auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
+ for (; it.rem; xcb_input_xi_device_info_next(&it)) {
+ xcb_input_xi_device_info_t *deviceInfo = it.data;
+ if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_MASTER_POINTER) {
+ m_xiMasterPointerIds.append(deviceInfo->deviceid);
continue;
}
- if (deviceInfo.use == XISlavePointer) // only slave pointer devices are relevant here
- xi2SetupDevice(&deviceInfo, false);
+ // only slave pointer devices are relevant here
+ if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER)
+ xi2SetupDevice(deviceInfo, false);
}
+
if (m_xiMasterPointerIds.size() > 1)
qCDebug(lcQpaXInputDevices) << "multi-pointer X detected";
- XIFreeDeviceInfo(devices);
}
/*! \internal
@@ -376,70 +374,64 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window)
if (window == rootWindow())
return;
- unsigned int mask = 0;
- unsigned char *bitMask = reinterpret_cast<unsigned char *>(&mask);
- Display *dpy = static_cast<Display *>(m_xlib_display);
+ uint32_t mask = 0;
-#ifdef XCB_USE_XINPUT22
if (isAtLeastXI22()) {
- mask |= XI_TouchBeginMask;
- mask |= XI_TouchUpdateMask;
- mask |= XI_TouchEndMask;
-
- XIEventMask xiMask;
- xiMask.mask_len = sizeof(mask);
- xiMask.mask = bitMask;
- xiMask.deviceid = XIAllMasterDevices;
- Status result = XISelectEvents(dpy, window, &xiMask, 1);
- if (result == Success)
+ mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN;
+ mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE;
+ mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_END;
+
+ qt_xcb_input_event_mask_t xiMask;
+ xiMask.header.deviceid = XCB_INPUT_DEVICE_ALL_MASTER;
+ xiMask.header.mask_len = 1;
+ xiMask.mask = mask;
+
+ xcb_void_cookie_t cookie =
+ xcb_input_xi_select_events_checked(m_connection, window, 1, &xiMask.header);
+ xcb_generic_error_t *error = xcb_request_check(m_connection, cookie);
+ if (error) {
+ qCDebug(lcQpaXInput, "failed to select events, window %x, error code %d", window, error->error_code);
+ free(error);
+ } else {
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
- else
- qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result);
+ }
}
-#endif
- mask = XI_ButtonPressMask;
- mask |= XI_ButtonReleaseMask;
- mask |= XI_MotionMask;
+ mask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS;
+ mask |= XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE;
+ mask |= XCB_INPUT_XI_EVENT_MASK_MOTION;
#if QT_CONFIG(tabletevent)
QSet<int> tabletDevices;
if (!m_tabletData.isEmpty()) {
const int nrTablets = m_tabletData.count();
- QVector<XIEventMask> xiEventMask(nrTablets);
+ QVector<qt_xcb_input_event_mask_t> xiEventMask(nrTablets);
for (int i = 0; i < nrTablets; ++i) {
int deviceId = m_tabletData.at(i).deviceId;
tabletDevices.insert(deviceId);
- xiEventMask[i].deviceid = deviceId;
- xiEventMask[i].mask_len = sizeof(mask);
- xiEventMask[i].mask = bitMask;
+ xiEventMask[i].header.deviceid = deviceId;
+ xiEventMask[i].header.mask_len = 1;
+ xiEventMask[i].mask = mask;
}
- XISelectEvents(dpy, window, xiEventMask.data(), nrTablets);
+ xcb_input_xi_select_events(m_connection, window, nrTablets, &(xiEventMask.data()->header));
}
#endif
-#ifdef XCB_USE_XINPUT21
if (!m_scrollingDevices.isEmpty()) {
- QVector<XIEventMask> xiEventMask(m_scrollingDevices.size());
+ QVector<qt_xcb_input_event_mask_t> xiEventMask(m_scrollingDevices.size());
int i = 0;
for (const ScrollingDevice& scrollingDevice : qAsConst(m_scrollingDevices)) {
#if QT_CONFIG(tabletevent)
if (tabletDevices.contains(scrollingDevice.deviceId))
continue; // All necessary events are already captured.
#endif
- xiEventMask[i].deviceid = scrollingDevice.deviceId;
- xiEventMask[i].mask_len = sizeof(mask);
- xiEventMask[i].mask = bitMask;
+ xiEventMask[i].header.deviceid = scrollingDevice.deviceId;
+ xiEventMask[i].header.mask_len = 1;
+ xiEventMask[i].mask = mask;
i++;
}
- XISelectEvents(dpy, window, xiEventMask.data(), i);
+ xcb_input_xi_select_events(m_connection, window, i, &(xiEventMask.data()->header));
}
-#endif
-
-#if !QT_CONFIG(tabletevent) && !defined(XCB_USE_XINPUT21)
- Q_UNUSED(bitMask);
- Q_UNUSED(dpy);
-#endif
}
QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
@@ -452,39 +444,38 @@ QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info)
{
- XIDeviceInfo *deviceinfo = reinterpret_cast<XIDeviceInfo *>(info);
+ auto *deviceinfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info);
QTouchDevice::Capabilities caps = 0;
int type = -1;
int maxTouchPoints = 1;
bool isTouchDevice = false;
bool hasRelativeCoords = false;
TouchDeviceData dev;
- for (int i = 0; i < deviceinfo->num_classes; ++i) {
- XIAnyClassInfo *classinfo = deviceinfo->classes[i];
+ auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceinfo);
+ for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
+ xcb_input_device_class_t *classinfo = classes_it.data;
switch (classinfo->type) {
-#ifdef XCB_USE_XINPUT22
- case XITouchClass: {
- XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo);
+ case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH: {
+ auto *tci = reinterpret_cast<xcb_input_touch_class_t *>(classinfo);
maxTouchPoints = tci->num_touches;
qCDebug(lcQpaXInputDevices, " has touch class with mode %d", tci->mode);
switch (tci->mode) {
- case XIDependentTouch:
+ case XCB_INPUT_TOUCH_MODE_DEPENDENT:
type = QTouchDevice::TouchPad;
break;
- case XIDirectTouch:
+ case XCB_INPUT_TOUCH_MODE_DIRECT:
type = QTouchDevice::TouchScreen;
break;
}
break;
}
-#endif // XCB_USE_XINPUT22
- case XIValuatorClass: {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo);
+ case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
+ auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
const QXcbAtom::Atom valuatorAtom = qatom(vci->label);
if (valuatorAtom < QXcbAtom::NAtoms) {
TouchDeviceData::ValuatorClassInfo info;
- info.min = vci->min;
- info.max = vci->max;
+ info.min = fixed3232ToReal(vci->min);
+ info.max = fixed3232ToReal(vci->max);
info.number = vci->number;
info.label = valuatorAtom;
dev.valuatorInfo.append(info);
@@ -502,16 +493,16 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
caps |= QTouchDevice::Pressure;
else if (valuatorAtom == QXcbAtom::RelX) {
hasRelativeCoords = true;
- dev.size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
} else if (valuatorAtom == QXcbAtom::RelY) {
hasRelativeCoords = true;
- dev.size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
} else if (valuatorAtom == QXcbAtom::AbsX) {
caps |= QTouchDevice::Position;
- dev.size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
} else if (valuatorAtom == QXcbAtom::AbsY) {
caps |= QTouchDevice::Position;
- dev.size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
}
break;
}
@@ -530,7 +521,8 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
if (type >= QTouchDevice::TouchScreen && type <= QTouchDevice::TouchPad) {
dev.qtTouchDevice = new QTouchDevice;
- dev.qtTouchDevice->setName(QString::fromUtf8(deviceinfo->name));
+ dev.qtTouchDevice->setName(QString::fromUtf8(xcb_input_xi_device_info_name(deviceinfo),
+ xcb_input_xi_device_info_name_length(deviceinfo)));
dev.qtTouchDevice->setType((QTouchDevice::DeviceType)type);
dev.qtTouchDevice->setCapabilities(caps);
dev.qtTouchDevice->setMaximumTouchPoints(maxTouchPoints);
@@ -543,49 +535,46 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
return isTouchDevice ? &m_touchDevices[deviceinfo->deviceid] : nullptr;
}
-#if defined(XCB_USE_XINPUT21) || QT_CONFIG(tabletevent)
-static inline qreal fixed1616ToReal(FP1616 val)
+#if QT_CONFIG(tabletevent)
+static inline qreal fixed1616ToReal(xcb_input_fp1616_t val)
{
return qreal(val) / 0x10000;
}
-#endif // defined(XCB_USE_XINPUT21) || QT_CONFIG(tabletevent)
+#endif // QT_CONFIG(tabletevent)
void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
{
- xi2PrepareXIGenericDeviceEvent(event);
- xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
+ auto *xiEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
int sourceDeviceId = xiEvent->deviceid; // may be the master id
- xXIDeviceEvent *xiDeviceEvent = 0;
- xXIEnterEvent *xiEnterEvent = 0;
+ qt_xcb_input_device_event_t *xiDeviceEvent = nullptr;
+ xcb_input_enter_event_t *xiEnterEvent = nullptr;
QXcbWindowEventListener *eventListener = 0;
- switch (xiEvent->evtype) {
- case XI_ButtonPress:
- case XI_ButtonRelease:
- case XI_Motion:
-#ifdef XCB_USE_XINPUT22
- case XI_TouchBegin:
- case XI_TouchUpdate:
- case XI_TouchEnd:
-#endif
+ switch (xiEvent->event_type) {
+ case XCB_INPUT_BUTTON_PRESS:
+ case XCB_INPUT_BUTTON_RELEASE:
+ case XCB_INPUT_MOTION:
+ case XCB_INPUT_TOUCH_BEGIN:
+ case XCB_INPUT_TOUCH_UPDATE:
+ case XCB_INPUT_TOUCH_END:
{
- xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
+ xiDeviceEvent = xiEvent;
eventListener = windowEventListenerFromId(xiDeviceEvent->event);
sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master
break;
}
- case XI_Enter:
- case XI_Leave: {
- xiEnterEvent = reinterpret_cast<xXIEnterEvent *>(event);
+ case XCB_INPUT_ENTER:
+ case XCB_INPUT_LEAVE: {
+ xiEnterEvent = reinterpret_cast<xcb_input_enter_event_t *>(event);
eventListener = windowEventListenerFromId(xiEnterEvent->event);
sourceDeviceId = xiEnterEvent->sourceid; // use the actual device id instead of the master
break;
}
- case XI_HierarchyChanged:
- xi2HandleHierarchyEvent(xiEvent);
+ case XCB_INPUT_HIERARCHY:
+ xi2HandleHierarchyEvent(event);
return;
- case XI_DeviceChanged:
- xi2HandleDeviceChangedEvent(xiEvent);
+ case XCB_INPUT_DEVICE_CHANGED:
+ xi2HandleDeviceChangedEvent(event);
return;
default:
break;
@@ -600,32 +589,30 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
#if QT_CONFIG(tabletevent)
if (!xiEnterEvent) {
QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId);
- if (tablet && xi2HandleTabletEvent(xiEvent, tablet))
+ if (tablet && xi2HandleTabletEvent(event, tablet))
return;
}
#endif // QT_CONFIG(tabletevent)
-#ifdef XCB_USE_XINPUT21
if (ScrollingDevice *device = scrollingDeviceForId(sourceDeviceId))
- xi2HandleScrollEvent(xiEvent, *device);
-#endif // XCB_USE_XINPUT21
+ xi2HandleScrollEvent(event, *device);
-#ifdef XCB_USE_XINPUT22
if (xiDeviceEvent) {
- switch (xiDeviceEvent->evtype) {
- case XI_ButtonPress:
- case XI_ButtonRelease:
- case XI_Motion:
- if (!xi2MouseEventsDisabled() && eventListener && !(xiDeviceEvent->flags & XIPointerEmulated))
+ switch (xiDeviceEvent->event_type) {
+ case XCB_INPUT_BUTTON_PRESS:
+ case XCB_INPUT_BUTTON_RELEASE:
+ case XCB_INPUT_MOTION:
+ if (!xi2MouseEventsDisabled() && eventListener &&
+ !(xiDeviceEvent->flags & XCB_INPUT_POINTER_EVENT_FLAGS_POINTER_EMULATED))
eventListener->handleXIMouseEvent(event);
break;
- case XI_TouchBegin:
- case XI_TouchUpdate:
- case XI_TouchEnd:
+ case XCB_INPUT_TOUCH_BEGIN:
+ case XCB_INPUT_TOUCH_UPDATE:
+ case XCB_INPUT_TOUCH_END:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x",
- event->event_type, xiDeviceEvent->sequenceNumber, xiDeviceEvent->detail,
+ event->event_type, xiDeviceEvent->sequence, xiDeviceEvent->detail,
fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event);
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event))
@@ -633,14 +620,13 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
break;
}
} else if (xiEnterEvent && !xi2MouseEventsDisabled() && eventListener) {
- switch (xiEnterEvent->evtype) {
- case XI_Enter:
- case XI_Leave:
+ switch (xiEnterEvent->event_type) {
+ case XCB_INPUT_ENTER:
+ case XCB_INPUT_LEAVE:
eventListener->handleXIEnterLeave(event);
break;
}
}
-#endif // XCB_USE_XINPUT22
}
bool QXcbConnection::xi2MouseEventsDisabled() const
@@ -651,7 +637,6 @@ bool QXcbConnection::xi2MouseEventsDisabled() const
return xi2MouseDisabled || has_xinerama_extension;
}
-#ifdef XCB_USE_XINPUT22
bool QXcbConnection::isTouchScreen(int id)
{
auto device = touchDeviceForId(id);
@@ -660,11 +645,11 @@ bool QXcbConnection::isTouchScreen(int id)
void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow)
{
- xXIDeviceEvent *xiDeviceEvent = static_cast<xXIDeviceEvent *>(xiDevEvent);
+ auto *xiDeviceEvent = reinterpret_cast<xcb_input_touch_begin_event_t *>(xiDevEvent);
TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
Q_ASSERT(dev);
const bool firstTouch = dev->touchPoints.isEmpty();
- if (xiDeviceEvent->evtype == XI_TouchBegin) {
+ if (xiDeviceEvent->event_type == XCB_INPUT_TOUCH_BEGIN) {
QWindowSystemInterface::TouchPoint tp;
tp.id = xiDeviceEvent->detail % INT_MAX;
tp.state = Qt::TouchPointPressed;
@@ -735,7 +720,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
y = touchPoint.area.center().y();
ny = y / screen->geometry().height();
}
- if (xiDeviceEvent->evtype != XI_TouchEnd) {
+ if (xiDeviceEvent->event_type != XCB_INPUT_TOUCH_END) {
if (!dev->providesTouchOrientation) {
if (w == 0.0)
w = touchPoint.area.width();
@@ -750,8 +735,8 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
}
}
- switch (xiDeviceEvent->evtype) {
- case XI_TouchBegin:
+ switch (xiDeviceEvent->event_type) {
+ case XCB_INPUT_TOUCH_BEGIN:
if (firstTouch) {
dev->firstPressedPosition = QPointF(x, y);
dev->firstPressedNormalPosition = QPointF(nx, ny);
@@ -761,14 +746,12 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
// Touches must be accepted when we are grabbing touch events. Otherwise the entire sequence
// will get replayed when the grab ends.
if (m_xiGrab) {
- // Note that XIAllowTouchEvents is known to deadlock with older libXi versions,
- // for details see qtbase/src/plugins/platforms/xcb/README. This has nothing to
- // do with the XInput protocol version, but is a bug in libXi implementation instead.
- XIAllowTouchEvents(static_cast<Display *>(m_xlib_display), xiDeviceEvent->deviceid,
- xiDeviceEvent->detail, xiDeviceEvent->event, XIAcceptTouch);
+ xcb_input_xi_allow_events(m_connection, XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
+ XCB_INPUT_EVENT_MODE_ACCEPT_TOUCH,
+ xiDeviceEvent->detail, xiDeviceEvent->event);
}
break;
- case XI_TouchUpdate:
+ case XCB_INPUT_TOUCH_UPDATE:
if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
@@ -789,14 +772,15 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
xiDeviceEvent->detail == m_startSystemMoveResizeInfo.pointid) {
QXcbWindow *window = platformWindowFromId(m_startSystemMoveResizeInfo.window);
if (window) {
- XIAllowTouchEvents(static_cast<Display *>(m_xlib_display), xiDeviceEvent->deviceid,
- xiDeviceEvent->detail, xiDeviceEvent->event, XIRejectTouch);
+ xcb_input_xi_allow_events(m_connection, XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
+ XCB_INPUT_EVENT_MODE_REJECT_TOUCH,
+ xiDeviceEvent->detail, xiDeviceEvent->event);
window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.corner);
m_startSystemMoveResizeInfo.window = XCB_NONE;
}
}
break;
- case XI_TouchEnd:
+ case XCB_INPUT_TOUCH_END:
touchPoint.state = Qt::TouchPointReleased;
if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
@@ -814,7 +798,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents) << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition <<
" area " << touchPoint.area << " pressure " << touchPoint.pressure;
- Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
+ Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiDeviceEvent->time, dev->qtTouchDevice, dev->touchPoints.values(), modifiers);
if (touchPoint.state == Qt::TouchPointReleased)
// If a touchpoint was released, we can forget it, because the ID won't be reused.
@@ -845,46 +829,46 @@ bool QXcbConnection::startSystemMoveResizeForTouchBegin(xcb_window_t window, con
}
return false;
}
-#endif // XCB_USE_XINPUT22
bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
{
- Display *xDisplay = static_cast<Display *>(xlib_display());
bool ok = false;
if (grab) { // grab
- XIEventMask evmask;
- unsigned char mask[XIMaskLen(XI_LASTEVENT)];
- evmask.mask = mask;
- evmask.mask_len = sizeof(mask);
- memset(mask, 0, sizeof(mask));
- XISetMask(mask, XI_ButtonPress);
- XISetMask(mask, XI_ButtonRelease);
- XISetMask(mask, XI_Motion);
- XISetMask(mask, XI_Enter);
- XISetMask(mask, XI_Leave);
- XISetMask(mask, XI_TouchBegin);
- XISetMask(mask, XI_TouchUpdate);
- XISetMask(mask, XI_TouchEnd);
+ uint32_t mask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS
+ | XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE
+ | XCB_INPUT_XI_EVENT_MASK_MOTION
+ | XCB_INPUT_XI_EVENT_MASK_ENTER
+ | XCB_INPUT_XI_EVENT_MASK_LEAVE
+ | XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN
+ | XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE
+ | XCB_INPUT_XI_EVENT_MASK_TOUCH_END;
for (int id : m_xiMasterPointerIds) {
- evmask.deviceid = id;
- Status result = XIGrabDevice(xDisplay, id, w, CurrentTime, None,
- XIGrabModeAsync, XIGrabModeAsync, False, &evmask);
- if (result != Success) {
+ xcb_generic_error_t *error = nullptr;
+ auto cookie = xcb_input_xi_grab_device(m_connection, w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id,
+ XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC,
+ false, 1, &mask);
+ auto *reply = xcb_input_xi_grab_device_reply(m_connection, cookie, &error);
+ if (error) {
qCDebug(lcQpaXInput, "failed to grab events for device %d on window %x"
- "(result %d)", id, w, result);
+ "(error code %d)", id, w, error->error_code);
+ free(error);
} else {
// Managed to grab at least one of master pointers, that should be enough
// to properly dismiss windows that rely on mouse grabbing.
ok = true;
}
+ free(reply);
}
} else { // ungrab
for (int id : m_xiMasterPointerIds) {
- Status result = XIUngrabDevice(xDisplay, id, CurrentTime);
- if (result != Success)
- qCDebug(lcQpaXInput, "XIUngrabDevice failed - id: %d (result %d)", id, result);
+ auto cookie = xcb_input_xi_ungrab_device_checked(m_connection, XCB_CURRENT_TIME, id);
+ xcb_generic_error_t *error = xcb_request_check(m_connection, cookie);
+ if (error) {
+ qCDebug(lcQpaXInput, "XIUngrabDevice failed - id: %d (error code %d)", id, error->error_code);
+ free(error);
+ }
}
// XIUngrabDevice does not seem to wait for a reply from X server (similar to
// xcb_ungrab_pointer). Ungrabbing won't fail, unless NoSuchExtension error
@@ -901,9 +885,9 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
void QXcbConnection::xi2HandleHierarchyEvent(void *event)
{
- xXIHierarchyEvent *xiEvent = reinterpret_cast<xXIHierarchyEvent *>(event);
+ auto *xiEvent = reinterpret_cast<xcb_input_hierarchy_event_t *>(event);
// We only care about hotplugged devices
- if (!(xiEvent->flags & (XISlaveRemoved | XISlaveAdded)))
+ if (!(xiEvent->flags & (XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED | XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED)))
return;
xi2SetupDevices();
@@ -920,23 +904,19 @@ void QXcbConnection::xi2HandleHierarchyEvent(void *event)
void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
{
- xXIDeviceChangedEvent *xiEvent = reinterpret_cast<xXIDeviceChangedEvent *>(event);
+ auto *xiEvent = reinterpret_cast<xcb_input_device_changed_event_t *>(event);
switch (xiEvent->reason) {
- case XIDeviceChange: {
- int nrDevices = 0;
- Display *dpy = static_cast<Display *>(m_xlib_display);
- XIDeviceInfo* deviceInfo = XIQueryDevice(dpy, xiEvent->sourceid, &nrDevices);
- if (nrDevices <= 0)
+ case XCB_INPUT_CHANGE_REASON_DEVICE_CHANGE: {
+ auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, xiEvent->sourceid);
+ if (!reply || reply->num_infos <= 0)
return;
- xi2SetupDevice(deviceInfo);
- XIFreeDeviceInfo(deviceInfo);
+ auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
+ xi2SetupDevice(it.data);
break;
}
- case XISlaveSwitch: {
-#ifdef XCB_USE_XINPUT21
+ case XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH: {
if (ScrollingDevice *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid))
xi2UpdateScrollingDevice(*scrollingDevice);
-#endif
break;
}
default:
@@ -945,28 +925,28 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
}
}
-#ifdef XCB_USE_XINPUT21
void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice)
{
- int nrDevices = 0;
- Display *dpy = static_cast<Display *>(m_xlib_display);
- XIDeviceInfo* deviceInfo = XIQueryDevice(dpy, scrollingDevice.deviceId, &nrDevices);
- if (nrDevices <= 0) {
+ auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, scrollingDevice.deviceId);
+ if (!reply || reply->num_infos <= 0) {
qCDebug(lcQpaXInputDevices, "scrolling device %d no longer present", scrollingDevice.deviceId);
return;
}
QPointF lastScrollPosition;
if (lcQpaXInputEvents().isDebugEnabled())
lastScrollPosition = scrollingDevice.lastScrollPosition;
- for (int c = 0; c < deviceInfo->num_classes; ++c) {
- XIAnyClassInfo *classInfo = deviceInfo->classes[c];
- if (classInfo->type == XIValuatorClass) {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classInfo);
+
+ xcb_input_xi_device_info_t *deviceInfo = xcb_input_xi_query_device_infos_iterator(reply.get()).data;
+ auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
+ for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
+ xcb_input_device_class_t *classInfo = classes_it.data;
+ if (classInfo->type == XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR) {
+ auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classInfo);
const int valuatorAtom = qatom(vci->label);
if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
- scrollingDevice.lastScrollPosition.setX(vci->value);
+ scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value));
else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
- scrollingDevice.lastScrollPosition.setY(vci->value);
+ scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value));
}
}
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice.lastScrollPosition))
@@ -974,8 +954,6 @@ void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice)
lastScrollPosition.x(), lastScrollPosition.y(),
scrollingDevice.lastScrollPosition.x(),
scrollingDevice.lastScrollPosition.y());
-
- XIFreeDeviceInfo(deviceInfo);
}
void QXcbConnection::xi2UpdateScrollingDevices()
@@ -998,10 +976,9 @@ QXcbConnection::ScrollingDevice *QXcbConnection::scrollingDeviceForId(int id)
void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice)
{
- xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
+ auto *xiDeviceEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
- if (xiEvent->evtype == XI_Motion && scrollingDevice.orientations) {
- xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
+ if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice.orientations) {
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
QPoint rawDelta;
QPoint angleDelta;
@@ -1035,16 +1012,15 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
if (!angleDelta.isNull()) {
QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
- Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
+ Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
if (modifiers & Qt::AltModifier) {
std::swap(angleDelta.rx(), angleDelta.ry());
std::swap(rawDelta.rx(), rawDelta.ry());
}
- QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers);
+ QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, rawDelta, angleDelta, modifiers);
}
}
- } else if (xiEvent->evtype == XI_ButtonRelease && scrollingDevice.legacyOrientations) {
- xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
+ } else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice.legacyOrientations) {
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
QPoint angleDelta;
if (scrollingDevice.legacyOrientations & Qt::Vertical) {
@@ -1062,15 +1038,14 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
if (!angleDelta.isNull()) {
QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
- Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
+ Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry());
- QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, QPoint(), angleDelta, modifiers);
+ QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, QPoint(), angleDelta, modifiers);
}
}
}
}
-#endif // XCB_USE_XINPUT21
static int xi2ValuatorOffset(const unsigned char *maskPtr, int maskLen, int number)
{
@@ -1093,10 +1068,10 @@ static int xi2ValuatorOffset(const unsigned char *maskPtr, int maskLen, int numb
bool QXcbConnection::xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value)
{
- const xXIDeviceEvent *xideviceevent = static_cast<const xXIDeviceEvent *>(event);
- const unsigned char *buttonsMaskAddr = (const unsigned char*)&xideviceevent[1];
- const unsigned char *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
- FP3232 *valuatorsValuesAddr = (FP3232*)(valuatorsMaskAddr + xideviceevent->valuators_len * 4);
+ auto *xideviceevent = static_cast<const qt_xcb_input_device_event_t *>(event);
+ auto *buttonsMaskAddr = reinterpret_cast<const unsigned char *>(&xideviceevent[1]);
+ auto *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
+ auto *valuatorsValuesAddr = reinterpret_cast<const xcb_input_fp3232_t *>(valuatorsMaskAddr + xideviceevent->valuators_len * 4);
int valuatorOffset = xi2ValuatorOffset(valuatorsMaskAddr, xideviceevent->valuators_len, valuatorNum);
if (valuatorOffset < 0)
@@ -1107,15 +1082,6 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(const void *event, int valuatorNum
return true;
}
-void QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event)
-{
- // xcb event structs contain stuff that wasn't on the wire, the full_sequence field
- // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes.
- // Move this data back to have the same layout in memory as it was on the wire
- // and allow casting, overwriting the full_sequence field.
- memmove((char*) event + 32, (char*) event + 36, event->length * 4);
-}
-
Qt::MouseButton QXcbConnection::xiToQtMouseButton(uint32_t b)
{
switch (b) {
@@ -1179,31 +1145,29 @@ static const char *pointerTypeName(QTabletEvent::PointerType ptype) {
bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletData)
{
bool handled = true;
- Display *xDisplay = static_cast<Display *>(m_xlib_display);
- const xXIGenericDeviceEvent *xiEvent = static_cast<const xXIGenericDeviceEvent *>(event);
- const xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<const xXIDeviceEvent *>(xiEvent);
+ const auto *xiDeviceEvent = reinterpret_cast<const qt_xcb_input_device_event_t *>(event);
- switch (xiEvent->evtype) {
- case XI_ButtonPress: {
+ switch (xiDeviceEvent->event_type) {
+ case XCB_INPUT_BUTTON_PRESS: {
Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
tabletData->buttons |= b;
- xi2ReportTabletEvent(xiEvent, tabletData);
+ xi2ReportTabletEvent(event, tabletData);
break;
}
- case XI_ButtonRelease: {
+ case XCB_INPUT_BUTTON_RELEASE: {
Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
tabletData->buttons ^= b;
- xi2ReportTabletEvent(xiEvent, tabletData);
+ xi2ReportTabletEvent(event, tabletData);
break;
}
- case XI_Motion:
- xi2ReportTabletEvent(xiEvent, tabletData);
+ case XCB_INPUT_MOTION:
+ xi2ReportTabletEvent(event, tabletData);
break;
- case XI_PropertyEvent: {
+ case XCB_INPUT_PROPERTY: {
// This is the wacom driver's way of reporting tool proximity.
// The evdev driver doesn't do it this way.
- const xXIPropertyEvent *ev = reinterpret_cast<const xXIPropertyEvent *>(event);
- if (ev->what == XIPropertyModified) {
+ const auto *ev = reinterpret_cast<const xcb_input_property_event_t *>(event);
+ if (ev->what == XCB_INPUT_PROPERTY_FLAG_MODIFIED) {
if (ev->property == atom(QXcbAtom::WacomSerialIDs)) {
enum WacomSerialIndex {
_WACSER_USB_ID = 0,
@@ -1213,15 +1177,12 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
_WACSER_TOOL_ID,
_WACSER_COUNT
};
- Atom propType;
- int propFormat;
- unsigned long numItems, bytesAfter;
- unsigned char *data;
- if (XIGetProperty(xDisplay, tabletData->deviceId, ev->property, 0, 100,
- 0, AnyPropertyType, &propType, &propFormat,
- &numItems, &bytesAfter, &data) == Success) {
- if (propType == atom(QXcbAtom::INTEGER) && propFormat == 32 && numItems == _WACSER_COUNT) {
- quint32 *ptr = reinterpret_cast<quint32 *>(data);
+
+ auto reply = Q_XCB_REPLY(xcb_input_xi_get_property, m_connection, tabletData->deviceId, 0,
+ ev->property, XCB_GET_PROPERTY_TYPE_ANY, 0, 100);
+ if (reply) {
+ if (reply->type == atom(QXcbAtom::INTEGER) && reply->format == 32 && reply->num_items == _WACSER_COUNT) {
+ quint32 *ptr = reinterpret_cast<quint32 *>(xcb_input_xi_get_property_items(reply.get()));
quint32 tool = ptr[_WACSER_TOOL_ID];
// Workaround for http://sourceforge.net/p/linuxwacom/bugs/246/
// e.g. on Thinkpad Helix, tool ID will be 0 and serial will be 1
@@ -1253,7 +1214,6 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
tabletData->deviceId, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], toolName(tabletData->tool));
}
- XFree(data);
}
}
}
@@ -1269,12 +1229,12 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletData)
{
- const xXIDeviceEvent *ev = reinterpret_cast<const xXIDeviceEvent *>(event);
+ auto *ev = reinterpret_cast<const qt_xcb_input_device_event_t *>(event);
QXcbWindow *xcbWindow = platformWindowFromId(ev->event);
if (!xcbWindow)
return;
QWindow *window = xcbWindow->window();
- const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective_mods);
+ const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective);
QPointF local(fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y));
QPointF global(fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y));
double pressure = 0, rotation = 0, tangentialPressure = 0;
@@ -1317,7 +1277,7 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD
qCDebug(lcQpaXInputEvents, "XI2 event on tablet %d with tool %s type %s seq %d detail %d time %d "
"pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf modifiers 0x%x",
tabletData->deviceId, toolName(tabletData->tool), pointerTypeName(tabletData->pointerType),
- ev->sequenceNumber, ev->detail, ev->time,
+ ev->sequence, ev->detail, ev->time,
local.x(), local.y(), global.x(), global.y(),
(int)tabletData->buttons, pressure, xTilt, yTilt, rotation, (int)modifiers);
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 471287eb44..143ea799b0 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -65,12 +65,12 @@
#if QT_CONFIG(xcb_xlib)
#include <X11/Xlib.h>
+#endif
#if QT_CONFIG(xcb_native_painting)
#include "qxcbnativepainting.h"
#include "qpixmap_x11_p.h"
#include "qbackingstore_x11_p.h"
#endif
-#endif
#include <qpa/qplatforminputcontextfactory_p.h>
#include <private/qgenericunixthemes_p.h>
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index e4551b0139..d9cddef2d2 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -52,10 +52,8 @@
#include <xkbcommon/xkbcommon-keysyms.h>
-#if QT_CONFIG(xinput2)
-#include <X11/extensions/XI2proto.h>
-#undef KeyPress
-#undef KeyRelease
+#if QT_CONFIG(xcb_xinput)
+#include <xcb/xinput.h>
#endif
QT_BEGIN_NAMESPACE
@@ -824,20 +822,20 @@ void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
}
}
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
{
if (m_config && !connection()->hasXKB()) {
- xXIModifierInfo *mods = static_cast<xXIModifierInfo *>(modInfo);
- xXIGroupInfo *group = static_cast<xXIGroupInfo *>(groupInfo);
+ auto *mods = static_cast<xcb_input_modifier_info_t *>(modInfo);
+ auto *group = static_cast<xcb_input_group_info_t *>(groupInfo);
const xkb_state_component changedComponents
= xkb_state_update_mask(m_xkbState.get(),
- mods->base_mods,
- mods->latched_mods,
- mods->locked_mods,
- group->base_group,
- group->latched_group,
- group->locked_group);
+ mods->base,
+ mods->latched,
+ mods->locked,
+ group->base,
+ group->latched,
+ group->locked);
handleStateChanges(changedComponents);
}
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index c131d69267..ab926eab84 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -74,7 +74,7 @@ public:
void updateXKBMods();
xkb_mod_mask_t xkbModMask(quint16 state);
void updateXKBStateFromCore(quint16 state);
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
void updateXKBStateFromXI(void *modInfo, void *groupInfo);
#endif
#if QT_CONFIG(xkb)
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index f87da28ee0..01eb88eea7 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -68,6 +68,9 @@
#undef class
#include <xcb/xfixes.h>
#include <xcb/shape.h>
+#if QT_CONFIG(xcb_xinput)
+#include <xcb/xinput.h>
+#endif
// xcb-icccm 3.8 support
#ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
@@ -105,11 +108,6 @@
#include <X11/Xutil.h>
#endif
-#if QT_CONFIG(xinput2)
-#include <X11/extensions/XInput2.h>
-#include <X11/extensions/XI2proto.h>
-#endif
-
#define XCOORD_MAX 16383
enum {
defaultWindowWidth = 160,
@@ -520,7 +518,7 @@ void QXcbWindow::create()
atom(QXcbAtom::_XEMBED_INFO),
32, 2, (void *)data);
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (connection()->hasXInput2()) {
if (connection()->xi2MouseEventsDisabled())
connection()->xi2SelectDeviceEventsCompatibility(m_window);
@@ -2145,7 +2143,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
QPoint global(root_x, root_y);
if (isWheel) {
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (!connection()->isAtLeastXI21()) {
#endif
QPoint angleDelta;
@@ -2160,7 +2158,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry());
QWindowSystemInterface::handleWheelEvent(window(), timestamp, local, global, QPoint(), angleDelta, modifiers);
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
}
#endif
return;
@@ -2200,7 +2198,7 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
if (conn) {
const bool mouseButtonsPressed = (conn->buttonState() != Qt::NoButton);
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
return mouseButtonsPressed || (conn->hasXInput2() && !conn->xi2MouseEventsDisabled());
#else
return mouseButtonsPressed;
@@ -2249,7 +2247,7 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
quint8 mode, quint8 detail, xcb_timestamp_t timestamp)
{
connection()->setTime(timestamp);
-#ifdef XCB_USE_XINPUT21
+#if QT_CONFIG(xcb_xinput)
// Updates scroll valuators, as user might have done some scrolling outside our X client.
connection()->xi2UpdateScrollingDevices();
#endif
@@ -2326,16 +2324,18 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
event->time, QEvent::MouseMove);
}
-#if QT_CONFIG(xinput2)
-static inline int fixed1616ToInt(FP1616 val)
+#if QT_CONFIG(xcb_xinput)
+static inline int fixed1616ToInt(xcb_input_fp1616_t val)
{
return int(qreal(val) / 0x10000);
}
+#define qt_xcb_mask_is_set(ptr, event) (((unsigned char*)(ptr))[(event)>>3] & (1 << ((event) & 7)))
+
void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource source)
{
QXcbConnection *conn = connection();
- xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event);
+ auto *ev = reinterpret_cast<xcb_input_button_press_event_t *>(event);
if (ev->buttons_len > 0) {
unsigned char *buttonMask = (unsigned char *) &ev[1];
@@ -2343,16 +2343,16 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource
// XIPointerEmulated being set: https://bugs.freedesktop.org/show_bug.cgi?id=98188
// Filter them out by other attributes: when their source device is a touch screen
// and the LMB is pressed.
- if (XIMaskIsSet(buttonMask, 1) && conn->isTouchScreen(ev->sourceid)) {
+ if (qt_xcb_mask_is_set(buttonMask, 1) && conn->isTouchScreen(ev->sourceid)) {
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInput, "XI2 mouse event from touch device %d was ignored", ev->sourceid);
return;
}
for (int i = 1; i <= 15; ++i)
- conn->setButtonState(conn->translateMouseButton(i), XIMaskIsSet(buttonMask, i));
+ conn->setButtonState(conn->translateMouseButton(i), qt_xcb_mask_is_set(buttonMask, i));
}
- const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective_mods);
+ const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective);
const int event_x = fixed1616ToInt(ev->event_x);
const int event_y = fixed1616ToInt(ev->event_y);
const int root_x = fixed1616ToInt(ev->root_x);
@@ -2369,47 +2369,47 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource
sourceName = me.valueToKey(source);
}
- switch (ev->evtype) {
- case XI_ButtonPress:
+ switch (ev->event_type) {
+ case XCB_INPUT_BUTTON_PRESS:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, true);
handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source);
break;
- case XI_ButtonRelease:
+ case XCB_INPUT_BUTTON_RELEASE:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, false);
handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source);
break;
- case XI_Motion:
+ case XCB_INPUT_MOTION:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse motion %d,%d, time %d, source %s", event_x, event_y, ev->time, sourceName);
handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, QEvent::MouseMove, source);
break;
default:
- qWarning() << "Unrecognized XI2 mouse event" << ev->evtype;
+ qWarning() << "Unrecognized XI2 mouse event" << ev->event_type;
break;
}
}
void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event)
{
- xXIEnterEvent *ev = reinterpret_cast<xXIEnterEvent *>(event);
+ auto *ev = reinterpret_cast<xcb_input_enter_event_t *>(event);
// Compare the window with current mouse grabber to prevent deliver events to any other windows.
// If leave event occurs and the window is under mouse - allow to deliver the leave event.
QXcbWindow *mouseGrabber = connection()->mouseGrabber();
if (mouseGrabber && mouseGrabber != this
- && (ev->evtype != XI_Leave || QGuiApplicationPrivate::currentMouseWindow != window())) {
+ && (ev->event_type != XCB_INPUT_LEAVE || QGuiApplicationPrivate::currentMouseWindow != window())) {
return;
}
const int root_x = fixed1616ToInt(ev->root_x);
const int root_y = fixed1616ToInt(ev->root_y);
- switch (ev->evtype) {
- case XI_Enter: {
+ switch (ev->event_type) {
+ case XCB_INPUT_ENTER: {
const int event_x = fixed1616ToInt(ev->event_x);
const int event_y = fixed1616ToInt(ev->event_y);
qCDebug(lcQpaXInputEvents, "XI2 mouse enter %d,%d, mode %d, detail %d, time %d",
@@ -2417,7 +2417,7 @@ void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event)
handleEnterNotifyEvent(event_x, event_y, root_x, root_y, ev->mode, ev->detail, ev->time);
break;
}
- case XI_Leave:
+ case XCB_INPUT_LEAVE:
qCDebug(lcQpaXInputEvents, "XI2 mouse leave, mode %d, detail %d, time %d",
ev->mode, ev->detail, ev->time);
connection()->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group);
@@ -2559,7 +2559,7 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
if (grab && !connection()->canGrab())
return false;
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (connection()->hasXInput2() && !connection()->xi2MouseEventsDisabled()) {
bool result = connection()->xi2SetMouseGrabEnabled(m_window, grab);
if (grab && result)
@@ -2632,7 +2632,7 @@ bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int corner)
if (!connection()->wmSupport()->isSupportedByWM(moveResize))
return false;
const QPoint globalPos = QHighDpi::toNativePixels(window()->mapToGlobal(pos), window()->screen());
-#ifdef XCB_USE_XINPUT22
+#if QT_CONFIG(xcb_xinput)
if (connection()->startSystemMoveResizeForTouchBegin(m_window, globalPos, corner))
return true;
#endif
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index cb8af9e666..edfee1f574 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -137,7 +137,7 @@ public:
void handleFocusInEvent(const xcb_focus_in_event_t *event) override;
void handleFocusOutEvent(const xcb_focus_out_event_t *event) override;
void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override;
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized) override;
void handleXIEnterLeave(xcb_ge_event_t *) override;
#endif
diff --git a/src/plugins/platforms/xcb/xcb-static/xcb-static.pro b/src/plugins/platforms/xcb/xcb-static/xcb-static.pro
index 20d8b83e7c..078b275381 100644
--- a/src/plugins/platforms/xcb/xcb-static/xcb-static.pro
+++ b/src/plugins/platforms/xcb/xcb-static/xcb-static.pro
@@ -2,7 +2,7 @@
# Statically compile in code for
# libxcb-fixes, libxcb-randr, libxcb-shm, libxcb-sync, libxcb-image,
# libxcb-keysyms, libxcb-icccm, libxcb-renderutil, libxcb-xkb,
-# libxcb-xinerama
+# libxcb-xinerama, libxcb-xinput
#
CONFIG += static
@@ -29,7 +29,8 @@ SOURCES += \
$$LIBXCB_DIR/render.c \
$$LIBXCB_DIR/shape.c \
$$LIBXCB_DIR/xkb.c \
- $$LIBXCB_DIR/xinerama.c
+ $$LIBXCB_DIR/xinerama.c \
+ $$LIBXCB_DIR/xinput.c
#
# xcb-util
diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
index ffc8a29116..d71aacbf96 100644
--- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro
+++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
@@ -55,11 +55,10 @@ DEFINES += QT_BUILD_XCB_PLUGIN
qtConfig(xcb-xlib) {
QMAKE_USE += xcb_xlib
+}
- qtConfig(xinput2) {
- SOURCES += qxcbconnection_xi2.cpp
- QMAKE_USE += xinput2
- }
+qtConfig(xcb-xinput) {
+ SOURCES += qxcbconnection_xi2.cpp
}
qtConfig(xcb-sm) {
@@ -86,6 +85,7 @@ qtConfig(vulkan) {
} else {
qtConfig(xkb): QMAKE_USE += xcb_xkb
qtConfig(xcb-render): QMAKE_USE += xcb_render
+ qtConfig(xcb-xinput): QMAKE_USE += xcb_xinput
QMAKE_USE += xcb_syslibs
}
diff --git a/src/plugins/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp
index 6c29a99705..c9683eb99d 100644
--- a/src/plugins/printsupport/cups/qcupsprintengine.cpp
+++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp
@@ -104,7 +104,11 @@ void QCupsPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &v
break;
case PPK_QPageLayout: {
QPageLayout pageLayout = value.value<QPageLayout>();
- if (pageLayout.isValid() && (d->m_printDevice.isValidPageLayout(pageLayout, d->resolution) || d->m_printDevice.supportsCustomPageSizes())) {
+ if (pageLayout.isValid() && (d->m_printDevice.isValidPageLayout(pageLayout, d->resolution)
+ || d->m_printDevice.supportsCustomPageSizes()
+ || d->m_printDevice.supportedPageSizes().isEmpty())) {
+ // supportedPageSizes().isEmpty() because QPageSetupWidget::initPageSizes says
+ // "If no available printer page sizes, populate with all page sizes"
d->m_pageLayout = pageLayout;
d->setPageSize(pageLayout.pageSize());
}
@@ -132,6 +136,9 @@ QVariant QCupsPrintEngine::property(PrintEnginePropertyKey key) const
case PPK_CupsOptions:
ret = d->cupsOptions;
break;
+ case PPK_Duplex:
+ ret = d->duplex;
+ break;
default:
ret = QPdfPrintEngine::property(key);
break;
@@ -140,7 +147,9 @@ QVariant QCupsPrintEngine::property(PrintEnginePropertyKey key) const
}
-QCupsPrintEnginePrivate::QCupsPrintEnginePrivate(QPrinter::PrinterMode m) : QPdfPrintEnginePrivate(m)
+QCupsPrintEnginePrivate::QCupsPrintEnginePrivate(QPrinter::PrinterMode m)
+ : QPdfPrintEnginePrivate(m)
+ , duplex(QPrint::DuplexNone)
{
}
diff --git a/src/plugins/printsupport/cups/qcupsprintengine_p.h b/src/plugins/printsupport/cups/qcupsprintengine_p.h
index d5363bb8cc..2a1a83b9d7 100644
--- a/src/plugins/printsupport/cups/qcupsprintengine_p.h
+++ b/src/plugins/printsupport/cups/qcupsprintengine_p.h
@@ -99,6 +99,7 @@ private:
QPrintDevice m_printDevice;
QStringList cupsOptions;
QString cupsTempFile;
+ QPrint::DuplexMode duplex;
};
QT_END_NAMESPACE
diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp
index 340b1a1ff4..d2ddc4144f 100644
--- a/src/plugins/printsupport/cups/qppdprintdevice.cpp
+++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp
@@ -50,13 +50,6 @@
QT_BEGIN_NAMESPACE
-QPpdPrintDevice::QPpdPrintDevice()
- : QPlatformPrintDevice(),
- m_cupsDest(0),
- m_ppd(0)
-{
-}
-
QPpdPrintDevice::QPpdPrintDevice(const QString &id)
: QPlatformPrintDevice(id),
m_cupsDest(0),
@@ -69,9 +62,26 @@ QPpdPrintDevice::QPpdPrintDevice(const QString &id)
m_cupsName = parts.at(0).toUtf8();
if (parts.size() > 1)
m_cupsInstance = parts.at(1).toUtf8();
- loadPrinter();
- if (m_cupsDest && m_ppd) {
+ // Get the print instance and PPD file
+ m_cupsDest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, m_cupsName, m_cupsInstance.isNull() ? nullptr : m_cupsInstance.constData());
+ if (m_cupsDest) {
+ const char *ppdFile = cupsGetPPD(m_cupsName);
+ if (ppdFile) {
+ m_ppd = ppdOpenFile(ppdFile);
+ unlink(ppdFile);
+ }
+ if (m_ppd) {
+ ppdMarkDefaults(m_ppd);
+ cupsMarkOptions(m_ppd, m_cupsDest->num_options, m_cupsDest->options);
+ ppdLocalize(m_ppd);
+
+ m_minimumPhysicalPageSize = QSize(m_ppd->custom_min[0], m_ppd->custom_min[1]);
+ m_maximumPhysicalPageSize = QSize(m_ppd->custom_max[0], m_ppd->custom_max[1]);
+ m_customMargins = QMarginsF(m_ppd->custom_margins[0], m_ppd->custom_margins[3],
+ m_ppd->custom_margins[2], m_ppd->custom_margins[1]);
+ }
+
m_name = printerOption("printer-info");
m_location = printerOption("printer-location");
m_makeAndModel = printerOption("printer-make-and-model");
@@ -87,10 +97,6 @@ QPpdPrintDevice::QPpdPrintDevice(const QString &id)
// Cups ppd_file_t variable_sizes custom_min custom_max
// PPD MaxMediaWidth MaxMediaHeight
m_supportsCustomPageSizes = type & CUPS_PRINTER_VARIABLE;
- m_minimumPhysicalPageSize = QSize(m_ppd->custom_min[0], m_ppd->custom_min[1]);
- m_maximumPhysicalPageSize = QSize(m_ppd->custom_max[0], m_ppd->custom_max[1]);
- m_customMargins = QMarginsF(m_ppd->custom_margins[0], m_ppd->custom_margins[3],
- m_ppd->custom_margins[2], m_ppd->custom_margins[1]);
}
}
}
@@ -107,7 +113,7 @@ QPpdPrintDevice::~QPpdPrintDevice()
bool QPpdPrintDevice::isValid() const
{
- return m_cupsDest && m_ppd;
+ return m_cupsDest;
}
bool QPpdPrintDevice::isDefault() const
@@ -152,8 +158,8 @@ void QPpdPrintDevice::loadPageSizes() const
}
}
}
- m_havePageSizes = true;
}
+ m_havePageSizes = true;
}
QPageSize QPpdPrintDevice::defaultPageSize() const
@@ -359,14 +365,18 @@ void QPpdPrintDevice::loadDuplexModes() const
ppd_option_t *duplexModes = ppdFindOption(m_ppd, "Duplex");
if (duplexModes) {
m_duplexModes.reserve(duplexModes->num_choices);
- for (int i = 0; i < duplexModes->num_choices; ++i)
- m_duplexModes.append(QPrintUtils::ppdChoiceToDuplexMode(duplexModes->choices[i].choice));
+ for (int i = 0; i < duplexModes->num_choices; ++i) {
+ if (ppdInstallableConflict(m_ppd, duplexModes->keyword, duplexModes->choices[i].choice) == 0) {
+ m_duplexModes.append(QPrintUtils::ppdChoiceToDuplexMode(duplexModes->choices[i].choice));
+ }
+ }
}
// If no result, try just the default
if (m_duplexModes.size() == 0) {
duplexModes = ppdFindOption(m_ppd, "DefaultDuplex");
- if (duplexModes)
+ if (duplexModes && (ppdInstallableConflict(m_ppd, duplexModes->keyword, duplexModes->choices[0].choice) == 0)) {
m_duplexModes.append(QPrintUtils::ppdChoiceToDuplexMode(duplexModes->choices[0].choice));
+ }
}
}
// If still no result, or not added in PPD, then add None
@@ -417,7 +427,7 @@ QPrint::ColorMode QPpdPrintDevice::defaultColorMode() const
ppd_option_t *colorModel = ppdFindOption(m_ppd, "DefaultColorModel");
if (!colorModel)
colorModel = ppdFindOption(m_ppd, "ColorModel");
- if (!colorModel || (colorModel && !qstrcmp(colorModel->defchoice, "Gray")))
+ if (!colorModel || qstrcmp(colorModel->defchoice, "Gray") != 0)
return QPrint::Color;
}
return QPrint::GrayScale;
@@ -481,38 +491,6 @@ void QPpdPrintDevice::loadMimeTypes() const
}
#endif
-void QPpdPrintDevice::loadPrinter()
-{
- // Just to be safe, check if existing printer needs closing
- if (m_ppd) {
- ppdClose(m_ppd);
- m_ppd = 0;
- }
- if (m_cupsDest) {
- cupsFreeDests(1, m_cupsDest);
- m_cupsDest = 0;
- }
-
- // Get the print instance and PPD file
- m_cupsDest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, m_cupsName, m_cupsInstance.isNull() ? nullptr : m_cupsInstance.constData());
- if (m_cupsDest) {
- const char *ppdFile = cupsGetPPD(m_cupsName);
- if (ppdFile) {
- m_ppd = ppdOpenFile(ppdFile);
- unlink(ppdFile);
- }
- if (m_ppd) {
- ppdMarkDefaults(m_ppd);
- cupsMarkOptions(m_ppd, m_cupsDest->num_options, m_cupsDest->options);
- ppdLocalize(m_ppd);
- } else {
- cupsFreeDests(1, m_cupsDest);
- m_cupsDest = 0;
- m_ppd = 0;
- }
- }
-}
-
QString QPpdPrintDevice::printerOption(const QString &key) const
{
return cupsGetOption(key.toUtf8(), m_cupsDest->num_options, m_cupsDest->options);
diff --git a/src/plugins/printsupport/cups/qppdprintdevice.h b/src/plugins/printsupport/cups/qppdprintdevice.h
index 9867083bd7..90f90d6788 100644
--- a/src/plugins/printsupport/cups/qppdprintdevice.h
+++ b/src/plugins/printsupport/cups/qppdprintdevice.h
@@ -65,7 +65,6 @@ QT_BEGIN_NAMESPACE
class QPpdPrintDevice : public QPlatformPrintDevice
{
public:
- QPpdPrintDevice();
explicit QPpdPrintDevice(const QString &id);
virtual ~QPpdPrintDevice();
@@ -105,7 +104,6 @@ protected:
#endif
private:
- void loadPrinter();
QString printerOption(const QString &key) const;
cups_ptype_e printerTypeFlags() const;
diff --git a/src/plugins/sqldrivers/configure.json b/src/plugins/sqldrivers/configure.json
index 234f880579..4802d3b04d 100644
--- a/src/plugins/sqldrivers/configure.json
+++ b/src/plugins/sqldrivers/configure.json
@@ -229,7 +229,7 @@ Oracle driver, as the current build will most likely fail."
"summary": [
{
- "section": "Qt Sql",
+ "section": "Qt Sql Drivers",
"entries": [
"sql-db2", "sql-ibase", "sql-mysql", "sql-oci", "sql-odbc", "sql-psql",
"sql-sqlite2", "sql-sqlite", "system-sqlite", "sql-tds"
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index 569eeef0ff..d37fdcb806 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -144,22 +144,12 @@ static QWindow *qt_getWindow(const QWidget *widget)
return widget ? widget->window()->windowHandle() : 0;
}
-@interface QT_MANGLE_NAMESPACE(NotificationReceiver) : NSObject {
-QMacStylePrivate *mPrivate;
-}
-- (id)initWithPrivate:(QMacStylePrivate *)priv;
-- (void)scrollBarStyleDidChange:(NSNotification *)notification;
+@interface QT_MANGLE_NAMESPACE(NotificationReceiver) : NSObject
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver);
@implementation NotificationReceiver
-- (id)initWithPrivate:(QMacStylePrivate *)priv
-{
- self = [super init];
- mPrivate = priv;
- return self;
-}
- (void)scrollBarStyleDidChange:(NSNotification *)notification
{
@@ -1927,7 +1917,7 @@ QMacStyle::QMacStyle()
Q_D(QMacStyle);
QMacAutoReleasePool pool;
- d->receiver = [[NotificationReceiver alloc] initWithPrivate:d];
+ d->receiver = [[NotificationReceiver alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:d->receiver
selector:@selector(scrollBarStyleDidChange:)
name:NSPreferredScrollerStyleDidChangeNotification
@@ -5891,7 +5881,7 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
switch (ct) {
#if QT_CONFIG(spinbox)
case CT_SpinBox:
- if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ if (qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
const int buttonWidth = 20; // FIXME Use subControlRect()
sz += QSize(buttonWidth, 0);
}
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
index 6add110249..bb110660a3 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
+++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
@@ -2171,12 +2171,12 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt
if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
if (!buttonVisible(subControl, tb))
return rect;
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
const bool isToolTitle = false;
const int height = tb->rect.height();
const int width = tb->rect.width();
const int buttonWidth =
- qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * QWindowsStylePrivate::nativeMetricScaleFactor(widget)
- - QStyleHelper::dpiScaled(4));
+ qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor - QStyleHelper::dpiScaled(4));
const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option, widget);
const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
@@ -2190,31 +2190,31 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt
rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
if (isToolTitle) {
if (sysmenuHint) {
- rect.adjust(0, 0, -buttonWidth - 3, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 3 * factor), 0);
}
if (minimizeHint || maximizeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
} else {
if (sysmenuHint) {
- const int leftOffset = height - 8;
- rect.adjust(leftOffset, 0, 0, 4);
+ const int leftOffset = int(height - 8 * factor);
+ rect.adjust(leftOffset, 0, 0, int(4 * factor));
}
if (minimizeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
if (maximizeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
if (contextHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
if (shadeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
}
- rect.translate(0, 2);
+ rect.translate(0, int(2 * factor));
rect = visualRect(option->direction, option->rect, rect);
break;
case SC_TitleBarSysMenu:
{
- const int controlTop = 6;
- const int controlHeight = height - controlTop - 3;
+ const int controlTop = int(6 * factor);
+ const int controlHeight = int(height - controlTop - 3 * factor);
int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent));
if (tb->icon.isNull())
@@ -2222,7 +2222,7 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt
int hPad = (controlHeight - iconSize.height())/2;
int vPad = (controlHeight - iconSize.width())/2;
rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height());
- rect.translate(0, 3);
+ rect.translate(0, int(3 * factor));
rect = visualRect(option->direction, option->rect, rect);
}
break;
diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
index 9d2e770191..e690a424ac 100644
--- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
+++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
@@ -494,7 +494,8 @@ bool QWindowsXPStylePrivate::isTransparent(XPThemeData &themeData)
QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData)
{
HRGN hRgn = 0;
- RECT rect = themeData.toRECT(themeData.rect);
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(themeData.widget);
+ RECT rect = themeData.toRECT(QRect(themeData.rect.topLeft() / factor, themeData.rect.size() / factor));
if (!SUCCEEDED(GetThemeBackgroundRegion(themeData.handle(), bufferHDC(), themeData.partId,
themeData.stateId, &rect, &hRgn))) {
return QRegion();
@@ -523,7 +524,7 @@ QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData)
RECT *r = reinterpret_cast<RECT*>(rd->Buffer);
for (uint i = 0; i < rd->rdh.nCount; ++i) {
QRect rect;
- rect.setCoords(r->left, r->top, r->right - 1, r->bottom - 1);
+ rect.setCoords(int(r->left * factor), int(r->top * factor), int((r->right - 1) * factor), int((r->bottom - 1) * factor));
++r;
region |= rect;
}
@@ -1756,9 +1757,9 @@ case PE_Frame:
else
stateId = FS_INACTIVE;
- int fwidth = frm->lineWidth + frm->midLineWidth;
+ int fwidth = int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
- XPThemeData theme(0, p, themeNumber, 0, stateId);
+ XPThemeData theme(widget, p, themeNumber, 0, stateId);
if (!theme.isValid())
break;
@@ -2949,6 +2950,7 @@ void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCo
{
if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option))
{
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
bool isActive = tb->titleBarState & QStyle::State_Active;
XPThemeData theme(widget, p, QWindowsXPStylePrivate::WindowTheme);
if (sub & SC_TitleBarLabel) {
@@ -2975,13 +2977,15 @@ void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCo
GetThemeColor(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
p->setPen(textShadow);
- p->drawText(ir.x() + 3, ir.y() + 2, ir.width() - 1, ir.height(),
+ p->drawText(int(ir.x() + 3 * factor), int(ir.y() + 2 * factor),
+ int(ir.width() - 1 * factor), ir.height(),
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
}
COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
p->setPen(textColor);
- p->drawText(ir.x() + 2, ir.y() + 1, ir.width() - 2, ir.height(),
+ p->drawText(int(ir.x() + 2 * factor), int(ir.y() + 1 * factor),
+ int(ir.width() - 2 * factor), ir.height(),
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
}
if (sub & SC_TitleBarSysMenu && tb->titleBarFlags & Qt::WindowSystemMenuHint) {