#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "clutter-input-device-x11.h" #include "../clutter-debug.h" #include "../clutter-private.h" #ifdef HAVE_XINPUT #include #endif typedef struct _ClutterInputDeviceClass ClutterInputDeviceX11Class; /* a specific X11 input device */ struct _ClutterInputDeviceX11 { ClutterInputDevice device; #ifdef HAVE_XINPUT XDevice *xdevice; XEventClass xevent_list[5]; /* MAX 5 event types */ int num_events; #endif guint is_core : 1; }; enum { PROP_0, PROP_IS_CORE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterInputDeviceX11, clutter_input_device_x11, CLUTTER_TYPE_INPUT_DEVICE); static void clutter_input_device_x11_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterInputDeviceX11 *self = CLUTTER_INPUT_DEVICE_X11 (gobject); switch (prop_id) { case PROP_IS_CORE: self->is_core = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_input_device_x11_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterInputDeviceX11 *self = CLUTTER_INPUT_DEVICE_X11 (gobject); switch (prop_id) { case PROP_IS_CORE: g_value_set_boolean (value, self->is_core); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_input_device_x11_class_init (ClutterInputDeviceX11Class *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; gobject_class->set_property = clutter_input_device_x11_set_property; gobject_class->get_property = clutter_input_device_x11_get_property; pspec = g_param_spec_boolean ("is-core", "Is Core", "Whether the device is a core one", FALSE, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_IS_CORE] = pspec; g_object_class_install_property (gobject_class, PROP_IS_CORE, pspec); } static void clutter_input_device_x11_init (ClutterInputDeviceX11 *self) { self->is_core = FALSE; } gint _clutter_input_device_x11_construct (ClutterInputDevice *device, ClutterBackendX11 *backend) { int n_events = 0; #ifdef HAVE_XINPUT ClutterInputDeviceX11 *device_x11; XDevice *x_device = NULL; gint device_id; int i; device_x11 = CLUTTER_INPUT_DEVICE_X11 (device); device_id = clutter_input_device_get_device_id (device); clutter_x11_trap_x_errors (); /* retrieve the X11 device */ x_device = XOpenDevice (backend->xdpy, device_id); if (clutter_x11_untrap_x_errors () || x_device == NULL) { CLUTTER_NOTE (BACKEND, "Unable to open device %i", device_id); return 0; } device_x11->xdevice = x_device; CLUTTER_NOTE (BACKEND, "Registering XINPUT device with XID: %li", x_device->device_id); /* We must go through all the classes supported by this device and * register the appropriate events we want. Each class only appears * once. We need to store the types with the stage since they are * created dynamically by the server. They are not device specific. */ for (i = 0; i < x_device->num_classes; i++) { XInputClassInfo *xclass_info = x_device->classes + i; int *button_press, *button_release, *motion_notify; int *key_press, *key_release; button_press = &backend->event_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT]; button_release = &backend->event_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT]; motion_notify = &backend->event_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT]; key_press = &backend->event_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT]; key_release = &backend->event_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT]; switch (xclass_info->input_class) { /* event though XInput 1.x is broken for keyboard-like devices * it might still be useful to track them down; the core keyboard * will handle the right events anyway */ case KeyClass: DeviceKeyPress (x_device, *key_press, device_x11->xevent_list[n_events]); n_events++; DeviceKeyRelease (x_device, *key_release, device_x11->xevent_list[n_events]); n_events++; break; case ButtonClass: DeviceButtonPress (x_device, *button_press, device_x11->xevent_list[n_events]); n_events++; DeviceButtonRelease (x_device, *button_release, device_x11->xevent_list[n_events]); n_events++; break; case ValuatorClass: DeviceMotionNotify (x_device, *motion_notify, device_x11->xevent_list[n_events]); n_events++; break; } } device_x11->num_events = n_events; #endif /* HAVE_XINPUT */ return n_events; } void _clutter_input_device_x11_select_events (ClutterInputDevice *device, ClutterBackendX11 *backend_x11, Window xwin) { #if HAVE_XINPUT ClutterInputDeviceX11 *device_x11; device_x11 = CLUTTER_INPUT_DEVICE_X11 (device); if (device_x11->xdevice == None || device_x11->num_events == 0) return; XSelectExtensionEvent (backend_x11->xdpy, xwin, device_x11->xevent_list, device_x11->num_events); #endif /* HAVE_XINPUT */ }