xcb: Use XCB instead of Xlib for XInput

- Replace xinput2 feature by xcb-xinput, which doesn't
  depend on xcb-xlib
- Remove xi2PrepareXIGenericDeviceEvent() that was used to
  fix incompatibilty between XCB and libXi structs
- Drop XCB_USE_XINPUT21 and XCB_USE_XINPUT22 defines that were
  needed with libXi

Although xcb-xinput was released in version 1.13 of libxcb,
it was quite stable in version 1.12, and the parts that we
use did not change between versions, so require system
xcb-xinput 1.12.

[ChangeLog][X11] The xcb plugin was ported to use libxcb-xinput
instead of libXi for XInput2 support. The -xinput2 configure
option was replaced by -xcb-xinput.

Task-number: QTBUG-39624
Change-Id: I37475b09b2bd7057763345c3f33d8c7751a4e831
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: Gatis Paeglis <gatis.paeglis@qt.io>
This commit is contained in:
Alexander Volkov 2018-03-06 16:02:54 +03:00 committed by Gatis Paeglis
parent 8b16557c35
commit a692d7cd28
11 changed files with 373 additions and 454 deletions

View File

@ -297,7 +297,7 @@ Gui, printing, widget options:
-libinput .......... Enable libinput support [auto] -libinput .......... Enable libinput support [auto]
-mtdev ............. Enable mtdev support [auto] -mtdev ............. Enable mtdev support [auto]
-tslib ............. Enable tslib support [auto] -tslib ............. Enable tslib support [auto]
-xinput2 ........... Enable XInput2 support [auto] -xcb-xinput ........ Enable XInput2 support [auto]
-xkbcommon-x11 ..... Select xkbcommon used in combination with xcb -xkbcommon-x11 ..... Select xkbcommon used in combination with xcb
[system/qt/no] [system/qt/no]
-xkbcommon-evdev ... Enable X-less xkbcommon in combination with libinput -xkbcommon-evdev ... Enable X-less xkbcommon in combination with libinput

View File

@ -44,7 +44,7 @@
"xcb": { "type": "enum", "values": [ "no", "yes", "qt", "system" ] }, "xcb": { "type": "enum", "values": [ "no", "yes", "qt", "system" ] },
"xcb-native-painting": "boolean", "xcb-native-painting": "boolean",
"xcb-xlib": "boolean", "xcb-xlib": "boolean",
"xinput2": "boolean", "xcb-xinput": "boolean",
"xkb": "boolean", "xkb": "boolean",
"xkbcommon": { "type": "enum", "values": [ "no", "qt", "system" ] }, "xkbcommon": { "type": "enum", "values": [ "no", "qt", "system" ] },
"xkbcommon-evdev": "boolean", "xkbcommon-evdev": "boolean",
@ -566,33 +566,22 @@
"-lxcb-glx -lxcb" "-lxcb-glx -lxcb"
] ]
}, },
"xinput2": { "xcb_xinput": {
"label": "Xinput2", "label": "XCB XInput",
"test": { "test": {
"include": [ "X11/Xlib.h", "X11/extensions/XInput2.h", "X11/extensions/Xge.h" ], "include": [ "xcb/xcb.h", "xcb/xinput.h" ],
"tail": [
"#ifndef XInput_2_0",
"# error Missing XInput_2_0 #define",
"#endif"
],
"main": [ "main": [
"// need XGenericEventCookie for XInput2 to work", "int primaryScreen = 0;",
"Display *dpy = 0;", "xcb_connection_t *connection = xcb_connect(\"\", &primaryScreen);",
"XEvent xevent;", "xcb_generic_error_t *error = 0;",
"XIEvent *xievent = 0;", "xcb_input_xi_query_version_cookie_t xinput_query_cookie = xcb_input_xi_query_version(",
"XIDeviceEvent *xideviceevent = 0;", " connection, XCB_INPUT_MAJOR_VERSION, XCB_INPUT_MINOR_VERSION);",
"XIHierarchyEvent *xihierarchyevent = 0;", "xcb_input_xi_query_version_reply(connection, xinput_query_cookie, &error);"
"int deviceid = 0;", ]
"int len = 0;",
"(void) XGetEventData(dpy, &xevent.xcookie);",
"XFreeEventData(dpy, &xevent.xcookie);",
"(void) XIListProperties(dpy, deviceid, &len);"
],
"qmake": "CONFIG += x11"
}, },
"sources": [ "sources": [
{ "type": "pkgConfig", "args": "xi" }, { "type": "pkgConfig", "args": "xcb-xinput >= 1.12 xcb" },
"-lXi" "-lxcb-xinput -lxcb"
] ]
}, },
"xkbcommon": { "xkbcommon": {
@ -1352,10 +1341,10 @@
"condition": "features.sessionmanager && libs.x11sm", "condition": "features.sessionmanager && libs.x11sm",
"output": [ "privateFeature" ] "output": [ "privateFeature" ]
}, },
"xinput2": { "xcb-xinput": {
"label": "Xinput2", "label": "XCB XInput",
"emitIf": "features.xcb", "emitIf": "features.xcb",
"condition": "features.xcb-xlib && libs.xinput2", "condition": "!features.system-xcb || libs.xcb_xinput",
"output": [ "privateFeature" ] "output": [ "privateFeature" ]
}, },
"xkbcommon-evdev": { "xkbcommon-evdev": {
@ -1726,7 +1715,7 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla
"section": "X11", "section": "X11",
"condition": "features.xcb", "condition": "features.xcb",
"entries": [ "entries": [
"system-xcb", "egl_x11", "xinput2", "xkb", "xlib", "xcb-render", "xcb-glx", "xcb-xlib", "xkbcommon-system", "xcb-native-painting" "system-xcb", "egl_x11", "xkb", "xlib", "xcb-render", "xcb-glx", "xcb-xinput", "xcb-xlib", "xkbcommon-system", "xcb-native-painting"
] ]
}, },
{ {

View File

@ -3,7 +3,7 @@ Requires libxcb >= 1.5.
PACKAGE DEPENDENCIES PACKAGE DEPENDENCIES
Required packages: Required packages:
libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxcb-xinerama0-dev libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxcb-xinerama0-dev libxcb-xinput0-dev
On Ubuntu 11.10 icccm1 is replaced by icccm4 and xcb-render-util is not available: On Ubuntu 11.10 icccm1 is replaced by icccm4 and xcb-render-util is not available:
libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxcb-xinerama0-dev libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxcb-xinerama0-dev
@ -21,12 +21,3 @@ REDUCING RUNTIME DEPENDENCIES
The '-qt-xcb' configure option can be used to get rid of most xcb- dependencies. Only libxcb will The '-qt-xcb' configure option can be used to get rid of most xcb- dependencies. Only libxcb will
still be linked dynamically, since it will be most likely be pulled in via other dependencies anyway. still be linked dynamically, since it will be most likely be pulled in via other dependencies anyway.
This should allow for binaries that are portable across most modern Linux distributions. This should allow for binaries that are portable across most modern Linux distributions.
PACKAGE VERSION REQUIREMENTS
When using touch input via XInput 2.2 or higher, there is a potential issue on systems that ship with
a libXi older than 1.7.5. This is because XIAllowTouchEvents can deadlock with libXi 1.7.4 and earlier.
When touch events are never received, this is not an issue, so plain mouse/keyboard systems are not affected.
Qt versions before 5.8 attempted to recognize this scenario based on the pkg-config package version and skip
the call. This has been removed starting from 5.8 since relying on pkg-config package versions is unsafe given
that Qt must also support systems with limited or incomplete pkg-config setups.

View File

@ -76,8 +76,8 @@
#include <X11/Xutil.h> #include <X11/Xutil.h>
#endif #endif
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
#include <X11/extensions/XI2proto.h> #include <xcb/xinput.h>
#endif #endif
#if QT_CONFIG(xcb_render) #if QT_CONFIG(xcb_render)
@ -120,7 +120,7 @@ Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard")
#define XCB_GE_GENERIC 35 #define XCB_GE_GENERIC 35
#endif #endif
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: // Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed:
// - "pad0" became "extension" // - "pad0" became "extension"
// - "pad1" and "pad" became "pad0" // - "pad1" and "pad" became "pad0"
@ -138,7 +138,7 @@ static inline bool isXIEvent(xcb_generic_event_t *event, int opCode)
qt_xcb_ge_event_t *e = reinterpret_cast<qt_xcb_ge_event_t *>(event); qt_xcb_ge_event_t *e = reinterpret_cast<qt_xcb_ge_event_t *>(event);
return e->extension == opCode; return e->extension == opCode;
} }
#endif // QT_CONFIG(xinput2) #endif // QT_CONFIG(xcb_xinput)
#if QT_CONFIG(xcb_xlib) #if QT_CONFIG(xcb_xlib)
static const char * const xcbConnectionErrors[] = { static const char * const xcbConnectionErrors[] = {
@ -572,6 +572,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
#endif #endif
#if QT_CONFIG(xcb_render) #if QT_CONFIG(xcb_render)
&xcb_render_id, &xcb_render_id,
#endif
#if QT_CONFIG(xcb_xinput)
&xcb_input_id,
#endif #endif
0 0
}; };
@ -592,7 +595,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeScreens(); initializeScreens();
initializeXRender(); initializeXRender();
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2")) if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2"))
initializeXInput2(); initializeXInput2();
#endif #endif
@ -1105,13 +1108,13 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
handleClientMessageEvent((xcb_client_message_event_t *)event); handleClientMessageEvent((xcb_client_message_event_t *)event);
break; break;
case XCB_ENTER_NOTIFY: case XCB_ENTER_NOTIFY:
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
if (hasXInput2() && !xi2MouseEventsDisabled()) if (hasXInput2() && !xi2MouseEventsDisabled())
break; break;
#endif #endif
HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
case XCB_LEAVE_NOTIFY: case XCB_LEAVE_NOTIFY:
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
if (hasXInput2() && !xi2MouseEventsDisabled()) if (hasXInput2() && !xi2MouseEventsDisabled())
break; break;
#endif #endif
@ -1174,7 +1177,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
} }
break; break;
} }
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
case XCB_GE_GENERIC: case XCB_GE_GENERIC:
// Here the windowEventListener is invoked from xi2HandleEvent() // Here the windowEventListener is invoked from xi2HandleEvent()
if (hasXInput2() && isXIEvent(event, m_xiOpCode)) if (hasXInput2() && isXIEvent(event, m_xiOpCode))
@ -1630,16 +1633,14 @@ void *QXcbConnection::createVisualInfoForDefaultVisualId() const
#endif #endif
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
// it is safe to cast XI_* events here as long as we are only touching the first 32 bytes,
// after that position event needs memmove, see xi2PrepareXIGenericDeviceEvent
static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t type) static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t type)
{ {
if (!isXIEvent(event, opCode)) if (!isXIEvent(event, opCode))
return false; return false;
xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); auto *e = reinterpret_cast<qt_xcb_ge_event_t *>(event);
return xiEvent->evtype == type; return e->event_type == type;
} }
#endif #endif
static inline bool isValid(xcb_generic_event_t *event) static inline bool isValid(xcb_generic_event_t *event)
@ -1675,16 +1676,16 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex,
} }
return false; return false;
} }
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
// compress XI_* events // compress XI_* events
if (responseType == XCB_GE_GENERIC) { if (responseType == XCB_GE_GENERIC) {
if (!hasXInput2()) if (!hasXInput2())
return false; return false;
// compress XI_Motion, but not from tablet devices // compress XI_Motion, but not from tablet devices
if (isXIType(event, m_xiOpCode, XI_Motion)) { if (isXIType(event, m_xiOpCode, XCB_INPUT_MOTION)) {
#if QT_CONFIG(tabletevent) #if QT_CONFIG(tabletevent)
xXIDeviceEvent *xdev = reinterpret_cast<xXIDeviceEvent *>(event); auto *xdev = reinterpret_cast<xcb_input_motion_event_t *>(event);
if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) && if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) &&
const_cast<QXcbConnection *>(this)->tabletDataForDevice(xdev->sourceid)) const_cast<QXcbConnection *>(this)->tabletDataForDevice(xdev->sourceid))
return false; return false;
@ -1693,29 +1694,27 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex,
xcb_generic_event_t *next = eventqueue->at(j); xcb_generic_event_t *next = eventqueue->at(j);
if (!isValid(next)) if (!isValid(next))
continue; continue;
if (isXIType(next, m_xiOpCode, XI_Motion)) if (isXIType(next, m_xiOpCode, XCB_INPUT_MOTION))
return true; return true;
} }
return false; return false;
} }
#ifdef XCB_USE_XINPUT22
// compress XI_TouchUpdate for the same touch point id // compress XI_TouchUpdate for the same touch point id
if (isXIType(event, m_xiOpCode, XI_TouchUpdate)) { if (isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) {
xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); auto *touchUpdateEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(event);
uint32_t id = xiDeviceEvent->detail % INT_MAX; uint32_t id = touchUpdateEvent->detail % INT_MAX;
for (int j = nextIndex; j < eventqueue->size(); ++j) { for (int j = nextIndex; j < eventqueue->size(); ++j) {
xcb_generic_event_t *next = eventqueue->at(j); xcb_generic_event_t *next = eventqueue->at(j);
if (!isValid(next)) if (!isValid(next))
continue; continue;
if (isXIType(next, m_xiOpCode, XI_TouchUpdate)) { if (isXIType(next, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) {
xXIDeviceEvent *xiDeviceNextEvent = reinterpret_cast<xXIDeviceEvent *>(next); auto *touchUpdateNextEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(next);
if (id == xiDeviceNextEvent->detail % INT_MAX) if (id == touchUpdateNextEvent->detail % INT_MAX)
return true; return true;
} }
} }
return false; return false;
} }
#endif
return false; return false;
} }
#endif #endif

View File

@ -71,16 +71,6 @@
#include <QTabletEvent> #include <QTabletEvent>
#endif #endif
#if QT_CONFIG(xinput2)
#include <X11/extensions/XI2.h>
#ifdef XIScrollClass
#define XCB_USE_XINPUT21 // XI 2.1 adds smooth scrolling support
#ifdef XI_TouchBeginMask
#define XCB_USE_XINPUT22 // XI 2.2 adds multi-point touch support
#endif
#endif
#endif // QT_CONFIG(xinput2)
struct xcb_randr_get_output_info_reply_t; struct xcb_randr_get_output_info_reply_t;
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -359,7 +349,7 @@ public:
virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {} virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {}
virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {} virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {}
virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {} virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {}
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
virtual void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource = Qt::MouseEventNotSynthesized) {} virtual void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource = Qt::MouseEventNotSynthesized) {}
virtual void handleXIEnterLeave(xcb_ge_event_t *) {} virtual void handleXIEnterLeave(xcb_ge_event_t *) {}
#endif #endif
@ -511,7 +501,7 @@ public:
static bool xEmbedSystemTrayAvailable(); static bool xEmbedSystemTrayAvailable();
static bool xEmbedSystemTrayVisualHasAlphaChannel(); static bool xEmbedSystemTrayVisualHasAlphaChannel();
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
void xi2SelectStateEvents(); void xi2SelectStateEvents();
void xi2SelectDeviceEvents(xcb_window_t window); void xi2SelectDeviceEvents(xcb_window_t window);
void xi2SelectDeviceEventsCompatibility(xcb_window_t window); void xi2SelectDeviceEventsCompatibility(xcb_window_t window);
@ -520,13 +510,9 @@ public:
bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; } bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; }
bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; } bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; }
Qt::MouseButton xiToQtMouseButton(uint32_t b); Qt::MouseButton xiToQtMouseButton(uint32_t b);
#ifdef XCB_USE_XINPUT21
void xi2UpdateScrollingDevices(); void xi2UpdateScrollingDevices();
#endif
#ifdef XCB_USE_XINPUT22
bool startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner); bool startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner);
bool isTouchScreen(int id); bool isTouchScreen(int id);
#endif
#endif #endif
QXcbEventReader *eventReader() const { return m_reader; } QXcbEventReader *eventReader() const { return m_reader; }
@ -568,7 +554,7 @@ private:
bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const; bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const;
bool m_xi2Enabled = false; bool m_xi2Enabled = false;
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
int m_xi2Minor = -1; int m_xi2Minor = -1;
void initializeXInput2(); void initializeXInput2();
void xi2SetupDevice(void *info, bool removeExisting = true); void xi2SetupDevice(void *info, bool removeExisting = true);
@ -596,10 +582,8 @@ private:
void xi2HandleEvent(xcb_ge_event_t *event); void xi2HandleEvent(xcb_ge_event_t *event);
void xi2HandleHierarchyEvent(void *event); void xi2HandleHierarchyEvent(void *event);
void xi2HandleDeviceChangedEvent(void *event); void xi2HandleDeviceChangedEvent(void *event);
int m_xiOpCode, m_xiEventBase, m_xiErrorBase; int m_xiOpCode;
#ifdef XCB_USE_XINPUT22
void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow); void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow);
#endif // XCB_USE_XINPUT22
#if QT_CONFIG(tabletevent) #if QT_CONFIG(tabletevent)
struct TabletData { struct TabletData {
int deviceId = 0; int deviceId = 0;
@ -634,14 +618,11 @@ private:
QPointF lastScrollPosition; QPointF lastScrollPosition;
}; };
QHash<int, ScrollingDevice> m_scrollingDevices; QHash<int, ScrollingDevice> m_scrollingDevices;
#ifdef XCB_USE_XINPUT21
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice); void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
void xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice); void xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice);
ScrollingDevice *scrollingDeviceForId(int id); ScrollingDevice *scrollingDeviceForId(int id);
#endif
static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value); static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);
static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event);
#endif #endif
xcb_connection_t *m_connection = nullptr; xcb_connection_t *m_connection = nullptr;
@ -675,16 +656,14 @@ private:
#endif #endif
QXcbEventReader *m_reader = nullptr; QXcbEventReader *m_reader = nullptr;
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
QHash<int, TouchDeviceData> m_touchDevices; QHash<int, TouchDeviceData> m_touchDevices;
#ifdef XCB_USE_XINPUT22
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 corner; int corner;
} m_startSystemMoveResizeInfo; } m_startSystemMoveResizeInfo;
#endif
#endif #endif
WindowMapper m_mapper; WindowMapper m_mapper;
@ -693,6 +672,9 @@ private:
uint32_t xfixes_first_event = 0; uint32_t xfixes_first_event = 0;
uint32_t xrandr_first_event = 0; uint32_t xrandr_first_event = 0;
uint32_t xkb_first_event = 0; uint32_t xkb_first_event = 0;
#if QT_CONFIG(xcb_xinput)
uint32_t xinput_first_event = 0;
#endif
bool has_xfixes = false; bool has_xfixes = false;
bool has_xinerama_extension = false; bool has_xinerama_extension = false;
@ -726,7 +708,7 @@ private:
QHash<qint32, qint32> m_peekerToCachedIndex; QHash<qint32, qint32> m_peekerToCachedIndex;
friend class QXcbEventReader; friend class QXcbEventReader;
}; };
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
#if QT_CONFIG(tabletevent) #if QT_CONFIG(tabletevent)
Q_DECLARE_TYPEINFO(QXcbConnection::TabletData::ValuatorClassInfo, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QXcbConnection::TabletData::ValuatorClassInfo, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE);

File diff suppressed because it is too large Load Diff

View File

@ -52,10 +52,8 @@
#include <xkbcommon/xkbcommon-keysyms.h> #include <xkbcommon/xkbcommon-keysyms.h>
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
#include <X11/extensions/XI2proto.h> #include <xcb/xinput.h>
#undef KeyPress
#undef KeyRelease
#endif #endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -824,20 +822,20 @@ void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
} }
} }
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo) void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
{ {
if (m_config && !connection()->hasXKB()) { if (m_config && !connection()->hasXKB()) {
xXIModifierInfo *mods = static_cast<xXIModifierInfo *>(modInfo); auto *mods = static_cast<xcb_input_modifier_info_t *>(modInfo);
xXIGroupInfo *group = static_cast<xXIGroupInfo *>(groupInfo); auto *group = static_cast<xcb_input_group_info_t *>(groupInfo);
const xkb_state_component changedComponents const xkb_state_component changedComponents
= xkb_state_update_mask(m_xkbState.get(), = xkb_state_update_mask(m_xkbState.get(),
mods->base_mods, mods->base,
mods->latched_mods, mods->latched,
mods->locked_mods, mods->locked,
group->base_group, group->base,
group->latched_group, group->latched,
group->locked_group); group->locked);
handleStateChanges(changedComponents); handleStateChanges(changedComponents);
} }

View File

@ -74,7 +74,7 @@ public:
void updateXKBMods(); void updateXKBMods();
xkb_mod_mask_t xkbModMask(quint16 state); xkb_mod_mask_t xkbModMask(quint16 state);
void updateXKBStateFromCore(quint16 state); void updateXKBStateFromCore(quint16 state);
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
void updateXKBStateFromXI(void *modInfo, void *groupInfo); void updateXKBStateFromXI(void *modInfo, void *groupInfo);
#endif #endif
#if QT_CONFIG(xkb) #if QT_CONFIG(xkb)

View File

@ -68,6 +68,9 @@
#undef class #undef class
#include <xcb/xfixes.h> #include <xcb/xfixes.h>
#include <xcb/shape.h> #include <xcb/shape.h>
#if QT_CONFIG(xcb_xinput)
#include <xcb/xinput.h>
#endif
// xcb-icccm 3.8 support // xcb-icccm 3.8 support
#ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS #ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
@ -105,11 +108,6 @@
#include <X11/Xutil.h> #include <X11/Xutil.h>
#endif #endif
#if QT_CONFIG(xinput2)
#include <X11/extensions/XInput2.h>
#include <X11/extensions/XI2proto.h>
#endif
#define XCOORD_MAX 16383 #define XCOORD_MAX 16383
enum { enum {
defaultWindowWidth = 160, defaultWindowWidth = 160,
@ -520,7 +518,7 @@ void QXcbWindow::create()
atom(QXcbAtom::_XEMBED_INFO), atom(QXcbAtom::_XEMBED_INFO),
32, 2, (void *)data); 32, 2, (void *)data);
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
if (connection()->hasXInput2()) { if (connection()->hasXInput2()) {
if (connection()->xi2MouseEventsDisabled()) if (connection()->xi2MouseEventsDisabled())
connection()->xi2SelectDeviceEventsCompatibility(m_window); connection()->xi2SelectDeviceEventsCompatibility(m_window);
@ -2149,7 +2147,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
QPoint global(root_x, root_y); QPoint global(root_x, root_y);
if (isWheel) { if (isWheel) {
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
if (!connection()->isAtLeastXI21()) { if (!connection()->isAtLeastXI21()) {
#endif #endif
QPoint angleDelta; QPoint angleDelta;
@ -2164,7 +2162,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
if (modifiers & Qt::AltModifier) if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry()); std::swap(angleDelta.rx(), angleDelta.ry());
QWindowSystemInterface::handleWheelEvent(window(), timestamp, local, global, QPoint(), angleDelta, modifiers); QWindowSystemInterface::handleWheelEvent(window(), timestamp, local, global, QPoint(), angleDelta, modifiers);
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
} }
#endif #endif
return; return;
@ -2204,7 +2202,7 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
if (conn) { if (conn) {
const bool mouseButtonsPressed = (conn->buttonState() != Qt::NoButton); const bool mouseButtonsPressed = (conn->buttonState() != Qt::NoButton);
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
return mouseButtonsPressed || (conn->hasXInput2() && !conn->xi2MouseEventsDisabled()); return mouseButtonsPressed || (conn->hasXInput2() && !conn->xi2MouseEventsDisabled());
#else #else
return mouseButtonsPressed; return mouseButtonsPressed;
@ -2253,7 +2251,7 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
quint8 mode, quint8 detail, xcb_timestamp_t timestamp) quint8 mode, quint8 detail, xcb_timestamp_t timestamp)
{ {
connection()->setTime(timestamp); connection()->setTime(timestamp);
#ifdef XCB_USE_XINPUT21 #if QT_CONFIG(xcb_xinput)
// Updates scroll valuators, as user might have done some scrolling outside our X client. // Updates scroll valuators, as user might have done some scrolling outside our X client.
connection()->xi2UpdateScrollingDevices(); connection()->xi2UpdateScrollingDevices();
#endif #endif
@ -2330,16 +2328,18 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
event->time, QEvent::MouseMove); event->time, QEvent::MouseMove);
} }
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
static inline int fixed1616ToInt(FP1616 val) static inline int fixed1616ToInt(xcb_input_fp1616_t val)
{ {
return int(qreal(val) / 0x10000); return int(qreal(val) / 0x10000);
} }
#define qt_xcb_mask_is_set(ptr, event) (((unsigned char*)(ptr))[(event)>>3] & (1 << ((event) & 7)))
void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource source) void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource source)
{ {
QXcbConnection *conn = connection(); QXcbConnection *conn = connection();
xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event); auto *ev = reinterpret_cast<xcb_input_button_press_event_t *>(event);
if (ev->buttons_len > 0) { if (ev->buttons_len > 0) {
unsigned char *buttonMask = (unsigned char *) &ev[1]; unsigned char *buttonMask = (unsigned char *) &ev[1];
@ -2347,16 +2347,16 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource
// XIPointerEmulated being set: https://bugs.freedesktop.org/show_bug.cgi?id=98188 // XIPointerEmulated being set: https://bugs.freedesktop.org/show_bug.cgi?id=98188
// Filter them out by other attributes: when their source device is a touch screen // Filter them out by other attributes: when their source device is a touch screen
// and the LMB is pressed. // and the LMB is pressed.
if (XIMaskIsSet(buttonMask, 1) && conn->isTouchScreen(ev->sourceid)) { if (qt_xcb_mask_is_set(buttonMask, 1) && conn->isTouchScreen(ev->sourceid)) {
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInput, "XI2 mouse event from touch device %d was ignored", ev->sourceid); qCDebug(lcQpaXInput, "XI2 mouse event from touch device %d was ignored", ev->sourceid);
return; return;
} }
for (int i = 1; i <= 15; ++i) for (int i = 1; i <= 15; ++i)
conn->setButtonState(conn->translateMouseButton(i), XIMaskIsSet(buttonMask, i)); conn->setButtonState(conn->translateMouseButton(i), qt_xcb_mask_is_set(buttonMask, i));
} }
const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective_mods); const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective);
const int event_x = fixed1616ToInt(ev->event_x); const int event_x = fixed1616ToInt(ev->event_x);
const int event_y = fixed1616ToInt(ev->event_y); const int event_y = fixed1616ToInt(ev->event_y);
const int root_x = fixed1616ToInt(ev->root_x); const int root_x = fixed1616ToInt(ev->root_x);
@ -2373,47 +2373,47 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource
sourceName = me.valueToKey(source); sourceName = me.valueToKey(source);
} }
switch (ev->evtype) { switch (ev->event_type) {
case XI_ButtonPress: case XCB_INPUT_BUTTON_PRESS:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName); qCDebug(lcQpaXInputEvents, "XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, true); conn->setButtonState(button, true);
handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source); handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source);
break; break;
case XI_ButtonRelease: case XCB_INPUT_BUTTON_RELEASE:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName); qCDebug(lcQpaXInputEvents, "XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, false); conn->setButtonState(button, false);
handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source); handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source);
break; break;
case XI_Motion: case XCB_INPUT_MOTION:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse motion %d,%d, time %d, source %s", event_x, event_y, ev->time, sourceName); qCDebug(lcQpaXInputEvents, "XI2 mouse motion %d,%d, time %d, source %s", event_x, event_y, ev->time, sourceName);
handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, QEvent::MouseMove, source); handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, QEvent::MouseMove, source);
break; break;
default: default:
qWarning() << "Unrecognized XI2 mouse event" << ev->evtype; qWarning() << "Unrecognized XI2 mouse event" << ev->event_type;
break; break;
} }
} }
void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event) void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event)
{ {
xXIEnterEvent *ev = reinterpret_cast<xXIEnterEvent *>(event); auto *ev = reinterpret_cast<xcb_input_enter_event_t *>(event);
// Compare the window with current mouse grabber to prevent deliver events to any other windows. // Compare the window with current mouse grabber to prevent deliver events to any other windows.
// If leave event occurs and the window is under mouse - allow to deliver the leave event. // If leave event occurs and the window is under mouse - allow to deliver the leave event.
QXcbWindow *mouseGrabber = connection()->mouseGrabber(); QXcbWindow *mouseGrabber = connection()->mouseGrabber();
if (mouseGrabber && mouseGrabber != this if (mouseGrabber && mouseGrabber != this
&& (ev->evtype != XI_Leave || QGuiApplicationPrivate::currentMouseWindow != window())) { && (ev->event_type != XCB_INPUT_LEAVE || QGuiApplicationPrivate::currentMouseWindow != window())) {
return; return;
} }
const int root_x = fixed1616ToInt(ev->root_x); const int root_x = fixed1616ToInt(ev->root_x);
const int root_y = fixed1616ToInt(ev->root_y); const int root_y = fixed1616ToInt(ev->root_y);
switch (ev->evtype) { switch (ev->event_type) {
case XI_Enter: { case XCB_INPUT_ENTER: {
const int event_x = fixed1616ToInt(ev->event_x); const int event_x = fixed1616ToInt(ev->event_x);
const int event_y = fixed1616ToInt(ev->event_y); const int event_y = fixed1616ToInt(ev->event_y);
qCDebug(lcQpaXInputEvents, "XI2 mouse enter %d,%d, mode %d, detail %d, time %d", qCDebug(lcQpaXInputEvents, "XI2 mouse enter %d,%d, mode %d, detail %d, time %d",
@ -2421,7 +2421,7 @@ void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event)
handleEnterNotifyEvent(event_x, event_y, root_x, root_y, ev->mode, ev->detail, ev->time); handleEnterNotifyEvent(event_x, event_y, root_x, root_y, ev->mode, ev->detail, ev->time);
break; break;
} }
case XI_Leave: case XCB_INPUT_LEAVE:
qCDebug(lcQpaXInputEvents, "XI2 mouse leave, mode %d, detail %d, time %d", qCDebug(lcQpaXInputEvents, "XI2 mouse leave, mode %d, detail %d, time %d",
ev->mode, ev->detail, ev->time); ev->mode, ev->detail, ev->time);
connection()->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group); connection()->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group);
@ -2563,7 +2563,7 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
if (grab && !connection()->canGrab()) if (grab && !connection()->canGrab())
return false; return false;
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
if (connection()->hasXInput2() && !connection()->xi2MouseEventsDisabled()) { if (connection()->hasXInput2() && !connection()->xi2MouseEventsDisabled()) {
bool result = connection()->xi2SetMouseGrabEnabled(m_window, grab); bool result = connection()->xi2SetMouseGrabEnabled(m_window, grab);
if (grab && result) if (grab && result)
@ -2654,7 +2654,7 @@ bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int corner)
if (!connection()->wmSupport()->isSupportedByWM(moveResize)) if (!connection()->wmSupport()->isSupportedByWM(moveResize))
return false; return false;
const QPoint globalPos = QHighDpi::toNativePixels(window()->mapToGlobal(pos), window()->screen()); const QPoint globalPos = QHighDpi::toNativePixels(window()->mapToGlobal(pos), window()->screen());
#ifdef XCB_USE_XINPUT22 #if QT_CONFIG(xcb_xinput)
if (connection()->startSystemMoveResizeForTouchBegin(m_window, globalPos, corner)) if (connection()->startSystemMoveResizeForTouchBegin(m_window, globalPos, corner))
return true; return true;
#endif #endif

View File

@ -139,7 +139,7 @@ public:
void handleFocusInEvent(const xcb_focus_in_event_t *event) override; void handleFocusInEvent(const xcb_focus_in_event_t *event) override;
void handleFocusOutEvent(const xcb_focus_out_event_t *event) override; void handleFocusOutEvent(const xcb_focus_out_event_t *event) override;
void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override; void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override;
#if QT_CONFIG(xinput2) #if QT_CONFIG(xcb_xinput)
void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized) override; void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized) override;
void handleXIEnterLeave(xcb_ge_event_t *) override; void handleXIEnterLeave(xcb_ge_event_t *) override;
#endif #endif

View File

@ -55,11 +55,10 @@ DEFINES += QT_BUILD_XCB_PLUGIN
qtConfig(xcb-xlib) { qtConfig(xcb-xlib) {
QMAKE_USE += xcb_xlib QMAKE_USE += xcb_xlib
}
qtConfig(xinput2) { qtConfig(xcb-xinput) {
SOURCES += qxcbconnection_xi2.cpp SOURCES += qxcbconnection_xi2.cpp
QMAKE_USE += xinput2
}
} }
qtConfig(xcb-sm) { qtConfig(xcb-sm) {
@ -86,6 +85,7 @@ qtConfig(vulkan) {
} else { } else {
qtConfig(xkb): QMAKE_USE += xcb_xkb qtConfig(xkb): QMAKE_USE += xcb_xkb
qtConfig(xcb-render): QMAKE_USE += xcb_render qtConfig(xcb-render): QMAKE_USE += xcb_render
qtConfig(xcb-xinput): QMAKE_USE += xcb_xinput
QMAKE_USE += xcb_syslibs QMAKE_USE += xcb_syslibs
} }