diff --git a/CMakeLists.txt b/CMakeLists.txt
index 19ba8ee..dc75e8f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,55 +1,55 @@
cmake_minimum_required(VERSION 3.0)
project(wacomtablet)
set(QT_MIN_VERSION "5.3.0")
find_package(ECM 1.6.0 REQUIRED CONFIG)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake/modules)
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(FeatureSummary)
include(ECMOptionalAddSubdirectory)
include(ECMInstallIcons)
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets DBus X11Extras Qml)
find_package(KF5 REQUIRED COMPONENTS CoreAddons I18n GlobalAccel Config XmlGui WidgetsAddons WindowSystem Notifications DBusAddons Plasma DocTools)
find_package(XCB REQUIRED COMPONENTS RANDR OPTIONAL_COMPONENTS XINPUT)
find_package(X11 REQUIRED COMPONENTS XLIB RANDR)
find_package(XorgWacom REQUIRED)
# xcb-xinput is an experimental API and is not built by default in the xcb
# repository. Downstream distributions without xcb-xinput, such as Kubuntu, can
# build using the Xlib version of the library instead.
#
# Because Qt5 uses xcb exclusively for native event handling, kded is unable
# to monitor hotplugging events, since these are signaled as xinput events.
#
# Users can enable xcb-xinput by building xcb with the configuration flag --enable-xinput.
if(XCB_XINPUT_FOUND)
message(STATUS "Using XCB_XINPUT. Please note this is an unstable API.")
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()
add_definitions( -DQT_STRICT_ITERATORS )
add_definitions( -DQT_NO_CAST_FROM_ASCII )
add_definitions( -DQT_NO_CAST_TO_ASCII )
add_definitions( -DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS )
add_subdirectory( src )
add_subdirectory( data )
add_subdirectory( images )
add_subdirectory( doc )
### Tests
if(BUILD_TESTING)
find_package(Qt5Test ${QT_MIN_VERSION} CONFIG REQUIRED)
add_subdirectory( autotests )
endif()
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/src/kded/x11eventnotifier-xlib.cpp b/src/kded/x11eventnotifier-xlib.cpp
index 82c1da7..705e2f0 100644
--- a/src/kded/x11eventnotifier-xlib.cpp
+++ b/src/kded/x11eventnotifier-xlib.cpp
@@ -1,146 +1,194 @@
/*
* This file is part of the KDE wacomtablet project. For copyright
* information and license terms see the AUTHORS and COPYING files
* in the top-level directory of this distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "debug.h" // always needs to be first include
#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
{
public:
bool isStarted = false;
};
}
using namespace Wacom;
X11EventNotifier::X11EventNotifier()
: EventNotifier(nullptr)
, QAbstractNativeEventFilter()
, d_ptr(new X11EventNotifierPrivate)
{
}
X11EventNotifier::~X11EventNotifier()
{
delete d_ptr;
}
X11EventNotifier& X11EventNotifier::instance()
{
static X11EventNotifier instance;
return instance;
}
void X11EventNotifier::start()
{
Q_D (X11EventNotifier);
if (d->isStarted) {
return;
}
if( QCoreApplication::instance() != nullptr ) {
registerForNewDeviceEvent(QX11Info::connection());
QCoreApplication::instance()->installNativeEventFilter(this);
d->isStarted = true;
}
}
void X11EventNotifier::stop()
{
Q_D (X11EventNotifier);
if( QCoreApplication::instance() != nullptr ) {
QCoreApplication::instance()->removeNativeEventFilter(this);
d->isStarted = false;
}
}
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;
}