diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ set(USING_X_LIBRARIES XCB::XINPUT XCB::RANDR ${X11_Xrandr_LIB} ${X11_Xinput_LIB}) add_definitions(-DHAVE_XCB_XINPUT) else() - message(STATUS "Falling back to X11_XINPUT. (Daemon will be unable to monitor hotplugging.)") + message(STATUS "Falling back to X11_XINPUT.") set(USING_X_LIBRARIES XCB::RANDR ${X11_LIBRARIES} ${X11_Xinput_LIB} ${X11_Xrandr_LIB}) endif() diff --git a/src/kded/x11eventnotifier-xlib.cpp b/src/kded/x11eventnotifier-xlib.cpp --- a/src/kded/x11eventnotifier-xlib.cpp +++ b/src/kded/x11eventnotifier-xlib.cpp @@ -22,21 +22,53 @@ #include #include - #include "x11eventnotifier.h" #include "x11input.h" #include "x11inputdevice.h" #include -#include - -#include -#include -#include -#include #include +/* XCB events have a slightly different layout, so they can't be directly + * treated as XIGenericDeviceEvent. Instead of doing a memmove like + * Qt does in qtbase/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp, + * we pull in the correct struct definition here. */ + +typedef enum xcb_input_hierarchy_mask_t { + XCB_INPUT_HIERARCHY_MASK_MASTER_ADDED = 1, + XCB_INPUT_HIERARCHY_MASK_MASTER_REMOVED = 2, + XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED = 4, + XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED = 8, + XCB_INPUT_HIERARCHY_MASK_SLAVE_ATTACHED = 16, + XCB_INPUT_HIERARCHY_MASK_SLAVE_DETACHED = 32, + XCB_INPUT_HIERARCHY_MASK_DEVICE_ENABLED = 64, + XCB_INPUT_HIERARCHY_MASK_DEVICE_DISABLED = 128 +} xcb_input_hierarchy_mask_t; + +typedef struct xcb_input_hierarchy_event_t { + uint8_t response_type; + uint8_t extension; + uint16_t sequence; + uint32_t length; + uint16_t event_type; + uint8_t deviceid; + xcb_timestamp_t time; + uint32_t flags; + uint16_t num_infos; + uint8_t pad0[10]; + uint32_t full_sequence; +} xcb_input_hierarchy_event_t; + +typedef struct xcb_input_hierarchy_info_t { + uint8_t deviceid; + uint8_t attachment; + uint8_t type; + uint8_t enabled; + uint8_t pad0[2]; + uint32_t flags; +} xcb_input_hierarchy_info_t; + namespace Wacom { class X11EventNotifierPrivate @@ -101,46 +133,62 @@ bool X11EventNotifier::nativeEventFilter(const QByteArray &eventType, void *message, long int *result) { - Q_UNUSED(eventType); Q_UNUSED(result); + if (eventType != "xcb_generic_event_t") { + return false; + } + xcb_generic_event_t *event = static_cast(message); xcb_ge_generic_event_t *cookie = reinterpret_cast(message); if (event->response_type == XCB_GE_GENERIC && cookie->event_type == XI_HierarchyChanged) { - // handleX11InputEvent(cookie); - } else { - // handleX11ScreenEvent(event); + handleX11InputEvent(cookie); } - // return QWidget::x11Event(event); return false; } // Handle plug/unplug events void X11EventNotifier::handleX11InputEvent(xcb_ge_generic_event_t* event) { - Q_UNUSED(event) - // Sadly there does not seem to be a way to use this functionality :( + xcb_input_hierarchy_event_t *hev = reinterpret_cast(event); + xcb_input_hierarchy_info_t *data = reinterpret_cast(hev + 1); + + while(hev->num_infos--) { + if (data->flags & XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED) { + dbgWacom << QString::fromLatin1("X11 device with id '%1' removed.").arg(data->deviceid); + emit tabletRemoved(data->deviceid); + + } else if (data->flags & XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED) { + dbgWacom << QString::fromLatin1("X11 device with id '%1' added.").arg(data->deviceid); + + X11InputDevice device (data->deviceid, QLatin1String("Unknown X11 Device")); + + if (device.isOpen() && device.isTabletDevice()) { + dbgWacom << QString::fromLatin1("Wacom tablet device with X11 id '%1' added.").arg(data->deviceid); + emit tabletAdded(data->deviceid); + } + } + data++; + } } -int X11EventNotifier::registerForNewDeviceEvent(xcb_connection_t* conn) +int X11EventNotifier::registerForNewDeviceEvent(xcb_connection_t *conn) { Q_UNUSED(conn) - // This is already done by xcb plugin with more flags, doing this ourselves - // will break Qt's xrandr functionality because connection is shared with Qt. - // TODO: uncomment this again when we use our private connection. -#if 0 - //register RandR events - int rrmask = XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE; - - xcb_randr_select_input(conn, QX11Info::appRootWindow(), 0); - xcb_randr_select_input(conn, QX11Info::appRootWindow(), rrmask); -#endif - - return 0; + + Display *display = QX11Info::display(); + + unsigned int bitmask = XI_HierarchyChangedMask; + + XIEventMask mask; + mask.mask_len = sizeof(bitmask); + mask.mask = reinterpret_cast(&bitmask); + int status = XISelectEvents(display, DefaultRootWindow(display), &mask, 1); + return status == Success ? 0 : 1; }