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 
39 #include "gdkprivate-win32.h"
40 #include "gdkinput-win32.h"
41 
42 static GdkDeviceAxis gdk_input_core_axes[] = {
43   { GDK_AXIS_X, 0, 0 },
44   { GDK_AXIS_Y, 0, 0 }
45 };
46 
47 /* Global variables  */
48 
49 GList            *_gdk_input_devices;
50 GList            *_gdk_input_windows;
51 gboolean          _gdk_input_in_proximity = 0;
52 gboolean          _gdk_input_inside_input_window = 0;
53 
54 void
_gdk_init_input_core(GdkDisplay * display)55 _gdk_init_input_core (GdkDisplay *display)
56 {
57   display->core_pointer = g_object_new (GDK_TYPE_DEVICE, NULL);
58 
59   display->core_pointer->name = "Core Pointer";
60   display->core_pointer->source = GDK_SOURCE_MOUSE;
61   display->core_pointer->mode = GDK_MODE_SCREEN;
62   display->core_pointer->has_cursor = TRUE;
63   display->core_pointer->num_axes = 2;
64   display->core_pointer->axes = gdk_input_core_axes;
65   display->core_pointer->num_keys = 0;
66   display->core_pointer->keys = NULL;
67 }
68 
69 GType
gdk_device_get_type(void)70 gdk_device_get_type (void)
71 {
72   static GType object_type = 0;
73 
74   if (!object_type)
75     {
76       const GTypeInfo object_info =
77 	{
78 	  sizeof (GdkDeviceClass),
79 	  (GBaseInitFunc) NULL,
80 	  (GBaseFinalizeFunc) NULL,
81 	  (GClassInitFunc) NULL,
82 	  NULL,			/* class_finalize */
83 	  NULL,			/* class_data */
84 	  sizeof (GdkDevicePrivate),
85 	  0,			/* n_preallocs */
86 	  (GInstanceInitFunc) NULL,
87 	};
88 
89       object_type = g_type_register_static (G_TYPE_OBJECT,
90                                             g_intern_static_string ("GdkDevice"),
91                                             &object_info, 0);
92     }
93 
94   return object_type;
95 }
96 
97 GList *
gdk_devices_list(void)98 gdk_devices_list (void)
99 {
100   return gdk_display_list_devices (_gdk_display);
101 }
102 
103 GList *
gdk_display_list_devices(GdkDisplay * dpy)104 gdk_display_list_devices (GdkDisplay *dpy)
105 {
106   g_return_val_if_fail (dpy == _gdk_display, NULL);
107 
108   _gdk_input_wintab_init_check ();
109   return _gdk_input_devices;
110 }
111 
112 const gchar *
gdk_device_get_name(GdkDevice * device)113 gdk_device_get_name (GdkDevice *device)
114 {
115   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
116 
117   return device->name;
118 }
119 
120 GdkInputSource
gdk_device_get_source(GdkDevice * device)121 gdk_device_get_source (GdkDevice *device)
122 {
123   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
124 
125   return device->source;
126 }
127 
128 GdkInputMode
gdk_device_get_mode(GdkDevice * device)129 gdk_device_get_mode (GdkDevice *device)
130 {
131   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
132 
133   return device->mode;
134 }
135 
136 gboolean
gdk_device_get_has_cursor(GdkDevice * device)137 gdk_device_get_has_cursor (GdkDevice *device)
138 {
139   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
140 
141   return device->has_cursor;
142 }
143 
144 void
gdk_device_set_source(GdkDevice * device,GdkInputSource source)145 gdk_device_set_source (GdkDevice      *device,
146 		       GdkInputSource  source)
147 {
148   g_return_if_fail (device != NULL);
149 
150   device->source = source;
151 }
152 
153 void
gdk_device_get_key(GdkDevice * device,guint index,guint * keyval,GdkModifierType * modifiers)154 gdk_device_get_key (GdkDevice       *device,
155                     guint            index,
156                     guint           *keyval,
157                     GdkModifierType *modifiers)
158 {
159   g_return_if_fail (GDK_IS_DEVICE (device));
160   g_return_if_fail (index < device->num_keys);
161 
162   if (!device->keys[index].keyval &&
163       !device->keys[index].modifiers)
164     return;
165 
166   if (keyval)
167     *keyval = device->keys[index].keyval;
168 
169   if (modifiers)
170     *modifiers = device->keys[index].modifiers;
171 }
172 
173 void
gdk_device_set_key(GdkDevice * device,guint index,guint keyval,GdkModifierType modifiers)174 gdk_device_set_key (GdkDevice      *device,
175 		    guint           index,
176 		    guint           keyval,
177 		    GdkModifierType modifiers)
178 {
179   g_return_if_fail (device != NULL);
180   g_return_if_fail (index < device->num_keys);
181 
182   device->keys[index].keyval = keyval;
183   device->keys[index].modifiers = modifiers;
184 }
185 
186 GdkAxisUse
gdk_device_get_axis_use(GdkDevice * device,guint index)187 gdk_device_get_axis_use (GdkDevice *device,
188                          guint      index)
189 {
190   g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_AXIS_IGNORE);
191   g_return_val_if_fail (index < device->num_axes, GDK_AXIS_IGNORE);
192 
193   return device->axes[index].use;
194 }
195 
196 gint
gdk_device_get_n_keys(GdkDevice * device)197 gdk_device_get_n_keys (GdkDevice *device)
198 {
199   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
200 
201   return device->num_keys;
202 }
203 
204 gint
gdk_device_get_n_axes(GdkDevice * device)205 gdk_device_get_n_axes (GdkDevice *device)
206 {
207   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
208 
209   return device->num_axes;
210 }
211 
212 void
gdk_device_set_axis_use(GdkDevice * device,guint index,GdkAxisUse use)213 gdk_device_set_axis_use (GdkDevice   *device,
214 			 guint        index,
215 			 GdkAxisUse   use)
216 {
217   g_return_if_fail (device != NULL);
218   g_return_if_fail (index < device->num_axes);
219 
220   device->axes[index].use = use;
221 
222   switch (use)
223     {
224     case GDK_AXIS_X:
225     case GDK_AXIS_Y:
226       device->axes[index].min = 0.;
227       device->axes[index].max = 0.;
228       break;
229     case GDK_AXIS_XTILT:
230     case GDK_AXIS_YTILT:
231       device->axes[index].min = -1.;
232       device->axes[index].max = 1;
233       break;
234     default:
235       device->axes[index].min = 0.;
236       device->axes[index].max = 1;
237       break;
238     }
239 }
240 
241 gboolean
gdk_device_get_history(GdkDevice * device,GdkWindow * window,guint32 start,guint32 stop,GdkTimeCoord *** events,gint * n_events)242 gdk_device_get_history  (GdkDevice         *device,
243 			 GdkWindow         *window,
244 			 guint32            start,
245 			 guint32            stop,
246 			 GdkTimeCoord    ***events,
247 			 gint              *n_events)
248 {
249   g_return_val_if_fail (window != NULL, FALSE);
250   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
251   g_return_val_if_fail (events != NULL, FALSE);
252   g_return_val_if_fail (n_events != NULL, FALSE);
253 
254   if (n_events)
255     *n_events = 0;
256   if (events)
257     *events = NULL;
258 
259   if (GDK_WINDOW_DESTROYED (window))
260     return FALSE;
261 
262   if (GDK_IS_CORE (device))
263     return FALSE;
264   else
265     return _gdk_device_get_history (device, window, start, stop, events, n_events);
266 }
267 
268 GdkTimeCoord **
_gdk_device_allocate_history(GdkDevice * device,gint n_events)269 _gdk_device_allocate_history (GdkDevice *device,
270 			      gint       n_events)
271 {
272   GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events);
273   gint i;
274 
275   for (i=0; i<n_events; i++)
276     result[i] = g_malloc (sizeof (GdkTimeCoord) -
277 			  sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->num_axes));
278 
279   return result;
280 }
281 
282 void
gdk_device_free_history(GdkTimeCoord ** events,gint n_events)283 gdk_device_free_history (GdkTimeCoord **events,
284 			 gint           n_events)
285 {
286   gint i;
287 
288   for (i=0; i<n_events; i++)
289     g_free (events[i]);
290 
291   g_free (events);
292 }
293 
294 /* FIXME: this routine currently needs to be called between creation
295    and the corresponding configure event (because it doesn't get the
296    root_relative_geometry).  This should work with
297    gtk_window_set_extension_events, but will likely fail in other
298    cases */
299 
300 static void
unset_extension_events(GdkWindow * window)301 unset_extension_events (GdkWindow *window)
302 {
303   GdkWindowObject *window_private;
304   GdkWindowObject *impl_window;
305   GdkInputWindow *iw;
306 
307   window_private = (GdkWindowObject*) window;
308   impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
309   iw = impl_window->input_window;
310 
311   if (window_private->extension_events != 0)
312     {
313       g_assert (iw != NULL);
314       g_assert (g_list_find (iw->windows, window) != NULL);
315 
316       iw->windows = g_list_remove (iw->windows, window);
317       if (iw->windows == NULL)
318 	{
319 	  impl_window->input_window = NULL;
320 	  _gdk_input_windows = g_list_remove(_gdk_input_windows,iw);
321 	  g_free (iw);
322 	}
323     }
324 
325   window_private->extension_events = 0;
326 }
327 
328 static void
gdk_input_get_root_relative_geometry(HWND w,int * x_ret,int * y_ret)329 gdk_input_get_root_relative_geometry (HWND w,
330 				      int  *x_ret,
331 				      int  *y_ret)
332 {
333   POINT pt;
334 
335   pt.x = 0;
336   pt.y = 0;
337   ClientToScreen (w, &pt);
338 
339   if (x_ret)
340     *x_ret = pt.x + _gdk_offset_x;
341   if (y_ret)
342     *y_ret = pt.y + _gdk_offset_y;
343 }
344 
345 void
gdk_input_set_extension_events(GdkWindow * window,gint mask,GdkExtensionMode mode)346 gdk_input_set_extension_events (GdkWindow *window, gint mask,
347 				GdkExtensionMode mode)
348 {
349   GdkWindowObject *window_private;
350   GdkWindowObject *impl_window;
351   GdkInputWindow *iw;
352 
353   g_return_if_fail (window != NULL);
354   g_return_if_fail (GDK_IS_WINDOW (window));
355 
356   window_private = (GdkWindowObject*) window;
357   if (GDK_WINDOW_DESTROYED (window))
358     return;
359 
360   impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
361 
362   if (mode == GDK_EXTENSION_EVENTS_ALL && mask != 0)
363     mask |= GDK_ALL_DEVICES_MASK;
364 
365   if (mode == GDK_EXTENSION_EVENTS_NONE)
366     mask = 0;
367 
368   iw = impl_window->input_window;
369 
370   if (mask != 0)
371     {
372       _gdk_input_wintab_init_check ();
373 
374       if (!iw)
375 	{
376 	  iw = g_new0 (GdkInputWindow,1);
377 
378 	  iw->impl_window = (GdkWindow *)impl_window;
379 
380 	  iw->windows = NULL;
381 
382 	  _gdk_input_windows = g_list_append(_gdk_input_windows, iw);
383 
384 	  gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window), &iw->root_x, &iw->root_y);
385 
386 	  impl_window->input_window = iw;
387 	}
388 
389       if (window_private->extension_events == 0)
390 	iw->windows = g_list_append (iw->windows, window);
391       window_private->extension_events = mask;
392     }
393   else
394     {
395       unset_extension_events (window);
396     }
397 
398   _gdk_input_select_events ((GdkWindow *)impl_window);
399 }
400 
401 void
_gdk_input_window_destroy(GdkWindow * window)402 _gdk_input_window_destroy (GdkWindow *window)
403 {
404   unset_extension_events (window);
405 }
406 
407 void
_gdk_input_check_proximity(void)408 _gdk_input_check_proximity (void)
409 {
410   GList *l;
411   gboolean new_proximity = FALSE;
412 
413   if (!_gdk_input_inside_input_window)
414     {
415       _gdk_display->ignore_core_events = FALSE;
416       return;
417     }
418 
419   for (l = _gdk_input_devices; l != NULL; l = l->next)
420     {
421       GdkDevicePrivate *gdkdev = l->data;
422 
423       if (gdkdev->info.mode != GDK_MODE_DISABLED &&
424 	  !GDK_IS_CORE (gdkdev))
425 	{
426 	  if (_gdk_input_in_proximity)
427 	    {
428 	      new_proximity = TRUE;
429 	      break;
430 	    }
431 	}
432     }
433 
434   _gdk_display->ignore_core_events = new_proximity;
435 }
436 
437 void
_gdk_input_crossing_event(GdkWindow * window,gboolean enter)438 _gdk_input_crossing_event (GdkWindow *window,
439 			   gboolean enter)
440 {
441   if (enter)
442     {
443       GdkWindowObject *priv = (GdkWindowObject *)window;
444       GdkInputWindow *input_window;
445       gint root_x, root_y;
446 
447       _gdk_input_inside_input_window = TRUE;
448 
449       input_window = priv->input_window;
450       if (input_window != NULL)
451 	{
452 	  gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window),
453 						&root_x, &root_y);
454 	  input_window->root_x = root_x;
455 	  input_window->root_y = root_y;
456 	}
457     }
458   else
459     {
460       _gdk_input_inside_input_window = FALSE;
461     }
462 
463   _gdk_input_check_proximity ();
464 }
465 
466 gboolean
gdk_device_get_axis(GdkDevice * device,gdouble * axes,GdkAxisUse use,gdouble * value)467 gdk_device_get_axis (GdkDevice  *device,
468 		     gdouble    *axes,
469 		     GdkAxisUse  use,
470 		     gdouble    *value)
471 {
472   gint i;
473 
474   g_return_val_if_fail (device != NULL, FALSE);
475 
476   if (axes == NULL)
477     return FALSE;
478 
479   for (i=0; i<device->num_axes; i++)
480     if (device->axes[i].use == use)
481       {
482 	if (value)
483 	  *value = axes[i];
484 	return TRUE;
485       }
486 
487   return FALSE;
488 }
489 
490 gboolean
gdk_device_set_mode(GdkDevice * device,GdkInputMode mode)491 gdk_device_set_mode (GdkDevice   *device,
492 		     GdkInputMode mode)
493 {
494   GList *tmp_list;
495   GdkDevicePrivate *gdkdev;
496   GdkInputWindow *input_window;
497 
498   if (GDK_IS_CORE (device))
499     return FALSE;
500 
501   gdkdev = (GdkDevicePrivate *)device;
502 
503   if (device->mode == mode)
504     return TRUE;
505 
506   device->mode = mode;
507 
508   if (mode == GDK_MODE_WINDOW)
509     device->has_cursor = FALSE;
510   else if (mode == GDK_MODE_SCREEN)
511     device->has_cursor = TRUE;
512 
513   for (tmp_list = _gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
514     {
515       input_window = (GdkInputWindow *)tmp_list->data;
516       _gdk_input_select_events (input_window->impl_window);
517     }
518 
519   if (!GDK_IS_CORE (gdkdev))
520     _gdk_input_update_for_device_mode (gdkdev);
521 
522   return TRUE;
523 }
524