From 2488f34ecfd68702b5508c50cca3fb8e967ac8ea Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Thu, 25 Feb 2016 14:39:51 +0300 Subject: xcb: Adapt QXcbWindow::startSystemResize() for touch events Window managers typically grab the pointer after receiving the _NET_WM_MOVERESIZE event. But they fail to do it for touch sequences which have a receiver. So we should reject the touch sequence before sending _NET_WM_MOVERESIZE event. QSizeGrip calls startSystemResize() on MouseButtonPress event which is synthesized by Qt on TouchBegin. We can find the id of the touch point by comparing coordinates of the synthesized MouseButtonPress event with coordinates of all TouchBegin events. Then we use this id to reject the touch sequence (it's possible only after receiving XI_TouchUpdate). Change-Id: I26519840cd221e28b0be7854e4617c9aba4b0817 Task-number: QTBUG-51385 Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbconnection.h | 9 ++++++ src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 40 ++++++++++++++++++++++-- src/plugins/platforms/xcb/qxcbwindow.cpp | 12 ++++++- src/plugins/platforms/xcb/qxcbwindow.h | 2 ++ 4 files changed, 60 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index cb337ea0da..60f0f487c5 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -504,6 +504,7 @@ public: #endif #ifdef XCB_USE_XINPUT22 + bool startSystemResizeForTouchBegin(xcb_window_t window, const QPoint &point, Qt::Corner corner); bool xi2SetMouseGrabEnabled(xcb_window_t w, bool grab); #endif Qt::MouseButton xiToQtMouseButton(uint32_t b); @@ -639,6 +640,14 @@ private: QXcbEventReader *m_reader; #if defined(XCB_USE_XINPUT2) QHash m_touchDevices; +#ifdef XCB_USE_XINPUT22 + struct StartSystemResizeInfo { + xcb_window_t window; + uint16_t deviceid; + uint32_t pointid; + Qt::Corner corner; + } m_startSystemResizeInfo; +#endif #endif #ifdef Q_XCB_DEBUG struct CallInfo { diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 93f8db92bf..0ace79a4f5 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -61,9 +61,9 @@ struct XInput2TouchDeviceData { XIDeviceInfo *xiDeviceInfo; QTouchDevice *qtTouchDevice; QHash touchPoints; + QHash pointPressedPosition; // in screen coordinates where each point was pressed // Stuff that is relevant only for touchpads - QHash pointPressedPosition; // in screen coordinates where each point was pressed QPointF firstPressedPosition; // in screen coordinates where the first point was pressed QPointF firstPressedNormalPosition; // device coordinates (0 to 1, 0 to 1) where the first point was pressed QSizeF size; // device size in mm @@ -93,6 +93,7 @@ void QXcbConnection::initializeXInput2() if (m_xi2Enabled) { #ifdef XCB_USE_XINPUT22 qCDebug(lcQpaXInputDevices, "XInput version %d.%d is available and Qt supports 2.2 or greater", xiMajor, m_xi2Minor); + m_startSystemResizeInfo.window = XCB_NONE; #else qCDebug(lcQpaXInputDevices, "XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor); #endif @@ -714,7 +715,21 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo touchPoint.state = Qt::TouchPointMoved; } else if (touchPoint.area.center() != QPoint(x, y)) { touchPoint.state = Qt::TouchPointMoved; - dev->pointPressedPosition[touchPoint.id] = QPointF(x, y); + if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad) + dev->pointPressedPosition[touchPoint.id] = QPointF(x, y); + } + + if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen && + xiDeviceEvent->event == m_startSystemResizeInfo.window && + xiDeviceEvent->sourceid == m_startSystemResizeInfo.deviceid && + xiDeviceEvent->detail == m_startSystemResizeInfo.pointid) { + QXcbWindow *window = platformWindowFromId(m_startSystemResizeInfo.window); + if (window) { + XIAllowTouchEvents(static_cast(m_xlib_display), xiDeviceEvent->deviceid, + xiDeviceEvent->detail, xiDeviceEvent->event, XIRejectTouch); + window->doStartSystemResize(QPoint(x, y), m_startSystemResizeInfo.corner); + m_startSystemResizeInfo.window = XCB_NONE; + } } break; case XI_TouchEnd: @@ -745,6 +760,27 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo touchPoint.state = Qt::TouchPointStationary; } +bool QXcbConnection::startSystemResizeForTouchBegin(xcb_window_t window, const QPoint &point, Qt::Corner corner) +{ + QHash::const_iterator devIt = m_touchDevices.constBegin(); + for (; devIt != m_touchDevices.constEnd(); ++devIt) { + XInput2TouchDeviceData *deviceData = devIt.value(); + if (deviceData->qtTouchDevice->type() == QTouchDevice::TouchScreen) { + QHash::const_iterator pointIt = deviceData->pointPressedPosition.constBegin(); + for (; pointIt != deviceData->pointPressedPosition.constEnd(); ++pointIt) { + if (pointIt.value().toPoint() == point) { + m_startSystemResizeInfo.window = window; + m_startSystemResizeInfo.deviceid = devIt.key(); + m_startSystemResizeInfo.pointid = pointIt.key(); + m_startSystemResizeInfo.corner = corner; + return true; + } + } + } + } + return false; +} + bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) { if (grab && !canGrab()) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 0c8e78491e..5fa8541f26 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2738,13 +2738,23 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); if (!connection()->wmSupport()->isSupportedByWM(moveResize)) return false; + const QPoint globalPos = window()->mapToGlobal(pos); +#ifdef XCB_USE_XINPUT22 + if (connection()->startSystemResizeForTouchBegin(m_window, globalPos, corner)) + return true; +#endif + return doStartSystemResize(globalPos, corner); +} + +bool QXcbWindow::doStartSystemResize(const QPoint &globalPos, Qt::Corner corner) +{ + 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 = xcb_window(); xev.format = 32; - const QPoint globalPos = window()->mapToGlobal(pos); xev.data.data32[0] = globalPos.x(); xev.data.data32[1] = globalPos.y(); const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner; diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 3d8d21be6b..089df8f3f6 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -178,6 +178,8 @@ public: QXcbScreen *xcbScreen() const; + bool doStartSystemResize(const QPoint &globalPos, Qt::Corner corner); + virtual void create(); virtual void destroy(); -- cgit v1.2.3