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.set_key = gdk_input_common_set_key;
80 gdk_input_vtable.motion_events = gdk_input_gxi_motion_events;
81 gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer;
82 gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer;
83 gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer;
84 gdk_input_vtable.configure_event = gdk_input_gxi_configure_event;
85 gdk_input_vtable.enter_event = gdk_input_gxi_enter_event;
86 gdk_input_vtable.other_event = gdk_input_gxi_other_event;
87 gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event;
88 gdk_input_vtable.enable_window = gdk_input_gxi_enable_window;
89 gdk_input_vtable.disable_window = gdk_input_gxi_disable_window;
91 gdk_input_ignore_core = FALSE;
92 gdk_input_core_pointer = NULL;
94 if (!gdk_input_gxid_host)
96 gdk_input_gxid_host = getenv("GXID_HOST");
98 if (!gdk_input_gxid_port)
100 char *t = getenv("GXID_PORT");
102 gdk_input_gxid_port = atoi(t);
105 gdk_input_common_init(TRUE);
107 /* find initial core pointer */
109 for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
111 GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data;
112 if (gdk_input_is_extension_device(gdkdev->info.deviceid))
114 gdk_input_gxi_select_notify (gdkdev);
118 if (gdkdev->info.deviceid != GDK_CORE_POINTER)
119 gdk_input_core_pointer = gdkdev;
125 gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev)
129 ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class);
131 XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1);
134 /* Set the core pointer. Device should already be enabled. */
136 gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev)
140 g_return_val_if_fail(gdkdev->xdevice,FALSE);
142 x_axis = gdkdev->axis_for_use[GDK_AXIS_X];
143 y_axis = gdkdev->axis_for_use[GDK_AXIS_Y];
145 g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE);
147 /* core_pointer might not be up to date so we check with the server
148 before change the pointer */
150 if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) )
153 if (gdkdev != gdk_input_core_pointer)
154 g_warning("core pointer inconsistency");
159 if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis)
166 gdk_input_gxi_update_device (gdk_input_core_pointer);
167 gdk_input_core_pointer = gdkdev;
173 /* FIXME, merge with gdk_input_xfree_set_mode */
176 gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode)
179 GdkDevicePrivate *gdkdev;
180 GdkInputMode old_mode;
181 GdkInputWindow *input_window;
183 gdkdev = gdk_input_find_device(deviceid);
184 g_return_val_if_fail (gdkdev != NULL,FALSE);
185 old_mode = gdkdev->info.mode;
187 if (gdkdev->info.mode == mode)
190 gdkdev->info.mode = mode;
192 if (old_mode != GDK_MODE_DISABLED)
194 for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
196 input_window = (GdkInputWindow *)tmp_list->data;
197 if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
198 gdk_input_disable_window (input_window->window, gdkdev);
202 if (mode != GDK_MODE_DISABLED)
204 for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
206 input_window = (GdkInputWindow *)tmp_list->data;
207 if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
208 if (!gdk_input_enable_window(input_window->window, gdkdev))
210 gdk_input_set_mode(deviceid, old_mode);
221 gdk_input_is_extension_device (guint32 deviceid)
223 XDeviceInfo *devices;
224 int num_devices, loop;
226 if (deviceid == GDK_CORE_POINTER)
229 devices = XListInputDevices(gdk_display, &num_devices);
230 for(loop=0; loop<num_devices; loop++)
232 if ((devices[loop].id == deviceid) && (devices[loop].use == IsXExtensionDevice))
234 XFreeDeviceList(devices);
239 XFreeDeviceList(devices);
244 gdk_input_gxi_configure_event (XConfigureEvent *xevent, GdkWindow *window)
246 GdkInputWindow *input_window;
249 input_window = gdk_input_window_find(window);
250 g_return_if_fail (input_window != NULL);
252 gdk_input_get_root_relative_geometry(gdk_display,GDK_WINDOW_XWINDOW(window),
253 &root_x, &root_y, NULL, NULL);
254 input_window->root_x = root_x;
255 input_window->root_y = root_y;
256 gdk_input_compute_obscuring(input_window);
260 gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window)
262 GdkInputWindow *input_window;
264 input_window = gdk_input_window_find(window);
265 g_return_if_fail (input_window != NULL);
267 gdk_input_compute_obscuring(input_window);
271 gdk_input_gxi_other_event (GdkEvent *event,
275 GdkInputWindow *input_window;
277 GdkDevicePrivate *gdkdev;
280 input_window = gdk_input_window_find(window);
281 g_return_val_if_fail (window != NULL, -1);
283 /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
284 but it's potentially faster than scanning through the types of
285 every device. If we were deceived, then it won't match any of
286 the types for the device anyways */
287 gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
290 return -1; /* we don't handle it - not an XInput event */
293 if (gdkdev->info.mode == GDK_MODE_DISABLED ||
294 input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
297 if (gdkdev != gdk_input_current_device &&
298 xevent->type != gdkdev->changenotify_type)
300 gdk_input_current_device = gdkdev;
303 return_val = gdk_input_common_other_event (event, xevent,
304 input_window, gdkdev);
306 if (return_val > 0 && event->type == GDK_MOTION_NOTIFY &&
307 (!gdkdev->button_state) && (!input_window->grabbed) &&
308 ((event->motion.x < 0) || (event->motion.y < 0) ||
309 (event->motion.x > ((GdkWindowPrivate *)window)->width) ||
310 (event->motion.y > ((GdkWindowPrivate *)window)->height) ||
311 gdk_input_is_obscured(input_window,event->motion.x,event->motion.y)))
313 #ifdef DEBUG_SWITCHING
314 g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n",
315 gdkdev->info.deviceid,event->motion.x,event->motion.y);
316 g_print(" window geometry is: %dx%d\n",
317 ((GdkWindowPrivate *)window)->width,
318 ((GdkWindowPrivate *)window)->height);
320 gdk_input_gxi_set_core_pointer(gdkdev);
329 gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev)
333 if (gdk_input_is_extension_device (gdkdev->info.deviceid))
335 if (!gdkdev->xdevice)
337 gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid);
338 gdk_input_gxi_select_notify (gdkdev);
339 gdkdev->needs_update = 1;
341 if (gdkdev->needs_update && gdkdev->xdevice)
343 for (t = gdk_input_windows; t; t = t->next)
344 gdk_input_common_select_events (((GdkInputWindow *)t->data)->window,
346 gdkdev->needs_update = 0;
352 gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent)
354 GdkDevicePrivate *gdkdev =
355 gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
358 return -1; /* we don't handle it - not an XInput event */
361 if (xevent->type == gdkdev->changenotify_type)
363 if (gdk_input_core_pointer != gdkdev)
365 #ifdef DEBUG_SWITCHING
366 g_print("ChangeNotify from %d to %d:\n",
367 gdk_input_core_pointer->info.deviceid,
368 gdkdev->info.deviceid);
370 gdk_input_gxi_update_device (gdk_input_core_pointer);
371 gdk_input_core_pointer = gdkdev;
379 gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
381 GdkInputWindow *input_window;
383 input_window = gdk_input_window_find (window);
384 g_return_val_if_fail (input_window != NULL, FALSE);
386 if (!gdkdev->claimed)
388 if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port,
389 gdkdev->info.deviceid,
390 GDK_WINDOW_XWINDOW(window), FALSE) !=
393 g_warning("Could not get device (is gxid running?)\n");
396 gdkdev->claimed = TRUE;
399 if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
400 gdk_input_common_select_events(window, gdkdev);
402 gdkdev->needs_update = TRUE;
408 gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev)
410 GdkInputWindow *input_window;
412 input_window = gdk_input_window_find (window);
413 g_return_val_if_fail (input_window != NULL, FALSE);
417 gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port,
418 gdkdev->info.deviceid,
419 GDK_WINDOW_XWINDOW(window));
421 gdkdev->claimed = FALSE;
424 if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
425 gdk_input_common_select_events(window, gdkdev);
427 gdkdev->needs_update = TRUE;
433 gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y)
436 for (i=0;i<input_window->num_obscuring;i++)
438 GdkRectangle *rect = &input_window->obscuring[i];
439 if ((x >= rect->x) &&
441 (x < rect->x + rect->width) &&
442 (y < rect->y + rect->height))
448 /* If this routine needs fixing, the corresponding routine
449 in gxid.c will need it too. */
452 gdk_input_find_root_child(Display *dpy, Window w)
462 XQueryTree(dpy,w,&root,&parent,&children,&nchildren);
463 if (children) XFree(children);
465 while (parent != root);
471 gdk_input_compute_obscuring(GdkInputWindow *input_window)
474 int x,y,width,height;
475 int xc,yc,widthc,heightc,border_widthc,depthc;
481 Window w = GDK_WINDOW_XWINDOW(input_window->window);
482 Window root_child = gdk_input_find_root_child(gdk_display,w);
483 gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height);
485 input_window->root_x = x;
486 input_window->root_y = y;
488 XQueryTree(gdk_display,GDK_ROOT_WINDOW(),
489 &root,&parent,&children,&nchildren);
492 if (input_window->obscuring)
493 g_free(input_window->obscuring);
494 input_window->obscuring = 0;
495 input_window->num_obscuring = 0;
497 for (i=0;i<nchildren;i++)
498 if (children[i] == root_child)
508 input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1));
510 for (i=i+1;i<nchildren;i++)
512 int xmin, xmax, ymin, ymax;
513 XGetGeometry(gdk_display,children[i],&root,&xc,&yc,&widthc,&heightc,
514 &border_widthc, &depthc);
515 xmin = xc>x ? xc : x;
516 xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width;
517 ymin = yc>y ? yc : y;
518 ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height;
519 if ((xmin < xmax) && (ymin < ymax))
521 XWindowAttributes attributes;
522 XGetWindowAttributes(gdk_display,children[i],&attributes);
523 if (attributes.map_state == IsViewable)
525 GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring];
527 /* we store the whole window, not just the obscuring part */
530 rect->width = widthc;
531 rect->height = heightc;
532 input_window->num_obscuring++;
542 gdk_input_gxi_get_pointer (GdkWindow *window,
549 GdkModifierType *mask)
551 GdkDevicePrivate *gdkdev;
553 gdkdev = gdk_input_find_device (deviceid);
554 g_return_if_fail (gdkdev != NULL);
556 if (gdkdev == gdk_input_core_pointer)
557 gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y,
558 pressure, xtilt, ytilt, mask);
560 gdk_input_common_get_pointer (window, deviceid, x, y,
561 pressure, xtilt, ytilt, mask);
564 static GdkTimeCoord *
565 gdk_input_gxi_motion_events (GdkWindow *window,
569 gint *nevents_return)
571 GdkDevicePrivate *gdkdev;
573 gdkdev = gdk_input_find_device (deviceid);
574 g_return_val_if_fail (gdkdev != NULL, NULL);
577 if (gdkdev == gdk_input_core_pointer)
578 return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop,
581 return gdk_input_common_motion_events (window, deviceid, start, stop,
587 gdk_input_gxi_grab_pointer (GdkWindow * window,
589 GdkEventMask event_mask,
590 GdkWindow * confine_to,
593 GdkInputWindow *input_window, *new_window;
596 tmp_list = gdk_input_windows;
599 input_window = (GdkInputWindow *)tmp_list->data;
600 if (input_window->grabbed)
601 return AlreadyGrabbed;
603 if (input_window->window == window)
604 new_window = input_window;
606 tmp_list = tmp_list->next;
609 new_window->grabbed = TRUE;
614 gdk_input_gxi_ungrab_pointer (guint32 time)
616 GdkInputWindow *input_window;
619 tmp_list = gdk_input_windows;
622 input_window = (GdkInputWindow *)tmp_list->data;
623 if (input_window->grabbed)
624 input_window->grabbed = FALSE;
625 tmp_list = tmp_list->next;
629 #endif /* XINPUT_GXI */