From e71f7d7736ec2c845206daa5a48921affbcf8e44 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 19 Jul 2017 09:09:16 +0200 Subject: [PATCH] xcb: fix freeze when (un)plugging input devices .. in an application that has many native windows. We don't need to select XI_HierarchyChangedMask and XI_DeviceChangedMask for every window. It is enough to register one window for these events to update state of our X11 client (application). Furthermore, XIAllDevices and XIAllMasterDevices always apply, even if the device has been added after the client has selected for events. So there is no need to call XISelectEvents on XIAllDevices/XIAllMasterDevices again, if we are not updating event masks. With this patch and the test application from QTBUG-57013, removing/attaching a device takes few hundred milliseconds instead of 23-24 seconds. Task-number: QTBUG-57013 Change-Id: Ieb0b5ee25feef2922f901165825cb4a1289fc852 Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbconnection.h | 1 + .../platforms/xcb/qxcbconnection_xi2.cpp | 28 +++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index bba987983e..1129090eca 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -428,6 +428,7 @@ public: #if QT_CONFIG(xinput2) void xi2Select(xcb_window_t window); + void xi2SelectStateEvents(); #endif #ifdef XCB_USE_XINPUT21 bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; } diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 4d2a83b3cf..38ea2d9ab9 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -90,12 +90,29 @@ void QXcbConnection::initializeXInput2() #else qCDebug(lcQpaXInputDevices, "XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor); #endif + xi2SelectStateEvents(); } xi2SetupDevices(); } } +void QXcbConnection::xi2SelectStateEvents() +{ + // These state events do not depend on a specific X window, but are global + // for the X client's (application's) state. + unsigned int bitMask = 0; + unsigned char *xiBitMask = reinterpret_cast(&bitMask); + XIEventMask xiEventMask; + bitMask = XI_HierarchyChangedMask; + bitMask |= XI_DeviceChangedMask; + xiEventMask.deviceid = XIAllDevices; + xiEventMask.mask_len = sizeof(bitMask); + xiEventMask.mask = xiBitMask; + Display *dpy = static_cast(m_xlib_display); + XISelectEvents(dpy, DefaultRootWindow(dpy), &xiEventMask, 1); +} + void QXcbConnection::xi2SetupDevices() { #if QT_CONFIG(tabletevent) @@ -371,17 +388,6 @@ void QXcbConnection::xi2Select(xcb_window_t window) #else Q_UNUSED(xiBitMask); #endif - - { - // Listen for hotplug events - XIEventMask xiEventMask; - bitMask = XI_HierarchyChangedMask; - bitMask |= XI_DeviceChangedMask; - xiEventMask.deviceid = XIAllDevices; - xiEventMask.mask_len = sizeof(bitMask); - xiEventMask.mask = xiBitMask; - XISelectEvents(xDisplay, window, &xiEventMask, 1); - } } XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id)