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 <X11/extensions/XInput2.h>
23 #include "gdkdevice-xi2.h"
28 struct _GdkDeviceXI2Private
33 static void gdk_device_xi2_get_property (GObject *object,
37 static void gdk_device_xi2_set_property (GObject *object,
42 static void gdk_device_xi2_get_state (GdkDevice *device,
45 GdkModifierType *mask);
46 static void gdk_device_xi2_set_window_cursor (GdkDevice *device,
49 static void gdk_device_xi2_warp (GdkDevice *device,
53 static gboolean gdk_device_xi2_query_state (GdkDevice *device,
55 GdkWindow **root_window,
56 GdkWindow **child_window,
61 GdkModifierType *mask);
63 static GdkGrabStatus gdk_device_xi2_grab (GdkDevice *device,
65 gboolean owner_events,
66 GdkEventMask event_mask,
67 GdkWindow *confine_to,
70 static void gdk_device_xi2_ungrab (GdkDevice *device,
73 static GdkWindow * gdk_device_xi2_window_at_position (GdkDevice *device,
76 GdkModifierType *mask,
77 gboolean get_toplevel);
78 static void gdk_device_xi2_select_window_events (GdkDevice *device,
80 GdkEventMask event_mask);
83 G_DEFINE_TYPE (GdkDeviceXI2, gdk_device_xi2, GDK_TYPE_DEVICE)
91 gdk_device_xi2_class_init (GdkDeviceXI2Class *klass)
93 GObjectClass *object_class = G_OBJECT_CLASS (klass);
94 GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
96 object_class->get_property = gdk_device_xi2_get_property;
97 object_class->set_property = gdk_device_xi2_set_property;
99 device_class->get_state = gdk_device_xi2_get_state;
100 device_class->set_window_cursor = gdk_device_xi2_set_window_cursor;
101 device_class->warp = gdk_device_xi2_warp;
102 device_class->query_state = gdk_device_xi2_query_state;
103 device_class->grab = gdk_device_xi2_grab;
104 device_class->ungrab = gdk_device_xi2_ungrab;
105 device_class->window_at_position = gdk_device_xi2_window_at_position;
106 device_class->select_window_events = gdk_device_xi2_select_window_events;
108 g_object_class_install_property (object_class,
110 g_param_spec_int ("device-id",
112 P_("Device identifier"),
114 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
116 g_type_class_add_private (object_class, sizeof (GdkDeviceXI2Private));
120 gdk_device_xi2_init (GdkDeviceXI2 *device)
122 GdkDeviceXI2Private *priv;
124 device->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
126 GdkDeviceXI2Private);
130 gdk_device_xi2_get_property (GObject *object,
135 GdkDeviceXI2Private *priv;
137 priv = GDK_DEVICE_XI2 (object)->priv;
142 g_value_set_int (value, priv->device_id);
145 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
151 gdk_device_xi2_set_property (GObject *object,
156 GdkDeviceXI2Private *priv;
158 priv = GDK_DEVICE_XI2 (object)->priv;
163 priv->device_id = g_value_get_int (value);
166 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
172 gdk_device_xi2_get_state (GdkDevice *device,
175 GdkModifierType *mask)
177 GdkDeviceXI2Private *priv;
182 priv = GDK_DEVICE_XI2 (device)->priv;
183 display = gdk_device_get_display (device);
187 info = XIQueryDevice(GDK_DISPLAY_XDISPLAY (display),
188 priv->device_id, &ndevices);
190 for (i = 0, j = 0; i < info->num_classes; i++)
192 XIAnyClassInfo *class_info = info->classes[i];
196 if (class_info->type != XIValuatorClass)
199 value = ((XIValuatorClassInfo *) class_info)->value;
200 use = _gdk_device_get_axis_use (device, j);
206 case GDK_AXIS_IGNORE:
207 if (device->mode == GDK_MODE_WINDOW)
208 _gdk_device_translate_window_coord (device, window, j, value, &axes[j]);
213 /* FIXME: Maybe root coords chaching should happen here */
214 gdk_window_get_origin (window, &root_x, &root_y);
215 _gdk_device_translate_screen_coord (device, window,
222 _gdk_device_translate_axis (device, j, value, &axes[j]);
229 XIFreeDeviceInfo (info);
233 gdk_device_xi2_query_state (device, window,
241 gdk_device_xi2_set_window_cursor (GdkDevice *device,
245 GdkDeviceXI2Private *priv;
246 GdkCursorPrivate *cursor_private;
248 priv = GDK_DEVICE_XI2 (device)->priv;
250 /* Non-master devices don't have a cursor */
251 if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
256 cursor_private = (GdkCursorPrivate*) cursor;
258 XIDefineCursor (GDK_WINDOW_XDISPLAY (window),
260 GDK_WINDOW_XWINDOW (window),
261 cursor_private->xcursor);
264 XIUndefineCursor (GDK_WINDOW_XDISPLAY (window),
266 GDK_WINDOW_XWINDOW (window));
270 gdk_device_xi2_warp (GdkDevice *device,
275 GdkDeviceXI2Private *priv;
278 priv = GDK_DEVICE_XI2 (device)->priv;
279 dest = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
281 XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
288 gdk_device_xi2_query_state (GdkDevice *device,
290 GdkWindow **root_window,
291 GdkWindow **child_window,
296 GdkModifierType *mask)
299 GdkDeviceXI2Private *priv;
300 Window xroot_window, xchild_window;
301 gdouble xroot_x, xroot_y, xwin_x, xwin_y;
302 XIButtonState button_state;
303 XIModifierState mod_state;
304 XIGroupState group_state;
306 if (!window || GDK_WINDOW_DESTROYED (window))
309 priv = GDK_DEVICE_XI2 (device)->priv;
310 display = gdk_window_get_display (window);
312 if (!XIQueryPointer (GDK_WINDOW_XDISPLAY (window),
314 GDK_WINDOW_XID (window),
329 *root_window = gdk_window_lookup_for_display (display, xroot_window);
332 *child_window = gdk_window_lookup_for_display (display, xchild_window);
335 *root_x = (gint) xroot_x;
338 *root_y = (gint) xroot_y;
341 *win_x = (gint) xwin_x;
344 *win_y = (gint) xwin_y;
347 *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
353 gdk_device_xi2_grab (GdkDevice *device,
355 gboolean owner_events,
356 GdkEventMask event_mask,
357 GdkWindow *confine_to,
361 GdkDeviceXI2Private *priv;
368 priv = GDK_DEVICE_XI2 (device)->priv;
369 display = gdk_device_get_display (device);
371 /* FIXME: confine_to is actually unused */
373 xwindow = GDK_WINDOW_XID (window);
379 _gdk_x11_cursor_update_theme (cursor);
380 xcursor = ((GdkCursorPrivate *) cursor)->xcursor;
383 mask.deviceid = priv->device_id;
384 mask.mask = gdk_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
386 status = XIGrabDevice (GDK_DISPLAY_XDISPLAY (display),
391 GrabModeAsync, GrabModeAsync,
397 return _gdk_x11_convert_grab_status (status);
401 gdk_device_xi2_ungrab (GdkDevice *device,
404 GdkDeviceXI2Private *priv;
407 priv = GDK_DEVICE_XI2 (device)->priv;
408 display = gdk_device_get_display (device);
410 XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display),
416 gdk_device_xi2_window_at_position (GdkDevice *device,
419 GdkModifierType *mask,
420 gboolean get_toplevel)
422 GdkDeviceXI2Private *priv;
427 Window xwindow, root, child, last = None;
428 gdouble xroot_x, xroot_y, xwin_x, xwin_y;
429 XIButtonState button_state;
430 XIModifierState mod_state;
431 XIGroupState group_state;
433 priv = GDK_DEVICE_XI2 (device)->priv;
434 display = gdk_device_get_display (device);
435 screen = gdk_display_get_default_screen (display);
437 /* This function really only works if the mouse pointer is held still
438 * during its operation. If it moves from one leaf window to another
439 * than we'll end up with inaccurate values for win_x, win_y
442 gdk_x11_display_grab (display);
444 xdisplay = GDK_SCREEN_XDISPLAY (screen);
445 xwindow = GDK_SCREEN_XROOTWIN (screen);
447 XIQueryPointer (xdisplay,
465 XIQueryPointer (xdisplay,
475 if (get_toplevel && last != root &&
476 (window = gdk_window_lookup_for_display (display, last)) != NULL &&
477 GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
484 gdk_x11_display_ungrab (display);
486 window = gdk_window_lookup_for_display (display, last);
489 *win_x = (window) ? (gint) xwin_x : -1;
492 *win_y = (window) ? (gint) xwin_y : -1;
495 *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
501 gdk_device_xi2_select_window_events (GdkDevice *device,
503 GdkEventMask event_mask)
505 GdkDeviceXI2Private *priv;
508 priv = GDK_DEVICE_XI2 (device)->priv;
510 evmask.deviceid = priv->device_id;
511 evmask.mask = gdk_device_xi2_translate_event_mask (event_mask, &evmask.mask_len);
513 XISelectEvents (GDK_WINDOW_XDISPLAY (window),
514 GDK_WINDOW_XWINDOW (window),
517 g_free (evmask.mask);
521 gdk_device_xi2_translate_event_mask (GdkEventMask event_mask,
526 *len = XIMaskLen (XI_LASTEVENT);
527 mask = g_new0 (guchar, *len);
529 if (event_mask & GDK_POINTER_MOTION_MASK ||
530 event_mask & GDK_POINTER_MOTION_HINT_MASK)
531 XISetMask (mask, XI_Motion);
533 if (event_mask & GDK_BUTTON_MOTION_MASK ||
534 event_mask & GDK_BUTTON1_MOTION_MASK ||
535 event_mask & GDK_BUTTON2_MOTION_MASK ||
536 event_mask & GDK_BUTTON3_MOTION_MASK)
538 XISetMask (mask, XI_ButtonPress);
539 XISetMask (mask, XI_ButtonRelease);
540 XISetMask (mask, XI_Motion);
543 if (event_mask & GDK_SCROLL_MASK)
545 XISetMask (mask, XI_ButtonPress);
546 XISetMask (mask, XI_ButtonRelease);
549 if (event_mask & GDK_BUTTON_PRESS_MASK)
550 XISetMask (mask, XI_ButtonPress);
552 if (event_mask & GDK_BUTTON_RELEASE_MASK)
553 XISetMask (mask, XI_ButtonRelease);
555 if (event_mask & GDK_KEY_PRESS_MASK)
556 XISetMask (mask, XI_KeyPress);
558 if (event_mask & GDK_KEY_RELEASE_MASK)
559 XISetMask (mask, XI_KeyRelease);
561 if (event_mask & GDK_ENTER_NOTIFY_MASK)
562 XISetMask (mask, XI_Enter);
564 if (event_mask & GDK_LEAVE_NOTIFY_MASK)
565 XISetMask (mask, XI_Leave);
567 if (event_mask & GDK_FOCUS_CHANGE_MASK)
569 XISetMask (mask, XI_FocusIn);
570 XISetMask (mask, XI_FocusOut);
577 gdk_device_xi2_translate_state (XIModifierState *mods_state,
578 XIButtonState *buttons_state)
583 state = (guint) mods_state->effective;
589 /* We're only interested in the first 5 buttons */
590 len = MIN (5, buttons_state->mask_len * 8);
592 for (i = 0; i < len; i++)
594 if (!XIMaskIsSet (buttons_state->mask, i))
600 state |= GDK_BUTTON1_MASK;
603 state |= GDK_BUTTON2_MASK;
606 state |= GDK_BUTTON3_MASK;
609 state |= GDK_BUTTON4_MASK;
612 state |= GDK_BUTTON5_MASK;