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 Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* #define DEBUG_SWITCHING */
25 /* Forward declarations */
26 static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev);
27 static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode);
28 static gint gdk_input_is_extension_device (guint32 deviceid);
29 static void gdk_input_gxi_configure_event (XConfigureEvent *xevent,
31 static void gdk_input_gxi_enter_event (XCrossingEvent *xevent,
33 static gint gdk_input_gxi_other_event (GdkEvent *event,
36 static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev);
38 static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent);
39 static gint gdk_input_gxi_enable_window (GdkWindow *window,
40 GdkDevicePrivate *gdkdev);
41 static gint gdk_input_gxi_disable_window (GdkWindow *window,
42 GdkDevicePrivate *gdkdev);
43 static Window gdk_input_find_root_child(Display *dpy, Window w);
44 static void gdk_input_compute_obscuring(GdkInputWindow *input_window);
45 static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x,
47 static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window,
51 gint *nevents_return);
52 static void gdk_input_gxi_get_pointer (GdkWindow *window,
59 GdkModifierType *mask);
60 static gint gdk_input_gxi_grab_pointer (GdkWindow * window,
62 GdkEventMask event_mask,
63 GdkWindow * confine_to,
65 static void gdk_input_gxi_ungrab_pointer (guint32 time);
69 static GdkDevicePrivate *gdk_input_current_device;
70 static GdkDevicePrivate *gdk_input_core_pointer;
77 gdk_input_vtable.set_mode = gdk_input_gxi_set_mode;
78 gdk_input_vtable.set_axes = gdk_input_common_set_axes;
79 gdk_input_vtable.motion_events = gdk_input_gxi_motion_events;
80 gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer;
81 gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer;
82 gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer;
83 gdk_input_vtable.configure_event = gdk_input_gxi_configure_event;
84 gdk_input_vtable.enter_event = gdk_input_gxi_enter_event;
85 gdk_input_vtable.other_event = gdk_input_gxi_other_event;
86 gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event;
87 gdk_input_vtable.enable_window = gdk_input_gxi_enable_window;
88 gdk_input_vtable.disable_window = gdk_input_gxi_disable_window;
90 gdk_input_ignore_core = FALSE;
91 gdk_input_core_pointer = NULL;
93 if (!gdk_input_gxid_host)
95 gdk_input_gxid_host = getenv("GXID_HOST");
97 if (!gdk_input_gxid_port)
99 char *t = getenv("GXID_PORT");
101 gdk_input_gxid_port = atoi(t);
104 gdk_input_common_init(TRUE);
106 /* find initial core pointer */
108 for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
110 GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data;
111 if (gdk_input_is_extension_device(gdkdev->info.deviceid))
113 gdk_input_gxi_select_notify (gdkdev);
117 if (gdkdev->info.deviceid != GDK_CORE_POINTER)
118 gdk_input_core_pointer = gdkdev;
124 gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev)
128 ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class);
130 XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1);
133 /* Set the core pointer. Device should already be enabled. */
135 gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev)
139 g_return_val_if_fail(gdkdev->xdevice,FALSE);
141 x_axis = gdkdev->axis_for_use[GDK_AXIS_X];
142 y_axis = gdkdev->axis_for_use[GDK_AXIS_Y];
144 g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE);
146 /* core_pointer might not be up to date so we check with the server
147 before change the pointer */
149 if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) )
152 if (gdkdev != gdk_input_core_pointer)
153 g_warning("core pointer inconsistency");
158 if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis)
165 gdk_input_gxi_update_device (gdk_input_core_pointer);
166 gdk_input_core_pointer = gdkdev;
172 /* FIXME, merge with gdk_input_xfree_set_mode */
175 gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode)
178 GdkDevicePrivate *gdkdev;
179 GdkInputMode old_mode;
180 GdkInputWindow *input_window;
182 gdkdev = gdk_input_find_device(deviceid);
183 g_return_val_if_fail (gdkdev != NULL,FALSE);
184 old_mode = gdkdev->info.mode;
186 if (gdkdev->info.mode == mode)
189 gdkdev->info.mode = mode;
191 if (old_mode != GDK_MODE_DISABLED)
193 for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
195 input_window = (GdkInputWindow *)tmp_list->data;
196 if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
197 gdk_input_disable_window (input_window->window, gdkdev);
201 if (mode != GDK_MODE_DISABLED)
203 for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
205 input_window = (GdkInputWindow *)tmp_list->data;
206 if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
207 if (!gdk_input_enable_window(input_window->window, gdkdev))
209 gdk_input_set_mode(deviceid, old_mode);
220 gdk_input_is_extension_device (guint32 deviceid)
222 XDeviceInfo *devices;
223 int num_devices, loop;
225 if (deviceid == GDK_CORE_POINTER)
228 devices = XListInputDevices(gdk_display, &num_devices);
229 for(loop=0; loop<num_devices; loop++)
231 if ((devices[loop].id == deviceid) && (devices[loop].use == IsXExtensionDevice))
233 XFreeDeviceList(devices);
238 XFreeDeviceList(devices);
243 gdk_input_gxi_configure_event (XConfigureEvent *xevent, GdkWindow *window)
245 GdkInputWindow *input_window;
248 input_window = gdk_input_window_find(window);
249 g_return_if_fail (input_window != NULL);
251 gdk_input_get_root_relative_geometry(gdk_display,GDK_WINDOW_XWINDOW(window),
252 &root_x, &root_y, NULL, NULL);
253 input_window->root_x = root_x;
254 input_window->root_y = root_y;
255 gdk_input_compute_obscuring(input_window);
259 gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window)
261 GdkInputWindow *input_window;
263 input_window = gdk_input_window_find(window);
264 g_return_if_fail (input_window != NULL);
266 gdk_input_compute_obscuring(input_window);
270 gdk_input_gxi_other_event (GdkEvent *event,
274 GdkInputWindow *input_window;
276 GdkDevicePrivate *gdkdev;
279 input_window = gdk_input_window_find(window);
280 g_return_val_if_fail (window != NULL, -1);
282 /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
283 but it's potentially faster than scanning through the types of
284 every device. If we were deceived, then it won't match any of
285 the types for the device anyways */
286 gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
289 return -1; /* we don't handle it - not an XInput event */
292 if (gdkdev->info.mode == GDK_MODE_DISABLED ||
293 input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
296 if (gdkdev != gdk_input_current_device &&
297 xevent->type != gdkdev->changenotify_type)
299 gdk_input_current_device = gdkdev;
302 return_val = gdk_input_common_other_event (event, xevent,
303 input_window, gdkdev);
305 if (return_val > 0 && event->type == GDK_MOTION_NOTIFY &&
306 (!gdkdev->button_state) && (!input_window->grabbed) &&
307 ((event->motion.x < 0) || (event->motion.y < 0) ||
308 (event->motion.x > ((GdkWindowPrivate *)window)->width) ||
309 (event->motion.y > ((GdkWindowPrivate *)window)->height) ||
310 gdk_input_is_obscured(input_window,event->motion.x,event->motion.y)))
312 #ifdef DEBUG_SWITCHING
313 g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n",
314 gdkdev->info.deviceid,event->motion.x,event->motion.y);
315 g_print(" window geometry is: %dx%d\n",
316 ((GdkWindowPrivate *)window)->width,
317 ((GdkWindowPrivate *)window)->height);
319 gdk_input_gxi_set_core_pointer(gdkdev);
328 gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev)
332 if (gdk_input_is_extension_device (gdkdev->info.deviceid))
334 if (!gdkdev->xdevice)
336 gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid);
337 gdk_input_gxi_select_notify (gdkdev);
338 gdkdev->needs_update = 1;
340 if (gdkdev->needs_update && gdkdev->xdevice)
342 for (t = gdk_input_windows; t; t = t->next)
343 gdk_input_common_select_events (((GdkInputWindow *)t->data)->window,
345 gdkdev->needs_update = 0;
351 gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent)
353 GdkDevicePrivate *gdkdev =
354 gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
357 return -1; /* we don't handle it - not an XInput event */
360 if (xevent->type == gdkdev->changenotify_type)
362 if (gdk_input_core_pointer != gdkdev)
364 #ifdef DEBUG_SWITCHING
365 g_print("ChangeNotify from %d to %d:\n",
366 gdk_input_core_pointer->info.deviceid,
367 gdkdev->info.deviceid);
369 gdk_input_gxi_update_device (gdk_input_core_pointer);
370 gdk_input_core_pointer = gdkdev;
378 gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
380 GdkInputWindow *input_window;
382 input_window = gdk_input_window_find (window);
383 g_return_val_if_fail (input_window != NULL, FALSE);
385 if (!gdkdev->claimed)
387 if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port,
388 gdkdev->info.deviceid,
389 GDK_WINDOW_XWINDOW(window), FALSE) !=
392 g_warning("Could not get device (is gxid running?)\n");
395 gdkdev->claimed = TRUE;
398 if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
399 gdk_input_common_select_events(window, gdkdev);
401 gdkdev->needs_update = TRUE;
407 gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev)
409 GdkInputWindow *input_window;
411 input_window = gdk_input_window_find (window);
412 g_return_val_if_fail (input_window != NULL, FALSE);
416 gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port,
417 gdkdev->info.deviceid,
418 GDK_WINDOW_XWINDOW(window));
420 gdkdev->claimed = FALSE;
423 if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
424 gdk_input_common_select_events(window, gdkdev);
426 gdkdev->needs_update = TRUE;
432 gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y)
435 for (i=0;i<input_window->num_obscuring;i++)
437 GdkRectangle *rect = &input_window->obscuring[i];
438 if ((x >= rect->x) &&
440 (x < rect->x + rect->width) &&
441 (y < rect->y + rect->height))
447 /* If this routine needs fixing, the corresponding routine
448 in gxid.c will need it too. */
451 gdk_input_find_root_child(Display *dpy, Window w)
461 XQueryTree(dpy,w,&root,&parent,&children,&nchildren);
462 if (children) XFree(children);
464 while (parent != root);
470 gdk_input_compute_obscuring(GdkInputWindow *input_window)
473 int x,y,width,height;
474 int xc,yc,widthc,heightc,border_widthc,depthc;
480 Window w = GDK_WINDOW_XWINDOW(input_window->window);
481 Window root_child = gdk_input_find_root_child(gdk_display,w);
482 gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height);
484 input_window->root_x = x;
485 input_window->root_y = y;
487 XQueryTree(gdk_display,GDK_ROOT_WINDOW(),
488 &root,&parent,&children,&nchildren);
491 if (input_window->obscuring)
492 g_free(input_window->obscuring);
493 input_window->obscuring = 0;
494 input_window->num_obscuring = 0;
496 for (i=0;i<nchildren;i++)
497 if (children[i] == root_child)
507 input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1));
509 for (i=i+1;i<nchildren;i++)
511 int xmin, xmax, ymin, ymax;
512 XGetGeometry(gdk_display,children[i],&root,&xc,&yc,&widthc,&heightc,
513 &border_widthc, &depthc);
514 xmin = xc>x ? xc : x;
515 xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width;
516 ymin = yc>y ? yc : y;
517 ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height;
518 if ((xmin < xmax) && (ymin < ymax))
520 XWindowAttributes attributes;
521 XGetWindowAttributes(gdk_display,children[i],&attributes);
522 if (attributes.map_state == IsViewable)
524 GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring];
526 /* we store the whole window, not just the obscuring part */
529 rect->width = widthc;
530 rect->height = heightc;
531 input_window->num_obscuring++;
541 gdk_input_gxi_get_pointer (GdkWindow *window,
548 GdkModifierType *mask)
550 GdkDevicePrivate *gdkdev;
552 gdkdev = gdk_input_find_device (deviceid);
553 g_return_if_fail (gdkdev != NULL);
555 if (gdkdev == gdk_input_core_pointer)
556 gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y,
557 pressure, xtilt, ytilt, mask);
559 gdk_input_common_get_pointer (window, deviceid, x, y,
560 pressure, xtilt, ytilt, mask);
563 static GdkTimeCoord *
564 gdk_input_gxi_motion_events (GdkWindow *window,
568 gint *nevents_return)
570 GdkDevicePrivate *gdkdev;
572 gdkdev = gdk_input_find_device (deviceid);
573 g_return_val_if_fail (gdkdev != NULL, NULL);
576 if (gdkdev == gdk_input_core_pointer)
577 return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop,
580 return gdk_input_common_motion_events (window, deviceid, start, stop,
586 gdk_input_gxi_grab_pointer (GdkWindow * window,
588 GdkEventMask event_mask,
589 GdkWindow * confine_to,
592 GdkInputWindow *input_window, *new_window;
595 tmp_list = gdk_input_windows;
598 input_window = (GdkInputWindow *)tmp_list->data;
599 if (input_window->grabbed)
600 return AlreadyGrabbed;
602 if (input_window->window == window)
603 new_window = input_window;
605 tmp_list = tmp_list->next;
608 new_window->grabbed = TRUE;
613 gdk_input_gxi_ungrab_pointer (guint32 time)
615 GdkInputWindow *input_window;
618 tmp_list = gdk_input_windows;
621 input_window = (GdkInputWindow *)tmp_list->data;
622 if (input_window->grabbed)
623 input_window->grabbed = FALSE;
624 tmp_list = tmp_list->next;
628 #endif /* XINPUT_GXI */