summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@qt.io>2017-06-01 16:26:06 +0200
committerGatis Paeglis <gatis.paeglis@qt.io>2017-08-09 16:55:25 +0000
commit9184384bc9d9d71a146fff535021357258a0295e (patch)
treefaecbc4ad9c1d48221815979323fbe4a3c774534 /src/plugins
parent0ad79dd0f00013831ea06ea4b0d7875db285b85c (diff)
xcb: use XInput2 for mouse starting from 2.0 not 2.2
53d289ec4c0f512a3475da4bbf1f940cd6838ac fixed the issue of not getting touch events when grabbing via the plain xcb functions. And due to wanting to support a setup where mouse events are delivered via core events it was chosen to use mouse via XI2 only when really necessary. Thus starting only from 2.2, the version from which the mouse+touch grabbing becomes the issue (XI2 introduced touch support from 2.2). The same patch states that using QT_XCB_NO_XI2_MOUSE restores to the old behavior (grabbing via core) with broken touch grabbing. Broken only with 2.2+, not 2.0 and 2.1 since those versions of protocol do not know about touch. All of this implies the following: 1) The user code that already depends on QT_XCB_NO_XI2_MOUSE, won't see any behavioural difference if we will use XInput starting from 2.0 for mouse. Mouse grabbing will continue to be done via core (xcb_grab_pointer) as mentioned above and thus touch grabbing will continue to be broken with 2.2+. 2) The code that has never cared how we get the native events (core vs xinput2), won't see any behavioural difference. In this case grabbing will always be done via XI2 (XIGrabDevice) grab when XI2.0+ is available. Since there is no difference in the outcome, we migth as well use XI2 for mouse from 2.0, not 2.2. Extension events are always better choice than core. Besides the broken touch grabbing issue with QT_XCB_NO_XI2_MOUSE, there are other issues with that code path, for details see internal documentation of xi2SelectDeviceEventsCompatibility(), where the conclusion is: *** If your code relies on QT_XCB_NO_XI2_MOUSE, then your code needs fixing. *** This patch also cleans up how we select XInput2 events, by separating the QT_XCB_NO_XI2_MOUSE code path. This has two benefits - improved code readability and will make the deprecation of QT_XCB_NO_XI2_MOUSE easier. The patch removes some sparse comments as the behavior is now documented in one place, see xi2SelectDeviceEventsCompatibility(). [ChangeLog][Platform Specific Changes][Linux] The QT_XCB_NO_XI2_MOUSE environment variable is deprecated and will be removed in Qt 6. If your application relies on behavior set by QT_XCB_NO_XI2_MOUSE, it should be updated accordingly. [ChangeLog][Platform Specific Changes][Linux] Pointer event delivery on X11 is now done starting from XInput version 2.0 (when available) instead of 2.2. XInput support can be disabled by setting QT_XCB_NO_XI2=1 environment variable. Note that using QT_XCB_NO_XI2 would also disable tablet and touch support. Change-Id: I661b36d6710b9f6ec71fecc8287ba479432bff4c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp13
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h34
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp201
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp23
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h2
7 files changed, 165 insertions, 114 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 8c444ce7aa..88d8d86c96 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1023,7 +1023,6 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
case XCB_EXPOSE:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
- // press/release/motion is only delivered here when XI 2.2+ is _not_ in use
case XCB_BUTTON_PRESS: {
xcb_button_press_event_t *ev = (xcb_button_press_event_t *)event;
m_keyboard->updateXKBStateFromCore(ev->state);
@@ -1066,14 +1065,14 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
handleClientMessageEvent((xcb_client_message_event_t *)event);
break;
case XCB_ENTER_NOTIFY:
-#ifdef XCB_USE_XINPUT22
- if (isAtLeastXI22() && xi2MouseEvents())
+#if QT_CONFIG(xinput2)
+ if (hasXInput2() && !xi2MouseEventsDisabled())
break;
#endif
HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
case XCB_LEAVE_NOTIFY:
-#ifdef XCB_USE_XINPUT22
- if (isAtLeastXI22() && xi2MouseEvents())
+#if QT_CONFIG(xinput2)
+ if (hasXInput2() && !xi2MouseEventsDisabled())
break;
#endif
m_keyboard->updateXKBStateFromCore(((xcb_leave_notify_event_t *)event)->state);
@@ -1138,7 +1137,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
#if QT_CONFIG(xinput2)
case XCB_GE_GENERIC:
// Here the windowEventListener is invoked from xi2HandleEvent()
- if (m_xi2Enabled && isXIEvent(event, m_xiOpCode))
+ if (hasXInput2() && isXIEvent(event, m_xiOpCode))
xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event));
break;
#endif
@@ -1550,7 +1549,7 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex,
#if QT_CONFIG(xinput2)
// compress XI_* events
if (responseType == XCB_GE_GENERIC) {
- if (!m_xi2Enabled)
+ if (!hasXInput2())
return false;
// compress XI_Motion, but not from tablet devices
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 8ac05574f3..3f030e0a53 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -358,7 +358,7 @@ public:
virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {}
virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {}
virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {}
-#ifdef XCB_USE_XINPUT22
+#if QT_CONFIG(xinput2)
virtual void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource = Qt::MouseEventNotSynthesized) {}
virtual void handleXIEnterLeave(xcb_ge_event_t *) {}
#endif
@@ -425,14 +425,6 @@ public:
void *xlib_display() const;
void *createVisualInfoForDefaultVisualId() const;
#endif
-
-#if QT_CONFIG(xinput2)
- void xi2Select(xcb_window_t window);
- void xi2SelectStateEvents();
- bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; }
- bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; }
-#endif
-
void sync();
void handleXcbError(xcb_generic_error_t *error);
@@ -461,6 +453,7 @@ public:
bool hasInputShape() const { return has_input_shape; }
bool hasXKB() const { return has_xkb; }
bool hasXRender() const { return has_render_extension; }
+ bool hasXInput2() const { return m_xi2Enabled; }
bool threadedEventHandling() const { return m_reader->isRunning(); }
@@ -492,19 +485,23 @@ public:
static bool xEmbedSystemTrayAvailable();
static bool xEmbedSystemTrayVisualHasAlphaChannel();
+#if QT_CONFIG(xinput2)
+ void xi2SelectStateEvents();
+ void xi2SelectDeviceEvents(xcb_window_t window);
+ void xi2SelectDeviceEventsCompatibility(xcb_window_t window);
+ bool xi2SetMouseGrabEnabled(xcb_window_t w, bool grab);
+ bool xi2MouseEventsDisabled() const;
+ bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; }
+ bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; }
+ Qt::MouseButton xiToQtMouseButton(uint32_t b);
#ifdef XCB_USE_XINPUT21
void xi2UpdateScrollingDevices();
-#endif // XCB_USE_XINPUT21
-
+#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);
- bool xi2MouseEvents() const;
bool isTouchScreen(int id);
-#endif // XCB_USE_XINPUT22
-
- Qt::MouseButton xiToQtMouseButton(uint32_t b);
-
+#endif
+#endif
QXcbEventReader *eventReader() const { return m_reader; }
bool canGrab() const { return m_canGrabServer; }
@@ -542,8 +539,9 @@ private:
void destroyScreen(QXcbScreen *screen);
void initializeScreens();
bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const;
-#if QT_CONFIG(xinput2)
+
bool m_xi2Enabled = false;
+#if QT_CONFIG(xinput2)
int m_xi2Minor = -1;
void initializeXInput2();
void xi2SetupDevice(void *info, bool removeExisting = true);
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 8ed6909990..58e99ef3de 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -107,6 +107,41 @@ void QXcbConnection::xi2SelectStateEvents()
XISelectEvents(dpy, DefaultRootWindow(dpy), &xiEventMask, 1);
}
+void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
+{
+ if (window == rootWindow())
+ return;
+
+ unsigned int bitMask = 0;
+ unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask);
+ bitMask |= XI_ButtonPressMask;
+ bitMask |= XI_ButtonReleaseMask;
+ bitMask |= XI_MotionMask;
+ // There is a check for enter/leave events in plain xcb enter/leave event handler,
+ // core enter/leave events will be ignored in this case.
+ bitMask |= XI_EnterMask;
+ bitMask |= XI_LeaveMask;
+ bitMask |= XI_PropertyEventMask;
+#ifdef XCB_USE_XINPUT22
+ if (isAtLeastXI22()) {
+ bitMask |= XI_TouchBeginMask;
+ bitMask |= XI_TouchUpdateMask;
+ bitMask |= XI_TouchEndMask;
+ }
+#endif
+
+ XIEventMask mask;
+ mask.mask_len = sizeof(bitMask);
+ mask.mask = xiBitMask;
+ mask.deviceid = XIAllMasterDevices;
+ Display *dpy = static_cast<Display *>(m_xlib_display);
+ Status result = XISelectEvents(dpy, window, &mask, 1);
+ if (result == Success)
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+ else
+ qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result);
+}
+
void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
{
XIDeviceInfo *deviceInfo = reinterpret_cast<XIDeviceInfo *>(info);
@@ -299,96 +334,105 @@ void QXcbConnection::xi2SetupDevices()
XIFreeDeviceInfo(devices);
}
-void QXcbConnection::xi2Select(xcb_window_t window)
+/*! \internal
+
+ Notes on QT_XCB_NO_XI2_MOUSE Handling:
+
+ Here we don't select pointer button press/release and motion events on master devices, instead
+ we select these events directly on slave devices. This means that a master device will fallback
+ to sending core events for every XI_* event that is sent directly by a slave device. For more
+ details see "Event processing for attached slave devices" in XInput2 specification. To prevent
+ handling of the same event twice, we have checks for xi2MouseEventsDisabled() in XI2 event
+ handlers (but this is somewhat inconsistent in some situations). If the purpose for
+ QT_XCB_NO_XI2_MOUSE was so that an application using QAbstractNativeEventFilter would see core
+ mouse events before they are handled by Qt then QT_XCB_NO_XI2_MOUSE won't always work as
+ expected (e.g. we handle scroll event directly from a slave device event, before an application
+ has seen the fallback core event from a master device).
+
+ The commit introducing QT_XCB_NO_XI2_MOUSE also states that setting this envvar "restores the
+ old behavior with broken grabbing". It did not elaborate why grabbing was not fixed for this
+ code path. The issue that this envvar tries to solve seem to be less important than broken
+ grabbing (broken apparently only for touch events). Thus, if you really want core mouse events
+ in your application and do not care about broken touch, then use QT_XCB_NO_XI2 (more on this
+ below) to disable the extension all together. The reason why grabbing might have not been fixed
+ is that calling XIGrabDevice with this code path for some reason always returns AlreadyGrabbed
+ (by debugging X server's code it appears that when we call XIGrabDevice, an X server first grabs
+ pointer via core pointer and then fails to do XI2 grab with AlreadyGrabbed; disclaimer - I did
+ not debug this in great detail). When we try supporting odd setups like QT_XCB_NO_XI2_MOUSE, we
+ are asking for trouble anyways.
+
+ In conclusion, introduction of QT_XCB_NO_XI2_MOUSE causes more issues than solves - the above
+ mentioned inconsistencies, maintenance of this code path and that QT_XCB_NO_XI2_MOUSE replaces
+ less important issue with somewhat more important issue. It also makes us to use less optimal
+ code paths in certain situations (see xi2HandleHierarchyEvent). Using of QT_XCB_NO_XI2 has its
+ drawbacks too - no tablet and touch events. So the only real fix in this case is at an
+ application side (teach the application about xcb_ge_event_t events). Based on this,
+ QT_XCB_NO_XI2_MOUSE will be removed in ### Qt 6. It should not have existed in the first place,
+ native events seen by QAbstractNativeEventFilter is not really a public API, applications should
+ expect changes at this level and do ifdefs if something changes between Qt version.
+*/
+void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window)
{
- if (!m_xi2Enabled || window == rootWindow())
+ if (window == rootWindow())
return;
- Display *xDisplay = static_cast<Display *>(m_xlib_display);
- unsigned int bitMask = 0;
- unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask);
-
+ unsigned int mask = 0;
+ unsigned char *bitMask = reinterpret_cast<unsigned char *>(&mask);
+ mask |= XI_PropertyEventMask;
#ifdef XCB_USE_XINPUT22
if (isAtLeastXI22()) {
- bitMask |= XI_TouchBeginMask;
- bitMask |= XI_TouchUpdateMask;
- bitMask |= XI_TouchEndMask;
- bitMask |= XI_PropertyEventMask; // for tablets
- if (xi2MouseEvents()) {
- // We want both mouse and touch through XI2 if touch is supported (>= 2.2).
- // The plain xcb press and motion events will not be delivered after this.
- bitMask |= XI_ButtonPressMask;
- bitMask |= XI_ButtonReleaseMask;
- bitMask |= XI_MotionMask;
-
- // There is a check for enter/leave events in plain xcb enter/leave event handler
- bitMask |= XI_EnterMask;
- bitMask |= XI_LeaveMask;
-
- qCDebug(lcQpaXInput, "XInput 2.2: Selecting press/release/motion events in addition to touch");
- }
- XIEventMask mask;
- mask.mask_len = sizeof(bitMask);
- mask.mask = xiBitMask;
- // When xi2MouseEvents() is true (the default), pointer emulation for touch and tablet
- // events will get disabled. This is preferable, as Qt Quick handles touch events
- // directly, while for other applications QtGui synthesizes mouse events.
- mask.deviceid = XIAllMasterDevices;
- Status result = XISelectEvents(xDisplay, window, &mask, 1);
- if (result == Success)
- QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
- else
- qCDebug(lcQpaXInput, "XInput 2.2: failed to select pointer/touch events, window %x, result %d", window, result);
+ mask |= XI_TouchBeginMask;
+ mask |= XI_TouchUpdateMask;
+ mask |= XI_TouchEndMask;
}
+#endif
+ XIEventMask xiMask;
+ xiMask.mask_len = sizeof(mask);
+ xiMask.mask = bitMask;
+ xiMask.deviceid = XIAllMasterDevices;
+ Display *dpy = static_cast<Display *>(m_xlib_display);
+ Status result = XISelectEvents(dpy, window, &xiMask, 1);
+ if (result == Success)
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+ else
+ qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result);
- const bool pointerSelected = isAtLeastXI22() && xi2MouseEvents();
-#else
- const bool pointerSelected = false;
-#endif // XCB_USE_XINPUT22
+ mask = XI_ButtonPressMask;
+ mask |= XI_ButtonReleaseMask;
+ mask |= XI_MotionMask;
- QSet<int> tabletDevices;
#if QT_CONFIG(tabletevent)
+ QSet<int> tabletDevices;
if (!m_tabletData.isEmpty()) {
- unsigned int tabletBitMask;
- unsigned char *xiTabletBitMask = reinterpret_cast<unsigned char *>(&tabletBitMask);
- QVector<XIEventMask> xiEventMask(m_tabletData.count());
- tabletBitMask = XI_PropertyEventMask;
- if (!pointerSelected)
- tabletBitMask |= XI_ButtonPressMask | XI_ButtonReleaseMask | XI_MotionMask;
- for (int i = 0; i < m_tabletData.count(); ++i) {
+ const int nrTablets = m_tabletData.count();
+ QVector<XIEventMask> xiEventMask(nrTablets);
+ for (int i = 0; i < nrTablets; ++i) {
int deviceId = m_tabletData.at(i).deviceId;
tabletDevices.insert(deviceId);
xiEventMask[i].deviceid = deviceId;
- xiEventMask[i].mask_len = sizeof(tabletBitMask);
- xiEventMask[i].mask = xiTabletBitMask;
+ xiEventMask[i].mask_len = sizeof(mask);
+ xiEventMask[i].mask = bitMask;
}
- XISelectEvents(xDisplay, window, xiEventMask.data(), m_tabletData.count());
+ XISelectEvents(dpy, window, xiEventMask.data(), nrTablets);
}
-#endif // QT_CONFIG(tabletevent)
+#endif
#ifdef XCB_USE_XINPUT21
- // Enable each scroll device
- if (!m_scrollingDevices.isEmpty() && !pointerSelected) {
- // Only when XI2 mouse events are not enabled, otherwise motion and release are selected already.
+ if (!m_scrollingDevices.isEmpty()) {
QVector<XIEventMask> xiEventMask(m_scrollingDevices.size());
- unsigned int scrollBitMask;
- unsigned char *xiScrollBitMask = reinterpret_cast<unsigned char *>(&scrollBitMask);
-
- scrollBitMask = XI_MotionMask;
- scrollBitMask |= XI_ButtonReleaseMask;
- int i=0;
+ int i = 0;
for (const ScrollingDevice& scrollingDevice : qAsConst(m_scrollingDevices)) {
+#if QT_CONFIG(tabletevent)
if (tabletDevices.contains(scrollingDevice.deviceId))
continue; // All necessary events are already captured.
+#endif
xiEventMask[i].deviceid = scrollingDevice.deviceId;
- xiEventMask[i].mask_len = sizeof(scrollBitMask);
- xiEventMask[i].mask = xiScrollBitMask;
+ xiEventMask[i].mask_len = sizeof(mask);
+ xiEventMask[i].mask = bitMask;
i++;
}
- XISelectEvents(xDisplay, window, xiEventMask.data(), i);
+ XISelectEvents(dpy, window, xiEventMask.data(), i);
}
-#else
- Q_UNUSED(xiBitMask);
#endif
}
@@ -566,7 +610,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
case XI_ButtonPress:
case XI_ButtonRelease:
case XI_Motion:
- if (xi2MouseEvents() && eventListener && !(xiDeviceEvent->flags & XIPointerEmulated))
+ if (!xi2MouseEventsDisabled() && eventListener && !(xiDeviceEvent->flags & XIPointerEmulated))
eventListener->handleXIMouseEvent(event);
break;
@@ -582,7 +626,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
xi2ProcessTouch(xiDeviceEvent, platformWindow);
break;
}
- } else if (xiEnterEvent && xi2MouseEvents() && eventListener) {
+ } else if (xiEnterEvent && !xi2MouseEventsDisabled() && eventListener) {
switch (xiEnterEvent->evtype) {
case XI_Enter:
case XI_Leave:
@@ -593,15 +637,15 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
#endif // XCB_USE_XINPUT22
}
-#ifdef XCB_USE_XINPUT22
-bool QXcbConnection::xi2MouseEvents() const
+bool QXcbConnection::xi2MouseEventsDisabled() const
{
- static bool mouseViaXI2 = !qEnvironmentVariableIsSet("QT_XCB_NO_XI2_MOUSE");
+ static bool xi2MouseDisabled = qEnvironmentVariableIsSet("QT_XCB_NO_XI2_MOUSE");
// FIXME: Don't use XInput2 mouse events when Xinerama extension
// is enabled, because it causes problems with multi-monitor setup.
- return mouseViaXI2 && isAtLeastXI22() && !has_xinerama_extension;
+ return xi2MouseDisabled || has_xinerama_extension;
}
+#ifdef XCB_USE_XINPUT22
bool QXcbConnection::isTouchScreen(int id)
{
auto device = touchDeviceForId(id);
@@ -794,6 +838,7 @@ bool QXcbConnection::startSystemResizeForTouchBegin(xcb_window_t window, const Q
}
return false;
}
+#endif // XCB_USE_XINPUT22
bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
{
@@ -854,7 +899,6 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
return grabbed;
}
-#endif // XCB_USE_XINPUT22
void QXcbConnection::xi2HandleHierarchyEvent(void *event)
{
@@ -862,10 +906,17 @@ void QXcbConnection::xi2HandleHierarchyEvent(void *event)
// We only care about hotplugged devices
if (!(xiEvent->flags & (XISlaveRemoved | XISlaveAdded)))
return;
+
xi2SetupDevices();
- // Reselect events for all event-listening windows.
- for (auto it = m_mapper.cbegin(), end = m_mapper.cend(); it != end; ++it)
- xi2Select(it.key());
+
+ if (xi2MouseEventsDisabled()) {
+ // In compatibility mode (a.k.a xi2MouseEventsDisabled() mode) we select events for
+ // each device separately. When a new device appears, we have to select events from
+ // this device on all event-listening windows. This is not needed when events are
+ // selected via XIAllDevices/XIAllMasterDevices (as in xi2SelectDeviceEvents()).
+ for (auto it = m_mapper.cbegin(), end = m_mapper.cend(); it != end; ++it)
+ xi2SelectDeviceEventsCompatibility(it.key());
+ }
}
void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 891b53d2dc..e24bd07b6f 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -53,7 +53,7 @@
#include <stdio.h>
#include <X11/keysym.h>
-#ifdef XCB_USE_XINPUT22
+#if QT_CONFIG(xinput2)
#include <X11/extensions/XI2proto.h>
#undef KeyPress
#undef KeyRelease
@@ -800,7 +800,7 @@ void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
}
}
-#ifdef XCB_USE_XINPUT22
+#if QT_CONFIG(xinput2)
void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
{
if (m_config && !connection()->hasXKB()) {
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 74f9da0353..7f1c51fab8 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -74,7 +74,7 @@ public:
void updateXKBMods();
quint32 xkbModMask(quint16 state);
void updateXKBStateFromCore(quint16 state);
-#ifdef XCB_USE_XINPUT22
+#if QT_CONFIG(xinput2)
void updateXKBStateFromXI(void *modInfo, void *groupInfo);
#endif
#if QT_CONFIG(xkb)
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index c3d00b53bf..affc2a0dd6 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -576,9 +576,13 @@ void QXcbWindow::create()
atom(QXcbAtom::_XEMBED_INFO),
32, 2, (void *)data);
-
#if QT_CONFIG(xinput2)
- connection()->xi2Select(m_window);
+ if (connection()->hasXInput2()) {
+ if (connection()->xi2MouseEventsDisabled())
+ connection()->xi2SelectDeviceEventsCompatibility(m_window);
+ else
+ connection()->xi2SelectDeviceEvents(m_window);
+ }
#endif
setWindowState(window()->windowStates());
@@ -2237,9 +2241,10 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
* not pressed, otherwise (e.g. on Alt+Tab) it can igonre important enter/leave events.
*/
if (conn) {
+
const bool mouseButtonsPressed = (conn->buttonState() != Qt::NoButton);
-#ifdef XCB_USE_XINPUT22
- return mouseButtonsPressed || (conn->isAtLeastXI22() && conn->xi2MouseEvents());
+#if QT_CONFIG(xinput2)
+ return mouseButtonsPressed || (conn->hasXInput2() && !conn->xi2MouseEventsDisabled());
#else
return mouseButtonsPressed;
#endif
@@ -2342,7 +2347,6 @@ void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, i
handleMouseEvent(timestamp, local, global, modifiers, source);
}
-// Handlers for plain xcb events. Used only when XI 2.2 or newer is not available.
void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
{
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
@@ -2363,13 +2367,12 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
handleMotionNotifyEvent(event->event_x, event->event_y, event->root_x, event->root_y, modifiers, event->time);
}
-#ifdef XCB_USE_XINPUT22
+#if QT_CONFIG(xinput2)
static inline int fixed1616ToInt(FP1616 val)
{
return int((qreal(val >> 16)) + (val & 0xFFFF) / (qreal)0xFFFF);
}
-// With XI 2.2+ press/release/motion comes here instead of the above handlers.
void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource source)
{
QXcbConnection *conn = connection();
@@ -2431,7 +2434,6 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource
}
}
-// With XI 2.2+ enter/leave comes here and are blocked in plain xcb events
void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event)
{
xXIEnterEvent *ev = reinterpret_cast<xXIEnterEvent *>(event);
@@ -2591,8 +2593,9 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
{
if (!grab && connection()->mouseGrabber() == this)
connection()->setMouseGrabber(Q_NULLPTR);
-#ifdef XCB_USE_XINPUT22
- if (connection()->isAtLeastXI22() && connection()->xi2MouseEvents()) {
+
+#if QT_CONFIG(xinput2)
+ if (connection()->hasXInput2() && !connection()->xi2MouseEventsDisabled()) {
bool result = connection()->xi2SetMouseGrabEnabled(m_window, grab);
if (grab && result)
connection()->setMouseGrabber(this);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index b5bf33520f..1ce9b0a42f 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -138,7 +138,7 @@ public:
void handleFocusInEvent(const xcb_focus_in_event_t *event) override;
void handleFocusOutEvent(const xcb_focus_out_event_t *event) override;
void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override;
-#ifdef XCB_USE_XINPUT22
+#if QT_CONFIG(xinput2)
void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized) override;
void handleXIEnterLeave(xcb_ge_event_t *) override;
#endif