]> Pileus Git - ~andy/gtk/blob - gdk/broadway/gdkdevice-broadway.c
[broadway] Copy X backend to broadway
[~andy/gtk] / gdk / broadway / gdkdevice-broadway.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-broadway.h"
23
24 #include "gdkwindow.h"
25 #include "gdkprivate-broadway.h"
26 #include "gdkx.h"
27
28 static gboolean gdk_device_core_get_history (GdkDevice      *device,
29                                              GdkWindow      *window,
30                                              guint32         start,
31                                              guint32         stop,
32                                              GdkTimeCoord ***events,
33                                              gint           *n_events);
34 static void gdk_device_core_get_state (GdkDevice       *device,
35                                        GdkWindow       *window,
36                                        gdouble         *axes,
37                                        GdkModifierType *mask);
38 static void gdk_device_core_set_window_cursor (GdkDevice *device,
39                                                GdkWindow *window,
40                                                GdkCursor *cursor);
41 static void gdk_device_core_warp (GdkDevice *device,
42                                   GdkScreen *screen,
43                                   gint       x,
44                                   gint       y);
45 static gboolean gdk_device_core_query_state (GdkDevice        *device,
46                                              GdkWindow        *window,
47                                              GdkWindow       **root_window,
48                                              GdkWindow       **child_window,
49                                              gint             *root_x,
50                                              gint             *root_y,
51                                              gint             *win_x,
52                                              gint             *win_y,
53                                              GdkModifierType  *mask);
54 static GdkGrabStatus gdk_device_core_grab   (GdkDevice     *device,
55                                              GdkWindow     *window,
56                                              gboolean       owner_events,
57                                              GdkEventMask   event_mask,
58                                              GdkWindow     *confine_to,
59                                              GdkCursor     *cursor,
60                                              guint32        time_);
61 static void          gdk_device_core_ungrab (GdkDevice     *device,
62                                              guint32        time_);
63 static GdkWindow * gdk_device_core_window_at_position (GdkDevice       *device,
64                                                        gint            *win_x,
65                                                        gint            *win_y,
66                                                        GdkModifierType *mask,
67                                                        gboolean         get_toplevel);
68 static void      gdk_device_core_select_window_events (GdkDevice       *device,
69                                                        GdkWindow       *window,
70                                                        GdkEventMask     event_mask);
71
72
73 G_DEFINE_TYPE (GdkDeviceCore, gdk_device_core, GDK_TYPE_DEVICE)
74
75 static void
76 gdk_device_core_class_init (GdkDeviceCoreClass *klass)
77 {
78   GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
79
80   device_class->get_history = gdk_device_core_get_history;
81   device_class->get_state = gdk_device_core_get_state;
82   device_class->set_window_cursor = gdk_device_core_set_window_cursor;
83   device_class->warp = gdk_device_core_warp;
84   device_class->query_state = gdk_device_core_query_state;
85   device_class->grab = gdk_device_core_grab;
86   device_class->ungrab = gdk_device_core_ungrab;
87   device_class->window_at_position = gdk_device_core_window_at_position;
88   device_class->select_window_events = gdk_device_core_select_window_events;
89 }
90
91 static void
92 gdk_device_core_init (GdkDeviceCore *device_core)
93 {
94   GdkDevice *device;
95
96   device = GDK_DEVICE (device_core);
97
98   _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
99   _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
100 }
101
102 static gboolean
103 impl_coord_in_window (GdkWindow *window,
104                       int        impl_x,
105                       int        impl_y)
106 {
107   GdkWindowObject *priv = (GdkWindowObject *) window;
108
109   if (impl_x < priv->abs_x ||
110       impl_x > priv->abs_x + priv->width)
111     return FALSE;
112
113   if (impl_y < priv->abs_y ||
114       impl_y > priv->abs_y + priv->height)
115     return FALSE;
116
117   return TRUE;
118 }
119
120 static gboolean
121 gdk_device_core_get_history (GdkDevice      *device,
122                              GdkWindow      *window,
123                              guint32         start,
124                              guint32         stop,
125                              GdkTimeCoord ***events,
126                              gint           *n_events)
127 {
128   GdkWindowObject *priv;
129   XTimeCoord *xcoords;
130   GdkTimeCoord **coords;
131   GdkWindow *impl_window;
132   int tmp_n_events;
133   int i, j;
134
135   impl_window = _gdk_window_get_impl_window (window);
136   xcoords = XGetMotionEvents (GDK_DRAWABLE_XDISPLAY (window),
137                               GDK_DRAWABLE_XID (impl_window),
138                               start, stop, &tmp_n_events);
139   if (!xcoords)
140     return FALSE;
141
142   priv = (GdkWindowObject *) window;
143   coords = _gdk_device_allocate_history (device, tmp_n_events);
144
145   for (i = 0, j = 0; i < tmp_n_events; i++)
146     {
147       if (impl_coord_in_window (window, xcoords[i].x, xcoords[i].y))
148         {
149           coords[j]->time = xcoords[i].time;
150           coords[j]->axes[0] = xcoords[i].x - priv->abs_x;
151           coords[j]->axes[1] = xcoords[i].y - priv->abs_y;
152           j++;
153         }
154     }
155
156   XFree (xcoords);
157
158   /* free the events we allocated too much */
159   for (i = j; i < tmp_n_events; i++)
160     {
161       g_free (coords[i]);
162       coords[i] = NULL;
163     }
164
165   tmp_n_events = j;
166
167   if (tmp_n_events == 0)
168     {
169       gdk_device_free_history (coords, tmp_n_events);
170       return FALSE;
171     }
172
173   if (n_events)
174     *n_events = tmp_n_events;
175
176   if (events)
177     *events = coords;
178   else if (coords)
179     gdk_device_free_history (coords, tmp_n_events);
180
181   return TRUE;
182 }
183
184 static void
185 gdk_device_core_get_state (GdkDevice       *device,
186                            GdkWindow       *window,
187                            gdouble         *axes,
188                            GdkModifierType *mask)
189 {
190   gint x_int, y_int;
191
192   gdk_window_get_pointer (window, &x_int, &y_int, mask);
193
194   if (axes)
195     {
196       axes[0] = x_int;
197       axes[1] = y_int;
198     }
199 }
200
201 static void
202 gdk_device_core_set_window_cursor (GdkDevice *device,
203                                    GdkWindow *window,
204                                    GdkCursor *cursor)
205 {
206   GdkCursorPrivate *cursor_private;
207   Cursor xcursor;
208
209   cursor_private = (GdkCursorPrivate*) cursor;
210
211   if (!cursor)
212     xcursor = None;
213   else
214     xcursor = cursor_private->xcursor;
215
216   XDefineCursor (GDK_WINDOW_XDISPLAY (window),
217                  GDK_WINDOW_XID (window),
218                  xcursor);
219 }
220
221 static void
222 gdk_device_core_warp (GdkDevice *device,
223                       GdkScreen *screen,
224                       gint       x,
225                       gint       y)
226 {
227   Display *xdisplay;
228   Window dest;
229
230   xdisplay = GDK_DISPLAY_XDISPLAY (gdk_device_get_display (device));
231   dest = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
232
233   XWarpPointer (xdisplay, None, dest, 0, 0, 0, 0, x, y);
234 }
235
236 static gboolean
237 gdk_device_core_query_state (GdkDevice        *device,
238                              GdkWindow        *window,
239                              GdkWindow       **root_window,
240                              GdkWindow       **child_window,
241                              gint             *root_x,
242                              gint             *root_y,
243                              gint             *win_x,
244                              gint             *win_y,
245                              GdkModifierType  *mask)
246 {
247   GdkDisplay *display;
248   Window xroot_window, xchild_window;
249   int xroot_x, xroot_y, xwin_x, xwin_y;
250   unsigned int xmask;
251
252   display = gdk_window_get_display (window);
253
254   if (!XQueryPointer (GDK_WINDOW_XDISPLAY (window),
255                       GDK_WINDOW_XID (window),
256                       &xroot_window,
257                       &xchild_window,
258                       &xroot_x,
259                       &xroot_y,
260                       &xwin_x,
261                       &xwin_y,
262                       &xmask))
263     {
264       return FALSE;
265     }
266
267   if (root_window)
268     *root_window = gdk_window_lookup_for_display (display, xroot_window);
269
270   if (child_window)
271     *child_window = gdk_window_lookup_for_display (display, xchild_window);
272
273   if (root_x)
274     *root_x = xroot_x;
275
276   if (root_y)
277     *root_y = xroot_y;
278
279   if (win_x)
280     *win_x = xwin_x;
281
282   if (win_y)
283     *win_y = xwin_y;
284
285   if (mask)
286     *mask = xmask;
287
288   return TRUE;
289 }
290
291 static GdkGrabStatus
292 gdk_device_core_grab (GdkDevice    *device,
293                       GdkWindow    *window,
294                       gboolean      owner_events,
295                       GdkEventMask  event_mask,
296                       GdkWindow    *confine_to,
297                       GdkCursor    *cursor,
298                       guint32       time_)
299 {
300   GdkDisplay *display;
301   Window xwindow, xconfine_to;
302   int status;
303
304   display = gdk_device_get_display (device);
305
306   xwindow = GDK_WINDOW_XID (window);
307
308   if (confine_to)
309     confine_to = _gdk_window_get_impl_window (confine_to);
310
311   if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
312     xconfine_to = None;
313   else
314     xconfine_to = GDK_WINDOW_XID (confine_to);
315
316   if (device->source == GDK_SOURCE_KEYBOARD)
317     {
318       /* Device is a keyboard */
319       status = XGrabKeyboard (GDK_DISPLAY_XDISPLAY (display),
320                               xwindow,
321                               owner_events,
322                               GrabModeAsync, GrabModeAsync,
323                               time_);
324     }
325   else
326     {
327       Cursor xcursor;
328       guint xevent_mask;
329       gint i;
330
331       /* Device is a pointer */
332       if (!cursor)
333         xcursor = None;
334       else
335         {
336           _gdk_x11_cursor_update_theme (cursor);
337           xcursor = ((GdkCursorPrivate *) cursor)->xcursor;
338         }
339
340       xevent_mask = 0;
341
342       for (i = 0; i < _gdk_nenvent_masks; i++)
343         {
344           if (event_mask & (1 << (i + 1)))
345             xevent_mask |= _gdk_event_mask_table[i];
346         }
347
348       /* We don't want to set a native motion hint mask, as we're emulating motion
349        * hints. If we set a native one we just wouldn't get any events.
350        */
351       xevent_mask &= ~PointerMotionHintMask;
352
353       status = XGrabPointer (GDK_DISPLAY_XDISPLAY (display),
354                              xwindow,
355                              owner_events,
356                              xevent_mask,
357                              GrabModeAsync, GrabModeAsync,
358                              xconfine_to,
359                              xcursor,
360                              time_);
361     }
362
363   return _gdk_x11_convert_grab_status (status);
364 }
365
366 static void
367 gdk_device_core_ungrab (GdkDevice *device,
368                         guint32    time_)
369 {
370   GdkDisplay *display;
371
372   display = gdk_device_get_display (device);
373
374   if (device->source == GDK_SOURCE_KEYBOARD)
375     XUngrabKeyboard (GDK_DISPLAY_XDISPLAY (display), time_);
376   else
377     XUngrabPointer (GDK_DISPLAY_XDISPLAY (display), time_);
378 }
379
380 static GdkWindow *
381 gdk_device_core_window_at_position (GdkDevice       *device,
382                                     gint            *win_x,
383                                     gint            *win_y,
384                                     GdkModifierType *mask,
385                                     gboolean         get_toplevel)
386 {
387   GdkDisplay *display;
388   GdkScreen *screen;
389   Display *xdisplay;
390   GdkWindow *window;
391   Window xwindow, root, child, last;
392   int xroot_x, xroot_y, xwin_x, xwin_y;
393   unsigned int xmask;
394
395   last = None;
396   display = gdk_device_get_display (device);
397   screen = gdk_display_get_default_screen (display);
398
399   /* This function really only works if the mouse pointer is held still
400    * during its operation. If it moves from one leaf window to another
401    * than we'll end up with inaccurate values for win_x, win_y
402    * and the result.
403    */
404   gdk_x11_display_grab (display);
405
406   xdisplay = GDK_SCREEN_XDISPLAY (screen);
407   xwindow = GDK_SCREEN_XROOTWIN (screen);
408
409   XQueryPointer (xdisplay, xwindow,
410                  &root, &child,
411                  &xroot_x, &xroot_y,
412                  &xwin_x, &xwin_y,
413                  &xmask);
414
415   if (root == xwindow)
416     xwindow = child;
417   else
418     xwindow = root;
419
420   while (xwindow)
421     {
422       last = xwindow;
423       XQueryPointer (xdisplay, xwindow,
424                      &root, &xwindow,
425                      &xroot_x, &xroot_y,
426                      &xwin_x, &xwin_y,
427                      &xmask);
428
429       if (get_toplevel && last != root &&
430           (window = gdk_window_lookup_for_display (display, last)) != NULL &&
431           GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
432         {
433           xwindow = last;
434           break;
435         }
436     }
437
438   gdk_x11_display_ungrab (display);
439
440   window = gdk_window_lookup_for_display (display, last);
441
442   if (win_x)
443     *win_x = (window) ? xwin_x : -1;
444
445   if (win_y)
446     *win_y = (window) ? xwin_y : -1;
447
448   if (mask)
449     *mask = xmask;
450
451   return window;
452 }
453
454 static void
455 gdk_device_core_select_window_events (GdkDevice    *device,
456                                       GdkWindow    *window,
457                                       GdkEventMask  event_mask)
458 {
459   GdkEventMask filter_mask, window_mask;
460   guint xmask = 0;
461   gint i;
462
463   window_mask = gdk_window_get_events (window);
464   filter_mask = (GDK_POINTER_MOTION_MASK &
465                  GDK_POINTER_MOTION_HINT_MASK &
466                  GDK_BUTTON_MOTION_MASK &
467                  GDK_BUTTON1_MOTION_MASK &
468                  GDK_BUTTON2_MOTION_MASK &
469                  GDK_BUTTON3_MOTION_MASK &
470                  GDK_BUTTON_PRESS_MASK &
471                  GDK_BUTTON_RELEASE_MASK &
472                  GDK_KEY_PRESS_MASK &
473                  GDK_KEY_RELEASE_MASK &
474                  GDK_ENTER_NOTIFY_MASK &
475                  GDK_LEAVE_NOTIFY_MASK &
476                  GDK_FOCUS_CHANGE_MASK &
477                  GDK_PROXIMITY_IN_MASK &
478                  GDK_PROXIMITY_OUT_MASK &
479                  GDK_SCROLL_MASK);
480
481   /* Filter out non-device events */
482   event_mask &= filter_mask;
483
484   /* Unset device events on window mask */
485   window_mask &= ~(filter_mask);
486
487   /* Combine masks */
488   event_mask |= window_mask;
489
490   for (i = 0; i < _gdk_nenvent_masks; i++)
491     {
492       if (event_mask & (1 << (i + 1)))
493         xmask |= _gdk_event_mask_table[i];
494     }
495
496   if (GDK_WINDOW_XID (window) != GDK_WINDOW_XROOTWIN (window))
497     xmask |= StructureNotifyMask | PropertyChangeMask;
498
499   XSelectInput (GDK_WINDOW_XDISPLAY (window),
500                 GDK_WINDOW_XWINDOW (window),
501                 xmask);
502 }