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>
This commit is contained in:
parent
3ca5b46e5d
commit
8e506fdd29
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user