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 <allan.jensen@qt.io>
This commit is contained in:
Gatis Paeglis 2017-07-19 09:09:16 +02:00
parent 4585889467
commit e71f7d7736
2 changed files with 18 additions and 11 deletions

View File

@ -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; }

View File

@ -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<unsigned char *>(&bitMask);
XIEventMask xiEventMask;
bitMask = XI_HierarchyChangedMask;
bitMask |= XI_DeviceChangedMask;
xiEventMask.deviceid = XIAllDevices;
xiEventMask.mask_len = sizeof(bitMask);
xiEventMask.mask = xiBitMask;
Display *dpy = static_cast<Display *>(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)