]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkdevice-xi2.c
Merge branch 'master' into broadway2
[~andy/gtk] / gdk / x11 / gdkdevice-xi2.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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gdkx11device-xi2.h"
23 #include "gdkdeviceprivate.h"
24
25 #include "gdkintl.h"
26 #include "gdkasync.h"
27 #include "gdkprivate-x11.h"
28
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/extensions/XInput2.h>
32
33 struct _GdkX11DeviceXI2
34 {
35   GdkDevice parent_instance;
36
37   gint device_id;
38 };
39
40 struct _GdkX11DeviceXI2Class
41 {
42   GdkDeviceClass parent_class;
43 };
44
45 static void gdk_x11_device_xi2_get_property (GObject      *object,
46                                              guint         prop_id,
47                                              GValue       *value,
48                                              GParamSpec   *pspec);
49 static void gdk_x11_device_xi2_set_property (GObject      *object,
50                                              guint         prop_id,
51                                              const GValue *value,
52                                              GParamSpec   *pspec);
53
54 static void gdk_x11_device_xi2_get_state (GdkDevice       *device,
55                                           GdkWindow       *window,
56                                           gdouble         *axes,
57                                           GdkModifierType *mask);
58 static void gdk_x11_device_xi2_set_window_cursor (GdkDevice *device,
59                                                   GdkWindow *window,
60                                                   GdkCursor *cursor);
61 static void gdk_x11_device_xi2_warp (GdkDevice *device,
62                                      GdkScreen *screen,
63                                      gint       x,
64                                      gint       y);
65 static gboolean gdk_x11_device_xi2_query_state (GdkDevice        *device,
66                                                 GdkWindow        *window,
67                                                 GdkWindow       **root_window,
68                                                 GdkWindow       **child_window,
69                                                 gint             *root_x,
70                                                 gint             *root_y,
71                                                 gint             *win_x,
72                                                 gint             *win_y,
73                                                 GdkModifierType  *mask);
74
75 static GdkGrabStatus gdk_x11_device_xi2_grab   (GdkDevice     *device,
76                                                 GdkWindow     *window,
77                                                 gboolean       owner_events,
78                                                 GdkEventMask   event_mask,
79                                                 GdkWindow     *confine_to,
80                                                 GdkCursor     *cursor,
81                                                 guint32        time_);
82 static void          gdk_x11_device_xi2_ungrab (GdkDevice     *device,
83                                                 guint32        time_);
84
85 static GdkWindow * gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
86                                                           gint            *win_x,
87                                                           gint            *win_y,
88                                                           GdkModifierType *mask,
89                                                           gboolean         get_toplevel);
90 static void  gdk_x11_device_xi2_select_window_events (GdkDevice    *device,
91                                                       GdkWindow    *window,
92                                                       GdkEventMask  event_mask);
93
94
95 G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
96
97 enum {
98   PROP_0,
99   PROP_DEVICE_ID
100 };
101
102 static void
103 gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
104 {
105   GObjectClass *object_class = G_OBJECT_CLASS (klass);
106   GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
107
108   object_class->get_property = gdk_x11_device_xi2_get_property;
109   object_class->set_property = gdk_x11_device_xi2_set_property;
110
111   device_class->get_state = gdk_x11_device_xi2_get_state;
112   device_class->set_window_cursor = gdk_x11_device_xi2_set_window_cursor;
113   device_class->warp = gdk_x11_device_xi2_warp;
114   device_class->query_state = gdk_x11_device_xi2_query_state;
115   device_class->grab = gdk_x11_device_xi2_grab;
116   device_class->ungrab = gdk_x11_device_xi2_ungrab;
117   device_class->window_at_position = gdk_x11_device_xi2_window_at_position;
118   device_class->select_window_events = gdk_x11_device_xi2_select_window_events;
119
120   g_object_class_install_property (object_class,
121                                    PROP_DEVICE_ID,
122                                    g_param_spec_int ("device-id",
123                                                      P_("Device ID"),
124                                                      P_("Device identifier"),
125                                                      0, G_MAXINT, 0,
126                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
127 }
128
129 static void
130 gdk_x11_device_xi2_init (GdkX11DeviceXI2 *device)
131 {
132 }
133
134 static void
135 gdk_x11_device_xi2_get_property (GObject    *object,
136                                  guint       prop_id,
137                                  GValue     *value,
138                                  GParamSpec *pspec)
139 {
140   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (object);
141
142   switch (prop_id)
143     {
144     case PROP_DEVICE_ID:
145       g_value_set_int (value, device_xi2->device_id);
146       break;
147     default:
148       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
149       break;
150     }
151 }
152
153 static void
154 gdk_x11_device_xi2_set_property (GObject      *object,
155                                  guint         prop_id,
156                                  const GValue *value,
157                                  GParamSpec   *pspec)
158 {
159   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (object);
160
161   switch (prop_id)
162     {
163     case PROP_DEVICE_ID:
164       device_xi2->device_id = g_value_get_int (value);
165       break;
166     default:
167       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
168       break;
169     }
170 }
171
172 static void
173 gdk_x11_device_xi2_get_state (GdkDevice       *device,
174                               GdkWindow       *window,
175                               gdouble         *axes,
176                               GdkModifierType *mask)
177 {
178   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
179   GdkDisplay *display;
180   XIDeviceInfo *info;
181   gint i, j, ndevices;
182
183   display = gdk_device_get_display (device);
184
185   if (axes)
186     {
187       info = XIQueryDevice(GDK_DISPLAY_XDISPLAY (display),
188                            device_xi2->device_id, &ndevices);
189
190       for (i = 0, j = 0; i < info->num_classes; i++)
191         {
192           XIAnyClassInfo *class_info = info->classes[i];
193           GdkAxisUse use;
194           gdouble value;
195
196           if (class_info->type != XIValuatorClass)
197             continue;
198
199           value = ((XIValuatorClassInfo *) class_info)->value;
200           use = _gdk_device_get_axis_use (device, j);
201
202           switch (use)
203             {
204             case GDK_AXIS_X:
205             case GDK_AXIS_Y:
206             case GDK_AXIS_IGNORE:
207               if (gdk_device_get_mode (device) == GDK_MODE_WINDOW)
208                 _gdk_device_translate_window_coord (device, window, j, value, &axes[j]);
209               else
210                 {
211                   gint root_x, root_y;
212
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,
216                                                       root_x, root_y,
217                                                       j, value,
218                                                       &axes[j]);
219                 }
220               break;
221             default:
222               _gdk_device_translate_axis (device, j, value, &axes[j]);
223               break;
224             }
225
226           j++;
227         }
228
229       XIFreeDeviceInfo (info);
230     }
231
232   if (mask)
233     gdk_x11_device_xi2_query_state (device, window,
234                                     NULL, NULL,
235                                     NULL, NULL,
236                                     NULL, NULL,
237                                     mask);
238 }
239
240 static void
241 gdk_x11_device_xi2_set_window_cursor (GdkDevice *device,
242                                       GdkWindow *window,
243                                       GdkCursor *cursor)
244 {
245   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
246
247   /* Non-master devices don't have a cursor */
248   if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
249     return;
250
251   if (cursor)
252     XIDefineCursor (GDK_WINDOW_XDISPLAY (window),
253                     device_xi2->device_id,
254                     GDK_WINDOW_XID (window),
255                     gdk_x11_cursor_get_xcursor (cursor));
256   else
257     XIUndefineCursor (GDK_WINDOW_XDISPLAY (window),
258                       device_xi2->device_id,
259                       GDK_WINDOW_XID (window));
260 }
261
262 static void
263 gdk_x11_device_xi2_warp (GdkDevice *device,
264                          GdkScreen *screen,
265                          gint       x,
266                          gint       y)
267 {
268   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
269   Window dest;
270
271   dest = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
272
273   XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
274                  device_xi2->device_id,
275                  None, dest,
276                  0, 0, 0, 0, x, y);
277 }
278
279 static gboolean
280 gdk_x11_device_xi2_query_state (GdkDevice        *device,
281                                 GdkWindow        *window,
282                                 GdkWindow       **root_window,
283                                 GdkWindow       **child_window,
284                                 gint             *root_x,
285                                 gint             *root_y,
286                                 gint             *win_x,
287                                 gint             *win_y,
288                                 GdkModifierType  *mask)
289 {
290   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
291   GdkDisplay *display;
292   GdkScreen *default_screen;
293   Window xroot_window, xchild_window;
294   gdouble xroot_x, xroot_y, xwin_x, xwin_y;
295   XIButtonState button_state;
296   XIModifierState mod_state;
297   XIGroupState group_state;
298
299   if (!window || GDK_WINDOW_DESTROYED (window))
300     return FALSE;
301
302   display = gdk_window_get_display (window);
303   default_screen = gdk_display_get_default_screen (display);
304
305   if (G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
306     {
307       if (!XIQueryPointer (GDK_WINDOW_XDISPLAY (window),
308                            device_xi2->device_id,
309                            GDK_WINDOW_XID (window),
310                            &xroot_window,
311                            &xchild_window,
312                            &xroot_x, &xroot_y,
313                            &xwin_x, &xwin_y,
314                            &button_state,
315                            &mod_state,
316                            &group_state))
317         return FALSE;
318     }
319   else
320     {
321       XSetWindowAttributes attributes;
322       Display *xdisplay;
323       Window xwindow, w;
324
325       /* FIXME: untrusted clients not multidevice-safe */
326       xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
327       xwindow = GDK_SCREEN_XROOTWIN (default_screen);
328
329       w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
330                          CopyFromParent, InputOnly, CopyFromParent,
331                          0, &attributes);
332       XIQueryPointer (xdisplay, device_xi2->device_id,
333                       w,
334                       &xroot_window,
335                       &xchild_window,
336                       &xroot_x, &xroot_y,
337                       &xwin_x, &xwin_y,
338                       &button_state,
339                       &mod_state,
340                       &group_state);
341       XDestroyWindow (xdisplay, w);
342     }
343
344   if (root_window)
345     *root_window = gdk_x11_window_lookup_for_display (display, xroot_window);
346
347   if (child_window)
348     *child_window = gdk_x11_window_lookup_for_display (display, xchild_window);
349
350   if (root_x)
351     *root_x = (gint) xroot_x;
352
353   if (root_y)
354     *root_y = (gint) xroot_y;
355
356   if (win_x)
357     *win_x = (gint) xwin_x;
358
359   if (win_y)
360     *win_y = (gint) xwin_y;
361
362   if (mask)
363     *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state);
364
365   return TRUE;
366 }
367
368 static GdkGrabStatus
369 gdk_x11_device_xi2_grab (GdkDevice    *device,
370                          GdkWindow    *window,
371                          gboolean      owner_events,
372                          GdkEventMask  event_mask,
373                          GdkWindow    *confine_to,
374                          GdkCursor    *cursor,
375                          guint32       time_)
376 {
377   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
378   GdkDisplay *display;
379   XIEventMask mask;
380   Window xwindow;
381   Cursor xcursor;
382   gint status;
383
384   display = gdk_device_get_display (device);
385
386   /* FIXME: confine_to is actually unused */
387
388   xwindow = GDK_WINDOW_XID (window);
389
390   if (!cursor)
391     xcursor = None;
392   else
393     {
394       _gdk_x11_cursor_update_theme (cursor);
395       xcursor = gdk_x11_cursor_get_xcursor (cursor);
396     }
397
398   mask.deviceid = device_xi2->device_id;
399   mask.mask = _gdk_x11_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
400
401 #ifdef G_ENABLE_DEBUG
402   if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
403     status = GrabSuccess;
404   else
405 #endif
406   status = XIGrabDevice (GDK_DISPLAY_XDISPLAY (display),
407                          device_xi2->device_id,
408                          xwindow,
409                          time_,
410                          xcursor,
411                          GrabModeAsync, GrabModeAsync,
412                          owner_events,
413                          &mask);
414
415   g_free (mask.mask);
416
417   _gdk_x11_display_update_grab_info (display, device, status);
418
419   return _gdk_x11_convert_grab_status (status);
420 }
421
422 static void
423 gdk_x11_device_xi2_ungrab (GdkDevice *device,
424                            guint32    time_)
425 {
426   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
427   GdkDisplay *display;
428   gulong serial;
429
430   display = gdk_device_get_display (device);
431   serial = NextRequest (GDK_DISPLAY_XDISPLAY (display));
432
433   XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display), device_xi2->device_id, time_);
434
435   _gdk_x11_display_update_grab_info_ungrab (display, device, time_, serial);
436 }
437
438 static GdkWindow *
439 gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
440                                        gint            *win_x,
441                                        gint            *win_y,
442                                        GdkModifierType *mask,
443                                        gboolean         get_toplevel)
444 {
445   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
446   GdkDisplay *display;
447   GdkScreen *screen;
448   Display *xdisplay;
449   GdkWindow *window;
450   Window xwindow, root, child, last = None;
451   gdouble xroot_x, xroot_y, xwin_x, xwin_y;
452   XIButtonState button_state;
453   XIModifierState mod_state;
454   XIGroupState group_state;
455
456   display = gdk_device_get_display (device);
457   screen = gdk_display_get_default_screen (display);
458
459   /* This function really only works if the mouse pointer is held still
460    * during its operation. If it moves from one leaf window to another
461    * than we'll end up with inaccurate values for win_x, win_y
462    * and the result.
463    */
464   gdk_x11_display_grab (display);
465
466   xdisplay = GDK_SCREEN_XDISPLAY (screen);
467   xwindow = GDK_SCREEN_XROOTWIN (screen);
468
469   if (G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
470     {
471       XIQueryPointer (xdisplay,
472                       device_xi2->device_id,
473                       xwindow,
474                       &root, &child,
475                       &xroot_x, &xroot_y,
476                       &xwin_x, &xwin_y,
477                       &button_state,
478                       &mod_state,
479                       &group_state);
480
481       if (root == xwindow)
482         xwindow = child;
483       else
484         xwindow = root;
485     }
486   else
487     {
488       gint i, screens, width, height;
489       GList *toplevels, *list;
490       Window pointer_window, root, child;
491
492       /* FIXME: untrusted clients case not multidevice-safe */
493       pointer_window = None;
494       screens = gdk_display_get_n_screens (display);
495
496       for (i = 0; i < screens; ++i)
497         {
498           screen = gdk_display_get_screen (display, i);
499           toplevels = gdk_screen_get_toplevel_windows (screen);
500           for (list = toplevels; list != NULL; list = g_list_next (list))
501             {
502               window = GDK_WINDOW (list->data);
503               xwindow = GDK_WINDOW_XID (window);
504               gdk_x11_display_error_trap_push (display);
505               XIQueryPointer (xdisplay,
506                               device_xi2->device_id,
507                               xwindow,
508                               &root, &child,
509                               &xroot_x, &xroot_y,
510                               &xwin_x, &xwin_y,
511                               &button_state,
512                               &mod_state,
513                               &group_state);
514               if (gdk_x11_display_error_trap_pop (display))
515                 continue;
516               if (child != None)
517                 {
518                   pointer_window = child;
519                   break;
520                 }
521               gdk_window_get_geometry (window, NULL, NULL, &width, &height);
522               if (xwin_x >= 0 && xwin_y >= 0 && xwin_x < width && xwin_y < height)
523                 {
524                   /* A childless toplevel, or below another window? */
525                   XSetWindowAttributes attributes;
526                   Window w;
527
528                   w = XCreateWindow (xdisplay, xwindow, (int)xwin_x, (int)xwin_y, 1, 1, 0,
529                                      CopyFromParent, InputOnly, CopyFromParent,
530                                      0, &attributes);
531                   XMapWindow (xdisplay, w);
532                   XIQueryPointer (xdisplay,
533                                   device_xi2->device_id,
534                                   xwindow,
535                                   &root, &child,
536                                   &xroot_x, &xroot_y,
537                                   &xwin_x, &xwin_y,
538                                   &button_state,
539                                   &mod_state,
540                                   &group_state);
541                   XDestroyWindow (xdisplay, w);
542                   if (child == w)
543                     {
544                       pointer_window = xwindow;
545                       break;
546                     }
547                 }
548             }
549
550           g_list_free (toplevels);
551           if (pointer_window != None)
552             break;
553         }
554
555       xwindow = pointer_window;
556     }
557
558   while (xwindow)
559     {
560       last = xwindow;
561       gdk_x11_display_error_trap_push (display);
562       XIQueryPointer (xdisplay,
563                       device_xi2->device_id,
564                       xwindow,
565                       &root, &xwindow,
566                       &xroot_x, &xroot_y,
567                       &xwin_x, &xwin_y,
568                       &button_state,
569                       &mod_state,
570                       &group_state);
571       if (gdk_x11_display_error_trap_pop (display))
572         break;
573
574       if (get_toplevel && last != root &&
575           (window = gdk_x11_window_lookup_for_display (display, last)) != NULL &&
576           GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
577         {
578           xwindow = last;
579           break;
580         }
581     }
582
583   gdk_x11_display_ungrab (display);
584
585   window = gdk_x11_window_lookup_for_display (display, last);
586
587   if (win_x)
588     *win_x = (window) ? (gint) xwin_x : -1;
589
590   if (win_y)
591     *win_y = (window) ? (gint) xwin_y : -1;
592
593   if (mask)
594     *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state);
595
596   return window;
597 }
598
599 static void
600 gdk_x11_device_xi2_select_window_events (GdkDevice    *device,
601                                          GdkWindow    *window,
602                                          GdkEventMask  event_mask)
603 {
604   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
605   XIEventMask evmask;
606
607   evmask.deviceid = device_xi2->device_id;
608   evmask.mask = _gdk_x11_device_xi2_translate_event_mask (event_mask, &evmask.mask_len);
609
610   XISelectEvents (GDK_WINDOW_XDISPLAY (window),
611                   GDK_WINDOW_XID (window),
612                   &evmask, 1);
613
614   g_free (evmask.mask);
615 }
616
617 guchar *
618 _gdk_x11_device_xi2_translate_event_mask (GdkEventMask  event_mask,
619                                           gint         *len)
620 {
621   guchar *mask;
622
623   *len = XIMaskLen (XI_LASTEVENT);
624   mask = g_new0 (guchar, *len);
625
626   if (event_mask & GDK_POINTER_MOTION_MASK ||
627       event_mask & GDK_POINTER_MOTION_HINT_MASK)
628     XISetMask (mask, XI_Motion);
629
630   if (event_mask & GDK_BUTTON_MOTION_MASK ||
631       event_mask & GDK_BUTTON1_MOTION_MASK ||
632       event_mask & GDK_BUTTON2_MOTION_MASK ||
633       event_mask & GDK_BUTTON3_MOTION_MASK)
634     {
635       XISetMask (mask, XI_ButtonPress);
636       XISetMask (mask, XI_ButtonRelease);
637       XISetMask (mask, XI_Motion);
638     }
639
640   if (event_mask & GDK_SCROLL_MASK)
641     {
642       XISetMask (mask, XI_ButtonPress);
643       XISetMask (mask, XI_ButtonRelease);
644     }
645
646   if (event_mask & GDK_BUTTON_PRESS_MASK)
647     XISetMask (mask, XI_ButtonPress);
648
649   if (event_mask & GDK_BUTTON_RELEASE_MASK)
650     XISetMask (mask, XI_ButtonRelease);
651
652   if (event_mask & GDK_KEY_PRESS_MASK)
653     XISetMask (mask, XI_KeyPress);
654
655   if (event_mask & GDK_KEY_RELEASE_MASK)
656     XISetMask (mask, XI_KeyRelease);
657
658   if (event_mask & GDK_ENTER_NOTIFY_MASK)
659     XISetMask (mask, XI_Enter);
660
661   if (event_mask & GDK_LEAVE_NOTIFY_MASK)
662     XISetMask (mask, XI_Leave);
663
664   if (event_mask & GDK_FOCUS_CHANGE_MASK)
665     {
666       XISetMask (mask, XI_FocusIn);
667       XISetMask (mask, XI_FocusOut);
668     }
669
670   return mask;
671 }
672
673 guint
674 _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
675                                      XIButtonState   *buttons_state)
676 {
677   guint state = 0;
678
679   if (mods_state)
680     state = (guint) mods_state->effective;
681
682   if (buttons_state)
683     {
684       gint len, i;
685
686       /* We're only interested in the first 5 buttons */
687       len = MIN (5, buttons_state->mask_len * 8);
688
689       for (i = 0; i < len; i++)
690         {
691           if (!XIMaskIsSet (buttons_state->mask, i))
692             continue;
693
694           switch (i)
695             {
696             case 1:
697               state |= GDK_BUTTON1_MASK;
698               break;
699             case 2:
700               state |= GDK_BUTTON2_MASK;
701               break;
702             case 3:
703               state |= GDK_BUTTON3_MASK;
704               break;
705             case 4:
706               state |= GDK_BUTTON4_MASK;
707               break;
708             case 5:
709               state |= GDK_BUTTON5_MASK;
710               break;
711             default:
712               break;
713             }
714         }
715     }
716
717   return state;
718 }