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 <gdk/gdkwindow.h>
23 #include "gdkdeviceprivate.h"
24 #include "gdkdevice-xi.h"
25 #include "gdkprivate-x11.h"
29 #define MAX_DEVICE_CLASSES 13
31 static GQuark quark_window_input_info = 0;
39 static void gdk_device_xi_constructed (GObject *object);
40 static void gdk_device_xi_dispose (GObject *object);
42 static void gdk_device_xi_set_property (GObject *object,
46 static void gdk_device_xi_get_property (GObject *object,
51 static gboolean gdk_device_xi_get_history (GdkDevice *device,
55 GdkTimeCoord ***events,
58 static void gdk_device_xi_get_state (GdkDevice *device,
61 GdkModifierType *mask);
62 static void gdk_device_xi_set_window_cursor (GdkDevice *device,
65 static void gdk_device_xi_warp (GdkDevice *device,
69 static gboolean gdk_device_xi_query_state (GdkDevice *device,
71 GdkWindow **root_window,
72 GdkWindow **child_window,
77 GdkModifierType *mask);
78 static GdkGrabStatus gdk_device_xi_grab (GdkDevice *device,
80 gboolean owner_events,
81 GdkEventMask event_mask,
82 GdkWindow *confine_to,
85 static void gdk_device_xi_ungrab (GdkDevice *device,
88 static GdkWindow* gdk_device_xi_window_at_position (GdkDevice *device,
91 GdkModifierType *mask,
92 gboolean get_toplevel);
94 static void gdk_device_xi_select_window_events (GdkDevice *device,
99 G_DEFINE_TYPE (GdkDeviceXI, gdk_device_xi, GDK_TYPE_DEVICE)
107 gdk_device_xi_class_init (GdkDeviceXIClass *klass)
109 GObjectClass *object_class = G_OBJECT_CLASS (klass);
110 GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
112 quark_window_input_info = g_quark_from_static_string ("gdk-window-input-info");
114 object_class->constructed = gdk_device_xi_constructed;
115 object_class->set_property = gdk_device_xi_set_property;
116 object_class->get_property = gdk_device_xi_get_property;
117 object_class->dispose = gdk_device_xi_dispose;
119 device_class->get_history = gdk_device_xi_get_history;
120 device_class->get_state = gdk_device_xi_get_state;
121 device_class->set_window_cursor = gdk_device_xi_set_window_cursor;
122 device_class->warp = gdk_device_xi_warp;
123 device_class->query_state = gdk_device_xi_query_state;
124 device_class->grab = gdk_device_xi_grab;
125 device_class->ungrab = gdk_device_xi_ungrab;
126 device_class->window_at_position = gdk_device_xi_window_at_position;
127 device_class->select_window_events = gdk_device_xi_select_window_events;
129 g_object_class_install_property (object_class,
131 g_param_spec_int ("device-id",
135 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
139 gdk_device_xi_init (GdkDeviceXI *device)
144 gdk_device_xi_constructed (GObject *object)
149 device = GDK_DEVICE_XI (object);
150 display = gdk_device_get_display (GDK_DEVICE (object));
152 gdk_error_trap_push ();
153 device->xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (display),
156 if (gdk_error_trap_pop ())
157 g_warning ("Device %s can't be opened", GDK_DEVICE (device)->name);
159 if (G_OBJECT_CLASS (gdk_device_xi_parent_class)->constructed)
160 G_OBJECT_CLASS (gdk_device_xi_parent_class)->constructed (object);
164 gdk_device_xi_set_property (GObject *object,
169 GdkDeviceXI *device = GDK_DEVICE_XI (object);
174 device->device_id = g_value_get_int (value);
177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
183 gdk_device_xi_get_property (GObject *object,
188 GdkDeviceXI *device = GDK_DEVICE_XI (object);
193 g_value_set_int (value, device->device_id);
196 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202 gdk_device_xi_dispose (GObject *object)
204 GdkDeviceXI *device_xi;
207 device_xi = GDK_DEVICE_XI (object);
208 display = gdk_device_get_display (GDK_DEVICE (device_xi));
210 if (device_xi->xdevice)
212 XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device_xi->xdevice);
213 device_xi->xdevice = NULL;
216 if (device_xi->axis_data)
218 g_free (device_xi->axis_data);
219 device_xi->axis_data = NULL;
222 G_OBJECT_CLASS (gdk_device_xi_parent_class)->dispose (object);
226 gdk_device_xi_get_history (GdkDevice *device,
230 GdkTimeCoord ***events,
233 GdkTimeCoord **coords;
234 XDeviceTimeCoord *device_coords;
235 GdkWindow *impl_window;
236 GdkDeviceXI *device_xi;
237 gint n_events_return;
239 gint axis_count_return;
242 device_xi = GDK_DEVICE_XI (device);
243 impl_window = _gdk_window_get_impl_window (window);
245 device_coords = XGetDeviceMotionEvents (GDK_WINDOW_XDISPLAY (impl_window),
255 *n_events = (guint) n_events_return;
256 coords = _gdk_device_allocate_history (device, *n_events);
258 for (i = 0; i < *n_events; i++)
260 coords[i]->time = device_coords[i].time;
261 gdk_device_xi_translate_axes (device, window,
262 device_coords[i].data,
267 XFreeDeviceMotionEvents (device_coords);
275 gdk_device_xi_get_state (GdkDevice *device,
278 GdkModifierType *mask)
280 GdkDeviceXI *device_xi;
282 XInputClass *input_class;
286 gdk_window_get_pointer (window, NULL, NULL, mask);
288 device_xi = GDK_DEVICE_XI (device);
289 state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
291 input_class = state->data;
293 for (i = 0; i < state->num_classes; i++)
295 switch (input_class->class)
299 gdk_device_xi_translate_axes (device, window,
300 ((XValuatorState *) input_class)->valuators,
308 if (((XButtonState *)input_class)->num_buttons > 0)
309 *mask |= ((XButtonState *)input_class)->buttons[0] << 7;
310 /* GDK_BUTTON1_MASK = 1 << 8, and button n is stored
311 * in bit 1<<(n%8) in byte n/8. n = 1,2,... */
316 input_class = (XInputClass *)(((char *)input_class)+input_class->length);
319 XFreeDeviceState (state);
323 gdk_device_xi_set_window_cursor (GdkDevice *device,
330 gdk_device_xi_warp (GdkDevice *device,
338 find_events (GdkDevice *device,
340 XEventClass *classes,
343 GdkDeviceXI *device_xi;
347 device_xi = GDK_DEVICE_XI (device);
350 if (mask & GDK_BUTTON_PRESS_MASK)
352 DeviceButtonPress (device_xi->xdevice, device_xi->button_press_type, class);
354 classes[i++] = class;
356 DeviceButtonPressGrab (device_xi->xdevice, 0, class);
358 classes[i++] = class;
361 if (mask & GDK_BUTTON_RELEASE_MASK)
363 DeviceButtonRelease (device_xi->xdevice, device_xi->button_release_type, class);
365 classes[i++] = class;
368 if (mask & (GDK_POINTER_MOTION_MASK |
369 GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
370 GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_MOTION_MASK))
372 /* Make sure device->motionnotify_type is set */
373 DeviceMotionNotify (device_xi->xdevice, device_xi->motion_notify_type, class);
375 classes[i++] = class;
376 DeviceStateNotify (device_xi->xdevice, device_xi->state_notify_type, class);
378 classes[i++] = class;
381 if (mask & GDK_KEY_PRESS_MASK)
383 DeviceKeyPress (device_xi->xdevice, device_xi->key_press_type, class);
385 classes[i++] = class;
388 if (mask & GDK_KEY_RELEASE_MASK)
390 DeviceKeyRelease (device_xi->xdevice, device_xi->key_release_type, class);
392 classes[i++] = class;
395 if (mask & GDK_PROXIMITY_IN_MASK)
397 ProximityIn (device_xi->xdevice, device_xi->proximity_in_type, class);
399 classes[i++] = class;
402 if (mask & GDK_PROXIMITY_OUT_MASK)
404 ProximityOut (device_xi->xdevice, device_xi->proximity_out_type, class);
406 classes[i++] = class;
413 gdk_device_xi_query_state (GdkDevice *device,
415 GdkWindow **root_window,
416 GdkWindow **child_window,
421 GdkModifierType *mask)
427 gdk_device_xi_grab (GdkDevice *device,
429 gboolean owner_events,
430 GdkEventMask event_mask,
431 GdkWindow *confine_to,
435 XEventClass event_classes[MAX_DEVICE_CLASSES];
436 gint status, num_classes;
437 GdkDeviceXI *device_xi;
439 device_xi = GDK_DEVICE_XI (device);
440 find_events (device, event_mask, event_classes, &num_classes);
442 status = XGrabDevice (GDK_WINDOW_XDISPLAY (window),
444 GDK_WINDOW_XWINDOW (window),
446 num_classes, event_classes,
447 GrabModeAsync, GrabModeAsync,
450 return _gdk_x11_convert_grab_status (status);
454 gdk_device_xi_ungrab (GdkDevice *device,
458 GdkDeviceXI *device_xi;
460 device_xi = GDK_DEVICE_XI (device);
461 display = gdk_device_get_display (device);
463 XUngrabDevice (GDK_DISPLAY_XDISPLAY (device),
469 gdk_device_xi_window_at_position (GdkDevice *device,
472 GdkModifierType *mask,
473 gboolean get_toplevel)
478 gdk_device_xi_select_window_events (GdkDevice *device,
480 GdkEventMask event_mask)
482 XEventClass event_classes[MAX_DEVICE_CLASSES];
483 GdkDeviceXI *device_xi;
486 event_mask |= (GDK_PROXIMITY_IN_MASK |
487 GDK_PROXIMITY_OUT_MASK);
489 device_xi = GDK_DEVICE_XI (device);
490 find_events (device, event_mask, event_classes, &num_classes);
492 XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (window),
493 GDK_WINDOW_XWINDOW (window),
494 event_classes, num_classes);
498 GdkWindowInputInfo *info;
500 info = g_new0 (GdkWindowInputInfo, 1);
501 g_object_set_qdata_full (G_OBJECT (window),
502 quark_window_input_info,
504 (GDestroyNotify) g_free);
507 g_object_set_qdata (G_OBJECT (window),
508 quark_window_input_info,
513 gdk_device_xi_update_window_info (GdkWindow *window)
515 GdkWindowInputInfo *info;
518 info = g_object_get_qdata (G_OBJECT (window),
519 quark_window_input_info);
524 gdk_window_get_origin (window, &root_x, &root_y);
525 info->root_x = (gdouble) root_x;
526 info->root_y = (gdouble) root_y;
530 gdk_device_xi_get_window_info (GdkWindow *window,
534 GdkWindowInputInfo *info;
536 info = g_object_get_qdata (G_OBJECT (window),
537 quark_window_input_info);
542 *root_x = info->root_x;
543 *root_y = info->root_y;
549 gdk_device_xi_update_axes (GdkDevice *device,
554 GdkDeviceXI *device_xi;
557 device_xi = GDK_DEVICE_XI (device);
558 g_return_if_fail (first_axis >= 0 && first_axis + axes_count <= device->num_axes);
560 if (!device_xi->axis_data)
561 device_xi->axis_data = g_new0 (gint, device->num_axes);
563 for (i = 0; i < axes_count; i++)
564 device_xi->axis_data[first_axis + i] = axis_data[i];
568 gdk_device_xi_translate_axes (GdkDevice *device,
575 GdkDeviceXI *device_xi;
576 GdkWindow *impl_window;
577 gdouble root_x, root_y;
578 gdouble temp_x, temp_y;
581 device_xi = GDK_DEVICE_XI (device);
582 impl_window = _gdk_window_get_impl_window (window);
585 if (!gdk_device_xi_get_window_info (impl_window, &root_x, &root_y))
588 for (i = 0; i < device->num_axes; i++)
592 use = _gdk_device_get_axis_use (device, i);
598 if (device->mode == GDK_MODE_WINDOW)
599 _gdk_device_translate_window_coord (device, window,
603 _gdk_device_translate_screen_coord (device, window,
607 if (use == GDK_AXIS_X)
609 else if (use == GDK_AXIS_Y)
614 _gdk_device_translate_axis (device, i, axis_data[i], &axes[i]);