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 "gdkdevice-xi2.h"
27 #include <X11/extensions/XInput2.h>
29 struct _GdkDeviceXI2Private
34 static void gdk_device_xi2_get_property (GObject *object,
38 static void gdk_device_xi2_set_property (GObject *object,
43 static void gdk_device_xi2_get_state (GdkDevice *device,
46 GdkModifierType *mask);
47 static void gdk_device_xi2_set_window_cursor (GdkDevice *device,
50 static void gdk_device_xi2_warp (GdkDevice *device,
54 static gboolean gdk_device_xi2_query_state (GdkDevice *device,
56 GdkWindow **root_window,
57 GdkWindow **child_window,
62 GdkModifierType *mask);
64 static GdkGrabStatus gdk_device_xi2_grab (GdkDevice *device,
66 gboolean owner_events,
67 GdkEventMask event_mask,
68 GdkWindow *confine_to,
71 static void gdk_device_xi2_ungrab (GdkDevice *device,
74 static GdkWindow * gdk_device_xi2_window_at_position (GdkDevice *device,
77 GdkModifierType *mask,
78 gboolean get_toplevel);
79 static void gdk_device_xi2_select_window_events (GdkDevice *device,
81 GdkEventMask event_mask);
84 G_DEFINE_TYPE (GdkDeviceXI2, gdk_device_xi2, GDK_TYPE_DEVICE)
92 gdk_device_xi2_class_init (GdkDeviceXI2Class *klass)
94 GObjectClass *object_class = G_OBJECT_CLASS (klass);
95 GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
97 object_class->get_property = gdk_device_xi2_get_property;
98 object_class->set_property = gdk_device_xi2_set_property;
100 device_class->get_state = gdk_device_xi2_get_state;
101 device_class->set_window_cursor = gdk_device_xi2_set_window_cursor;
102 device_class->warp = gdk_device_xi2_warp;
103 device_class->query_state = gdk_device_xi2_query_state;
104 device_class->grab = gdk_device_xi2_grab;
105 device_class->ungrab = gdk_device_xi2_ungrab;
106 device_class->window_at_position = gdk_device_xi2_window_at_position;
107 device_class->select_window_events = gdk_device_xi2_select_window_events;
109 g_object_class_install_property (object_class,
111 g_param_spec_int ("device-id",
113 P_("Device identifier"),
115 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
117 g_type_class_add_private (object_class, sizeof (GdkDeviceXI2Private));
121 gdk_device_xi2_init (GdkDeviceXI2 *device)
123 GdkDeviceXI2Private *priv;
125 device->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
127 GdkDeviceXI2Private);
131 gdk_device_xi2_get_property (GObject *object,
136 GdkDeviceXI2Private *priv;
138 priv = GDK_DEVICE_XI2 (object)->priv;
143 g_value_set_int (value, priv->device_id);
146 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
152 gdk_device_xi2_set_property (GObject *object,
157 GdkDeviceXI2Private *priv;
159 priv = GDK_DEVICE_XI2 (object)->priv;
164 priv->device_id = g_value_get_int (value);
167 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
173 gdk_device_xi2_get_state (GdkDevice *device,
176 GdkModifierType *mask)
178 GdkDeviceXI2Private *priv;
183 priv = GDK_DEVICE_XI2 (device)->priv;
184 display = gdk_device_get_display (device);
188 info = XIQueryDevice(GDK_DISPLAY_XDISPLAY (display),
189 priv->device_id, &ndevices);
191 for (i = 0, j = 0; i < info->num_classes; i++)
193 XIAnyClassInfo *class_info = info->classes[i];
197 if (class_info->type != XIValuatorClass)
200 value = ((XIValuatorClassInfo *) class_info)->value;
201 use = _gdk_device_get_axis_use (device, j);
207 case GDK_AXIS_IGNORE:
208 if (device->mode == GDK_MODE_WINDOW)
209 _gdk_device_translate_window_coord (device, window, j, value, &axes[j]);
214 /* FIXME: Maybe root coords chaching should happen here */
215 gdk_window_get_origin (window, &root_x, &root_y);
216 _gdk_device_translate_screen_coord (device, window,
223 _gdk_device_translate_axis (device, j, value, &axes[j]);
230 XIFreeDeviceInfo (info);
234 gdk_device_xi2_query_state (device, window,
242 gdk_device_xi2_set_window_cursor (GdkDevice *device,
246 GdkDeviceXI2Private *priv;
247 GdkCursorPrivate *cursor_private;
249 priv = GDK_DEVICE_XI2 (device)->priv;
251 /* Non-master devices don't have a cursor */
252 if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
257 cursor_private = (GdkCursorPrivate*) cursor;
259 XIDefineCursor (GDK_WINDOW_XDISPLAY (window),
261 GDK_WINDOW_XWINDOW (window),
262 cursor_private->xcursor);
265 XIUndefineCursor (GDK_WINDOW_XDISPLAY (window),
267 GDK_WINDOW_XWINDOW (window));
271 gdk_device_xi2_warp (GdkDevice *device,
276 GdkDeviceXI2Private *priv;
279 priv = GDK_DEVICE_XI2 (device)->priv;
280 dest = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
282 XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
289 gdk_device_xi2_query_state (GdkDevice *device,
291 GdkWindow **root_window,
292 GdkWindow **child_window,
297 GdkModifierType *mask)
300 GdkDeviceXI2Private *priv;
301 Window xroot_window, xchild_window;
302 gdouble xroot_x, xroot_y, xwin_x, xwin_y;
303 XIButtonState button_state;
304 XIModifierState mod_state;
305 XIGroupState group_state;
307 if (!window || GDK_WINDOW_DESTROYED (window))
310 priv = GDK_DEVICE_XI2 (device)->priv;
311 display = gdk_window_get_display (window);
313 if (!XIQueryPointer (GDK_WINDOW_XDISPLAY (window),
315 GDK_WINDOW_XID (window),
330 *root_window = gdk_window_lookup_for_display (display, xroot_window);
333 *child_window = gdk_window_lookup_for_display (display, xchild_window);
336 *root_x = (gint) xroot_x;
339 *root_y = (gint) xroot_y;
342 *win_x = (gint) xwin_x;
345 *win_y = (gint) xwin_y;
348 *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
354 gdk_device_xi2_grab (GdkDevice *device,
356 gboolean owner_events,
357 GdkEventMask event_mask,
358 GdkWindow *confine_to,
362 GdkDeviceXI2Private *priv;
369 priv = GDK_DEVICE_XI2 (device)->priv;
370 display = gdk_device_get_display (device);
372 /* FIXME: confine_to is actually unused */
374 xwindow = GDK_WINDOW_XID (window);
380 _gdk_x11_cursor_update_theme (cursor);
381 xcursor = ((GdkCursorPrivate *) cursor)->xcursor;
384 mask.deviceid = priv->device_id;
385 mask.mask = gdk_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
387 status = XIGrabDevice (GDK_DISPLAY_XDISPLAY (display),
392 GrabModeAsync, GrabModeAsync,
398 return _gdk_x11_convert_grab_status (status);
402 gdk_device_xi2_ungrab (GdkDevice *device,
405 GdkDeviceXI2Private *priv;
408 priv = GDK_DEVICE_XI2 (device)->priv;
409 display = gdk_device_get_display (device);
411 XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display),
417 gdk_device_xi2_window_at_position (GdkDevice *device,
420 GdkModifierType *mask,
421 gboolean get_toplevel)
423 GdkDeviceXI2Private *priv;
428 Window xwindow, root, child, last = None;
429 gdouble xroot_x, xroot_y, xwin_x, xwin_y;
430 XIButtonState button_state;
431 XIModifierState mod_state;
432 XIGroupState group_state;
434 priv = GDK_DEVICE_XI2 (device)->priv;
435 display = gdk_device_get_display (device);
436 screen = gdk_display_get_default_screen (display);
438 /* This function really only works if the mouse pointer is held still
439 * during its operation. If it moves from one leaf window to another
440 * than we'll end up with inaccurate values for win_x, win_y
443 gdk_x11_display_grab (display);
445 xdisplay = GDK_SCREEN_XDISPLAY (screen);
446 xwindow = GDK_SCREEN_XROOTWIN (screen);
448 XIQueryPointer (xdisplay,
466 XIQueryPointer (xdisplay,
476 if (get_toplevel && last != root &&
477 (window = gdk_window_lookup_for_display (display, last)) != NULL &&
478 GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
485 gdk_x11_display_ungrab (display);
487 window = gdk_window_lookup_for_display (display, last);
490 *win_x = (window) ? (gint) xwin_x : -1;
493 *win_y = (window) ? (gint) xwin_y : -1;
496 *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
502 gdk_device_xi2_select_window_events (GdkDevice *device,
504 GdkEventMask event_mask)
506 GdkDeviceXI2Private *priv;
509 priv = GDK_DEVICE_XI2 (device)->priv;
511 evmask.deviceid = priv->device_id;
512 evmask.mask = gdk_device_xi2_translate_event_mask (event_mask, &evmask.mask_len);
514 XISelectEvents (GDK_WINDOW_XDISPLAY (window),
515 GDK_WINDOW_XWINDOW (window),
518 g_free (evmask.mask);
522 gdk_device_xi2_translate_event_mask (GdkEventMask event_mask,
527 *len = XIMaskLen (XI_LASTEVENT);
528 mask = g_new0 (guchar, *len);
530 if (event_mask & GDK_POINTER_MOTION_MASK ||
531 event_mask & GDK_POINTER_MOTION_HINT_MASK)
532 XISetMask (mask, XI_Motion);
534 if (event_mask & GDK_BUTTON_MOTION_MASK ||
535 event_mask & GDK_BUTTON1_MOTION_MASK ||
536 event_mask & GDK_BUTTON2_MOTION_MASK ||
537 event_mask & GDK_BUTTON3_MOTION_MASK)
539 XISetMask (mask, XI_ButtonPress);
540 XISetMask (mask, XI_ButtonRelease);
541 XISetMask (mask, XI_Motion);
544 if (event_mask & GDK_SCROLL_MASK)
546 XISetMask (mask, XI_ButtonPress);
547 XISetMask (mask, XI_ButtonRelease);
550 if (event_mask & GDK_BUTTON_PRESS_MASK)
551 XISetMask (mask, XI_ButtonPress);
553 if (event_mask & GDK_BUTTON_RELEASE_MASK)
554 XISetMask (mask, XI_ButtonRelease);
556 if (event_mask & GDK_KEY_PRESS_MASK)
557 XISetMask (mask, XI_KeyPress);
559 if (event_mask & GDK_KEY_RELEASE_MASK)
560 XISetMask (mask, XI_KeyRelease);
562 if (event_mask & GDK_ENTER_NOTIFY_MASK)
563 XISetMask (mask, XI_Enter);
565 if (event_mask & GDK_LEAVE_NOTIFY_MASK)
566 XISetMask (mask, XI_Leave);
568 if (event_mask & GDK_FOCUS_CHANGE_MASK)
570 XISetMask (mask, XI_FocusIn);
571 XISetMask (mask, XI_FocusOut);
578 gdk_device_xi2_translate_state (XIModifierState *mods_state,
579 XIButtonState *buttons_state)
584 state = (guint) mods_state->effective;
590 /* We're only interested in the first 5 buttons */
591 len = MIN (5, buttons_state->mask_len * 8);
593 for (i = 0; i < len; i++)
595 if (!XIMaskIsSet (buttons_state->mask, i))
601 state |= GDK_BUTTON1_MASK;
604 state |= GDK_BUTTON2_MASK;
607 state |= GDK_BUTTON3_MASK;
610 state |= GDK_BUTTON4_MASK;
613 state |= GDK_BUTTON5_MASK;