]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkinput.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~andy/gtk] / gdk / win32 / gdkinput.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 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 /* This file should really be one level up, in the backend-independent
28  * GDK, and the x11/gdkinput.c could also be removed.
29  * 
30  * That stuff in x11/gdkinput.c which really *is* X11-dependent should
31  * be in x11/gdkinput-x11.c.
32  */
33
34 #include <config.h>
35
36 #include "gdkdisplay.h"
37 #include "gdkinput.h"
38 #include "gdkprivate.h"
39
40 /* When ther necessary stuff is in
41  * gdkinput.h, gdkinternals.h and
42  * gdkprivate.h, these includes shouldn't be here.
43  */
44
45 #include <windows.h>
46 #ifdef HAVE_WINTAB
47 #include <wintab.h>
48 #endif
49
50 #include "gdkinput-win32.h"
51
52 static GdkDeviceAxis gdk_input_core_axes[] = {
53   { GDK_AXIS_X, 0, 0 },
54   { GDK_AXIS_Y, 0, 0 }
55 };
56
57 /* Global variables  */
58
59 gint              _gdk_input_ignore_core;
60
61 GList            *_gdk_input_devices;
62 GList            *_gdk_input_windows;
63
64 void
65 _gdk_init_input_core (GdkDisplay *display)
66 {
67   display->core_pointer = g_object_new (GDK_TYPE_DEVICE, NULL);
68   
69   display->core_pointer->name = "Core Pointer";
70   display->core_pointer->source = GDK_SOURCE_MOUSE;
71   display->core_pointer->mode = GDK_MODE_SCREEN;
72   display->core_pointer->has_cursor = TRUE;
73   display->core_pointer->num_axes = 2;
74   display->core_pointer->axes = gdk_input_core_axes;
75   display->core_pointer->num_keys = 0;
76   display->core_pointer->keys = NULL;
77 }
78
79 static void
80 gdk_device_finalize (GObject *object)
81 {
82   g_error ("A GdkDevice object was finalized. This should not happen");
83 }
84
85 static void
86 gdk_device_class_init (GObjectClass *class)
87 {
88   class->finalize = gdk_device_finalize;
89 }
90
91 GType
92 gdk_device_get_type (void)
93 {
94   static GType object_type = 0;
95
96   if (!object_type)
97     {
98       static const GTypeInfo object_info =
99       {
100         sizeof (GdkDeviceClass),
101         (GBaseInitFunc) NULL,
102         (GBaseFinalizeFunc) NULL,
103         (GClassInitFunc) gdk_device_class_init,
104         NULL,           /* class_finalize */
105         NULL,           /* class_data */
106         sizeof (GdkDevicePrivate),
107         0,              /* n_preallocs */
108         (GInstanceInitFunc) NULL,
109       };
110       
111       object_type = g_type_register_static (G_TYPE_OBJECT,
112                                             "GdkDevice",
113                                             &object_info, 0);
114     }
115   
116   return object_type;
117 }
118
119 GList *
120 gdk_devices_list (void)
121 {
122   return _gdk_input_devices;
123 }
124
125 GList *
126 gdk_display_list_devices (GdkDisplay *dpy)
127 {
128   return _gdk_input_devices;
129 }
130
131 void
132 gdk_device_set_source (GdkDevice      *device,
133                        GdkInputSource  source)
134 {
135   g_return_if_fail (device != NULL);
136
137   device->source = source;
138 }
139
140 void
141 gdk_device_set_key (GdkDevice      *device,
142                     guint           index,
143                     guint           keyval,
144                     GdkModifierType modifiers)
145 {
146   g_return_if_fail (device != NULL);
147   g_return_if_fail (index < device->num_keys);
148
149   device->keys[index].keyval = keyval;
150   device->keys[index].modifiers = modifiers;
151 }
152
153 void
154 gdk_device_set_axis_use (GdkDevice   *device,
155                          guint        index,
156                          GdkAxisUse   use)
157 {
158   g_return_if_fail (device != NULL);
159   g_return_if_fail (index < device->num_axes);
160
161   device->axes[index].use = use;
162
163   switch (use)
164     {
165     case GDK_AXIS_X:
166     case GDK_AXIS_Y:
167       device->axes[index].min = 0.;
168       device->axes[index].max = 0.;
169       break;
170     case GDK_AXIS_XTILT:
171     case GDK_AXIS_YTILT:
172       device->axes[index].min = -1.;
173       device->axes[index].max = 1;
174       break;
175     default:
176       device->axes[index].min = 0.;
177       device->axes[index].max = 1;
178       break;
179     }
180 }
181
182 gboolean
183 gdk_device_get_history  (GdkDevice         *device,
184                          GdkWindow         *window,
185                          guint32            start,
186                          guint32            stop,
187                          GdkTimeCoord    ***events,
188                          gint              *n_events)
189 {
190   g_return_val_if_fail (window != NULL, FALSE);
191   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
192   g_return_val_if_fail (events != NULL, FALSE);
193   g_return_val_if_fail (n_events != NULL, FALSE);
194
195   if (n_events)
196     *n_events = 0;
197   if (events)
198     *events = NULL;
199
200   if (GDK_WINDOW_DESTROYED (window))
201     return FALSE;
202     
203   if (GDK_IS_CORE (device))
204     return FALSE;
205   else
206     return _gdk_device_get_history (device, window, start, stop, events, n_events);
207 }
208
209 GdkTimeCoord ** 
210 _gdk_device_allocate_history (GdkDevice *device,
211                               gint       n_events)
212 {
213   GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events);
214   gint i;
215
216   for (i=0; i<n_events; i++)
217     result[i] = g_malloc (sizeof (GdkTimeCoord) -
218                           sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->num_axes));
219
220   return result;
221 }
222
223 void 
224 gdk_device_free_history (GdkTimeCoord **events,
225                          gint           n_events)
226 {
227   gint i;
228   
229   for (i=0; i<n_events; i++)
230     g_free (events[i]);
231
232   g_free (events);
233 }
234
235 GdkInputWindow *
236 _gdk_input_window_find(GdkWindow *window)
237 {
238   GList *tmp_list;
239
240   for (tmp_list=_gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
241     if (((GdkInputWindow *)(tmp_list->data))->window == window)
242       return (GdkInputWindow *)(tmp_list->data);
243
244   return NULL;      /* Not found */
245 }
246
247 /* FIXME: this routine currently needs to be called between creation
248    and the corresponding configure event (because it doesn't get the
249    root_relative_geometry).  This should work with
250    gtk_window_set_extension_events, but will likely fail in other
251    cases */
252
253 void
254 gdk_input_set_extension_events (GdkWindow *window, gint mask,
255                                 GdkExtensionMode mode)
256 {
257   GdkWindowObject *window_private;
258   GList *tmp_list;
259   GdkInputWindow *iw;
260
261   g_return_if_fail (window != NULL);
262   g_return_if_fail (GDK_IS_WINDOW (window));
263
264   window_private = (GdkWindowObject*) window;
265   if (GDK_WINDOW_DESTROYED (window))
266     return;
267
268   if (mode == GDK_EXTENSION_EVENTS_NONE)
269     mask = 0;
270
271   if (mask != 0)
272     {
273       iw = g_new(GdkInputWindow,1);
274
275       iw->window = window;
276       iw->mode = mode;
277
278       iw->obscuring = NULL;
279       iw->num_obscuring = 0;
280       iw->grabbed = FALSE;
281
282       _gdk_input_windows = g_list_append(_gdk_input_windows,iw);
283       window_private->extension_events = mask;
284
285       /* Add enter window events to the event mask */
286       if (g_list_length (_gdk_input_devices) > 1)
287         gdk_window_set_events (window,
288                                gdk_window_get_events (window) | 
289                                GDK_ENTER_NOTIFY_MASK);
290     }
291   else
292     {
293       iw = _gdk_input_window_find (window);
294       if (iw)
295         {
296           _gdk_input_windows = g_list_remove(_gdk_input_windows,iw);
297           g_free(iw);
298         }
299
300       window_private->extension_events = 0;
301     }
302
303   for (tmp_list = _gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
304     {
305       GdkDevicePrivate *gdkdev = tmp_list->data;
306
307       if (!GDK_IS_CORE (gdkdev))
308         {
309           if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED
310               && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL))
311             _gdk_input_enable_window (window,gdkdev);
312           else
313             _gdk_input_disable_window (window,gdkdev);
314         }
315     }
316 }
317
318 void
319 _gdk_input_window_destroy (GdkWindow *window)
320 {
321   GdkInputWindow *input_window;
322
323   input_window = _gdk_input_window_find (window);
324   g_return_if_fail (input_window != NULL);
325
326   _gdk_input_windows = g_list_remove (_gdk_input_windows,input_window);
327   g_free(input_window);
328 }
329
330 void
331 _gdk_input_exit (void)
332 {
333   GList *tmp_list;
334   GdkDevicePrivate *gdkdev;
335
336   for (tmp_list = _gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
337     {
338       gdkdev = (GdkDevicePrivate *)(tmp_list->data);
339       if (!GDK_IS_CORE (gdkdev))
340         {
341           gdk_device_set_mode (&gdkdev->info, GDK_MODE_DISABLED);
342
343           g_free(gdkdev->info.name);
344           g_free(gdkdev->axes);
345           g_free(gdkdev->info.axes);
346           g_free(gdkdev->info.keys);
347           g_free(gdkdev);
348         }
349     }
350
351   g_list_free(_gdk_input_devices);
352
353   for (tmp_list = _gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
354     g_free(tmp_list->data);
355
356   g_list_free(_gdk_input_windows);
357 }
358
359 gboolean
360 gdk_device_get_axis (GdkDevice  *device,
361                      gdouble    *axes,
362                      GdkAxisUse  use,
363                      gdouble    *value)
364 {
365   gint i;
366   
367   g_return_val_if_fail (device != NULL, FALSE);
368
369   if (axes == NULL)
370     return FALSE;
371   
372   for (i=0; i<device->num_axes; i++)
373     if (device->axes[i].use == use)
374       {
375         if (value)
376           *value = axes[i];
377         return TRUE;
378       }
379   
380   return FALSE;
381 }
382
383 gboolean
384 gdk_device_set_mode (GdkDevice   *device,
385                      GdkInputMode mode)
386 {
387   GList *tmp_list;
388   GdkDevicePrivate *gdkdev;
389   GdkInputMode old_mode;
390   GdkInputWindow *input_window;
391
392   if (GDK_IS_CORE (device))
393     return FALSE;
394
395   gdkdev = (GdkDevicePrivate *)device;
396
397   if (device->mode == mode)
398     return TRUE;
399
400   old_mode = device->mode;
401   device->mode = mode;
402
403   if (mode == GDK_MODE_WINDOW)
404     {
405       device->has_cursor = FALSE;
406       for (tmp_list = _gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
407         {
408           input_window = (GdkInputWindow *)tmp_list->data;
409           if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
410             _gdk_input_enable_window (input_window->window, gdkdev);
411           else
412             if (old_mode != GDK_MODE_DISABLED)
413               _gdk_input_disable_window (input_window->window, gdkdev);
414         }
415     }
416   else if (mode == GDK_MODE_SCREEN)
417     {
418       device->has_cursor = TRUE;
419       for (tmp_list = _gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
420         _gdk_input_enable_window (((GdkInputWindow *)tmp_list->data)->window,
421                                   gdkdev);
422     }
423   else  /* mode == GDK_MODE_DISABLED */
424     {
425       for (tmp_list = _gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
426         {
427           input_window = (GdkInputWindow *)tmp_list->data;
428           if (old_mode != GDK_MODE_WINDOW ||
429               input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
430             _gdk_input_disable_window (input_window->window, gdkdev);
431         }
432     }
433
434   return TRUE;
435 }