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]
-mtdev ............. Enable mtdev 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
[system/qt/no]
-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-native-painting": "boolean",
"xcb-xlib": "boolean",
"xinput2": "boolean",
"xcb-xinput": "boolean",
"xkb": "boolean",
"xkbcommon": { "type": "enum", "values": [ "no", "qt", "system" ] },
"xkbcommon-evdev": "boolean",
@ -566,33 +566,22 @@
"-lxcb-glx -lxcb"
]
},
"xinput2": {
"label": "Xinput2",
"xcb_xinput": {
"label": "XCB XInput",
"test": {
"include": [ "X11/Xlib.h", "X11/extensions/XInput2.h", "X11/extensions/Xge.h" ],
"tail": [
"#ifndef XInput_2_0",
"# error Missing XInput_2_0 #define",
"#endif"
],
"include": [ "xcb/xcb.h", "xcb/xinput.h" ],
"main": [
"// need XGenericEventCookie for XInput2 to work",
"Display *dpy = 0;",
"XEvent xevent;",
"XIEvent *xievent = 0;",
"XIDeviceEvent *xideviceevent = 0;",
"XIHierarchyEvent *xihierarchyevent = 0;",
"int deviceid = 0;",
"int len = 0;",
"(void) XGetEventData(dpy, &xevent.xcookie);",
"XFreeEventData(dpy, &xevent.xcookie);",
"(void) XIListProperties(dpy, deviceid, &len);"
],
"qmake": "CONFIG += x11"
"int primaryScreen = 0;",
"xcb_connection_t *connection = xcb_connect(\"\", &primaryScreen);",
"xcb_generic_error_t *error = 0;",
"xcb_input_xi_query_version_cookie_t xinput_query_cookie = xcb_input_xi_query_version(",
" connection, XCB_INPUT_MAJOR_VERSION, XCB_INPUT_MINOR_VERSION);",
"xcb_input_xi_query_version_reply(connection, xinput_query_cookie, &error);"
]
},
"sources": [
{ "type": "pkgConfig", "args": "xi" },
"-lXi"
{ "type": "pkgConfig", "args": "xcb-xinput >= 1.12 xcb" },
"-lxcb-xinput -lxcb"
]
},
"xkbcommon": {
@ -1352,10 +1341,10 @@
"condition": "features.sessionmanager && libs.x11sm",
"output": [ "privateFeature" ]
},
"xinput2": {
"label": "Xinput2",
"xcb-xinput": {
"label": "XCB XInput",
"emitIf": "features.xcb",
"condition": "features.xcb-xlib && libs.xinput2",
"condition": "!features.system-xcb || libs.xcb_xinput",
"output": [ "privateFeature" ]
},
"xkbcommon-evdev": {
@ -1726,7 +1715,7 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla
"section": "X11",
"condition": "features.xcb",
"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
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:
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
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.
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>
#endif
#if QT_CONFIG(xinput2)
#include <X11/extensions/XI2proto.h>
#if QT_CONFIG(xcb_xinput)
#include <xcb/xinput.h>
#endif
#if QT_CONFIG(xcb_render)
@ -120,7 +120,7 @@ Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard")
#define XCB_GE_GENERIC 35
#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:
// - "pad0" became "extension"
// - "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);
return e->extension == opCode;
}
#endif // QT_CONFIG(xinput2)
#endif // QT_CONFIG(xcb_xinput)
#if QT_CONFIG(xcb_xlib)
static const char * const xcbConnectionErrors[] = {
@ -572,6 +572,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
#endif
#if QT_CONFIG(xcb_render)
&xcb_render_id,
#endif
#if QT_CONFIG(xcb_xinput)
&xcb_input_id,
#endif
0
};
@ -592,7 +595,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeScreens();
initializeXRender();
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2"))
initializeXInput2();
#endif
@ -1105,13 +1108,13 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
handleClientMessageEvent((xcb_client_message_event_t *)event);
break;
case XCB_ENTER_NOTIFY:
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
if (hasXInput2() && !xi2MouseEventsDisabled())
break;
#endif
HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
case XCB_LEAVE_NOTIFY:
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
if (hasXInput2() && !xi2MouseEventsDisabled())
break;
#endif
@ -1174,7 +1177,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
}
break;
}
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
case XCB_GE_GENERIC:
// Here the windowEventListener is invoked from xi2HandleEvent()
if (hasXInput2() && isXIEvent(event, m_xiOpCode))
@ -1630,16 +1633,14 @@ void *QXcbConnection::createVisualInfoForDefaultVisualId() const
#endif
#if QT_CONFIG(xinput2)
// 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
#if QT_CONFIG(xcb_xinput)
static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t type)
{
if (!isXIEvent(event, opCode))
return false;
xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
return xiEvent->evtype == type;
auto *e = reinterpret_cast<qt_xcb_ge_event_t *>(event);
return e->event_type == type;
}
#endif
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;
}
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
// compress XI_* events
if (responseType == XCB_GE_GENERIC) {
if (!hasXInput2())
return false;
// 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)
xXIDeviceEvent *xdev = reinterpret_cast<xXIDeviceEvent *>(event);
auto *xdev = reinterpret_cast<xcb_input_motion_event_t *>(event);
if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) &&
const_cast<QXcbConnection *>(this)->tabletDataForDevice(xdev->sourceid))
return false;
@ -1693,29 +1694,27 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex,
xcb_generic_event_t *next = eventqueue->at(j);
if (!isValid(next))
continue;
if (isXIType(next, m_xiOpCode, XI_Motion))
if (isXIType(next, m_xiOpCode, XCB_INPUT_MOTION))
return true;
}
return false;
}
#ifdef XCB_USE_XINPUT22
// compress XI_TouchUpdate for the same touch point id
if (isXIType(event, m_xiOpCode, XI_TouchUpdate)) {
xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
uint32_t id = xiDeviceEvent->detail % INT_MAX;
if (isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) {
auto *touchUpdateEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(event);
uint32_t id = touchUpdateEvent->detail % INT_MAX;
for (int j = nextIndex; j < eventqueue->size(); ++j) {
xcb_generic_event_t *next = eventqueue->at(j);
if (!isValid(next))
continue;
if (isXIType(next, m_xiOpCode, XI_TouchUpdate)) {
xXIDeviceEvent *xiDeviceNextEvent = reinterpret_cast<xXIDeviceEvent *>(next);
if (id == xiDeviceNextEvent->detail % INT_MAX)
if (isXIType(next, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) {
auto *touchUpdateNextEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(next);
if (id == touchUpdateNextEvent->detail % INT_MAX)
return true;
}
}
return false;
}
#endif
return false;
}
#endif

View File

@ -71,16 +71,6 @@
#include <QTabletEvent>
#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;
QT_BEGIN_NAMESPACE
@ -359,7 +349,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 *) {}
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
virtual void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource = Qt::MouseEventNotSynthesized) {}
virtual void handleXIEnterLeave(xcb_ge_event_t *) {}
#endif
@ -511,7 +501,7 @@ public:
static bool xEmbedSystemTrayAvailable();
static bool xEmbedSystemTrayVisualHasAlphaChannel();
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
void xi2SelectStateEvents();
void xi2SelectDeviceEvents(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 isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; }
Qt::MouseButton xiToQtMouseButton(uint32_t b);
#ifdef XCB_USE_XINPUT21
void xi2UpdateScrollingDevices();
#endif
#ifdef XCB_USE_XINPUT22
bool startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner);
bool isTouchScreen(int id);
#endif
#endif
QXcbEventReader *eventReader() const { return m_reader; }
@ -568,7 +554,7 @@ private:
bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const;
bool m_xi2Enabled = false;
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
int m_xi2Minor = -1;
void initializeXInput2();
void xi2SetupDevice(void *info, bool removeExisting = true);
@ -596,10 +582,8 @@ private:
void xi2HandleEvent(xcb_ge_event_t *event);
void xi2HandleHierarchyEvent(void *event);
void xi2HandleDeviceChangedEvent(void *event);
int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
#ifdef XCB_USE_XINPUT22
int m_xiOpCode;
void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow);
#endif // XCB_USE_XINPUT22
#if QT_CONFIG(tabletevent)
struct TabletData {
int deviceId = 0;
@ -634,14 +618,11 @@ private:
QPointF lastScrollPosition;
};
QHash<int, ScrollingDevice> m_scrollingDevices;
#ifdef XCB_USE_XINPUT21
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
void xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice);
ScrollingDevice *scrollingDeviceForId(int id);
#endif
static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);
static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event);
#endif
xcb_connection_t *m_connection = nullptr;
@ -675,16 +656,14 @@ private:
#endif
QXcbEventReader *m_reader = nullptr;
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
QHash<int, TouchDeviceData> m_touchDevices;
#ifdef XCB_USE_XINPUT22
struct StartSystemMoveResizeInfo {
xcb_window_t window = XCB_NONE;
uint16_t deviceid;
uint32_t pointid;
int corner;
} m_startSystemMoveResizeInfo;
#endif
#endif
WindowMapper m_mapper;
@ -693,6 +672,9 @@ private:
uint32_t xfixes_first_event = 0;
uint32_t xrandr_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_xinerama_extension = false;
@ -726,7 +708,7 @@ private:
QHash<qint32, qint32> m_peekerToCachedIndex;
friend class QXcbEventReader;
};
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
#if QT_CONFIG(tabletevent)
Q_DECLARE_TYPEINFO(QXcbConnection::TabletData::ValuatorClassInfo, Q_PRIMITIVE_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>
#if QT_CONFIG(xinput2)
#include <X11/extensions/XI2proto.h>
#undef KeyPress
#undef KeyRelease
#if QT_CONFIG(xcb_xinput)
#include <xcb/xinput.h>
#endif
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)
{
if (m_config && !connection()->hasXKB()) {
xXIModifierInfo *mods = static_cast<xXIModifierInfo *>(modInfo);
xXIGroupInfo *group = static_cast<xXIGroupInfo *>(groupInfo);
auto *mods = static_cast<xcb_input_modifier_info_t *>(modInfo);
auto *group = static_cast<xcb_input_group_info_t *>(groupInfo);
const xkb_state_component changedComponents
= xkb_state_update_mask(m_xkbState.get(),
mods->base_mods,
mods->latched_mods,
mods->locked_mods,
group->base_group,
group->latched_group,
group->locked_group);
mods->base,
mods->latched,
mods->locked,
group->base,
group->latched,
group->locked);
handleStateChanges(changedComponents);
}

View File

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

View File

@ -68,6 +68,9 @@
#undef class
#include <xcb/xfixes.h>
#include <xcb/shape.h>
#if QT_CONFIG(xcb_xinput)
#include <xcb/xinput.h>
#endif
// xcb-icccm 3.8 support
#ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
@ -105,11 +108,6 @@
#include <X11/Xutil.h>
#endif
#if QT_CONFIG(xinput2)
#include <X11/extensions/XInput2.h>
#include <X11/extensions/XI2proto.h>
#endif
#define XCOORD_MAX 16383
enum {
defaultWindowWidth = 160,
@ -520,7 +518,7 @@ void QXcbWindow::create()
atom(QXcbAtom::_XEMBED_INFO),
32, 2, (void *)data);
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
if (connection()->hasXInput2()) {
if (connection()->xi2MouseEventsDisabled())
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);
if (isWheel) {
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
if (!connection()->isAtLeastXI21()) {
#endif
QPoint angleDelta;
@ -2164,7 +2162,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry());
QWindowSystemInterface::handleWheelEvent(window(), timestamp, local, global, QPoint(), angleDelta, modifiers);
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
}
#endif
return;
@ -2204,7 +2202,7 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
if (conn) {
const bool mouseButtonsPressed = (conn->buttonState() != Qt::NoButton);
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
return mouseButtonsPressed || (conn->hasXInput2() && !conn->xi2MouseEventsDisabled());
#else
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)
{
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.
connection()->xi2UpdateScrollingDevices();
#endif
@ -2330,16 +2328,18 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
event->time, QEvent::MouseMove);
}
#if QT_CONFIG(xinput2)
static inline int fixed1616ToInt(FP1616 val)
#if QT_CONFIG(xcb_xinput)
static inline int fixed1616ToInt(xcb_input_fp1616_t val)
{
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)
{
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) {
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
// Filter them out by other attributes: when their source device is a touch screen
// 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()))
qCDebug(lcQpaXInput, "XI2 mouse event from touch device %d was ignored", ev->sourceid);
return;
}
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_y = fixed1616ToInt(ev->event_y);
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);
}
switch (ev->evtype) {
case XI_ButtonPress:
switch (ev->event_type) {
case XCB_INPUT_BUTTON_PRESS:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, true);
handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source);
break;
case XI_ButtonRelease:
case XCB_INPUT_BUTTON_RELEASE:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, false);
handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source);
break;
case XI_Motion:
case XCB_INPUT_MOTION:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
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);
break;
default:
qWarning() << "Unrecognized XI2 mouse event" << ev->evtype;
qWarning() << "Unrecognized XI2 mouse event" << ev->event_type;
break;
}
}
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.
// If leave event occurs and the window is under mouse - allow to deliver the leave event.
QXcbWindow *mouseGrabber = connection()->mouseGrabber();
if (mouseGrabber && mouseGrabber != this
&& (ev->evtype != XI_Leave || QGuiApplicationPrivate::currentMouseWindow != window())) {
&& (ev->event_type != XCB_INPUT_LEAVE || QGuiApplicationPrivate::currentMouseWindow != window())) {
return;
}
const int root_x = fixed1616ToInt(ev->root_x);
const int root_y = fixed1616ToInt(ev->root_y);
switch (ev->evtype) {
case XI_Enter: {
switch (ev->event_type) {
case XCB_INPUT_ENTER: {
const int event_x = fixed1616ToInt(ev->event_x);
const int event_y = fixed1616ToInt(ev->event_y);
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);
break;
}
case XI_Leave:
case XCB_INPUT_LEAVE:
qCDebug(lcQpaXInputEvents, "XI2 mouse leave, mode %d, detail %d, time %d",
ev->mode, ev->detail, ev->time);
connection()->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group);
@ -2563,7 +2563,7 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
if (grab && !connection()->canGrab())
return false;
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
if (connection()->hasXInput2() && !connection()->xi2MouseEventsDisabled()) {
bool result = connection()->xi2SetMouseGrabEnabled(m_window, grab);
if (grab && result)
@ -2654,7 +2654,7 @@ bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int corner)
if (!connection()->wmSupport()->isSupportedByWM(moveResize))
return false;
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))
return true;
#endif

View File

@ -139,7 +139,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;
#if QT_CONFIG(xinput2)
#if QT_CONFIG(xcb_xinput)
void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized) override;
void handleXIEnterLeave(xcb_ge_event_t *) override;
#endif

View File

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