source: trunk/third/gtk/gdk/gdkinputgxi.h @ 14482

Revision 14482, 17.3 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
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 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.
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 * Library General Public License for more details.
13 *
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.
18 */
19
20/*
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/.
25 */
26
27#ifdef XINPUT_GXI
28
29/* #define DEBUG_SWITCHING */
30
31#include <gxid_lib.h>
32
33/* Forward declarations */
34static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev);
35static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode);
36static gint gdk_input_is_extension_device (guint32 deviceid);
37static void gdk_input_gxi_configure_event (XConfigureEvent *xevent,
38                                           GdkWindow *window);
39static void gdk_input_gxi_enter_event (XCrossingEvent *xevent,
40                                       GdkWindow *window);
41static gint gdk_input_gxi_other_event (GdkEvent *event,
42                                       XEvent *xevent,
43                                       GdkWindow *window);
44static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev);
45
46static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent);
47static gint gdk_input_gxi_enable_window (GdkWindow *window,
48                                         GdkDevicePrivate *gdkdev);
49static gint gdk_input_gxi_disable_window (GdkWindow *window,
50                                          GdkDevicePrivate *gdkdev);
51static Window gdk_input_find_root_child(Display *dpy, Window w);
52static void gdk_input_compute_obscuring(GdkInputWindow *input_window);
53static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x,
54                                  gdouble y);
55static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window,
56                                                  guint32 deviceid,
57                                                  guint32 start,
58                                                  guint32 stop,
59                                                  gint *nevents_return);
60static void gdk_input_gxi_get_pointer (GdkWindow       *window,
61                                       guint32     deviceid,
62                                       gdouble         *x,
63                                       gdouble         *y,
64                                       gdouble         *pressure,
65                                       gdouble         *xtilt,
66                                       gdouble         *ytilt,
67                                       GdkModifierType *mask);
68static gint gdk_input_gxi_grab_pointer (GdkWindow *     window,
69                                        gint            owner_events,
70                                        GdkEventMask    event_mask,
71                                        GdkWindow *     confine_to,
72                                        guint32         time);
73static void gdk_input_gxi_ungrab_pointer (guint32 time);
74
75/* Local variables */
76
77static GdkDevicePrivate *gdk_input_current_device;
78static GdkDevicePrivate *gdk_input_core_pointer;
79
80void
81gdk_input_init(void)
82{
83  GList *tmp_list;
84 
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;
98
99  gdk_input_ignore_core = FALSE;
100  gdk_input_core_pointer = NULL;
101
102  if (!gdk_input_gxid_host)
103    {
104      gdk_input_gxid_host = getenv("GXID_HOST");
105    }
106  if (!gdk_input_gxid_port)
107    {
108      char *t = getenv("GXID_PORT");
109      if (t)
110        gdk_input_gxid_port = atoi(t);
111    }
112 
113  gdk_input_common_init(TRUE);
114
115  /* find initial core pointer */
116 
117  for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
118    {
119      GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data;
120      if (gdk_input_is_extension_device(gdkdev->info.deviceid))
121        {
122          gdk_input_gxi_select_notify (gdkdev);
123        }
124      else
125        {
126          if (gdkdev->info.deviceid != GDK_CORE_POINTER)
127            gdk_input_core_pointer = gdkdev;
128        }
129    }
130}
131
132static void
133gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev)
134{
135  XEventClass class;
136
137  ChangeDeviceNotify  (gdkdev->xdevice, gdkdev->changenotify_type, class);
138
139  XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1);
140}
141
142/* Set the core pointer. Device should already be enabled. */
143static gint
144gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev)
145{
146  int x_axis,y_axis;
147
148  g_return_val_if_fail(gdkdev->xdevice,FALSE);
149
150  x_axis = gdkdev->axis_for_use[GDK_AXIS_X];
151  y_axis = gdkdev->axis_for_use[GDK_AXIS_Y];
152
153  g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE);
154
155  /* core_pointer might not be up to date so we check with the server
156     before change the pointer */
157
158  if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) )
159    {
160#if 0
161      if (gdkdev != gdk_input_core_pointer)
162        g_warning("core pointer inconsistency");
163#endif     
164      return TRUE;
165    }
166
167  if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis)
168       != Success )
169    {
170      return FALSE;
171    }
172  else
173    {
174      gdk_input_gxi_update_device (gdk_input_core_pointer);
175      gdk_input_core_pointer = gdkdev;
176      return TRUE;
177    }
178}
179
180
181/* FIXME, merge with gdk_input_xfree_set_mode */
182
183static gint
184gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode)
185{
186  GList *tmp_list;
187  GdkDevicePrivate *gdkdev;
188  GdkInputMode old_mode;
189  GdkInputWindow *input_window;
190
191  gdkdev = gdk_input_find_device(deviceid);
192  g_return_val_if_fail (gdkdev != NULL,FALSE);
193  old_mode = gdkdev->info.mode;
194
195  if (gdkdev->info.mode == mode)
196    return TRUE;
197 
198  gdkdev->info.mode = mode;
199
200  if (old_mode != GDK_MODE_DISABLED)
201    {
202      for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
203        {
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);
207        }
208    }
209 
210  if (mode != GDK_MODE_DISABLED)
211    {
212      for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
213        {
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))
217              {
218                gdk_input_set_mode(deviceid, old_mode);
219                return FALSE;
220              }
221        }
222    }
223
224  return TRUE;
225
226}
227
228gint
229gdk_input_is_extension_device (guint32 deviceid)
230{
231  XDeviceInfo   *devices;
232  int num_devices, loop;
233
234  if (deviceid == GDK_CORE_POINTER)
235    return FALSE;
236 
237  devices = XListInputDevices(gdk_display, &num_devices);
238  for(loop=0; loop<num_devices; loop++)
239    {
240      if ((devices[loop].id == deviceid) && (devices[loop].use == IsXExtensionDevice))
241        {
242          XFreeDeviceList(devices);
243          return TRUE;
244        }
245    }
246
247  XFreeDeviceList(devices);
248  return FALSE;
249}
250
251static void
252gdk_input_gxi_configure_event (XConfigureEvent *xevent, GdkWindow *window)
253{
254  GdkInputWindow *input_window;
255  gint root_x, root_y;
256
257  input_window = gdk_input_window_find(window);
258  g_return_if_fail (input_window != NULL);
259
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);
265}
266
267static void
268gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window)
269{
270  GdkInputWindow *input_window;
271
272  input_window = gdk_input_window_find(window);
273  g_return_if_fail (input_window != NULL);
274
275  gdk_input_compute_obscuring(input_window);
276}
277
278static gint
279gdk_input_gxi_other_event (GdkEvent *event,
280                           XEvent *xevent,
281                           GdkWindow *window)
282{
283  GdkInputWindow *input_window;
284
285  GdkDevicePrivate *gdkdev;
286  gint return_val;
287
288  input_window = gdk_input_window_find(window);
289  g_return_val_if_fail (window != NULL, -1);
290
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);
296
297  if (!gdkdev) {
298    return -1;                  /* we don't handle it - not an XInput event */
299  }
300
301  if (gdkdev->info.mode == GDK_MODE_DISABLED ||
302      input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
303    return FALSE;
304 
305  if (gdkdev != gdk_input_current_device &&
306      xevent->type != gdkdev->changenotify_type)
307    {
308      gdk_input_current_device = gdkdev;
309    }
310
311  return_val = gdk_input_common_other_event (event, xevent,
312                                             input_window, gdkdev);
313
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)))
320    {
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);
327#endif     
328      gdk_input_gxi_set_core_pointer(gdkdev);
329      return FALSE;
330    }
331  else
332    return return_val;
333
334}
335
336static void
337gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev)
338{
339  GList *t;
340
341  if (gdk_input_is_extension_device (gdkdev->info.deviceid))
342    {
343      if (!gdkdev->xdevice)
344        {
345          gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid);
346          gdk_input_gxi_select_notify (gdkdev);
347          gdkdev->needs_update = 1;
348        }
349      if (gdkdev->needs_update && gdkdev->xdevice)
350        {
351          for (t = gdk_input_windows; t; t = t->next)
352            gdk_input_common_select_events (((GdkInputWindow *)t->data)->window,
353                                         gdkdev);
354          gdkdev->needs_update = 0;
355        }
356    }
357}
358
359static gint
360gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent)
361{
362  GdkDevicePrivate *gdkdev =
363    gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid);
364
365  if (!gdkdev) {
366    return -1;                  /* we don't handle it - not an XInput event */
367  }
368
369  if (xevent->type == gdkdev->changenotify_type)
370    {
371      if (gdk_input_core_pointer != gdkdev)
372        {
373#ifdef DEBUG_SWITCHING
374          g_print("ChangeNotify from %d to %d:\n",
375                  gdk_input_core_pointer->info.deviceid,
376                  gdkdev->info.deviceid);
377#endif
378          gdk_input_gxi_update_device (gdk_input_core_pointer);
379          gdk_input_core_pointer = gdkdev;
380        }
381    }
382               
383  return FALSE;
384}
385
386static gint
387gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
388{
389  GdkInputWindow *input_window;
390
391  input_window = gdk_input_window_find (window);
392  g_return_val_if_fail (input_window != NULL, FALSE);
393
394  if (!gdkdev->claimed)
395    {
396      if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port,
397                            gdkdev->info.deviceid,
398                            GDK_WINDOW_XWINDOW(window), FALSE) !=
399          GXID_RETURN_OK)
400        {
401          g_warning("Could not get device (is gxid running?)\n");
402          return FALSE;
403        }
404      gdkdev->claimed = TRUE;
405    }
406
407  if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
408    gdk_input_common_select_events(window, gdkdev);
409  else
410    gdkdev->needs_update = TRUE;
411 
412  return TRUE;
413}
414
415static gint
416gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev)
417{
418  GdkInputWindow *input_window;
419
420  input_window = gdk_input_window_find (window);
421  g_return_val_if_fail (input_window != NULL, FALSE);
422
423  if (gdkdev->claimed)
424    {
425      gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port,
426                          gdkdev->info.deviceid,
427                          GDK_WINDOW_XWINDOW(window));
428
429      gdkdev->claimed = FALSE;
430    }
431
432  if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer)
433    gdk_input_common_select_events(window, gdkdev);
434  else
435    gdkdev->needs_update = TRUE;
436 
437  return TRUE;
438}
439
440static gint
441gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y)
442{
443  int i;
444  for (i=0;i<input_window->num_obscuring;i++)
445    {
446      GdkRectangle *rect = &input_window->obscuring[i];
447      if ((x >= rect->x) &&
448          (y >= rect->y) &&
449          (x < rect->x + rect->width) &&
450          (y < rect->y + rect->height))
451        return TRUE;
452    }
453  return FALSE;
454}
455
456/* If this routine needs fixing, the corresponding routine
457   in gxid.c will need it too. */
458
459static Window
460gdk_input_find_root_child(Display *dpy, Window w)
461{
462  Window root,parent;
463  Window *children;
464  int nchildren;
465
466  parent = w;
467  do
468    {
469      w = parent;
470      XQueryTree(dpy,w,&root,&parent,&children,&nchildren);
471      if (children) XFree(children);
472    }
473  while (parent != root);
474 
475  return w;
476}
477
478void
479gdk_input_compute_obscuring(GdkInputWindow *input_window)
480{
481  int i;
482  int x,y,width,height;
483  int xc,yc,widthc,heightc,border_widthc,depthc;
484
485  Window root,parent;
486  Window *children;
487  int nchildren;
488
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);
492
493  input_window->root_x = x;
494  input_window->root_y = y;
495
496  XQueryTree(gdk_display,GDK_ROOT_WINDOW(),
497             &root,&parent,&children,&nchildren);
498
499
500  if (input_window->obscuring)
501    g_free(input_window->obscuring);
502  input_window->obscuring = 0;
503  input_window->num_obscuring = 0;
504
505  for (i=0;i<nchildren;i++)
506    if (children[i] == root_child)
507      break;
508
509  if (i>=nchildren-1)
510    {
511      if (nchildren)
512        XFree(children);
513      return;
514    }
515
516  input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1));
517
518  for (i=i+1;i<nchildren;i++)
519    {
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))
528        {
529          XWindowAttributes attributes;
530          XGetWindowAttributes(gdk_display,children[i],&attributes);
531          if (attributes.map_state == IsViewable)
532            {
533              GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring];
534             
535              /* we store the whole window, not just the obscuring part */
536              rect->x = xc - x;
537              rect->y = yc - y;
538              rect->width = widthc;
539              rect->height = heightc;
540              input_window->num_obscuring++;
541            }
542        }
543    }
544
545  if (nchildren)
546    XFree(children);
547}
548
549static void
550gdk_input_gxi_get_pointer     (GdkWindow       *window,
551                               guint32     deviceid,
552                               gdouble         *x,
553                               gdouble         *y,
554                               gdouble         *pressure,
555                               gdouble         *xtilt,
556                               gdouble         *ytilt,
557                               GdkModifierType *mask)
558{
559  GdkDevicePrivate *gdkdev;
560
561  gdkdev = gdk_input_find_device (deviceid);
562  g_return_if_fail (gdkdev != NULL);
563
564  if (gdkdev == gdk_input_core_pointer)
565    gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y,
566                                  pressure, xtilt, ytilt, mask);
567  else
568    gdk_input_common_get_pointer (window, deviceid, x, y,
569                                  pressure, xtilt, ytilt, mask);
570}
571
572static GdkTimeCoord *
573gdk_input_gxi_motion_events (GdkWindow *window,
574                             guint32 deviceid,
575                             guint32 start,
576                             guint32 stop,
577                             gint *nevents_return)
578{
579  GdkDevicePrivate *gdkdev;
580
581  gdkdev = gdk_input_find_device (deviceid);
582  g_return_val_if_fail (gdkdev != NULL, NULL);
583 
584
585  if (gdkdev == gdk_input_core_pointer)
586    return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop,
587                                    nevents_return);
588  else
589    return gdk_input_common_motion_events (window, deviceid, start, stop,
590                                           nevents_return);
591 
592}
593
594static gint
595gdk_input_gxi_grab_pointer (GdkWindow *     window,
596                            gint            owner_events,
597                            GdkEventMask    event_mask,
598                            GdkWindow *     confine_to,
599                            guint32         time)
600{
601  GList *tmp_list;
602  GdkInputWindow *input_window;
603  GdkDevicePrivate *gdkdev;
604
605  tmp_list = gdk_input_windows;
606  while (tmp_list)
607    {
608      input_window = (GdkInputWindow *)tmp_list->data;
609
610      if (input_window->window == window)
611        input_window->grabbed = TRUE;
612      else if (input_window->grabbed)
613        input_window->grabbed = FALSE;
614
615      tmp_list = tmp_list->next;
616    }
617
618  tmp_list = gdk_input_devices;
619  while (tmp_list)
620    {
621      gdkdev = (GdkDevicePrivate *)tmp_list->data;
622      if (gdkdev->info.deviceid != GDK_CORE_POINTER &&
623          gdkdev->xdevice &&
624          (gdkdev->button_state != 0))
625        gdkdev->button_state = 0;
626     
627      tmp_list = tmp_list->next;
628    }
629
630  return Success;
631}
632
633static void
634gdk_input_gxi_ungrab_pointer (guint32 time)
635{
636  GdkInputWindow *input_window;
637  GList *tmp_list;
638
639  tmp_list = gdk_input_windows;
640  while (tmp_list)
641    {
642      input_window = (GdkInputWindow *)tmp_list->data;
643      if (input_window->grabbed)
644        input_window->grabbed = FALSE;
645      tmp_list = tmp_list->next;
646    }
647}
648
649#endif /* XINPUT_GXI */
Note: See TracBrowser for help on using the repository browser.