]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkinput-xfree.c
Initial revision
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #ifdef XINPUT_XFREE
20
21 /* forward declarations */
22
23 static gint gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode);
24 static void gdk_input_check_proximity();
25 static void gdk_input_xfree_configure_event (XConfigureEvent *xevent, 
26                                              GdkWindow *window);
27 static void gdk_input_xfree_enter_event (XCrossingEvent *xevent, 
28                                        GdkWindow *window);
29 static gint gdk_input_xfree_other_event (GdkEvent *event, 
30                                          XEvent *xevent, 
31                                          GdkWindow *window);
32 static gint gdk_input_xfree_enable_window(GdkWindow *window, 
33                                           GdkDevicePrivate *gdkdev);
34 static gint gdk_input_xfree_disable_window(GdkWindow *window,
35                                            GdkDevicePrivate *gdkdev);
36 static gint gdk_input_xfree_grab_pointer (GdkWindow *     window,
37                                         gint            owner_events,
38                                         GdkEventMask    event_mask,
39                                         GdkWindow *     confine_to,
40                                         guint32         time);
41 static void gdk_input_xfree_ungrab_pointer (guint32 time);
42
43 void 
44 gdk_input_init(void)
45 {
46   gdk_input_vtable.set_mode           = gdk_input_xfree_set_mode;
47   gdk_input_vtable.set_axes        = gdk_input_common_set_axes;
48   gdk_input_vtable.motion_events      = gdk_input_common_motion_events;
49   gdk_input_vtable.get_pointer        = gdk_input_common_get_pointer;
50   gdk_input_vtable.grab_pointer       = gdk_input_xfree_grab_pointer;
51   gdk_input_vtable.ungrab_pointer     = gdk_input_xfree_ungrab_pointer;
52   gdk_input_vtable.configure_event    = gdk_input_xfree_configure_event;
53   gdk_input_vtable.enter_event        = gdk_input_xfree_enter_event;
54   gdk_input_vtable.other_event        = gdk_input_xfree_other_event;
55   gdk_input_vtable.window_none_event  = NULL;
56   gdk_input_vtable.enable_window      = gdk_input_xfree_enable_window;
57   gdk_input_vtable.disable_window     = gdk_input_xfree_disable_window;
58
59   gdk_input_ignore_core = FALSE;
60   gdk_input_common_init(FALSE);
61 }
62
63 static gint
64 gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode)
65 {
66   GList *tmp_list;
67   GdkDevicePrivate *gdkdev;
68   GdkInputMode old_mode;
69   GdkInputWindow *input_window;
70
71   gdkdev = gdk_input_find_device(deviceid);
72   g_return_val_if_fail (gdkdev != NULL,FALSE);
73   old_mode = gdkdev->info.mode;
74
75   if (gdkdev->info.mode == mode)
76     return TRUE;
77
78   gdkdev->info.mode = mode;
79
80   if (mode == GDK_MODE_WINDOW)
81     {
82       gdkdev->info.has_cursor = FALSE;
83       for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
84         {
85           input_window = (GdkInputWindow *)tmp_list->data;
86           if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
87             gdk_input_enable_window (input_window->window, gdkdev);
88           else
89             if (old_mode != GDK_MODE_DISABLED)
90               gdk_input_disable_window (input_window->window, gdkdev);
91         }
92     }
93   else if (mode == GDK_MODE_SCREEN)
94     {
95       gdkdev->info.has_cursor = TRUE;
96       for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
97         gdk_input_enable_window (((GdkInputWindow *)tmp_list->data)->window,
98                                  gdkdev);
99     }
100   else  /* mode == GDK_MODE_DISABLED */
101     {
102       for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
103         {
104           input_window = (GdkInputWindow *)tmp_list->data;
105           if (old_mode != GDK_MODE_WINDOW ||
106               input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
107             gdk_input_disable_window (input_window->window, gdkdev);
108         }
109     }
110
111   return TRUE;
112   
113 }
114
115 static void
116 gdk_input_check_proximity()
117 {
118   gint new_proximity = 0;
119   GList *tmp_list = gdk_input_devices;
120
121   while (tmp_list && !new_proximity) 
122     {
123       GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
124
125       if (gdkdev->info.mode != GDK_MODE_DISABLED 
126           && gdkdev->info.deviceid != GDK_CORE_POINTER
127           && gdkdev->xdevice)
128         {
129           XDeviceState *state = XQueryDeviceState(GDK_DISPLAY(),
130                                                   gdkdev->xdevice);
131           XInputClass *xic;
132           int i;
133           
134           xic = state->data;
135           for (i=0; i<state->num_classes; i++)
136             {
137               if (xic->class == ValuatorClass)
138                 {
139                   XValuatorState *xvs = (XValuatorState *)xic;
140                   if ((xvs->mode & ProximityState) == InProximity)
141                     {
142                       new_proximity = TRUE;
143                     }
144                   break;
145                 }
146               xic = (XInputClass *)((char *)xic + xic->length);
147             }
148         }
149       tmp_list = tmp_list->next;
150     }
151
152   gdk_input_ignore_core = new_proximity;
153 }
154
155 static void
156 gdk_input_xfree_configure_event (XConfigureEvent *xevent, GdkWindow *window)
157 {
158   GdkInputWindow *input_window;
159   gint root_x, root_y;
160
161   input_window = gdk_input_window_find(window);
162   g_return_if_fail (window != NULL);
163
164   gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window),
165                                  &root_x, 
166                                  &root_y, NULL, NULL);
167
168   input_window->root_x = root_x;
169   input_window->root_y = root_y;
170 }
171
172 static void 
173 gdk_input_xfree_enter_event (XCrossingEvent *xevent, 
174                                        GdkWindow *window)
175 {
176   GdkInputWindow *input_window;
177   gint root_x, root_y;
178
179   input_window = gdk_input_window_find(window);
180   g_return_if_fail (window != NULL);
181
182   gdk_input_check_proximity();
183
184   gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window),
185                                  &root_x, 
186                                  &root_y, NULL, NULL);
187
188   input_window->root_x = root_x;
189   input_window->root_y = root_y;
190 }
191
192 static gint 
193 gdk_input_xfree_other_event (GdkEvent *event, 
194                              XEvent *xevent, 
195                              GdkWindow *window)
196 {
197   GdkInputWindow *input_window;
198
199   GdkDevicePrivate *gdkdev;
200   gint return_val;
201
202   input_window = gdk_input_window_find(window);
203   g_return_val_if_fail (window != NULL, -1);
204
205   /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
206      but it's potentially faster than scanning through the types of
207      every device. If we were deceived, then it won't match any of
208      the types for the device anyways */
209   gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
210
211   if (!gdkdev) {
212     return -1;                  /* we don't handle it - not an XInput event */
213   }
214
215   /* FIXME: It would be nice if we could just get rid of the events 
216      entirely, instead of having to ignore them */
217   if (gdkdev->info.mode == GDK_MODE_DISABLED ||
218       (gdkdev->info.mode == GDK_MODE_WINDOW 
219        && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR))
220     return FALSE;
221   
222   if (!gdk_input_ignore_core)
223     gdk_input_check_proximity();
224
225   return_val = gdk_input_common_other_event (event, xevent, 
226                                              input_window, gdkdev);
227
228   if (return_val > 0 && event->type == GDK_PROXIMITY_OUT &&
229       gdk_input_ignore_core)
230     gdk_input_check_proximity();
231
232   /* Do a passive button grab. We have to be careful not to release
233      an explicit grab, if any. Doubling the grab should be harmless,
234      but we check anyways. */
235
236   /* FIXME, finding the proper events here is going to be SLOW - but
237      we might have different sets for each window/device combination */
238   
239   if (return_val> 0 && !input_window->grabbed)
240     {
241       if (event->type == GDK_BUTTON_PRESS)
242         {
243           XEventClass event_classes[6];
244           gint num_classes;
245           
246           gdk_input_common_find_events (window, gdkdev, 
247                                         ((GdkWindowPrivate *)window)->extension_events, 
248                                         event_classes, &num_classes);
249           
250         XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice,
251                      GDK_WINDOW_XWINDOW (window),
252                      TRUE, num_classes, event_classes,
253                      GrabModeAsync, GrabModeAsync, event->button.time);
254         }
255       else if (event->type == GDK_BUTTON_RELEASE)
256         XUngrabDevice( GDK_DISPLAY(), gdkdev->xdevice, event->button.time);
257     }
258
259   return return_val;
260 }
261
262 static gint
263 gdk_input_xfree_enable_window(GdkWindow *window, GdkDevicePrivate *gdkdev)
264 {
265   /* FIXME: watchout, gdkdev might be core pointer, never opened */
266   gdk_input_common_select_events (window, gdkdev);
267   return TRUE;
268 }
269
270 static gint
271 gdk_input_xfree_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev)
272 {
273   gdk_input_common_select_events (window, gdkdev);
274   return TRUE;
275 }
276
277 static gint 
278 gdk_input_xfree_grab_pointer (GdkWindow *     window,
279                               gint            owner_events,
280                               GdkEventMask    event_mask,
281                               GdkWindow *     confine_to,
282                               guint32         time)
283 {
284   GdkInputWindow *input_window, *new_window;
285   GdkDevicePrivate *gdkdev;
286   GList *tmp_list;
287   XEventClass event_classes[6];
288   gint num_classes;
289
290   tmp_list = gdk_input_windows;
291   new_window = NULL;
292   while (tmp_list)
293     {
294       input_window = (GdkInputWindow *)tmp_list->data;
295       if (input_window->grabbed)
296         return AlreadyGrabbed;
297
298       if (input_window->window == window)
299         {
300           new_window = input_window;
301           break;
302         }
303       
304       tmp_list = tmp_list->next;
305     }
306   
307   g_return_if_fail (new_window == NULL);
308   
309   new_window->grabbed = TRUE;
310
311   tmp_list = gdk_input_devices;
312   while (tmp_list)
313     {
314       gdkdev = (GdkDevicePrivate *)tmp_list->data;
315       if (gdkdev->info.deviceid != GDK_CORE_POINTER &&
316           gdkdev->xdevice && !gdkdev->button_state)
317         {
318           gdk_input_common_find_events (window, gdkdev, 
319                                         ((GdkWindowPrivate *)window)->extension_events, 
320                                         event_classes, &num_classes);
321
322           /* FIXME: we should do something on failure */
323           XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice,
324                        GDK_WINDOW_XWINDOW (window),
325                        TRUE, num_classes, event_classes,
326                        GrabModeAsync, GrabModeAsync, time);
327         }
328       tmp_list = tmp_list->next;
329     }
330   
331   return Success;
332 }
333
334 static void 
335 gdk_input_xfree_ungrab_pointer (guint32 time)
336 {
337   GdkInputWindow *input_window;
338   GdkDevicePrivate *gdkdev;
339   GList *tmp_list;
340
341   tmp_list = gdk_input_windows;
342   while (tmp_list)
343     {
344       input_window = (GdkInputWindow *)tmp_list->data;
345       if (input_window->grabbed)
346         break;
347       tmp_list = tmp_list->next;
348     }
349
350   if (tmp_list)                 /* we found a grabbed window */
351     {
352       input_window->grabbed = FALSE;
353
354       tmp_list = gdk_input_devices;
355       while (tmp_list)
356         {
357           gdkdev = (GdkDevicePrivate *)tmp_list->data;
358           if (gdkdev->info.deviceid != GDK_CORE_POINTER &&
359               gdkdev->xdevice && !gdkdev->button_state)
360             {
361               XUngrabDevice( gdk_display, gdkdev->xdevice, time);
362             }
363           tmp_list = tmp_list->next;
364         }
365     }
366 }
367
368 #endif /* XINPUT_XFREE */