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 /* #define DEBUG_SWITCHING */
33 /* Forward declarations */
34 static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev);
35 static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode);
36 static gint gdk_input_is_extension_device (guint32 deviceid);
37 static void gdk_input_gxi_configure_event (XConfigureEvent *xevent,
39 static void gdk_input_gxi_enter_event (XCrossingEvent *xevent,
41 static gint gdk_input_gxi_other_event (GdkEvent *event,
44 static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev);
46 static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent);
47 static gint gdk_input_gxi_enable_window (GdkWindow *window,
48 GdkDevicePrivate *gdkdev);
49 static gint gdk_input_gxi_disable_window (GdkWindow *window,
50 GdkDevicePrivate *gdkdev);
51 static Window gdk_input_find_root_child(Display *dpy, Window w);
52 static void gdk_input_compute_obscuring(GdkInputWindow *input_window);
53 static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x,
55 static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window,
59 gint *nevents_return);
60 static void gdk_input_gxi_get_pointer (GdkWindow *window,
67 GdkModifierType *mask);
68 static gint gdk_input_gxi_grab_pointer (GdkWindow * window,
70 GdkEventMask event_mask,
71 GdkWindow * confine_to,
73 static void gdk_input_gxi_ungrab_pointer (guint32 time);
77 static GdkDevicePrivate *gdk_input_current_device;
78 static GdkDevicePrivate *gdk_input_core_pointer;
85 gdk_input_vtable.set_mode = gdk_input_gxi_set_mode;
86 gdk_input_vtable.set_axes = gdk_input_common_set_axes;
87 gdk_input_vtable.set_key = gdk_input_common_set_key;
88 gdk_input_vtable.motion_events = gdk_input_gxi_motion_events;
89 gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer;
90 gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer;
91 gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer;
92 gdk_input_vtable.configure_event = gdk_input_gxi_configure_event;
93 gdk_input_vtable.enter_event = gdk_input_gxi_enter_event;
94 gdk_input_vtable.other_event = gdk_input_gxi_other_event;
95 gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event;
96 gdk_input_vtable.enable_window = gdk_input_gxi_enable_window;
97 gdk_input_vtable.disable_window = gdk_input_gxi_disable_window;
99 gdk_input_ignore_core = FALSE;
100 gdk_input_core_pointer = NULL;
102 if (!gdk_input_gxid_host)
104 gdk_input_gxid_host = getenv("GXID_HOST");
106 if (!gdk_input_gxid_port)
108 char *t = getenv("GXID_PORT");
110 gdk_input_gxid_port = atoi(t);
113 gdk_input_common_init(TRUE);
115 /* find initial core pointer */
117 for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
119 GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data;
120 if (gdk_input_is_extension_device(gdkdev->info.deviceid))
122 gdk_input_gxi_select_notify (gdkdev);
126 if (gdkdev->info.deviceid != GDK_CORE_POINTER)
127 gdk_input_core_pointer = gdkdev;
133 gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev)
137 ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class);
139 XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1);
142 /* Set the core pointer. Device should already be enabled. */
144 gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev)
148 g_return_val_if_fail(gdkdev->xdevice,FALSE);
150 x_axis = gdkdev->axis_for_use[GDK_AXIS_X];
151 y_axis = gdkdev->axis_for_use[GDK_AXIS_Y];
153 g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE);
155 /* core_pointer might not be up to date so we check with the server
156 before change the pointer */
158 if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) )
161 if (gdkdev != gdk_input_core_pointer)
162 g_warning("core pointer inconsistency");
167 if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis)
174 gdk_input_gxi_update_device (gdk_input_core_pointer);
175 gdk_input_core_pointer = gdkdev;
181 /* FIXME, merge with gdk_input_xfree_set_mode */
184 gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode)
187 GdkDevicePrivate *gdkdev;
188 GdkInputMode old_mode;
189 GdkInputWindow *input_window;
191 gdkdev = gdk_input_find_device(deviceid);
192 g_return_val_if_fail (gdkdev != NULL,FALSE);
193 old_mode = gdkdev->info.mode;
195 if (gdkdev->info.mode == mode)
198 gdkdev->info.mode = mode;
200 if (old_mode != GDK_MODE_DISABLED)
202 for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
204 input_window = (GdkInputWindow *)tmp_list->data;
205 if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
206 gdk_input_disable_window (input_window->window, gdkdev);
210 if (mode != GDK_MODE_DISABLED)
212 for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
214 input_window = (GdkInputWindow *)tmp_list->data;
215 if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
216 if (!gdk_input_enable_window(input_window->window, gdkdev))
218 gdk_input_set_mode(deviceid, old_mode);
229 gdk_input_is_extension_device (guint32 deviceid)
231 XDeviceInfo *devices;
232 int num_devices, loop;
234 if (deviceid == GDK_CORE_POINTER)
237 devices = XListInputDevices(gdk_display, &num_devices);
238 for(loop=0; loop<num_devices; loop++)
240 if ((devices[loop].id == deviceid) && (devices[loop].use == IsXExtensionDevice))
242 XFreeDeviceList(devices);
247 XFreeDeviceList(devices);
252 gdk_input_gxi_configure_event (XConfigureEvent *xevent, GdkWindow *window)
254 GdkInputWindow *input_window;
257 input_window = gdk_input_window_find(window);
258 g_return_if_fail (input_window != NULL);
260 gdk_input_get_root_relative_geometry(gdk_display,GDK_WINDOW_XWINDOW(window),
261 &root_x, &root_y, NULL, NULL);
262 input_window->root_x = root_x;
263 input_window->root_y = root_y;
264 gdk_input_compute_obscuring(input_window);
268 gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window)
270 GdkInputWindow *input_window;
272 input_window = gdk_input_window_find(window);
273 g_return_if_fail (input_window != NULL);
275 gdk_input_compute_obscuring(input_window);
279 gdk_input_gxi_other_event (GdkEvent *event,
283 GdkInputWindow *input_window;
285 GdkDevicePrivate *gdkdev;
288 input_window = gdk_input_window_find(window);
289 g_return_val_if_fail (window != NULL, -1);
291 /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
292 but it's potentially faster than scanning through the types of
293 every device. If we were deceived, then it won't match any of
294 the types for the device anyways */
295 gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
298 return -1; /* we don't handle it - not an XInput event */
301 if (gdkdev->info.mode == GDK_MODE_DISABLED ||
302 input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
305 if (gdkdev != gdk_input_current_device &&
306 xevent->type != gdkdev->changenotify_type)
308 gdk_input_current_device = gdkdev;
311 return_val = gdk_input_common_other_event (event, xevent,
312 input_window, gdkdev);
314 if (return_val > 0 && event->type == GDK_MOTION_NOTIFY &&
315 (!gdkdev->button_state) && (!input_window->grabbed) &&
316 ((event->motion.x < 0) || (event->motion.y < 0) ||
317 (event->motion.x > ((GdkWindowPrivate *)window)->width) ||
318 (event->motion.y > ((GdkWindowPrivate *)window)->height) ||
319 gdk_input_is_obscured(input_window,event->motion.x,event->motion.y)))
321 #ifdef DEBUG_SWITCHING
322 g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n",
323 gdkdev->info.deviceid,event->motion.x,event->motion.y);
324 g_print(" window geometry is: %dx%d\n",
325 ((GdkWindowPrivate *)window)->width,
326 ((GdkWindowPrivate *)window)->height);
328 gdk_input_gxi_set_core_pointer(gdkdev);
337 gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev)
341 if (gdk_input_is_extension_device (gdkdev->info.deviceid))
343 if (!gdkdev->xdevice)
345 gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid);
346 gdk_input_gxi_select_notify (gdkdev);
347 gdkdev->needs_update = 1;
349 if (gdkdev->needs_update && gdkdev->xdevice)
351 for (t = gdk_input_windows; t; t = t->next)
352 gdk_input_common_select_events (((GdkInputWindow *)t->data)->window,
354 gdkdev->needs_update = 0;
360 gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent)
362 GdkDevicePrivate *gdkdev =
363 gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
366 return -1; /* we don't handle it - not an XInput event */
369 if (xevent->type == gdkdev->changenotify_type)
371 if (gdk_input_core_pointer != gdkdev)
373 #ifdef DEBUG_SWITCHING
374 g_print("ChangeNotify from %d to %d:\n",
375 gdk_input_core_pointer->info.deviceid,
376 gdkdev->info.deviceid);
378 gdk_input_gxi_update_device (gdk_input_core_pointer);
379 gdk_input_core_pointer = gdkdev;
387 gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
389 GdkInputWindow *input_window;
391 input_window = gdk_input_window_find (window);
392 g_return_val_if_fail (input_window != NULL, FALSE);
394 if (!gdkdev->claimed)
396 if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port,
397 gdkdev->info.deviceid,
398 GDK_WINDOW_XWINDOW(window), FALSE) !=
401 g_warning("Could not get device (is gxid running?)\n");
404 gdkdev->claimed = TRUE;
407 if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
408 gdk_input_common_select_events(window, gdkdev);
410 gdkdev->needs_update = TRUE;
416 gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev)
418 GdkInputWindow *input_window;
420 input_window = gdk_input_window_find (window);
421 g_return_val_if_fail (input_window != NULL, FALSE);
425 gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port,
426 gdkdev->info.deviceid,
427 GDK_WINDOW_XWINDOW(window));
429 gdkdev->claimed = FALSE;
432 if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
433 gdk_input_common_select_events(window, gdkdev);
435 gdkdev->needs_update = TRUE;
441 gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y)
444 for (i=0;i<input_window->num_obscuring;i++)
446 GdkRectangle *rect = &input_window->obscuring[i];
447 if ((x >= rect->x) &&
449 (x < rect->x + rect->width) &&
450 (y < rect->y + rect->height))
456 /* If this routine needs fixing, the corresponding routine
457 in gxid.c will need it too. */
460 gdk_input_find_root_child(Display *dpy, Window w)
470 XQueryTree(dpy,w,&root,&parent,&children,&nchildren);
471 if (children) XFree(children);
473 while (parent != root);
479 gdk_input_compute_obscuring(GdkInputWindow *input_window)
482 int x,y,width,height;
483 int xc,yc,widthc,heightc,border_widthc,depthc;
489 Window w = GDK_WINDOW_XWINDOW(input_window->window);
490 Window root_child = gdk_input_find_root_child(gdk_display,w);
491 gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height);
493 input_window->root_x = x;
494 input_window->root_y = y;
496 XQueryTree(gdk_display,GDK_ROOT_WINDOW(),
497 &root,&parent,&children,&nchildren);
500 if (input_window->obscuring)
501 g_free(input_window->obscuring);
502 input_window->obscuring = 0;
503 input_window->num_obscuring = 0;
505 for (i=0;i<nchildren;i++)
506 if (children[i] == root_child)
516 input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1));
518 for (i=i+1;i<nchildren;i++)
520 int xmin, xmax, ymin, ymax;
521 XGetGeometry(gdk_display,children[i],&root,&xc,&yc,&widthc,&heightc,
522 &border_widthc, &depthc);
523 xmin = xc>x ? xc : x;
524 xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width;
525 ymin = yc>y ? yc : y;
526 ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height;
527 if ((xmin < xmax) && (ymin < ymax))
529 XWindowAttributes attributes;
530 XGetWindowAttributes(gdk_display,children[i],&attributes);
531 if (attributes.map_state == IsViewable)
533 GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring];
535 /* we store the whole window, not just the obscuring part */
538 rect->width = widthc;
539 rect->height = heightc;
540 input_window->num_obscuring++;
550 gdk_input_gxi_get_pointer (GdkWindow *window,
557 GdkModifierType *mask)
559 GdkDevicePrivate *gdkdev;
561 gdkdev = gdk_input_find_device (deviceid);
562 g_return_if_fail (gdkdev != NULL);
564 if (gdkdev == gdk_input_core_pointer)
565 gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y,
566 pressure, xtilt, ytilt, mask);
568 gdk_input_common_get_pointer (window, deviceid, x, y,
569 pressure, xtilt, ytilt, mask);
572 static GdkTimeCoord *
573 gdk_input_gxi_motion_events (GdkWindow *window,
577 gint *nevents_return)
579 GdkDevicePrivate *gdkdev;
581 gdkdev = gdk_input_find_device (deviceid);
582 g_return_val_if_fail (gdkdev != NULL, NULL);
585 if (gdkdev == gdk_input_core_pointer)
586 return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop,
589 return gdk_input_common_motion_events (window, deviceid, start, stop,
595 gdk_input_gxi_grab_pointer (GdkWindow * window,
597 GdkEventMask event_mask,
598 GdkWindow * confine_to,
602 GdkInputWindow *input_window;
603 GdkDevicePrivate *gdkdev;
605 tmp_list = gdk_input_windows;
608 input_window = (GdkInputWindow *)tmp_list->data;
610 if (input_window->window == window)
611 input_window->grabbed = TRUE;
612 else if (input_window->grabbed)
613 input_window->grabbed = FALSE;
615 tmp_list = tmp_list->next;
618 tmp_list = gdk_input_devices;
621 gdkdev = (GdkDevicePrivate *)tmp_list->data;
622 if (gdkdev->info.deviceid != GDK_CORE_POINTER &&
624 (gdkdev->button_state != 0))
625 gdkdev->button_state = 0;
627 tmp_list = tmp_list->next;
634 gdk_input_gxi_ungrab_pointer (guint32 time)
636 GdkInputWindow *input_window;
639 tmp_list = gdk_input_windows;
642 input_window = (GdkInputWindow *)tmp_list->data;
643 if (input_window->grabbed)
644 input_window->grabbed = FALSE;
645 tmp_list = tmp_list->next;
649 #endif /* XINPUT_GXI */