diff options
author | Liang Qi <liang.qi@qt.io> | 2021-05-26 10:32:04 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2021-06-16 15:53:22 +0200 |
commit | 8e506fdd299d2fa18172209bea316f484e234e19 (patch) | |
tree | d66211c59b20fbd26f7f1d65f8ccacd122c72a03 /src/plugins/platforms/xcb | |
parent | 3ca5b46e5da04672ed0eaeaa6a5b30673705e4c9 (diff) |
xcb: fix QWindow::startSystemMove()/Resize() triggered by mouse
We can't get mouse release event from master pointers after
QXcbWindow::doStartSystemMoveResize() which calls xcb_ungrab_pointer(),
it looks like most X11 WMs work as that.
So we try to get mouse release event from slave pointers.
Based on https://specifications.freedesktop.org/wm-spec/1.4/ar01s04.html
, we need to send _NET_WM_MOVERESIZE_CANCEL when we get mouse release
event.
Task-number: QTBUG-91077
Change-Id: I01e74a01c87b381ee7cd6f20d51a1fa61c0e98fc
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 10 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 47 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 8 |
4 files changed, 60 insertions, 8 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index b19b070a4d..58a4a8ea04 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) @@ -592,6 +593,8 @@ 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) + abortSystemMoveResize(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 8938d28939..556e6b1002 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -231,10 +231,13 @@ public: 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 abortSystemMoveResize(xcb_window_t window); + bool isDuringSystemMoveResize() const; + void setDuringSystemMoveResize(bool during); + bool canGrab() const { return m_canGrabServer; } QXcbGlIntegration *glIntegration() const; @@ -323,12 +326,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; @@ -367,6 +372,7 @@ private: mutable bool m_glIntegrationInitialized = false; bool m_xiGrab = false; QList<int> m_xiMasterPointerIds; + QList<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 9abdfd422b..0e79f35d60 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -90,7 +90,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 = @@ -493,6 +493,7 @@ void QXcbConnection::xi2SetupDevices() // already registered break; case XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER: { + m_xiSlavePointerIds.append(deviceInfo->deviceid); QInputDevice *master = const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment)); Q_ASSERT(master); xi2SetupSlavePointerDevice(deviceInfo, false, qobject_cast<QPointingDevice *>(master)); @@ -638,6 +639,19 @@ 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 == XCB_NONE) + return; + + if (xiEvent->event_type == XCB_INPUT_BUTTON_RELEASE + && xiEvent->detail == XCB_BUTTON_INDEX_1 ) { + abortSystemMoveResize(xiEvent->event); + } else { + return; + } + } int sourceDeviceId = xiEvent->deviceid; // may be the master id qt_xcb_input_device_event_t *xiDeviceEvent = nullptr; xcb_input_enter_event_t *xiEnterEvent = nullptr; @@ -915,9 +929,38 @@ bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window, int edge return false; } -void QXcbConnection::abortSystemMoveResizeForTouch() +void QXcbConnection::abortSystemMoveResize(xcb_window_t window) { + qCDebug(lcQpaXInputDevices) << "sending client message NET_WM_MOVERESIZE_CANCEL to window: " << 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; } 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 2ee5dc300c..122e89f22e 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2334,14 +2334,11 @@ bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int edges) if (startedByTouch) { if (connection()->isUnity()) { // Unity fails to move/resize via _NET_WM_MOVERESIZE (WM bug?). - connection()->abortSystemMoveResizeForTouch(); + connection()->abortSystemMoveResize(m_window); return false; } // KWin, Openbox, AwesomeWM and Gnome have been tested to work with _NET_WM_MOVERESIZE. } else { // Started by mouse press. - if (connection()->isUnity()) - return false; // _NET_WM_MOVERESIZE on this WM is bouncy (WM bug?). - doStartSystemMoveResize(mapToGlobal(pos), edges); } @@ -2373,6 +2370,7 @@ static uint qtEdgesToXcbMoveResizeDirection(Qt::Edges edges) void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int edges) { + qCDebug(lcQpaXInputDevices) << "triggered system move or resize via sending _NET_WM_MOVERESIZE client message"; const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); xcb_client_message_event_t xev; xev.response_type = XCB_CLIENT_MESSAGE; @@ -2392,6 +2390,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. |