1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include "gdkdevicemanager-xi.h"
23 #include "gdkeventtranslator.h"
24 #include "gdkdevice-xi.h"
28 #include <X11/extensions/XInput.h>
31 struct _GdkDeviceManagerXIPrivate
36 gboolean ignore_core_events;
39 static void gdk_device_manager_xi_constructed (GObject *object);
40 static void gdk_device_manager_xi_finalize (GObject *object);
41 static void gdk_device_manager_xi_set_property (GObject *object,
45 static void gdk_device_manager_xi_get_property (GObject *object,
50 static void gdk_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface);
51 static gboolean gdk_device_manager_xi_translate_event (GdkEventTranslator *translator,
55 static GList * gdk_device_manager_xi_list_devices (GdkDeviceManager *device_manager,
59 G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerXI, gdk_device_manager_xi, GDK_TYPE_DEVICE_MANAGER_CORE,
60 G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
61 gdk_device_manager_xi_event_translator_init))
69 gdk_device_manager_xi_class_init (GdkDeviceManagerXIClass *klass)
71 GObjectClass *object_class = G_OBJECT_CLASS (klass);
72 GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
74 object_class->constructed = gdk_device_manager_xi_constructed;
75 object_class->finalize = gdk_device_manager_xi_finalize;
76 object_class->set_property = gdk_device_manager_xi_set_property;
77 object_class->get_property = gdk_device_manager_xi_get_property;
79 device_manager_class->list_devices = gdk_device_manager_xi_list_devices;
81 g_object_class_install_property (object_class,
83 g_param_spec_int ("event-base",
85 P_("Event base for XInput events"),
87 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
89 g_type_class_add_private (object_class, sizeof (GdkDeviceManagerXIPrivate));
92 static GdkFilterReturn
93 window_input_info_filter (GdkXEvent *xevent,
97 GdkDeviceManager *device_manager;
102 device_manager = user_data;
103 xev = (XEvent *) xevent;
105 display = gdk_device_manager_get_display (device_manager);
106 window = gdk_window_lookup_for_display (display, xev->xany.window);
108 if (window && xev->type == ConfigureNotify)
109 gdk_device_xi_update_window_info (window);
111 return GDK_FILTER_CONTINUE;
115 gdk_device_manager_xi_init (GdkDeviceManagerXI *device_manager)
117 GdkDeviceManagerXIPrivate *priv;
119 device_manager->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device_manager,
120 GDK_TYPE_DEVICE_MANAGER_XI,
121 GdkDeviceManagerXIPrivate);
123 priv->id_table = g_hash_table_new_full (NULL, NULL, NULL,
124 (GDestroyNotify) g_object_unref);
126 gdk_window_add_filter (NULL, window_input_info_filter, device_manager);
130 translate_class_info (GdkDevice *device,
133 GdkDeviceXI *device_xi;
137 device_xi = GDK_DEVICE_XI (device);
138 class = info->inputclassinfo;
140 for (i = 0; i < info->num_classes; i++)
142 switch (class->class) {
147 XKeyInfo *xki = (XKeyInfo *)class;
150 num_keys = xki->max_keycode - xki->min_keycode + 1;
151 _gdk_device_set_keys (device, num_keys);
153 device_xi->min_keycode = xki->min_keycode;
159 XValuatorInfo *xvi = (XValuatorInfo *)class;
161 for (j = 0; j < xvi->num_axes; j++)
174 use = GDK_AXIS_PRESSURE;
177 use = GDK_AXIS_XTILT;
180 use = GDK_AXIS_YTILT;
183 use = GDK_AXIS_WHEEL;
186 use = GDK_AXIS_IGNORE;
189 _gdk_device_add_axis (device,
192 xvi->axes[j].min_value,
193 xvi->axes[j].max_value,
194 xvi->axes[j].resolution);
201 class = (XAnyClassPtr) (((char *) class) + class->length);
205 /* old versions of XI.h don't define these */
206 #ifndef IsXExtensionKeyboard
207 #define IsXExtensionKeyboard 3
208 #define IsXExtensionPointer 4
212 create_device (GdkDeviceManager *device_manager,
216 GdkInputSource input_source;
219 if (info->use != IsXExtensionPointer &&
220 info->use != IsXExtensionKeyboard)
223 if (info->use == IsXExtensionKeyboard)
224 input_source = GDK_SOURCE_KEYBOARD;
229 tmp_name = g_ascii_strdown (info->name, -1);
231 if (strstr (tmp_name, "eraser"))
232 input_source = GDK_SOURCE_ERASER;
233 else if (strstr (tmp_name, "cursor"))
234 input_source = GDK_SOURCE_CURSOR;
235 else if (strstr (tmp_name, "wacom") ||
236 strstr (tmp_name, "pen"))
237 input_source = GDK_SOURCE_PEN;
239 input_source = GDK_SOURCE_MOUSE;
244 device = g_object_new (GDK_TYPE_DEVICE_XI,
246 "type", GDK_DEVICE_TYPE_FLOATING,
247 "input-source", input_source,
248 "input-mode", GDK_MODE_DISABLED,
251 "device-manager", device_manager,
252 "device-id", info->id,
254 translate_class_info (device, info);
260 gdk_device_manager_xi_constructed (GObject *object)
262 GdkDeviceManagerXIPrivate *priv;
263 XDeviceInfo *devices;
267 priv = GDK_DEVICE_MANAGER_XI (object)->priv;
268 display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
269 devices = XListInputDevices(GDK_DISPLAY_XDISPLAY (display), &num_devices);
271 for(i = 0; i < num_devices; i++)
275 device = create_device (GDK_DEVICE_MANAGER (object),
276 display, &devices[i]);
279 priv->devices = g_list_prepend (priv->devices, device);
280 g_hash_table_insert (priv->id_table,
281 GINT_TO_POINTER (devices[i].id),
286 XFreeDeviceList(devices);
288 gdk_x11_register_standard_event_type (display,
290 15 /* Number of events */);
292 if (G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->constructed)
293 G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->constructed (object);
297 gdk_device_manager_xi_finalize (GObject *object)
299 GdkDeviceManagerXIPrivate *priv;
301 priv = GDK_DEVICE_MANAGER_XI (object)->priv;
303 g_list_foreach (priv->devices, (GFunc) g_object_unref, NULL);
304 g_list_free (priv->devices);
306 g_hash_table_destroy (priv->id_table);
308 gdk_window_remove_filter (NULL, window_input_info_filter, object);
310 G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->finalize (object);
314 gdk_device_manager_xi_set_property (GObject *object,
319 GdkDeviceManagerXIPrivate *priv;
321 priv = GDK_DEVICE_MANAGER_XI (object)->priv;
325 case PROP_EVENT_BASE:
326 priv->event_base = g_value_get_int (value);
329 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
335 gdk_device_manager_xi_get_property (GObject *object,
340 GdkDeviceManagerXIPrivate *priv;
342 priv = GDK_DEVICE_MANAGER_XI (object)->priv;
346 case PROP_EVENT_BASE:
347 g_value_set_int (value, priv->event_base);
350 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
356 gdk_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface)
358 iface->translate_event = gdk_device_manager_xi_translate_event;
361 /* combine the state of the core device and the device state
362 * into one - for now we do this in a simple-minded manner -
363 * we just take the keyboard portion of the core device and
364 * the button portion (all of?) the device state.
365 * Any button remapping should go on here.
368 translate_state (guint state, guint device_state)
370 return device_state | (state & 0xFF);
374 lookup_device (GdkDeviceManagerXI *device_manager,
377 GdkDeviceManagerXIPrivate *priv;
380 priv = GDK_DEVICE_MANAGER_XI (device_manager)->priv;
382 /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
383 but it's potentially faster than scanning through the types of
384 every device. If we were deceived, then it won't match any of
385 the types for the device anyways */
386 device_id = ((XDeviceButtonEvent *)xevent)->deviceid;
388 return g_hash_table_lookup (priv->id_table, GINT_TO_POINTER (device_id));
392 gdk_device_manager_xi_translate_event (GdkEventTranslator *translator,
397 GdkDeviceManagerXIPrivate *priv;
398 GdkDeviceManagerXI *device_manager;
399 GdkEventTranslatorIface *parent_iface;
400 GdkDeviceXI *device_xi;
404 parent_iface = g_type_interface_peek_parent (GDK_EVENT_TRANSLATOR_GET_IFACE (translator));
405 device_manager = GDK_DEVICE_MANAGER_XI (translator);
406 priv = device_manager->priv;
408 if (!priv->ignore_core_events &&
409 parent_iface->translate_event (translator, display, event, xevent))
412 device = lookup_device (device_manager, xevent);
413 device_xi = GDK_DEVICE_XI (device);
418 window = gdk_window_lookup_for_display (display, xevent->xany.window);
423 if ((xevent->type == device_xi->button_press_type) ||
424 (xevent->type == device_xi->button_release_type))
426 XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *) xevent;
428 event->button.type = (xdbe->type == device_xi->button_press_type) ?
429 GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
431 event->button.device = device;
432 event->button.window = g_object_ref (window);
433 event->button.time = xdbe->time;
435 event->button.x_root = (gdouble) xdbe->x_root;
436 event->button.y_root = (gdouble) xdbe->y_root;
438 event->button.axes = g_new0 (gdouble, device->num_axes);
439 gdk_device_xi_update_axes (device, xdbe->axes_count,
440 xdbe->first_axis, xdbe->axis_data);
441 gdk_device_xi_translate_axes (device, window,
442 device_xi->axis_data,
447 event->button.state = translate_state (xdbe->state, xdbe->device_state);
448 event->button.button = xdbe->button;
450 if (event->button.type == GDK_BUTTON_PRESS)
451 _gdk_event_button_generate (gdk_drawable_get_display (event->button.window),
455 g_print ("button %s:\t\twindow: %ld device: %ld x,y: %f %f button: %d\n",
456 (event->button.type == GDK_BUTTON_PRESS) ? "press" : "release",
459 event->button.x, event->button.y,
462 /* Update the timestamp of the latest user interaction, if the event has
465 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
466 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
467 gdk_event_get_time (event));
471 if ((xevent->type == device_xi->key_press_type) ||
472 (xevent->type == device_xi->key_release_type))
474 XDeviceKeyEvent *xdke = (XDeviceKeyEvent *) xevent;
477 g_print ("device key %s:\twindow: %ld device: %ld keycode: %d\n",
478 (event->key.type == GDK_KEY_PRESS) ? "press" : "release",
483 if (xdke->keycode < device_xi->min_keycode ||
484 xdke->keycode >= device_xi->min_keycode + device->num_keys)
486 g_warning ("Invalid device key code received");
490 event->key.keyval = device->keys[xdke->keycode - device_xi->min_keycode].keyval;
492 if (event->key.keyval == 0)
495 g_print ("\t\ttranslation - NONE\n"));
500 event->key.type = (xdke->type == device_xi->key_press_type) ?
501 GDK_KEY_PRESS : GDK_KEY_RELEASE;
503 event->key.window = g_object_ref (window);
504 event->key.time = xdke->time;
506 event->key.state = translate_state (xdke->state, xdke->device_state)
507 | device->keys[xdke->keycode - device_xi->min_keycode].modifiers;
509 /* Add a string translation for the key event */
510 if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xFF))
512 event->key.length = 1;
513 event->key.string = g_new (gchar, 2);
514 event->key.string[0] = (gchar) event->key.keyval;
515 event->key.string[1] = 0;
519 event->key.length = 0;
520 event->key.string = g_new0 (gchar, 1);
524 g_print ("\t\ttranslation - keyval: %d modifiers: %#x\n",
528 /* Update the timestamp of the latest user interaction, if the event has
531 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
532 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
533 gdk_event_get_time (event));
537 if (xevent->type == device_xi->motion_notify_type)
539 XDeviceMotionEvent *xdme = (XDeviceMotionEvent *) xevent;
541 event->motion.device = device;
543 if (device_xi->in_proximity)
544 priv->ignore_core_events = TRUE;
546 event->motion.x_root = (gdouble) xdme->x_root;
547 event->motion.y_root = (gdouble) xdme->y_root;
549 event->motion.axes = g_new0 (gdouble, device->num_axes);
550 gdk_device_xi_update_axes (device, xdme->axes_count,
551 xdme->first_axis, xdme->axis_data);
552 gdk_device_xi_translate_axes (device, window,
553 device_xi->axis_data,
558 event->motion.type = GDK_MOTION_NOTIFY;
559 event->motion.window = g_object_ref (window);
560 event->motion.time = xdme->time;
561 event->motion.state = translate_state (xdme->state,
563 event->motion.is_hint = xdme->is_hint;
566 g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f state %#4x hint: %s\n",
569 event->motion.x, event->motion.y,
571 (xdme->is_hint) ? "true" : "false"));
574 /* Update the timestamp of the latest user interaction, if the event has
577 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
578 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
579 gdk_event_get_time (event));
583 if (xevent->type == device_xi->proximity_in_type ||
584 xevent->type == device_xi->proximity_out_type)
586 XProximityNotifyEvent *xpne = (XProximityNotifyEvent *) xevent;
588 if (xevent->type == device_xi->proximity_in_type)
590 event->proximity.type = GDK_PROXIMITY_IN;
591 device_xi->in_proximity = TRUE;
592 priv->ignore_core_events = TRUE;
596 event->proximity.type = GDK_PROXIMITY_OUT;
597 device_xi->in_proximity = FALSE;
598 priv->ignore_core_events = FALSE;
601 event->proximity.device = device;
602 event->proximity.window = g_object_ref (window);
603 event->proximity.time = xpne->time;
605 /* Update the timestamp of the latest user interaction, if the event has
608 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
609 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
610 gdk_event_get_time (event));
614 if (xevent->type == device_xi->state_notify_type)
616 XDeviceStateNotifyEvent *xdse = (XDeviceStateNotifyEvent *) xevent;
617 XInputClass *input_class = (XInputClass *) xdse->data;
620 for (i = 0; i < xdse->num_classes; i++)
622 if (input_class->class == ValuatorClass)
623 gdk_device_xi_update_axes (device, device->num_axes, 0,
624 ((XValuatorState *)input_class)->valuators);
626 input_class = (XInputClass *)(((char *)input_class)+input_class->length);
630 g_print ("device state notify:\t\twindow: %ld device: %ld\n",
641 gdk_device_manager_xi_list_devices (GdkDeviceManager *device_manager,
644 GdkDeviceManagerXIPrivate *priv;
646 priv = GDK_DEVICE_MANAGER_XI (device_manager)->priv;
648 if (type == GDK_DEVICE_TYPE_MASTER)
649 return GDK_DEVICE_MANAGER_CLASS (gdk_device_manager_xi_parent_class)->list_devices (device_manager, type);
650 else if (type == GDK_DEVICE_TYPE_FLOATING)
652 return g_list_copy (priv->devices);