]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkdevice-xi.c
reftests: Add a rendering test for sibling matching
[~andy/gtk] / gdk / x11 / gdkdevice-xi.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
3  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 #include "config.h"
19
20 #include "gdkx11device-xi.h"
21
22 #include "gdkdeviceprivate-xi.h"
23
24 #ifdef XINPUT_XFREE
25
26 #include "gdkwindow.h"
27 #include "gdkintl.h"
28 #include "gdkprivate-x11.h"
29 #include "gdkasync.h"
30
31 #endif
32
33 G_DEFINE_TYPE (GdkX11DeviceXI, gdk_x11_device_xi, GDK_TYPE_DEVICE)
34
35 #ifdef XINPUT_XFREE
36
37 #define MAX_DEVICE_CLASSES 13
38
39 static GQuark quark_window_input_info = 0;
40
41 typedef struct
42 {
43   gdouble root_x;
44   gdouble root_y;
45 } GdkWindowInputInfo;
46
47 static void gdk_x11_device_xi_constructed  (GObject *object);
48 static void gdk_x11_device_xi_dispose      (GObject *object);
49
50 static void gdk_x11_device_xi_set_property (GObject      *object,
51                                             guint         prop_id,
52                                             const GValue *value,
53                                             GParamSpec   *pspec);
54 static void gdk_x11_device_xi_get_property (GObject      *object,
55                                             guint         prop_id,
56                                             GValue       *value,
57                                             GParamSpec   *pspec);
58
59 static gboolean gdk_x11_device_xi_get_history (GdkDevice      *device,
60                                                GdkWindow      *window,
61                                                guint32         start,
62                                                guint32         stop,
63                                                GdkTimeCoord ***events,
64                                                gint           *n_events);
65
66 static void gdk_x11_device_xi_get_state       (GdkDevice       *device,
67                                                GdkWindow       *window,
68                                                gdouble         *axes,
69                                                GdkModifierType *mask);
70 static void gdk_x11_device_xi_set_window_cursor (GdkDevice *device,
71                                                  GdkWindow *window,
72                                                  GdkCursor *cursor);
73 static void gdk_x11_device_xi_warp              (GdkDevice *device,
74                                                  GdkScreen *screen,
75                                                  gint       x,
76                                                  gint       y);
77 static gboolean gdk_x11_device_xi_query_state   (GdkDevice        *device,
78                                                  GdkWindow        *window,
79                                                  GdkWindow       **root_window,
80                                                  GdkWindow       **child_window,
81                                                  gint             *root_x,
82                                                  gint             *root_y,
83                                                  gint             *win_x,
84                                                  gint             *win_y,
85                                                  GdkModifierType  *mask);
86 static GdkGrabStatus gdk_x11_device_xi_grab     (GdkDevice    *device,
87                                                  GdkWindow    *window,
88                                                  gboolean      owner_events,
89                                                  GdkEventMask  event_mask,
90                                                  GdkWindow    *confine_to,
91                                                  GdkCursor    *cursor,
92                                                  guint32       time_);
93 static void          gdk_x11_device_xi_ungrab   (GdkDevice    *device,
94                                                  guint32       time_);
95
96 static GdkWindow* gdk_x11_device_xi_window_at_position (GdkDevice       *device,
97                                                         gint            *win_x,
98                                                         gint            *win_y,
99                                                         GdkModifierType *mask,
100                                                         gboolean         get_toplevel);
101
102 static void gdk_x11_device_xi_select_window_events (GdkDevice    *device,
103                                                     GdkWindow    *window,
104                                                     GdkEventMask  mask);
105
106
107 enum {
108   PROP_0,
109   PROP_DEVICE_ID
110 };
111
112 static void
113 gdk_x11_device_xi_class_init (GdkX11DeviceXIClass *klass)
114 {
115   GObjectClass *object_class = G_OBJECT_CLASS (klass);
116   GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
117
118   quark_window_input_info = g_quark_from_static_string ("gdk-window-input-info");
119
120   object_class->constructed = gdk_x11_device_xi_constructed;
121   object_class->set_property = gdk_x11_device_xi_set_property;
122   object_class->get_property = gdk_x11_device_xi_get_property;
123   object_class->dispose = gdk_x11_device_xi_dispose;
124
125   device_class->get_history = gdk_x11_device_xi_get_history;
126   device_class->get_state = gdk_x11_device_xi_get_state;
127   device_class->set_window_cursor = gdk_x11_device_xi_set_window_cursor;
128   device_class->warp = gdk_x11_device_xi_warp;
129   device_class->query_state = gdk_x11_device_xi_query_state;
130   device_class->grab = gdk_x11_device_xi_grab;
131   device_class->ungrab = gdk_x11_device_xi_ungrab;
132   device_class->window_at_position = gdk_x11_device_xi_window_at_position;
133   device_class->select_window_events = gdk_x11_device_xi_select_window_events;
134
135   g_object_class_install_property (object_class,
136                                    PROP_DEVICE_ID,
137                                    g_param_spec_int ("device-id",
138                                                      P_("Device ID"),
139                                                      P_("Device ID"),
140                                                      0, G_MAXINT, 0,
141                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
142 }
143
144 static void
145 gdk_x11_device_xi_init (GdkX11DeviceXI *device)
146 {
147 }
148
149 static void
150 gdk_x11_device_xi_constructed (GObject *object)
151 {
152   GdkX11DeviceXI *device;
153   GdkDisplay *display;
154
155   device = GDK_X11_DEVICE_XI (object);
156   display = gdk_device_get_display (GDK_DEVICE (object));
157
158   gdk_x11_display_error_trap_push (display);
159   device->xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (display),
160                                  device->device_id);
161
162   if (gdk_x11_display_error_trap_pop (display))
163     g_warning ("Device %s can't be opened",
164                gdk_device_get_name (GDK_DEVICE (device)));
165
166   if (G_OBJECT_CLASS (gdk_x11_device_xi_parent_class)->constructed)
167     G_OBJECT_CLASS (gdk_x11_device_xi_parent_class)->constructed (object);
168 }
169
170 static void
171 gdk_x11_device_xi_set_property (GObject      *object,
172                                 guint         prop_id,
173                                 const GValue *value,
174                                 GParamSpec   *pspec)
175 {
176   GdkX11DeviceXI *device = GDK_X11_DEVICE_XI (object);
177
178   switch (prop_id)
179     {
180     case PROP_DEVICE_ID:
181       device->device_id = g_value_get_int (value);
182       break;
183     default:
184       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
185       break;
186     }
187 }
188
189 static void
190 gdk_x11_device_xi_get_property (GObject    *object,
191                                 guint       prop_id,
192                                 GValue     *value,
193                                 GParamSpec *pspec)
194 {
195   GdkX11DeviceXI *device = GDK_X11_DEVICE_XI (object);
196
197   switch (prop_id)
198     {
199     case PROP_DEVICE_ID:
200       g_value_set_int (value, device->device_id);
201       break;
202     default:
203       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
204       break;
205     }
206 }
207
208 static void
209 gdk_x11_device_xi_dispose (GObject *object)
210 {
211   GdkX11DeviceXI *device_xi;
212   GdkDisplay *display;
213
214   device_xi = GDK_X11_DEVICE_XI (object);
215   display = gdk_device_get_display (GDK_DEVICE (device_xi));
216
217   if (device_xi->xdevice)
218     {
219       XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device_xi->xdevice);
220       device_xi->xdevice = NULL;
221     }
222
223   if (device_xi->axis_data)
224     {
225       g_free (device_xi->axis_data);
226       device_xi->axis_data = NULL;
227     }
228
229   G_OBJECT_CLASS (gdk_x11_device_xi_parent_class)->dispose (object);
230 }
231
232 static gboolean
233 gdk_x11_device_xi_get_history (GdkDevice      *device,
234                                GdkWindow      *window,
235                                guint32         start,
236                                guint32         stop,
237                                GdkTimeCoord ***events,
238                                gint           *n_events)
239 {
240   GdkTimeCoord **coords;
241   XDeviceTimeCoord *device_coords;
242   GdkWindow *impl_window;
243   GdkX11DeviceXI *device_xi;
244   gint n_events_return;
245   gint mode_return;
246   gint axis_count_return;
247   gint i;
248
249   device_xi = GDK_X11_DEVICE_XI (device);
250   impl_window = _gdk_window_get_impl_window (window);
251
252   device_coords = XGetDeviceMotionEvents (GDK_WINDOW_XDISPLAY (impl_window),
253                                           device_xi->xdevice,
254                                           start, stop,
255                                           &n_events_return,
256                                           &mode_return,
257                                           &axis_count_return);
258
259   if (!device_coords)
260     return FALSE;
261
262   *n_events = n_events_return;
263   coords = _gdk_device_allocate_history (device, *n_events);
264
265   for (i = 0; i < *n_events; i++)
266     {
267       coords[i]->time = device_coords[i].time;
268       _gdk_x11_device_xi_translate_axes (device, window,
269                                          device_coords[i].data,
270                                          coords[i]->axes,
271                                          NULL, NULL);
272     }
273
274   XFreeDeviceMotionEvents (device_coords);
275
276   *events = coords;
277
278   return TRUE;
279 }
280
281 static void
282 gdk_x11_device_xi_get_state (GdkDevice       *device,
283                              GdkWindow       *window,
284                              gdouble         *axes,
285                              GdkModifierType *mask)
286 {
287   GdkX11DeviceXI *device_xi;
288   XDeviceState *state;
289   XInputClass *input_class;
290   gint i;
291
292   if (mask)
293     gdk_window_get_device_position (window, device, NULL, NULL, mask);
294
295   device_xi = GDK_X11_DEVICE_XI (device);
296   state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
297                              device_xi->xdevice);
298   input_class = state->data;
299
300   for (i = 0; i < state->num_classes; i++)
301     {
302       switch (input_class->class)
303         {
304         case ValuatorClass:
305           if (axes)
306             _gdk_x11_device_xi_translate_axes (device, window,
307                                                ((XValuatorState *) input_class)->valuators,
308                                                axes, NULL, NULL);
309           break;
310
311         case ButtonClass:
312           if (mask)
313             {
314               *mask &= 0xFF;
315               if (((XButtonState *)input_class)->num_buttons > 0)
316                 *mask |= ((XButtonState *)input_class)->buttons[0] << 7;
317               /* GDK_BUTTON1_MASK = 1 << 8, and button n is stored
318                * in bit 1<<(n%8) in byte n/8. n = 1,2,... */
319             }
320           break;
321         }
322
323       input_class = (XInputClass *)(((char *)input_class)+input_class->length);
324     }
325
326   XFreeDeviceState (state);
327 }
328
329 static void
330 gdk_x11_device_xi_set_window_cursor (GdkDevice *device,
331                                      GdkWindow *window,
332                                      GdkCursor *cursor)
333 {
334 }
335
336 static void
337 gdk_x11_device_xi_warp (GdkDevice *device,
338                         GdkScreen *screen,
339                         gint       x,
340                         gint       y)
341 {
342 }
343
344 static void
345 find_events (GdkDevice    *device,
346              GdkEventMask  mask,
347              XEventClass  *classes,
348              int          *num_classes)
349 {
350   GdkX11DeviceXI *device_xi;
351   XEventClass class;
352   gint i;
353
354   device_xi = GDK_X11_DEVICE_XI (device);
355   i = 0;
356
357   if (mask & GDK_BUTTON_PRESS_MASK)
358     {
359       DeviceButtonPress (device_xi->xdevice, device_xi->button_press_type, class);
360       if (class != 0)
361         classes[i++] = class;
362
363       DeviceButtonPressGrab (device_xi->xdevice, 0, class);
364       if (class != 0)
365         classes[i++] = class;
366     }
367
368   if (mask & GDK_BUTTON_RELEASE_MASK)
369     {
370       DeviceButtonRelease (device_xi->xdevice, device_xi->button_release_type, class);
371       if (class != 0)
372         classes[i++] = class;
373     }
374
375   if (mask & (GDK_POINTER_MOTION_MASK |
376               GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
377               GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_MOTION_MASK))
378     {
379       /* Make sure device->motionnotify_type is set */
380       DeviceMotionNotify (device_xi->xdevice, device_xi->motion_notify_type, class);
381       if (class != 0)
382           classes[i++] = class;
383       DeviceStateNotify (device_xi->xdevice, device_xi->state_notify_type, class);
384       if (class != 0)
385           classes[i++] = class;
386     }
387
388   if (mask & GDK_KEY_PRESS_MASK)
389     {
390       DeviceKeyPress (device_xi->xdevice, device_xi->key_press_type, class);
391       if (class != 0)
392         classes[i++] = class;
393     }
394
395   if (mask & GDK_KEY_RELEASE_MASK)
396     {
397       DeviceKeyRelease (device_xi->xdevice, device_xi->key_release_type, class);
398       if (class != 0)
399         classes[i++] = class;
400     }
401
402   if (mask & GDK_PROXIMITY_IN_MASK)
403     {
404       ProximityIn (device_xi->xdevice, device_xi->proximity_in_type, class);
405       if (class != 0)
406         classes[i++] = class;
407     }
408
409   if (mask & GDK_PROXIMITY_OUT_MASK)
410     {
411       ProximityOut (device_xi->xdevice, device_xi->proximity_out_type, class);
412       if (class != 0)
413         classes[i++] = class;
414     }
415
416   *num_classes = i;
417 }
418
419 static gboolean
420 gdk_x11_device_xi_query_state (GdkDevice        *device,
421                                GdkWindow        *window,
422                                GdkWindow       **root_window,
423                                GdkWindow       **child_window,
424                                gint             *root_x,
425                                gint             *root_y,
426                                gint             *win_x,
427                                gint             *win_y,
428                                GdkModifierType  *mask)
429 {
430   return FALSE;
431 }
432
433 static GdkGrabStatus
434 gdk_x11_device_xi_grab (GdkDevice    *device,
435                         GdkWindow    *window,
436                         gboolean      owner_events,
437                         GdkEventMask  event_mask,
438                         GdkWindow    *confine_to,
439                         GdkCursor    *cursor,
440                         guint32       time_)
441 {
442   XEventClass event_classes[MAX_DEVICE_CLASSES];
443   gint status, num_classes;
444   GdkX11DeviceXI *device_xi;
445   GdkDisplay *display;
446
447   device_xi = GDK_X11_DEVICE_XI (device);
448   display = gdk_device_get_display (device);
449   find_events (device, event_mask, event_classes, &num_classes);
450
451 #ifdef G_ENABLE_DEBUG
452   if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
453     status = GrabSuccess;
454   else
455 #endif
456   status = XGrabDevice (GDK_DISPLAY_XDISPLAY (display),
457                         device_xi->xdevice,
458                         GDK_WINDOW_XID (window),
459                         owner_events,
460                         num_classes, event_classes,
461                         GrabModeAsync, GrabModeAsync,
462                         time_);
463
464   _gdk_x11_display_update_grab_info (display, device, status);
465
466   return _gdk_x11_convert_grab_status (status);
467 }
468
469 static void
470 gdk_x11_device_xi_ungrab (GdkDevice *device,
471                           guint32    time_)
472 {
473   GdkX11DeviceXI *device_xi;
474   GdkDisplay *display;
475   Display *xdisplay;
476   unsigned long serial;
477
478   device_xi = GDK_X11_DEVICE_XI (device);
479   display = gdk_device_get_display (device);
480   xdisplay = GDK_DISPLAY_XDISPLAY (display);
481
482   serial = NextRequest (xdisplay);
483
484   XUngrabDevice (xdisplay, device_xi->xdevice, time_);
485
486   _gdk_x11_display_update_grab_info_ungrab (display, device, time_, serial);
487 }
488
489 static GdkWindow*
490 gdk_x11_device_xi_window_at_position (GdkDevice       *device,
491                                       gint            *win_x,
492                                       gint            *win_y,
493                                       GdkModifierType *mask,
494                                       gboolean         get_toplevel)
495 {
496   return NULL;
497 }
498
499 static void
500 gdk_x11_device_xi_select_window_events (GdkDevice    *device,
501                                         GdkWindow    *window,
502                                         GdkEventMask  event_mask)
503 {
504   XEventClass event_classes[MAX_DEVICE_CLASSES];
505   gint num_classes;
506
507   event_mask |= (GDK_PROXIMITY_IN_MASK |
508                  GDK_PROXIMITY_OUT_MASK);
509
510   find_events (device, event_mask, event_classes, &num_classes);
511
512   XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (window),
513                          GDK_WINDOW_XID (window),
514                          event_classes, num_classes);
515
516   if (event_mask)
517     {
518       GdkWindowInputInfo *info;
519
520       info = g_new0 (GdkWindowInputInfo, 1);
521       g_object_set_qdata_full (G_OBJECT (window),
522                                quark_window_input_info,
523                                info,
524                                (GDestroyNotify) g_free);
525     }
526   else
527     g_object_set_qdata (G_OBJECT (window),
528                         quark_window_input_info,
529                         NULL);
530 }
531
532 void
533 _gdk_x11_device_xi_update_window_info (GdkWindow *window)
534 {
535   GdkWindowInputInfo *info;
536   gint root_x, root_y;
537
538   info = g_object_get_qdata (G_OBJECT (window),
539                              quark_window_input_info);
540
541   if (!info)
542     return;
543
544   gdk_window_get_origin (window, &root_x, &root_y);
545   info->root_x = (gdouble) root_x;
546   info->root_y = (gdouble) root_y;
547 }
548
549 static gboolean
550 gdk_x11_device_xi_get_window_info (GdkWindow *window,
551                                    gdouble   *root_x,
552                                    gdouble   *root_y)
553 {
554   GdkWindowInputInfo *info;
555
556   info = g_object_get_qdata (G_OBJECT (window),
557                              quark_window_input_info);
558
559   if (!info)
560     return FALSE;
561
562   *root_x = info->root_x;
563   *root_y = info->root_y;
564
565   return TRUE;
566 }
567
568 void
569 _gdk_x11_device_xi_update_axes (GdkDevice *device,
570                                 gint       axes_count,
571                                 gint       first_axis,
572                                 gint      *axis_data)
573 {
574   GdkX11DeviceXI *device_xi;
575   int i;
576
577   device_xi = GDK_X11_DEVICE_XI (device);
578   g_return_if_fail (first_axis >= 0 &&
579                     first_axis + axes_count <= gdk_device_get_n_axes (device));
580
581   if (!device_xi->axis_data)
582     device_xi->axis_data = g_new0 (gint, gdk_device_get_n_axes (device));
583
584   for (i = 0; i < axes_count; i++)
585     device_xi->axis_data[first_axis + i] = axis_data[i];
586 }
587
588 void
589 _gdk_x11_device_xi_translate_axes (GdkDevice *device,
590                                    GdkWindow *window,
591                                    gint      *axis_data,
592                                    gdouble   *axes,
593                                    gdouble   *x,
594                                    gdouble   *y)
595 {
596   GdkWindow *impl_window;
597   gdouble root_x, root_y;
598   gdouble temp_x, temp_y;
599   gint n_axes;
600   gint i;
601
602   impl_window = _gdk_window_get_impl_window (window);
603   temp_x = temp_y = 0;
604
605   if (!gdk_x11_device_xi_get_window_info (impl_window, &root_x, &root_y))
606     return;
607
608   n_axes = gdk_device_get_n_axes (device);
609
610   for (i = 0; i < n_axes; i++)
611     {
612       GdkAxisUse use;
613
614       use = gdk_device_get_axis_use (device, i);
615
616       switch (use)
617         {
618         case GDK_AXIS_X:
619         case GDK_AXIS_Y:
620           if (gdk_device_get_mode (device) == GDK_MODE_WINDOW)
621             _gdk_device_translate_window_coord (device, window,
622                                                 i, axis_data[i],
623                                                 &axes[i]);
624           else
625             _gdk_device_translate_screen_coord (device, window,
626                                                 root_x, root_y,
627                                                 i, axis_data[i],
628                                                 &axes[i]);
629           if (use == GDK_AXIS_X)
630             temp_x = axes[i];
631           else if (use == GDK_AXIS_Y)
632             temp_y = axes[i];
633
634           break;
635         default:
636           _gdk_device_translate_axis (device, i, axis_data[i], &axes[i]);
637           break;
638         }
639     }
640
641   if (x)
642     *x = temp_x;
643
644   if (y)
645     *y = temp_y;
646 }
647
648 #else /* XINPUT_XFREE */
649
650 static void
651 gdk_x11_device_xi_class_init (GdkX11DeviceXIClass *klass)
652 {
653 }
654
655 static void
656 gdk_x11_device_xi_init (GdkX11DeviceXI *device)
657 {
658 }
659
660 #endif /* XINPUT_XFREE */