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"
24 #include "gdkeventtranslator.h"
25 #include "gdkdevice-xi.h"
27 #include "gdkprivate-x11.h"
29 #include <X11/extensions/XInput.h>
32 struct _GdkDeviceManagerXIPrivate
37 gboolean ignore_core_events;
40 static void gdk_device_manager_xi_constructed (GObject *object);
41 static void gdk_device_manager_xi_dispose (GObject *object);
42 static void gdk_device_manager_xi_set_property (GObject *object,
46 static void gdk_device_manager_xi_get_property (GObject *object,
51 static void gdk_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface);
52 static gboolean gdk_device_manager_xi_translate_event (GdkEventTranslator *translator,
56 static GList * gdk_device_manager_xi_list_devices (GdkDeviceManager *device_manager,
60 G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerXI, gdk_device_manager_xi, GDK_TYPE_X11_DEVICE_MANAGER_CORE,
61 G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
62 gdk_device_manager_xi_event_translator_init))
70 gdk_device_manager_xi_class_init (GdkDeviceManagerXIClass *klass)
72 GObjectClass *object_class = G_OBJECT_CLASS (klass);
73 GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
75 object_class->constructed = gdk_device_manager_xi_constructed;
76 object_class->dispose = gdk_device_manager_xi_dispose;
77 object_class->set_property = gdk_device_manager_xi_set_property;
78 object_class->get_property = gdk_device_manager_xi_get_property;
80 device_manager_class->list_devices = gdk_device_manager_xi_list_devices;
82 g_object_class_install_property (object_class,
84 g_param_spec_int ("event-base",
86 P_("Event base for XInput events"),
88 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
90 g_type_class_add_private (object_class, sizeof (GdkDeviceManagerXIPrivate));
93 static GdkFilterReturn
94 window_input_info_filter (GdkXEvent *xevent,
98 GdkDeviceManager *device_manager;
103 device_manager = user_data;
104 xev = (XEvent *) xevent;
106 display = gdk_device_manager_get_display (device_manager);
107 window = gdk_x11_window_lookup_for_display (display, xev->xany.window);
109 if (window && xev->type == ConfigureNotify)
110 gdk_device_xi_update_window_info (window);
112 return GDK_FILTER_CONTINUE;
116 gdk_device_manager_xi_init (GdkDeviceManagerXI *device_manager)
118 GdkDeviceManagerXIPrivate *priv;
120 device_manager->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device_manager,
121 GDK_TYPE_DEVICE_MANAGER_XI,
122 GdkDeviceManagerXIPrivate);
124 priv->id_table = g_hash_table_new_full (NULL, NULL, NULL,
125 (GDestroyNotify) g_object_unref);
127 gdk_window_add_filter (NULL, window_input_info_filter, device_manager);
131 translate_class_info (GdkDevice *device,
134 GdkDeviceXI *device_xi;
138 device_xi = GDK_DEVICE_XI (device);
139 class = info->inputclassinfo;
141 for (i = 0; i < info->num_classes; i++)
143 switch (class->class) {
148 XKeyInfo *xki = (XKeyInfo *)class;
151 num_keys = xki->max_keycode - xki->min_keycode + 1;
152 _gdk_device_set_keys (device, num_keys);
154 device_xi->min_keycode = xki->min_keycode;
160 XValuatorInfo *xvi = (XValuatorInfo *)class;
162 for (j = 0; j < xvi->num_axes; j++)
175 use = GDK_AXIS_PRESSURE;
178 use = GDK_AXIS_XTILT;
181 use = GDK_AXIS_YTILT;
184 use = GDK_AXIS_WHEEL;
187 use = GDK_AXIS_IGNORE;
190 _gdk_device_add_axis (device,
193 xvi->axes[j].min_value,
194 xvi->axes[j].max_value,
195 xvi->axes[j].resolution);
202 class = (XAnyClassPtr) (((char *) class) + class->length);
206 /* old versions of XI.h don't define these */
207 #ifndef IsXExtensionKeyboard
208 #define IsXExtensionKeyboard 3
209 #define IsXExtensionPointer 4
213 create_device (GdkDeviceManager *device_manager,
217 GdkInputSource input_source;
220 if (info->use != IsXExtensionPointer &&
221 info->use != IsXExtensionKeyboard)
224 if (info->use == IsXExtensionKeyboard)
225 input_source = GDK_SOURCE_KEYBOARD;
230 tmp_name = g_ascii_strdown (info->name, -1);
232 if (strstr (tmp_name, "eraser"))
233 input_source = GDK_SOURCE_ERASER;
234 else if (strstr (tmp_name, "cursor"))
235 input_source = GDK_SOURCE_CURSOR;
236 else if (strstr (tmp_name, "wacom") ||
237 strstr (tmp_name, "pen"))
238 input_source = GDK_SOURCE_PEN;
240 input_source = GDK_SOURCE_MOUSE;
245 device = g_object_new (GDK_TYPE_DEVICE_XI,
247 "type", GDK_DEVICE_TYPE_FLOATING,
248 "input-source", input_source,
249 "input-mode", GDK_MODE_DISABLED,
252 "device-manager", device_manager,
253 "device-id", info->id,
255 translate_class_info (device, info);
261 gdk_device_manager_xi_constructed (GObject *object)
263 GdkDeviceManagerXIPrivate *priv;
264 XDeviceInfo *devices;
268 priv = GDK_DEVICE_MANAGER_XI (object)->priv;
269 display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
270 devices = XListInputDevices(GDK_DISPLAY_XDISPLAY (display), &num_devices);
272 for(i = 0; i < num_devices; i++)
276 device = create_device (GDK_DEVICE_MANAGER (object),
277 display, &devices[i]);
280 priv->devices = g_list_prepend (priv->devices, device);
281 g_hash_table_insert (priv->id_table,
282 GINT_TO_POINTER (devices[i].id),
283 g_object_ref (device));
287 XFreeDeviceList(devices);
289 gdk_x11_register_standard_event_type (display,
291 15 /* Number of events */);
293 if (G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->constructed)
294 G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->constructed (object);
298 gdk_device_manager_xi_dispose (GObject *object)
300 GdkDeviceManagerXIPrivate *priv;
302 priv = GDK_DEVICE_MANAGER_XI (object)->priv;
304 g_list_foreach (priv->devices, (GFunc) g_object_unref, NULL);
305 g_list_free (priv->devices);
306 priv->devices = NULL;
308 if (priv->id_table != NULL)
310 g_hash_table_destroy (priv->id_table);
311 priv->id_table = NULL;
314 gdk_window_remove_filter (NULL, window_input_info_filter, object);
316 G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->dispose (object);
320 gdk_device_manager_xi_set_property (GObject *object,
325 GdkDeviceManagerXIPrivate *priv;
327 priv = GDK_DEVICE_MANAGER_XI (object)->priv;
331 case PROP_EVENT_BASE:
332 priv->event_base = g_value_get_int (value);
335 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
341 gdk_device_manager_xi_get_property (GObject *object,
346 GdkDeviceManagerXIPrivate *priv;
348 priv = GDK_DEVICE_MANAGER_XI (object)->priv;
352 case PROP_EVENT_BASE:
353 g_value_set_int (value, priv->event_base);
356 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
362 gdk_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface)
364 iface->translate_event = gdk_device_manager_xi_translate_event;
367 /* combine the state of the core device and the device state
368 * into one - for now we do this in a simple-minded manner -
369 * we just take the keyboard portion of the core device and
370 * the button portion (all of?) the device state.
371 * Any button remapping should go on here.
374 translate_state (guint state, guint device_state)
376 return device_state | (state & 0xFF);
380 lookup_device (GdkDeviceManagerXI *device_manager,
383 GdkDeviceManagerXIPrivate *priv;
386 priv = GDK_DEVICE_MANAGER_XI (device_manager)->priv;
388 /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
389 but it's potentially faster than scanning through the types of
390 every device. If we were deceived, then it won't match any of
391 the types for the device anyways */
392 device_id = ((XDeviceButtonEvent *)xevent)->deviceid;
394 return g_hash_table_lookup (priv->id_table, GINT_TO_POINTER (device_id));
398 gdk_device_manager_xi_translate_event (GdkEventTranslator *translator,
403 GdkDeviceManagerXIPrivate *priv;
404 GdkDeviceManagerXI *device_manager;
405 GdkEventTranslatorIface *parent_iface;
406 GdkDeviceXI *device_xi;
410 parent_iface = g_type_interface_peek_parent (GDK_EVENT_TRANSLATOR_GET_IFACE (translator));
411 device_manager = GDK_DEVICE_MANAGER_XI (translator);
412 priv = device_manager->priv;
414 if (!priv->ignore_core_events &&
415 parent_iface->translate_event (translator, display, event, xevent))
418 device = lookup_device (device_manager, xevent);
419 device_xi = GDK_DEVICE_XI (device);
424 window = gdk_x11_window_lookup_for_display (display, xevent->xany.window);
429 if ((xevent->type == device_xi->button_press_type) ||
430 (xevent->type == device_xi->button_release_type))
432 XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *) xevent;
434 event->button.type = (xdbe->type == device_xi->button_press_type) ?
435 GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
437 event->button.device = device;
438 event->button.window = g_object_ref (window);
439 event->button.time = xdbe->time;
441 event->button.x_root = (gdouble) xdbe->x_root;
442 event->button.y_root = (gdouble) xdbe->y_root;
444 event->button.axes = g_new0 (gdouble, gdk_device_get_n_axes (device));
445 gdk_device_xi_update_axes (device, xdbe->axes_count,
446 xdbe->first_axis, xdbe->axis_data);
447 gdk_device_xi_translate_axes (device, window,
448 device_xi->axis_data,
453 event->button.state = translate_state (xdbe->state, xdbe->device_state);
454 event->button.button = xdbe->button;
456 if (event->button.type == GDK_BUTTON_PRESS)
457 _gdk_event_button_generate (gdk_window_get_display (event->button.window),
461 g_print ("button %s:\t\twindow: %ld device: %ld x,y: %f %f button: %d\n",
462 (event->button.type == GDK_BUTTON_PRESS) ? "press" : "release",
465 event->button.x, event->button.y,
468 /* Update the timestamp of the latest user interaction, if the event has
471 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
472 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
473 gdk_event_get_time (event));
477 if ((xevent->type == device_xi->key_press_type) ||
478 (xevent->type == device_xi->key_release_type))
480 XDeviceKeyEvent *xdke = (XDeviceKeyEvent *) xevent;
483 g_print ("device key %s:\twindow: %ld device: %ld keycode: %d\n",
484 (event->key.type == GDK_KEY_PRESS) ? "press" : "release",
489 if (xdke->keycode < device_xi->min_keycode ||
490 xdke->keycode >= device_xi->min_keycode + gdk_device_get_n_keys (device))
492 g_warning ("Invalid device key code received");
496 gdk_device_get_key (device, xdke->keycode - device_xi->min_keycode,
500 if (event->key.keyval == 0)
503 g_print ("\t\ttranslation - NONE\n"));
508 event->key.type = (xdke->type == device_xi->key_press_type) ?
509 GDK_KEY_PRESS : GDK_KEY_RELEASE;
511 event->key.window = g_object_ref (window);
512 event->key.time = xdke->time;
514 event->key.state |= translate_state (xdke->state, xdke->device_state);
516 /* Add a string translation for the key event */
517 if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xFF))
519 event->key.length = 1;
520 event->key.string = g_new (gchar, 2);
521 event->key.string[0] = (gchar) event->key.keyval;
522 event->key.string[1] = 0;
526 event->key.length = 0;
527 event->key.string = g_new0 (gchar, 1);
531 g_print ("\t\ttranslation - keyval: %d modifiers: %#x\n",
535 /* Update the timestamp of the latest user interaction, if the event has
538 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
539 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
540 gdk_event_get_time (event));
544 if (xevent->type == device_xi->motion_notify_type)
546 XDeviceMotionEvent *xdme = (XDeviceMotionEvent *) xevent;
548 event->motion.device = device;
550 if (device_xi->in_proximity)
551 priv->ignore_core_events = TRUE;
553 event->motion.x_root = (gdouble) xdme->x_root;
554 event->motion.y_root = (gdouble) xdme->y_root;
556 event->motion.axes = g_new0 (gdouble, gdk_device_get_n_axes (device));
557 gdk_device_xi_update_axes (device, xdme->axes_count,
558 xdme->first_axis, xdme->axis_data);
559 gdk_device_xi_translate_axes (device, window,
560 device_xi->axis_data,
565 event->motion.type = GDK_MOTION_NOTIFY;
566 event->motion.window = g_object_ref (window);
567 event->motion.time = xdme->time;
568 event->motion.state = translate_state (xdme->state,
570 event->motion.is_hint = xdme->is_hint;
573 g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f state %#4x hint: %s\n",
576 event->motion.x, event->motion.y,
578 (xdme->is_hint) ? "true" : "false"));
581 /* Update the timestamp of the latest user interaction, if the event has
584 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
585 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
586 gdk_event_get_time (event));
590 if (xevent->type == device_xi->proximity_in_type ||
591 xevent->type == device_xi->proximity_out_type)
593 XProximityNotifyEvent *xpne = (XProximityNotifyEvent *) xevent;
595 if (xevent->type == device_xi->proximity_in_type)
597 event->proximity.type = GDK_PROXIMITY_IN;
598 device_xi->in_proximity = TRUE;
599 priv->ignore_core_events = TRUE;
603 event->proximity.type = GDK_PROXIMITY_OUT;
604 device_xi->in_proximity = FALSE;
605 priv->ignore_core_events = FALSE;
608 event->proximity.device = device;
609 event->proximity.window = g_object_ref (window);
610 event->proximity.time = xpne->time;
612 /* Update the timestamp of the latest user interaction, if the event has
615 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
616 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
617 gdk_event_get_time (event));
621 if (xevent->type == device_xi->state_notify_type)
623 XDeviceStateNotifyEvent *xdse = (XDeviceStateNotifyEvent *) xevent;
624 XInputClass *input_class = (XInputClass *) xdse->data;
627 for (i = 0; i < xdse->num_classes; i++)
629 if (input_class->class == ValuatorClass)
630 gdk_device_xi_update_axes (device, gdk_device_get_n_axes (device), 0,
631 ((XValuatorState *)input_class)->valuators);
633 input_class = (XInputClass *)(((char *)input_class)+input_class->length);
637 g_print ("device state notify:\t\twindow: %ld device: %ld\n",
648 gdk_device_manager_xi_list_devices (GdkDeviceManager *device_manager,
651 GdkDeviceManagerXIPrivate *priv;
653 priv = GDK_DEVICE_MANAGER_XI (device_manager)->priv;
655 if (type == GDK_DEVICE_TYPE_MASTER)
656 return GDK_DEVICE_MANAGER_CLASS (gdk_device_manager_xi_parent_class)->list_devices (device_manager, type);
657 else if (type == GDK_DEVICE_TYPE_FLOATING)
659 return g_list_copy (priv->devices);