From 18f8a0ea8535039e922b3d5bd9430dd3de3a13a4 Mon Sep 17 00:00:00 2001
From: Liang Qi <liang.qi@qt.io>
Date: Thu, 15 Apr 2021 18:38:03 +0200
Subject: [PATCH] WIP: xcb: try to get mouse release in slave pointers

after QWindow::startSystemMove() and startSystemResize()

Abort the system move or resize when got mouse release event.

todo:
* need to check more about startSystemMove/Resize which is
triggered by touch events
* verify the behaviors on other wms.

Task-number: QTBUG-91077
Change-Id: I01e74a01c87b381ee7cd6f20d51a1fa61c0e98fc
---
 src/plugins/platforms/xcb/qxcbconnection.cpp  |  5 ++
 src/plugins/platforms/xcb/qxcbconnection.h    | 11 +++-
 .../platforms/xcb/qxcbconnection_xi2.cpp      | 59 ++++++++++++++++---
 src/plugins/platforms/xcb/qxcbwindow.cpp      |  5 ++
 4 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index c557109bd1..78eb7485ab 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -86,6 +86,7 @@ Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd")
 
 QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName)
     : QXcbBasicConnection(displayName)
+    , m_duringSystemMoveResize(false)
     , m_canGrabServer(canGrabServer)
     , m_defaultVisualId(defaultVisualId)
     , m_nativeInterface(nativeInterface)
@@ -557,6 +558,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
     }
     case XCB_BUTTON_RELEASE: {
         auto ev = reinterpret_cast<xcb_button_release_event_t *>(event);
+        if (m_duringSystemMoveResize && ev->root != XCB_NONE) {
+            qDebug() << "liang: aborted!";
+            abortSystemMoveResizeForTouch(ev->root);
+        }
         m_keyboard->updateXKBStateFromCore(ev->state);
         m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
         setButtonState(translateMouseButton(ev->detail), false);
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 8a4b577d2e..7fedd64bd9 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -230,10 +230,14 @@ public:
     bool xi2MouseEventsDisabled() const;
     Qt::MouseButton xiToQtMouseButton(uint32_t b);
     void xi2UpdateScrollingDevices();
-    bool startSystemMoveResizeForTouch(xcb_window_t window, int edges);
-    void abortSystemMoveResizeForTouch();
     bool isTouchScreen(int id);
 
+    bool startSystemMoveResizeForTouch(xcb_window_t window, int edges);
+    void abortSystemMoveResizeForTouch(xcb_window_t window);
+    bool isDuringSystemMoveResize() const;
+    void setDuringSystemMoveResize(bool during);
+    void setStartSystemMoveResizeInfo(xcb_window_t window, int devid, int pointid, int edges);
+
     bool canGrab() const { return m_canGrabServer; }
 
     QXcbGlIntegration *glIntegration() const;
@@ -330,12 +334,14 @@ private:
     static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);
 
     QHash<int, TouchDeviceData> m_touchDevices;
+
     struct StartSystemMoveResizeInfo {
         xcb_window_t window = XCB_NONE;
         uint16_t deviceid;
         uint32_t pointid;
         int edges;
     } m_startSystemMoveResizeInfo;
+    bool m_duringSystemMoveResize;
 
     const bool m_canGrabServer;
     const xcb_visualid_t m_defaultVisualId;
@@ -374,6 +380,7 @@ private:
     mutable bool m_glIntegrationInitialized = false;
     bool m_xiGrab = false;
     QVector<int> m_xiMasterPointerIds;
+    QVector<int> m_xiSlavePointerIds;
 
     xcb_window_t m_qtSelectionOwner = 0;
 
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 27a2526df1..de4fd34019 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -88,7 +88,7 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
     }
 
     qt_xcb_input_event_mask_t mask;
-    mask.header.deviceid = XCB_INPUT_DEVICE_ALL_MASTER;
+    mask.header.deviceid = XCB_INPUT_DEVICE_ALL;
     mask.header.mask_len = 1;
     mask.mask = bitMask;
     xcb_void_cookie_t cookie =
@@ -303,8 +303,10 @@ void QXcbConnection::xi2SetupDevices()
             continue;
         }
         // only slave pointer devices are relevant here
-        if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER)
+        if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER) {
+            m_xiSlavePointerIds.append(deviceInfo->deviceid);
             xi2SetupDevice(deviceInfo, false);
+        }
     }
 
     if (m_xiMasterPointerIds.size() > 1)
@@ -522,6 +524,16 @@ static inline qreal fixed1616ToReal(xcb_input_fp1616_t val)
 void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
 {
     auto *xiEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
+    if (m_xiSlavePointerIds.contains(xiEvent->deviceid)) {
+        if (!m_duringSystemMoveResize)
+            return;
+        if (xiEvent->event_type == XCB_INPUT_BUTTON_RELEASE
+            && xiEvent->detail == XCB_BUTTON_INDEX_1
+            && xiEvent->event != XCB_NONE) {
+            qDebug() << "liang: aborted!";
+            abortSystemMoveResizeForTouch(xiEvent->event);
+        }
+    }
     int sourceDeviceId = xiEvent->deviceid; // may be the master id
     qt_xcb_input_device_event_t *xiDeviceEvent = nullptr;
     xcb_input_enter_event_t *xiEnterEvent = nullptr;
@@ -795,10 +807,7 @@ bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window, int edge
             for (; pointIt != deviceData.touchPoints.constEnd(); ++pointIt) {
                 Qt::TouchPointState state = pointIt.value().state;
                 if (state == Qt::TouchPointMoved || state == Qt::TouchPointPressed || state == Qt::TouchPointStationary) {
-                    m_startSystemMoveResizeInfo.window = window;
-                    m_startSystemMoveResizeInfo.deviceid = devIt.key();
-                    m_startSystemMoveResizeInfo.pointid = pointIt.key();
-                    m_startSystemMoveResizeInfo.edges = edges;
+                    setStartSystemMoveResizeInfo(window, devIt.key(), pointIt.key(), edges);
                     return true;
                 }
             }
@@ -807,9 +816,45 @@ bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window, int edge
     return false;
 }
 
-void QXcbConnection::abortSystemMoveResizeForTouch()
+void QXcbConnection::abortSystemMoveResizeForTouch(xcb_window_t window)
 {
     m_startSystemMoveResizeInfo.window = XCB_NONE;
+
+    const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
+    xcb_client_message_event_t xev;
+    xev.response_type = XCB_CLIENT_MESSAGE;
+    xev.type = moveResize;
+    xev.sequence = 0;
+    xev.window = window;
+    xev.format = 32;
+    xev.data.data32[0] = 0;
+    xev.data.data32[1] = 0;
+    xev.data.data32[2] = 11; // _NET_WM_MOVERESIZE_CANCEL
+    xev.data.data32[3] = 0;
+    xev.data.data32[4] = 0;
+    xcb_send_event(xcb_connection(), false, primaryScreen()->root(),
+                   XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
+                   (const char *)&xev);
+
+    m_duringSystemMoveResize = false;
+}
+
+bool QXcbConnection::isDuringSystemMoveResize() const
+{
+    return m_duringSystemMoveResize;
+}
+
+void QXcbConnection::setDuringSystemMoveResize(bool during)
+{
+    m_duringSystemMoveResize = during;
+}
+
+void QXcbConnection::setStartSystemMoveResizeInfo(xcb_window_t window, int devid, int pointid, int edges)
+{
+    m_startSystemMoveResizeInfo.window = window;
+    m_startSystemMoveResizeInfo.deviceid = devid;
+    m_startSystemMoveResizeInfo.pointid = pointid;
+    m_startSystemMoveResizeInfo.edges = edges;
 }
 
 bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index b946453d3b..9aa57fa7db 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -2356,6 +2356,9 @@ bool QXcbWindow::startSystemMove()
 
 bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int edges)
 {
+    if (connection()->isDuringSystemMoveResize())
+        return true;
+
     const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
     if (!connection()->wmSupport()->isSupportedByWM(moveResize))
         return false;
@@ -2412,6 +2415,8 @@ void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int edges)
     xcb_send_event(connection()->xcb_connection(), false, xcbScreen()->root(),
                    XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
                    (const char *)&xev);
+
+    connection()->setDuringSystemMoveResize(true);
 }
 
 // Sends an XEmbed message.
-- 
2.31.1

