1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
21 * Modified by the GTK+ Team and others 1997-1999. 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/.
29 #include "gdkinputprivate.h"
32 /* #define DEBUG_SWITCHING */
36 /* Forward declarations */
37 static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev);
38 static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode);
39 static gint gdk_input_is_extension_device (guint32 deviceid);
40 static void gdk_input_gxi_configure_event (XConfigureEvent *xevent,
42 static void gdk_input_gxi_enter_event (XCrossingEvent *xevent,
44 static gint gdk_input_gxi_other_event (GdkEvent *event,
47 static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev);
49 static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent);
50 static gint gdk_input_gxi_enable_window (GdkWindow *window,
51 GdkDevicePrivate *gdkdev);
52 static gint gdk_input_gxi_disable_window (GdkWindow *window,
53 GdkDevicePrivate *gdkdev);
54 static Window gdk_input_find_root_child(Display *dpy, Window w);
55 static void gdk_input_compute_obscuring(GdkInputWindow *input_window);
56 static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x,
58 static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window,
62 gint *nevents_return);
63 static void gdk_input_gxi_get_pointer (GdkWindow *window,
70 GdkModifierType *mask);
71 static gint gdk_input_gxi_grab_pointer (GdkWindow * window,
73 GdkEventMask event_mask,
74 GdkWindow * confine_to,
76 static void gdk_input_gxi_ungrab_pointer (guint32 time);
80 static GdkDevicePrivate *gdk_input_current_device;
81 static GdkDevicePrivate *gdk_input_core_pointer;
88 gdk_input_vtable.set_mode = gdk_input_gxi_set_mode;
89 gdk_input_vtable.set_axes = gdk_input_common_set_axes;
90 gdk_input_vtable.set_key = gdk_input_common_set_key;
91 gdk_input_vtable.motion_events = gdk_input_gxi_motion_events;
92 gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer;
93 gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer;
94 gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer;
95 gdk_input_vtable.configure_event = gdk_input_gxi_configure_event;
96 gdk_input_vtable.enter_event = gdk_input_gxi_enter_event;
97 gdk_input_vtable.other_event = gdk_input_gxi_other_event;
98 gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event;
99 gdk_input_vtable.enable_window = gdk_input_gxi_enable_window;
100 gdk_input_vtable.disable_window = gdk_input_gxi_disable_window;
102 gdk_input_ignore_core = FALSE;
103 gdk_input_core_pointer = NULL;
105 if (!gdk_input_gxid_host)
107 gdk_input_gxid_host = getenv("GXID_HOST");
109 if (!gdk_input_gxid_port)
111 char *t = getenv("GXID_PORT");
113 gdk_input_gxid_port = atoi(t);
116 gdk_input_common_init(TRUE);
118 /* find initial core pointer */
120 for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
122 GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data;
123 if (gdk_input_is_extension_device(gdkdev->info.deviceid))
125 gdk_input_gxi_select_notify (gdkdev);
129 if (gdkdev->info.deviceid != GDK_CORE_POINTER)
130 gdk_input_core_pointer = gdkdev;
136 gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev)
140 ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class);
142 XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1);
145 /* Set the core pointer. Device should already be enabled. */
147 gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev)
151 g_return_val_if_fail(gdkdev->xdevice,FALSE);
153 x_axis = gdkdev->axis_for_use[GDK_AXIS_X];
154 y_axis = gdkdev->axis_for_use[GDK_AXIS_Y];
156 g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE);
158 /* core_pointer might not be up to date so we check with the server
159 before change the pointer */
161 if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) )
164 if (gdkdev != gdk_input_core_pointer)
165 g_warning("core pointer inconsistency");
170 if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis)
177 gdk_input_gxi_update_device (gdk_input_core_pointer);
178 gdk_input_core_pointer = gdkdev;
184 /* FIXME, merge with gdk_input_xfree_set_mode */
187 gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode)
190 GdkDevicePrivate *gdkdev;
191 GdkInputMode old_mode;
192 GdkInputWindow *input_window;
194 gdkdev = gdk_input_find_device(deviceid);
195 g_return_val_if_fail (gdkdev != NULL,FALSE);
196 old_mode = gdkdev->info.mode;
198 if (gdkdev->info.mode == mode)
201 gdkdev->info.mode = mode;
203 if (old_mode != GDK_MODE_DISABLED)
205 for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
207 input_window = (GdkInputWindow *)tmp_list->data;
208 if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
209 gdk_input_disable_window (input_window->window, gdkdev);
213 if (mode != GDK_MODE_DISABLED)
215 for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
217 input_window = (GdkInputWindow *)tmp_list->data;
218 if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
219 if (!gdk_input_enable_window(input_window->window, gdkdev))
221 gdk_input_set_mode(deviceid, old_mode);
232 gdk_input_is_extension_device (guint32 deviceid)
234 XDeviceInfo *devices;
235 int num_devices, loop;
237 if (deviceid == GDK_CORE_POINTER)
240 devices = XListInputDevices(gdk_display, &num_devices);
241 for(loop=0; loop<num_devices; loop++)
243 if ((devices[loop].id == deviceid) && (devices[loop].use == IsXExtensionDevice))
245 XFreeDeviceList(devices);
250 XFreeDeviceList(devices);
255 gdk_input_gxi_configure_event (XConfigureEvent *xevent, GdkWindow *window)
257 GdkInputWindow *input_window;
260 input_window = gdk_input_window_find(window);
261 g_return_if_fail (input_window != NULL);
263 gdk_input_get_root_relative_geometry(gdk_display,GDK_WINDOW_XWINDOW(window),
264 &root_x, &root_y, NULL, NULL);
265 input_window->root_x = root_x;
266 input_window->root_y = root_y;
267 gdk_input_compute_obscuring(input_window);
271 gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window)
273 GdkInputWindow *input_window;
275 input_window = gdk_input_window_find(window);
276 g_return_if_fail (input_window != NULL);
278 gdk_input_compute_obscuring(input_window);
282 gdk_input_gxi_other_event (GdkEvent *event,
286 GdkInputWindow *input_window;
288 GdkDevicePrivate *gdkdev;
291 input_window = gdk_input_window_find(window);
292 g_return_val_if_fail (window != NULL, -1);
294 /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
295 but it's potentially faster than scanning through the types of
296 every device. If we were deceived, then it won't match any of
297 the types for the device anyways */
298 gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
301 return -1; /* we don't handle it - not an XInput event */
304 if (gdkdev->info.mode == GDK_MODE_DISABLED ||
305 input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
308 if (gdkdev != gdk_input_current_device &&
309 xevent->type != gdkdev->changenotify_type)
311 gdk_input_current_device = gdkdev;
314 return_val = gdk_input_common_other_event (event, xevent,
315 input_window, gdkdev);
317 if (return_val > 0 && event->type == GDK_MOTION_NOTIFY &&
318 (!gdkdev->button_state) && (!input_window->grabbed) &&
319 ((event->motion.x < 0) || (event->motion.y < 0) ||
320 (event->motion.x > ((GdkDrawablePrivate *)window)->width) ||
321 (event->motion.y > ((GdkDrawablePrivate *)window)->height) ||
322 gdk_input_is_obscured(input_window,event->motion.x,event->motion.y)))
324 #ifdef DEBUG_SWITCHING
325 g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n",
326 gdkdev->info.deviceid,event->motion.x,event->motion.y);
327 g_print(" window geometry is: %dx%d\n",
328 ((GdkWindowPrivate *)window)->width,
329 ((GdkWindowPrivate *)window)->height);
331 gdk_input_gxi_set_core_pointer(gdkdev);
340 gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev)
344 if (gdk_input_is_extension_device (gdkdev->info.deviceid))
346 if (!gdkdev->xdevice)
348 gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid);
349 gdk_input_gxi_select_notify (gdkdev);
350 gdkdev->needs_update = 1;
352 if (gdkdev->needs_update && gdkdev->xdevice)
354 for (t = gdk_input_windows; t; t = t->next)
355 gdk_input_common_select_events (((GdkInputWindow *)t->data)->window,
357 gdkdev->needs_update = 0;
363 gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent)
365 GdkDevicePrivate *gdkdev =
366 gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
369 return -1; /* we don't handle it - not an XInput event */
372 if (xevent->type == gdkdev->changenotify_type)
374 if (gdk_input_core_pointer != gdkdev)
376 #ifdef DEBUG_SWITCHING
377 g_print("ChangeNotify from %d to %d:\n",
378 gdk_input_core_pointer->info.deviceid,
379 gdkdev->info.deviceid);
381 gdk_input_gxi_update_device (gdk_input_core_pointer);
382 gdk_input_core_pointer = gdkdev;
390 gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
392 GdkInputWindow *input_window;
394 input_window = gdk_input_window_find (window);
395 g_return_val_if_fail (input_window != NULL, FALSE);
397 if (!gdkdev->claimed)
399 if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port,
400 gdkdev->info.deviceid,
401 GDK_WINDOW_XWINDOW(window), FALSE) !=
404 g_warning("Could not get device (is gxid running?)\n");
407 gdkdev->claimed = TRUE;
410 if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
411 gdk_input_common_select_events(window, gdkdev);
413 gdkdev->needs_update = TRUE;
419 gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev)
421 GdkInputWindow *input_window;
423 input_window = gdk_input_window_find (window);
424 g_return_val_if_fail (input_window != NULL, FALSE);
428 gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port,
429 gdkdev->info.deviceid,
430 GDK_WINDOW_XWINDOW(window));
432 gdkdev->claimed = FALSE;
435 if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
436 gdk_input_common_select_events(window, gdkdev);
438 gdkdev->needs_update = TRUE;
444 gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y)
447 for (i=0;i<input_window->num_obscuring;i++)
449 GdkRectangle *rect = &input_window->obscuring[i];
450 if ((x >= rect->x) &&
452 (x < rect->x + rect->width) &&
453 (y < rect->y + rect->height))
459 /* If this routine needs fixing, the corresponding routine
460 in gxid.c will need it too. */
463 gdk_input_find_root_child(Display *dpy, Window w)
473 XQueryTree(dpy,w,&root,&parent,&children,&nchildren);
474 if (children) XFree(children);
476 while (parent != root);
482 gdk_input_compute_obscuring(GdkInputWindow *input_window)
485 int x,y,width,height;
486 int xc,yc,widthc,heightc,border_widthc,depthc;
492 Window w = GDK_WINDOW_XWINDOW(input_window->window);
493 Window root_child = gdk_input_find_root_child(gdk_display,w);
494 gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height);
496 input_window->root_x = x;
497 input_window->root_y = y;
499 XQueryTree(gdk_display,GDK_ROOT_WINDOW(),
500 &root,&parent,&children,&nchildren);
503 if (input_window->obscuring)
504 g_free(input_window->obscuring);
505 input_window->obscuring = 0;
506 input_window->num_obscuring = 0;
508 for (i=0;i<nchildren;i++)
509 if (children[i] == root_child)
519 input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1));
521 for (i=i+1;i<nchildren;i++)
523 int xmin, xmax, ymin, ymax;
524 XGetGeometry(gdk_display,children[i],&root,&xc,&yc,&widthc,&heightc,
525 &border_widthc, &depthc);
526 xmin = xc>x ? xc : x;
527 xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width;
528 ymin = yc>y ? yc : y;
529 ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height;
530 if ((xmin < xmax) && (ymin < ymax))
532 XWindowAttributes attributes;
533 XGetWindowAttributes(gdk_display,children[i],&attributes);
534 if (attributes.map_state == IsViewable)
536 GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring];
538 /* we store the whole window, not just the obscuring part */
541 rect->width = widthc;
542 rect->height = heightc;
543 input_window->num_obscuring++;
553 gdk_input_gxi_get_pointer (GdkWindow *window,
560 GdkModifierType *mask)
562 GdkDevicePrivate *gdkdev;
564 gdkdev = gdk_input_find_device (deviceid);
565 g_return_if_fail (gdkdev != NULL);
567 if (gdkdev == gdk_input_core_pointer)
568 gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y,
569 pressure, xtilt, ytilt, mask);
571 gdk_input_common_get_pointer (window, deviceid, x, y,
572 pressure, xtilt, ytilt, mask);
575 static GdkTimeCoord *
576 gdk_input_gxi_motion_events (GdkWindow *window,
580 gint *nevents_return)
582 GdkDevicePrivate *gdkdev;
584 gdkdev = gdk_input_find_device (deviceid);
585 g_return_val_if_fail (gdkdev != NULL, NULL);
588 if (gdkdev == gdk_input_core_pointer)
589 return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop,
592 return gdk_input_common_motion_events (window, deviceid, start, stop,
598 gdk_input_gxi_grab_pointer (GdkWindow * window,
600 GdkEventMask event_mask,
601 GdkWindow * confine_to,
605 GdkInputWindow *input_window;
606 GdkDevicePrivate *gdkdev;
608 tmp_list = gdk_input_windows;
611 input_window = (GdkInputWindow *)tmp_list->data;
613 if (input_window->window == window)
614 input_window->grabbed = TRUE;
615 else if (input_window->grabbed)
616 input_window->grabbed = FALSE;
618 tmp_list = tmp_list->next;
621 tmp_list = gdk_input_devices;
624 gdkdev = (GdkDevicePrivate *)tmp_list->data;
625 if (gdkdev->info.deviceid != GDK_CORE_POINTER &&
627 (gdkdev->button_state != 0))
628 gdkdev->button_state = 0;
630 tmp_list = tmp_list->next;
637 gdk_input_gxi_ungrab_pointer (guint32 time)
639 GdkInputWindow *input_window;
642 tmp_list = gdk_input_windows;
645 input_window = (GdkInputWindow *)tmp_list->data;
646 if (input_window->grabbed)
647 input_window->grabbed = FALSE;
648 tmp_list = tmp_list->next;