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