]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkinput-xfree.c
10fd33d919d8aa15e533b490c6a37cc935cac7ca
[~andy/gtk] / gdk / x11 / gdkinput-xfree.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 #include "gdkinputprivate.h"
22 #include "gdkdisplay-x11.h"
23 #include "gdkalias.h"
24
25 /*
26  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
27  * file for a list of people on the GTK+ Team.  See the ChangeLog
28  * files for a list of changes.  These files are distributed with
29  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30  */
31
32 /* forward declarations */
33
34 static void gdk_input_check_proximity (GdkDisplay *display);
35
36 void
37 _gdk_input_init(GdkDisplay *display)
38 {
39   _gdk_init_input_core (display);
40   display->ignore_core_events = FALSE;
41   _gdk_input_common_init (display, FALSE);
42 }
43
44 gboolean
45 gdk_device_set_mode (GdkDevice      *device,
46                      GdkInputMode    mode)
47 {
48   GList *tmp_list;
49   GdkDevicePrivate *gdkdev;
50   GdkInputWindow *input_window;
51   GdkDisplayX11 *display_impl;
52
53   if (GDK_IS_CORE (device))
54     return FALSE;
55
56   gdkdev = (GdkDevicePrivate *)device;
57
58   if (device->mode == mode)
59     return TRUE;
60
61   device->mode = mode;
62
63   if (mode == GDK_MODE_WINDOW)
64     device->has_cursor = FALSE;
65   else if (mode == GDK_MODE_SCREEN)
66     device->has_cursor = TRUE;
67
68   display_impl = GDK_DISPLAY_X11 (gdkdev->display);
69   for (tmp_list = display_impl->input_windows; tmp_list; tmp_list = tmp_list->next)
70     {
71       input_window = (GdkInputWindow *)tmp_list->data;
72       _gdk_input_select_events (input_window->impl_window, gdkdev);
73     }
74
75   return TRUE;
76 }
77
78 static void
79 gdk_input_check_proximity (GdkDisplay *display)
80 {
81   GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
82   GList *tmp_list = display_impl->input_devices;
83   gint new_proximity = 0;
84
85   while (tmp_list && !new_proximity)
86     {
87       GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
88
89       if (gdkdev->info.mode != GDK_MODE_DISABLED
90           && !GDK_IS_CORE (gdkdev)
91           && gdkdev->xdevice)
92         {
93           XDeviceState *state = XQueryDeviceState(display_impl->xdisplay,
94                                                   gdkdev->xdevice);
95           XInputClass *xic;
96           int i;
97
98           xic = state->data;
99           for (i=0; i<state->num_classes; i++)
100             {
101               if (xic->class == ValuatorClass)
102                 {
103                   XValuatorState *xvs = (XValuatorState *)xic;
104                   if ((xvs->mode & ProximityState) == InProximity)
105                     {
106                       new_proximity = TRUE;
107                     }
108                   break;
109                 }
110               xic = (XInputClass *)((char *)xic + xic->length);
111             }
112
113           XFreeDeviceState (state);
114         }
115       tmp_list = tmp_list->next;
116     }
117
118   display->ignore_core_events = new_proximity;
119 }
120
121 void
122 _gdk_input_configure_event (XConfigureEvent *xevent,
123                             GdkWindow       *window)
124 {
125   GdkWindowObject *priv = (GdkWindowObject *)window;
126   GdkInputWindow *input_window;
127   gint root_x, root_y;
128
129   input_window = priv->input_window;
130   if (input_window != NULL)
131     {
132       _gdk_input_get_root_relative_geometry (window, &root_x, &root_y);
133       input_window->root_x = root_x;
134       input_window->root_y = root_y;
135     }
136 }
137
138 void
139 _gdk_input_crossing_event (GdkWindow *window,
140                            gboolean enter)
141 {
142   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
143   GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
144   GdkWindowObject *priv = (GdkWindowObject *)window;
145   GdkInputWindow *input_window;
146   gint root_x, root_y;
147
148   if (enter)
149     {
150       gdk_input_check_proximity(display);
151
152       input_window = priv->input_window;
153       if (input_window != NULL)
154         {
155           _gdk_input_get_root_relative_geometry (window, &root_x, &root_y);
156           input_window->root_x = root_x;
157           input_window->root_y = root_y;
158         }
159     }
160   else
161     display->ignore_core_events = FALSE;
162 }
163
164 static GdkEventType
165 get_input_event_type (GdkDevicePrivate *gdkdev,
166                       XEvent *xevent,
167                       int *core_x, int *core_y)
168 {
169   if (xevent->type == gdkdev->buttonpress_type)
170     {
171       XDeviceButtonEvent *xie = (XDeviceButtonEvent *)(xevent);
172       *core_x = xie->x;
173       *core_y = xie->y;
174       return GDK_BUTTON_PRESS;
175     }
176
177   if (xevent->type == gdkdev->buttonrelease_type)
178     {
179       XDeviceButtonEvent *xie = (XDeviceButtonEvent *)(xevent);
180       *core_x = xie->x;
181       *core_y = xie->y;
182       return GDK_BUTTON_RELEASE;
183     }
184
185   if (xevent->type == gdkdev->keypress_type)
186     {
187       XDeviceKeyEvent *xie = (XDeviceKeyEvent *)(xevent);
188       *core_x = xie->x;
189       *core_y = xie->y;
190       return GDK_KEY_PRESS;
191     }
192
193   if (xevent->type == gdkdev->keyrelease_type)
194     {
195       XDeviceKeyEvent *xie = (XDeviceKeyEvent *)(xevent);
196       *core_x = xie->x;
197       *core_y = xie->y;
198       return GDK_KEY_RELEASE;
199     }
200
201   if (xevent->type == gdkdev->motionnotify_type)
202     {
203       XDeviceMotionEvent *xie = (XDeviceMotionEvent *)(xevent);
204       *core_x = xie->x;
205       *core_y = xie->y;
206       return GDK_MOTION_NOTIFY;
207     }
208
209   if (xevent->type == gdkdev->proximityin_type)
210     {
211       XProximityNotifyEvent *xie = (XProximityNotifyEvent *)(xevent);
212       *core_x = xie->x;
213       *core_y = xie->y;
214       return GDK_PROXIMITY_IN;
215     }
216
217   if (xevent->type == gdkdev->proximityout_type)
218     {
219       XProximityNotifyEvent *xie = (XProximityNotifyEvent *)(xevent);
220       *core_x = xie->x;
221       *core_y = xie->y;
222       return GDK_PROXIMITY_OUT;
223     }
224
225   *core_x = 0;
226   *core_y = 0;
227   return GDK_NOTHING;
228 }
229
230
231 gboolean
232 _gdk_input_other_event (GdkEvent *event,
233                         XEvent *xevent,
234                         GdkWindow *event_window)
235 {
236   GdkWindow *window;
237   GdkWindowObject *priv;
238   GdkInputWindow *iw;
239   GdkDevicePrivate *gdkdev;
240   gint return_val;
241   GdkEventType event_type;
242   int x, y;
243   GdkDisplay *display = GDK_WINDOW_DISPLAY (event_window);
244   GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
245
246   /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
247      but it's potentially faster than scanning through the types of
248      every device. If we were deceived, then it won't match any of
249      the types for the device anyways */
250   gdkdev = _gdk_input_find_device (display,
251                                    ((XDeviceButtonEvent *)xevent)->deviceid);
252   if (!gdkdev)
253     return FALSE;                       /* we don't handle it - not an XInput event */
254
255   event_type = get_input_event_type (gdkdev, xevent, &x, &y);
256   if (event_type == GDK_NOTHING)
257     return FALSE;
258
259   window = _gdk_window_get_input_window_for_event (event_window,
260                                                    event_type,
261                                                    x, y,
262                                                    xevent->xany.serial);
263   /* If we're not getting any event window its likely because we're outside the
264      window and there is no grab. We should still report according to the
265      implicit grab though. */
266   iw = ((GdkWindowObject *)event_window)->input_window;
267   if (window == NULL)
268     window = iw->button_down_window;
269
270   priv = (GdkWindowObject *)window;
271   if (window == NULL)
272     return FALSE;
273
274   if (gdkdev->info.mode == GDK_MODE_DISABLED ||
275       !(gdkdev->info.has_cursor || (priv->extension_events & GDK_ALL_DEVICES_MASK)))
276     return FALSE;
277
278   if (!display->ignore_core_events && priv->extension_events != 0)
279     gdk_input_check_proximity (GDK_WINDOW_DISPLAY (window));
280
281   return_val = _gdk_input_common_other_event (event, xevent, window, gdkdev);
282
283   if (return_val && event->type == GDK_BUTTON_PRESS)
284     iw->button_down_window = window;
285   if (return_val && event->type == GDK_BUTTON_RELEASE)
286     iw->button_down_window = NULL;
287
288   if (return_val && event->type == GDK_PROXIMITY_OUT &&
289       display->ignore_core_events)
290     gdk_input_check_proximity (GDK_WINDOW_DISPLAY (window));
291
292   return return_val;
293 }
294
295 gint
296 _gdk_input_grab_pointer (GdkWindow      *window,
297                          GdkWindow      *native_window, /* This is the toplevel */
298                          gint            owner_events,
299                          GdkEventMask    event_mask,
300                          GdkWindow *     confine_to,
301                          guint32         time)
302 {
303   GdkInputWindow *input_window;
304   GdkWindowObject *priv, *impl_window;
305   gboolean need_ungrab;
306   GdkDevicePrivate *gdkdev;
307   GList *tmp_list;
308   XEventClass event_classes[GDK_MAX_DEVICE_CLASSES];
309   gint num_classes;
310   gint result;
311   GdkDisplayX11 *display_impl  = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
312
313   tmp_list = display_impl->input_windows;
314   need_ungrab = FALSE;
315
316   while (tmp_list)
317     {
318       input_window = (GdkInputWindow *)tmp_list->data;
319
320       if (input_window->grabbed)
321         {
322           input_window->grabbed = FALSE;
323           need_ungrab = TRUE;
324           break;
325         }
326       tmp_list = tmp_list->next;
327     }
328
329   priv = (GdkWindowObject *)window;
330   impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
331   input_window = impl_window->input_window;
332   if (priv->extension_events)
333     {
334       g_assert (input_window != NULL);
335       input_window->grabbed = TRUE;
336
337       tmp_list = display_impl->input_devices;
338       while (tmp_list)
339         {
340           gdkdev = (GdkDevicePrivate *)tmp_list->data;
341           if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
342             {
343               _gdk_input_common_find_events (gdkdev, event_mask,
344                                              event_classes, &num_classes);
345 #ifdef G_ENABLE_DEBUG
346               if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
347                 result = GrabSuccess;
348               else
349 #endif
350                 result = XGrabDevice (display_impl->xdisplay, gdkdev->xdevice,
351                                       GDK_WINDOW_XWINDOW (native_window),
352                                       owner_events, num_classes, event_classes,
353                                       GrabModeAsync, GrabModeAsync, time);
354
355               /* FIXME: if failure occurs on something other than the first
356                  device, things will be badly inconsistent */
357               if (result != Success)
358                 return result;
359             }
360           tmp_list = tmp_list->next;
361         }
362     }
363   else
364     {
365       tmp_list = display_impl->input_devices;
366       while (tmp_list)
367         {
368           gdkdev = (GdkDevicePrivate *)tmp_list->data;
369           if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice &&
370               ((gdkdev->button_state != 0) || need_ungrab))
371             {
372               XUngrabDevice (display_impl->xdisplay, gdkdev->xdevice, time);
373               gdkdev->button_state = 0;
374             }
375
376           tmp_list = tmp_list->next;
377         }
378     }
379
380   return Success;
381 }
382
383 void
384 _gdk_input_ungrab_pointer (GdkDisplay *display,
385                            guint32 time)
386 {
387   GdkInputWindow *input_window = NULL; /* Quiet GCC */
388   GdkDevicePrivate *gdkdev;
389   GList *tmp_list;
390   GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
391
392   tmp_list = display_impl->input_windows;
393   while (tmp_list)
394     {
395       input_window = (GdkInputWindow *)tmp_list->data;
396       if (input_window->grabbed)
397         break;
398       tmp_list = tmp_list->next;
399     }
400
401   if (tmp_list)                 /* we found a grabbed window */
402     {
403       input_window->grabbed = FALSE;
404
405       tmp_list = display_impl->input_devices;
406       while (tmp_list)
407         {
408           gdkdev = (GdkDevicePrivate *)tmp_list->data;
409           if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
410             XUngrabDevice( display_impl->xdisplay, gdkdev->xdevice, time);
411
412           tmp_list = tmp_list->next;
413         }
414     }
415 }
416
417 #define __GDK_INPUT_XFREE_C__
418 #include "gdkaliasdef.c"