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)
|
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName)
|
||||||
: QXcbBasicConnection(displayName)
|
: QXcbBasicConnection(displayName)
|
||||||
|
, m_duringSystemMoveResize(false)
|
||||||
, m_canGrabServer(canGrabServer)
|
, m_canGrabServer(canGrabServer)
|
||||||
, m_defaultVisualId(defaultVisualId)
|
, m_defaultVisualId(defaultVisualId)
|
||||||
, m_nativeInterface(nativeInterface)
|
, m_nativeInterface(nativeInterface)
|
||||||
@ -592,6 +593,8 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
|
|||||||
}
|
}
|
||||||
case XCB_BUTTON_RELEASE: {
|
case XCB_BUTTON_RELEASE: {
|
||||||
auto ev = reinterpret_cast<xcb_button_release_event_t *>(event);
|
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_keyboard->updateXKBStateFromCore(ev->state);
|
||||||
m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
|
m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
|
||||||
setButtonState(translateMouseButton(ev->detail), false);
|
setButtonState(translateMouseButton(ev->detail), false);
|
||||||
|
@ -231,10 +231,13 @@ public:
|
|||||||
|
|
||||||
Qt::MouseButton xiToQtMouseButton(uint32_t b);
|
Qt::MouseButton xiToQtMouseButton(uint32_t b);
|
||||||
void xi2UpdateScrollingDevices();
|
void xi2UpdateScrollingDevices();
|
||||||
bool startSystemMoveResizeForTouch(xcb_window_t window, int edges);
|
|
||||||
void abortSystemMoveResizeForTouch();
|
|
||||||
bool isTouchScreen(int id);
|
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; }
|
bool canGrab() const { return m_canGrabServer; }
|
||||||
|
|
||||||
QXcbGlIntegration *glIntegration() const;
|
QXcbGlIntegration *glIntegration() const;
|
||||||
@ -323,12 +326,14 @@ private:
|
|||||||
static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);
|
static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);
|
||||||
|
|
||||||
QHash<int, TouchDeviceData> m_touchDevices;
|
QHash<int, TouchDeviceData> m_touchDevices;
|
||||||
|
|
||||||
struct StartSystemMoveResizeInfo {
|
struct StartSystemMoveResizeInfo {
|
||||||
xcb_window_t window = XCB_NONE;
|
xcb_window_t window = XCB_NONE;
|
||||||
uint16_t deviceid;
|
uint16_t deviceid;
|
||||||
uint32_t pointid;
|
uint32_t pointid;
|
||||||
int edges;
|
int edges;
|
||||||
} m_startSystemMoveResizeInfo;
|
} m_startSystemMoveResizeInfo;
|
||||||
|
bool m_duringSystemMoveResize;
|
||||||
|
|
||||||
const bool m_canGrabServer;
|
const bool m_canGrabServer;
|
||||||
const xcb_visualid_t m_defaultVisualId;
|
const xcb_visualid_t m_defaultVisualId;
|
||||||
@ -367,6 +372,7 @@ private:
|
|||||||
mutable bool m_glIntegrationInitialized = false;
|
mutable bool m_glIntegrationInitialized = false;
|
||||||
bool m_xiGrab = false;
|
bool m_xiGrab = false;
|
||||||
QList<int> m_xiMasterPointerIds;
|
QList<int> m_xiMasterPointerIds;
|
||||||
|
QList<int> m_xiSlavePointerIds;
|
||||||
|
|
||||||
xcb_window_t m_qtSelectionOwner = 0;
|
xcb_window_t m_qtSelectionOwner = 0;
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qt_xcb_input_event_mask_t mask;
|
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.header.mask_len = 1;
|
||||||
mask.mask = bitMask;
|
mask.mask = bitMask;
|
||||||
xcb_void_cookie_t cookie =
|
xcb_void_cookie_t cookie =
|
||||||
@ -493,6 +493,7 @@ void QXcbConnection::xi2SetupDevices()
|
|||||||
// already registered
|
// already registered
|
||||||
break;
|
break;
|
||||||
case XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER: {
|
case XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER: {
|
||||||
|
m_xiSlavePointerIds.append(deviceInfo->deviceid);
|
||||||
QInputDevice *master = const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
|
QInputDevice *master = const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
|
||||||
Q_ASSERT(master);
|
Q_ASSERT(master);
|
||||||
xi2SetupSlavePointerDevice(deviceInfo, false, qobject_cast<QPointingDevice *>(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)
|
void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
|
||||||
{
|
{
|
||||||
auto *xiEvent = reinterpret_cast<qt_xcb_input_device_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
|
int sourceDeviceId = xiEvent->deviceid; // may be the master id
|
||||||
qt_xcb_input_device_event_t *xiDeviceEvent = nullptr;
|
qt_xcb_input_device_event_t *xiDeviceEvent = nullptr;
|
||||||
xcb_input_enter_event_t *xiEnterEvent = nullptr;
|
xcb_input_enter_event_t *xiEnterEvent = nullptr;
|
||||||
@ -915,9 +929,38 @@ bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window, int edge
|
|||||||
return false;
|
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;
|
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)
|
bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
|
||||||
|
@ -2334,14 +2334,11 @@ bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int edges)
|
|||||||
if (startedByTouch) {
|
if (startedByTouch) {
|
||||||
if (connection()->isUnity()) {
|
if (connection()->isUnity()) {
|
||||||
// Unity fails to move/resize via _NET_WM_MOVERESIZE (WM bug?).
|
// Unity fails to move/resize via _NET_WM_MOVERESIZE (WM bug?).
|
||||||
connection()->abortSystemMoveResizeForTouch();
|
connection()->abortSystemMoveResize(m_window);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// KWin, Openbox, AwesomeWM and Gnome have been tested to work with _NET_WM_MOVERESIZE.
|
// KWin, Openbox, AwesomeWM and Gnome have been tested to work with _NET_WM_MOVERESIZE.
|
||||||
} else { // Started by mouse press.
|
} else { // Started by mouse press.
|
||||||
if (connection()->isUnity())
|
|
||||||
return false; // _NET_WM_MOVERESIZE on this WM is bouncy (WM bug?).
|
|
||||||
|
|
||||||
doStartSystemMoveResize(mapToGlobal(pos), edges);
|
doStartSystemMoveResize(mapToGlobal(pos), edges);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2373,6 +2370,7 @@ static uint qtEdgesToXcbMoveResizeDirection(Qt::Edges edges)
|
|||||||
|
|
||||||
void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int 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);
|
const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
|
||||||
xcb_client_message_event_t xev;
|
xcb_client_message_event_t xev;
|
||||||
xev.response_type = XCB_CLIENT_MESSAGE;
|
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_send_event(connection()->xcb_connection(), false, xcbScreen()->root(),
|
||||||
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
|
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
|
||||||
(const char *)&xev);
|
(const char *)&xev);
|
||||||
|
|
||||||
|
connection()->setDuringSystemMoveResize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends an XEmbed message.
|
// Sends an XEmbed message.
|
||||||
|
Loading…
Reference in New Issue
Block a user