summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2021-05-26 10:32:04 +0200
committerLiang Qi <liang.qi@qt.io>2021-06-16 15:53:22 +0200
commit8e506fdd299d2fa18172209bea316f484e234e19 (patch)
treed66211c59b20fbd26f7f1d65f8ccacd122c72a03 /src/plugins/platforms/xcb
parent3ca5b46e5da04672ed0eaeaa6a5b30673705e4c9 (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.cpp3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h10
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp47
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp8
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.