[gtk+/xi2: 214/215] Merge branch 'master' into xi2



commit 3863cdd6984cb465885fbd457536fb65192d4b34
Merge: 44f11d7... cf8c4a6...
Author: Carlos Garnacho <carlos gnome org>
Date:   Tue Oct 20 12:33:34 2009 +0200

    Merge branch 'master' into xi2
    
    Conflicts:
    	gdk/gdkdisplay.c
    	gdk/gdkinternals.h
    	gdk/gdkwindow.c
    	gdk/x11/gdkinput-x11.c
    	gdk/x11/gdkinput-xfree.c
    	gdk/x11/gdkinput.c
    	gdk/x11/gdkinputprivate.h
    	gdk/x11/gdkwindow-x11.c
    
    XInput changes in master that made sense yet have been merged to gdkdevice-xi.c
    and gdkdevicemanager-xi.c. The rest is mostly an adaption as-is to the xi2
    branch.

 NEWS                                             |  130 +
 README.in                                        |    5 +
 configure.in                                     |    4 +-
 demos/gtk-demo/Makefile.am                       |    1 +
 demos/gtk-demo/list_store.c                      |  146 +-
 demos/gtk-demo/spinner.c                         |   94 +
 docs/developers.txt                              |    9 -
 docs/dnd_internals.txt                           |    2 -
 docs/faq/gtk-faq.sgml                            |    8 +-
 docs/refcounting.txt                             |    8 +-
 docs/reference/gdk/tmpl/cairo_interaction.sgml   |    2 +-
 docs/reference/gdk/tmpl/input_devices.sgml       |    7 +-
 docs/reference/gdk/tmpl/windows.sgml             |    8 +
 docs/reference/gtk/Makefile.am                   |    1 +
 docs/reference/gtk/gtk-docs.sgml                 |    6 +
 docs/reference/gtk/gtk-sections.txt              |   37 +
 docs/reference/gtk/gtk.types                     |    2 +
 docs/reference/gtk/images/spinner.png            |  Bin 0 -> 3531 bytes
 docs/reference/gtk/tmpl/gtkaboutdialog.sgml      |  475 --
 docs/reference/gtk/tmpl/gtkaccelgroup.sgml       |  327 --
 docs/reference/gtk/tmpl/gtkaccessible.sgml       |   33 -
 docs/reference/gtk/tmpl/gtkactivatable.sgml      |   98 -
 docs/reference/gtk/tmpl/gtkimage.sgml            |    2 +-
 docs/reference/gtk/tmpl/gtkinputdialog.sgml      |   17 +-
 docs/reference/gtk/tmpl/gtkprintunixdialog.sgml  |    2 +-
 docs/reference/gtk/tmpl/gtktoolshell.sgml        |   80 -
 docs/reference/gtk/visual_index.xml              |    3 +
 docs/tools/widgets.c                             |   21 +
 docs/tutorial/gtk_tut.sgml                       |   14 +-
 docs/tutorial/gtk_tut_12.es.sgml                 |   10 +-
 docs/widget_system.txt                           |    2 +-
 gdk-pixbuf/io-gdip-utils.c                       |   68 +-
 gdk/directfb/gdkdnd-directfb.c                   |    4 +-
 gdk/directfb/gdkwindow-directfb.c                |   26 +-
 gdk/gdkdevice.c                                  |   23 +-
 gdk/gdkdeviceprivate.h                           |    3 +-
 gdk/gdkdisplay.c                                 |   26 +-
 gdk/gdkgc.h                                      |    2 +-
 gdk/gdkimage.h                                   |    2 +-
 gdk/gdkinternals.h                               |    4 +-
 gdk/gdkpixmap.h                                  |    8 +-
 gdk/gdkwindow.c                                  |  107 +-
 gdk/gdkwindow.h                                  |    4 +-
 gdk/quartz/GdkQuartzView.c                       |    7 +
 gdk/quartz/GdkQuartzWindow.c                     |   30 +
 gdk/quartz/gdkcursor-quartz.c                    |   21 +-
 gdk/quartz/gdkdnd-quartz.c                       |    6 +
 gdk/quartz/gdkevents-quartz.c                    |   36 +-
 gdk/quartz/gdkgeometry-quartz.c                  |   26 +
 gdk/quartz/gdkprivate-quartz.h                   |    3 +
 gdk/quartz/gdkscreen-quartz.c                    |   32 +-
 gdk/quartz/gdkwindow-quartz.c                    |  134 +-
 gdk/quartz/gdkwindow-quartz.h                    |    2 +
 gdk/testgdk.c                                    |    2 +-
 gdk/win32/gdkmain-win32.c                        |    2 -
 gdk/win32/gdkwindow-win32.c                      |  176 +-
 gdk/x11/gdkcursor-x11.c                          |    4 +-
 gdk/x11/gdkdevice-core.c                         |   11 +-
 gdk/x11/gdkdevice-xi.c                           |   86 +-
 gdk/x11/gdkdevice-xi.h                           |    8 +-
 gdk/x11/gdkdevice-xi2.c                          |   11 +-
 gdk/x11/gdkdevicemanager-xi.c                    |   47 +-
 gdk/x11/gdkdevicemanager-xi2.c                   |   14 +-
 gdk/x11/gdkwindow-x11.c                          |   11 +-
 gtk/Makefile.am                                  |   42 +-
 gtk/gtk.h                                        |    4 +-
 gtk/gtk.symbols                                  |   21 +
 gtk/gtkaboutdialog.c                             |   61 +
 gtk/gtkaboutdialog.h                             |   17 +
 gtk/gtkaccelgroup.c                              |   25 +
 gtk/gtkaccelgroup.h                              |   26 +
 gtk/gtkaccessible.c                              |    7 +
 gtk/gtkactivatable.c                             |    1 +
 gtk/gtkcellrendererspinner.c                     |  388 ++
 gtk/gtkcellrendererspinner.h                     |   64 +
 gtk/gtkdialog.c                                  |   43 +
 gtk/gtkdialog.h                                  |    2 +
 gtk/gtkdnd-quartz.c                              |  134 +-
 gtk/gtkentry.c                                   |   10 +-
 gtk/gtkfilechooserdefault.c                      | 2962 +++----------
 gtk/gtkfilechooserprivate.h                      |   68 +-
 gtk/gtkfilesystemmodel.c                         | 2998 +++++++-------
 gtk/gtkfilesystemmodel.h                         |   71 +-
 gtk/gtkiconview.c                                |   20 +-
 gtk/gtkimage.c                                   |   21 +-
 gtk/gtkinputdialog.h                             |    8 +-
 gtk/gtklabel.c                                   |   28 +-
 gtk/gtkmain.c                                    |   13 +
 gtk/gtkmarshalers.list                           |    1 +
 gtk/gtkprintbackend.c                            |  164 +-
 gtk/gtkprintbackend.h                            |   16 +-
 gtk/gtkprintcontext.c                            |   16 +-
 gtk/gtkprintoperation-unix.c                     |   21 +-
 gtk/gtkprintunixdialog.c                         |   28 +-
 gtk/gtksearchenginetracker.c                     |   95 +-
 gtk/gtkspinner.c                                 |  627 +++
 gtk/gtkspinner.h                                 |   65 +
 gtk/gtkstatusicon.c                              |    2 +-
 gtk/gtkstyle.c                                   |  118 +-
 gtk/gtkstyle.h                                   |   18 +-
 gtk/gtktextlayout.c                              |   65 +-
 gtk/gtktoolbutton.c                              |    7 +
 gtk/gtktoolshell.c                               |    1 +
 gtk/gtktooltip.c                                 |   37 +-
 gtk/gtktooltip.h                                 |    3 +
 gtk/gtktreemodelfilter.c                         |   55 +-
 gtk/gtkwidget.c                                  |    3 +
 gtk/gtkwidget.h                                  |    4 +-
 gtk/gtkwindow.c                                  |    7 +
 gtk/tests/defaultvalue.c                         |    9 +-
 gtk/tests/filtermodel.c                          |  291 ++-
 modules/engines/ms-windows/xp_theme.c            |    3 +
 modules/printbackends/cups/gtkcupsutils.c        |    5 +
 modules/printbackends/cups/gtkcupsutils.h        |    3 +
 modules/printbackends/cups/gtkprintbackendcups.c |  360 ++-
 modules/printbackends/cups/gtkprintercups.c      |   12 +
 modules/printbackends/cups/gtkprintercups.h      |    7 +
 modules/printbackends/lpr/gtkprintbackendlpr.c   |    2 -
 po-properties/af.po                              |   76 +-
 po-properties/am.po                              |   76 +-
 po-properties/ang.po                             |   76 +-
 po-properties/ar.po                              |   76 +-
 po-properties/as.po                              |  265 +-
 po-properties/ast.po                             |   76 +-
 po-properties/az.po                              |   76 +-
 po-properties/az_IR.po                           |   76 +-
 po-properties/be.po                              |   76 +-
 po-properties/be latin po                        |   76 +-
 po-properties/bg.po                              |   76 +-
 po-properties/bn.po                              |   76 +-
 po-properties/bn_IN.po                           | 3712 ++++++++--------
 po-properties/br.po                              |   76 +-
 po-properties/bs.po                              |   76 +-
 po-properties/ca.po                              | 3586 ++++++++--------
 po-properties/ca valencia po                     |   76 +-
 po-properties/crh.po                             |   76 +-
 po-properties/cs.po                              |   76 +-
 po-properties/cy.po                              |   76 +-
 po-properties/da.po                              | 3474 ++++++++--------
 po-properties/de.po                              | 3474 ++++++++--------
 po-properties/dz.po                              |   76 +-
 po-properties/el.po                              |   76 +-
 po-properties/en_CA.po                           |   76 +-
 po-properties/en_GB.po                           | 3490 ++++++++--------
 po-properties/eo.po                              |   76 +-
 po-properties/es.po                              |   76 +-
 po-properties/et.po                              |   76 +-
 po-properties/eu.po                              |   76 +-
 po-properties/fa.po                              |   76 +-
 po-properties/fi.po                              |   76 +-
 po-properties/fr.po                              |   76 +-
 po-properties/ga.po                              |   76 +-
 po-properties/gl.po                              |   76 +-
 po-properties/gu.po                              | 3646 ++++++++--------
 po-properties/he.po                              |   76 +-
 po-properties/hi.po                              |   76 +-
 po-properties/hr.po                              |   76 +-
 po-properties/hu.po                              |   76 +-
 po-properties/hy.po                              |   76 +-
 po-properties/ia.po                              |   76 +-
 po-properties/id.po                              |   76 +-
 po-properties/io.po                              |   76 +-
 po-properties/is.po                              |   76 +-
 po-properties/it.po                              |  258 +-
 po-properties/ja.po                              |   78 +-
 po-properties/ka.po                              |   76 +-
 po-properties/kn.po                              |   76 +-
 po-properties/ko.po                              |   76 +-
 po-properties/ku.po                              |   76 +-
 po-properties/li.po                              |   76 +-
 po-properties/lt.po                              | 3474 ++++++++--------
 po-properties/lv.po                              |   76 +-
 po-properties/mai.po                             | 3642 ++++++++--------
 po-properties/mi.po                              |   76 +-
 po-properties/mk.po                              |   76 +-
 po-properties/ml.po                              | 3663 ++++++++--------
 po-properties/mn.po                              |   76 +-
 po-properties/mr.po                              | 3664 ++++++++--------
 po-properties/ms.po                              |   76 +-
 po-properties/nb.po                              | 3476 ++++++++--------
 po-properties/ne.po                              |   76 +-
 po-properties/nl.po                              |   76 +-
 po-properties/nn.po                              |   76 +-
 po-properties/nso.po                             |   76 +-
 po-properties/oc.po                              |   76 +-
 po-properties/or.po                              | 3757 ++++++++--------
 po-properties/pa.po                              | 3654 ++++++++--------
 po-properties/pl.po                              |   76 +-
 po-properties/ps.po                              |   76 +-
 po-properties/pt.po                              |   76 +-
 po-properties/pt_BR.po                           |   76 +-
 po-properties/ro.po                              |   95 +-
 po-properties/ru.po                              | 3596 ++++++++--------
 po-properties/rw.po                              |   76 +-
 po-properties/si.po                              |   76 +-
 po-properties/sk.po                              |   76 +-
 po-properties/sl.po                              | 4733 +++++++++++----------
 po-properties/sq.po                              |   76 +-
 po-properties/sr.po                              | 5074 ++++++++++------------
 po-properties/sr ije po                          |   76 +-
 po-properties/sr latin po                        | 5131 ++++++++++------------
 po-properties/sv.po                              |   76 +-
 po-properties/ta.po                              |   76 +-
 po-properties/te.po                              |   76 +-
 po-properties/th.po                              |   76 +-
 po-properties/tk.po                              |   76 +-
 po-properties/tr.po                              |   76 +-
 po-properties/tt.po                              |   76 +-
 po-properties/uk.po                              | 3474 ++++++++--------
 po-properties/ur.po                              |   76 +-
 po-properties/uz.po                              |   76 +-
 po-properties/uz cyrillic po                     |   76 +-
 po-properties/vi.po                              |   76 +-
 po-properties/wa.po                              |   76 +-
 po-properties/xh.po                              |   76 +-
 po-properties/yi.po                              |   76 +-
 po-properties/zh_CN.po                           | 3477 ++++++++--------
 po-properties/zh_HK.po                           | 3571 ++++++++--------
 po-properties/zh_TW.po                           | 3474 ++++++++--------
 po/POTFILES.in                                   |    2 +
 po/af.po                                         |  435 +-
 po/am.po                                         |  410 +-
 po/ang.po                                        |  408 +-
 po/ar.po                                         |  408 +-
 po/as.po                                         |  457 ++-
 po/ast.po                                        |  409 +-
 po/az.po                                         |  410 +-
 po/az_IR.po                                      |  405 +-
 po/be.po                                         |  410 +-
 po/be latin po                                   |  410 +-
 po/bg.po                                         | 2226 +++++-----
 po/bn.po                                         |  407 +-
 po/bn_IN.po                                      |  408 +-
 po/br.po                                         |  406 +-
 po/bs.po                                         |  410 +-
 po/ca.po                                         | 2319 +++++-----
 po/ca valencia po                                |  410 +-
 po/crh.po                                        |  415 +-
 po/cs.po                                         |  410 +-
 po/cy.po                                         |  410 +-
 po/da.po                                         | 2235 +++++-----
 po/de.po                                         | 2236 +++++-----
 po/dz.po                                         |  410 +-
 po/el.po                                         | 1177 +++---
 po/en_CA.po                                      |  410 +-
 po/en_GB.po                                      | 2239 +++++-----
 po/eo.po                                         |  410 +-
 po/es.po                                         | 2283 +++++-----
 po/et.po                                         |  446 +-
 po/eu.po                                         |  409 +-
 po/fa.po                                         |  410 +-
 po/fi.po                                         | 2256 +++++-----
 po/fr.po                                         |  410 +-
 po/ga.po                                         |  408 +-
 po/gl.po                                         |  422 +-
 po/gu.po                                         | 2269 +++++-----
 po/he.po                                         |  410 +-
 po/hi.po                                         |  412 +-
 po/hr.po                                         |  410 +-
 po/hu.po                                         |  408 +-
 po/hy.po                                         |  410 +-
 po/ia.po                                         |  410 +-
 po/id.po                                         |  410 +-
 po/io.po                                         |  410 +-
 po/is.po                                         |  410 +-
 po/it.po                                         | 2229 +++++-----
 po/ja.po                                         |  409 +-
 po/ka.po                                         |  410 +-
 po/kn.po                                         |  408 +-
 po/ko.po                                         |  408 +-
 po/ku.po                                         |  410 +-
 po/li.po                                         |  410 +-
 po/lt.po                                         | 2240 +++++-----
 po/lv.po                                         |  410 +-
 po/mai.po                                        | 2272 +++++-----
 po/mi.po                                         |  410 +-
 po/mk.po                                         |  410 +-
 po/ml.po                                         | 2269 +++++-----
 po/mn.po                                         |  415 +-
 po/mr.po                                         | 2275 +++++-----
 po/ms.po                                         |  410 +-
 po/nb.po                                         |  393 +-
 po/ne.po                                         |  410 +-
 po/nl.po                                         | 2630 ++++++------
 po/nn.po                                         |  410 +-
 po/nso.po                                        |  410 +-
 po/oc.po                                         |  408 +-
 po/or.po                                         |  364 +-
 po/pa.po                                         | 2270 +++++-----
 po/pl.po                                         | 2593 ++++++------
 po/ps.po                                         |  410 +-
 po/pt.po                                         |  409 +-
 po/pt_BR.po                                      |  372 +-
 po/ro.po                                         | 2252 +++++-----
 po/ru.po                                         | 2390 +++++-----
 po/rw.po                                         |  415 +-
 po/si.po                                         |  410 +-
 po/sk.po                                         |  410 +-
 po/sl.po                                         |  630 ++--
 po/sq.po                                         |  410 +-
 po/sr.po                                         |  417 +-
 po/sr ije po                                     |  410 +-
 po/sr latin po                                   |  417 +-
 po/sv.po                                         | 2834 ++++++-------
 po/ta.po                                         |  408 +-
 po/te.po                                         |  408 +-
 po/th.po                                         |  408 +-
 po/tk.po                                         |  410 +-
 po/tr.po                                         |  415 +-
 po/tt.po                                         |  410 +-
 po/uk.po                                         | 2214 +++++-----
 po/ur.po                                         |  406 +-
 po/uz.po                                         |  410 +-
 po/uz cyrillic po                                |  410 +-
 po/vi.po                                         |  413 +-
 po/wa.po                                         |  410 +-
 po/xh.po                                         |  410 +-
 po/yi.po                                         |  410 +-
 po/zh_CN.po                                      | 2233 +++++-----
 po/zh_HK.po                                      | 2240 +++++-----
 po/zh_TW.po                                      | 2230 +++++-----
 tests/autotestkeywords.cc                        |    2 +
 tests/testinput.c                                |    2 +
 323 files changed, 92976 insertions(+), 90540 deletions(-)
---
diff --cc gdk/gdkdevice.c
index 67321e1,0000000..2fa58ab
mode 100644,000000..100644
--- a/gdk/gdkdevice.c
+++ b/gdk/gdkdevice.c
@@@ -1,1035 -1,0 +1,1052 @@@
 +/* GDK - The GIMP Drawing Kit
 + * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 + * Boston, MA 02111-1307, USA.
 + */
 +
 +#include "gdkdevice.h"
 +#include "gdkdeviceprivate.h"
 +#include "gdkintl.h"
 +#include "gdkinternals.h"
 +#include "gdkalias.h"
 +
 +#define GDK_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDK_TYPE_DEVICE, GdkDevicePrivate))
 +
 +typedef struct _GdkDevicePrivate GdkDevicePrivate;
 +typedef struct _GdkAxisInfo GdkAxisInfo;
 +
 +struct _GdkAxisInfo
 +{
 +  GdkAtom label;
 +  GdkAxisUse use;
 +
 +  gdouble min_axis;
 +  gdouble max_axis;
 +
 +  gdouble min_value;
 +  gdouble max_value;
 +  gdouble resolution;
 +};
 +
 +struct _GdkDevicePrivate
 +{
 +  GdkDeviceManager *device_manager;
 +  GdkDisplay *display;
 +  GdkDevice *relative;
 +  GdkDeviceType type;
 +  GArray *axes;
 +};
 +
 +static void gdk_device_dispose      (GObject      *object);
 +static void gdk_device_set_property (GObject      *object,
 +                                     guint         prop_id,
 +                                     const GValue *value,
 +                                     GParamSpec   *pspec);
 +static void gdk_device_get_property (GObject      *object,
 +                                     guint         prop_id,
 +                                     GValue       *value,
 +                                     GParamSpec   *pspec);
 +
 +
 +G_DEFINE_ABSTRACT_TYPE (GdkDevice, gdk_device, G_TYPE_OBJECT)
 +
 +enum {
 +  PROP_0,
 +  PROP_DISPLAY,
 +  PROP_DEVICE_MANAGER,
 +  PROP_NAME,
 +  PROP_RELATIVE,
 +  PROP_TYPE,
 +  PROP_INPUT_SOURCE,
 +  PROP_INPUT_MODE,
 +  PROP_HAS_CURSOR,
 +  PROP_N_AXES
 +};
 +
 +
 +static void
 +gdk_device_class_init (GdkDeviceClass *klass)
 +{
 +  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 +
 +  object_class->dispose = gdk_device_dispose;
 +  object_class->set_property = gdk_device_set_property;
 +  object_class->get_property = gdk_device_get_property;
 +
 +  g_object_class_install_property (object_class,
 +				   PROP_DISPLAY,
 +				   g_param_spec_object ("display",
 +                                                        P_("Device Display"),
 +                                                        P_("Display to which the device belongs to"),
 +                                                        GDK_TYPE_DISPLAY,
 +                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 +  g_object_class_install_property (object_class,
 +				   PROP_DEVICE_MANAGER,
 +				   g_param_spec_object ("device-manager",
 +                                                        P_("Device manager"),
 +                                                        P_("Device manager to which the device belongs to"),
 +                                                        GDK_TYPE_DEVICE_MANAGER,
 +                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 +  g_object_class_install_property (object_class,
 +				   PROP_NAME,
 +				   g_param_spec_string ("name",
 +                                                        P_("Device name"),
 +                                                        P_("Device name"),
 +                                                        NULL,
 +                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 +  g_object_class_install_property (object_class,
 +                                   PROP_TYPE,
 +                                   g_param_spec_enum ("type",
 +                                                      P_("Device type"),
 +                                                      P_("Device role in the device manager"),
 +                                                      GDK_TYPE_DEVICE_TYPE,
 +                                                      GDK_DEVICE_TYPE_MASTER,
 +                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 +  g_object_class_install_property (object_class,
 +				   PROP_RELATIVE,
 +				   g_param_spec_object ("relative",
 +                                                        P_("Relative device"),
 +                                                        P_("Corresponding pointer or keyboard to this device"),
 +                                                        GDK_TYPE_DEVICE,
 +                                                        G_PARAM_READABLE));
 +  g_object_class_install_property (object_class,
 +				   PROP_INPUT_SOURCE,
 +				   g_param_spec_enum ("input-source",
 +                                                      P_("Input source"),
 +                                                      P_("Source type for the device"),
 +                                                      GDK_TYPE_INPUT_SOURCE,
 +                                                      GDK_SOURCE_MOUSE,
 +                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 +  g_object_class_install_property (object_class,
 +                                   PROP_INPUT_MODE,
 +				   g_param_spec_enum ("input-mode",
 +                                                      P_("Input mode for the device"),
 +                                                      P_("Input mode for the device"),
 +                                                      GDK_TYPE_INPUT_MODE,
 +                                                      GDK_MODE_DISABLED,
 +                                                      G_PARAM_READWRITE));
 +  g_object_class_install_property (object_class,
 +				   PROP_HAS_CURSOR,
 +				   g_param_spec_boolean ("has-cursor",
 +                                                         P_("Whether the device has cursor"),
 +                                                         P_("Whether there is a visible cursor following device motion"),
 +                                                         FALSE,
 +                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 +  g_object_class_install_property (object_class,
 +				   PROP_N_AXES,
 +				   g_param_spec_uint ("n-axes",
 +                                                      P_("Number of axes in the device"),
 +                                                      P_("Number of axes in the device"),
 +                                                      0, G_MAXUINT, 0,
 +                                                      G_PARAM_READABLE));
 +
 +  g_type_class_add_private (object_class, sizeof (GdkDevicePrivate));
 +}
 +
 +static void
 +gdk_device_init (GdkDevice *device)
 +{
 +  GdkDevicePrivate *priv;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +  priv->axes = g_array_new (FALSE, TRUE, sizeof (GdkAxisInfo));
 +}
 +
 +static void
 +gdk_device_dispose (GObject *object)
 +{
 +  GdkDevicePrivate *priv;
 +  GdkDevice *device;
 +
 +  device = GDK_DEVICE (object);
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  if (priv->relative)
 +    {
 +      _gdk_device_set_relative (priv->relative, NULL);
 +      g_object_unref (priv->relative);
 +      priv->relative = NULL;
 +    }
 +
 +  if (priv->axes)
 +    {
 +      g_array_free (priv->axes, TRUE);
 +      priv->axes = NULL;
 +    }
 +
 +  g_free (device->name);
 +  g_free (device->keys);
 +  g_free (device->axes);
 +
 +  device->name = NULL;
 +  device->keys = NULL;
 +  device->axes = NULL;
 +
 +  G_OBJECT_CLASS (gdk_device_parent_class)->dispose (object);
 +}
 +
 +static void
 +gdk_device_set_property (GObject      *object,
 +                         guint         prop_id,
 +                         const GValue *value,
 +                         GParamSpec   *pspec)
 +{
 +  GdkDevice *device = GDK_DEVICE (object);
 +  GdkDevicePrivate *priv = GDK_DEVICE_GET_PRIVATE (object);
 +
 +  switch (prop_id)
 +    {
 +    case PROP_DISPLAY:
 +      priv->display = g_value_get_object (value);
 +      break;
 +    case PROP_DEVICE_MANAGER:
 +      priv->device_manager = g_value_get_object (value);
 +      break;
 +    case PROP_NAME:
 +      if (device->name)
 +        g_free (device->name);
 +
 +      device->name = g_value_dup_string (value);
 +      break;
 +    case PROP_TYPE:
 +      priv->type = g_value_get_enum (value);
 +      break;
 +    case PROP_INPUT_SOURCE:
 +      device->source = g_value_get_enum (value);
 +      break;
 +    case PROP_INPUT_MODE:
 +      gdk_device_set_mode (device, g_value_get_enum (value));
 +      break;
 +    case PROP_HAS_CURSOR:
 +      device->has_cursor = g_value_get_boolean (value);
 +      break;
 +    default:
 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 +      break;
 +    }
 +}
 +
 +static void
 +gdk_device_get_property (GObject    *object,
 +                         guint       prop_id,
 +                         GValue     *value,
 +                         GParamSpec *pspec)
 +{
 +  GdkDevice *device = GDK_DEVICE (object);
 +  GdkDevicePrivate *priv = GDK_DEVICE_GET_PRIVATE (object);
 +
 +  switch (prop_id)
 +    {
 +    case PROP_DISPLAY:
 +      g_value_set_object (value, priv->display);
 +      break;
 +    case PROP_DEVICE_MANAGER:
 +      g_value_set_object (value, priv->device_manager);
 +      break;
 +    case PROP_RELATIVE:
 +      g_value_set_object (value, priv->relative);
 +      break;
 +    case PROP_NAME:
 +      g_value_set_string (value,
 +                          device->name);
 +      break;
 +    case PROP_TYPE:
 +      g_value_set_enum (value, priv->type);
 +      break;
 +    case PROP_INPUT_SOURCE:
 +      g_value_set_enum (value, device->source);
 +      break;
 +    case PROP_INPUT_MODE:
 +      g_value_set_enum (value, device->mode);
 +      break;
 +    case PROP_HAS_CURSOR:
 +      g_value_set_boolean (value,
 +                           device->has_cursor);
 +      break;
 +    case PROP_N_AXES:
 +      g_value_set_uint (value, priv->axes->len);
 +      break;
 +    default:
 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 +      break;
 +    }
 +}
 +
 +void
 +gdk_device_get_state (GdkDevice       *device,
 +                      GdkWindow       *window,
 +                      gdouble         *axes,
 +                      GdkModifierType *mask)
 +{
 +  g_return_if_fail (GDK_IS_DEVICE (device));
 +  g_return_if_fail (GDK_IS_WINDOW (window));
 +
 +  if (GDK_DEVICE_GET_CLASS (device)->get_state)
 +    GDK_DEVICE_GET_CLASS (device)->get_state (device, window, axes, mask);
 +}
 +
 +/**
 + * gdk_device_get_history:
 + * @device: a #GdkDevice
 + * @window: the window with respect to which which the event coordinates will be reported
 + * @start: starting timestamp for range of events to return
 + * @stop: ending timestamp for the range of events to return
 + * @events: location to store a newly-allocated array of #GdkTimeCoord, or %NULL
 + * @n_events: location to store the length of @events, or %NULL
 + *
 + * Obtains the motion history for a device; given a starting and
 + * ending timestamp, return all events in the motion history for
 + * the device in the given range of time. Some windowing systems
 + * do not support motion history, in which case, %FALSE will
 + * be returned. (This is not distinguishable from the case where
 + * motion history is supported and no events were found.)
 + *
 + * Return value: %TRUE if the windowing system supports motion history and
 + *  at least one event was found.
 + **/
 +gboolean
 +gdk_device_get_history (GdkDevice      *device,
 +                        GdkWindow      *window,
 +                        guint32         start,
 +                        guint32         stop,
 +                        GdkTimeCoord ***events,
 +                        guint          *n_events)
 +{
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
 +  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 +
 +  if (!GDK_DEVICE_GET_CLASS (device)->get_history)
 +    return FALSE;
 +
 +  return GDK_DEVICE_GET_CLASS (device)->get_history (device, window,
 +                                                     start, stop,
 +                                                     events, n_events);
 +}
 +
 +GdkTimeCoord **
 +_gdk_device_allocate_history (GdkDevice *device,
 +                              guint      n_events)
 +{
 +  GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events);
 +  gint i;
 +
 +  for (i = 0; i < n_events; i++)
 +    result[i] = g_malloc (sizeof (GdkTimeCoord) -
 +			  sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->num_axes));
 +  return result;
 +}
 +
 +void
 +gdk_device_free_history (GdkTimeCoord **events,
 +                         gint           n_events)
 +{
 +  gint i;
 +
 +  for (i = 0; i < n_events; i++)
 +    g_free (events[i]);
 +
 +  g_free (events);
 +}
 +
 +void
 +gdk_device_set_source (GdkDevice      *device,
 +		       GdkInputSource  source)
 +{
 +  g_return_if_fail (GDK_IS_DEVICE (device));
 +
 +  device->source = source;
 +}
 +
 +gboolean
 +gdk_device_set_mode (GdkDevice    *device,
 +                     GdkInputMode  mode)
 +{
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
 +
 +  if (device->mode == mode)
 +    return TRUE;
 +
 +  if (mode == GDK_MODE_DISABLED &&
 +      gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER)
 +    return FALSE;
 +
 +  /* FIXME: setting has_cursor when mode is window? */
 +
 +  device->mode = mode;
 +  g_object_notify (G_OBJECT (device), "input-mode");
 +
 +  if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
 +    _gdk_input_check_extension_events (device);
 +
 +  return TRUE;
 +}
 +
 +void
 +gdk_device_set_key (GdkDevice      *device,
 +		    guint           index,
 +		    guint           keyval,
 +		    GdkModifierType modifiers)
 +{
 +  g_return_if_fail (GDK_IS_DEVICE (device));
 +  g_return_if_fail (index < device->num_keys);
 +
 +  device->keys[index].keyval = keyval;
 +  device->keys[index].modifiers = modifiers;
 +}
 +
 +void
 +gdk_device_set_axis_use (GdkDevice   *device,
 +			 guint        index,
 +			 GdkAxisUse   use)
 +{
 +  GdkDevicePrivate *priv;
 +  GdkAxisInfo *info;
 +
 +  g_return_if_fail (GDK_IS_DEVICE (device));
 +  g_return_if_fail (index < device->num_axes);
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +  info = &g_array_index (priv->axes, GdkAxisInfo, index);
 +  info->use = use;
 +
 +  device->axes[index].use = use;
 +
 +  switch (use)
 +    {
 +    case GDK_AXIS_X:
 +    case GDK_AXIS_Y:
 +      device->axes[index].min = info->min_value = 0;
 +      device->axes[index].max = info->max_value = 0;
 +      break;
 +    case GDK_AXIS_XTILT:
 +    case GDK_AXIS_YTILT:
 +      device->axes[index].min = info->min_value = -1;
 +      device->axes[index].max = info->max_value = 1;
 +      break;
 +    default:
 +      device->axes[index].min = info->min_value = 0;
 +      device->axes[index].max = info->max_value = 1;
 +      break;
 +    }
 +}
 +
 +/**
 + * gdk_device_get_display:
 + * @device: a #GdkDevice
 + *
 + * Returns the #GdkDisplay to which @device pertains.
 + *
 + * Returns: a #GdkDisplay. This memory is owned by GTK+,
 + *          and must not be freed or unreffed.
 + **/
 +GdkDisplay *
 +gdk_device_get_display (GdkDevice *device)
 +{
 +  GdkDevicePrivate *priv;
 +
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  return priv->display;
 +}
 +
 +GdkDevice *
 +gdk_device_get_relative (GdkDevice *device)
 +{
 +  GdkDevicePrivate *priv;
 +
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  return priv->relative;
 +}
 +
 +void
 +_gdk_device_set_relative (GdkDevice *device,
 +                          GdkDevice *relative)
 +{
 +  GdkDevicePrivate *priv;
 +
 +  g_return_if_fail (GDK_IS_DEVICE (device));
 +  g_return_if_fail (GDK_IS_DEVICE (relative));
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  if (priv->relative == relative)
 +    return;
 +
 +  if (priv->relative)
 +    {
 +      g_object_unref (priv->relative);
 +      priv->relative = NULL;
 +    }
 +
 +  if (relative)
 +    priv->relative = g_object_ref (relative);
 +}
 +
 +/**
 + * gdk_device_get_device_type:
 + * @device: a #GdkDevice
 + *
 + * Returns the device type for @device.
 + *
 + * Returns: the #GdkDeviceType for @device.
 + **/
 +GdkDeviceType
 +gdk_device_get_device_type (GdkDevice *device)
 +{
 +  GdkDevicePrivate *priv;
 +
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_DEVICE_TYPE_MASTER);
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  return priv->type;
 +}
 +
 +/**
 + * gdk_device_list_axes:
 + * @device: a #GdkDevice
 + *
 + * Returns a #GList of #GdkAtom<!-- -->s, containing the labels for
 + * the axes that @device currently has.
 + *
 + * Returns: A #GList of #GdkAtom<!-- -->s, free with g_list_free().
 + **/
 +GList *
 +gdk_device_list_axes (GdkDevice *device)
 +{
 +  GdkDevicePrivate *priv;
 +  GList *axes = NULL;
 +  gint i;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  for (i = 0; i < priv->axes->len; i++)
 +    {
 +      GdkAxisInfo axis_info;
 +
 +      axis_info = g_array_index (priv->axes, GdkAxisInfo, i);
 +      axes = g_list_prepend (axes, GDK_ATOM_TO_POINTER (axis_info.label));
 +    }
 +
 +  return g_list_reverse (axes);
 +}
 +
 +gboolean
 +gdk_device_get_axis_value (GdkDevice *device,
 +                           gdouble   *axes,
 +                           GdkAtom    axis_label,
 +                           gdouble   *value)
 +{
 +  GdkDevicePrivate *priv;
 +  gint i;
 +
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
 +
 +  if (axes == NULL)
 +    return FALSE;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  for (i = 0; i < priv->axes->len; i++)
 +    {
 +      GdkAxisInfo axis_info;
 +
 +      axis_info = g_array_index (priv->axes, GdkAxisInfo, i);
 +
 +      if (axis_info.label != axis_label)
 +        continue;
 +
 +      if (value)
 +        *value = axes[i];
 +
 +      return TRUE;
 +    }
 +
 +  return FALSE;
 +}
 +
 +/**
 + * gdk_device_get_axis:
 + * @device: a #GdkDevice
 + * @axes: pointer to an array of axes
 + * @use: the use to look for
 + * @value: location to store the found value.
 + *
 + * Interprets an array of double as axis values for a given device,
 + * and locates the value in the array for a given axis use.
 + *
 + * Return value: %TRUE if the given axis use was found, otherwise %FALSE
 + **/
 +gboolean
 +gdk_device_get_axis (GdkDevice  *device,
 +                     gdouble    *axes,
 +                     GdkAxisUse  use,
 +                     gdouble    *value)
 +{
 +  GdkDevicePrivate *priv;
 +  gint i;
 +
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
 +
 +  if (axes == NULL)
 +    return FALSE;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  g_return_val_if_fail (priv->axes != NULL, FALSE);
 +
 +  for (i = 0; i < priv->axes->len; i++)
 +    {
 +      GdkAxisInfo axis_info;
 +
 +      axis_info = g_array_index (priv->axes, GdkAxisInfo, i);
 +
 +      if (axis_info.use != use)
 +        continue;
 +
 +      if (value)
 +        *value = axes[i];
 +
 +      return TRUE;
 +    }
 +
 +  return FALSE;
 +}
 +
 +/**
 + * gdk_device_grab:
 + * @device: a #GdkDevice
 + * @window: the #GdkWindow which will own the grab (the grab window)
 + * @grab_ownership: 
 + * @owner_events: if %FALSE then all device events are reported with respect to
 + *                @window and are only reported if selected by @event_mask. If
 + *                %TRUE then pointer events for this application are reported
 + *                as normal, but pointer events outside this application are
 + *                reported with respect to @window and only if selected by
 + *                @event_mask. In either mode, unreported events are discarded.
 + * @event_mask: specifies the event mask, which is used in accordance with
 + *              @owner_events.
 + * @cursor: the cursor to display while the grab is active if the device is
 + *          a pointer. If this is %NULL then the normal cursors are used for
 + *          @window and its descendants, and the cursor for @window is used
 + *          elsewhere.
 + * @time_: the timestamp of the event which led to this pointer grab. This
 + *         usually comes from the #GdkEvent struct, though %GDK_CURRENT_TIME
 + *         can be used if the time isn't known.
 + *
 + * Grabs the device so that all events coming from this device are passed to
-  * this application until the device is ungrabbed with gdk_display_device_ungrab(),
++ * this application until the device is ungrabbed with gdk_device_ungrab(),
 + * or the window becomes unviewable. This overrides any previous grab on the device
 + * by this client.
 + *
 + * Device grabs are used for operations which need complete control over the
 + * given device events (either pointer or keyboard). For example in GTK+ this
 + * is used for Drag and Drop operations, popup menus and such.
 + *
 + * Note that if the event mask of an X window has selected both button press
 + * and button release events, then a button press event will cause an automatic
 + * pointer grab until the button is released. X does this automatically since
 + * most applications expect to receive button press and release events in pairs.
 + * It is equivalent to a pointer grab on the window with @owner_events set to
 + * %TRUE.
 + *
 + * If you set up anything at the time you take the grab that needs to be
 + * cleaned up when the grab ends, you should handle the #GdkEventGrabBroken
 + * events that are emitted when the grab ends unvoluntarily.
 + *
 + * Returns: %GDK_GRAB_SUCCESS if the grab was successful.
 + **/
 +GdkGrabStatus
 +gdk_device_grab (GdkDevice        *device,
 +                 GdkWindow        *window,
 +                 GdkGrabOwnership  grab_ownership,
 +                 gboolean          owner_events,
 +                 GdkEventMask      event_mask,
 +                 GdkCursor        *cursor,
 +                 guint32           time_)
 +{
 +  GdkGrabStatus res;
 +  GdkWindow *native;
 +
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
 +  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 +
 +  if (_gdk_native_windows)
 +    native = window;
 +  else
 +    native = gdk_window_get_toplevel (window);
 +
 +  while (((GdkWindowObject *) native)->window_type == GDK_WINDOW_OFFSCREEN)
 +    {
 +      native = gdk_offscreen_window_get_embedder (native);
 +
 +      if (native == NULL ||
 +	  (!_gdk_window_has_impl (native) &&
 +	   !gdk_window_is_viewable (native)))
 +	return GDK_GRAB_NOT_VIEWABLE;
 +
 +      native = gdk_window_get_toplevel (native);
 +    }
 +
 +  res = _gdk_windowing_device_grab (device,
 +                                    window,
 +                                    native,
 +                                    owner_events,
 +                                    event_mask,
 +                                    NULL,
 +                                    cursor,
 +                                    time_);
 +
 +  if (res == GDK_GRAB_SUCCESS)
 +    {
 +      GdkDisplay *display;
 +      gulong serial;
 +
 +      display = gdk_drawable_get_display (window);
 +      serial = _gdk_windowing_window_get_next_serial (display);
 +
 +      _gdk_display_add_device_grab (display,
 +                                    device,
 +                                    window,
 +                                    native,
 +                                    GDK_OWNERSHIP_NONE,
 +                                    owner_events,
 +                                    event_mask,
 +                                    serial,
 +                                    time_,
 +                                    FALSE);
 +    }
 +
 +  return res;
 +}
 +
 +/* Private API */
 +void
 +_gdk_device_reset_axes (GdkDevice *device)
 +{
 +  GdkDevicePrivate *priv;
 +  gint i;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  for (i = priv->axes->len - 1; i >= 0; i--)
 +    g_array_remove_index (priv->axes, i);
 +
 +  g_object_notify (G_OBJECT (device), "n-axes");
 +
 +  /* This is done for backwards compatibility */
 +  g_free (device->axes);
 +  device->axes = NULL;
 +}
 +
 +guint
 +_gdk_device_add_axis (GdkDevice   *device,
 +                      GdkAtom      label_atom,
 +                      GdkAxisUse   use,
 +                      gdouble      min_value,
 +                      gdouble      max_value,
 +                      gdouble      resolution)
 +{
 +  GdkDevicePrivate *priv;
 +  GdkAxisInfo axis_info;
 +  guint pos;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  axis_info.use = use;
 +  axis_info.label = label_atom;
 +  axis_info.min_value = min_value;
 +  axis_info.max_value = max_value;
 +  axis_info.resolution = resolution;
 +
 +  switch (use)
 +    {
 +    case GDK_AXIS_X:
 +    case GDK_AXIS_Y:
 +      axis_info.min_axis = 0.;
 +      axis_info.max_axis = 0.;
 +      break;
 +    case GDK_AXIS_XTILT:
 +    case GDK_AXIS_YTILT:
 +      axis_info.min_axis = -1.;
 +      axis_info.max_axis = 1.;
 +      break;
 +    default:
 +      axis_info.min_axis = 0.;
 +      axis_info.max_axis = 1.;
 +      break;
 +    }
 +
 +  priv->axes = g_array_append_val (priv->axes, axis_info);
 +  device->num_axes = priv->axes->len;
 +  pos = device->num_axes - 1;
 +
 +  /* This is done for backwards compatibility, since the public
 +   * struct doesn't actually store the device data.
 +   */
 +  device->axes = g_realloc (device->axes, sizeof (GdkDeviceAxis) * priv->axes->len);
 +  device->axes[pos].use = axis_info.use;
 +  device->axes[pos].min = axis_info.min_axis;
 +  device->axes[pos].max = axis_info.max_axis;
 +
 +  g_object_notify (G_OBJECT (device), "n-axes");
 +
 +  return pos;
 +}
 +
 +void
 +_gdk_device_set_keys (GdkDevice *device,
 +                      guint      num_keys)
 +{
 +  if (device->keys)
 +    g_free (device->keys);
 +
 +  device->num_keys = num_keys;
 +  device->keys = g_new0 (GdkDeviceKey, num_keys);
 +}
 +
 +GdkAxisInfo *
 +find_axis_info (GArray     *array,
 +                GdkAxisUse  use)
 +{
 +  GdkAxisInfo *info;
 +  gint i;
 +
 +  for (i = 0; i < GDK_AXIS_LAST; i++)
 +    {
 +      info = &g_array_index (array, GdkAxisInfo, i);
 +
 +      if (info->use == use)
 +        return info;
 +    }
 +
 +  return NULL;
 +}
 +
 +GdkAxisUse
 +_gdk_device_get_axis_use (GdkDevice *device,
 +                          guint      index)
 +{
 +  GdkDevicePrivate *priv;
 +  GdkAxisInfo info;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  info = g_array_index (priv->axes, GdkAxisInfo, index);
 +  return info.use;
 +}
 +
 +gboolean
 +_gdk_device_translate_window_coord (GdkDevice *device,
 +                                    GdkWindow *window,
 +                                    guint      index,
 +                                    gdouble    value,
 +                                    gdouble   *axis_value)
 +{
 +  GdkDevicePrivate *priv;
 +  GdkAxisInfo axis_info;
 +  GdkAxisInfo *axis_info_x, *axis_info_y;
 +  gdouble device_width, device_height;
 +  gdouble x_offset, y_offset;
 +  gdouble x_scale, y_scale;
++  gdouble x_min, y_min;
 +  gdouble x_resolution, y_resolution;
 +  gdouble device_aspect;
 +  gint window_width, window_height;
 +  GdkWindowObject *window_private;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  if (index >= priv->axes->len)
 +    return FALSE;
 +
 +  axis_info = g_array_index (priv->axes, GdkAxisInfo, index);
 +
 +  if (axis_info.use != GDK_AXIS_X &&
 +      axis_info.use != GDK_AXIS_Y)
 +    return FALSE;
 +
 +  if (axis_info.use == GDK_AXIS_X)
 +    {
 +      axis_info_x = &axis_info;
 +      axis_info_y = find_axis_info (priv->axes, GDK_AXIS_Y);
 +    }
 +  else
 +    {
 +      axis_info_x = find_axis_info (priv->axes, GDK_AXIS_X);
 +      axis_info_y = &axis_info;
 +    }
 +
 +  device_width = axis_info_x->max_value - axis_info_x->min_value;
 +  device_height = axis_info_y->max_value - axis_info_y->min_value;
 +
++  if (device_width > 0)
++    x_min = axis_info_x->min_value;
++  else
++    {
++      device_width = gdk_screen_get_width (gdk_drawable_get_screen (window));
++      x_min = 0;
++    }
++
++  if (device_height > 0)
++    y_min = axis_info_y->min_value;
++  else
++    {
++      device_height = gdk_screen_get_height (gdk_drawable_get_screen (window));
++      y_min = 0;
++    }
++
 +  window_private = (GdkWindowObject *) window;
 +  gdk_drawable_get_size (window, &window_width, &window_height);
 +
 +  x_resolution = axis_info_x->resolution;
 +  y_resolution = axis_info_y->resolution;
 +
 +  /*
 +   * Some drivers incorrectly report the resolution of the device
 +   * as zero (in partiular linuxwacom < 0.5.3 with usb tablets).
 +   * This causes the device_aspect to become NaN and totally
 +   * breaks windowed mode.  If this is the case, the best we can
 +   * do is to assume the resolution is non-zero is equal in both
 +   * directions (which is true for many devices).  The absolute
 +   * value of the resolution doesn't matter since we only use the
 +   * ratio.
 +   */
 +  if (x_resolution == 0 || y_resolution == 0)
 +    {
 +      x_resolution = 1;
 +      y_resolution = 1;
 +    }
 +
 +  device_aspect = (device_height * y_resolution) /
 +    (device_width * x_resolution);
 +
 +  if (device_aspect * window_width >= window_height)
 +    {
 +      /* device taller than window */
 +      x_scale = window_width / device_width;
 +      y_scale = (x_scale * x_resolution) / y_resolution;
 +
 +      x_offset = 0;
 +      y_offset = - (device_height * y_scale - window_height) / 2;
 +    }
 +  else
 +    {
 +      /* window taller than device */
 +      y_scale = window_height / device_height;
 +      x_scale = (y_scale * y_resolution) / x_resolution;
 +
 +      y_offset = 0;
 +      x_offset = - (device_width * x_scale - window_width) / 2;
 +    }
 +
 +  if (axis_value)
 +    {
 +      if (axis_info.use == GDK_AXIS_X)
-         *axis_value = x_offset + x_scale * (value - axis_info.min_value);
++        *axis_value = x_offset + x_scale * (value - x_min);
 +      else
-         *axis_value = y_offset + y_scale * (value - axis_info.min_value);
++        *axis_value = y_offset + y_scale * (value - y_min);
 +    }
 +
 +  return TRUE;
 +}
 +
 +gboolean
 +_gdk_device_translate_screen_coord (GdkDevice *device,
 +                                    GdkWindow *window,
 +                                    gint       window_root_x,
 +                                    gint       window_root_y,
 +                                    guint      index,
 +                                    gdouble    value,
 +                                    gdouble   *axis_value)
 +{
 +  GdkDevicePrivate *priv;
 +  GdkAxisInfo axis_info;
 +  gdouble axis_width, scale, offset;
 +  GdkWindowObject *window_private;
 +
 +  if (device->mode != GDK_MODE_SCREEN)
 +    return FALSE;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  if (index >= priv->axes->len)
 +    return FALSE;
 +
 +  axis_info = g_array_index (priv->axes, GdkAxisInfo, index);
 +
 +  if (axis_info.use != GDK_AXIS_X &&
 +      axis_info.use != GDK_AXIS_Y)
 +    return FALSE;
 +
 +  axis_width = axis_info.max_value - axis_info.min_value;
 +  window_private = (GdkWindowObject *) window;
 +
 +  if (axis_info.use == GDK_AXIS_X)
 +    {
 +      scale = gdk_screen_get_width (gdk_drawable_get_screen (window)) / axis_width;
 +      offset = - window_root_x - window_private->abs_x;
 +    }
 +  else
 +    {
 +      scale = gdk_screen_get_height (gdk_drawable_get_screen (window)) / axis_width;
 +      offset = - window_root_y - window_private->abs_y;
 +    }
 +
 +  if (axis_value)
 +    *axis_value = offset + scale * (value - axis_info.min_value);
 +
 +  return TRUE;
 +}
 +
 +gboolean
 +_gdk_device_translate_axis (GdkDevice *device,
 +                            guint      index,
 +                            gdouble    value,
 +                            gdouble   *axis_value)
 +{
 +  GdkDevicePrivate *priv;
 +  GdkAxisInfo axis_info;
 +  gdouble axis_width, out;
 +
 +  priv = GDK_DEVICE_GET_PRIVATE (device);
 +
 +  if (index >= priv->axes->len)
 +    return FALSE;
 +
 +  axis_info = g_array_index (priv->axes, GdkAxisInfo, index);
 +
 +  if (axis_info.use == GDK_AXIS_X ||
 +      axis_info.use == GDK_AXIS_Y)
 +    return FALSE;
 +
 +  axis_width = axis_info.max_value - axis_info.min_value;
 +  out = (axis_info.max_axis * (value - axis_info.min_value) +
 +         axis_info.min_axis * (axis_info.max_value - value)) / axis_width;
 +
 +  if (axis_value)
 +    *axis_value = out;
 +
 +  return TRUE;
 +}
 +
 +#define __GDK_DEVICE_C__
 +#include "gdkaliasdef.c"
diff --cc gdk/gdkdeviceprivate.h
index 507cf28,0000000..9ce5875
mode 100644,000000..100644
--- a/gdk/gdkdeviceprivate.h
+++ b/gdk/gdkdeviceprivate.h
@@@ -1,134 -1,0 +1,135 @@@
 +/* GDK - The GIMP Drawing Kit
 + * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 + * Boston, MA 02111-1307, USA.
 + */
 +
 +#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
 +#error "Only <gdk/gdk.h> can be included directly."
 +#endif
 +
 +#ifndef __GDK_DEVICE_PRIVATE_H__
 +#define __GDK_DEVICE_PRIVATE_H__
 +
 +#include <gdk/gdkdevice.h>
 +#include <gdk/gdkevents.h>
 +
 +G_BEGIN_DECLS
 +
 +#define GDK_DEVICE_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE, GdkDeviceClass))
 +#define GDK_IS_DEVICE_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE))
 +#define GDK_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE, GdkDeviceClass))
 +
 +typedef struct _GdkDeviceClass GdkDeviceClass;
 +
 +struct _GdkDeviceClass
 +{
 +  GObjectClass parent_class;
 +
 +  gboolean (* get_history) (GdkDevice      *device,
 +                            GdkWindow      *window,
 +                            guint32         start,
 +                            guint32         stop,
 +                            GdkTimeCoord ***events,
 +                            guint          *n_events);
 +
 +  void (* get_state) (GdkDevice       *device,
 +                      GdkWindow       *window,
 +                      gdouble         *axes,
 +                      GdkModifierType *mask);
 +
 +  void (* set_window_cursor) (GdkDevice *device,
 +                              GdkWindow *window,
 +                              GdkCursor *cursor);
 +
 +  void (* warp)              (GdkDevice  *device,
 +                              GdkScreen  *screen,
 +                              gint        x,
 +                              gint        y);
 +  gboolean (* query_state)   (GdkDevice        *device,
 +                              GdkWindow        *window,
 +                              GdkWindow       **root_window,
 +                              GdkWindow       **child_window,
 +                              gint             *root_x,
 +                              gint             *root_y,
 +                              gint             *win_x,
 +                              gint             *win_y,
 +                              GdkModifierType  *mask);
 +  GdkGrabStatus (* grab)     (GdkDevice        *device,
 +                              GdkWindow        *window,
 +                              gboolean          owner_events,
 +                              GdkEventMask      event_mask,
 +                              GdkWindow        *confine_to,
 +                              GdkCursor        *cursor,
 +                              guint32           time_);
 +  void          (*ungrab)    (GdkDevice        *device,
 +                              guint32           time_);
 +
 +  GdkWindow * (* window_at_position) (GdkDevice       *device,
 +                                      gint            *win_x,
 +                                      gint            *win_y,
-                                       GdkModifierType *mask);
++                                      GdkModifierType *mask,
++                                      gboolean         get_toplevel);
 +  void (* select_window_events)      (GdkDevice       *device,
 +                                      GdkWindow       *window,
 +                                      GdkEventMask     event_mask);
 +};
 +
 +void  _gdk_device_set_relative (GdkDevice *device,
 +                                GdkDevice *relative);
 +
 +void  _gdk_device_reset_axes (GdkDevice   *device);
 +guint _gdk_device_add_axis   (GdkDevice   *device,
 +                              GdkAtom      label_atom,
 +                              GdkAxisUse   use,
 +                              gdouble      min_value,
 +                              gdouble      max_value,
 +                              gdouble      resolution);
 +
 +void _gdk_device_set_keys    (GdkDevice   *device,
 +                              guint        num_keys);
 +
 +GdkAxisUse _gdk_device_get_axis_use (GdkDevice *device,
 +                                     guint      index);
 +
 +gboolean   _gdk_device_translate_window_coord (GdkDevice *device,
 +                                               GdkWindow *window,
 +                                               guint      index,
 +                                               gdouble    value,
 +                                               gdouble   *axis_value);
 +
 +gboolean   _gdk_device_translate_screen_coord (GdkDevice *device,
 +                                               GdkWindow *window,
 +                                               gint       window_root_x,
 +                                               gint       window_root_y,
 +                                               guint      index,
 +                                               gdouble    value,
 +                                               gdouble   *axis_value);
 +
 +gboolean   _gdk_device_translate_axis         (GdkDevice *device,
 +                                               guint      index,
 +                                               gdouble    value,
 +                                               gdouble   *axis_value);
 +
 +GdkTimeCoord ** _gdk_device_allocate_history  (GdkDevice *device,
 +                                               guint      n_events);
 +
 +void _gdk_input_check_extension_events (GdkDevice *device);
 +
 +
 +G_END_DECLS
 +
 +#endif /* __GDK_DEVICE_PRIVATE_H__ */
diff --cc gdk/gdkdisplay.c
index e39e10e,c2064ba..0c5dd79
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@@ -807,7 -510,7 +807,7 @@@ gdk_display_real_get_window_at_device_p
    GdkWindow *window;
    gint x, y;
  
-   window = _gdk_windowing_window_at_device_position (display, device, &x, &y, NULL);
 -  window = _gdk_windowing_window_at_pointer (display, &x, &y, NULL, FALSE);
++  window = _gdk_windowing_window_at_device_position (display, device, &x, &y, NULL, FALSE);
  
    /* This might need corrections, as the native window returned
       may contain client side children */
@@@ -1291,9 -916,7 +1291,8 @@@ get_current_toplevel (GdkDisplay      *
    int x, y;
    GdkModifierType state;
  
-   pointer_window = _gdk_windowing_window_at_device_position (display, device, &x, &y, &state);
 -  pointer_window = _gdk_windowing_window_at_pointer (display,  &x, &y, &state, TRUE);
++  pointer_window = _gdk_windowing_window_at_device_position (display, device, &x, &y, &state, TRUE);
 +
    if (pointer_window != NULL &&
        (GDK_WINDOW_DESTROYED (pointer_window) ||
         GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
@@@ -1421,27 -1031,22 +1407,25 @@@ switch_to_pointer_grab (GdkDispla
  }
  
  void
 -_gdk_display_pointer_grab_update (GdkDisplay *display,
 -				  gulong current_serial)
 +_gdk_display_device_grab_update (GdkDisplay *display,
 +                                 GdkDevice  *device,
 +                                 gulong      current_serial)
  {
 -  GdkPointerGrabInfo *current_grab, *next_grab;
 +  GdkDeviceGrabInfo *current_grab, *next_grab;
 +  GList *grabs;
    guint32 time;
 -  
 +
    time = display->last_event_time;
 +  grabs = g_hash_table_lookup (display->device_grabs, device);
  
 -  while (display->pointer_grabs != NULL)
 +  while (grabs != NULL)
      {
 -      current_grab = display->pointer_grabs->data;
 +      current_grab = grabs->data;
  
        if (current_grab->serial_start > current_serial)
-         return; /* Hasn't started yet */
+ 	return; /* Hasn't started yet */
 -      
 +
-       if (current_grab->serial_end > current_serial ||
- 	  (current_grab->serial_end == current_serial &&
- 	   current_grab->grab_one_pointer_release_event))
+       if (current_grab->serial_end > current_serial)
  	{
  	  /* This one hasn't ended yet.
  	     its the currently active one or scheduled to be active */
diff --cc gdk/gdkinternals.h
index 3199186,0681bdc..69e4c26
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@@ -182,12 -182,10 +182,11 @@@ typedef struc
    guint event_mask;
    gboolean implicit;
    guint32 time;
 +  GdkGrabOwnership ownership;
  
 -  gboolean activated;
 -  gboolean implicit_ungrab;
 -} GdkPointerGrabInfo;
 +  guint activated : 1;
 +  guint implicit_ungrab : 1;
-   guint grab_one_pointer_release_event : 1;
 +} GdkDeviceGrabInfo;
  
  typedef struct _GdkInputWindow GdkInputWindow;
  
@@@ -473,13 -457,12 +472,14 @@@ void       _gdk_windowing_get_device_st
  					      gint             *x,
  					      gint             *y,
  					      GdkModifierType  *mask);
 -GdkWindow* _gdk_windowing_window_at_pointer  (GdkDisplay       *display,
 -					      gint             *win_x,
 -					      gint             *win_y,
 -					      GdkModifierType  *mask,
 -					      gboolean          get_toplevel);
 -GdkGrabStatus _gdk_windowing_pointer_grab    (GdkWindow        *window,
 +GdkWindow* _gdk_windowing_window_at_device_position  (GdkDisplay       *display,
 +                                                      GdkDevice        *device,
 +                                                      gint             *win_x,
 +                                                      gint             *win_y,
-                                                       GdkModifierType  *mask);
++                                                      GdkModifierType  *mask,
++                                                      gboolean          get_toplevel);
 +GdkGrabStatus _gdk_windowing_device_grab     (GdkDevice        *device,
 +                                              GdkWindow        *window,
  					      GdkWindow        *native,
  					      gboolean          owner_events,
  					      GdkEventMask      event_mask,
diff --cc gdk/gdkwindow.c
index 17d35a4,2bb5551..fd1bfaa
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@@ -1197,37 -1160,67 +1198,73 @@@ get_native_device_event_mask (GdkWindow
    if (_gdk_native_windows ||
        private->window_type == GDK_WINDOW_ROOT ||
        private->window_type == GDK_WINDOW_FOREIGN)
 -    return private->event_mask;
 +    return event_mask;
    else
      {
-       return
- 	/* We need thse for all native window so we can emulate
- 	   events on children: */
+       GdkEventMask mask;
+ 
+       /* Do whatever the app asks to, since the app
+        * may be asking for weird things for native windows,
+        * but filter out things that override the special
+        * requests below. */
+       mask = private->event_mask &
+ 	~(GDK_POINTER_MOTION_HINT_MASK |
+ 	  GDK_BUTTON_MOTION_MASK |
+ 	  GDK_BUTTON1_MOTION_MASK |
+ 	  GDK_BUTTON2_MOTION_MASK |
+ 	  GDK_BUTTON3_MOTION_MASK);
+ 
+       /* We need thse for all native windows so we can
+ 	 emulate events on children: */
+       mask |=
  	GDK_EXPOSURE_MASK |
  	GDK_VISIBILITY_NOTIFY_MASK |
- 	GDK_POINTER_MOTION_MASK |
- 	GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- 	GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
- 	GDK_SCROLL_MASK |
- 	/* Then do whatever the app asks to, since the app
- 	 * may be asking for weird things for native windows,
- 	 * but filter out things that override the above
- 	 * requests somehow. */
- 	(event_mask &
- 	 ~(GDK_POINTER_MOTION_HINT_MASK |
- 	   GDK_BUTTON_MOTION_MASK |
- 	   GDK_BUTTON1_MOTION_MASK |
- 	   GDK_BUTTON2_MOTION_MASK |
- 	   GDK_BUTTON3_MOTION_MASK));
+ 	GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
+ 
+       /* Additionally we select for pointer and button events
+        * for toplevels as we need to get these to emulate
+        * them for non-native subwindows. Even though we don't
+        * select on them for all native windows we will get them
+        * as the events are propagated out to the first window
+        * that select for them.
+        * Not selecting for button press on all windows is an
+        * important thing, because in X only one client can do
+        * so, and we don't want to unexpectedly prevent another
+        * client from doing it.
+        */
+       if (gdk_window_is_toplevel (private))
+ 	mask |=
+ 	  GDK_POINTER_MOTION_MASK |
+ 	  GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ 	  GDK_SCROLL_MASK;
+ 
+       return mask;
      }
  }
  
  static GdkEventMask
+ get_native_grab_event_mask (GdkEventMask grab_mask)
+ {
+   /* Similar to the above but for pointer events only */
+   return
+     GDK_POINTER_MOTION_MASK |
+     GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+     GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+     GDK_SCROLL_MASK |
+     (grab_mask &
+      ~(GDK_POINTER_MOTION_HINT_MASK |
+        GDK_BUTTON_MOTION_MASK |
+        GDK_BUTTON1_MOTION_MASK |
+        GDK_BUTTON2_MOTION_MASK |
+        GDK_BUTTON3_MOTION_MASK));
+ }
+ 
++static GdkEventMask
 +get_native_event_mask (GdkWindowObject *private)
 +{
 +  return get_native_device_event_mask (private, NULL);
 +}
 +
  /* Puts the native window in the right order wrt the other native windows
   * in the hierarchy, given the position it has in the client side data.
   * This is useful if some operation changed the stacking order.
@@@ -6822,26 -6778,27 +6865,26 @@@ gdk_window_hide (GdkWindow *window
  
        /* May need to break grabs on children */
        display = gdk_drawable_get_display (window);
 +      device_manager = gdk_display_get_device_manager (display);
  
 -      if (_gdk_display_end_pointer_grab (display,
 -					 _gdk_windowing_window_get_next_serial (display),
 -					 window,
 -					 TRUE))
 -	gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
 +      /* Get all devices */
 +      devices = gdk_device_manager_get_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 +      devices = g_list_concat (devices, gdk_device_manager_get_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
 +      devices = g_list_concat (devices, gdk_device_manager_get_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
  
 -      if (display->keyboard_grab.window != NULL)
 -	{
 -	  if (is_parent_of (window, display->keyboard_grab.window))
 -	    {
 -	      /* Call this ourselves, even though gdk_display_keyboard_ungrab
 -		 does so too, since we want to pass implicit == TRUE so the
 -		 broken grab event is generated */
 -	      _gdk_display_unset_has_keyboard_grab (display,
 -						    TRUE);
 -	      gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
 -	    }
 -	}
 +      for (d = devices; d; d = d->next)
 +        {
 +          GdkDevice *device = d->data;
 +
 +          if (_gdk_display_end_device_grab (display, device,
 +                                            _gdk_windowing_window_get_next_serial (display),
 +                                            window,
 +                                            TRUE))
-             gdk_display_device_ungrab (display, device, GDK_CURRENT_TIME);
++            gdk_device_ungrab (device, GDK_CURRENT_TIME);
 +        }
  
        private->state = GDK_WINDOW_STATE_WITHDRAWN;
 +      g_list_free (devices);
      }
  
    did_hide = _gdk_window_update_viewable (window);
@@@ -9938,123 -9599,24 +9981,123 @@@ gdk_pointer_grab (GdkWindow *	  window
    display = gdk_drawable_get_display (window);
  
    serial = _gdk_windowing_window_get_next_serial (display);
 +  device_manager = gdk_display_get_device_manager (display);
 +  devices = gdk_device_manager_get_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 +
 +  /* FIXME: Should this be generic to all backends? */
 +  /* FIXME: What happens with extended devices? */
 +  for (dev = devices; dev; dev = dev->next)
 +    {
 +      device = dev->data;
 +
 +      if (device->source != GDK_SOURCE_MOUSE)
 +        continue;
 +
 +      res = _gdk_windowing_device_grab (device,
 +                                        window,
 +                                        native,
 +                                        owner_events,
-                                         event_mask,
++                                        get_native_grab_event_mask (event_mask),
 +                                        confine_to,
 +                                        cursor,
 +                                        time);
 +
 +      if (res == GDK_GRAB_SUCCESS)
 +        _gdk_display_add_device_grab (display,
 +                                      device,
 +                                      window,
 +                                      native,
 +                                      GDK_OWNERSHIP_NONE,
 +                                      owner_events,
 +                                      event_mask,
 +                                      serial,
 +                                      time,
 +                                      FALSE);
 +    }
 +
 +  /* FIXME: handle errors when grabbing */
 +
 +  g_list_free (devices);
 +
 +  return res;
 +}
 +
 +GdkGrabStatus
 +gdk_keyboard_grab (GdkWindow *window,
 +		   gboolean   owner_events,
 +		   guint32    time)
 +{
 +  GdkWindow *native;
 +  GdkDisplay *display;
 +  GdkDeviceManager *device_manager;
 +  GdkDevice *device;
 +  GdkGrabStatus res = 0;
 +  gulong serial;
 +  GList *devices, *dev;
 +
 +  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 +
 +  /* Non-viewable client side window => fail */
 +  if (!_gdk_window_has_impl (window) &&
 +      !gdk_window_is_viewable (window))
 +    return GDK_GRAB_NOT_VIEWABLE;
 +
 +  if (_gdk_native_windows)
 +    native = window;
 +  else
 +    native = gdk_window_get_toplevel (window);
 +
 +  while (gdk_window_is_offscreen ((GdkWindowObject *)native))
 +    {
 +      native = gdk_offscreen_window_get_embedder (native);
 +
 +      if (native == NULL ||
 +	  (!_gdk_window_has_impl (native) &&
 +	   !gdk_window_is_viewable (native)))
 +	return GDK_GRAB_NOT_VIEWABLE;
 +
 +      native = gdk_window_get_toplevel (native);
 +    }
 +
 +  display = gdk_drawable_get_display (window);
 +
 +  serial = _gdk_windowing_window_get_next_serial (display);
 +  device_manager = gdk_display_get_device_manager (display);
 +  devices = gdk_device_manager_get_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 +
 +  /* FIXME: Should this be generic to all backends? */
 +  /* FIXME: What happens with extended devices? */
 +  for (dev = devices; dev; dev = dev->next)
 +    {
 +      device = dev->data;
 +
 +      if (device->source != GDK_SOURCE_KEYBOARD)
 +        continue;
  
 -  res = _gdk_windowing_pointer_grab (window,
 -				     native,
 -				     owner_events,
 -				     get_native_grab_event_mask (event_mask),
 -				     confine_to,
 -				     cursor,
 -				     time);
 -
 -  if (res == GDK_GRAB_SUCCESS)
 -    _gdk_display_add_pointer_grab (display,
 -				   window,
 -				   native,
 -				   owner_events,
 -				   event_mask,
 -				   serial,
 -				   time,
 -				   FALSE);
 +      res = _gdk_windowing_device_grab (device,
 +                                        window,
 +                                        native,
 +                                        owner_events,
 +                                        GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
 +                                        NULL,
 +                                        NULL,
 +                                        time);
 +
 +      if (res == GDK_GRAB_SUCCESS)
 +        _gdk_display_add_device_grab (display,
 +                                      device,
 +                                      window,
 +                                      native,
 +                                      GDK_OWNERSHIP_NONE,
 +                                      owner_events, 0,
 +                                      serial,
 +                                      time,
 +                                      FALSE);
 +    }
 +
 +  /* FIXME: handle errors when grabbing */
 +
 +  g_list_free (devices);
  
    return res;
  }
@@@ -10455,7 -9988,8 +10498,8 @@@ proxy_button_event (GdkEvent *source_ev
  						       &toplevel_x, &toplevel_y);
  
    if (type == GDK_BUTTON_PRESS &&
+       !source_event->any.send_event &&
 -      _gdk_display_has_pointer_grab (display, serial) == NULL)
 +      _gdk_display_has_device_grab (display, device, serial) == NULL)
      {
        pointer_window =
  	_gdk_window_find_descendant_at (toplevel_window,
@@@ -10677,24 -10198,25 +10721,26 @@@ _gdk_windowing_got_event (GdkDisplay *d
    if (_gdk_native_windows)
      {
        if (event->type == GDK_BUTTON_PRESS &&
+ 	  !event->any.send_event &&
 -	  _gdk_display_has_pointer_grab (display, serial) == NULL)
 +	  _gdk_display_has_device_grab (display, device, serial) == NULL)
  	{
 -	  _gdk_display_add_pointer_grab  (display,
 -					  event_window,
 -					  event_window,
 -					  FALSE,
 -					  gdk_window_get_events (event_window),
 -					  serial,
 -					  gdk_event_get_time (event),
 -					  TRUE);
 -	  _gdk_display_pointer_grab_update (display,
 -					    serial);
 +	  _gdk_display_add_device_grab  (display,
 +                                         device,
 +                                         event_window,
 +                                         event_window,
 +                                         GDK_OWNERSHIP_NONE,
 +                                         FALSE,
 +                                         gdk_window_get_events (event_window),
 +                                         serial,
 +                                         gdk_event_get_time (event),
 +                                         TRUE);
 +	  _gdk_display_device_grab_update (display, device, serial);
  	}
-       if (event->type == GDK_BUTTON_RELEASE)
+       if (event->type == GDK_BUTTON_RELEASE &&
+ 	  !event->any.send_event)
  	{
  	  button_release_grab =
 -	    _gdk_display_has_pointer_grab (display, serial);
 +            _gdk_display_has_device_grab (display, device, serial);
  	  if (button_release_grab &&
  	      button_release_grab->implicit &&
  	      (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
@@@ -10811,10 -10336,11 +10857,11 @@@
      unlink_event = proxy_button_event (event,
  				       serial);
  
-   if (event->type == GDK_BUTTON_RELEASE)
+   if (event->type == GDK_BUTTON_RELEASE &&
+       !event->any.send_event)
      {
        button_release_grab =
 -	_gdk_display_has_pointer_grab (display, serial);
 +	_gdk_display_has_device_grab (display, device, serial);
        if (button_release_grab &&
  	  button_release_grab->implicit &&
  	  (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
diff --cc gdk/x11/gdkdevice-core.c
index c2506ff,0000000..56dc148
mode 100644,000000..100644
--- a/gdk/x11/gdkdevice-core.c
+++ b/gdk/x11/gdkdevice-core.c
@@@ -1,489 -1,0 +1,496 @@@
 +/* GDK - The GIMP Drawing Kit
 + * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 + * Boston, MA 02111-1307, USA.
 + */
 +
 +#include <gdk/gdkwindow.h>
 +#include "gdkdevice-core.h"
 +#include "gdkprivate-x11.h"
 +#include "gdkx.h"
 +
 +static gboolean gdk_device_core_get_history (GdkDevice      *device,
 +                                             GdkWindow      *window,
 +                                             guint32         start,
 +                                             guint32         stop,
 +                                             GdkTimeCoord ***events,
 +                                             guint          *n_events);
 +static void gdk_device_core_get_state (GdkDevice       *device,
 +                                       GdkWindow       *window,
 +                                       gdouble         *axes,
 +                                       GdkModifierType *mask);
 +static void gdk_device_core_set_window_cursor (GdkDevice *device,
 +                                               GdkWindow *window,
 +                                               GdkCursor *cursor);
 +static void gdk_device_core_warp (GdkDevice *device,
 +                                  GdkScreen *screen,
 +                                  gint       x,
 +                                  gint       y);
 +static gboolean gdk_device_core_query_state (GdkDevice        *device,
 +                                             GdkWindow        *window,
 +                                             GdkWindow       **root_window,
 +                                             GdkWindow       **child_window,
 +                                             gint             *root_x,
 +                                             gint             *root_y,
 +                                             gint             *win_x,
 +                                             gint             *win_y,
 +                                             GdkModifierType  *mask);
 +static GdkGrabStatus gdk_device_core_grab   (GdkDevice     *device,
 +                                             GdkWindow     *window,
 +                                             gboolean       owner_events,
 +                                             GdkEventMask   event_mask,
 +                                             GdkWindow     *confine_to,
 +                                             GdkCursor     *cursor,
 +                                             guint32        time_);
 +static void          gdk_device_core_ungrab (GdkDevice     *device,
 +                                             guint32        time_);
 +static GdkWindow * gdk_device_core_window_at_position (GdkDevice       *device,
 +                                                       gint            *win_x,
 +                                                       gint            *win_y,
-                                                        GdkModifierType *mask);
++                                                       GdkModifierType *mask,
++                                                       gboolean         get_toplevel);
 +static void      gdk_device_core_select_window_events (GdkDevice       *device,
 +                                                       GdkWindow       *window,
 +                                                       GdkEventMask     event_mask);
 +
 +
 +G_DEFINE_TYPE (GdkDeviceCore, gdk_device_core, GDK_TYPE_DEVICE)
 +
 +static void
 +gdk_device_core_class_init (GdkDeviceCoreClass *klass)
 +{
 +  GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
 +
 +  device_class->get_history = gdk_device_core_get_history;
 +  device_class->get_state = gdk_device_core_get_state;
 +  device_class->set_window_cursor = gdk_device_core_set_window_cursor;
 +  device_class->warp = gdk_device_core_warp;
 +  device_class->query_state = gdk_device_core_query_state;
 +  device_class->grab = gdk_device_core_grab;
 +  device_class->ungrab = gdk_device_core_ungrab;
 +  device_class->window_at_position = gdk_device_core_window_at_position;
 +  device_class->select_window_events = gdk_device_core_select_window_events;
 +}
 +
 +static void
 +gdk_device_core_init (GdkDeviceCore *device_core)
 +{
 +  GdkDevice *device;
 +
 +  device = GDK_DEVICE (device_core);
 +
 +  _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
 +  _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
 +}
 +
 +static gboolean
 +impl_coord_in_window (GdkWindow *window,
 +		      int        impl_x,
 +		      int        impl_y)
 +{
 +  GdkWindowObject *priv = (GdkWindowObject *) window;
 +
 +  if (impl_x < priv->abs_x ||
 +      impl_x > priv->abs_x + priv->width)
 +    return FALSE;
 +
 +  if (impl_y < priv->abs_y ||
 +      impl_y > priv->abs_y + priv->height)
 +    return FALSE;
 +
 +  return TRUE;
 +}
 +
 +static gboolean
 +gdk_device_core_get_history (GdkDevice      *device,
 +                             GdkWindow      *window,
 +                             guint32         start,
 +                             guint32         stop,
 +                             GdkTimeCoord ***events,
 +                             guint          *n_events)
 +{
 +  GdkWindowObject *priv;
 +  XTimeCoord *xcoords;
 +  GdkTimeCoord **coords;
 +  GdkWindow *impl_window;
 +  int tmp_n_events;
 +  int i, j;
 +
 +  impl_window = _gdk_window_get_impl_window (window);
 +  xcoords = XGetMotionEvents (GDK_DRAWABLE_XDISPLAY (window),
 +                              GDK_DRAWABLE_XID (impl_window),
 +                              start, stop, &tmp_n_events);
 +  if (!xcoords)
 +    return FALSE;
 +
 +  priv = (GdkWindowObject *) window;
 +  coords = _gdk_device_allocate_history (device, tmp_n_events);
 +
 +  for (i = 0, j = 0; i < tmp_n_events; i++)
 +    {
 +      if (impl_coord_in_window (window, xcoords[i].x, xcoords[i].y))
 +        {
 +          coords[j]->time = xcoords[i].time;
 +          coords[j]->axes[0] = xcoords[i].x - priv->abs_x;
 +          coords[j]->axes[1] = xcoords[i].y - priv->abs_y;
 +          j++;
 +        }
 +    }
 +
 +  XFree (xcoords);
 +
 +  /* free the events we allocated too much */
 +  for (i = j; i < tmp_n_events; i++)
 +    {
 +      g_free (coords[i]);
 +      coords[i] = NULL;
 +    }
 +
 +  tmp_n_events = j;
 +
 +  if (tmp_n_events == 0)
 +    {
 +      gdk_device_free_history (coords, tmp_n_events);
 +      return FALSE;
 +    }
 +
 +  if (n_events)
 +    *n_events = tmp_n_events;
 +
 +  if (events)
 +    *events = coords;
 +  else if (coords)
 +    gdk_device_free_history (coords, tmp_n_events);
 +
 +  return TRUE;
 +}
 +
 +static void
 +gdk_device_core_get_state (GdkDevice       *device,
 +                           GdkWindow       *window,
 +                           gdouble         *axes,
 +                           GdkModifierType *mask)
 +{
 +  gint x_int, y_int;
 +
 +  gdk_window_get_pointer (window, &x_int, &y_int, mask);
 +
 +  if (axes)
 +    {
 +      axes[0] = x_int;
 +      axes[1] = y_int;
 +    }
 +}
 +
 +static void
 +gdk_device_core_set_window_cursor (GdkDevice *device,
 +                                   GdkWindow *window,
 +                                   GdkCursor *cursor)
 +{
 +  GdkCursorPrivate *cursor_private;
 +  Cursor xcursor;
 +
 +  cursor_private = (GdkCursorPrivate*) cursor;
 +
 +  if (!cursor)
 +    xcursor = None;
 +  else
 +    xcursor = cursor_private->xcursor;
 +
 +  XDefineCursor (GDK_WINDOW_XDISPLAY (window),
 +                 GDK_WINDOW_XID (window),
 +                 xcursor);
 +}
 +
 +static void
 +gdk_device_core_warp (GdkDevice *device,
 +                      GdkScreen *screen,
 +                      gint       x,
 +                      gint       y)
 +{
 +  Display *xdisplay;
 +  Window dest;
 +
 +  xdisplay = GDK_DISPLAY_XDISPLAY (gdk_device_get_display (device));
 +  dest = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
 +
 +  XWarpPointer (xdisplay, None, dest, 0, 0, 0, 0, x, y);
 +}
 +
 +static gboolean
 +gdk_device_core_query_state (GdkDevice        *device,
 +                             GdkWindow        *window,
 +                             GdkWindow       **root_window,
 +                             GdkWindow       **child_window,
 +                             gint             *root_x,
 +                             gint             *root_y,
 +                             gint             *win_x,
 +                             gint             *win_y,
 +                             GdkModifierType  *mask)
 +{
 +  GdkDisplay *display;
 +  Window xroot_window, xchild_window;
 +  int xroot_x, xroot_y, xwin_x, xwin_y;
 +  unsigned int xmask;
 +
 +  display = gdk_drawable_get_display (window);
 +
 +  if (!XQueryPointer (GDK_WINDOW_XDISPLAY (window),
 +                      GDK_WINDOW_XID (window),
 +                      &xroot_window,
 +                      &xchild_window,
 +                      &xroot_x,
 +                      &xroot_y,
 +                      &xwin_x,
 +                      &xwin_y,
 +                      &xmask))
 +    {
 +      return FALSE;
 +    }
 +
 +  if (root_window)
 +    *root_window = gdk_window_lookup_for_display (display, xroot_window);
 +
 +  if (child_window)
 +    *child_window = gdk_window_lookup_for_display (display, xchild_window);
 +
 +  if (root_x)
 +    *root_x = xroot_x;
 +
 +  if (root_y)
 +    *root_y = xroot_y;
 +
 +  if (win_x)
 +    *win_x = xwin_x;
 +
 +  if (win_y)
 +    *win_y = xwin_y;
 +
 +  if (mask)
 +    *mask = xmask;
 +
 +  return TRUE;
 +}
 +
 +static GdkGrabStatus
 +gdk_device_core_grab (GdkDevice    *device,
 +                      GdkWindow    *window,
 +                      gboolean      owner_events,
 +                      GdkEventMask  event_mask,
 +                      GdkWindow    *confine_to,
 +                      GdkCursor    *cursor,
 +                      guint32       time_)
 +{
 +  GdkDisplay *display;
 +  Window xwindow, xconfine_to;
 +  int status;
 +
 +  display = gdk_device_get_display (device);
 +
 +  xwindow = GDK_WINDOW_XID (window);
 +
 +  if (confine_to)
 +    confine_to = _gdk_window_get_impl_window (confine_to);
 +
 +  if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
 +    xconfine_to = None;
 +  else
 +    xconfine_to = GDK_WINDOW_XID (confine_to);
 +
 +  if (device->source == GDK_SOURCE_KEYBOARD)
 +    {
 +      /* Device is a keyboard */
 +      status = XGrabKeyboard (GDK_DISPLAY_XDISPLAY (display),
 +                              xwindow,
 +                              owner_events,
 +                              GrabModeAsync, GrabModeAsync,
 +                              time_);
 +    }
 +  else
 +    {
 +      Cursor xcursor;
 +      guint xevent_mask;
 +      gint i;
 +
 +      /* Device is a pointer */
 +      if (!cursor)
 +        xcursor = None;
 +      else
 +        {
 +          _gdk_x11_cursor_update_theme (cursor);
 +          xcursor = ((GdkCursorPrivate *) cursor)->xcursor;
 +        }
 +
 +      xevent_mask = 0;
 +
 +      for (i = 0; i < _gdk_nenvent_masks; i++)
 +        {
 +          if (event_mask & (1 << (i + 1)))
 +            xevent_mask |= _gdk_event_mask_table[i];
 +        }
 +
 +      /* We don't want to set a native motion hint mask, as we're emulating motion
 +       * hints. If we set a native one we just wouldn't get any events.
 +       */
 +      xevent_mask &= ~PointerMotionHintMask;
 +
 +      status = XGrabPointer (GDK_DISPLAY_XDISPLAY (display),
 +                             xwindow,
 +                             owner_events,
 +                             xevent_mask,
 +                             GrabModeAsync, GrabModeAsync,
 +                             xconfine_to,
 +                             xcursor,
 +                             time_);
 +    }
 +
 +  return gdk_x11_convert_grab_status (status);
 +}
 +
 +static void
 +gdk_device_core_ungrab (GdkDevice *device,
 +                        guint32    time_)
 +{
 +  GdkDisplay *display;
 +
 +  display = gdk_device_get_display (device);
 +
 +  if (device->source == GDK_SOURCE_KEYBOARD)
 +    XUngrabKeyboard (GDK_DISPLAY_XDISPLAY (display), time_);
 +  else
 +    XUngrabPointer (GDK_DISPLAY_XDISPLAY (display), time_);
 +}
 +
 +static GdkWindow *
 +gdk_device_core_window_at_position (GdkDevice       *device,
 +                                    gint            *win_x,
 +                                    gint            *win_y,
-                                     GdkModifierType *mask)
++                                    GdkModifierType *mask,
++                                    gboolean         get_toplevel)
 +{
 +  GdkDisplay *display;
 +  GdkScreen *screen;
 +  Display *xdisplay;
 +  GdkWindow *window;
 +  Window xwindow, root, child, last;
 +  int xroot_x, xroot_y, xwin_x, xwin_y;
 +  unsigned int xmask;
 +
 +  last = None;
 +  display = gdk_device_get_display (device);
 +  screen = gdk_display_get_default_screen (display);
 +
 +  /* This function really only works if the mouse pointer is held still
 +   * during its operation. If it moves from one leaf window to another
 +   * than we'll end up with inaccurate values for win_x, win_y
 +   * and the result.
 +   */
 +  gdk_x11_display_grab (display);
 +
 +  xdisplay = GDK_SCREEN_XDISPLAY (screen);
 +  xwindow = GDK_SCREEN_XROOTWIN (screen);
 +
 +  XQueryPointer (xdisplay, xwindow,
 +                 &root, &child,
 +                 &xroot_x, &xroot_y,
 +                 &xwin_x, &xwin_y,
 +                 &xmask);
 +
 +  if (root == xwindow)
 +    xwindow = child;
 +  else
 +    xwindow = root;
 +
 +  while (xwindow)
 +    {
 +      last = xwindow;
 +      XQueryPointer (xdisplay, xwindow,
 +                     &root, &xwindow,
 +                     &xroot_x, &xroot_y,
 +                     &xwin_x, &xwin_y,
 +                     &xmask);
++
++      if (get_toplevel &&
++          (window = gdk_window_lookup_for_display (display, last)) != NULL &&
++          GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
++        break;
 +    }
 +
 +  gdk_x11_display_ungrab (display);
 +
 +  window = gdk_window_lookup_for_display (display, last);
 +
 +  if (win_x)
 +    *win_x = (window) ? xwin_x : -1;
 +
 +  if (win_y)
 +    *win_y = (window) ? xwin_y : -1;
 +
 +  if (mask)
 +    *mask = xmask;
 +
 +  return window;
 +}
 +
 +static void
 +gdk_device_core_select_window_events (GdkDevice    *device,
 +                                      GdkWindow    *window,
 +                                      GdkEventMask  event_mask)
 +{
 +  GdkEventMask filter_mask, window_mask;
 +  guint xmask = 0;
 +  gint i;
 +
 +  window_mask = gdk_window_get_events (window);
 +  filter_mask = (GDK_POINTER_MOTION_MASK &
 +                 GDK_POINTER_MOTION_HINT_MASK &
 +                 GDK_BUTTON_MOTION_MASK &
 +                 GDK_BUTTON1_MOTION_MASK &
 +                 GDK_BUTTON2_MOTION_MASK &
 +                 GDK_BUTTON3_MOTION_MASK &
 +                 GDK_BUTTON_PRESS_MASK &
 +                 GDK_BUTTON_RELEASE_MASK &
 +                 GDK_KEY_PRESS_MASK &
 +                 GDK_KEY_RELEASE_MASK &
 +                 GDK_ENTER_NOTIFY_MASK &
 +                 GDK_LEAVE_NOTIFY_MASK &
 +                 GDK_FOCUS_CHANGE_MASK &
 +                 GDK_PROXIMITY_IN_MASK &
 +                 GDK_PROXIMITY_OUT_MASK &
 +                 GDK_SCROLL_MASK);
 +
 +  /* Filter out non-device events */
 +  event_mask &= filter_mask;
 +
 +  /* Unset device events on window mask */
 +  window_mask &= ~(filter_mask);
 +
 +  /* Combine masks */
 +  event_mask |= window_mask;
 +
 +  for (i = 0; i < _gdk_nenvent_masks; i++)
 +    {
 +      if (event_mask & (1 << (i + 1)))
 +        xmask |= _gdk_event_mask_table[i];
 +    }
 +
 +  if (GDK_WINDOW_XID (window) != GDK_WINDOW_XROOTWIN (window))
 +    xmask |= StructureNotifyMask | PropertyChangeMask;
 +
 +  XSelectInput (GDK_WINDOW_XDISPLAY (window),
 +                GDK_WINDOW_XWINDOW (window),
 +                xmask);
 +}
diff --cc gdk/x11/gdkdevice-xi.c
index 1ecb438,0000000..ca98321
mode 100644,000000..100644
--- a/gdk/x11/gdkdevice-xi.c
+++ b/gdk/x11/gdkdevice-xi.c
@@@ -1,630 -1,0 +1,622 @@@
 +/* GDK - The GIMP Drawing Kit
 + * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 + * Boston, MA 02111-1307, USA.
 + */
 +
 +#include <gdk/gdkwindow.h>
 +#include "gdkdeviceprivate.h"
 +#include "gdkdevice-xi.h"
 +#include "gdkprivate-x11.h"
 +#include "gdkintl.h"
 +#include "gdkx.h"
 +
 +#define MAX_DEVICE_CLASSES 13
 +
 +static GQuark quark_window_input_info = 0;
 +
 +typedef struct
 +{
 +  gdouble root_x;
 +  gdouble root_y;
 +} GdkWindowInputInfo;
 +
 +static void gdk_device_xi_constructed  (GObject *object);
++static void gdk_device_xi_dispose      (GObject *object);
++
 +static void gdk_device_xi_set_property (GObject      *object,
 +                                        guint         prop_id,
 +                                        const GValue *value,
 +                                        GParamSpec   *pspec);
 +static void gdk_device_xi_get_property (GObject      *object,
 +                                        guint         prop_id,
 +                                        GValue       *value,
 +                                        GParamSpec   *pspec);
 +
 +static gboolean gdk_device_xi_get_history (GdkDevice      *device,
 +                                           GdkWindow      *window,
 +                                           guint32         start,
 +                                           guint32         stop,
 +                                           GdkTimeCoord ***events,
 +                                           guint          *n_events);
 +
 +static void gdk_device_xi_get_state       (GdkDevice       *device,
 +                                           GdkWindow       *window,
 +                                           gdouble         *axes,
 +                                           GdkModifierType *mask);
 +static void gdk_device_xi_set_window_cursor (GdkDevice *device,
 +                                             GdkWindow *window,
 +                                             GdkCursor *cursor);
 +static void gdk_device_xi_warp              (GdkDevice *device,
 +                                             GdkScreen *screen,
 +                                             gint       x,
 +                                             gint       y);
 +static gboolean gdk_device_xi_query_state   (GdkDevice        *device,
 +                                             GdkWindow        *window,
 +                                             GdkWindow       **root_window,
 +                                             GdkWindow       **child_window,
 +                                             gint             *root_x,
 +                                             gint             *root_y,
 +                                             gint             *win_x,
 +                                             gint             *win_y,
 +                                             GdkModifierType  *mask);
 +static GdkGrabStatus gdk_device_xi_grab     (GdkDevice    *device,
 +                                             GdkWindow    *window,
 +                                             gboolean      owner_events,
 +                                             GdkEventMask  event_mask,
 +                                             GdkWindow    *confine_to,
 +                                             GdkCursor    *cursor,
 +                                             guint32       time_);
 +static void          gdk_device_xi_ungrab   (GdkDevice    *device,
 +                                             guint32       time_);
 +
 +static GdkWindow* gdk_device_xi_window_at_position (GdkDevice       *device,
 +                                                    gint            *win_x,
 +                                                    gint            *win_y,
-                                                     GdkModifierType *mask);
++                                                    GdkModifierType *mask,
++                                                    gboolean         get_toplevel);
 +
 +static void gdk_device_xi_select_window_events (GdkDevice    *device,
 +                                                GdkWindow    *window,
 +                                                GdkEventMask  mask);
 +
 +
 +G_DEFINE_TYPE (GdkDeviceXI, gdk_device_xi, GDK_TYPE_DEVICE)
 +
 +enum {
 +  PROP_0,
 +  PROP_DEVICE_ID
 +};
 +
 +static void
 +gdk_device_xi_class_init (GdkDeviceXIClass *klass)
 +{
 +  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 +  GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
 +
 +  quark_window_input_info = g_quark_from_static_string ("gdk-window-input-info");
 +
 +  object_class->constructed = gdk_device_xi_constructed;
 +  object_class->set_property = gdk_device_xi_set_property;
 +  object_class->get_property = gdk_device_xi_get_property;
 +  object_class->dispose = gdk_device_xi_dispose;
 +
 +  device_class->get_history = gdk_device_xi_get_history;
 +  device_class->get_state = gdk_device_xi_get_state;
 +  device_class->set_window_cursor = gdk_device_xi_set_window_cursor;
 +  device_class->warp = gdk_device_xi_warp;
 +  device_class->query_state = gdk_device_xi_query_state;
 +  device_class->grab = gdk_device_xi_grab;
 +  device_class->ungrab = gdk_device_xi_ungrab;
 +  device_class->window_at_position = gdk_device_xi_window_at_position;
 +  device_class->select_window_events = gdk_device_xi_select_window_events;
 +
 +  g_object_class_install_property (object_class,
 +				   PROP_DEVICE_ID,
 +				   g_param_spec_int ("device-id",
 +                                                     P_("Device ID"),
 +                                                     P_("Device ID"),
 +                                                     0, G_MAXINT, 0,
 +                                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 +}
 +
 +static void
 +gdk_device_xi_init (GdkDeviceXI *device)
 +{
 +}
 +
 +static void
 +gdk_device_xi_constructed (GObject *object)
 +{
 +  GdkDeviceXI *device;
 +  GdkDisplay *display;
 +
 +  device = GDK_DEVICE_XI (object);
 +  display = gdk_device_get_display (GDK_DEVICE (object));
 +
 +  gdk_error_trap_push ();
 +  device->xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (display),
 +                                 device->device_id);
 +
 +  if (gdk_error_trap_pop ())
 +    g_warning ("Device %s can't be opened", GDK_DEVICE (device)->name);
 +
 +  if (G_OBJECT_CLASS (gdk_device_xi_parent_class)->constructed)
 +    G_OBJECT_CLASS (gdk_device_xi_parent_class)->constructed (object);
 +}
 +
 +static void
 +gdk_device_xi_set_property (GObject      *object,
 +                            guint         prop_id,
 +                            const GValue *value,
 +                            GParamSpec   *pspec)
 +{
 +  GdkDeviceXI *device = GDK_DEVICE_XI (object);
 +
 +  switch (prop_id)
 +    {
 +    case PROP_DEVICE_ID:
 +      device->device_id = g_value_get_int (value);
 +      break;
 +    default:
 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 +      break;
 +    }
 +}
 +
 +static void
 +gdk_device_xi_get_property (GObject    *object,
 +                            guint       prop_id,
 +                            GValue     *value,
 +                            GParamSpec *pspec)
 +{
 +  GdkDeviceXI *device = GDK_DEVICE_XI (object);
 +
 +  switch (prop_id)
 +    {
 +    case PROP_DEVICE_ID:
 +      g_value_set_int (value, device->device_id);
 +      break;
 +    default:
 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 +      break;
 +    }
 +}
 +
 +static void
 +gdk_device_xi_dispose (GObject *object)
 +{
 +  GdkDeviceXI *device_xi;
 +  GdkDisplay *display;
 +
 +  device_xi = GDK_DEVICE_XI (object);
 +  display = gdk_device_get_display (GDK_DEVICE (device_xi));
 +
 +  if (device_xi->xdevice)
 +    {
 +      XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device_xi->xdevice);
 +      device_xi->xdevice = NULL;
 +    }
 +
++  if (device_xi->axis_data)
++    {
++      g_free (device_xi->axis_data);
++      device_xi->axis_data = NULL;
++    }
++
 +  G_OBJECT_CLASS (gdk_device_xi_parent_class)->dispose (object);
 +}
 +
 +static gboolean
 +gdk_device_xi_get_history (GdkDevice      *device,
 +                           GdkWindow      *window,
 +                           guint32         start,
 +                           guint32         stop,
 +                           GdkTimeCoord ***events,
 +                           guint          *n_events)
 +{
 +  GdkTimeCoord **coords;
 +  XDeviceTimeCoord *device_coords;
 +  GdkWindow *impl_window;
 +  GdkDeviceXI *device_xi;
 +  gint n_events_return;
 +  gint mode_return;
 +  gint axis_count_return;
 +  gint i;
 +
 +  device_xi = GDK_DEVICE_XI (device);
 +  impl_window = _gdk_window_get_impl_window (window);
 +
 +  device_coords = XGetDeviceMotionEvents (GDK_WINDOW_XDISPLAY (impl_window),
 +					  device_xi->xdevice,
 +					  start, stop,
 +					  &n_events_return,
 +                                          &mode_return,
 +					  &axis_count_return);
 +
 +  if (!device_coords)
 +    return FALSE;
 +
 +  *n_events = (guint) n_events_return;
 +  coords = _gdk_device_allocate_history (device, *n_events);
 +
 +  for (i = 0; i < *n_events; i++)
 +    {
 +      coords[i]->time = device_coords[i].time;
 +      gdk_device_xi_translate_axes (device, window,
 +                                    device_coords[i].data,
 +                                    coords[i]->axes,
 +                                    NULL, NULL);
 +    }
 +
 +  XFreeDeviceMotionEvents (device_coords);
 +
 +  *events = coords;
 +
 +  return TRUE;
 +}
 +
 +static void
 +gdk_device_xi_get_state (GdkDevice       *device,
 +                         GdkWindow       *window,
 +                         gdouble         *axes,
 +                         GdkModifierType *mask)
 +{
 +  GdkDeviceXI *device_xi;
 +  XDeviceState *state;
 +  XInputClass *input_class;
 +  gint i;
 +
 +  if (mask)
 +    gdk_window_get_pointer (window, NULL, NULL, mask);
 +
 +  device_xi = GDK_DEVICE_XI (device);
 +  state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
 +                             device_xi->xdevice);
 +  input_class = state->data;
 +
 +  for (i = 0; i < state->num_classes; i++)
 +    {
 +      switch (input_class->class)
 +        {
 +        case ValuatorClass:
 +          if (axes)
 +            gdk_device_xi_translate_axes (device, window,
 +                                          ((XValuatorState *) input_class)->valuators,
 +                                          axes, NULL, NULL);
 +          break;
 +
 +        case ButtonClass:
 +          if (mask)
 +            {
 +              *mask &= 0xFF;
 +              if (((XButtonState *)input_class)->num_buttons > 0)
 +                *mask |= ((XButtonState *)input_class)->buttons[0] << 7;
 +              /* GDK_BUTTON1_MASK = 1 << 8, and button n is stored
 +               * in bit 1<<(n%8) in byte n/8. n = 1,2,... */
 +            }
 +          break;
 +        }
 +
 +      input_class = (XInputClass *)(((char *)input_class)+input_class->length);
 +    }
 +
 +  XFreeDeviceState (state);
 +}
 +
 +static void
 +gdk_device_xi_set_window_cursor (GdkDevice *device,
 +                                 GdkWindow *window,
 +                                 GdkCursor *cursor)
 +{
 +}
 +
 +static void
 +gdk_device_xi_warp (GdkDevice *device,
 +                    GdkScreen *screen,
 +                    gint       x,
 +                    gint       y)
 +{
 +}
 +
 +static void
 +find_events (GdkDevice    *device,
 +             GdkEventMask  mask,
 +             XEventClass  *classes,
 +             int          *num_classes)
 +{
 +  GdkDeviceXI *device_xi;
 +  XEventClass class;
 +  gint i;
 +
 +  device_xi = GDK_DEVICE_XI (device);
 +  i = 0;
 +
 +  if (mask & GDK_BUTTON_PRESS_MASK)
 +    {
 +      DeviceButtonPress (device_xi->xdevice, device_xi->button_press_type, class);
 +      if (class != 0)
 +        classes[i++] = class;
 +
 +      DeviceButtonPressGrab (device_xi->xdevice, 0, class);
 +      if (class != 0)
 +        classes[i++] = class;
 +    }
 +
 +  if (mask & GDK_BUTTON_RELEASE_MASK)
 +    {
 +      DeviceButtonRelease (device_xi->xdevice, device_xi->button_release_type, class);
 +      if (class != 0)
 +        classes[i++] = class;
 +    }
 +
-   if (mask & GDK_POINTER_MOTION_MASK)
-     {
-       DeviceMotionNotify (device_xi->xdevice, device_xi->motion_notify_type, class);
-       if (class != 0)
-         classes[i++] = class;
-     }
-   else if (mask & (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
-                    GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_MOTION_MASK |
-                    GDK_POINTER_MOTION_HINT_MASK))
++  if (mask & (GDK_POINTER_MOTION_MASK |
++              GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
++              GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_MOTION_MASK))
 +    {
 +      /* Make sure device->motionnotify_type is set */
 +      DeviceMotionNotify (device_xi->xdevice, device_xi->motion_notify_type, class);
-     }
- 
-   if (mask & GDK_BUTTON1_MOTION_MASK)
-     {
-       DeviceButton1Motion (device_xi->xdevice, 0, class);
 +      if (class != 0)
-         classes[i++] = class;
-     }
- 
-   if (mask & GDK_BUTTON2_MOTION_MASK)
-     {
-       DeviceButton2Motion (device_xi->xdevice, 0, class);
++	  classes[i++] = class;
++      DeviceStateNotify (device_xi->xdevice, device_xi->state_notify_type, class);
 +      if (class != 0)
-         classes[i++] = class;
-     }
- 
-   if (mask & GDK_BUTTON3_MOTION_MASK)
-     {
-       DeviceButton3Motion (device_xi->xdevice, 0, class);
-       if (class != 0)
-         classes[i++] = class;
-     }
- 
-   if (mask & GDK_BUTTON_MOTION_MASK)
-     {
-       DeviceButtonMotion (device_xi->xdevice, 0, class);
-       if (class != 0)
-         classes[i++] = class;
-     }
- 
-   if (mask & GDK_POINTER_MOTION_HINT_MASK)
-     {
-       /* We'll get into trouble if the macros change, but at
-        * least we'll know about it, and we avoid warnings now
-        */
-       DevicePointerMotionHint (device_xi->xdevice, 0, class);
-       if (class != 0)
-         classes[i++] = class;
++	  classes[i++] = class;
 +    }
 +
 +  if (mask & GDK_KEY_PRESS_MASK)
 +    {
 +      DeviceKeyPress (device_xi->xdevice, device_xi->key_press_type, class);
 +      if (class != 0)
 +        classes[i++] = class;
 +    }
 +
 +  if (mask & GDK_KEY_RELEASE_MASK)
 +    {
 +      DeviceKeyRelease (device_xi->xdevice, device_xi->key_release_type, class);
 +      if (class != 0)
 +        classes[i++] = class;
 +    }
 +
 +  if (mask & GDK_PROXIMITY_IN_MASK)
 +    {
 +      ProximityIn (device_xi->xdevice, device_xi->proximity_in_type, class);
 +      if (class != 0)
 +        classes[i++] = class;
 +    }
 +
 +  if (mask & GDK_PROXIMITY_OUT_MASK)
 +    {
 +      ProximityOut (device_xi->xdevice, device_xi->proximity_out_type, class);
 +      if (class != 0)
 +        classes[i++] = class;
 +    }
 +
 +  *num_classes = i;
 +}
 +
 +static gboolean
 +gdk_device_xi_query_state (GdkDevice        *device,
 +                           GdkWindow        *window,
 +                           GdkWindow       **root_window,
 +                           GdkWindow       **child_window,
 +                           gint             *root_x,
 +                           gint             *root_y,
 +                           gint             *win_x,
 +                           gint             *win_y,
 +                           GdkModifierType  *mask)
 +{
 +  return FALSE;
 +}
 +
 +static GdkGrabStatus
 +gdk_device_xi_grab (GdkDevice    *device,
 +                    GdkWindow    *window,
 +                    gboolean      owner_events,
 +                    GdkEventMask  event_mask,
 +                    GdkWindow    *confine_to,
 +                    GdkCursor    *cursor,
 +                    guint32       time_)
 +{
 +  XEventClass event_classes[MAX_DEVICE_CLASSES];
 +  gint status, num_classes;
 +  GdkDeviceXI *device_xi;
 +
 +  device_xi = GDK_DEVICE_XI (device);
 +  find_events (device, event_mask, event_classes, &num_classes);
 +
 +  status = XGrabDevice (GDK_WINDOW_XDISPLAY (window),
 +                        device_xi->xdevice,
 +                        GDK_WINDOW_XWINDOW (window),
 +                        owner_events,
 +                        num_classes, event_classes,
 +                        GrabModeAsync, GrabModeAsync,
 +                        time_);
 +
 +  return gdk_x11_convert_grab_status (status);
 +}
 +
 +static void
 +gdk_device_xi_ungrab (GdkDevice *device,
 +                      guint32    time_)
 +{
 +  GdkDisplay *display;
 +  GdkDeviceXI *device_xi;
 +
 +  device_xi = GDK_DEVICE_XI (device);
 +  display = gdk_device_get_display (device);
 +
 +  XUngrabDevice (GDK_DISPLAY_XDISPLAY (device),
 +                 device_xi->xdevice,
 +                 time_);
 +}
 +
 +static GdkWindow*
 +gdk_device_xi_window_at_position (GdkDevice       *device,
 +                                  gint            *win_x,
 +                                  gint            *win_y,
-                                   GdkModifierType *mask)
++                                  GdkModifierType *mask,
++                                  gboolean         get_toplevel)
 +{
 +  return NULL;
 +}
 +static void
 +gdk_device_xi_select_window_events (GdkDevice    *device,
 +                                    GdkWindow    *window,
 +                                    GdkEventMask  event_mask)
 +{
 +  XEventClass event_classes[MAX_DEVICE_CLASSES];
 +  GdkDeviceXI *device_xi;
 +  gint num_classes;
 +
 +  event_mask |= (GDK_PROXIMITY_IN_MASK |
 +                 GDK_PROXIMITY_OUT_MASK);
 +
 +  device_xi = GDK_DEVICE_XI (device);
 +  find_events (device, event_mask, event_classes, &num_classes);
 +
 +  XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (window),
 +			 GDK_WINDOW_XWINDOW (window),
 +			 event_classes, num_classes);
 +
 +  if (event_mask)
 +    {
 +      GdkWindowInputInfo *info;
 +
 +      info = g_new0 (GdkWindowInputInfo, 1);
 +      g_object_set_qdata_full (G_OBJECT (window),
 +                               quark_window_input_info,
 +                               info,
 +                               (GDestroyNotify) g_free);
 +    }
 +  else
 +    g_object_set_qdata (G_OBJECT (window),
 +                        quark_window_input_info,
 +                        NULL);
 +}
 +
 +void
 +gdk_device_xi_update_window_info (GdkWindow *window)
 +{
 +  GdkWindowInputInfo *info;
 +  gint root_x, root_y;
 +
 +  info = g_object_get_qdata (G_OBJECT (window),
 +                             quark_window_input_info);
 +
 +  if (!info)
 +    return;
 +
 +  gdk_window_get_origin (window, &root_x, &root_y);
 +  info->root_x = (gdouble) root_x;
 +  info->root_y = (gdouble) root_y;
 +}
 +
 +static gboolean
 +gdk_device_xi_get_window_info (GdkWindow *window,
 +                               gdouble   *root_x,
 +                               gdouble   *root_y)
 +{
 +  GdkWindowInputInfo *info;
 +
 +  info = g_object_get_qdata (G_OBJECT (window),
 +                             quark_window_input_info);
 +
 +  if (!info)
 +    return FALSE;
 +
 +  *root_x = info->root_x;
 +  *root_y = info->root_y;
 +
 +  return TRUE;
 +}
 +
 +void
++gdk_device_xi_update_axes (GdkDevice *device,
++                           gint       axes_count,
++                           gint       first_axis,
++                           gint      *axis_data)
++{
++  GdkDeviceXI *device_xi;
++  int i;
++
++  device_xi = GDK_DEVICE_XI (device);
++  g_return_if_fail (first_axis >= 0 && first_axis + axes_count <= device->num_axes);
++
++  if (!device_xi->axis_data)
++    device_xi->axis_data = g_new0 (gint, device->num_axes);
++
++  for (i = 0; i < axes_count; i++)
++    device_xi->axis_data[first_axis + i] = axis_data[i];
++}
++
++void
 +gdk_device_xi_translate_axes (GdkDevice *device,
 +                              GdkWindow *window,
 +                              gint      *axis_data,
 +                              gdouble   *axes,
 +                              gdouble   *x,
 +                              gdouble   *y)
 +{
++  GdkDeviceXI *device_xi;
 +  GdkWindow *impl_window;
 +  gdouble root_x, root_y;
 +  gdouble temp_x, temp_y;
 +  gint i;
 +
++  device_xi = GDK_DEVICE_XI (device);
 +  impl_window = _gdk_window_get_impl_window (window);
 +  temp_x = temp_y = 0;
 +
 +  if (!gdk_device_xi_get_window_info (impl_window, &root_x, &root_y))
 +    return;
 +
 +  for (i = 0; i < device->num_axes; i++)
 +    {
 +      GdkAxisUse use;
 +
 +      use = _gdk_device_get_axis_use (device, i);
 +
 +      switch (use)
 +        {
 +        case GDK_AXIS_X:
 +        case GDK_AXIS_Y:
 +          if (device->mode == GDK_MODE_WINDOW)
 +            _gdk_device_translate_window_coord (device, window,
 +                                                i, axis_data[i],
 +                                                &axes[i]);
 +          else
 +            _gdk_device_translate_screen_coord (device, window,
 +                                                root_x, root_y,
 +                                                i, axis_data[i],
 +                                                &axes[i]);
 +          if (use == GDK_AXIS_X)
 +            temp_x = axes[i];
 +          else if (use == GDK_AXIS_Y)
 +            temp_y = axes[i];
 +
 +          break;
 +        default:
 +          _gdk_device_translate_axis (device, i, axis_data[i], &axes[i]);
 +          break;
 +        }
 +    }
 +
 +  if (x)
 +    *x = temp_x;
 +
 +  if (y)
 +    *y = temp_y;
 +}
diff --cc gdk/x11/gdkdevice-xi.h
index 448f1fa,0000000..5f8f586
mode 100644,000000..100644
--- a/gdk/x11/gdkdevice-xi.h
+++ b/gdk/x11/gdkdevice-xi.h
@@@ -1,80 -1,0 +1,84 @@@
 +/* GDK - The GIMP Drawing Kit
 + * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 + * Boston, MA 02111-1307, USA.
 + */
 +
 +#ifndef __GDK_DEVICE_XI_H__
 +#define __GDK_DEVICE_XI_H__
 +
 +#include <gdk/gdkdeviceprivate.h>
 +#include <X11/extensions/XInput.h>
 +
 +G_BEGIN_DECLS
 +
 +#define GDK_TYPE_DEVICE_XI         (gdk_device_xi_get_type ())
 +#define GDK_DEVICE_XI(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_XI, GdkDeviceXI))
 +#define GDK_DEVICE_XI_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_XI, GdkDeviceXIClass))
 +#define GDK_IS_DEVICE_XI(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_XI))
 +#define GDK_IS_DEVICE_XI_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_XI))
 +#define GDK_DEVICE_XI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_XI, GdkDeviceXIClass))
 +
 +typedef struct _GdkDeviceXI GdkDeviceXI;
 +typedef struct _GdkDeviceXIClass GdkDeviceXIClass;
 +
 +struct _GdkDeviceXI
 +{
 +  GdkDevice parent_instance;
 +
 +  guint32 device_id;
 +  XDevice *xdevice;
 +
 +  gint button_press_type;
 +  gint button_release_type;
 +  gint key_press_type;
 +  gint key_release_type;
 +  gint motion_notify_type;
 +  gint proximity_in_type;
 +  gint proximity_out_type;
++  gint state_notify_type;
 +
 +  /* minimum key code for device */
 +  gint min_keycode;
 +
-   /* Mask of buttons (used for button grabs) */
-   gint button_state;
++  gint *axis_data;
 +
 +  guint in_proximity : 1;
 +};
 +
 +struct _GdkDeviceXIClass
 +{
 +  GdkDeviceClass parent_class;
 +};
 +
 +GType gdk_device_xi_get_type (void) G_GNUC_CONST;
 +
 +void     gdk_device_xi_update_window_info (GdkWindow *window);
 +
++void     gdk_device_xi_update_axes (GdkDevice *device,
++                                    gint       axes_count,
++                                    gint       first_axis,
++                                    gint      *axis_data);
 +void     gdk_device_xi_translate_axes     (GdkDevice *device,
 +                                           GdkWindow *window,
 +                                           gint      *axis_data,
 +                                           gdouble   *axes,
 +                                           gdouble   *x,
 +                                           gdouble   *y);
 +
 +G_END_DECLS
 +
 +#endif /* __GDK_DEVICE_XI_H__ */
diff --cc gdk/x11/gdkdevice-xi2.c
index 8565406,0000000..1d5e84e
mode 100644,000000..100644
--- a/gdk/x11/gdkdevice-xi2.c
+++ b/gdk/x11/gdkdevice-xi2.c
@@@ -1,555 -1,0 +1,562 @@@
 +/* GDK - The GIMP Drawing Kit
 + * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 + * Boston, MA 02111-1307, USA.
 + */
 +
 +#include <X11/extensions/XInput2.h>
 +#include "gdkdevice-xi2.h"
 +#include "gdkintl.h"
 +#include "gdkx.h"
 +
 +#define BIT_IS_ON(ptr, bit) (((unsigned char *) (ptr))[(bit)>>3] & (1 << ((bit) & 7)))
 +#define GDK_DEVICE_XI2_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDK_TYPE_DEVICE_XI2, GdkDeviceXI2Private))
 +
 +typedef struct GdkDeviceXI2Private GdkDeviceXI2Private;
 +
 +struct GdkDeviceXI2Private
 +{
 +  int device_id;
 +};
 +
 +static void gdk_device_xi2_get_property (GObject      *object,
 +                                         guint         prop_id,
 +                                         GValue       *value,
 +                                         GParamSpec   *pspec);
 +static void gdk_device_xi2_set_property (GObject      *object,
 +                                         guint         prop_id,
 +                                         const GValue *value,
 +                                         GParamSpec   *pspec);
 +
 +static void gdk_device_xi2_get_state (GdkDevice       *device,
 +                                      GdkWindow       *window,
 +                                      gdouble         *axes,
 +                                      GdkModifierType *mask);
 +static void gdk_device_xi2_set_window_cursor (GdkDevice *device,
 +                                              GdkWindow *window,
 +                                              GdkCursor *cursor);
 +static void gdk_device_xi2_warp (GdkDevice *device,
 +                                 GdkScreen *screen,
 +                                 gint       x,
 +                                 gint       y);
 +static gboolean gdk_device_xi2_query_state (GdkDevice        *device,
 +                                            GdkWindow        *window,
 +                                            GdkWindow       **root_window,
 +                                            GdkWindow       **child_window,
 +                                            gint             *root_x,
 +                                            gint             *root_y,
 +                                            gint             *win_x,
 +                                            gint             *win_y,
 +                                            GdkModifierType  *mask);
 +
 +static GdkGrabStatus gdk_device_xi2_grab   (GdkDevice     *device,
 +                                            GdkWindow     *window,
 +                                            gboolean       owner_events,
 +                                            GdkEventMask   event_mask,
 +                                            GdkWindow     *confine_to,
 +                                            GdkCursor     *cursor,
 +                                            guint32        time_);
 +static void          gdk_device_xi2_ungrab (GdkDevice     *device,
 +                                            guint32        time_);
 +
 +static GdkWindow * gdk_device_xi2_window_at_position (GdkDevice       *device,
 +                                                      gint            *win_x,
 +                                                      gint            *win_y,
-                                                       GdkModifierType *mask);
++                                                      GdkModifierType *mask,
++                                                      gboolean         get_toplevel);
 +static void  gdk_device_xi2_select_window_events (GdkDevice    *device,
 +                                                  GdkWindow    *window,
 +                                                  GdkEventMask  event_mask);
 +
 +
 +G_DEFINE_TYPE (GdkDeviceXI2, gdk_device_xi2, GDK_TYPE_DEVICE)
 +
 +enum {
 +  PROP_0,
 +  PROP_DEVICE_ID
 +};
 +
 +static void
 +gdk_device_xi2_class_init (GdkDeviceXI2Class *klass)
 +{
 +  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 +  GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
 +
 +  object_class->get_property = gdk_device_xi2_get_property;
 +  object_class->set_property = gdk_device_xi2_set_property;
 +
 +  device_class->get_state = gdk_device_xi2_get_state;
 +  device_class->set_window_cursor = gdk_device_xi2_set_window_cursor;
 +  device_class->warp = gdk_device_xi2_warp;
 +  device_class->query_state = gdk_device_xi2_query_state;
 +  device_class->grab = gdk_device_xi2_grab;
 +  device_class->ungrab = gdk_device_xi2_ungrab;
 +  device_class->window_at_position = gdk_device_xi2_window_at_position;
 +  device_class->select_window_events = gdk_device_xi2_select_window_events;
 +
 +  g_object_class_install_property (object_class,
 +				   PROP_DEVICE_ID,
 +				   g_param_spec_int ("device-id",
 +                                                     P_("Device ID"),
 +                                                     P_("Device identifier"),
 +                                                     0, G_MAXINT, 0,
 +                                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 +
 +  g_type_class_add_private (object_class, sizeof (GdkDeviceXI2Private));
 +}
 +
 +static void
 +gdk_device_xi2_init (GdkDeviceXI2 *device)
 +{
 +}
 +
 +static void
 +gdk_device_xi2_get_property (GObject    *object,
 +                             guint       prop_id,
 +                             GValue     *value,
 +                             GParamSpec *pspec)
 +{
 +  GdkDeviceXI2Private *priv;
 +
 +  priv = GDK_DEVICE_XI2_GET_PRIVATE (object);
 +
 +  switch (prop_id)
 +    {
 +    case PROP_DEVICE_ID:
 +      g_value_set_int (value, priv->device_id);
 +      break;
 +    default:
 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 +      break;
 +    }
 +}
 +
 +static void
 +gdk_device_xi2_set_property (GObject      *object,
 +                             guint         prop_id,
 +                             const GValue *value,
 +                             GParamSpec   *pspec)
 +{
 +  GdkDeviceXI2Private *priv;
 +
 +  priv = GDK_DEVICE_XI2_GET_PRIVATE (object);
 +
 +  switch (prop_id)
 +    {
 +    case PROP_DEVICE_ID:
 +      priv->device_id = g_value_get_int (value);
 +      break;
 +    default:
 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 +      break;
 +    }
 +}
 +
 +static void
 +gdk_device_xi2_get_state (GdkDevice       *device,
 +                          GdkWindow       *window,
 +                          gdouble         *axes,
 +                          GdkModifierType *mask)
 +{
 +  /* FIXME: Axes are not being translated, there doesn't
 +   * seem to be any function to get valuators state in XI2.
 +   */
 +  gdk_device_xi2_query_state (device, window,
 +                              NULL, NULL,
 +                              NULL, NULL,
 +                              NULL, NULL,
 +                              mask);
 +}
 +
 +static void
 +gdk_device_xi2_set_window_cursor (GdkDevice *device,
 +                                  GdkWindow *window,
 +                                  GdkCursor *cursor)
 +{
 +  GdkDeviceXI2Private *priv;
 +  GdkCursorPrivate *cursor_private;
 +
 +  priv = GDK_DEVICE_XI2_GET_PRIVATE (device);
 +
 +  /* Non-master devices don't have a cursor */
 +  if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
 +    return;
 +
 +  if (cursor)
 +    {
 +      cursor_private = (GdkCursorPrivate*) cursor;
 +
 +      XIDefineCursor (GDK_WINDOW_XDISPLAY (window),
 +                      priv->device_id,
 +                      GDK_WINDOW_XWINDOW (window),
 +                      cursor_private->xcursor);
 +    }
 +  else
 +    XIUndefineCursor (GDK_WINDOW_XDISPLAY (window),
 +                      priv->device_id,
 +                      GDK_WINDOW_XWINDOW (window));
 +}
 +
 +static void
 +gdk_device_xi2_warp (GdkDevice *device,
 +                     GdkScreen *screen,
 +                     gint       x,
 +                     gint       y)
 +{
 +  GdkDeviceXI2Private *priv;
 +  Window dest;
 +
 +  priv = GDK_DEVICE_XI2_GET_PRIVATE (device);
 +  dest = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
 +
 +  XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
 +                 priv->device_id,
 +                 None, dest,
 +                 0, 0, 0, 0, x, y);
 +}
 +
 +static gboolean
 +gdk_device_xi2_query_state (GdkDevice        *device,
 +                            GdkWindow        *window,
 +                            GdkWindow       **root_window,
 +                            GdkWindow       **child_window,
 +                            gint             *root_x,
 +                            gint             *root_y,
 +                            gint             *win_x,
 +                            gint             *win_y,
 +                            GdkModifierType  *mask)
 +{
 +  GdkDisplay *display;
 +  GdkDeviceXI2Private *priv;
 +  Window xroot_window, xchild_window;
 +  gdouble xroot_x, xroot_y, xwin_x, xwin_y;
 +  XIButtonState button_state;
 +  XIModifierState mod_state;
 +  XIGroupState group_state;
 +
 +  if (!window || GDK_WINDOW_DESTROYED (window))
 +    return FALSE;
 +
 +  priv = GDK_DEVICE_XI2_GET_PRIVATE (device);
 +  display = gdk_drawable_get_display (window);
 +
 +  if (!XIQueryPointer (GDK_WINDOW_XDISPLAY (window),
 +                       priv->device_id,
 +                       GDK_WINDOW_XID (window),
 +                       &xroot_window,
 +                       &xchild_window,
 +                       &xroot_x,
 +                       &xroot_y,
 +                       &xwin_x,
 +                       &xwin_y,
 +                       &button_state,
 +                       &mod_state,
 +                       &group_state))
 +    {
 +      return FALSE;
 +    }
 +
 +  if (root_window)
 +    *root_window = gdk_window_lookup_for_display (display, xroot_window);
 +
 +  if (child_window)
 +    *child_window = gdk_window_lookup_for_display (display, xchild_window);
 +
 +  if (root_x)
 +    *root_x = (gint) xroot_x;
 +
 +  if (root_y)
 +    *root_y = (gint) xroot_y;
 +
 +  if (win_x)
 +    *win_x = (gint) xwin_x;
 +
 +  if (win_y)
 +    *win_y = (gint) xwin_y;
 +
 +  if (mask)
 +    *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
 +
 +  return TRUE;
 +}
 +
 +static GdkGrabStatus
 +gdk_device_xi2_grab (GdkDevice    *device,
 +                     GdkWindow    *window,
 +                     gboolean      owner_events,
 +                     GdkEventMask  event_mask,
 +                     GdkWindow    *confine_to,
 +                     GdkCursor    *cursor,
 +                     guint32       time_)
 +{
 +  GdkDeviceXI2Private *priv;
 +  GdkDisplay *display;
 +  XIEventMask mask;
 +  Window xwindow;
 +  Cursor xcursor;
 +  int status;
 +
 +  priv = GDK_DEVICE_XI2_GET_PRIVATE (device);
 +  display = gdk_device_get_display (device);
 +
 +  /* FIXME: confine_to is actually unused */
 +
 +  xwindow = GDK_WINDOW_XID (window);
 +
 +  if (!cursor)
 +    xcursor = None;
 +  else
 +    {
 +      _gdk_x11_cursor_update_theme (cursor);
 +      xcursor = ((GdkCursorPrivate *) cursor)->xcursor;
 +    }
 +
 +  mask.deviceid = priv->device_id;
 +  mask.mask = gdk_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
 +
 +  status = XIGrabDevice (GDK_DISPLAY_XDISPLAY (display),
 +                         priv->device_id,
 +                         xwindow,
 +                         time_,
 +                         xcursor,
 +                         GrabModeAsync, GrabModeAsync,
 +                         owner_events,
 +                         &mask);
 +
 +  g_free (mask.mask);
 +
 +  return gdk_x11_convert_grab_status (status);
 +}
 +
 +static void
 +gdk_device_xi2_ungrab (GdkDevice *device,
 +                       guint32    time_)
 +{
 +  GdkDeviceXI2Private *priv;
 +  GdkDisplay *display;
 +
 +  priv = GDK_DEVICE_XI2_GET_PRIVATE (device);
 +  display = gdk_device_get_display (device);
 +
 +  XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display),
 +                  priv->device_id,
 +                  time_);
 +}
 +
 +static GdkWindow *
 +gdk_device_xi2_window_at_position (GdkDevice       *device,
 +                                   gint            *win_x,
 +                                   gint            *win_y,
-                                    GdkModifierType *mask)
++                                   GdkModifierType *mask,
++                                   gboolean         get_toplevel)
 +{
 +  GdkDeviceXI2Private *priv;
 +  GdkDisplay *display;
 +  GdkScreen *screen;
 +  Display *xdisplay;
 +  GdkWindow *window;
 +  Window xwindow, root, child, last = None;
 +  gdouble xroot_x, xroot_y, xwin_x, xwin_y;
 +  XIButtonState button_state;
 +  XIModifierState mod_state;
 +  XIGroupState group_state;
 +
 +  priv = GDK_DEVICE_XI2_GET_PRIVATE (device);
 +  display = gdk_device_get_display (device);
 +  screen = gdk_display_get_default_screen (display);
 +
 +  /* This function really only works if the mouse pointer is held still
 +   * during its operation. If it moves from one leaf window to another
 +   * than we'll end up with inaccurate values for win_x, win_y
 +   * and the result.
 +   */
 +  gdk_x11_display_grab (display);
 +
 +  xdisplay = GDK_SCREEN_XDISPLAY (screen);
 +  xwindow = GDK_SCREEN_XROOTWIN (screen);
 +
 +  XIQueryPointer (xdisplay,
 +                  priv->device_id,
 +                  xwindow,
 +                  &root, &child,
 +                  &xroot_x, &xroot_y,
 +                  &xwin_x, &xwin_y,
 +                  &button_state,
 +                  &mod_state,
 +                  &group_state);
 +
 +  if (root == xwindow)
 +    xwindow = child;
 +  else
 +    xwindow = root;
 +
 +  while (xwindow)
 +    {
 +      last = xwindow;
 +      XIQueryPointer (xdisplay,
 +                      priv->device_id,
 +                      xwindow,
 +                      &root, &xwindow,
 +                      &xroot_x, &xroot_y,
 +                      &xwin_x, &xwin_y,
 +                      &button_state,
 +                      &mod_state,
 +                      &group_state);
++
++      if (get_toplevel &&
++          (window = gdk_window_lookup_for_display (display, last)) != NULL &&
++          GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
++        break;
 +    }
 +
 +  gdk_x11_display_ungrab (display);
 +
 +  window = gdk_window_lookup_for_display (display, last);
 +
 +  if (win_x)
 +    *win_x = (window) ? (gint) xwin_x : -1;
 +
 +  if (win_y)
 +    *win_y = (window) ? (gint) xwin_y : -1;
 +
 +  if (mask)
 +    *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
 +
 +  return window;
 +}
 +
 +static void
 +gdk_device_xi2_select_window_events (GdkDevice    *device,
 +                                     GdkWindow    *window,
 +                                     GdkEventMask  event_mask)
 +{
 +  GdkDeviceXI2Private *priv;
 +  XIEventMask evmask;
 +
 +  priv = GDK_DEVICE_XI2_GET_PRIVATE (device);
 +
 +  evmask.deviceid = priv->device_id;
 +  evmask.mask = gdk_device_xi2_translate_event_mask (event_mask, &evmask.mask_len);
 +
 +  XISelectEvents (GDK_WINDOW_XDISPLAY (window),
 +                  GDK_WINDOW_XWINDOW (window),
 +                  &evmask, 1);
 +
 +  g_free (evmask.mask);
 +}
 +
 +guchar *
 +gdk_device_xi2_translate_event_mask (GdkEventMask  event_mask,
 +                                     int          *len)
 +{
 +  guchar *mask;
 +
 +  *len = XIMaskLen (XI_LASTEVENT);
 +  mask = g_new0 (guchar, *len);
 +
 +  if (event_mask & GDK_POINTER_MOTION_MASK ||
 +      event_mask & GDK_POINTER_MOTION_HINT_MASK)
 +    XISetMask (mask, XI_Motion);
 +
 +  if (event_mask & GDK_BUTTON_MOTION_MASK ||
 +      event_mask & GDK_BUTTON1_MOTION_MASK ||
 +      event_mask & GDK_BUTTON2_MOTION_MASK ||
 +      event_mask & GDK_BUTTON3_MOTION_MASK)
 +    {
 +      XISetMask (mask, XI_ButtonPress);
 +      XISetMask (mask, XI_ButtonRelease);
 +      XISetMask (mask, XI_Motion);
 +    }
 +
 +  if (event_mask & GDK_SCROLL_MASK)
 +    {
 +      XISetMask (mask, XI_ButtonPress);
 +      XISetMask (mask, XI_ButtonRelease);
 +    }
 +
 +  if (event_mask & GDK_BUTTON_PRESS_MASK)
 +    XISetMask (mask, XI_ButtonPress);
 +
 +  if (event_mask & GDK_BUTTON_RELEASE_MASK)
 +    XISetMask (mask, XI_ButtonRelease);
 +
 +  if (event_mask & GDK_KEY_PRESS_MASK)
 +    XISetMask (mask, XI_KeyPress);
 +
 +  if (event_mask & GDK_KEY_RELEASE_MASK)
 +    XISetMask (mask, XI_KeyRelease);
 +
 +  if (event_mask & GDK_ENTER_NOTIFY_MASK)
 +    XISetMask (mask, XI_Enter);
 +
 +  if (event_mask & GDK_LEAVE_NOTIFY_MASK)
 +    XISetMask (mask, XI_Leave);
 +
 +  if (event_mask & GDK_FOCUS_CHANGE_MASK)
 +    {
 +      XISetMask (mask, XI_FocusIn);
 +      XISetMask (mask, XI_FocusOut);
 +    }
 +
 +  return mask;
 +}
 +
 +guint
 +gdk_device_xi2_translate_state (XIModifierState *mods_state,
 +                                XIButtonState   *buttons_state)
 +{
 +  guint state = 0;
 +
 +  if (mods_state)
 +    state = (guint) mods_state->effective;
 +
 +  if (buttons_state)
 +    {
 +      gint len, i;
 +
 +      /* We're only interested in the first 5 buttons */
 +      len = MIN (5, buttons_state->mask_len * 8);
 +
 +      for (i = 0; i < len; i++)
 +        {
 +          if (!BIT_IS_ON (buttons_state->mask, i))
 +            continue;
 +
 +          switch (i)
 +            {
 +            case 1:
 +              state |= GDK_BUTTON1_MASK;
 +              break;
 +            case 2:
 +              state |= GDK_BUTTON2_MASK;
 +              break;
 +            case 3:
 +              state |= GDK_BUTTON3_MASK;
 +              break;
 +            case 4:
 +              state |= GDK_BUTTON4_MASK;
 +              break;
 +            case 5:
 +              state |= GDK_BUTTON5_MASK;
 +              break;
 +            default:
 +              break;
 +            }
 +        }
 +    }
 +
 +  return state;
 +}
diff --cc gdk/x11/gdkdevicemanager-xi.c
index 5584fae,0000000..c857eb7
mode 100644,000000..100644
--- a/gdk/x11/gdkdevicemanager-xi.c
+++ b/gdk/x11/gdkdevicemanager-xi.c
@@@ -1,620 -1,0 +1,645 @@@
 +/* GDK - The GIMP Drawing Kit
 + * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 + * Boston, MA 02111-1307, USA.
 + */
 +
 +#include "gdkdevicemanager-xi.h"
 +#include "gdkeventtranslator.h"
 +#include "gdkdevice-xi.h"
 +#include "gdkintl.h"
 +#include "gdkx.h"
 +
 +#include <X11/extensions/XInput.h>
 +
 +#define GDK_DEVICE_MANAGER_XI_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GDK_TYPE_DEVICE_MANAGER_XI, GdkDeviceManagerXIPrivate))
 +
 +typedef struct GdkDeviceManagerXIPrivate GdkDeviceManagerXIPrivate;
 +
 +struct GdkDeviceManagerXIPrivate
 +{
 +  GHashTable *id_table;
 +  gint event_base;
 +  GList *devices;
 +  gboolean ignore_core_events;
 +};
 +
 +static void gdk_device_manager_xi_constructed  (GObject      *object);
 +static void gdk_device_manager_xi_finalize     (GObject      *object);
 +static void gdk_device_manager_xi_set_property (GObject      *object,
 +                                                guint         prop_id,
 +                                                const GValue *value,
 +                                                GParamSpec   *pspec);
 +static void gdk_device_manager_xi_get_property (GObject      *object,
 +                                                guint         prop_id,
 +                                                GValue       *value,
 +                                                GParamSpec   *pspec);
 +
 +static void     gdk_device_manager_xi_event_translator_init  (GdkEventTranslatorIface *iface);
 +static gboolean gdk_device_manager_xi_translate_event (GdkEventTranslator *translator,
 +                                                       GdkDisplay         *display,
 +                                                       GdkEvent           *event,
 +                                                       XEvent             *xevent);
 +static GList *  gdk_device_manager_xi_get_devices     (GdkDeviceManager  *device_manager,
 +                                                       GdkDeviceType      type);
 +
 +
 +G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerXI, gdk_device_manager_xi, GDK_TYPE_DEVICE_MANAGER_CORE,
 +                         G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
 +                                                gdk_device_manager_xi_event_translator_init))
 +
 +enum {
 +  PROP_0,
 +  PROP_EVENT_BASE
 +};
 +
 +static void
 +gdk_device_manager_xi_class_init (GdkDeviceManagerXIClass *klass)
 +{
 +  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 +  GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
 +
 +  object_class->constructed = gdk_device_manager_xi_constructed;
 +  object_class->finalize = gdk_device_manager_xi_finalize;
 +  object_class->set_property = gdk_device_manager_xi_set_property;
 +  object_class->get_property = gdk_device_manager_xi_get_property;
 +
 +  device_manager_class->get_devices = gdk_device_manager_xi_get_devices;
 +
 +  g_object_class_install_property (object_class,
 +				   PROP_EVENT_BASE,
 +				   g_param_spec_int ("event-base",
 +                                                     P_("Event base"),
 +                                                     P_("Event base for XInput events"),
 +                                                     0, G_MAXINT, 0,
 +                                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 +
 +  g_type_class_add_private (object_class, sizeof (GdkDeviceManagerXIPrivate));
 +}
 +
 +static GdkFilterReturn
 +window_input_info_filter (GdkXEvent *xevent,
 +                          GdkEvent  *event,
 +                          gpointer   user_data)
 +{
 +  GdkDeviceManager *device_manager;
 +  GdkDisplay *display;
 +  GdkWindow *window;
 +  XEvent *xev;
 +
 +  device_manager = user_data;
 +  xev = (XEvent *) xevent;
 +
 +  display = gdk_device_manager_get_display (device_manager);
 +  window = gdk_window_lookup_for_display (display, xev->xany.window);
 +
 +  if (window && xev->type == ConfigureNotify)
 +    gdk_device_xi_update_window_info (window);
 +
 +  return GDK_FILTER_CONTINUE;
 +}
 +
 +static void
 +gdk_device_manager_xi_init (GdkDeviceManagerXI *device_manager)
 +{
 +  GdkDeviceManagerXIPrivate *priv;
 +
 +  priv = GDK_DEVICE_MANAGER_XI_GET_PRIVATE (device_manager);
 +  priv->id_table = g_hash_table_new_full (NULL, NULL, NULL,
 +                                          (GDestroyNotify) g_object_unref);
 +
 +  gdk_window_add_filter (NULL, window_input_info_filter, device_manager);
 +}
 +
 +static void
 +translate_class_info (GdkDevice   *device,
 +                      XDeviceInfo *info)
 +{
 +  GdkDeviceXI *device_xi;
 +  XAnyClassPtr class;
 +  gint i, j;
 +
 +  device_xi = GDK_DEVICE_XI (device);
 +  class = info->inputclassinfo;
 +
 +  for (i = 0; i < info->num_classes; i++)
 +    {
 +      switch (class->class) {
 +      case ButtonClass:
 +	break;
 +      case KeyClass:
 +	{
 +	  XKeyInfo *xki = (XKeyInfo *)class;
 +          guint num_keys;
 +
 +          num_keys = xki->max_keycode - xki->min_keycode + 1;
 +          _gdk_device_set_keys (device, num_keys);
 +
 +          device_xi->min_keycode = xki->min_keycode;
 +
 +	  break;
 +	}
 +      case ValuatorClass:
 +	{
 +	  XValuatorInfo *xvi = (XValuatorInfo *)class;
 +
 +          for (j = 0; j < xvi->num_axes; j++)
 +            {
 +              GdkAxisUse use;
 +
 +              switch (j)
 +                {
 +                case 0:
 +                  use = GDK_AXIS_X;
 +                  break;
 +                case 1:
 +                  use = GDK_AXIS_Y;
 +                  break;
 +                case 2:
 +                  use = GDK_AXIS_PRESSURE;
 +                  break;
 +                case 3:
 +                  use = GDK_AXIS_XTILT;
 +                  break;
 +                case 4:
 +                  use = GDK_AXIS_YTILT;
 +                  break;
 +                case 5:
 +                  use = GDK_AXIS_WHEEL;
 +                  break;
 +                default:
 +                  use = GDK_AXIS_IGNORE;
 +                }
 +
 +              _gdk_device_add_axis (device,
 +                                    GDK_NONE,
 +                                    use,
 +                                    xvi->axes[j].min_value,
 +                                    xvi->axes[j].max_value,
 +                                    xvi->axes[j].resolution);
 +            }
 +
 +	  break;
 +	}
 +      }
 +
 +      class = (XAnyClassPtr) (((char *) class) + class->length);
 +    }
 +}
 +
 +static GdkDevice *
 +create_device (GdkDeviceManager *device_manager,
 +               GdkDisplay       *display,
 +               XDeviceInfo      *info)
 +{
 +  GdkInputSource input_source;
 +  GdkDevice *device;
 +
 +  if (info->use != IsXExtensionPointer &&
 +      info->use != IsXExtensionKeyboard)
 +    return NULL;
 +
 +  if (info->use == IsXExtensionKeyboard)
 +    input_source = GDK_SOURCE_KEYBOARD;
 +  else
 +    {
 +      gchar *tmp_name;
 +
 +      tmp_name = g_ascii_strdown (info->name, -1);
 +
-       if (g_str_has_suffix (tmp_name, "pointer"))
-         input_source = GDK_SOURCE_MOUSE;
-       else if (strcmp (tmp_name, "wacom") == 0 ||
-                strcmp (tmp_name, "pen") == 0)
-         input_source = GDK_SOURCE_PEN;
-       else if (strcmp (tmp_name, "eraser") == 0)
++      if (strstr (tmp_name, "eraser"))
 +        input_source = GDK_SOURCE_ERASER;
-       else if (strcmp (tmp_name, "cursor") == 0)
++      else if (strstr (tmp_name, "cursor"))
 +        input_source = GDK_SOURCE_CURSOR;
-       else
++      else if (strstr (tmp_name, "wacom") ||
++               strstr (tmp_name, "pen"))
 +        input_source = GDK_SOURCE_PEN;
++      else
++        input_source = GDK_SOURCE_MOUSE;
 +
 +      g_free (tmp_name);
 +    }
 +
 +  device = g_object_new (GDK_TYPE_DEVICE_XI,
 +                         "name", info->name,
 +                         "type", GDK_DEVICE_TYPE_FLOATING,
 +                         "input-source", input_source,
 +                         "input-mode", GDK_MODE_DISABLED,
 +                         "has-cursor", FALSE,
 +                         "display", display,
 +                         "device-manager", device_manager,
 +                         "device-id", info->id,
 +                         NULL);
 +  translate_class_info (device, info);
 +
 +  return device;
 +}
 +
 +static void
 +gdk_device_manager_xi_constructed (GObject *object)
 +{
 +  GdkDeviceManagerXIPrivate *priv;
 +  XDeviceInfo *devices;
 +  gint i, num_devices;
 +  GdkDisplay *display;
 +
 +  priv = GDK_DEVICE_MANAGER_XI_GET_PRIVATE (object);
 +  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
 +  devices = XListInputDevices(GDK_DISPLAY_XDISPLAY (display), &num_devices);
 +
 +  for(i = 0; i < num_devices; i++)
 +    {
 +      GdkDevice *device;
 +
 +      device = create_device (GDK_DEVICE_MANAGER (object),
 +                              display, &devices[i]);
 +      if (device)
 +        {
 +          priv->devices = g_list_prepend (priv->devices, device);
 +          g_hash_table_insert (priv->id_table,
 +                               GINT_TO_POINTER (devices[i].id),
 +                               device);
 +        }
 +    }
 +
 +  XFreeDeviceList(devices);
 +
 +  gdk_x11_register_standard_event_type (display,
 +                                        priv->event_base,
 +                                        15 /* Number of events */);
 +
 +  if (G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->constructed)
 +    G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->constructed (object);
 +}
 +
 +static void
 +gdk_device_manager_xi_finalize (GObject *object)
 +{
 +  GdkDeviceManagerXIPrivate *priv;
 +
 +  priv = GDK_DEVICE_MANAGER_XI_GET_PRIVATE (object);
 +
 +  g_list_foreach (priv->devices, (GFunc) g_object_unref, NULL);
 +  g_list_free (priv->devices);
 +
 +  g_hash_table_destroy (priv->id_table);
 +
 +  gdk_window_remove_filter (NULL, window_input_info_filter, object);
 +
 +  G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->finalize (object);
 +}
 +
 +static void
 +gdk_device_manager_xi_set_property (GObject      *object,
 +                                    guint         prop_id,
 +                                    const GValue *value,
 +                                    GParamSpec   *pspec)
 +{
 +  GdkDeviceManagerXIPrivate *priv;
 +
 +  priv = GDK_DEVICE_MANAGER_XI_GET_PRIVATE (object);
 +
 +  switch (prop_id)
 +    {
 +    case PROP_EVENT_BASE:
 +      priv->event_base = g_value_get_int (value);
 +      break;
 +    default:
 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 +      break;
 +    }
 +}
 +
 +static void
 +gdk_device_manager_xi_get_property (GObject    *object,
 +                                    guint       prop_id,
 +                                    GValue     *value,
 +                                    GParamSpec *pspec)
 +{
 +  GdkDeviceManagerXIPrivate *priv;
 +
 +  priv = GDK_DEVICE_MANAGER_XI_GET_PRIVATE (object);
 +
 +  switch (prop_id)
 +    {
 +    case PROP_EVENT_BASE:
 +      g_value_set_int (value, priv->event_base);
 +      break;
 +    default:
 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 +      break;
 +    }
 +}
 +
 +static void
 +gdk_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface)
 +{
 +  iface->translate_event = gdk_device_manager_xi_translate_event;
 +}
 +
 +/* combine the state of the core device and the device state
 + * into one - for now we do this in a simple-minded manner -
 + * we just take the keyboard portion of the core device and
 + * the button portion (all of?) the device state.
 + * Any button remapping should go on here.
 + */
 +static guint
 +translate_state (guint state, guint device_state)
 +{
 +  return device_state | (state & 0xFF);
 +}
 +
 +static GdkDevice *
 +lookup_device (GdkDeviceManagerXI *device_manager,
 +               XEvent             *xevent)
 +{
 +  GdkDeviceManagerXIPrivate *priv;
 +  guint32 device_id;
 +
 +  priv = GDK_DEVICE_MANAGER_XI_GET_PRIVATE (device_manager);
 +
 +  /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
 +     but it's potentially faster than scanning through the types of
 +     every device. If we were deceived, then it won't match any of
 +     the types for the device anyways */
 +  device_id = ((XDeviceButtonEvent *)xevent)->deviceid;
 +
 +  return g_hash_table_lookup (priv->id_table, GINT_TO_POINTER (device_id));
 +}
 +
 +static gboolean
 +gdk_device_manager_xi_translate_event (GdkEventTranslator *translator,
 +                                       GdkDisplay         *display,
 +                                       GdkEvent           *event,
 +                                       XEvent             *xevent)
 +{
 +  GdkDeviceManagerXIPrivate *priv;
 +  GdkEventTranslatorIface *parent_iface;
 +  GdkDeviceXI *device_xi;
 +  GdkDevice *device;
 +  GdkWindow *window;
 +
 +  parent_iface = g_type_interface_peek_parent (GDK_EVENT_TRANSLATOR_GET_IFACE (translator));
 +  priv = GDK_DEVICE_MANAGER_XI_GET_PRIVATE (translator);
 +
 +  if (!priv->ignore_core_events &&
 +      parent_iface->translate_event (translator, display, event, xevent))
 +    return TRUE;
 +
 +  device = lookup_device (GDK_DEVICE_MANAGER_XI (translator), xevent);
 +  device_xi = GDK_DEVICE_XI (device);
 +
 +  if (!device)
 +    return FALSE;
 +
 +  window = gdk_window_lookup_for_display (display, xevent->xany.window);
 +
 +  if (!window)
 +    return FALSE;
 +
 +  if ((xevent->type == device_xi->button_press_type) ||
 +      (xevent->type == device_xi->button_release_type))
 +    {
 +      XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *) xevent;
 +
 +      event->button.type = (xdbe->type == device_xi->button_press_type) ?
 +        GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
 +
 +      event->button.device = device;
 +      event->button.window = g_object_ref (window);
 +      event->button.time = xdbe->time;
 +
 +      event->button.x_root = (gdouble) xdbe->x_root;
 +      event->button.y_root = (gdouble) xdbe->y_root;
 +
 +      event->button.axes = g_new0 (gdouble, device->num_axes);
++      gdk_device_xi_update_axes (device, xdbe->axes_count,
++                                 xdbe->first_axis, xdbe->axis_data);
 +      gdk_device_xi_translate_axes (device, window,
-                                     xdbe->axis_data,
++                                    device_xi->axis_data,
 +                                    event->button.axes,
 +                                    &event->button.x,
 +                                    &event->button.y);
 +
 +      event->button.state = translate_state (xdbe->state, xdbe->device_state);
 +      event->button.button = xdbe->button;
 +
 +      if (event->button.type == GDK_BUTTON_PRESS)
 +	_gdk_event_button_generate (gdk_drawable_get_display (event->button.window),
 +				    event);
 +
 +      GDK_NOTE (EVENTS,
 +	g_print ("button %s:\t\twindow: %ld  device: %ld  x,y: %f %f  button: %d\n",
 +		 (event->button.type == GDK_BUTTON_PRESS) ? "press" : "release",
 +		 xdbe->window,
 +		 xdbe->deviceid,
 +		 event->button.x, event->button.y,
 +		 xdbe->button));
 +
 +      /* Update the timestamp of the latest user interaction, if the event has
 +       * a valid timestamp.
 +       */
 +      if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
 +	gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
 +				      gdk_event_get_time (event));
 +      return TRUE;
 +    }
 +
 +  if ((xevent->type == device_xi->key_press_type) ||
 +      (xevent->type == device_xi->key_release_type))
 +    {
 +      XDeviceKeyEvent *xdke = (XDeviceKeyEvent *) xevent;
 +
 +      GDK_NOTE (EVENTS,
 +	g_print ("device key %s:\twindow: %ld  device: %ld  keycode: %d\n",
 +		 (event->key.type == GDK_KEY_PRESS) ? "press" : "release",
 +		 xdke->window,
 +		 xdke->deviceid,
 +		 xdke->keycode));
 +
 +      if (xdke->keycode < device_xi->min_keycode ||
 +	  xdke->keycode >= device_xi->min_keycode + device->num_keys)
 +	{
 +	  g_warning ("Invalid device key code received");
 +	  return FALSE;
 +	}
 +
 +      event->key.keyval = device->keys[xdke->keycode - device_xi->min_keycode].keyval;
 +
 +      if (event->key.keyval == 0)
 +	{
 +	  GDK_NOTE (EVENTS,
 +	    g_print ("\t\ttranslation - NONE\n"));
 +
 +	  return FALSE;
 +	}
 +
 +      event->key.type = (xdke->type == device_xi->key_press_type) ?
 +	GDK_KEY_PRESS : GDK_KEY_RELEASE;
 +
 +      event->key.window = g_object_ref (window);
 +      event->key.time = xdke->time;
 +
 +      event->key.state = translate_state (xdke->state, xdke->device_state)
 +	| device->keys[xdke->keycode - device_xi->min_keycode].modifiers;
 +
 +      /* Add a string translation for the key event */
 +      if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xFF))
 +	{
 +	  event->key.length = 1;
 +	  event->key.string = g_new (gchar, 2);
 +	  event->key.string[0] = (gchar) event->key.keyval;
 +	  event->key.string[1] = 0;
 +	}
 +      else
 +	{
 +	  event->key.length = 0;
 +	  event->key.string = g_new0 (gchar, 1);
 +	}
 +
 +      GDK_NOTE (EVENTS,
 +	g_print ("\t\ttranslation - keyval: %d modifiers: %#x\n",
 +		 event->key.keyval,
 +		 event->key.state));
 +
 +      /* Update the timestamp of the latest user interaction, if the event has
 +       * a valid timestamp.
 +       */
 +      if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
 +	gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
 +				      gdk_event_get_time (event));
 +      return TRUE;
 +    }
 +
 +  if (xevent->type == device_xi->motion_notify_type)
 +    {
 +      XDeviceMotionEvent *xdme = (XDeviceMotionEvent *) xevent;
 +
 +      event->motion.device = device;
 +
 +      if (device_xi->in_proximity)
 +        priv->ignore_core_events = TRUE;
 +
 +      event->motion.x_root = (gdouble) xdme->x_root;
 +      event->motion.y_root = (gdouble) xdme->y_root;
 +
 +      event->motion.axes = g_new0 (gdouble, device->num_axes);
++      gdk_device_xi_update_axes (device, xdme->axes_count,
++                                 xdme->first_axis, xdme->axis_data);
 +      gdk_device_xi_translate_axes (device, window,
-                                     xdme->axis_data,
++                                    device_xi->axis_data,
 +                                    event->motion.axes,
 +                                    &event->motion.x,
 +                                    &event->motion.y);
 +
 +      event->motion.type = GDK_MOTION_NOTIFY;
 +      event->motion.window = g_object_ref (window);
 +      event->motion.time = xdme->time;
 +      event->motion.state = translate_state (xdme->state,
 +                                             xdme->device_state);
 +      event->motion.is_hint = xdme->is_hint;
 +
 +      GDK_NOTE (EVENTS,
 +	g_print ("motion notify:\t\twindow: %ld  device: %ld  x,y: %f %f  state %#4x  hint: %s\n",
 +		 xdme->window,
 +		 xdme->deviceid,
 +		 event->motion.x, event->motion.y,
 +		 event->motion.state,
 +		 (xdme->is_hint) ? "true" : "false"));
 +
 +
 +      /* Update the timestamp of the latest user interaction, if the event has
 +       * a valid timestamp.
 +       */
 +      if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
 +	gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
 +				      gdk_event_get_time (event));
 +      return TRUE;
 +    }
 +
 +  if (xevent->type == device_xi->proximity_in_type ||
 +      xevent->type == device_xi->proximity_out_type)
 +    {
 +      XProximityNotifyEvent *xpne = (XProximityNotifyEvent *) xevent;
 +
 +      if (xevent->type == device_xi->proximity_in_type)
 +        {
 +          event->proximity.type = GDK_PROXIMITY_IN;
 +          device_xi->in_proximity = TRUE;
 +          priv->ignore_core_events = TRUE;
 +        }
 +      else
 +        {
 +          event->proximity.type = GDK_PROXIMITY_OUT;
 +          device_xi->in_proximity = FALSE;
 +          priv->ignore_core_events = FALSE;
 +        }
 +
 +      event->proximity.device = device;
 +      event->proximity.window = g_object_ref (window);
 +      event->proximity.time = xpne->time;
 +
 +      /* Update the timestamp of the latest user interaction, if the event has
 +       * a valid timestamp.
 +       */
 +      if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
 +	gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
 +				      gdk_event_get_time (event));
 +      return TRUE;
-   }
++    }
++
++  if (xevent->type == device_xi->state_notify_type)
++    {
++      XDeviceStateNotifyEvent *xdse = (XDeviceStateNotifyEvent *) xevent;
++      XInputClass *input_class = (XInputClass *) xdse->data;
++      int i;
++
++      for (i = 0; i < xdse->num_classes; i++)
++        {
++          if (input_class->class == ValuatorClass)
++            gdk_device_xi_update_axes (device, device->num_axes, 0,
++                                       ((XValuatorState *)input_class)->valuators);
++
++          input_class = (XInputClass *)(((char *)input_class)+input_class->length);
++        }
++
++      GDK_NOTE (EVENTS,
++                g_print ("device state notify:\t\twindow: %ld  device: %ld\n",
++                         xdse->window,
++                         xdse->deviceid));
++
++      return FALSE;
++    }
 +
 +  return FALSE;
 +}
 +
 +static GList *
 +gdk_device_manager_xi_get_devices (GdkDeviceManager *device_manager,
 +                                   GdkDeviceType     type)
 +{
 +  GdkDeviceManagerXIPrivate *priv;
 +
 +  if (type == GDK_DEVICE_TYPE_MASTER)
 +    return GDK_DEVICE_MANAGER_CLASS (gdk_device_manager_xi_parent_class)->get_devices (device_manager, type);
 +  else if (type == GDK_DEVICE_TYPE_FLOATING)
 +    {
 +      priv = GDK_DEVICE_MANAGER_XI_GET_PRIVATE (device_manager);
 +      return g_list_copy (priv->devices);
 +    }
 +  else
 +    return NULL;
 +}
diff --cc gdk/x11/gdkdevicemanager-xi2.c
index 926cd39,0000000..d0ccb2a
mode 100644,000000..100644
--- a/gdk/x11/gdkdevicemanager-xi2.c
+++ b/gdk/x11/gdkdevicemanager-xi2.c
@@@ -1,1133 -1,0 +1,1131 @@@
 +/* GDK - The GIMP Drawing Kit
 + * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 + * Boston, MA 02111-1307, USA.
 + */
 +
 +#include <string.h>
 +
 +#include <gdk/gdkdeviceprivate.h>
 +#include "gdkdevicemanager-xi2.h"
 +#include "gdkeventtranslator.h"
 +#include "gdkdevice-xi2.h"
 +#include "gdkkeysyms.h"
 +#include "gdkx.h"
 +
 +#define HAS_FOCUS(toplevel) ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
 +
 +
 +static void    gdk_device_manager_xi2_constructed (GObject *object);
 +static void    gdk_device_manager_xi2_finalize    (GObject *object);
 +
 +static GList * gdk_device_manager_xi2_get_devices (GdkDeviceManager *device_manager,
 +                                                   GdkDeviceType     type);
 +
 +static void     gdk_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface);
 +
 +static gboolean gdk_device_manager_xi2_translate_event (GdkEventTranslator *translator,
 +                                                        GdkDisplay         *display,
 +                                                        GdkEvent           *event,
 +                                                        XEvent             *xevent);
 +static GdkEventMask gdk_device_manager_xi2_get_handled_events   (GdkEventTranslator *translator);
 +static void         gdk_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
 +                                                                 Window              window,
 +                                                                 GdkEventMask        event_mask);
 +
 +
 +G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerXI2, gdk_device_manager_xi2, GDK_TYPE_DEVICE_MANAGER,
 +                         G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
 +                                                gdk_device_manager_xi2_event_translator_init))
 +
 +
 +static void
 +gdk_device_manager_xi2_class_init (GdkDeviceManagerXI2Class *klass)
 +{
 +  GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
 +  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 +
 +  object_class->constructed = gdk_device_manager_xi2_constructed;
 +  object_class->finalize = gdk_device_manager_xi2_finalize;
 +
 +  device_manager_class->get_devices = gdk_device_manager_xi2_get_devices;
 +}
 +
 +static void
 +gdk_device_manager_xi2_init (GdkDeviceManagerXI2 *device_manager)
 +{
 +  device_manager->id_table = g_hash_table_new_full (g_direct_hash,
 +                                                    g_direct_equal,
 +                                                    NULL,
 +                                                    (GDestroyNotify) g_object_unref);
 +}
 +
 +static void
 +_gdk_device_manager_xi2_select_events (GdkDeviceManager *device_manager,
 +                                       Window            xwindow,
 +                                       XIEventMask      *event_mask)
 +{
 +  GdkDisplay *display;
 +  Display *xdisplay;
 +
 +  display = gdk_device_manager_get_display (device_manager);
 +  xdisplay = GDK_DISPLAY_XDISPLAY (display);
 +
 +  XISelectEvents (xdisplay, xwindow, event_mask, 1);
 +}
 +
 +static void
 +translate_valuator_class (GdkDisplay          *display,
 +                          GdkDevice           *device,
 +                          XIValuatorClassInfo *info,
 +                          gint                 n_valuator)
 +{
 +  static gboolean initialized = FALSE;
 +  static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
 +  GdkAxisUse use = GDK_AXIS_IGNORE;
 +  GdkAtom label;
 +  gint i;
 +
 +  if (!initialized)
 +    {
 +      label_atoms [GDK_AXIS_X] = gdk_x11_get_xatom_by_name_for_display (display, "Abs X");
 +      label_atoms [GDK_AXIS_Y] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Y");
 +      label_atoms [GDK_AXIS_PRESSURE] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Pressure");
 +      label_atoms [GDK_AXIS_XTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt X");
 +      label_atoms [GDK_AXIS_YTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt Y");
 +      label_atoms [GDK_AXIS_WHEEL] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Wheel");
 +      initialized = TRUE;
 +    }
 +
 +  for (i = GDK_AXIS_IGNORE; i <= GDK_AXIS_LAST; i++)
 +    {
 +      if (label_atoms[i] == info->label)
 +        {
 +          use = i;
 +          break;
 +        }
 +    }
 +
 +  if (info->label != None)
 +    label = gdk_x11_xatom_to_atom_for_display (display, info->label);
 +  else
 +    label = GDK_NONE;
 +
 +  _gdk_device_add_axis (device,
 +                        label,
 +                        use,
 +                        info->min,
 +                        info->max,
 +                        info->resolution);
 +}
 +
 +static void
 +translate_device_classes (GdkDisplay      *display,
 +                          GdkDevice       *device,
 +                          XIAnyClassInfo **classes,
 +                          guint            n_classes)
 +{
 +  gint i, n_valuator = 0;
 +
 +  g_object_freeze_notify (G_OBJECT (device));
 +
 +  for (i = 0; i < n_classes; i++)
 +    {
 +      XIAnyClassInfo *class_info = classes[i];
 +
 +      switch (class_info->type)
 +        {
 +        case XIKeyClass:
 +          {
 +            XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info;
 +            gint i;
 +
 +            _gdk_device_set_keys (device, key_info->num_keycodes);
 +
 +            for (i = 0; i < key_info->num_keycodes; i++)
 +              gdk_device_set_key (device, i, key_info->keycodes[i], 0);
 +          }
 +          break;
 +        case XIValuatorClass:
 +          translate_valuator_class (display, device,
 +                                    (XIValuatorClassInfo *) class_info,
 +                                    n_valuator);
 +          n_valuator++;
 +          break;
 +        default:
 +          /* Ignore */
 +          break;
 +        }
 +    }
 +
 +  g_object_thaw_notify (G_OBJECT (device));
 +}
 +
 +static GdkDevice *
 +create_device (GdkDeviceManager *device_manager,
 +               GdkDisplay       *display,
 +               XIDeviceInfo     *dev)
 +{
 +  GdkInputSource input_source;
 +  GdkDeviceType type;
 +  GdkDevice *device;
 +  GdkInputMode mode;
 +
 +  if (dev->use == XIMasterKeyboard || dev->use == XISlaveKeyboard)
 +    input_source = GDK_SOURCE_KEYBOARD;
 +  else
 +    {
 +      gchar *tmp_name;
 +
 +      tmp_name = g_ascii_strdown (dev->name, -1);
 +
-       if (g_str_has_suffix (tmp_name, "pointer"))
-         input_source = GDK_SOURCE_MOUSE;
-       else if (strcmp (tmp_name, "wacom") == 0 ||
-                strcmp (tmp_name, "pen") == 0)
-         input_source = GDK_SOURCE_PEN;
-       else if (strcmp (tmp_name, "eraser") == 0)
++      if (strstr (tmp_name, "eraser"))
 +        input_source = GDK_SOURCE_ERASER;
-       else if (strcmp (tmp_name, "cursor") == 0)
++      else if (strstr (tmp_name, "cursor"))
 +        input_source = GDK_SOURCE_CURSOR;
-       else
++      else if (strstr (tmp_name, "wacom") ||
++               strstr (tmp_name, "pen"))
 +        input_source = GDK_SOURCE_PEN;
++      else
++        input_source = GDK_SOURCE_MOUSE;
 +
 +      g_free (tmp_name);
 +    }
 +
 +  switch (dev->use)
 +    {
 +    case XIMasterKeyboard:
 +    case XIMasterPointer:
 +      type = GDK_DEVICE_TYPE_MASTER;
 +      mode = GDK_MODE_SCREEN;
 +      break;
 +    case XISlaveKeyboard:
 +    case XISlavePointer:
 +      type = GDK_DEVICE_TYPE_SLAVE;
 +      mode = GDK_MODE_DISABLED;
 +      break;
 +    case XIFloatingSlave:
 +    default:
 +      type = GDK_DEVICE_TYPE_FLOATING;
 +      mode = GDK_MODE_DISABLED;
 +      break;
 +    }
 +
 +  device = g_object_new (GDK_TYPE_DEVICE_XI2,
 +                         "name", dev->name,
 +                         "type", type,
 +                         "input-source", input_source,
 +                         "input-mode", mode,
 +                         "has-cursor", (dev->use == XIMasterPointer),
 +                         "display", display,
 +                         "device-manager", device_manager,
 +                         "device-id", dev->deviceid,
 +                         NULL);
 +
 +  translate_device_classes (display, device, dev->classes, dev->num_classes);
 +
 +  return device;
 +}
 +
 +static GdkDevice *
 +add_device (GdkDeviceManagerXI2 *device_manager,
 +            XIDeviceInfo        *dev,
 +            gboolean             emit_signal)
 +{
 +  GdkDisplay *display;
 +  GdkDevice *device;
 +
 +  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
 +  device = create_device (GDK_DEVICE_MANAGER (device_manager), display, dev);
 +
 +  g_hash_table_replace (device_manager->id_table,
 +                        GINT_TO_POINTER (dev->deviceid),
 +                        device);
 +
 +  if (dev->use == XIMasterPointer || dev->use == XIMasterKeyboard)
 +    device_manager->master_devices = g_list_append (device_manager->master_devices, device);
 +  else if (dev->use == XISlavePointer || dev->use == XISlaveKeyboard)
 +    device_manager->slave_devices = g_list_append (device_manager->slave_devices, device);
 +  else if (dev->use == XIFloatingSlave)
 +    device_manager->floating_devices = g_list_append (device_manager->floating_devices, device);
 +  else
 +    g_warning ("Unhandled device: %s\n", device->name);
 +
 +  if (emit_signal)
 +    g_signal_emit_by_name (device_manager, "device-added", device);
 +
 +  return device;
 +}
 +
 +static void
 +remove_device (GdkDeviceManagerXI2 *device_manager,
 +               int                  device_id)
 +{
 +  GdkDevice *device;
 +
 +  device = g_hash_table_lookup (device_manager->id_table,
 +                                GINT_TO_POINTER (device_id));
 +
 +  if (device)
 +    {
 +      device_manager->master_devices = g_list_remove (device_manager->master_devices, device);
 +      device_manager->slave_devices = g_list_remove (device_manager->slave_devices, device);
 +      device_manager->floating_devices = g_list_remove (device_manager->floating_devices, device);
 +
 +      g_signal_emit_by_name (device_manager, "device-removed", device);
 +
 +      g_object_run_dispose (G_OBJECT (device));
 +
 +      g_hash_table_remove (device_manager->id_table,
 +                           GINT_TO_POINTER (device_id));
 +    }
 +}
 +
 +static void
 +relate_devices (gpointer key,
 +                gpointer value,
 +                gpointer user_data)
 +{
 +  GdkDeviceManagerXI2 *device_manager;
 +  GdkDevice *device, *relative;
 +
 +  device_manager = user_data;
 +  device = g_hash_table_lookup (device_manager->id_table, key);
 +  relative = g_hash_table_lookup (device_manager->id_table, value);
 +
 +  _gdk_device_set_relative (device, relative);
 +  _gdk_device_set_relative (relative, device);
 +}
 +
 +static void
 +gdk_device_manager_xi2_constructed (GObject *object)
 +{
 +  GdkDeviceManagerXI2 *device_manager_xi2;
 +  GdkDisplay *display;
 +  GdkScreen *screen;
 +  GHashTable *relations;
 +  Display *xdisplay;
 +  XIDeviceInfo *info, *dev;
 +  int ndevices, i;
 +  XIEventMask event_mask;
 +  unsigned char mask[2] = { 0 };
 +
 +  device_manager_xi2 = GDK_DEVICE_MANAGER_XI2 (object);
 +  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
 +  xdisplay = GDK_DISPLAY_XDISPLAY (display);
 +  relations = g_hash_table_new (NULL, NULL);
 +
 +  info = XIQueryDevice(xdisplay, XIAllDevices, &ndevices);
 +
 +  /* Initialize devices list */
 +  for (i = 0; i < ndevices; i++)
 +    {
 +      GdkDevice *device;
 +
 +      dev = &info[i];
 +      device = add_device (device_manager_xi2, dev, FALSE);
 +
 +      if (dev->use == XIMasterPointer ||
 +          dev->use == XIMasterKeyboard)
 +        {
 +          g_hash_table_insert (relations,
 +                               GINT_TO_POINTER (dev->deviceid),
 +                               GINT_TO_POINTER (dev->attachment));
 +        }
 +    }
 +
 +  XIFreeDeviceInfo(info);
 +
 +  /* Stablish relationships between devices */
 +  g_hash_table_foreach (relations, relate_devices, object);
 +  g_hash_table_destroy (relations);
 +
 +  /* Connect to hierarchy change events */
 +  screen = gdk_display_get_default_screen (display);
 +  XISetMask (mask, XI_HierarchyChanged);
 +  XISetMask (mask, XI_DeviceChanged);
 +
 +  event_mask.deviceid = XIAllDevices;
 +  event_mask.mask_len = sizeof (mask);
 +  event_mask.mask = mask;
 +
 +  _gdk_device_manager_xi2_select_events (GDK_DEVICE_MANAGER (object),
 +                                         GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)),
 +                                         &event_mask);
 +}
 +
 +static void
 +gdk_device_manager_xi2_finalize (GObject *object)
 +{
 +  GdkDeviceManagerXI2 *device_manager_xi2;
 +
 +  device_manager_xi2 = GDK_DEVICE_MANAGER_XI2 (object);
 +
 +  g_list_foreach (device_manager_xi2->master_devices, (GFunc) g_object_unref, NULL);
 +  g_list_free (device_manager_xi2->master_devices);
 +
 +  g_list_foreach (device_manager_xi2->slave_devices, (GFunc) g_object_unref, NULL);
 +  g_list_free (device_manager_xi2->slave_devices);
 +
 +  g_list_foreach (device_manager_xi2->floating_devices, (GFunc) g_object_unref, NULL);
 +  g_list_free (device_manager_xi2->floating_devices);
 +
 +  g_hash_table_destroy (device_manager_xi2->id_table);
 +
 +  G_OBJECT_CLASS (gdk_device_manager_xi2_parent_class)->finalize (object);
 +}
 +
 +static GList *
 +gdk_device_manager_xi2_get_devices (GdkDeviceManager *device_manager,
 +                                    GdkDeviceType     type)
 +{
 +  GdkDeviceManagerXI2 *device_manager_xi2;
 +  GList *list = NULL;
 +
 +  device_manager_xi2 = GDK_DEVICE_MANAGER_XI2 (device_manager);
 +
 +  switch (type)
 +    {
 +    case GDK_DEVICE_TYPE_MASTER:
 +      list = device_manager_xi2->master_devices;
 +      break;
 +    case GDK_DEVICE_TYPE_SLAVE:
 +      list = device_manager_xi2->slave_devices;
 +      break;
 +    case GDK_DEVICE_TYPE_FLOATING:
 +      list = device_manager_xi2->floating_devices;
 +      break;
 +    default:
 +      g_assert_not_reached ();
 +    }
 +
 +  return g_list_copy (list);
 +}
 +
 +static void
 +gdk_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface)
 +{
 +  iface->translate_event = gdk_device_manager_xi2_translate_event;
 +  iface->get_handled_events = gdk_device_manager_xi2_get_handled_events;
 +  iface->select_window_events = gdk_device_manager_xi2_select_window_events;
 +}
 +
 +static void
 +handle_hierarchy_changed (GdkDeviceManagerXI2 *device_manager,
 +                          XIHierarchyEvent    *ev)
 +{
 +  GdkDevice *device;
 +  gint i;
 +
 +  /* We only care about enabled devices */
 +  if (!(ev->flags & XIDeviceEnabled) &&
 +      !(ev->flags & XIDeviceDisabled))
 +    return;
 +
 +  for (i = 0; i < ev->num_info; i++)
 +    {
 +      if (ev->info[i].flags & XIDeviceEnabled)
 +        {
 +          GdkDisplay *display;
 +          Display *xdisplay;
 +          XIDeviceInfo *info;
 +          int ndevices;
 +
 +          display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
 +          xdisplay = GDK_DISPLAY_XDISPLAY (display);
 +
 +          info = XIQueryDevice(xdisplay, ev->info[i].deviceid, &ndevices);
 +          device = add_device (device_manager, &info[0], TRUE);
 +          XIFreeDeviceInfo(info);
 +        }
 +      else if (ev->info[i].flags & XIDeviceDisabled)
 +        remove_device (device_manager, ev->info[i].deviceid);
 +    }
 +}
 +
 +static void
 +handle_device_changed (GdkDeviceManagerXI2  *device_manager,
 +                       XIDeviceChangedEvent *ev)
 +{
 +  GdkDisplay *display;
 +  GdkDevice *device;
 +
 +  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
 +  device = g_hash_table_lookup (device_manager->id_table,
 +                                GUINT_TO_POINTER (ev->deviceid));
 +
 +  _gdk_device_reset_axes (device);
 +  translate_device_classes (display, device, ev->classes, ev->num_classes);
 +}
 +
 +static GdkCrossingMode
 +translate_crossing_mode (int mode)
 +{
 +  switch (mode)
 +    {
 +    case NotifyNormal:
 +      return GDK_CROSSING_NORMAL;
 +    case NotifyGrab:
 +      return GDK_CROSSING_GRAB;
 +    case NotifyUngrab:
 +      return GDK_CROSSING_UNGRAB;
 +    default:
 +      g_assert_not_reached ();
 +    }
 +}
 +
 +static GdkNotifyType
 +translate_notify_type (int detail)
 +{
 +  switch (detail)
 +    {
 +    case NotifyInferior:
 +      return GDK_NOTIFY_INFERIOR;
 +    case NotifyAncestor:
 +      return GDK_NOTIFY_ANCESTOR;
 +    case NotifyVirtual:
 +      return GDK_NOTIFY_VIRTUAL;
 +    case NotifyNonlinear:
 +      return GDK_NOTIFY_NONLINEAR;
 +    case NotifyNonlinearVirtual:
 +      return GDK_NOTIFY_NONLINEAR_VIRTUAL;
 +    default:
 +      g_assert_not_reached ();
 +    }
 +}
 +
 +static gboolean
 +set_screen_from_root (GdkDisplay *display,
 +		      GdkEvent   *event,
 +		      Window      xrootwin)
 +{
 +  GdkScreen *screen;
 +
 +  screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
 +
 +  if (screen)
 +    {
 +      gdk_event_set_screen (event, screen);
 +
 +      return TRUE;
 +    }
 +
 +  return FALSE;
 +}
 +
 +static void
 +set_user_time (GdkEvent *event)
 +{
 +  GdkWindow *window;
 +  guint32 time;
 +
 +  window = gdk_window_get_toplevel (event->any.window);
 +  g_return_if_fail (GDK_IS_WINDOW (window));
 +
 +  time = gdk_event_get_time (event);
 +
 +  /* If an event doesn't have a valid timestamp, we shouldn't use it
 +   * to update the latest user interaction time.
 +   */
 +  if (time != GDK_CURRENT_TIME)
 +    gdk_x11_window_set_user_time (window, time);
 +}
 +
 +static void
 +translate_keyboard_string (GdkEventKey *event)
 +{
 +  gunichar c = 0;
 +  gchar buf[7];
 +
 +  /* Fill in event->string crudely, since various programs
 +   * depend on it.
 +   */
 +  event->string = NULL;
 +
 +  if (event->keyval != GDK_VoidSymbol)
 +    c = gdk_keyval_to_unicode (event->keyval);
 +
 +  if (c)
 +    {
 +      gsize bytes_written;
 +      gint len;
 +
 +      /* Apply the control key - Taken from Xlib
 +       */
 +      if (event->state & GDK_CONTROL_MASK)
 +	{
 +	  if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
 +	  else if (c == '2')
 +	    {
 +	      event->string = g_memdup ("\0\0", 2);
 +	      event->length = 1;
 +	      buf[0] = '\0';
 +              return;
 +	    }
 +	  else if (c >= '3' && c <= '7') c -= ('3' - '\033');
 +	  else if (c == '8') c = '\177';
 +	  else if (c == '/') c = '_' & 0x1F;
 +	}
 +
 +      len = g_unichar_to_utf8 (c, buf);
 +      buf[len] = '\0';
 +
 +      event->string = g_locale_from_utf8 (buf, len,
 +                                          NULL, &bytes_written,
 +                                          NULL);
 +      if (event->string)
 +	event->length = bytes_written;
 +    }
 +  else if (event->keyval == GDK_Escape)
 +    {
 +      event->length = 1;
 +      event->string = g_strdup ("\033");
 +    }
 +  else if (event->keyval == GDK_Return ||
 +	  event->keyval == GDK_KP_Enter)
 +    {
 +      event->length = 1;
 +      event->string = g_strdup ("\r");
 +    }
 +
 +  if (!event->string)
 +    {
 +      event->length = 0;
 +      event->string = g_strdup ("");
 +    }
 +}
 +
 +static void
 +generate_focus_event (GdkWindow *window,
 +		      gboolean   in)
 +{
 +  GdkEvent event;
 +
 +  event.type = GDK_FOCUS_CHANGE;
 +  event.focus_change.window = window;
 +  event.focus_change.send_event = FALSE;
 +  event.focus_change.in = in;
 +
 +  gdk_event_put (&event);
 +}
 +
 +static void
 +handle_focus_change (GdkWindow *window,
 +                     gint       detail,
 +                     gint       mode,
 +                     gboolean   in)
 +{
 +  GdkToplevelX11 *toplevel;
 +  gboolean had_focus;
 +
 +  toplevel = _gdk_x11_window_get_toplevel (window);
 +
 +  if (!toplevel)
 +    return;
 +
 +  had_focus = HAS_FOCUS (toplevel);
 +
 +  switch (detail)
 +    {
 +    case NotifyAncestor:
 +    case NotifyVirtual:
 +      /* When the focus moves from an ancestor of the window to
 +       * the window or a descendent of the window, *and* the
 +       * pointer is inside the window, then we were previously
 +       * receiving keystroke events in the has_pointer_focus
 +       * case and are now receiving them in the
 +       * has_focus_window case.
 +       */
 +      if (toplevel->has_pointer &&
 +          mode != NotifyGrab &&
 +          mode != NotifyUngrab)
 +        toplevel->has_pointer_focus = (in) ? FALSE : TRUE;
 +
 +      /* fall through */
 +    case NotifyNonlinear:
 +    case NotifyNonlinearVirtual:
 +      if (mode != NotifyGrab &&
 +          mode != NotifyUngrab)
 +        toplevel->has_focus_window = (in) ? TRUE : FALSE;
 +      /* We pretend that the focus moves to the grab
 +       * window, so we pay attention to NotifyGrab
 +       * NotifyUngrab, and ignore NotifyWhileGrabbed
 +       */
 +      if (mode != NotifyWhileGrabbed)
 +        toplevel->has_focus = (in) ? TRUE : FALSE;
 +      break;
 +    case NotifyPointer:
 +      /* The X server sends NotifyPointer/NotifyGrab,
 +       * but the pointer focus is ignored while a
 +       * grab is in effect
 +       */
 +      if (mode != NotifyGrab &&
 +          mode != NotifyUngrab)
 +        toplevel->has_pointer_focus = (in) ? TRUE :FALSE;
 +      break;
 +    case NotifyInferior:
 +    case NotifyPointerRoot:
 +    case NotifyDetailNone:
 +      break;
 +    }
 +
 +  if (HAS_FOCUS (toplevel) != had_focus)
 +    generate_focus_event (window, (in) ? TRUE : FALSE);
 +}
 +
 +static gdouble *
 +translate_axes (GdkDevice       *device,
 +                gdouble          x,
 +                gdouble          y,
 +                GdkWindow       *window,
 +                XIValuatorState *valuators)
 +{
 +  guint n_axes, i;
 +  gint width, height;
 +  gdouble *axes;
 +  double *vals;
 +
 +  g_object_get (device, "n-axes", &n_axes, NULL);
 +
 +  axes = g_new0 (gdouble, n_axes);
 +  vals = valuators->values;
 +
 +  gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
 +
 +  for (i = 0; i < valuators->mask_len * 8; i++)
 +    {
 +      GdkAxisUse use;
 +      gdouble val;
 +
 +      if (!XIMaskIsSet (valuators->mask, i))
 +        continue;
 +
 +      use = _gdk_device_get_axis_use (device, i);
 +      val = *vals++;
 +
 +      switch (use)
 +        {
 +        case GDK_AXIS_X:
 +        case GDK_AXIS_Y:
 +          if (device->mode == GDK_MODE_WINDOW)
 +            _gdk_device_translate_window_coord (device, window, i, val, &axes[i]);
 +          else
 +            {
 +              if (use == GDK_AXIS_X)
 +                axes[i] = x;
 +              else
 +                axes[i] = y;
 +            }
 +          break;
 +        default:
 +          _gdk_device_translate_axis (device, i, val, &axes[i]);
 +          break;
 +        }
 +    }
 +
 +  return axes;
 +}
 +
 +static gboolean
 +is_parent_of (GdkWindow *parent,
 +              GdkWindow *child)
 +{
 +  GdkWindow *w;
 +
 +  w = child;
 +  while (w != NULL)
 +    {
 +      if (w == parent)
 +	return TRUE;
 +
 +      w = gdk_window_get_parent (w);
 +    }
 +
 +  return FALSE;
 +}
 +
 +static GdkWindow *
 +get_event_window (GdkEventTranslator *translator,
 +                  XIEvent            *ev)
 +{
 +  GdkDisplay *display;
 +  GdkWindow *window = NULL;
 +
 +  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (translator));
 +
 +  switch (ev->evtype)
 +    {
 +    case XI_KeyPress:
 +    case XI_KeyRelease:
 +    case XI_ButtonPress:
 +    case XI_ButtonRelease:
 +    case XI_Motion:
 +      {
 +        XIDeviceEvent *xev = (XIDeviceEvent *) ev;
 +
 +        window = gdk_window_lookup_for_display (display, xev->event);
 +
 +        /* Apply keyboard grabs to non-native windows */
 +        if (ev->evtype == XI_KeyPress || ev->evtype == XI_KeyRelease)
 +          {
 +            GdkDeviceGrabInfo *info;
 +            GdkDevice *device;
 +            gulong serial;
 +
 +            device = g_hash_table_lookup (GDK_DEVICE_MANAGER_XI2 (translator)->id_table,
 +                                          GUINT_TO_POINTER (((XIDeviceEvent *) ev)->deviceid));
 +
 +            serial = _gdk_windowing_window_get_next_serial (display);
 +            info = _gdk_display_has_device_grab (display, device, serial);
 +
 +            if (info &&
 +                (!is_parent_of (info->window, window) ||
 +                 !info->owner_events))
 +              {
 +                /* Report key event against grab window */
 +                window = info->window;
 +              }
 +          }
 +      }
 +      break;
 +    case XI_Enter:
 +    case XI_Leave:
 +    case XI_FocusIn:
 +    case XI_FocusOut:
 +      {
 +        XIEnterEvent *xev = (XIEnterEvent *) ev;
 +
 +        window = gdk_window_lookup_for_display (display, xev->event);
 +      }
 +      break;
 +    }
 +
 +  return window;
 +}
 +
 +static gboolean
 +gdk_device_manager_xi2_translate_event (GdkEventTranslator *translator,
 +                                        GdkDisplay         *display,
 +                                        GdkEvent           *event,
 +                                        XEvent             *xevent)
 +{
 +  GdkDeviceManagerXI2 *device_manager;
 +  XGenericEventCookie *cookie;
 +  gboolean return_val = TRUE;
 +  GdkWindow *window;
 +  XIEvent *ev;
 +  Display *dpy;
 +
 +  dpy = GDK_DISPLAY_XDISPLAY (display);
 +  device_manager = (GdkDeviceManagerXI2 *) translator;
 +  cookie = &xevent->xcookie;
 +
 +  if (!XGetEventData (dpy, cookie))
 +    return FALSE;
 +
 +  if (cookie->type != GenericEvent ||
 +      cookie->extension != device_manager->opcode)
 +    {
 +      XFreeEventData (dpy, cookie);
 +      return FALSE;
 +    }
 +
 +  ev = (XIEvent *) cookie->data;
 +
 +  window = get_event_window (translator, ev);
 +
 +  if (window && GDK_WINDOW_DESTROYED (window))
 +    {
 +      XFreeEventData (dpy, cookie);
 +      return FALSE;
 +    }
 +
 +  if (ev->evtype == XI_Motion ||
 +      ev->evtype == XI_ButtonRelease)
 +    {
 +      if (_gdk_moveresize_handle_event (xevent))
 +        {
 +          XFreeEventData (dpy, cookie);
 +          return FALSE;
 +        }
 +    }
 +
 +  switch (ev->evtype)
 +    {
 +    case XI_HierarchyChanged:
 +      handle_hierarchy_changed (device_manager,
 +                                (XIHierarchyEvent *) ev);
 +      return_val = FALSE;
 +      break;
 +    case XI_DeviceChanged:
 +      handle_device_changed (device_manager,
 +                             (XIDeviceChangedEvent *) ev);
 +      return_val = FALSE;
 +      break;
 +    case XI_KeyPress:
 +    case XI_KeyRelease:
 +      {
 +        XIDeviceEvent *xev = (XIDeviceEvent *) ev;
 +        GdkKeymap *keymap = gdk_keymap_get_for_display (display);
 +
 +        event->key.type = xev->evtype == XI_KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
 +
 +        event->key.window = window;
 +
 +        event->key.time = xev->time;
 +        event->key.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
 +        event->key.group = _gdk_x11_get_group_for_state (display, event->key.state);
 +
 +        event->key.hardware_keycode = xev->detail;
 +        event->key.is_modifier = _gdk_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
 +
 +        event->key.device = g_hash_table_lookup (device_manager->id_table,
 +                                                 GUINT_TO_POINTER (xev->deviceid));
 +
 +        _gdk_keymap_add_virtual_modifiers (keymap, &event->key.state);
 +
 +        event->key.keyval = GDK_VoidSymbol;
 +
 +        gdk_keymap_translate_keyboard_state (keymap,
 +                                             event->key.hardware_keycode,
 +                                             event->key.state,
 +                                             event->key.group,
 +                                             &event->key.keyval,
 +                                             NULL, NULL, NULL);
 +
 +        translate_keyboard_string ((GdkEventKey *) event);
 +
 +        if (ev->evtype == XI_KeyPress)
 +          set_user_time (event);
 +
 +        /* FIXME: emulate autorepeat on key
 +         * release? XI2 seems attached to Xkb.
 +         */
 +      }
 +
 +      break;
 +    case XI_ButtonPress:
 +    case XI_ButtonRelease:
 +      {
 +        XIDeviceEvent *xev = (XIDeviceEvent *) ev;
 +
 +        switch (xev->detail)
 +          {
 +          case 4:
 +          case 5:
 +          case 6:
 +          case 7:
 +            event->scroll.type = GDK_SCROLL;
 +
 +            if (xev->detail == 4)
 +              event->scroll.direction = GDK_SCROLL_UP;
 +            else if (xev->detail == 5)
 +              event->scroll.direction = GDK_SCROLL_DOWN;
 +            else if (xev->detail == 6)
 +              event->scroll.direction = GDK_SCROLL_LEFT;
 +            else
 +              event->scroll.direction = GDK_SCROLL_RIGHT;
 +
 +            event->scroll.window = window;
 +            event->scroll.time = xev->time;
 +            event->scroll.x = (gdouble) xev->event_x;
 +            event->scroll.y = (gdouble) xev->event_y;
 +            event->scroll.x_root = (gdouble) xev->root_x;
 +            event->scroll.y_root = (gdouble) xev->root_y;
 +
 +            event->scroll.device = g_hash_table_lookup (device_manager->id_table,
 +                                                        GUINT_TO_POINTER (xev->deviceid));
 +
 +            event->scroll.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
 +            break;
 +          default:
 +            event->button.type = (ev->evtype == XI_ButtonPress) ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
 +
 +            event->button.window = window;
 +            event->button.time = xev->time;
 +            event->button.x = (gdouble) xev->event_x;
 +            event->button.y = (gdouble) xev->event_y;
 +            event->button.x_root = (gdouble) xev->root_x;
 +            event->button.y_root = (gdouble) xev->root_y;
 +
 +            event->button.device = g_hash_table_lookup (device_manager->id_table,
 +                                                        GUINT_TO_POINTER (xev->deviceid));
 +
 +            event->button.axes = translate_axes (event->button.device,
 +                                                 event->button.x,
 +                                                 event->button.y,
 +                                                 event->button.window,
 +                                                 &xev->valuators);
 +
 +            if (event->button.device->mode == GDK_MODE_WINDOW)
 +              {
 +                GdkDevice *device = event->button.device;
 +
 +                /* Update event coordinates from axes */
 +                gdk_device_get_axis (device, event->button.axes, GDK_AXIS_X, &event->button.x);
 +                gdk_device_get_axis (device, event->button.axes, GDK_AXIS_Y, &event->button.y);
 +              }
 +
 +            event->button.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
 +            event->button.button = xev->detail;
 +          }
 +
 +        if (!set_screen_from_root (display, event, xev->root))
 +          {
 +            return_val = FALSE;
 +            break;
 +          }
 +
 +        set_user_time (event);
 +
 +        break;
 +      }
 +    case XI_Motion:
 +      {
 +        XIDeviceEvent *xev = (XIDeviceEvent *) ev;
 +
 +        event->motion.type = GDK_MOTION_NOTIFY;
 +
 +        event->motion.window = window;
 +
 +        event->motion.time = xev->time;
 +        event->motion.x = (gdouble) xev->event_x;
 +        event->motion.y = (gdouble) xev->event_y;
 +        event->motion.x_root = (gdouble) xev->root_x;
 +        event->motion.y_root = (gdouble) xev->root_y;
 +
 +        event->motion.device = g_hash_table_lookup (device_manager->id_table,
 +                                                    GINT_TO_POINTER (xev->deviceid));
 +
 +        event->motion.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
 +
 +        /* There doesn't seem to be motion hints in XI */
 +        event->motion.is_hint = FALSE;
 +
 +        event->motion.axes = translate_axes (event->motion.device,
 +                                             event->motion.x,
 +                                             event->motion.y,
 +                                             event->motion.window,
 +                                             &xev->valuators);
 +
 +        if (event->motion.device->mode == GDK_MODE_WINDOW)
 +          {
 +            GdkDevice *device = event->motion.device;
 +
 +            /* Update event coordinates from axes */
 +            gdk_device_get_axis (device, event->motion.axes, GDK_AXIS_X, &event->motion.x);
 +            gdk_device_get_axis (device, event->motion.axes, GDK_AXIS_Y, &event->motion.y);
 +          }
 +      }
 +      break;
 +    case XI_Enter:
 +    case XI_Leave:
 +      {
 +        XIEnterEvent *xev = (XIEnterEvent *) ev;
 +
 +        event->crossing.type = (ev->evtype == XI_Enter) ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
 +
 +        event->crossing.x = (gdouble) xev->event_x;
 +        event->crossing.y = (gdouble) xev->event_y;
 +        event->crossing.x_root = (gdouble) xev->root_x;
 +        event->crossing.y_root = (gdouble) xev->root_y;
 +        event->crossing.time = xev->time;
 +        event->crossing.focus = xev->focus;
 +
 +        event->crossing.window = window;
 +        event->crossing.subwindow = gdk_window_lookup_for_display (display, xev->child);
 +        event->crossing.device = g_hash_table_lookup (device_manager->id_table,
 +                                                      GINT_TO_POINTER (xev->deviceid));
 +
 +        event->crossing.mode = translate_crossing_mode (xev->mode);
 +        event->crossing.detail = translate_notify_type (xev->detail);
 +        event->crossing.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
 +      }
 +      break;
 +    case XI_FocusIn:
 +    case XI_FocusOut:
 +      {
 +        XIEnterEvent *xev = (XIEnterEvent *) ev;
 +
 +        handle_focus_change (window, xev->detail, xev->mode,
 +                             (ev->evtype == XI_FocusIn) ? TRUE : FALSE);
 +
 +        return_val = FALSE;
 +      }
 +    default:
 +      return_val = FALSE;
 +      break;
 +    }
 +
 +  event->any.send_event = cookie->send_event;
 +
 +  if (return_val)
 +    {
 +      if (event->any.window)
 +        g_object_ref (event->any.window);
 +
 +      if (((event->any.type == GDK_ENTER_NOTIFY) ||
 +	   (event->any.type == GDK_LEAVE_NOTIFY)) &&
 +	  (event->crossing.subwindow != NULL))
 +        g_object_ref (event->crossing.subwindow);
 +    }
 +  else
 +    {
 +      /* Mark this event as having no resources to be freed */
 +      event->any.window = NULL;
 +      event->any.type = GDK_NOTHING;
 +    }
 +
 +  XFreeEventData (dpy, cookie);
 +
 +  return return_val;
 +}
 +
 +static GdkEventMask
 +gdk_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
 +{
 +  return (GDK_KEY_PRESS_MASK |
 +          GDK_KEY_RELEASE_MASK |
 +          GDK_BUTTON_PRESS_MASK |
 +          GDK_BUTTON_RELEASE_MASK |
 +          GDK_SCROLL_MASK |
 +          GDK_ENTER_NOTIFY_MASK |
 +          GDK_LEAVE_NOTIFY_MASK |
 +          GDK_POINTER_MOTION_MASK |
 +          GDK_POINTER_MOTION_HINT_MASK |
 +          GDK_BUTTON1_MOTION_MASK |
 +          GDK_BUTTON2_MOTION_MASK |
 +          GDK_BUTTON3_MOTION_MASK |
 +          GDK_BUTTON_MOTION_MASK |
 +          GDK_FOCUS_CHANGE_MASK);
 +}
 +
 +static void
 +gdk_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
 +                                             Window              window,
 +                                             GdkEventMask        evmask)
 +{
 +  GdkDeviceManager *device_manager;
 +  XIEventMask event_mask;
 +
 +  device_manager = GDK_DEVICE_MANAGER (translator);
 +
 +  event_mask.deviceid = XIAllMasterDevices;
 +  event_mask.mask = gdk_device_xi2_translate_event_mask (evmask, &event_mask.mask_len);
 +
 +  _gdk_device_manager_xi2_select_events (device_manager, window, &event_mask);
 +  g_free (event_mask.mask);
 +}
diff --cc gdk/x11/gdkwindow-x11.c
index 28f0589,a8dd83b..40c957b
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@@ -3258,11 -3212,11 +3258,12 @@@ gdk_display_warp_device (GdkDisplay *di
  }
  
  GdkWindow*
 -_gdk_windowing_window_at_pointer (GdkDisplay *display,
 -                                  gint       *win_x,
 -				  gint       *win_y,
 -				  GdkModifierType *mask,
 -				  gboolean   get_toplevel)
 +_gdk_windowing_window_at_device_position (GdkDisplay      *display,
 +                                          GdkDevice       *device,
 +                                          gint            *win_x,
 +                                          gint            *win_y,
-                                           GdkModifierType *mask)
++                                          GdkModifierType *mask,
++                                          gboolean         get_toplevel)
  {
    GdkWindow *window;
    GdkScreen *screen;
@@@ -3275,9 -3240,30 +3276,9 @@@
     * and the result.
     */
    gdk_x11_display_grab (display);
 -  if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client)) 
 -    {
 -      XQueryPointer (xdisplay, xwindow,
 -		     &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
 -      if (root == xwindow)
 -	xwindow = child;
 -      else
 -	xwindow = root;
 -      
 -      while (xwindow)
 -	{
 -	  xwindow_last = xwindow;
 -	  XQueryPointer (xdisplay, xwindow,
 -			 &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
 -	  if (get_toplevel &&
 -	      (window = gdk_window_lookup_for_display (display, xwindow_last)) != NULL &&
 -	      GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
 -	    {
 -	      xwindow = xwindow_last;
 -	      break;
 -	    }
 -	}
 -    } 
 -  else 
 +  if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
-     window = GDK_DEVICE_GET_CLASS (device)->window_at_position (device, win_x, win_y, mask);
++    window = GDK_DEVICE_GET_CLASS (device)->window_at_position (device, win_x, win_y, mask, get_toplevel);
 +  else
      {
        gint i, screens, width, height;
        GList *toplevels, *list;
@@@ -3348,18 -3324,21 +3349,22 @@@
  	  gdk_flush ();
  	  if (gdk_error_trap_pop ())
  	    break;
+ 	  if (get_toplevel &&
+ 	      (window = gdk_window_lookup_for_display (display, xwindow_last)) != NULL &&
+ 	      GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
+ 	    break;
  	}
 +
 +      window = gdk_window_lookup_for_display (display, xwindow_last);
 +
 +      *win_x = window ? winx : -1;
 +      *win_y = window ? winy : -1;
 +      if (mask)
 +        *mask = xmask;
      }
 -  
 +
    gdk_x11_display_ungrab (display);
  
 -  window = gdk_window_lookup_for_display (display, xwindow_last);
 -  *win_x = window ? winx : -1;
 -  *win_y = window ? winy : -1;
 -  if (mask)
 -    *mask = xmask;
 -  
    return window;
  }
  



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]