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, see <http://www.gnu.org/licenses/>.
20 #include "gdkx11devicemanager-xi.h"
21 #include "gdkdevicemanagerprivate-core.h"
22 #include "gdkdeviceprivate-xi.h"
24 #include "gdkdevicemanagerprivate.h"
25 #include "gdkeventtranslator.h"
27 #include "gdkprivate-x11.h"
31 #include <X11/extensions/XInput.h>
33 #endif /* XINPUT_XFREE */
35 struct _GdkX11DeviceManagerXI
37 GdkX11DeviceManagerCore parent_object;
42 gboolean ignore_core_events;
45 struct _GdkX11DeviceManagerXIClass
47 GdkX11DeviceManagerCoreClass parent_class;
50 static void gdk_x11_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface);
52 G_DEFINE_TYPE_WITH_CODE (GdkX11DeviceManagerXI, gdk_x11_device_manager_xi, GDK_TYPE_X11_DEVICE_MANAGER_CORE,
53 G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
54 gdk_x11_device_manager_xi_event_translator_init))
58 static void gdk_x11_device_manager_xi_constructed (GObject *object);
59 static void gdk_x11_device_manager_xi_dispose (GObject *object);
60 static void gdk_x11_device_manager_xi_set_property (GObject *object,
64 static void gdk_x11_device_manager_xi_get_property (GObject *object,
69 static gboolean gdk_x11_device_manager_xi_translate_event (GdkEventTranslator *translator,
73 static GList * gdk_x11_device_manager_xi_list_devices (GdkDeviceManager *device_manager,
83 gdk_x11_device_manager_xi_class_init (GdkX11DeviceManagerXIClass *klass)
85 GObjectClass *object_class = G_OBJECT_CLASS (klass);
86 GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
88 object_class->constructed = gdk_x11_device_manager_xi_constructed;
89 object_class->dispose = gdk_x11_device_manager_xi_dispose;
90 object_class->set_property = gdk_x11_device_manager_xi_set_property;
91 object_class->get_property = gdk_x11_device_manager_xi_get_property;
93 device_manager_class->list_devices = gdk_x11_device_manager_xi_list_devices;
95 g_object_class_install_property (object_class,
97 g_param_spec_int ("event-base",
99 P_("Event base for XInput events"),
101 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
104 static GdkFilterReturn
105 window_input_info_filter (GdkXEvent *xevent,
109 GdkDeviceManager *device_manager;
114 device_manager = user_data;
115 xev = (XEvent *) xevent;
117 display = gdk_device_manager_get_display (device_manager);
118 window = gdk_x11_window_lookup_for_display (display, xev->xany.window);
120 if (window && xev->type == ConfigureNotify)
121 _gdk_x11_device_xi_update_window_info (window);
123 return GDK_FILTER_CONTINUE;
127 gdk_x11_device_manager_xi_init (GdkX11DeviceManagerXI *device_manager)
129 device_manager->id_table = g_hash_table_new_full (NULL, NULL, NULL,
130 (GDestroyNotify) g_object_unref);
132 gdk_window_add_filter (NULL, window_input_info_filter, device_manager);
136 translate_class_info (GdkDevice *device,
139 GdkX11DeviceXI *device_xi;
143 device_xi = GDK_X11_DEVICE_XI (device);
144 class = info->inputclassinfo;
146 for (i = 0; i < info->num_classes; i++)
148 switch (class->class)
154 XKeyInfo *xki = (XKeyInfo *)class;
157 num_keys = xki->max_keycode - xki->min_keycode + 1;
158 _gdk_device_set_keys (device, num_keys);
160 device_xi->min_keycode = xki->min_keycode;
166 XValuatorInfo *xvi = (XValuatorInfo *)class;
168 for (j = 0; j < xvi->num_axes; j++)
181 use = GDK_AXIS_PRESSURE;
184 use = GDK_AXIS_XTILT;
187 use = GDK_AXIS_YTILT;
190 use = GDK_AXIS_WHEEL;
193 use = GDK_AXIS_IGNORE;
196 _gdk_device_add_axis (device,
199 xvi->axes[j].min_value,
200 xvi->axes[j].max_value,
201 xvi->axes[j].resolution);
208 class = (XAnyClassPtr) (((char *) class) + class->length);
212 /* old versions of XI.h don't define these */
213 #ifndef IsXExtensionKeyboard
214 #define IsXExtensionKeyboard 3
215 #define IsXExtensionPointer 4
219 create_device (GdkDeviceManager *device_manager,
223 GdkInputSource input_source;
226 if (info->use != IsXExtensionPointer &&
227 info->use != IsXExtensionKeyboard)
230 if (info->use == IsXExtensionKeyboard)
231 input_source = GDK_SOURCE_KEYBOARD;
236 tmp_name = g_ascii_strdown (info->name, -1);
238 if (strstr (tmp_name, "eraser"))
239 input_source = GDK_SOURCE_ERASER;
240 else if (strstr (tmp_name, "cursor"))
241 input_source = GDK_SOURCE_CURSOR;
242 else if (strstr (tmp_name, "wacom") ||
243 strstr (tmp_name, "pen"))
244 input_source = GDK_SOURCE_PEN;
246 input_source = GDK_SOURCE_MOUSE;
251 device = g_object_new (GDK_TYPE_X11_DEVICE_XI,
253 "type", GDK_DEVICE_TYPE_FLOATING,
254 "input-source", input_source,
255 "input-mode", GDK_MODE_DISABLED,
258 "device-manager", device_manager,
259 "device-id", info->id,
261 translate_class_info (device, info);
267 gdk_x11_device_manager_xi_constructed (GObject *object)
269 GdkX11DeviceManagerXI *device_manager;
270 XDeviceInfo *devices;
274 device_manager = GDK_X11_DEVICE_MANAGER_XI (object);
275 display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
276 devices = XListInputDevices (GDK_DISPLAY_XDISPLAY (display), &num_devices);
278 for(i = 0; i < num_devices; i++)
282 device = create_device (GDK_DEVICE_MANAGER (object),
283 display, &devices[i]);
286 device_manager->devices = g_list_prepend (device_manager->devices, device);
287 g_hash_table_insert (device_manager->id_table,
288 GINT_TO_POINTER (devices[i].id),
289 g_object_ref (device));
293 XFreeDeviceList (devices);
295 gdk_x11_register_standard_event_type (display,
296 device_manager->event_base,
297 15 /* Number of events */);
299 if (G_OBJECT_CLASS (gdk_x11_device_manager_xi_parent_class)->constructed)
300 G_OBJECT_CLASS (gdk_x11_device_manager_xi_parent_class)->constructed (object);
304 gdk_x11_device_manager_xi_dispose (GObject *object)
306 GdkX11DeviceManagerXI *device_manager;
308 device_manager = GDK_X11_DEVICE_MANAGER_XI (object);
310 g_list_free_full (device_manager->devices, g_object_unref);
311 device_manager->devices = NULL;
313 if (device_manager->id_table != NULL)
315 g_hash_table_destroy (device_manager->id_table);
316 device_manager->id_table = NULL;
319 gdk_window_remove_filter (NULL, window_input_info_filter, object);
321 G_OBJECT_CLASS (gdk_x11_device_manager_xi_parent_class)->dispose (object);
325 gdk_x11_device_manager_xi_set_property (GObject *object,
330 GdkX11DeviceManagerXI *device_manager;
332 device_manager = GDK_X11_DEVICE_MANAGER_XI (object);
336 case PROP_EVENT_BASE:
337 device_manager->event_base = g_value_get_int (value);
340 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
346 gdk_x11_device_manager_xi_get_property (GObject *object,
351 GdkX11DeviceManagerXI *device_manager;
353 device_manager = GDK_X11_DEVICE_MANAGER_XI (object);
357 case PROP_EVENT_BASE:
358 g_value_set_int (value, device_manager->event_base);
361 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
367 gdk_x11_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface)
369 iface->translate_event = gdk_x11_device_manager_xi_translate_event;
372 /* combine the state of the core device and the device state
373 * into one - for now we do this in a simple-minded manner -
374 * we just take the keyboard portion of the core device and
375 * the button portion (all of?) the device state.
376 * Any button remapping should go on here.
379 translate_state (guint state, guint device_state)
381 return device_state | (state & 0xFF);
385 lookup_device (GdkX11DeviceManagerXI *manager,
388 GdkX11DeviceManagerXI *device_manager;
391 device_manager = GDK_X11_DEVICE_MANAGER_XI (manager);
393 /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
394 but it's potentially faster than scanning through the types of
395 every device. If we were deceived, then it won't match any of
396 the types for the device anyways */
397 device_id = ((XDeviceButtonEvent *)xevent)->deviceid;
399 return g_hash_table_lookup (device_manager->id_table, GINT_TO_POINTER (device_id));
403 gdk_x11_device_manager_xi_translate_event (GdkEventTranslator *translator,
408 GdkX11DeviceManagerXI *device_manager;
409 GdkEventTranslatorIface *parent_iface;
410 GdkX11DeviceXI *device_xi;
414 parent_iface = g_type_interface_peek_parent (GDK_EVENT_TRANSLATOR_GET_IFACE (translator));
415 device_manager = GDK_X11_DEVICE_MANAGER_XI (translator);
417 if (!device_manager->ignore_core_events &&
418 parent_iface->translate_event (translator, display, event, xevent))
421 device = lookup_device (device_manager, xevent);
422 device_xi = GDK_X11_DEVICE_XI (device);
427 window = gdk_x11_window_lookup_for_display (display, xevent->xany.window);
432 if ((xevent->type == device_xi->button_press_type) ||
433 (xevent->type == device_xi->button_release_type))
435 XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *) xevent;
437 event->button.type = (xdbe->type == device_xi->button_press_type) ?
438 GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
440 event->button.device = device;
441 event->button.window = g_object_ref (window);
442 event->button.time = xdbe->time;
444 event->button.x_root = (gdouble) xdbe->x_root;
445 event->button.y_root = (gdouble) xdbe->y_root;
447 event->button.axes = g_new0 (gdouble, gdk_device_get_n_axes (device));
448 _gdk_x11_device_xi_update_axes (device, xdbe->axes_count,
449 xdbe->first_axis, xdbe->axis_data);
450 _gdk_x11_device_xi_translate_axes (device, window,
451 device_xi->axis_data,
456 event->button.state = translate_state (xdbe->state, xdbe->device_state);
457 event->button.button = xdbe->button;
459 if (event->button.type == GDK_BUTTON_PRESS)
460 _gdk_event_button_generate (gdk_window_get_display (event->button.window),
464 g_print ("button %s:\t\twindow: %ld device: %ld x,y: %f %f button: %d\n",
465 (event->button.type == GDK_BUTTON_PRESS) ? "press" : "release",
468 event->button.x, event->button.y,
471 /* Update the timestamp of the latest user interaction, if the event has
474 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
475 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
476 gdk_event_get_time (event));
480 if ((xevent->type == device_xi->key_press_type) ||
481 (xevent->type == device_xi->key_release_type))
483 XDeviceKeyEvent *xdke = (XDeviceKeyEvent *) xevent;
486 g_print ("device key %s:\twindow: %ld device: %ld keycode: %d\n",
487 (event->key.type == GDK_KEY_PRESS) ? "press" : "release",
492 if (xdke->keycode < device_xi->min_keycode ||
493 xdke->keycode >= device_xi->min_keycode + gdk_device_get_n_keys (device))
495 g_warning ("Invalid device key code received");
499 gdk_device_get_key (device, xdke->keycode - device_xi->min_keycode,
503 if (event->key.keyval == 0)
506 g_print ("\t\ttranslation - NONE\n"));
511 event->key.type = (xdke->type == device_xi->key_press_type) ?
512 GDK_KEY_PRESS : GDK_KEY_RELEASE;
514 event->key.window = g_object_ref (window);
515 event->key.time = xdke->time;
517 event->key.state |= translate_state (xdke->state, xdke->device_state);
519 /* Add a string translation for the key event */
520 if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xFF))
522 event->key.length = 1;
523 event->key.string = g_new (gchar, 2);
524 event->key.string[0] = (gchar) event->key.keyval;
525 event->key.string[1] = 0;
529 event->key.length = 0;
530 event->key.string = g_new0 (gchar, 1);
534 g_print ("\t\ttranslation - keyval: %d modifiers: %#x\n",
538 /* Update the timestamp of the latest user interaction, if the event has
541 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
542 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
543 gdk_event_get_time (event));
547 if (xevent->type == device_xi->motion_notify_type)
549 XDeviceMotionEvent *xdme = (XDeviceMotionEvent *) xevent;
551 event->motion.device = device;
553 if (device_xi->in_proximity)
554 device_manager->ignore_core_events = TRUE;
556 event->motion.x_root = (gdouble) xdme->x_root;
557 event->motion.y_root = (gdouble) xdme->y_root;
559 event->motion.axes = g_new0 (gdouble, gdk_device_get_n_axes (device));
560 _gdk_x11_device_xi_update_axes (device, xdme->axes_count,
561 xdme->first_axis, xdme->axis_data);
562 _gdk_x11_device_xi_translate_axes (device, window,
563 device_xi->axis_data,
568 event->motion.type = GDK_MOTION_NOTIFY;
569 event->motion.window = g_object_ref (window);
570 event->motion.time = xdme->time;
571 event->motion.state = translate_state (xdme->state,
573 event->motion.is_hint = xdme->is_hint;
576 g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f state %#4x hint: %s\n",
579 event->motion.x, event->motion.y,
581 (xdme->is_hint) ? "true" : "false"));
584 /* Update the timestamp of the latest user interaction, if the event has
587 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
588 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
589 gdk_event_get_time (event));
593 if (xevent->type == device_xi->proximity_in_type ||
594 xevent->type == device_xi->proximity_out_type)
596 XProximityNotifyEvent *xpne = (XProximityNotifyEvent *) xevent;
598 if (xevent->type == device_xi->proximity_in_type)
600 event->proximity.type = GDK_PROXIMITY_IN;
601 device_xi->in_proximity = TRUE;
602 device_manager->ignore_core_events = TRUE;
606 event->proximity.type = GDK_PROXIMITY_OUT;
607 device_xi->in_proximity = FALSE;
608 device_manager->ignore_core_events = FALSE;
611 event->proximity.device = device;
612 event->proximity.window = g_object_ref (window);
613 event->proximity.time = xpne->time;
615 /* Update the timestamp of the latest user interaction, if the event has
618 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
619 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
620 gdk_event_get_time (event));
624 if (xevent->type == device_xi->state_notify_type)
626 XDeviceStateNotifyEvent *xdse = (XDeviceStateNotifyEvent *) xevent;
627 XInputClass *input_class = (XInputClass *) xdse->data;
630 for (i = 0; i < xdse->num_classes; i++)
632 if (input_class->class == ValuatorClass)
633 _gdk_x11_device_xi_update_axes (device, gdk_device_get_n_axes (device), 0,
634 ((XValuatorState *)input_class)->valuators);
636 input_class = (XInputClass *)(((char *)input_class)+input_class->length);
640 g_print ("device state notify:\t\twindow: %ld device: %ld\n",
651 gdk_x11_device_manager_xi_list_devices (GdkDeviceManager *manager,
654 GdkX11DeviceManagerXI *device_manager;
656 device_manager = GDK_X11_DEVICE_MANAGER_XI (manager);
658 if (type == GDK_DEVICE_TYPE_MASTER)
659 return GDK_DEVICE_MANAGER_CLASS (gdk_x11_device_manager_xi_parent_class)->list_devices (manager, type);
660 else if (type == GDK_DEVICE_TYPE_FLOATING)
662 return g_list_copy (device_manager->devices);
668 #else /* XINPUT_XFREE */
671 gdk_x11_device_manager_xi_class_init (GdkX11DeviceManagerXIClass *klass)
676 gdk_x11_device_manager_xi_init (GdkX11DeviceManagerXI *device_manager)
681 gdk_x11_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface)
685 #endif /* XINPUT_XFREE */