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