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