[gtk+/broadway: 1/71] [broadway] Copy X backend to broadway



commit 5b480e1b0de0c8184cb2805ac85f7362c42fb2f6
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Nov 12 13:18:58 2010 +0100

    [broadway] Copy X backend to broadway

 configure.ac                                |  271 ++-
 gdk/Makefile.am                             |    8 +-
 gdk/broadway/Makefile.am                    |   71 +
 gdk/broadway/MwmUtil.h                      |  136 +
 gdk/broadway/gdkapplaunchcontext-broadway.c |  440 +++
 gdk/broadway/gdkasync.c                     |  845 ++++
 gdk/broadway/gdkasync.h                     |   75 +
 gdk/broadway/gdkcursor-broadway.c           | 1040 +++++
 gdk/broadway/gdkdevice-broadway.c           |  502 +++
 gdk/broadway/gdkdevice-broadway.h           |   52 +
 gdk/broadway/gdkdevicemanager-broadway.c    |  920 +++++
 gdk/broadway/gdkdevicemanager-broadway.h    |   54 +
 gdk/broadway/gdkdisplay-broadway.c          | 2977 ++++++++++++++
 gdk/broadway/gdkdisplay-broadway.h          |  160 +
 gdk/broadway/gdkdnd-broadway.c              | 4035 +++++++++++++++++++
 gdk/broadway/gdkdrawable-broadway.c         |  235 ++
 gdk/broadway/gdkdrawable-broadway.h         |   75 +
 gdk/broadway/gdkeventsource.c               |  435 +++
 gdk/broadway/gdkeventsource.h               |   46 +
 gdk/broadway/gdkeventtranslator.c           |   89 +
 gdk/broadway/gdkeventtranslator.h           |   65 +
 gdk/broadway/gdkgeometry-broadway.c         |  390 ++
 gdk/broadway/gdkglobals-broadway.c          |   37 +
 gdk/broadway/gdkim-broadway.c               |  103 +
 gdk/broadway/gdkinput.c                     |  231 ++
 gdk/broadway/gdkkeys-broadway.c             | 1859 +++++++++
 gdk/broadway/gdkmain-broadway.c             |  698 ++++
 gdk/broadway/gdkprivate-broadway.h          |  162 +
 gdk/broadway/gdkproperty-broadway.c         |  761 ++++
 gdk/broadway/gdkscreen-broadway.c           | 2003 ++++++++++
 gdk/broadway/gdkscreen-broadway.h           |  129 +
 gdk/broadway/gdkselection-broadway.c        |  891 +++++
 gdk/broadway/gdksettings.c                  |  128 +
 gdk/broadway/gdkspawn-broadway.c            |  214 +
 gdk/broadway/gdktestutils-broadway.c        |  254 ++
 gdk/broadway/gdkvisual-broadway.c           |  730 ++++
 gdk/broadway/gdkwindow-broadway.c           | 5583 +++++++++++++++++++++++++++
 gdk/broadway/gdkwindow-broadway.h           |  162 +
 gdk/broadway/gdkx.h                         |  169 +
 gdk/broadway/gdkxftdefaults.c               |  268 ++
 gdk/broadway/gdkxid.c                       |  133 +
 gdk/broadway/xsettings-client.c             |  611 +++
 gdk/broadway/xsettings-client.h             |   79 +
 gdk/broadway/xsettings-common.c             |  267 ++
 gdk/broadway/xsettings-common.h             |  132 +
 gtk/Makefile.am                             |    6 +-
 tests/testsocket_common.c                   |    2 +
 47 files changed, 28520 insertions(+), 13 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 3ac0bec..12ae11d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -258,13 +258,13 @@ else
   gdktarget=x11
 fi
 
-AC_ARG_WITH(gdktarget, [  --with-gdktarget=[[x11/win32/quartz]] select non-default GDK target],
+AC_ARG_WITH(gdktarget, [  --with-gdktarget=[[x11/win32/quartz/broadway]] select non-default GDK target],
 	gdktarget=$with_gdktarget)
 
 AC_SUBST(gdktarget)
 case $gdktarget in
-  x11|win32|quartz) ;;
-  *) AC_MSG_ERROR([Invalid target for GDK: use x11, quartz or win32.]);;
+  x11|win32|quartz|broadway) ;;
+  *) AC_MSG_ERROR([Invalid target for GDK: use x11, broadway, quartz or win32.]);;
 esac
 
 gdktargetlib=libgdk-$gdktarget-$GTK_API_VERSION.la
@@ -367,15 +367,18 @@ PKG_CHECK_MODULES(BASE_DEPENDENCIES,
 ## In addition to checking that cairo is present, we also need to
 ## check that the correct cairo backend is there. E.g. if the GDK
 ## target is win32 we need the cairo-win32 backend and so on.
-cairo_backend=$gdktarget
+cairo_backend=cairo-$gdktarget
 
 # GDK calls the xlib backend "x11," cairo calls it "xlib." Other
 # backend names are identical.
-if test "x$cairo_backend" = "xx11"; then
-   cairo_backend=xlib
+if test "x$cairo_backend" = "xcairo-x11"; then
+   cairo_backend=cairo-xlib
+fi
+if test "x$cairo_backend" = "xcairo-broadway"; then
+   cairo_backend=cairo
 fi
 PKG_CHECK_MODULES(CAIRO_BACKEND,
-  [cairo-$cairo_backend >= cairo_required_version])
+  [$cairo_backend >= cairo_required_version])
 
 if test "$os_win32" != yes; then
     # libtool option to control which symbols are exported
@@ -1185,6 +1188,250 @@ else
   AM_CONDITIONAL(USE_QUARTZ, false)
 fi
 
+if test "x$gdktarget" = "xbroadway" ; then
+  X_PACKAGES=fontconfig
+
+  #
+  # We use fontconfig very peripherally when decoding the default
+  # settings.
+  #
+  if $PKG_CONFIG --exists fontconfig; then : ; else
+    AC_MSG_ERROR([
+*** fontconfig (http://www.fontconfig.org) is required by the X11 backend.])
+  fi
+
+  #
+  # Check for basic X packages; we use pkg-config if available
+  #
+  if $PKG_CONFIG --exists x11 xext; then
+    have_base_x_pc=true
+    X_PACKAGES="$X_PACKAGES x11 xext"
+    x_libs="`$PKG_CONFIG --libs x11 xext`"
+    X_CFLAGS="`$PKG_CONFIG --cflags x11 xext`"
+
+    # Strip out any .la files that pkg-config might give us (this happens
+    # with -uninstalled.pc files)
+    x_libs_for_checks=
+    for I in $x_libs ; do
+      case $I in
+        *.la) ;;
+        *) x_libs_for_checks="$x_libs_for_checks $I" ;;
+      esac
+    done
+
+    GTK_PACKAGES_FOR_X="x11"
+  else
+    have_base_x_pc=false
+    AC_PATH_XTRA
+    if test x$no_x = xyes ; then
+      AC_MSG_ERROR([X development libraries not found])
+    fi
+
+    x_cflags="$X_CFLAGS"
+    x_libs_for_checks="$X_LIBS -lXext -lX11 $X_EXTRA_LIBS"
+
+    GTK_DEP_LIBS_FOR_X="$X_LIBS -lX11 $X_EXTRA_LIBS"
+  fi
+
+  # Extra libraries found during checks (-lXinerama, etc), not from pkg-config.
+  x_extra_libs=
+
+  gtk_save_cppflags="$CPPFLAGS"
+  CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+
+  gtk_save_LIBS=$LIBS
+  LIBS="$x_libs_for_checks $LIBS"
+
+  # Sanity check for the X11 and Xext libraries. While everything we need from
+  # Xext is optional, the chances a system has *none* of these things is so
+  # small that we just unconditionally require it.
+  AC_CHECK_FUNC(XOpenDisplay, :,
+                AC_MSG_ERROR([*** libX11 not found. Check 'config.log' for more details.]))
+  AC_CHECK_FUNC(XextFindDisplay, :,
+                AC_MSG_ERROR([*** libXext not found. Check 'config.log' for more details.]))
+
+  # Check for xReply
+
+  AC_MSG_CHECKING([if <X11/extensions/XIproto.h> is needed for xReply])
+  AC_TRY_COMPILE([#include <X11/Xlibint.h>],
+      [xReply *rep;],
+      [AC_MSG_RESULT([no])],
+      [AC_TRY_COMPILE([#include <X11/extensions/XIproto.h>
+#include <X11/Xlibint.h>],
+           [xReply *rep;],
+           [AC_MSG_RESULT([yes])
+            AC_DEFINE([NEED_XIPROTO_H_FOR_XREPLY], 1,
+                      [Define if <X11/extensions/XIproto.h> needed for xReply])],
+           [AC_MSG_RESULT([unknown])
+            AC_MSG_ERROR([xReply type unavailable. X11 is too old])])])
+
+  # Check for XConvertCase, XInternAtoms (X11R6 specific)
+
+  AC_CHECK_FUNCS(XConvertCase XInternAtoms)
+
+  # Generic X11R6 check needed for XIM support; we could
+  # probably use this to replace the above, but we'll
+  # leave the separate checks for XConvertCase and XInternAtoms
+  # for clarity
+
+  have_x11r6=false
+  AC_CHECK_FUNC(XAddConnectionWatch,
+      have_x11r6=true)
+
+  if $have_x11r6; then
+    AC_DEFINE(HAVE_X11R6, 1, [Define if we have X11R6])
+  fi
+  AM_CONDITIONAL(HAVE_X11R6, $have_x11r6)
+
+  # Check for XKB support.
+
+  if test "x$enable_xkb" = "xyes"; then
+        AC_MSG_WARN(XKB support explicitly enabled)
+        AC_DEFINE(HAVE_XKB, 1, [Define to use XKB extension])
+  elif test "x$enable_xkb" = "xmaybe"; then
+        AC_CHECK_FUNC(XkbQueryExtension,
+                      AC_DEFINE(HAVE_XKB, 1, [Define to use XKB extension]))
+  else
+        AC_MSG_WARN(XKB support explicitly disabled)
+  fi
+
+  # Check for shaped window extension
+
+  AC_CHECK_FUNC(XShapeCombineMask, :,
+     [AC_MSG_ERROR([Shape extension not found, check your development headers])])
+
+  # X SYNC check
+  gtk_save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS $x_cflags"
+
+  AC_CHECK_FUNC(XSyncQueryExtension,
+      [AC_CHECK_HEADER(X11/extensions/sync.h,
+	  AC_DEFINE(HAVE_XSYNC, 1, [Have the SYNC extension library]),
+	  :, [#include <X11/Xlib.h>])])
+
+  CFLAGS="$gtk_save_CFLAGS"
+
+  if test "x$enable_xinerama" = "xyes"; then
+    # Check for Xinerama extension (Solaris impl or Xfree impl)
+    gtk_save_cppflags="$CPPFLAGS"
+    CPPFLAGS="$CPPFLAGS $x_cflags"
+
+    # Check for XFree
+    AC_MSG_CHECKING(for Xinerama support on XFree86)
+
+    have_xfree_xinerama=false
+    if $PKG_CONFIG --exists xinerama ; then
+       have_xfree_xinerama=true
+       X_PACKAGES="$X_PACKAGES xinerama"
+    else
+       AC_CHECK_LIB(Xinerama, XineramaQueryExtension,
+	   [AC_CHECK_HEADER(X11/extensions/Xinerama.h,
+	   [GTK_ADD_LIB(x_extra_libs,Xinerama)
+	   have_xfree_xinerama=true], :,
+           [#include <X11/Xlib.h>])])
+    fi
+
+    if $have_xfree_xinerama ; then
+      AC_DEFINE(HAVE_XFREE_XINERAMA, 1,
+                [Define to 1 if XFree Xinerama is available])
+      AC_DEFINE(HAVE_XINERAMA, 1,
+                [Define to 1 is Xinerama is available])
+      AC_MSG_RESULT(yes)
+    else
+      AC_MSG_RESULT(no)
+
+      case "$host" in
+        *-*-solaris*)
+            # Check for solaris
+	    AC_MSG_CHECKING(for Xinerama support on Solaris)
+
+	    have_solaris_xinerama=false
+	    AC_CHECK_FUNC(XineramaGetInfo,
+	        [AC_CHECK_HEADER(X11/extensions/xinerama.h,
+		    [have_solaris_xinerama=true], :,
+		    [#include <X11/Xlib.h>])])
+
+            if $have_solaris_xinerama ; then
+              AC_DEFINE(HAVE_SOLARIS_XINERAMA, 1,
+                        [Define to 1 if solaris xinerama is available])
+	      AC_DEFINE(HAVE_XINERAMA, 1,
+                        [Define to 1 if xinerama is available])
+              AC_MSG_RESULT(yes)
+            else
+              AC_MSG_RESULT(no)
+            fi
+            ;;
+        *)
+            ;;
+      esac
+    fi
+  fi
+
+  AC_DEFINE(XINPUT_NONE, 1, [Define to 1 if no XInput should be used])
+  AM_CONDITIONAL(XINPUT_XFREE, false)
+  AM_CONDITIONAL(XINPUT_2, false)
+
+  # Check for the RANDR extension
+  if $PKG_CONFIG --exists "xrandr >= 1.2.99" ; then
+     AC_DEFINE(HAVE_RANDR, 1, [Have the Xrandr extension library])
+
+     X_PACKAGES="$X_PACKAGES xrandr"
+  fi
+
+  # Checks for Xcursor library
+
+  if $PKG_CONFIG --exists xcursor ; then
+    AC_DEFINE(HAVE_XCURSOR, 1, [Have the Xcursor library])
+
+    X_PACKAGES="$X_PACKAGES xcursor"
+  fi
+
+  # Checks for XFixes extension
+
+  if $PKG_CONFIG --exists xfixes ; then
+    AC_DEFINE(HAVE_XFIXES, 1, [Have the XFIXES X extension])
+
+    X_PACKAGES="$X_PACKAGES xfixes"
+    GTK_PACKAGES_FOR_X="$GTK_PACKAGES_FOR_X xfixes"
+  fi
+
+  # Checks for Xcomposite extension
+
+  if $PKG_CONFIG --exists xcomposite ; then
+    AC_DEFINE(HAVE_XCOMPOSITE, 1, [Have the XCOMPOSITE X extension])
+
+    X_PACKAGES="$X_PACKAGES xcomposite"
+    GTK_PACKAGES_FOR_X="$GTK_PACKAGES_FOR_X xcomposite"
+  fi
+
+  # Checks for Xdamage extension
+
+  if $PKG_CONFIG --exists xdamage ; then
+    AC_DEFINE(HAVE_XDAMAGE, 1, [Have the XDAMAGE X extension])
+
+    X_PACKAGES="$X_PACKAGES xdamage"
+    GTK_PACKAGES_FOR_X="$GTK_PACKAGES_FOR_X xdamage"
+  fi
+
+  if $have_base_x_pc ; then
+    GDK_EXTRA_LIBS="$x_extra_libs"
+  else
+    GDK_EXTRA_LIBS="$X_LIBS $x_extra_libs -lXext -lX11 $GDK_EXTRA_LIBS"
+  fi
+
+  CPPFLAGS="$gtk_save_cppflags"
+  LIBS="$gtk_save_libs"
+
+  AM_CONDITIONAL(USE_X11, true)
+else
+  XPACKAGES=
+
+  AM_CONDITIONAL(XINPUT_XFREE, false)
+  AM_CONDITIONAL(XINPUT_2, false)
+  AM_CONDITIONAL(USE_X11, false)
+  AM_CONDITIONAL(HAVE_X11R6, false)
+fi
+
 # Check for Pango flags
 
 if test "x$gdktarget" = "xwin32"; then
@@ -1223,10 +1470,10 @@ CFLAGS="$saved_cflags"
 LDFLAGS="$saved_ldflags"
 
 # Pull in gio-unix for GDesktopAppInfo usage, see at least gdkapplaunchcontext-x11.c
-if test "x$gdktarget" = "xx11"; then
-  GDK_PACKAGES="$PANGO_PACKAGES gio-unix-2.0 $X_PACKAGES gdk-pixbuf-2.0 cairo-$cairo_backend cairo-gobject"
+if test "x$gdktarget" = "xx11" || test "x$gdktarget" = "xbroadway" ; then
+  GDK_PACKAGES="$PANGO_PACKAGES gio-unix-2.0 $X_PACKAGES gdk-pixbuf-2.0 $cairo_backend cairo-gobject"
 else
-  GDK_PACKAGES="$PANGO_PACKAGES gio-2.0 gdk-pixbuf-2.0 cairo-$cairo_backend cairo-gobject"
+  GDK_PACKAGES="$PANGO_PACKAGES gio-2.0 gdk-pixbuf-2.0 $cairo_backend cairo-gobject"
 fi
 
 GDK_DEP_LIBS="$GDK_EXTRA_LIBS `$PKG_CONFIG --libs $GDK_PACKAGES`"
@@ -1584,6 +1831,9 @@ elif test "x$gdktarget" = "xwin32" ; then
 elif test "x$gdktarget" = "xquartz" ; then
   gdk_windowing='
 #define GDK_WINDOWING_QUARTZ'
+elif test "x$gdktarget" = "xbroadway" ; then
+  gdk_windowing='
+#define GDK_WINDOWING_BROADWAY'
 fi
 
 if test x$gdk_wchar_h = xyes; then
@@ -1653,6 +1903,7 @@ build/Makefile
 build/win32/Makefile
 build/win32/vs9/Makefile
 gdk/Makefile
+gdk/broadway/Makefile
 gdk/x11/Makefile
 gdk/win32/Makefile
 gdk/win32/rc/Makefile
diff --git a/gdk/Makefile.am b/gdk/Makefile.am
index 9a48fe8..f222a96 100644
--- a/gdk/Makefile.am
+++ b/gdk/Makefile.am
@@ -9,7 +9,7 @@ INTROSPECTION_COMPILER_ARGS = \
    --includedir=.
 
 SUBDIRS = $(gdktarget) . tests
-DIST_SUBDIRS = win32 x11 quartz tests
+DIST_SUBDIRS = win32 x11 quartz broadway tests
 
 CLEANFILES =
 
@@ -158,6 +158,10 @@ common_sources = 		\
 	gdkmarshalers.c		\
 	gdkmarshalers.h
 
+libgdk_broadway_3_0_la_SOURCES = $(common_sources)
+libgdk_broadway_3_0_la_LIBADD = broadway/libgdk-broadway.la $(GDK_DEP_LIBS)
+libgdk_broadway_3_0_la_LDFLAGS = $(LDADD)
+
 libgdk_x11_3_0_la_SOURCES = $(common_sources)
 libgdk_x11_3_0_la_LIBADD = x11/libgdk-x11.la $(GDK_DEP_LIBS)
 libgdk_x11_3_0_la_LDFLAGS = $(LDADD)
@@ -288,7 +292,7 @@ endif
 
 lib_LTLIBRARIES = $(gdktargetlib)
 
-EXTRA_LTLIBRARIES = libgdk-x11-3.0.la libgdk-win32-3.0.la libgdk-quartz-3.0.la
+EXTRA_LTLIBRARIES = libgdk-broadway-3.0.la libgdk-x11-3.0.la libgdk-win32-3.0.la libgdk-quartz-3.0.la
 
 MAINTAINERCLEANFILES = $(gdk_built_sources) stamp-gdkenumtypes.h
 EXTRA_DIST += $(gdk_built_sources)
diff --git a/gdk/broadway/Makefile.am b/gdk/broadway/Makefile.am
new file mode 100644
index 0000000..e61e92b
--- /dev/null
+++ b/gdk/broadway/Makefile.am
@@ -0,0 +1,71 @@
+## Process this file with automake to produce Makefile.in
+include $(top_srcdir)/Makefile.decl
+
+libgdkincludedir = $(includedir)/gtk-3.0/gdk
+
+INCLUDES =			\
+	-DG_LOG_DOMAIN=\"Gdk\"	\
+	-DGDK_COMPILATION	\
+	-I$(top_srcdir)		\
+	-I$(top_srcdir)/gdk	\
+	-I$(top_builddir)/gdk	\
+	$(GTK_DEBUG_FLAGS)	\
+	$(GDK_DEP_CFLAGS)
+
+LDADDS = $(GDK_DEP_LIBS)
+
+noinst_LTLIBRARIES = libgdk-broadway.la
+
+libgdk_broadway_la_SOURCES =		\
+	MwmUtil.h		\
+	gdkapplaunchcontext-broadway.c \
+	gdkasync.c		\
+	gdkasync.h		\
+	gdkcursor-broadway.c	\
+	gdkdevice-broadway.h	\
+	gdkdevice-broadway.c	\
+	gdkdevicemanager-broadway.h \
+	gdkdevicemanager-broadway.c \
+	gdkdisplay-broadway.c	\
+	gdkdisplay-broadway.h	\
+	gdkdnd-broadway.c	\
+	gdkdrawable-broadway.c	\
+	gdkdrawable-broadway.h	\
+	gdkeventsource.c	\
+	gdkeventsource.h	\
+	gdkeventtranslator.c	\
+	gdkeventtranslator.h	\
+	gdkgeometry-broadway.c	\
+	gdkglobals-broadway.c	\
+	gdkim-broadway.c	\
+	gdkinput.c		\
+	gdkkeys-broadway.c	\
+	gdkmain-broadway.c	\
+	gdkproperty-broadway.c	\
+	gdkscreen-broadway.c	\
+	gdkscreen-broadway.h	\
+	gdkselection-broadway.c	\
+	gdkspawn-broadway.c	\
+	gdktestutils-broadway.c	\
+	gdkvisual-broadway.c	\
+	gdkwindow-broadway.c	\
+	gdkwindow-broadway.h	\
+	gdkxftdefaults.c	\
+	gdkxid.c		\
+	gdkx.h			\
+	gdkprivate-broadway.h	\
+	xsettings-client.h	\
+	xsettings-client.c	\
+	xsettings-common.h	\
+	xsettings-common.c
+
+libgdkinclude_HEADERS =		\
+	gdkx.h
+
+
+# We need to include all these C files here since the conditionals
+# don't seem to be correctly expanded for the dist files.
+EXTRA_DIST +=			\
+	gdksettings.c
+
+-include $(top_srcdir)/git.mk
diff --git a/gdk/broadway/MwmUtil.h b/gdk/broadway/MwmUtil.h
new file mode 100644
index 0000000..7d4c5bc
--- /dev/null
+++ b/gdk/broadway/MwmUtil.h
@@ -0,0 +1,136 @@
+/**
+ *
+ * $Id$
+ *
+ * Copyright (C) 1995 Free Software Foundation, Inc.
+ *
+ * This file is part of the GNU LessTif Library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ *
+ *
+ * * Feb 21 1999 - George Lebl (jirka 5z com)
+ *                 Owen Taylor (otaylor redhat com)
+ *
+ *   Modified so that the MotifWmHints structure defined here
+ *   is suitable for client side use on 64-bit architectures.
+ *   X expects fields with a format of 32 to be longs, even
+ *   when sizeof(long) == 8.
+ **/
+
+#ifndef MWMUTIL_H_INCLUDED
+#define MWMUTIL_H_INCLUDED
+
+#include <X11/Xmd.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+    unsigned long flags;
+    unsigned long functions;
+    unsigned long decorations;
+    long input_mode;
+    unsigned long status;
+} MotifWmHints, MwmHints;
+
+#define MWM_HINTS_FUNCTIONS     (1L << 0)
+#define MWM_HINTS_DECORATIONS   (1L << 1)
+#define MWM_HINTS_INPUT_MODE    (1L << 2)
+#define MWM_HINTS_STATUS        (1L << 3)
+
+#define MWM_FUNC_ALL            (1L << 0)
+#define MWM_FUNC_RESIZE         (1L << 1)
+#define MWM_FUNC_MOVE           (1L << 2)
+#define MWM_FUNC_MINIMIZE       (1L << 3)
+#define MWM_FUNC_MAXIMIZE       (1L << 4)
+#define MWM_FUNC_CLOSE          (1L << 5)
+
+#define MWM_DECOR_ALL           (1L << 0)
+#define MWM_DECOR_BORDER        (1L << 1)
+#define MWM_DECOR_RESIZEH       (1L << 2)
+#define MWM_DECOR_TITLE         (1L << 3)
+#define MWM_DECOR_MENU          (1L << 4)
+#define MWM_DECOR_MINIMIZE      (1L << 5)
+#define MWM_DECOR_MAXIMIZE      (1L << 6)
+
+#define MWM_INPUT_MODELESS 0
+#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
+#define MWM_INPUT_SYSTEM_MODAL 2
+#define MWM_INPUT_FULL_APPLICATION_MODAL 3
+#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
+
+#define MWM_TEAROFF_WINDOW	(1L<<0)
+
+/*
+ * atoms
+ */
+#define _XA_MOTIF_BINDINGS		"_MOTIF_BINDINGS"
+#define _XA_MOTIF_WM_HINTS		"_MOTIF_WM_HINTS"
+#define _XA_MOTIF_WM_MESSAGES		"_MOTIF_WM_MESSAGES"
+#define _XA_MOTIF_WM_OFFSET		"_MOTIF_WM_OFFSET"
+#define _XA_MOTIF_WM_MENU		"_MOTIF_WM_MENU"
+#define _XA_MOTIF_WM_INFO		"_MOTIF_WM_INFO"
+#define _XA_MWM_HINTS			_XA_MOTIF_WM_HINTS
+#define _XA_MWM_MESSAGES		_XA_MOTIF_WM_MESSAGES
+#define _XA_MWM_MENU			_XA_MOTIF_WM_MENU
+#define _XA_MWM_INFO			_XA_MOTIF_WM_INFO
+
+
+/*
+ * _MWM_INFO property
+ */
+typedef struct {
+    long flags;
+    Window wm_window;
+} MotifWmInfo;
+
+typedef MotifWmInfo MwmInfo;
+
+#define MWM_INFO_STARTUP_STANDARD	(1L<<0)
+#define MWM_INFO_STARTUP_CUSTOM		(1L<<1)
+
+/*
+ * _MWM_HINTS property
+ */
+typedef struct {
+    unsigned long flags;
+    unsigned long functions;
+    unsigned long decorations;
+    long inputMode;
+    unsigned long status;
+} PropMotifWmHints;
+
+typedef PropMotifWmHints PropMwmHints;
+
+#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+#define PROP_MWM_HINTS_ELEMENTS PROP_MOTIF_WM_HINTS_ELEMENTS
+
+/*
+ * _MWM_INFO property, slight return
+ */
+typedef struct {
+    unsigned long flags;
+    unsigned long wmWindow;
+} PropMotifWmInfo;
+
+typedef PropMotifWmInfo PropMwmInfo;
+
+#define PROP_MOTIF_WM_INFO_ELEMENTS 2
+#define PROP_MWM_INFO_ELEMENTS PROP_MOTIF_WM_INFO_ELEMENTS
+
+G_END_DECLS
+
+#endif /* MWMUTIL_H_INCLUDED */
diff --git a/gdk/broadway/gdkapplaunchcontext-broadway.c b/gdk/broadway/gdkapplaunchcontext-broadway.c
new file mode 100644
index 0000000..df3781e
--- /dev/null
+++ b/gdk/broadway/gdkapplaunchcontext-broadway.c
@@ -0,0 +1,440 @@
+/* gdkapplaunchcontext-x11.c - Gtk+ implementation for GAppLaunchContext
+
+   Copyright (C) 2007 Red Hat, Inc.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Alexander Larsson <alexl redhat com>
+*/
+
+#include "config.h"
+
+#include "gdkapplaunchcontext.h"
+
+#include "gdkx.h"
+#include "gdkscreen.h"
+#include "gdkinternals.h"
+#include "gdkintl.h"
+
+#include <glib.h>
+#include <gio/gdesktopappinfo.h>
+
+#include <string.h>
+#include <unistd.h>
+
+static char *
+get_display_name (GFile *file)
+{
+  GFileInfo *info;
+  char *name, *tmp;
+
+  /* This does sync I/O, which isn't ideal.
+   * It should probably use the NautilusFile machinery
+   */
+
+  name = NULL;
+  info = g_file_query_info (file,
+			    G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, 0, NULL, NULL);
+  if (info)
+    {
+      name = g_strdup (g_file_info_get_display_name (info));
+      g_object_unref (info);
+    }
+
+  if (name == NULL)
+    {
+      name = g_file_get_basename (file);
+      if (!g_utf8_validate (name, -1, NULL))
+	{
+	  tmp = name;
+	  name =
+	    g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH,
+				 TRUE);
+	  g_free (tmp);
+	}
+    }
+
+  return name;
+}
+
+static GIcon *
+get_icon (GFile *file)
+{
+  GFileInfo *info;
+  GIcon *icon;
+
+  icon = NULL;
+  info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_ICON, 0, NULL, NULL);
+  if (info)
+    {
+      icon = g_file_info_get_icon (info);
+      if (icon)
+	g_object_ref (icon);
+      g_object_unref (info);
+    }
+
+  return icon;
+}
+
+static char *
+gicon_to_string (GIcon *icon)
+{
+  GFile *file;
+  const char *const *names;
+
+  if (G_IS_FILE_ICON (icon))
+    {
+      file = g_file_icon_get_file (G_FILE_ICON (icon));
+      if (file)
+	return g_file_get_path (file);
+    }
+  else if (G_IS_THEMED_ICON (icon))
+    {
+      names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+      if (names)
+	return g_strdup (names[0]);
+    }
+  else if (G_IS_EMBLEMED_ICON (icon))
+    {
+      GIcon *base;
+
+      base = g_emblemed_icon_get_icon (G_EMBLEMED_ICON (icon));
+
+      return gicon_to_string (base);
+    }
+
+  return NULL;
+}
+
+static void
+end_startup_notification (GdkDisplay *display,
+			  const char *startup_id)
+{
+  gdk_x11_display_broadcast_startup_message (display, "remove",
+					     "ID", startup_id,
+					     NULL);
+}
+
+
+/* This should be fairly long, as it's confusing to users if a startup
+ * ends when it shouldn't (it appears that the startup failed, and
+ * they have to relaunch the app). Also the timeout only matters when
+ * there are bugs and apps don't end their own startup sequence.
+ *
+ * This timeout is a "last resort" timeout that ignores whether the
+ * startup sequence has shown activity or not.  Metacity and the
+ * tasklist have smarter, and correspondingly able-to-be-shorter
+ * timeouts. The reason our timeout is dumb is that we don't monitor
+ * the sequence (don't use an SnMonitorContext)
+ */
+#define STARTUP_TIMEOUT_LENGTH_SECONDS 30 
+#define STARTUP_TIMEOUT_LENGTH (STARTUP_TIMEOUT_LENGTH_SECONDS * 1000)
+
+typedef struct 
+{
+  GdkDisplay *display;
+  char *startup_id;
+  GTimeVal time;
+} StartupNotificationData;
+
+static void
+free_startup_notification_data (gpointer data)
+{
+  StartupNotificationData *sn_data = data;
+
+  g_object_unref (sn_data->display);
+  g_free (sn_data->startup_id);
+  g_free (sn_data);
+}
+
+typedef struct 
+{
+  GSList *contexts;
+  guint timeout_id;
+} StartupTimeoutData;
+
+static void
+free_startup_timeout (void *data)
+{
+  StartupTimeoutData *std;
+
+  std = data;
+
+  g_slist_foreach (std->contexts, (GFunc) free_startup_notification_data, NULL);
+  g_slist_free (std->contexts);
+
+  if (std->timeout_id != 0)
+    {
+      g_source_remove (std->timeout_id);
+      std->timeout_id = 0;
+    }
+
+  g_free (std);
+}
+
+static gboolean
+startup_timeout (void *data)
+{
+  StartupTimeoutData *std;
+  GSList *tmp;
+  GTimeVal now;
+  int min_timeout;
+
+  std = data;
+
+  min_timeout = STARTUP_TIMEOUT_LENGTH;
+
+  g_get_current_time (&now);
+
+  tmp = std->contexts;
+  while (tmp != NULL)
+    {
+      StartupNotificationData *sn_data;
+      GSList *next;
+      double elapsed;
+
+      sn_data = tmp->data;
+      next = tmp->next;
+
+      elapsed =
+	((((double) now.tv_sec - sn_data->time.tv_sec) * G_USEC_PER_SEC +
+	  (now.tv_usec - sn_data->time.tv_usec))) / 1000.0;
+
+      if (elapsed >= STARTUP_TIMEOUT_LENGTH)
+	{
+	  std->contexts = g_slist_remove (std->contexts, sn_data);
+	  end_startup_notification (sn_data->display, sn_data->startup_id);
+	  free_startup_notification_data (sn_data);
+	}
+      else
+	{
+	  min_timeout = MIN (min_timeout, (STARTUP_TIMEOUT_LENGTH - elapsed));
+	}
+
+      tmp = next;
+    }
+
+  if (std->contexts == NULL)
+    std->timeout_id = 0;
+  else
+    std->timeout_id = g_timeout_add_seconds ((min_timeout + 500)/1000, startup_timeout, std);
+
+  /* always remove this one, but we may have reinstalled another one. */
+  return FALSE;
+}
+
+
+static void
+add_startup_timeout (GdkScreen  *screen,
+		     const char *startup_id)
+{
+  StartupTimeoutData *data;
+  StartupNotificationData *sn_data;
+
+  data = g_object_get_data (G_OBJECT (screen), "appinfo-startup-data");
+
+  if (data == NULL)
+    {
+      data = g_new (StartupTimeoutData, 1);
+      data->contexts = NULL;
+      data->timeout_id = 0;
+
+      g_object_set_data_full (G_OBJECT (screen), "appinfo-startup-data",
+			      data, free_startup_timeout);
+    }
+
+  sn_data = g_new (StartupNotificationData, 1);
+  sn_data->display = g_object_ref (gdk_screen_get_display (screen));
+  sn_data->startup_id = g_strdup (startup_id);
+  g_get_current_time (&sn_data->time);
+
+  data->contexts = g_slist_prepend (data->contexts, sn_data);
+
+  if (data->timeout_id == 0)
+    data->timeout_id = g_timeout_add_seconds (STARTUP_TIMEOUT_LENGTH_SECONDS,
+					      startup_timeout, data);
+}
+
+
+char *
+_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
+				      GAppInfo          *info, 
+				      GList             *files)
+{
+  static int sequence = 0;
+  GdkAppLaunchContextPrivate *priv;
+  GdkDisplay *display;
+  GdkScreen *screen;
+  int files_count;
+  char *description;
+  char *icon_name;
+  const char *binary_name;
+  const char *application_id;
+  char *screen_str;
+  char *workspace_str;
+  GIcon *icon;
+  guint32 timestamp;
+  char *startup_id;
+
+  priv = GDK_APP_LAUNCH_CONTEXT (context)->priv;
+
+  if (priv->screen)
+    {
+      screen = priv->screen;
+      display = gdk_screen_get_display (priv->screen);
+    }
+  else if (priv->display)
+    {
+      display = priv->display;
+      screen = gdk_display_get_default_screen (display);
+    }
+  else
+    {
+      display = gdk_display_get_default ();
+      screen = gdk_display_get_default_screen (display);
+    }
+
+  files_count = g_list_length (files);
+  if (files_count == 0)
+    description = g_strdup_printf (_("Starting %s"), g_app_info_get_name (info));
+  else if (files_count == 1)
+    {
+      gchar *display_name = get_display_name (files->data);
+      description = g_strdup_printf (_("Opening %s"), display_name);
+      g_free (display_name);
+    }
+  else
+    description = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
+						"Opening %d Item",
+						"Opening %d Items",
+						files_count), files_count);
+
+  icon_name = NULL;
+  if (priv->icon_name)
+    icon_name = g_strdup (priv->icon_name);
+  else
+    {
+      icon = NULL;
+
+      if (priv->icon != NULL)
+	icon = g_object_ref (priv->icon);
+      else if (files_count == 1)
+	icon = get_icon (files->data);
+
+      if (icon == NULL)
+	{
+	  icon = g_app_info_get_icon (info);
+	  g_object_ref (icon);
+	}
+
+      if (icon)
+	icon_name = gicon_to_string (icon);
+
+      g_object_unref (icon);
+    }
+
+  binary_name = g_app_info_get_executable (info);
+
+  timestamp = priv->timestamp;
+  if (timestamp == GDK_CURRENT_TIME)
+    timestamp = gdk_x11_display_get_user_time (display);
+
+  screen_str = g_strdup_printf ("%d", gdk_screen_get_number (screen));
+  if (priv->workspace > -1) 
+    workspace_str = g_strdup_printf ("%d", priv->workspace);
+  else
+    workspace_str = NULL;
+
+  if (G_IS_DESKTOP_APP_INFO (info))
+    application_id = g_desktop_app_info_get_filename (G_DESKTOP_APP_INFO (info));
+  else
+    application_id = NULL;
+
+  startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu",
+				g_get_prgname (),
+				(unsigned long)getpid (),
+				g_get_host_name (),
+				binary_name,
+				sequence++,
+				(unsigned long)timestamp);
+
+  
+  gdk_x11_display_broadcast_startup_message (display, "new",
+					     "ID", startup_id,
+					     "NAME", g_app_info_get_name (info),
+					     "SCREEN", screen_str,
+					     "BIN", binary_name,
+					     "ICON", icon_name,
+					     "DESKTOP", workspace_str,
+					     "DESCRIPTION", description,
+					     "WMCLASS", NULL, /* FIXME */
+					     "APPLICATION_ID", application_id,
+					     NULL);
+
+  g_free (description);
+  g_free (screen_str);
+  g_free (workspace_str);
+  g_free (icon_name);
+
+  add_startup_timeout (screen, startup_id);
+
+  return startup_id;
+}
+
+
+void
+_gdk_windowing_launch_failed (GAppLaunchContext *context, 
+			      const char        *startup_notify_id)
+{
+  GdkAppLaunchContextPrivate *priv;
+  GdkScreen *screen;
+  StartupTimeoutData *data;
+  StartupNotificationData *sn_data;
+  GSList *l;
+
+  priv = GDK_APP_LAUNCH_CONTEXT (context)->priv;
+
+  if (priv->screen)
+    screen = priv->screen;
+  else if (priv->display)
+    screen = gdk_display_get_default_screen (priv->display);
+  else
+    screen = gdk_display_get_default_screen (gdk_display_get_default ());
+
+  data = g_object_get_data (G_OBJECT (screen), "appinfo-startup-data");
+
+  if (data)
+    {
+      for (l = data->contexts; l != NULL; l = l->next)
+	{
+	  sn_data = l->data;
+	  if (strcmp (startup_notify_id, sn_data->startup_id) == 0)
+	    {
+	      data->contexts = g_slist_remove (data->contexts, sn_data);
+	      end_startup_notification (sn_data->display, sn_data->startup_id);
+	      free_startup_notification_data (sn_data);
+					      
+	      break;
+	    }
+	}
+
+      if (data->contexts == NULL)
+	{
+	  g_source_remove (data->timeout_id);
+	  data->timeout_id = 0;
+	}
+    }
+}
diff --git a/gdk/broadway/gdkasync.c b/gdk/broadway/gdkasync.c
new file mode 100644
index 0000000..2f591b0
--- /dev/null
+++ b/gdk/broadway/gdkasync.c
@@ -0,0 +1,845 @@
+/* GTK - The GIMP Toolkit
+ * gdkasync.c: Utility functions using the Xlib asynchronous interfaces
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * 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.
+ */
+/* Portions of code in this file are based on code from Xlib
+ */
+/*
+Copyright 1986, 1998  The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+#include "config.h"
+
+#include "gdkasync.h"
+#include "gdkx.h"
+
+#ifdef NEED_XIPROTO_H_FOR_XREPLY
+#include <X11/extensions/XIproto.h>
+#endif
+
+#include <X11/Xlibint.h>
+
+
+typedef struct _ChildInfoChildState ChildInfoChildState;
+typedef struct _ChildInfoState ChildInfoState;
+typedef struct _ListChildrenState ListChildrenState;
+typedef struct _SendEventState SendEventState;
+typedef struct _SetInputFocusState SetInputFocusState;
+typedef struct _RoundtripState RoundtripState;
+
+typedef enum {
+  CHILD_INFO_GET_PROPERTY,
+  CHILD_INFO_GET_WA,
+  CHILD_INFO_GET_GEOMETRY
+} ChildInfoReq;
+
+struct _ChildInfoChildState
+{
+  gulong seq[3];
+};
+
+struct _ChildInfoState
+{
+  gboolean get_wm_state;
+  Window *children;
+  guint nchildren;
+  GdkChildInfoX11 *child_info;
+  ChildInfoChildState *child_states;
+
+  guint current_child;
+  guint n_children_found;
+  gint current_request;
+  gboolean have_error;
+  gboolean child_has_error;
+};
+
+struct _ListChildrenState
+{
+  Display *dpy;
+  gulong get_property_req;
+  gboolean have_error;
+  gboolean has_wm_state;
+};
+
+struct _SendEventState
+{
+  Display *dpy;
+  Window window;
+  _XAsyncHandler async;
+  gulong send_event_req;
+  gulong get_input_focus_req;
+  gboolean have_error;
+  GdkSendXEventCallback callback;
+  gpointer data;
+};
+
+struct _SetInputFocusState
+{
+  Display *dpy;
+  _XAsyncHandler async;
+  gulong set_input_focus_req;
+  gulong get_input_focus_req;
+};
+
+struct _RoundtripState
+{
+  Display *dpy;
+  _XAsyncHandler async;
+  gulong get_input_focus_req;
+  GdkDisplay *display;
+  GdkRoundTripCallback callback;
+  gpointer data;
+};
+
+static gboolean
+callback_idle (gpointer data)
+{
+  SendEventState *state = (SendEventState *)data;  
+  
+  state->callback (state->window, !state->have_error, state->data);
+
+  g_free (state);
+
+  return FALSE;
+}
+
+static Bool
+send_event_handler (Display *dpy,
+		    xReply  *rep,
+		    char    *buf,
+		    int      len,
+		    XPointer data)
+{
+  SendEventState *state = (SendEventState *)data;  
+
+  if (dpy->last_request_read == state->send_event_req)
+    {
+      if (rep->generic.type == X_Error &&
+	  rep->error.errorCode == BadWindow)
+	{
+	  state->have_error = TRUE;
+	  return True;
+	}
+    }
+  else if (dpy->last_request_read == state->get_input_focus_req)
+    {
+      xGetInputFocusReply replbuf;
+      xGetInputFocusReply *repl;
+      
+      if (rep->generic.type != X_Error)
+	{
+	  /* Actually does nothing, since there are no additional bytes
+	   * to read, but maintain good form.
+	   */
+	  repl = (xGetInputFocusReply *)
+	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
+			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
+			    True);
+	}
+
+      if (state->callback)
+        gdk_threads_add_idle (callback_idle, state);
+
+      DeqAsyncHandler(state->dpy, &state->async);
+
+      return (rep->generic.type != X_Error);
+    }
+
+  return False;
+}
+
+static void
+client_message_to_wire (XClientMessageEvent *ev,
+			xEvent              *event)
+{
+  int i;
+  event->u.clientMessage.window = ev->window;
+  event->u.u.type = ev->type;
+  event->u.u.detail = ev->format;
+  switch (ev->format)
+    {
+    case 8:	
+      event->u.clientMessage.u.b.type   = ev->message_type;
+      for (i = 0; i < 20; i++)
+	event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
+      break;
+    case 16:
+      event->u.clientMessage.u.s.type   = ev->message_type;
+      event->u.clientMessage.u.s.shorts0   = ev->data.s[0];
+      event->u.clientMessage.u.s.shorts1   = ev->data.s[1];
+      event->u.clientMessage.u.s.shorts2   = ev->data.s[2];
+      event->u.clientMessage.u.s.shorts3   = ev->data.s[3];
+      event->u.clientMessage.u.s.shorts4   = ev->data.s[4];
+      event->u.clientMessage.u.s.shorts5   = ev->data.s[5];
+      event->u.clientMessage.u.s.shorts6   = ev->data.s[6];
+      event->u.clientMessage.u.s.shorts7   = ev->data.s[7];
+      event->u.clientMessage.u.s.shorts8   = ev->data.s[8];
+      event->u.clientMessage.u.s.shorts9   = ev->data.s[9];
+      break;
+    case 32:
+      event->u.clientMessage.u.l.type   = ev->message_type;
+      event->u.clientMessage.u.l.longs0   = ev->data.l[0];
+      event->u.clientMessage.u.l.longs1   = ev->data.l[1];
+      event->u.clientMessage.u.l.longs2   = ev->data.l[2];
+      event->u.clientMessage.u.l.longs3   = ev->data.l[3];
+      event->u.clientMessage.u.l.longs4   = ev->data.l[4];
+      break;
+    default:
+      /* client passing bogus data, let server complain */
+      break;
+    }
+}
+
+void
+_gdk_x11_send_client_message_async (GdkDisplay           *display, 
+				    Window                window, 
+				    gboolean              propagate,
+				    glong                 event_mask,
+				    XClientMessageEvent  *event_send,
+				    GdkSendXEventCallback callback,
+				    gpointer              data)
+{
+  Display *dpy;
+  SendEventState *state;
+  
+  dpy = GDK_DISPLAY_XDISPLAY (display);
+
+  state = g_new (SendEventState, 1);
+
+  state->dpy = dpy;
+  state->window = window;
+  state->callback = callback;
+  state->data = data;
+  state->have_error = FALSE;
+  
+  LockDisplay(dpy);
+
+  state->async.next = dpy->async_handlers;
+  state->async.handler = send_event_handler;
+  state->async.data = (XPointer) state;
+  dpy->async_handlers = &state->async;
+
+  {
+    register xSendEventReq *req;
+    xEvent ev;
+    
+    client_message_to_wire (event_send, &ev);
+      
+    GetReq(SendEvent, req);
+    req->destination = window;
+    req->propagate = propagate;
+    req->eventMask = event_mask;
+    /* gross, matches Xproto.h */
+#ifdef WORD64			
+    memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
+#else    
+    memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
+#endif
+    
+    state->send_event_req = dpy->request;
+  }
+
+  /*
+   * XSync (dpy, 0)
+   */
+  {
+    xReq *req;
+    
+    GetEmptyReq(GetInputFocus, req);
+    state->get_input_focus_req = dpy->request;
+  }
+  
+  UnlockDisplay(dpy);
+  SyncHandle();
+}
+
+static Bool
+set_input_focus_handler (Display *dpy,
+			 xReply  *rep,
+			 char    *buf,
+			 int      len,
+			 XPointer data)
+{
+  SetInputFocusState *state = (SetInputFocusState *)data;  
+
+  if (dpy->last_request_read == state->set_input_focus_req)
+    {
+      if (rep->generic.type == X_Error &&
+	  rep->error.errorCode == BadMatch)
+	{
+	  /* Consume BadMatch errors, since we have no control
+	   * over them.
+	   */
+	  return True;
+	}
+    }
+  
+  if (dpy->last_request_read == state->get_input_focus_req)
+    {
+      xGetInputFocusReply replbuf;
+      xGetInputFocusReply *repl;
+      
+      if (rep->generic.type != X_Error)
+	{
+	  /* Actually does nothing, since there are no additional bytes
+	   * to read, but maintain good form.
+	   */
+	  repl = (xGetInputFocusReply *)
+	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
+			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
+			    True);
+	}
+
+      DeqAsyncHandler(state->dpy, &state->async);
+
+      g_free (state);
+      
+      return (rep->generic.type != X_Error);
+    }
+
+  return False;
+}
+
+void
+_gdk_x11_set_input_focus_safe (GdkDisplay             *display,
+			       Window                  window,
+			       int                     revert_to,
+			       Time                    time)
+{
+  Display *dpy;
+  SetInputFocusState *state;
+  
+  dpy = GDK_DISPLAY_XDISPLAY (display);
+
+  state = g_new (SetInputFocusState, 1);
+
+  state->dpy = dpy;
+  
+  LockDisplay(dpy);
+
+  state->async.next = dpy->async_handlers;
+  state->async.handler = set_input_focus_handler;
+  state->async.data = (XPointer) state;
+  dpy->async_handlers = &state->async;
+
+  {
+    xSetInputFocusReq *req;
+    
+    GetReq(SetInputFocus, req);
+    req->focus = window;
+    req->revertTo = revert_to;
+    req->time = time;
+    state->set_input_focus_req = dpy->request;
+  }
+
+  /*
+   * XSync (dpy, 0)
+   */
+  {
+    xReq *req;
+    
+    GetEmptyReq(GetInputFocus, req);
+    state->get_input_focus_req = dpy->request;
+  }
+  
+  UnlockDisplay(dpy);
+  SyncHandle();
+}
+
+static Bool
+list_children_handler (Display *dpy,
+		       xReply  *rep,
+		       char    *buf,
+		       int      len,
+		       XPointer data)
+{
+  ListChildrenState *state = (ListChildrenState *)data;
+
+  if (dpy->last_request_read != state->get_property_req)
+    return False;
+  
+  if (rep->generic.type == X_Error)
+    {
+      state->have_error = TRUE;
+      return False;
+    }
+  else
+    {
+      xGetPropertyReply replbuf;
+      xGetPropertyReply *repl;
+	    
+      repl = (xGetPropertyReply *)
+	_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
+			(sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
+			True);
+
+      state->has_wm_state = repl->propertyType != None;
+      /* Since we called GetProperty with longLength of 0, we don't
+       * have to worry about consuming the property data that would
+       * normally follow after the reply
+       */
+
+      return True;
+    }
+}
+
+static gboolean
+list_children_and_wm_state (Display      *dpy,
+			    Window        w,
+			    Atom          wm_state_atom,
+			    gboolean     *has_wm_state,
+			    Window      **children,
+			    unsigned int *nchildren)
+{
+  ListChildrenState state;
+  _XAsyncHandler async;
+  long nbytes;
+  xQueryTreeReply rep;
+  register xResourceReq *req;
+  xGetPropertyReq *prop_req;
+
+  LockDisplay(dpy);
+
+  *children = NULL;
+  *nchildren = 0;
+  *has_wm_state = FALSE;
+  
+  state.have_error = FALSE;
+  state.has_wm_state = FALSE;
+
+  if (wm_state_atom)
+    {
+      async.next = dpy->async_handlers;
+      async.handler = list_children_handler;
+      async.data = (XPointer) &state;
+      dpy->async_handlers = &async;
+
+      GetReq (GetProperty, prop_req);
+      prop_req->window = w;
+      prop_req->property = wm_state_atom;
+      prop_req->type = AnyPropertyType;
+      prop_req->delete = False;
+      prop_req->longOffset = 0;
+      prop_req->longLength = 0;
+      
+      state.get_property_req = dpy->request;
+    }
+  
+  GetResReq(QueryTree, w, req);
+  if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
+    {
+      state.have_error = TRUE;
+      goto out;
+    }
+
+  if (rep.nChildren != 0)
+    {
+      nbytes = rep.nChildren << 2;
+      if (state.have_error)
+	{
+	  _XEatData(dpy, (unsigned long) nbytes);
+	  goto out;
+	}
+      *children = g_new (Window, rep.nChildren);
+      _XRead32 (dpy, (long *) *children, nbytes);
+    }
+
+  *nchildren = rep.nChildren;
+  *has_wm_state = state.has_wm_state;
+
+ out:
+  if (wm_state_atom)
+    DeqAsyncHandler(dpy, &async);
+  UnlockDisplay(dpy);
+  SyncHandle();
+  
+  return !state.have_error;
+}
+
+static void
+handle_get_wa_reply (Display                   *dpy,
+		     ChildInfoState            *state,
+		     xGetWindowAttributesReply *repl)
+{
+  GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
+  child->is_mapped = repl->mapState != IsUnmapped;
+  child->window_class = repl->class;
+}
+
+static void
+handle_get_geometry_reply (Display           *dpy,
+			   ChildInfoState    *state,
+			   xGetGeometryReply *repl)
+{
+  GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
+  
+  child->x = cvtINT16toInt (repl->x);
+  child->y = cvtINT16toInt (repl->y);
+  child->width = repl->width;
+  child->height = repl->height;
+}
+
+static void
+handle_get_property_reply (Display           *dpy,
+			   ChildInfoState    *state,
+			   xGetPropertyReply *repl)
+{
+  GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
+  child->has_wm_state = repl->propertyType != None;
+
+  /* Since we called GetProperty with longLength of 0, we don't
+   * have to worry about consuming the property data that would
+   * normally follow after the reply
+   */
+}
+
+static void
+next_child (ChildInfoState *state)
+{
+  if (state->current_request == CHILD_INFO_GET_GEOMETRY)
+    {
+      if (!state->have_error && !state->child_has_error)
+	{
+	  state->child_info[state->n_children_found].window = state->children[state->current_child];
+	  state->n_children_found++;
+	}
+      state->current_child++;
+      if (state->get_wm_state)
+	state->current_request = CHILD_INFO_GET_PROPERTY;
+      else
+	state->current_request = CHILD_INFO_GET_WA;
+      state->child_has_error = FALSE;
+      state->have_error = FALSE;
+    }
+  else
+    state->current_request++;
+}
+
+static Bool
+get_child_info_handler (Display *dpy,
+			xReply  *rep,
+			char    *buf,
+			int      len,
+			XPointer data)
+{
+  Bool result = True;
+  
+  ChildInfoState *state = (ChildInfoState *)data;
+
+  if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
+    return False;
+  
+  if (rep->generic.type == X_Error)
+    {
+      state->child_has_error = TRUE;
+      if (rep->error.errorCode != BadDrawable ||
+	  rep->error.errorCode != BadWindow)
+	{
+	  state->have_error = TRUE;
+	  result = False;
+	}
+    }
+  else
+    {
+      switch (state->current_request)
+	{
+	case CHILD_INFO_GET_PROPERTY:
+	  {
+	    xGetPropertyReply replbuf;
+	    xGetPropertyReply *repl;
+	    
+	    repl = (xGetPropertyReply *)
+	      _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
+			      (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
+			      True);
+	    
+	    handle_get_property_reply (dpy, state, repl);
+	  }
+	  break;
+	case CHILD_INFO_GET_WA:
+	  {
+	    xGetWindowAttributesReply replbuf;
+	    xGetWindowAttributesReply *repl;
+	    
+	    repl = (xGetWindowAttributesReply *)
+	      _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
+			      (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
+			      True);
+	    
+	    handle_get_wa_reply (dpy, state, repl);
+	  }
+	  break;
+	case CHILD_INFO_GET_GEOMETRY:
+	  {
+	    xGetGeometryReply replbuf;
+	    xGetGeometryReply *repl;
+	    
+	    repl = (xGetGeometryReply *)
+	      _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
+			      (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
+			      True);
+	    
+	    handle_get_geometry_reply (dpy, state, repl);
+	  }
+	  break;
+	}
+    }
+
+  next_child (state);
+
+  return result;
+}
+
+gboolean
+_gdk_x11_get_window_child_info (GdkDisplay       *display,
+				Window            window,
+				gboolean          get_wm_state,
+				gboolean         *win_has_wm_state,
+				GdkChildInfoX11 **children,
+				guint            *nchildren)
+{
+  Display *dpy;
+  _XAsyncHandler async;
+  ChildInfoState state;
+  Atom wm_state_atom;
+  gboolean has_wm_state;
+  Bool result;
+  guint i;
+
+  *children = NULL;
+  *nchildren = 0;
+  
+  dpy = GDK_DISPLAY_XDISPLAY (display);
+  if (get_wm_state)
+    wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
+  else
+    wm_state_atom = None;
+
+  state.children = NULL;
+  state.nchildren = 0;
+
+  gdk_error_trap_push ();
+  result = list_children_and_wm_state (dpy, window,
+				       win_has_wm_state ? wm_state_atom : None,
+				       &has_wm_state,
+				       &state.children, &state.nchildren);
+  gdk_error_trap_pop_ignored ();
+  if (!result)
+    {
+      g_free (state.children);
+      return FALSE;
+    }
+
+  if (has_wm_state)
+    {
+      if (win_has_wm_state)
+	*win_has_wm_state = TRUE;
+      g_free (state.children);
+      return TRUE;
+    }
+  else
+    {
+      if (win_has_wm_state)
+	*win_has_wm_state = FALSE;
+    }
+
+  state.get_wm_state = get_wm_state;
+  state.child_info = g_new (GdkChildInfoX11, state.nchildren);
+  state.child_states = g_new (ChildInfoChildState, state.nchildren);
+  state.current_child = 0;
+  state.n_children_found = 0;
+  if (get_wm_state)
+    state.current_request = CHILD_INFO_GET_PROPERTY;
+  else
+    state.current_request = CHILD_INFO_GET_WA;
+  state.have_error = FALSE;
+  state.child_has_error = FALSE;
+
+  LockDisplay(dpy);
+
+  async.next = dpy->async_handlers;
+  async.handler = get_child_info_handler;
+  async.data = (XPointer) &state;
+  dpy->async_handlers = &async;
+  
+  for (i = 0; i < state.nchildren; i++)
+    {
+      xResourceReq *resource_req;
+      xGetPropertyReq *prop_req;
+      Window window = state.children[i];
+      
+      if (get_wm_state)
+	{
+	  GetReq (GetProperty, prop_req);
+	  prop_req->window = window;
+	  prop_req->property = wm_state_atom;
+	  prop_req->type = AnyPropertyType;
+	  prop_req->delete = False;
+	  prop_req->longOffset = 0;
+	  prop_req->longLength = 0;
+
+	  state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
+	}
+      
+      GetResReq(GetWindowAttributes, window, resource_req);
+      state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
+      
+      GetResReq(GetGeometry, window, resource_req);
+      state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
+    }
+
+  if (i != 0)
+    {
+      /* Wait for the last reply
+       */
+      xGetGeometryReply rep;
+
+      /* On error, our async handler will get called
+       */
+      if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
+	handle_get_geometry_reply (dpy, &state, &rep);
+
+      next_child (&state);
+    }
+
+  if (!state.have_error)
+    {
+      *children = state.child_info;
+      *nchildren = state.n_children_found;
+    }
+  else
+    {
+      g_free (state.child_info);
+    }
+
+  g_free (state.children);
+  g_free (state.child_states);
+  
+  DeqAsyncHandler(dpy, &async);
+  UnlockDisplay(dpy);
+  SyncHandle();
+
+  return !state.have_error;
+}
+
+static gboolean
+roundtrip_callback_idle (gpointer data)
+{
+  RoundtripState *state = (RoundtripState *)data;  
+  
+  state->callback (state->display, state->data, state->get_input_focus_req);
+
+  g_free (state);
+
+  return FALSE;
+}
+
+static Bool
+roundtrip_handler (Display *dpy,
+		   xReply  *rep,
+		   char    *buf,
+		   int      len,
+		   XPointer data)
+{
+  RoundtripState *state = (RoundtripState *)data;  
+  
+  if (dpy->last_request_read == state->get_input_focus_req)
+    {
+      xGetInputFocusReply replbuf;
+      xGetInputFocusReply *repl;
+      
+      if (rep->generic.type != X_Error)
+	{
+	  /* Actually does nothing, since there are no additional bytes
+	   * to read, but maintain good form.
+	   */
+	  repl = (xGetInputFocusReply *)
+	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
+			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
+			    True);
+	}
+
+      
+      if (state->callback)
+        gdk_threads_add_idle (roundtrip_callback_idle, state);
+
+      DeqAsyncHandler(state->dpy, &state->async);
+
+      return (rep->generic.type != X_Error);
+    }
+
+  return False;
+}
+
+void
+_gdk_x11_roundtrip_async (GdkDisplay           *display, 
+			  GdkRoundTripCallback callback,
+			  gpointer              data)
+{
+  Display *dpy;
+  RoundtripState *state;
+  
+  dpy = GDK_DISPLAY_XDISPLAY (display);
+
+  state = g_new (RoundtripState, 1);
+
+  state->display = display;
+  state->dpy = dpy;
+  state->callback = callback;
+  state->data = data;
+  
+  LockDisplay(dpy);
+
+  state->async.next = dpy->async_handlers;
+  state->async.handler = roundtrip_handler;
+  state->async.data = (XPointer) state;
+  dpy->async_handlers = &state->async;
+
+  /*
+   * XSync (dpy, 0)
+   */
+  {
+    xReq *req;
+    
+    GetEmptyReq(GetInputFocus, req);
+    state->get_input_focus_req = dpy->request;
+  }
+  
+  UnlockDisplay(dpy);
+  SyncHandle();
+}
diff --git a/gdk/broadway/gdkasync.h b/gdk/broadway/gdkasync.h
new file mode 100644
index 0000000..eebea39
--- /dev/null
+++ b/gdk/broadway/gdkasync.h
@@ -0,0 +1,75 @@
+/* GTK - The GIMP Toolkit
+ * gdkasync.h: Utility functions using the Xlib asynchronous interfaces
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * 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_ASYNC_H__
+#define __GDK_ASYNC_H__
+
+#include <gdk/gdkdisplay.h>
+#include <X11/Xlib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkChildInfoX11 GdkChildInfoX11;
+
+typedef void (*GdkSendXEventCallback) (Window   window,
+				       gboolean success,
+				       gpointer data);
+typedef void (*GdkRoundTripCallback)  (GdkDisplay *display,
+				       gpointer data,
+				       gulong serial);
+
+struct _GdkChildInfoX11
+{
+  Window window;
+  gint x;
+  gint y;
+  gint width;
+  gint height;
+  guint is_mapped : 1;
+  guint has_wm_state : 1;
+  guint window_class : 2;
+};
+
+void _gdk_x11_send_client_message_async (GdkDisplay            *display,
+					 Window                 window,
+					 gboolean               propagate,
+					 glong                  event_mask,
+					 XClientMessageEvent   *event_send,
+					 GdkSendXEventCallback  callback,
+					 gpointer               data);
+void _gdk_x11_set_input_focus_safe      (GdkDisplay            *display,
+					 Window                 window,
+					 int                    revert_to,
+					 Time                   time);
+
+gboolean _gdk_x11_get_window_child_info (GdkDisplay       *display,
+					 Window            window,
+					 gboolean          get_wm_state,
+					 gboolean         *win_has_wm_state,
+					 GdkChildInfoX11 **children,
+					 guint            *nchildren);
+
+void _gdk_x11_roundtrip_async           (GdkDisplay           *display, 
+					 GdkRoundTripCallback callback,
+					 gpointer              data);
+
+G_END_DECLS
+
+#endif /* __GDK_ASYNC_H__ */
diff --git a/gdk/broadway/gdkcursor-broadway.c b/gdk/broadway/gdkcursor-broadway.c
new file mode 100644
index 0000000..470f723
--- /dev/null
+++ b/gdk/broadway/gdkcursor-broadway.c
@@ -0,0 +1,1040 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+/* needs to be first because any header might include gdk-pixbuf.h otherwise */
+#define GDK_PIXBUF_ENABLE_BACKEND
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "gdkcursor.h"
+
+#include "gdkprivate-broadway.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkx.h"
+
+#include <X11/Xlib.h>
+#include <X11/cursorfont.h>
+#ifdef HAVE_XCURSOR
+#include <X11/Xcursor/Xcursor.h>
+#endif
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+
+static guint theme_serial = 0;
+
+/* cursor_cache holds a cache of non-pixmap cursors to avoid expensive 
+ * libXcursor searches, cursors are added to it but only removed when
+ * their display is closed. We make the assumption that since there are 
+ * a small number of display's and a small number of cursor's that this 
+ * list will stay small enough not to be a problem.
+ */
+static GSList* cursor_cache = NULL;
+
+struct cursor_cache_key
+{
+  GdkDisplay* display;
+  GdkCursorType type;
+  const char* name;
+};
+
+/* Caller should check if there is already a match first.
+ * Cursor MUST be either a typed cursor or a pixmap with 
+ * a non-NULL name.
+ */
+static void
+add_to_cache (GdkCursorPrivate* cursor)
+{
+  cursor_cache = g_slist_prepend (cursor_cache, cursor);
+
+  /* Take a ref so that if the caller frees it we still have it */
+  gdk_cursor_ref ((GdkCursor*) cursor);
+}
+
+/* Returns 0 on a match
+ */
+static gint
+cache_compare_func (gconstpointer listelem, 
+                    gconstpointer target)
+{
+  GdkCursorPrivate* cursor = (GdkCursorPrivate*)listelem;
+  struct cursor_cache_key* key = (struct cursor_cache_key*)target;
+
+  if ((cursor->cursor.type != key->type) ||
+      (cursor->display != key->display))
+    return 1; /* No match */
+  
+  /* Elements marked as pixmap must be named cursors 
+   * (since we don't store normal pixmap cursors 
+   */
+  if (key->type == GDK_CURSOR_IS_PIXMAP)
+    return strcmp (key->name, cursor->name);
+
+  return 0; /* Match */
+}
+
+/* Returns the cursor if there is a match, NULL if not
+ * For named cursors type shall be GDK_CURSOR_IS_PIXMAP
+ * For unnamed, typed cursors, name shall be NULL
+ */
+static GdkCursorPrivate*
+find_in_cache (GdkDisplay    *display, 
+               GdkCursorType  type,
+               const char    *name)
+{
+  GSList* res;
+  struct cursor_cache_key key;
+
+  key.display = display;
+  key.type = type;
+  key.name = name;
+
+  res = g_slist_find_custom (cursor_cache, &key, cache_compare_func);
+
+  if (res)
+    return (GdkCursorPrivate *) res->data;
+
+  return NULL;
+}
+
+/* Called by gdk_display_x11_finalize to flush any cached cursors
+ * for a dead display.
+ */
+void 
+_gdk_x11_cursor_display_finalize (GdkDisplay *display)
+{
+  GSList* item;
+  GSList** itemp; /* Pointer to the thing to fix when we delete an item */
+  item = cursor_cache;
+  itemp = &cursor_cache;
+  while (item)
+    {
+      GdkCursorPrivate* cursor = (GdkCursorPrivate*)(item->data);
+      if (cursor->display == display)
+        {
+	  GSList* olditem;
+          gdk_cursor_unref ((GdkCursor*) cursor);
+	  /* Remove this item from the list */
+	  *(itemp) = item->next;
+	  olditem = item;
+	  item = g_slist_next (item);
+	  g_slist_free_1 (olditem);
+        } 
+      else 
+        {
+	  itemp = &(item->next);
+	  item = g_slist_next (item);
+	}
+    }
+}
+
+static Cursor
+get_blank_cursor (GdkDisplay *display)
+{
+  GdkScreen *screen;
+  Pixmap pixmap;
+  XColor color;
+  Cursor cursor;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+
+  screen = gdk_display_get_default_screen (display);
+  surface = _gdk_x11_window_create_bitmap_surface (gdk_screen_get_root_window (screen), 1, 1);
+  /* Clear surface */
+  cr = cairo_create (surface);
+  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+ 
+  pixmap = cairo_xlib_surface_get_drawable (surface);
+
+  color.pixel = 0; 
+  color.red = color.blue = color.green = 0;
+  
+  if (display->closed)
+    cursor = None;
+  else
+    cursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display),
+                                  pixmap, pixmap,
+                                  &color, &color, 1, 1);
+  cairo_surface_destroy (surface);
+
+  return cursor;
+}
+
+/**
+ * gdk_cursor_new_for_display:
+ * @display: the #GdkDisplay for which the cursor will be created
+ * @cursor_type: cursor to create
+ * 
+ * Creates a new cursor from the set of builtin cursors.
+ * Some useful ones are:
+ * <itemizedlist>
+ * <listitem><para>
+ *  <inlinegraphic format="PNG" fileref="right_ptr.png"></inlinegraphic> #GDK_RIGHT_PTR (right-facing arrow)
+ * </para></listitem>
+ * <listitem><para>
+ *  <inlinegraphic format="PNG" fileref="crosshair.png"></inlinegraphic> #GDK_CROSSHAIR (crosshair)
+ * </para></listitem>
+ * <listitem><para>
+ *  <inlinegraphic format="PNG" fileref="xterm.png"></inlinegraphic> #GDK_XTERM (I-beam)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="watch.png"></inlinegraphic> #GDK_WATCH (busy)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="fleur.png"></inlinegraphic> #GDK_FLEUR (for moving objects)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="hand1.png"></inlinegraphic> #GDK_HAND1 (a right-pointing hand)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="hand2.png"></inlinegraphic> #GDK_HAND2 (a left-pointing hand)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="left_side.png"></inlinegraphic> #GDK_LEFT_SIDE (resize left side)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="right_side.png"></inlinegraphic> #GDK_RIGHT_SIDE (resize right side)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="top_left_corner.png"></inlinegraphic> #GDK_TOP_LEFT_CORNER (resize northwest corner)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="top_right_corner.png"></inlinegraphic> #GDK_TOP_RIGHT_CORNER (resize northeast corner)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="bottom_left_corner.png"></inlinegraphic> #GDK_BOTTOM_LEFT_CORNER (resize southwest corner)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="bottom_right_corner.png"></inlinegraphic> #GDK_BOTTOM_RIGHT_CORNER (resize southeast corner)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="top_side.png"></inlinegraphic> #GDK_TOP_SIDE (resize top side)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="bottom_side.png"></inlinegraphic> #GDK_BOTTOM_SIDE (resize bottom side)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="sb_h_double_arrow.png"></inlinegraphic> #GDK_SB_H_DOUBLE_ARROW (move vertical splitter)
+ * </para></listitem>
+ * <listitem><para>
+ * <inlinegraphic format="PNG" fileref="sb_v_double_arrow.png"></inlinegraphic> #GDK_SB_V_DOUBLE_ARROW (move horizontal splitter)
+ * </para></listitem>
+ * <listitem><para>
+ * #GDK_BLANK_CURSOR (Blank cursor). Since 2.16
+ * </para></listitem>
+ * </itemizedlist>
+ *
+ * Return value: a new #GdkCursor
+ *
+ * Since: 2.2
+ **/
+GdkCursor*
+gdk_cursor_new_for_display (GdkDisplay    *display,
+			    GdkCursorType  cursor_type)
+{
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+  Cursor xcursor;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+  if (display->closed)
+    {
+      xcursor = None;
+    } 
+  else 
+    {
+      private = find_in_cache (display, cursor_type, NULL);
+
+      if (private)
+        {
+          /* Cache had it, add a ref for this user */
+          gdk_cursor_ref ((GdkCursor*) private);
+       
+          return (GdkCursor*) private;
+        } 
+      else 
+        {
+	  if (cursor_type != GDK_BLANK_CURSOR)
+            xcursor = XCreateFontCursor (GDK_DISPLAY_XDISPLAY (display),
+                                         cursor_type);
+	  else
+	    xcursor = get_blank_cursor (display);
+       }
+    }
+  
+  private = g_new (GdkCursorPrivate, 1);
+  private->display = display;
+  private->xcursor = xcursor;
+  private->name = NULL;
+  private->serial = theme_serial;
+
+  cursor = (GdkCursor *) private;
+  cursor->type = cursor_type;
+  cursor->ref_count = 1;
+  
+  if (xcursor != None)
+    add_to_cache (private);
+
+  return cursor;
+}
+
+void
+_gdk_cursor_destroy (GdkCursor *cursor)
+{
+  GdkCursorPrivate *private;
+
+  g_return_if_fail (cursor != NULL);
+  g_return_if_fail (cursor->ref_count == 0);
+
+  private = (GdkCursorPrivate *) cursor;
+  if (!private->display->closed && private->xcursor)
+    XFreeCursor (GDK_DISPLAY_XDISPLAY (private->display), private->xcursor);
+
+  g_free (private->name);
+  g_free (private);
+}
+
+/**
+ * gdk_x11_cursor_get_xdisplay:
+ * @cursor: a #GdkCursor.
+ * 
+ * Returns the display of a #GdkCursor.
+ * 
+ * Return value: an Xlib <type>Display*</type>.
+ **/
+Display *
+gdk_x11_cursor_get_xdisplay (GdkCursor *cursor)
+{
+  g_return_val_if_fail (cursor != NULL, NULL);
+
+  return GDK_DISPLAY_XDISPLAY(((GdkCursorPrivate *)cursor)->display);
+}
+
+/**
+ * gdk_x11_cursor_get_xcursor:
+ * @cursor: a #GdkCursor.
+ * 
+ * Returns the X cursor belonging to a #GdkCursor.
+ * 
+ * Return value: an Xlib <type>Cursor</type>.
+ **/
+Cursor
+gdk_x11_cursor_get_xcursor (GdkCursor *cursor)
+{
+  g_return_val_if_fail (cursor != NULL, None);
+
+  return ((GdkCursorPrivate *)cursor)->xcursor;
+}
+
+/** 
+ * gdk_cursor_get_display:
+ * @cursor: a #GdkCursor.
+ *
+ * Returns the display on which the #GdkCursor is defined.
+ *
+ * Returns: the #GdkDisplay associated to @cursor
+ *
+ * Since: 2.2
+ */
+
+GdkDisplay *
+gdk_cursor_get_display (GdkCursor *cursor)
+{
+  g_return_val_if_fail (cursor != NULL, NULL);
+
+  return ((GdkCursorPrivate *)cursor)->display;
+}
+
+#if defined(HAVE_XCURSOR) && defined(HAVE_XFIXES) && XFIXES_MAJOR >= 2
+
+/**
+ * gdk_cursor_get_image:
+ * @cursor: a #GdkCursor
+ *
+ * Returns a #GdkPixbuf with the image used to display the cursor.
+ *
+ * Note that depending on the capabilities of the windowing system and 
+ * on the cursor, GDK may not be able to obtain the image data. In this 
+ * case, %NULL is returned.
+ *
+ * Returns: a #GdkPixbuf representing @cursor, or %NULL
+ *
+ * Since: 2.8
+ */
+GdkPixbuf*  
+gdk_cursor_get_image (GdkCursor *cursor)
+{
+  Display *xdisplay;
+  GdkCursorPrivate *private;
+  XcursorImages *images = NULL;
+  XcursorImage *image;
+  gint size;
+  gchar buf[32];
+  guchar *data, *p, tmp;
+  GdkPixbuf *pixbuf;
+  gchar *theme;
+  
+  g_return_val_if_fail (cursor != NULL, NULL);
+
+  private = (GdkCursorPrivate *) cursor;
+    
+  xdisplay = GDK_DISPLAY_XDISPLAY (private->display);
+
+  size = XcursorGetDefaultSize (xdisplay);
+  theme = XcursorGetTheme (xdisplay);
+
+  if (cursor->type == GDK_CURSOR_IS_PIXMAP)
+    {
+      if (private->name)
+	images = XcursorLibraryLoadImages (private->name, theme, size);
+    }
+  else 
+    images = XcursorShapeLoadImages (cursor->type, theme, size);
+
+  if (!images)
+    return NULL;
+  
+  image = images->images[0];
+
+  data = g_malloc (4 * image->width * image->height);
+  memcpy (data, image->pixels, 4 * image->width * image->height);
+
+  for (p = data; p < data + (4 * image->width * image->height); p += 4)
+    {
+      tmp = p[0];
+      p[0] = p[2];
+      p[2] = tmp;
+    }
+
+  pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, TRUE,
+				     8, image->width, image->height,
+				     4 * image->width, 
+				     (GdkPixbufDestroyNotify)g_free, NULL);
+
+  if (private->name)
+    gdk_pixbuf_set_option (pixbuf, "name", private->name);
+  g_snprintf (buf, 32, "%d", image->xhot);
+  gdk_pixbuf_set_option (pixbuf, "x_hot", buf);
+  g_snprintf (buf, 32, "%d", image->yhot);
+  gdk_pixbuf_set_option (pixbuf, "y_hot", buf);
+
+  XcursorImagesDestroy (images);
+
+  return pixbuf;
+}
+
+void
+_gdk_x11_cursor_update_theme (GdkCursor *cursor)
+{
+  Display *xdisplay;
+  GdkCursorPrivate *private;
+  Cursor new_cursor = None;
+  GdkDisplayX11 *display_x11;
+
+  private = (GdkCursorPrivate *) cursor;
+  xdisplay = GDK_DISPLAY_XDISPLAY (private->display);
+  display_x11 = GDK_DISPLAY_X11 (private->display);
+
+  if (!display_x11->have_xfixes)
+    return;
+
+  if (private->serial == theme_serial)
+    return;
+
+  private->serial = theme_serial;
+
+  if (private->xcursor != None)
+    {
+      if (cursor->type == GDK_BLANK_CURSOR)
+        return;
+
+      if (cursor->type == GDK_CURSOR_IS_PIXMAP)
+	{
+	  if (private->name)
+	    new_cursor = XcursorLibraryLoadCursor (xdisplay, private->name);
+	}
+      else 
+	new_cursor = XcursorShapeLoadCursor (xdisplay, cursor->type);
+      
+      if (new_cursor != None)
+	{
+	  XFixesChangeCursor (xdisplay, new_cursor, private->xcursor);
+ 	  private->xcursor = new_cursor;
+	}
+    }
+}
+
+static void
+update_cursor (gpointer data,
+	       gpointer user_data)
+{
+  GdkCursor *cursor;
+
+  cursor = (GdkCursor*)(data);
+
+  if (!cursor)
+    return;
+  
+  _gdk_x11_cursor_update_theme (cursor);
+}
+
+/**
+ * gdk_x11_display_set_cursor_theme:
+ * @display: a #GdkDisplay
+ * @theme: the name of the cursor theme to use, or %NULL to unset
+ *         a previously set value 
+ * @size: the cursor size to use, or 0 to keep the previous size
+ *
+ * Sets the cursor theme from which the images for cursor
+ * should be taken. 
+ * 
+ * If the windowing system supports it, existing cursors created 
+ * with gdk_cursor_new(), gdk_cursor_new_for_display() and 
+ * gdk_cursor_new_for_name() are updated to reflect the theme 
+ * change. Custom cursors constructed with
+ * gdk_cursor_new_from_pixbuf() will have to be handled
+ * by the application (GTK+ applications can learn about 
+ * cursor theme changes by listening for change notification
+ * for the corresponding #GtkSetting).
+ *
+ * Since: 2.8
+ */
+void
+gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
+				  const gchar *theme,
+				  const gint   size)
+{
+  GdkDisplayX11 *display_x11;
+  Display *xdisplay;
+  gchar *old_theme;
+  gint old_size;
+
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+  xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+  old_theme = XcursorGetTheme (xdisplay);
+  old_size = XcursorGetDefaultSize (xdisplay);
+
+  if (old_size == size &&
+      (old_theme == theme ||
+       (old_theme && theme && strcmp (old_theme, theme) == 0)))
+    return;
+
+  theme_serial++;
+
+  XcursorSetTheme (xdisplay, theme);
+  if (size > 0)
+    XcursorSetDefaultSize (xdisplay, size);
+    
+  g_slist_foreach (cursor_cache, update_cursor, NULL);
+}
+
+#else
+
+GdkPixbuf*  
+gdk_cursor_get_image (GdkCursor *cursor)
+{
+  g_return_val_if_fail (cursor != NULL, NULL);
+  
+  return NULL;
+}
+
+void
+gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
+				  const gchar *theme,
+				  const gint   size)
+{
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+}
+
+void
+_gdk_x11_cursor_update_theme (GdkCursor *cursor)
+{
+  g_return_if_fail (cursor != NULL);
+}
+
+#endif
+
+#ifdef HAVE_XCURSOR
+
+static XcursorImage*
+create_cursor_image (GdkPixbuf *pixbuf,
+		     gint       x,
+		     gint       y)
+{
+  guint width, height;
+  XcursorImage *xcimage;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  xcimage = XcursorImageCreate (width, height);
+
+  xcimage->xhot = x;
+  xcimage->yhot = y;
+
+  surface = cairo_image_surface_create_for_data ((guchar *) xcimage->pixels,
+                                                 CAIRO_FORMAT_ARGB32,
+                                                 width,
+                                                 height,
+                                                 width * 4);
+
+  cr = cairo_create (surface);
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+  gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+
+  cairo_surface_destroy (surface);
+
+  return xcimage;
+}
+
+
+/**
+ * gdk_cursor_new_from_pixbuf:
+ * @display: the #GdkDisplay for which the cursor will be created
+ * @pixbuf: the #GdkPixbuf containing the cursor image
+ * @x: the horizontal offset of the 'hotspot' of the cursor. 
+ * @y: the vertical offset of the 'hotspot' of the cursor.
+ *
+ * Creates a new cursor from a pixbuf. 
+ *
+ * Not all GDK backends support RGBA cursors. If they are not 
+ * supported, a monochrome approximation will be displayed. 
+ * The functions gdk_display_supports_cursor_alpha() and 
+ * gdk_display_supports_cursor_color() can be used to determine
+ * whether RGBA cursors are supported; 
+ * gdk_display_get_default_cursor_size() and 
+ * gdk_display_get_maximal_cursor_size() give information about 
+ * cursor sizes.
+ *
+ * If @x or @y are <literal>-1</literal>, the pixbuf must have
+ * options named "x_hot" and "y_hot", resp., containing
+ * integer values between %0 and the width resp. height of
+ * the pixbuf. (Since: 3.0)
+ *
+ * On the X backend, support for RGBA cursors requires a
+ * sufficently new version of the X Render extension. 
+ *
+ * Returns: a new #GdkCursor.
+ * 
+ * Since: 2.4
+ */
+GdkCursor *
+gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
+			    GdkPixbuf  *pixbuf,
+			    gint        x,
+			    gint        y)
+{
+  XcursorImage *xcimage;
+  Cursor xcursor;
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+  const char *option;
+  char *end;
+  gint64 value;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+  if (x == -1 && (option = gdk_pixbuf_get_option (pixbuf, "x_hot")))
+    {
+      errno = 0;
+      end = NULL;
+      value = g_ascii_strtoll (option, &end, 10);
+      if (errno == 0 &&
+          end != option &&
+          value >= 0 && value < G_MAXINT)
+        x = (gint) value;
+    }
+  if (y == -1 && (option = gdk_pixbuf_get_option (pixbuf, "y_hot")))
+    {
+      errno = 0;
+      end = NULL;
+      value = g_ascii_strtoll (option, &end, 10);
+      if (errno == 0 &&
+          end != option &&
+          value >= 0 && value < G_MAXINT)
+        y = (gint) value;
+    }
+
+  g_return_val_if_fail (0 <= x && x < gdk_pixbuf_get_width (pixbuf), NULL);
+  g_return_val_if_fail (0 <= y && y < gdk_pixbuf_get_height (pixbuf), NULL);
+
+  if (display->closed)
+    xcursor = None;
+  else 
+    {
+      xcimage = create_cursor_image (pixbuf, x, y);
+      xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimage);
+      XcursorImageDestroy (xcimage);
+    }
+
+  private = g_new (GdkCursorPrivate, 1);
+  private->display = display;
+  private->xcursor = xcursor;
+  private->name = NULL;
+  private->serial = theme_serial;
+
+  cursor = (GdkCursor *) private;
+  cursor->type = GDK_CURSOR_IS_PIXMAP;
+  cursor->ref_count = 1;
+  
+  return cursor;
+}
+
+/**
+ * gdk_cursor_new_from_name:
+ * @display: the #GdkDisplay for which the cursor will be created
+ * @name: the name of the cursor
+ *
+ * Creates a new cursor by looking up @name in the current cursor
+ * theme. 
+ * 
+ * Returns: a new #GdkCursor, or %NULL if there is no cursor with 
+ *   the given name 
+ *
+ * Since: 2.8
+ */
+GdkCursor*  
+gdk_cursor_new_from_name (GdkDisplay  *display,
+			  const gchar *name)
+{
+  Cursor xcursor;
+  Display *xdisplay;
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+  if (display->closed)
+    xcursor = None;
+  else 
+    {
+      private = find_in_cache (display, GDK_CURSOR_IS_PIXMAP, name);
+
+      if (private)
+        {
+          /* Cache had it, add a ref for this user */
+          gdk_cursor_ref ((GdkCursor*) private);
+
+          return (GdkCursor*) private;
+        }
+
+      xdisplay = GDK_DISPLAY_XDISPLAY (display);
+      xcursor = XcursorLibraryLoadCursor (xdisplay, name);
+      if (xcursor == None)
+	return NULL;
+    }
+
+  private = g_new (GdkCursorPrivate, 1);
+  private->display = display;
+  private->xcursor = xcursor;
+  private->name = g_strdup (name);
+  private->serial = theme_serial;
+
+  cursor = (GdkCursor *) private;
+  cursor->type = GDK_CURSOR_IS_PIXMAP;
+  cursor->ref_count = 1;
+  add_to_cache (private);
+
+  return cursor;
+}
+
+/**
+ * gdk_display_supports_cursor_alpha:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if cursors can use an 8bit alpha channel 
+ * on @display. Otherwise, cursors are restricted to bilevel 
+ * alpha (i.e. a mask).
+ *
+ * Returns: whether cursors can have alpha channels.
+ *
+ * Since: 2.4
+ */
+gboolean 
+gdk_display_supports_cursor_alpha (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
+}
+
+/**
+ * gdk_display_supports_cursor_color:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if multicolored cursors are supported
+ * on @display. Otherwise, cursors have only a forground
+ * and a background color.
+ *
+ * Returns: whether cursors can have multiple colors.
+ *
+ * Since: 2.4
+ */
+gboolean 
+gdk_display_supports_cursor_color (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
+}
+
+/**
+ * gdk_display_get_default_cursor_size:
+ * @display: a #GdkDisplay
+ *
+ * Returns the default size to use for cursors on @display.
+ *
+ * Returns: the default cursor size.
+ *
+ * Since: 2.4
+ */
+guint     
+gdk_display_get_default_cursor_size (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return XcursorGetDefaultSize (GDK_DISPLAY_XDISPLAY (display));
+}
+
+#else
+
+static GdkCursor*
+gdk_cursor_new_from_pixmap (GdkDisplay     *display,
+                            Pixmap          source_pixmap,
+			    Pixmap          mask_pixmap,
+			    const GdkColor *fg,
+			    const GdkColor *bg,
+			    gint            x,
+			    gint            y)
+{
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+  Cursor xcursor;
+  XColor xfg, xbg;
+
+  g_return_val_if_fail (fg != NULL, NULL);
+  g_return_val_if_fail (bg != NULL, NULL);
+
+  xfg.pixel = fg->pixel;
+  xfg.red = fg->red;
+  xfg.blue = fg->blue;
+  xfg.green = fg->green;
+  xbg.pixel = bg->pixel;
+  xbg.red = bg->red;
+  xbg.blue = bg->blue;
+  xbg.green = bg->green;
+  
+  if (display->closed)
+    xcursor = None;
+  else
+    xcursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display),
+				   source_pixmap, mask_pixmap, &xfg, &xbg, x, y);
+  private = g_new (GdkCursorPrivate, 1);
+  private->display = display;
+  private->xcursor = xcursor;
+  private->name = NULL;
+  private->serial = theme_serial;
+
+  cursor = (GdkCursor *) private;
+  cursor->type = GDK_CURSOR_IS_PIXMAP;
+  cursor->ref_count = 1;
+  
+  return cursor;
+}
+
+GdkCursor *
+gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
+			    GdkPixbuf  *pixbuf,
+			    gint        x,
+			    gint        y)
+{
+  GdkCursor *cursor;
+  cairo_surface_t *pixmap, *mask;
+  guint width, height, n_channels, rowstride, data_stride, i, j;
+  guint8 *data, *mask_data, *pixels;
+  GdkColor fg = { 0, 0, 0, 0 };
+  GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
+  GdkScreen *screen;
+  cairo_surface_t *image;
+  cairo_t *cr;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  g_return_val_if_fail (0 <= x && x < width, NULL);
+  g_return_val_if_fail (0 <= y && y < height, NULL);
+
+  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+  pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+  data_stride = 4 * ((width + 31) / 32);
+  data = g_new0 (guint8, data_stride * height);
+  mask_data = g_new0 (guint8, data_stride * height);
+
+  for (j = 0; j < height; j++)
+    {
+      guint8 *src = pixels + j * rowstride;
+      guint8 *d = data + data_stride * j;
+      guint8 *md = mask_data + data_stride * j;
+	
+      for (i = 0; i < width; i++)
+	{
+	  if (src[1] < 0x80)
+	    *d |= 1 << (i % 8);
+	  
+	  if (n_channels == 3 || src[3] >= 0x80)
+	    *md |= 1 << (i % 8);
+	  
+	  src += n_channels;
+	  if (i % 8 == 7)
+	    {
+	      d++; 
+	      md++;
+	    }
+	}
+    }
+      
+  screen = gdk_display_get_default_screen (display);
+
+  pixmap = _gdk_x11_window_create_bitmap_surface (gdk_screen_get_root_window (screen), 
+	 		                          width, height);
+  cr = cairo_create (pixmap);
+  image = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_A1,
+                                               width, height, data_stride);
+  cairo_set_source_surface (cr, image, 0, 0);
+  cairo_surface_destroy (image);
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+ 
+  mask = _gdk_x11_window_create_bitmap_surface (gdk_screen_get_root_window (screen), 
+			                        width, height);
+  cr = cairo_create (mask);
+  image = cairo_image_surface_create_for_data (mask_data, CAIRO_FORMAT_A1,
+                                               width, height, data_stride);
+  cairo_set_source_surface (cr, image, 0, 0);
+  cairo_surface_destroy (image);
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+ 
+  cursor = gdk_cursor_new_from_pixmap (display,
+                                       cairo_xlib_surface_get_drawable (pixmap),
+                                       cairo_xlib_surface_get_drawable (mask),
+                                       &fg, &bg,
+                                       x, y);
+   
+  cairo_surface_destroy (pixmap);
+  cairo_surface_destroy (mask);
+
+  g_free (data);
+  g_free (mask_data);
+  
+  return cursor;
+}
+
+GdkCursor*  
+gdk_cursor_new_from_name (GdkDisplay  *display,
+			  const gchar *name)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+  return NULL;
+}
+
+gboolean 
+gdk_display_supports_cursor_alpha (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return FALSE;
+}
+
+gboolean 
+gdk_display_supports_cursor_color (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return FALSE;
+}
+
+guint     
+gdk_display_get_default_cursor_size (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
+  
+  /* no idea, really */
+  return 20; 
+}
+
+#endif
+
+
+/**
+ * gdk_display_get_maximal_cursor_size:
+ * @display: a #GdkDisplay
+ * @width: (out): the return location for the maximal cursor width
+ * @height: (out): the return location for the maximal cursor height
+ *
+ * Gets the maximal size to use for cursors on @display.
+ *
+ * Since: 2.4
+ */
+void     
+gdk_display_get_maximal_cursor_size (GdkDisplay *display,
+				     guint       *width,
+				     guint       *height)
+{
+  GdkScreen *screen;
+  GdkWindow *window;
+
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+  
+  screen = gdk_display_get_default_screen (display);
+  window = gdk_screen_get_root_window (screen);
+  XQueryBestCursor (GDK_DISPLAY_XDISPLAY (display), 
+		    GDK_WINDOW_XWINDOW (window), 
+		    128, 128, width, height);
+}
diff --git a/gdk/broadway/gdkdevice-broadway.c b/gdk/broadway/gdkdevice-broadway.c
new file mode 100644
index 0000000..3be222d
--- /dev/null
+++ b/gdk/broadway/gdkdevice-broadway.c
@@ -0,0 +1,502 @@
+/* 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 "config.h"
+
+#include "gdkdevice-broadway.h"
+
+#include "gdkwindow.h"
+#include "gdkprivate-broadway.h"
+#include "gdkx.h"
+
+static gboolean gdk_device_core_get_history (GdkDevice      *device,
+                                             GdkWindow      *window,
+                                             guint32         start,
+                                             guint32         stop,
+                                             GdkTimeCoord ***events,
+                                             gint           *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,
+                                                       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,
+                             gint           *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_window_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,
+                                    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 && last != root &&
+          (window = gdk_window_lookup_for_display (display, last)) != NULL &&
+          GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
+        {
+          xwindow = last;
+          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 --git a/gdk/broadway/gdkdevice-broadway.h b/gdk/broadway/gdkdevice-broadway.h
new file mode 100644
index 0000000..9ff65c9
--- /dev/null
+++ b/gdk/broadway/gdkdevice-broadway.h
@@ -0,0 +1,52 @@
+/* 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_BROADWAY_H__
+#define __GDK_DEVICE_BROADWAY_H__
+
+#include <gdk/gdkdeviceprivate.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_CORE         (gdk_device_core_get_type ())
+#define GDK_DEVICE_CORE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_CORE, GdkDeviceCore))
+#define GDK_DEVICE_CORE_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_CORE, GdkDeviceCoreClass))
+#define GDK_IS_DEVICE_CORE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_CORE))
+#define GDK_IS_DEVICE_CORE_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_CORE))
+#define GDK_DEVICE_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_CORE, GdkDeviceCoreClass))
+
+typedef struct _GdkDeviceCore GdkDeviceCore;
+typedef struct _GdkDeviceCoreClass GdkDeviceCoreClass;
+
+struct _GdkDeviceCore
+{
+  GdkDevice parent_instance;
+};
+
+struct _GdkDeviceCoreClass
+{
+  GdkDeviceClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType gdk_device_core_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_BROADWAY_H__ */
diff --git a/gdk/broadway/gdkdevicemanager-broadway.c b/gdk/broadway/gdkdevicemanager-broadway.c
new file mode 100644
index 0000000..7b69bd0
--- /dev/null
+++ b/gdk/broadway/gdkdevicemanager-broadway.c
@@ -0,0 +1,920 @@
+/* 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 "config.h"
+
+#include "gdkdevicemanager-broadway.h"
+
+#include "gdktypes.h"
+#include "gdkdevicemanager.h"
+#include "gdkeventtranslator.h"
+#include "gdkdevice-broadway.h"
+#include "gdkkeysyms.h"
+#include "gdkprivate-broadway.h"
+#include "gdkx.h"
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+
+#define HAS_FOCUS(toplevel)                           \
+  ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
+
+static void    gdk_device_manager_core_finalize    (GObject *object);
+static void    gdk_device_manager_core_constructed (GObject *object);
+
+static GList * gdk_device_manager_core_list_devices (GdkDeviceManager *device_manager,
+                                                     GdkDeviceType     type);
+static GdkDevice * gdk_device_manager_core_get_client_pointer (GdkDeviceManager *device_manager);
+
+static void     gdk_device_manager_event_translator_init (GdkEventTranslatorIface *iface);
+
+static gboolean gdk_device_manager_core_translate_event  (GdkEventTranslator *translator,
+                                                          GdkDisplay         *display,
+                                                          GdkEvent           *event,
+                                                          XEvent             *xevent);
+
+
+G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerCore, gdk_device_manager_core, GDK_TYPE_DEVICE_MANAGER,
+                         G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
+                                                gdk_device_manager_event_translator_init))
+
+static void
+gdk_device_manager_core_class_init (GdkDeviceManagerCoreClass *klass)
+{
+  GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gdk_device_manager_core_finalize;
+  object_class->constructed = gdk_device_manager_core_constructed;
+  device_manager_class->list_devices = gdk_device_manager_core_list_devices;
+  device_manager_class->get_client_pointer = gdk_device_manager_core_get_client_pointer;
+}
+
+static void
+gdk_device_manager_event_translator_init (GdkEventTranslatorIface *iface)
+{
+  iface->translate_event = gdk_device_manager_core_translate_event;
+}
+
+static GdkDevice *
+create_core_pointer (GdkDeviceManager *device_manager,
+                     GdkDisplay       *display)
+{
+  return g_object_new (GDK_TYPE_DEVICE_CORE,
+                       "name", "Core Pointer",
+                       "type", GDK_DEVICE_TYPE_MASTER,
+                       "input-source", GDK_SOURCE_MOUSE,
+                       "input-mode", GDK_MODE_SCREEN,
+                       "has-cursor", TRUE,
+                       "display", display,
+                       "device-manager", device_manager,
+                       NULL);
+}
+
+static GdkDevice *
+create_core_keyboard (GdkDeviceManager *device_manager,
+                      GdkDisplay       *display)
+{
+  return g_object_new (GDK_TYPE_DEVICE_CORE,
+                       "name", "Core Keyboard",
+                       "type", GDK_DEVICE_TYPE_MASTER,
+                       "input-source", GDK_SOURCE_KEYBOARD,
+                       "input-mode", GDK_MODE_SCREEN,
+                       "has-cursor", FALSE,
+                       "display", display,
+                       "device-manager", device_manager,
+                       NULL);
+}
+
+static void
+gdk_device_manager_core_init (GdkDeviceManagerCore *device_manager)
+{
+}
+
+static void
+gdk_device_manager_core_finalize (GObject *object)
+{
+  GdkDeviceManagerCore *device_manager_core;
+
+  device_manager_core = GDK_DEVICE_MANAGER_CORE (object);
+
+  g_object_unref (device_manager_core->core_pointer);
+  g_object_unref (device_manager_core->core_keyboard);
+
+  G_OBJECT_CLASS (gdk_device_manager_core_parent_class)->finalize (object);
+}
+
+static void
+gdk_device_manager_core_constructed (GObject *object)
+{
+  GdkDeviceManagerCore *device_manager;
+  GdkDisplay *display;
+
+  device_manager = GDK_DEVICE_MANAGER_CORE (object);
+  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
+  device_manager->core_pointer = create_core_pointer (GDK_DEVICE_MANAGER (device_manager), display);
+  device_manager->core_keyboard = create_core_keyboard (GDK_DEVICE_MANAGER (device_manager), display);
+
+  _gdk_device_set_associated_device (device_manager->core_pointer, device_manager->core_keyboard);
+  _gdk_device_set_associated_device (device_manager->core_keyboard, device_manager->core_pointer);
+}
+
+static void
+translate_key_event (GdkDisplay           *display,
+                     GdkDeviceManagerCore *device_manager,
+		     GdkEvent             *event,
+		     XEvent               *xevent)
+{
+  GdkKeymap *keymap = gdk_keymap_get_for_display (display);
+  GdkModifierType consumed, state;
+  gunichar c = 0;
+  gchar buf[7];
+
+  event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
+  event->key.time = xevent->xkey.time;
+  gdk_event_set_device (event, device_manager->core_keyboard);
+
+  event->key.state = (GdkModifierType) xevent->xkey.state;
+  event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
+  event->key.hardware_keycode = xevent->xkey.keycode;
+
+  event->key.keyval = GDK_KEY_VoidSymbol;
+
+  gdk_keymap_translate_keyboard_state (keymap,
+				       event->key.hardware_keycode,
+				       event->key.state,
+				       event->key.group,
+				       &event->key.keyval,
+                                       NULL, NULL, &consumed);
+
+  state = event->key.state & ~consumed;
+  _gdk_keymap_add_virtual_modifiers_compat (keymap, &state);
+  event->key.state |= state;
+
+  event->key.is_modifier = _gdk_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
+
+  /* Fill in event->string crudely, since various programs
+   * depend on it.
+   */
+  event->key.string = NULL;
+
+  if (event->key.keyval != GDK_KEY_VoidSymbol)
+    c = gdk_keyval_to_unicode (event->key.keyval);
+
+  if (c)
+    {
+      gsize bytes_written;
+      gint len;
+
+      /* Apply the control key - Taken from Xlib
+       */
+      if (event->key.state & GDK_CONTROL_MASK)
+	{
+	  if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
+	  else if (c == '2')
+	    {
+	      event->key.string = g_memdup ("\0\0", 2);
+	      event->key.length = 1;
+	      buf[0] = '\0';
+	      goto out;
+	    }
+	  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->key.string = g_locale_from_utf8 (buf, len,
+					      NULL, &bytes_written,
+					      NULL);
+      if (event->key.string)
+	event->key.length = bytes_written;
+    }
+  else if (event->key.keyval == GDK_KEY_Escape)
+    {
+      event->key.length = 1;
+      event->key.string = g_strdup ("\033");
+    }
+  else if (event->key.keyval == GDK_KEY_Return ||
+	  event->key.keyval == GDK_KEY_KP_Enter)
+    {
+      event->key.length = 1;
+      event->key.string = g_strdup ("\r");
+    }
+
+  if (!event->key.string)
+    {
+      event->key.length = 0;
+      event->key.string = g_strdup ("");
+    }
+
+ out:
+#ifdef G_ENABLE_DEBUG
+  if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
+    {
+      g_message ("%s:\t\twindow: %ld	 key: %12s  %d",
+		 event->type == GDK_KEY_PRESS ? "key press  " : "key release",
+		 xevent->xkey.window,
+		 event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
+		 event->key.keyval);
+
+      if (event->key.length > 0)
+	g_message ("\t\tlength: %4d string: \"%s\"",
+		   event->key.length, buf);
+    }
+#endif /* G_ENABLE_DEBUG */
+  return;
+}
+
+#ifdef G_ENABLE_DEBUG
+static const char notify_modes[][19] = {
+  "NotifyNormal",
+  "NotifyGrab",
+  "NotifyUngrab",
+  "NotifyWhileGrabbed"
+};
+
+static const char notify_details[][23] = {
+  "NotifyAncestor",
+  "NotifyVirtual",
+  "NotifyInferior",
+  "NotifyNonlinear",
+  "NotifyNonlinearVirtual",
+  "NotifyPointer",
+  "NotifyPointerRoot",
+  "NotifyDetailNone"
+};
+#endif
+
+static void
+set_user_time (GdkWindow *window,
+	       GdkEvent  *event)
+{
+  g_return_if_fail (event != NULL);
+
+  window = gdk_window_get_toplevel (event->client.window);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  /* If an event doesn't have a valid timestamp, we shouldn't use it
+   * to update the latest user interaction time.
+   */
+  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));
+}
+
+static void
+generate_focus_event (GdkDeviceManagerCore *device_manager,
+                      GdkWindow            *window,
+		      gboolean              in)
+{
+  GdkEvent *event;
+
+  event = gdk_event_new (GDK_FOCUS_CHANGE);
+  event->focus_change.window = g_object_ref (window);
+  event->focus_change.send_event = FALSE;
+  event->focus_change.in = in;
+  gdk_event_set_device (event, device_manager->core_keyboard);
+
+  gdk_event_put (event);
+  gdk_event_free (event);
+}
+
+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 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
+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,
+                  XEvent             *xevent)
+{
+  GdkDeviceManager *device_manager;
+  GdkDisplay *display;
+  GdkWindow *window;
+
+  device_manager = GDK_DEVICE_MANAGER (translator);
+  display = gdk_device_manager_get_display (device_manager);
+  window = gdk_window_lookup_for_display (display, xevent->xany.window);
+
+  /* Apply keyboard grabs to non-native windows */
+  if (xevent->type == KeyPress || xevent->type == KeyRelease)
+    {
+      GdkDeviceGrabInfo *info;
+      gulong serial;
+
+      serial = _gdk_windowing_window_get_next_serial (display);
+      info = _gdk_display_has_device_grab (display,
+                                           GDK_DEVICE_MANAGER_CORE (device_manager)->core_keyboard,
+                                           serial);
+      if (info &&
+          (!is_parent_of (info->window, window) ||
+           !info->owner_events))
+        {
+          /* Report key event against grab window */
+          window = info->window;
+        }
+    }
+
+  return window;
+}
+
+static gboolean
+gdk_device_manager_core_translate_event (GdkEventTranslator *translator,
+                                         GdkDisplay         *display,
+                                         GdkEvent           *event,
+                                         XEvent             *xevent)
+{
+  GdkDeviceManagerCore *device_manager;
+  GdkWindow *window;
+  GdkWindowObject *window_private;
+  GdkWindowImplX11 *window_impl = NULL;
+  gboolean return_val;
+  GdkToplevelX11 *toplevel = NULL;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  device_manager = GDK_DEVICE_MANAGER_CORE (translator);
+  return_val = FALSE;
+
+  window = get_event_window (translator, xevent);
+  window_private = (GdkWindowObject *) window;
+
+  if (window)
+    {
+      if (GDK_WINDOW_DESTROYED (window) || !GDK_IS_WINDOW (window))
+        return FALSE;
+
+      toplevel = _gdk_x11_window_get_toplevel (window);
+      window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+      g_object_ref (window);
+    }
+
+  event->any.window = window;
+  event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
+
+  if (window_private && GDK_WINDOW_DESTROYED (window))
+    {
+      if (xevent->type != DestroyNotify)
+	{
+	  return_val = FALSE;
+	  goto done;
+	}
+    }
+
+  if (window &&
+      (xevent->type == MotionNotify ||
+       xevent->type == ButtonRelease))
+    {
+      if (_gdk_moveresize_handle_event (xevent))
+	{
+          return_val = FALSE;
+          goto done;
+        }
+    }
+
+  /* We do a "manual" conversion of the XEvent to a
+   *  GdkEvent. The structures are mostly the same so
+   *  the conversion is fairly straightforward. We also
+   *  optionally print debugging info regarding events
+   *  received.
+   */
+
+  return_val = TRUE;
+
+  switch (xevent->type)
+    {
+    case KeyPress:
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+      translate_key_event (display, device_manager, event, xevent);
+      set_user_time (window, event);
+      break;
+
+    case KeyRelease:
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      /* Emulate detectable auto-repeat by checking to see
+       * if the next event is a key press with the same
+       * keycode and timestamp, and if so, ignoring the event.
+       */
+
+      if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
+	{
+	  XEvent next_event;
+
+	  XPeekEvent (xevent->xkey.display, &next_event);
+
+	  if (next_event.type == KeyPress &&
+	      next_event.xkey.keycode == xevent->xkey.keycode &&
+	      next_event.xkey.time == xevent->xkey.time)
+	    {
+	      return_val = FALSE;
+	      break;
+	    }
+	}
+
+      translate_key_event (display, device_manager, event, xevent);
+      break;
+
+    case ButtonPress:
+      GDK_NOTE (EVENTS,
+		g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
+			   xevent->xbutton.window,
+			   xevent->xbutton.x, xevent->xbutton.y,
+			   xevent->xbutton.button));
+
+      if (window_private == NULL)
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      /* If we get a ButtonPress event where the button is 4 or 5,
+	 it's a Scroll event */
+      switch (xevent->xbutton.button)
+        {
+        case 4: /* up */
+        case 5: /* down */
+        case 6: /* left */
+        case 7: /* right */
+	  event->scroll.type = GDK_SCROLL;
+
+          if (xevent->xbutton.button == 4)
+            event->scroll.direction = GDK_SCROLL_UP;
+          else if (xevent->xbutton.button == 5)
+            event->scroll.direction = GDK_SCROLL_DOWN;
+          else if (xevent->xbutton.button == 6)
+            event->scroll.direction = GDK_SCROLL_LEFT;
+          else
+            event->scroll.direction = GDK_SCROLL_RIGHT;
+
+	  event->scroll.window = window;
+	  event->scroll.time = xevent->xbutton.time;
+	  event->scroll.x = (gdouble) xevent->xbutton.x;
+	  event->scroll.y = (gdouble) xevent->xbutton.y;
+	  event->scroll.x_root = (gdouble) xevent->xbutton.x_root;
+	  event->scroll.y_root = (gdouble) xevent->xbutton.y_root;
+	  event->scroll.state = (GdkModifierType) xevent->xbutton.state;
+	  event->scroll.device = device_manager->core_pointer;
+
+	  if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	    {
+	      return_val = FALSE;
+	      break;
+	    }
+
+          break;
+
+        default:
+	  event->button.type = GDK_BUTTON_PRESS;
+	  event->button.window = window;
+	  event->button.time = xevent->xbutton.time;
+	  event->button.x = (gdouble) xevent->xbutton.x;
+	  event->button.y = (gdouble) xevent->xbutton.y;
+	  event->button.x_root = (gdouble) xevent->xbutton.x_root;
+	  event->button.y_root = (gdouble) xevent->xbutton.y_root;
+	  event->button.axes = NULL;
+	  event->button.state = (GdkModifierType) xevent->xbutton.state;
+	  event->button.button = xevent->xbutton.button;
+	  event->button.device = device_manager->core_pointer;
+
+	  if (!set_screen_from_root (display, event, xevent->xbutton.root))
+            return_val = FALSE;
+
+          break;
+	}
+
+      set_user_time (window, event);
+
+      break;
+
+    case ButtonRelease:
+      GDK_NOTE (EVENTS,
+		g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
+			   xevent->xbutton.window,
+			   xevent->xbutton.x, xevent->xbutton.y,
+			   xevent->xbutton.button));
+
+      if (window_private == NULL)
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      /* We treat button presses as scroll wheel events, so ignore the release */
+      if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
+          xevent->xbutton.button == 6 || xevent->xbutton.button == 7)
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      event->button.type = GDK_BUTTON_RELEASE;
+      event->button.window = window;
+      event->button.time = xevent->xbutton.time;
+      event->button.x = (gdouble) xevent->xbutton.x;
+      event->button.y = (gdouble) xevent->xbutton.y;
+      event->button.x_root = (gdouble) xevent->xbutton.x_root;
+      event->button.y_root = (gdouble) xevent->xbutton.y_root;
+      event->button.axes = NULL;
+      event->button.state = (GdkModifierType) xevent->xbutton.state;
+      event->button.button = xevent->xbutton.button;
+      event->button.device = device_manager->core_pointer;
+
+      if (!set_screen_from_root (display, event, xevent->xbutton.root))
+        return_val = FALSE;
+
+      break;
+
+    case MotionNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s",
+			   xevent->xmotion.window,
+			   xevent->xmotion.x, xevent->xmotion.y,
+			   (xevent->xmotion.is_hint) ? "true" : "false"));
+
+      if (window_private == NULL)
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      event->motion.type = GDK_MOTION_NOTIFY;
+      event->motion.window = window;
+      event->motion.time = xevent->xmotion.time;
+      event->motion.x = (gdouble) xevent->xmotion.x;
+      event->motion.y = (gdouble) xevent->xmotion.y;
+      event->motion.x_root = (gdouble) xevent->xmotion.x_root;
+      event->motion.y_root = (gdouble) xevent->xmotion.y_root;
+      event->motion.axes = NULL;
+      event->motion.state = (GdkModifierType) xevent->xmotion.state;
+      event->motion.is_hint = xevent->xmotion.is_hint;
+      event->motion.device = device_manager->core_pointer;
+
+      if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      break;
+
+    case EnterNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
+			   xevent->xcrossing.window,
+			   xevent->xcrossing.detail,
+			   xevent->xcrossing.subwindow));
+
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      event->crossing.type = GDK_ENTER_NOTIFY;
+      event->crossing.window = window;
+      gdk_event_set_device (event, device_manager->core_pointer);
+
+      /* If the subwindow field of the XEvent is non-NULL, then
+       *  lookup the corresponding GdkWindow.
+       */
+      if (xevent->xcrossing.subwindow != None)
+	event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
+      else
+	event->crossing.subwindow = NULL;
+
+      event->crossing.time = xevent->xcrossing.time;
+      event->crossing.x = (gdouble) xevent->xcrossing.x;
+      event->crossing.y = (gdouble) xevent->xcrossing.y;
+      event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
+      event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
+
+      event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
+      event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
+
+      event->crossing.focus = xevent->xcrossing.focus;
+      event->crossing.state = xevent->xcrossing.state;
+
+      break;
+
+    case LeaveNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
+			   xevent->xcrossing.window,
+			   xevent->xcrossing.detail, xevent->xcrossing.subwindow));
+
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      event->crossing.type = GDK_LEAVE_NOTIFY;
+      event->crossing.window = window;
+      gdk_event_set_device (event, device_manager->core_pointer);
+
+      /* If the subwindow field of the XEvent is non-NULL, then
+       *  lookup the corresponding GdkWindow.
+       */
+      if (xevent->xcrossing.subwindow != None)
+	event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
+      else
+	event->crossing.subwindow = NULL;
+
+      event->crossing.time = xevent->xcrossing.time;
+      event->crossing.x = (gdouble) xevent->xcrossing.x;
+      event->crossing.y = (gdouble) xevent->xcrossing.y;
+      event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
+      event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
+
+      event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
+      event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
+
+      event->crossing.focus = xevent->xcrossing.focus;
+      event->crossing.state = xevent->xcrossing.state;
+
+      break;
+
+      /* We only care about focus events that indicate that _this_
+       * window (not a ancestor or child) got or lost the focus
+       */
+    case FocusIn:
+      GDK_NOTE (EVENTS,
+		g_message ("focus in:\t\twindow: %ld, detail: %s, mode: %s",
+			   xevent->xfocus.window,
+			   notify_details[xevent->xfocus.detail],
+			   notify_modes[xevent->xfocus.mode]));
+
+      if (toplevel)
+	{
+	  gboolean had_focus = HAS_FOCUS (toplevel);
+
+	  switch (xevent->xfocus.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 &&
+		  xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_pointer_focus = FALSE;
+
+	      /* fall through */
+	    case NotifyNonlinear:
+	    case NotifyNonlinearVirtual:
+	      if (xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_focus_window = TRUE;
+	      /* We pretend that the focus moves to the grab
+	       * window, so we pay attention to NotifyGrab
+	       * NotifyUngrab, and ignore NotifyWhileGrabbed
+	       */
+	      if (xevent->xfocus.mode != NotifyWhileGrabbed)
+		toplevel->has_focus = TRUE;
+	      break;
+	    case NotifyPointer:
+	      /* The X server sends NotifyPointer/NotifyGrab,
+	       * but the pointer focus is ignored while a
+	       * grab is in effect
+	       */
+	      if (xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_pointer_focus = TRUE;
+	      break;
+	    case NotifyInferior:
+	    case NotifyPointerRoot:
+	    case NotifyDetailNone:
+	      break;
+	    }
+
+	  if (HAS_FOCUS (toplevel) != had_focus)
+	    generate_focus_event (device_manager, window, TRUE);
+	}
+      break;
+    case FocusOut:
+      GDK_NOTE (EVENTS,
+		g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s",
+			   xevent->xfocus.window,
+			   notify_details[xevent->xfocus.detail],
+			   notify_modes[xevent->xfocus.mode]));
+
+      if (toplevel)
+	{
+	  gboolean had_focus = HAS_FOCUS (toplevel);
+
+	  switch (xevent->xfocus.detail)
+	    {
+	    case NotifyAncestor:
+	    case NotifyVirtual:
+	      /* When the focus moves from the window or a descendent
+	       * of the window to an ancestor of the window, *and* the
+	       * pointer is inside the window, then we were previously
+	       * receiving keystroke events in the has_focus_window
+	       * case and are now receiving them in the
+	       * has_pointer_focus case.
+	       */
+	      if (toplevel->has_pointer &&
+		  xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_pointer_focus = TRUE;
+
+	      /* fall through */
+	    case NotifyNonlinear:
+	    case NotifyNonlinearVirtual:
+	      if (xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_focus_window = FALSE;
+	      if (xevent->xfocus.mode != NotifyWhileGrabbed)
+		toplevel->has_focus = FALSE;
+	      break;
+	    case NotifyPointer:
+	      if (xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_pointer_focus = FALSE;
+	    break;
+	    case NotifyInferior:
+	    case NotifyPointerRoot:
+	    case NotifyDetailNone:
+	      break;
+	    }
+
+	  if (HAS_FOCUS (toplevel) != had_focus)
+	    generate_focus_event (device_manager, window, FALSE);
+	}
+      break;
+
+    default:
+        return_val = FALSE;
+    }
+
+ done:
+  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;
+    }
+
+  if (window)
+    g_object_unref (window);
+
+  return return_val;
+}
+
+static GList *
+gdk_device_manager_core_list_devices (GdkDeviceManager *device_manager,
+                                      GdkDeviceType     type)
+{
+  GdkDeviceManagerCore *device_manager_core;
+  GList *devices = NULL;
+
+  if (type == GDK_DEVICE_TYPE_MASTER)
+    {
+      device_manager_core = (GdkDeviceManagerCore *) device_manager;
+      devices = g_list_prepend (devices, device_manager_core->core_keyboard);
+      devices = g_list_prepend (devices, device_manager_core->core_pointer);
+    }
+
+  return devices;
+}
+
+static GdkDevice *
+gdk_device_manager_core_get_client_pointer (GdkDeviceManager *device_manager)
+{
+  GdkDeviceManagerCore *device_manager_core;
+
+  device_manager_core = (GdkDeviceManagerCore *) device_manager;
+  return device_manager_core->core_pointer;
+}
+
+GdkDeviceManager *
+_gdk_device_manager_new (GdkDisplay *display)
+{
+  return g_object_new (GDK_TYPE_DEVICE_MANAGER_CORE,
+		       "display", display,
+		       NULL);
+}
diff --git a/gdk/broadway/gdkdevicemanager-broadway.h b/gdk/broadway/gdkdevicemanager-broadway.h
new file mode 100644
index 0000000..50ea91d
--- /dev/null
+++ b/gdk/broadway/gdkdevicemanager-broadway.h
@@ -0,0 +1,54 @@
+/* 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_MANAGER_BROADWAY_H__
+#define __GDK_DEVICE_MANAGER_BROADWAY_H__
+
+#include <gdk/gdkdevicemanager.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_MANAGER_CORE         (gdk_device_manager_core_get_type ())
+#define GDK_DEVICE_MANAGER_CORE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_MANAGER_CORE, GdkDeviceManagerCore))
+#define GDK_DEVICE_MANAGER_CORE_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_MANAGER_CORE, GdkDeviceManagerCoreClass))
+#define GDK_IS_DEVICE_MANAGER_CORE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_MANAGER_CORE))
+#define GDK_IS_DEVICE_MANAGER_CORE_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_MANAGER_CORE))
+#define GDK_DEVICE_MANAGER_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_MANAGER_CORE, GdkDeviceManagerCoreClass))
+
+typedef struct _GdkDeviceManagerCore GdkDeviceManagerCore;
+typedef struct _GdkDeviceManagerCoreClass GdkDeviceManagerCoreClass;
+
+struct _GdkDeviceManagerCore
+{
+  GdkDeviceManager parent_object;
+  GdkDevice *core_pointer;
+  GdkDevice *core_keyboard;
+};
+
+struct _GdkDeviceManagerCoreClass
+{
+  GdkDeviceManagerClass parent_class;
+};
+
+GType gdk_device_manager_core_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_MANAGER_BROADWAY_H__ */
diff --git a/gdk/broadway/gdkdisplay-broadway.c b/gdk/broadway/gdkdisplay-broadway.c
new file mode 100644
index 0000000..8a8e1ba
--- /dev/null
+++ b/gdk/broadway/gdkdisplay-broadway.c
@@ -0,0 +1,2977 @@
+/* GDK - The GIMP Drawing Kit
+ * gdkdisplay-x11.c
+ * 
+ * Copyright 2001 Sun Microsystems Inc.
+ * Copyright (C) 2004 Nokia Corporation
+ *
+ * Erwann Chenede <erwann chenede sun com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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 "config.h"
+
+#include "gdkdisplay-broadway.h"
+
+#include "gdkx.h"
+#include "gdkasync.h"
+#include "gdkdisplay.h"
+#include "gdkeventsource.h"
+#include "gdkeventtranslator.h"
+#include "gdkscreen.h"
+#include "gdkscreen-broadway.h"
+#include "gdkinternals.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdevicemanager.h"
+#include "xsettings-client.h"
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <X11/Xatom.h>
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+#include <X11/extensions/shape.h>
+
+#ifdef HAVE_XCOMPOSITE
+#include <X11/extensions/Xcomposite.h>
+#endif
+
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+
+#ifdef HAVE_RANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
+typedef struct _GdkErrorTrap  GdkErrorTrap;
+
+struct _GdkErrorTrap
+{
+  /* Next sequence when trap was pushed, i.e. first sequence to
+   * ignore
+   */
+  gulong start_sequence;
+
+  /* Next sequence when trap was popped, i.e. first sequence
+   * to not ignore. 0 if trap is still active.
+   */
+  gulong end_sequence;
+
+  /* Most recent error code within the sequence */
+  int error_code;
+};
+
+static void   gdk_display_x11_dispose            (GObject            *object);
+static void   gdk_display_x11_finalize           (GObject            *object);
+
+static void     gdk_display_x11_event_translator_init (GdkEventTranslatorIface *iface);
+
+static gboolean gdk_display_x11_translate_event (GdkEventTranslator *translator,
+                                                 GdkDisplay         *display,
+                                                 GdkEvent           *event,
+                                                 XEvent             *xevent);
+
+#ifdef HAVE_X11R6
+static void gdk_internal_connection_watch (Display  *display,
+					   XPointer  arg,
+					   gint      fd,
+					   gboolean  opening,
+					   XPointer *watch_data);
+#endif /* HAVE_X11R6 */
+
+typedef struct _GdkEventTypeX11 GdkEventTypeX11;
+
+struct _GdkEventTypeX11
+{
+  gint base;
+  gint n_events;
+};
+
+/* Note that we never *directly* use WM_LOCALE_NAME, WM_PROTOCOLS,
+ * but including them here has the side-effect of getting them
+ * into the internal Xlib cache
+ */
+static const char *const precache_atoms[] = {
+  "UTF8_STRING",
+  "WM_CLIENT_LEADER",
+  "WM_DELETE_WINDOW",
+  "WM_ICON_NAME",
+  "WM_LOCALE_NAME",
+  "WM_NAME",
+  "WM_PROTOCOLS",
+  "WM_TAKE_FOCUS",
+  "WM_WINDOW_ROLE",
+  "_NET_ACTIVE_WINDOW",
+  "_NET_CURRENT_DESKTOP",
+  "_NET_FRAME_EXTENTS",
+  "_NET_STARTUP_ID",
+  "_NET_WM_CM_S0",
+  "_NET_WM_DESKTOP",
+  "_NET_WM_ICON",
+  "_NET_WM_ICON_NAME",
+  "_NET_WM_NAME",
+  "_NET_WM_PID",
+  "_NET_WM_PING",
+  "_NET_WM_STATE",
+  "_NET_WM_STATE_ABOVE",
+  "_NET_WM_STATE_BELOW",
+  "_NET_WM_STATE_FULLSCREEN",
+  "_NET_WM_STATE_MODAL",
+  "_NET_WM_STATE_MAXIMIZED_VERT",
+  "_NET_WM_STATE_MAXIMIZED_HORZ",
+  "_NET_WM_STATE_SKIP_TASKBAR",
+  "_NET_WM_STATE_SKIP_PAGER",
+  "_NET_WM_STATE_STICKY",
+  "_NET_WM_SYNC_REQUEST",
+  "_NET_WM_SYNC_REQUEST_COUNTER",
+  "_NET_WM_WINDOW_TYPE",
+  "_NET_WM_WINDOW_TYPE_NORMAL",
+  "_NET_WM_USER_TIME",
+  "_NET_VIRTUAL_ROOTS"
+};
+
+G_DEFINE_TYPE_WITH_CODE (GdkDisplayX11, _gdk_display_x11, GDK_TYPE_DISPLAY,
+                         G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
+                                                gdk_display_x11_event_translator_init))
+
+
+static void
+_gdk_display_x11_class_init (GdkDisplayX11Class * class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  
+  object_class->dispose = gdk_display_x11_dispose;
+  object_class->finalize = gdk_display_x11_finalize;
+}
+
+static void
+_gdk_display_x11_init (GdkDisplayX11 *display)
+{
+}
+
+static void
+gdk_display_x11_event_translator_init (GdkEventTranslatorIface *iface)
+{
+  iface->translate_event = gdk_display_x11_translate_event;
+}
+
+static void
+do_net_wm_state_changes (GdkWindow *window)
+{
+  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+  GdkWindowState old_state;
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL)
+    return;
+
+  old_state = gdk_window_get_state (window);
+
+  /* For found_sticky to remain TRUE, we have to also be on desktop
+   * 0xFFFFFFFF
+   */
+  if (old_state & GDK_WINDOW_STATE_STICKY)
+    {
+      if (!(toplevel->have_sticky && toplevel->on_all_desktops))
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_STICKY,
+                                     0);
+    }
+  else
+    {
+      if (toplevel->have_sticky || toplevel->on_all_desktops)
+        gdk_synthesize_window_state (window,
+                                     0,
+                                     GDK_WINDOW_STATE_STICKY);
+    }
+
+  if (old_state & GDK_WINDOW_STATE_FULLSCREEN)
+    {
+      if (!toplevel->have_fullscreen)
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_FULLSCREEN,
+                                     0);
+    }
+  else
+    {
+      if (toplevel->have_fullscreen)
+        gdk_synthesize_window_state (window,
+                                     0,
+                                     GDK_WINDOW_STATE_FULLSCREEN);
+    }
+
+  /* Our "maximized" means both vertical and horizontal; if only one,
+   * we don't expose that via GDK
+   */
+  if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
+    {
+      if (!(toplevel->have_maxvert && toplevel->have_maxhorz))
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_MAXIMIZED,
+                                     0);
+    }
+  else
+    {
+      if (toplevel->have_maxvert && toplevel->have_maxhorz)
+        gdk_synthesize_window_state (window,
+                                     0,
+                                     GDK_WINDOW_STATE_MAXIMIZED);
+    }
+}
+
+static void
+gdk_check_wm_desktop_changed (GdkWindow *window)
+{
+  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  guchar *data;
+  gulong *desktop;
+
+  type = None;
+  gdk_error_trap_push ();
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+                      GDK_WINDOW_XID (window),
+                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
+                      0, G_MAXLONG, False, XA_CARDINAL, &type,
+                      &format, &nitems,
+                      &bytes_after, &data);
+  gdk_error_trap_pop_ignored ();
+
+  if (type != None)
+    {
+      desktop = (gulong *)data;
+      toplevel->on_all_desktops = (*desktop == 0xFFFFFFFF);
+      XFree (desktop);
+    }
+  else
+    toplevel->on_all_desktops = FALSE;
+
+  do_net_wm_state_changes (window);
+}
+
+static void
+gdk_check_wm_state_changed (GdkWindow *window)
+{
+  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  guchar *data;
+  Atom *atoms = NULL;
+  gulong i;
+
+  gboolean had_sticky = toplevel->have_sticky;
+
+  toplevel->have_sticky = FALSE;
+  toplevel->have_maxvert = FALSE;
+  toplevel->have_maxhorz = FALSE;
+  toplevel->have_fullscreen = FALSE;
+
+  type = None;
+  gdk_error_trap_push ();
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+		      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
+		      0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
+		      &bytes_after, &data);
+  gdk_error_trap_pop_ignored ();
+
+  if (type != None)
+    {
+      Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY");
+      Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
+      Atom maxhorz_atom	= gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
+      Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
+
+      atoms = (Atom *)data;
+
+      i = 0;
+      while (i < nitems)
+        {
+          if (atoms[i] == sticky_atom)
+            toplevel->have_sticky = TRUE;
+          else if (atoms[i] == maxvert_atom)
+            toplevel->have_maxvert = TRUE;
+          else if (atoms[i] == maxhorz_atom)
+            toplevel->have_maxhorz = TRUE;
+          else if (atoms[i] == fullscreen_atom)
+            toplevel->have_fullscreen = TRUE;
+
+          ++i;
+        }
+
+      XFree (atoms);
+    }
+
+  /* When have_sticky is turned on, we have to check the DESKTOP property
+   * as well.
+   */
+  if (toplevel->have_sticky && !had_sticky)
+    gdk_check_wm_desktop_changed (window);
+  else
+    do_net_wm_state_changes (window);
+}
+
+static GdkWindow *
+get_event_window (GdkEventTranslator *translator,
+                  XEvent             *xevent)
+{
+  GdkDisplay *display;
+  Window xwindow;
+
+  display = (GdkDisplay *) translator;
+
+  switch (xevent->type)
+    {
+    case DestroyNotify:
+      xwindow = xevent->xdestroywindow.window;
+      break;
+    case UnmapNotify:
+      xwindow = xevent->xunmap.window;
+      break;
+    case MapNotify:
+      xwindow = xevent->xmap.window;
+      break;
+    case ConfigureNotify:
+      xwindow = xevent->xconfigure.window;
+      break;
+    default:
+      xwindow = xevent->xany.window;
+    }
+
+  return gdk_window_lookup_for_display (display, xwindow);
+}
+
+static gboolean
+gdk_display_x11_translate_event (GdkEventTranslator *translator,
+                                 GdkDisplay         *display,
+                                 GdkEvent           *event,
+                                 XEvent             *xevent)
+{
+  GdkWindow *window;
+  GdkWindowObject *window_private;
+  GdkWindowImplX11 *window_impl = NULL;
+  GdkScreen *screen = NULL;
+  GdkScreenX11 *screen_x11 = NULL;
+  GdkToplevelX11 *toplevel = NULL;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  gboolean return_val;
+  Window xwindow = None;
+
+  /* Find the GdkWindow that this event relates to.
+   * Basically this means substructure events
+   * are reported same as structure events
+   */
+  window = get_event_window (translator, xevent);
+  window_private = (GdkWindowObject *) window;
+
+  if (window)
+    {
+      /* We may receive events such as NoExpose/GraphicsExpose
+       * and ShmCompletion for pixmaps
+       */
+      if (!GDK_IS_WINDOW (window))
+        return FALSE;
+
+      screen = GDK_WINDOW_SCREEN (window);
+      screen_x11 = GDK_SCREEN_X11 (screen);
+      toplevel = _gdk_x11_window_get_toplevel (window);
+      window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+      xwindow = GDK_WINDOW_XID (window);
+
+      g_object_ref (window);
+    }
+
+  event->any.window = window;
+  event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
+
+  if (window_private && GDK_WINDOW_DESTROYED (window))
+    {
+      if (xevent->type != DestroyNotify)
+	{
+	  return_val = FALSE;
+	  goto done;
+	}
+    }
+
+  if (xevent->type == DestroyNotify)
+    {
+      int i, n;
+
+      n = gdk_display_get_n_screens (display);
+      for (i = 0; i < n; i++)
+        {
+          screen = gdk_display_get_screen (display, i);
+          screen_x11 = GDK_SCREEN_X11 (screen);
+
+          if (screen_x11->wmspec_check_window == xwindow)
+            {
+              screen_x11->wmspec_check_window = None;
+              screen_x11->last_wmspec_check_time = 0;
+              g_free (screen_x11->window_manager_name);
+              screen_x11->window_manager_name = g_strdup ("unknown");
+
+              /* careful, reentrancy */
+              _gdk_x11_screen_window_manager_changed (screen);
+
+              return_val = FALSE;
+              goto done;
+            }
+        }
+    }
+
+  /* We do a "manual" conversion of the XEvent to a
+   *  GdkEvent. The structures are mostly the same so
+   *  the conversion is fairly straightforward. We also
+   *  optionally print debugging info regarding events
+   *  received.
+   */
+
+  return_val = TRUE;
+
+  switch (xevent->type)
+    {
+    case KeymapNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("keymap notify"));
+
+      /* Not currently handled */
+      return_val = FALSE;
+      break;
+
+    case Expose:
+      GDK_NOTE (EVENTS,
+		g_message ("expose:\t\twindow: %ld  %d	x,y: %d %d  w,h: %d %d%s",
+			   xevent->xexpose.window, xevent->xexpose.count,
+			   xevent->xexpose.x, xevent->xexpose.y,
+			   xevent->xexpose.width, xevent->xexpose.height,
+			   event->any.send_event ? " (send)" : ""));
+
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      {
+	GdkRectangle expose_rect;
+
+	expose_rect.x = xevent->xexpose.x;
+	expose_rect.y = xevent->xexpose.y;
+	expose_rect.width = xevent->xexpose.width;
+	expose_rect.height = xevent->xexpose.height;
+
+        _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
+        return_val = FALSE;
+      }
+
+      break;
+
+    case GraphicsExpose:
+      {
+	GdkRectangle expose_rect;
+
+        GDK_NOTE (EVENTS,
+		  g_message ("graphics expose:\tdrawable: %ld",
+			     xevent->xgraphicsexpose.drawable));
+
+        if (window_private == NULL)
+          {
+            return_val = FALSE;
+            break;
+          }
+
+	expose_rect.x = xevent->xgraphicsexpose.x;
+	expose_rect.y = xevent->xgraphicsexpose.y;
+	expose_rect.width = xevent->xgraphicsexpose.width;
+	expose_rect.height = xevent->xgraphicsexpose.height;
+
+        _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
+        return_val = FALSE;
+      }
+      break;
+
+    case NoExpose:
+      GDK_NOTE (EVENTS,
+		g_message ("no expose:\t\tdrawable: %ld",
+			   xevent->xnoexpose.drawable));
+
+      event->no_expose.type = GDK_NO_EXPOSE;
+      event->no_expose.window = window;
+
+      break;
+
+    case VisibilityNotify:
+#ifdef G_ENABLE_DEBUG
+      if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
+	switch (xevent->xvisibility.state)
+	  {
+	  case VisibilityFullyObscured:
+	    g_message ("visibility notify:\twindow: %ld	 none",
+		       xevent->xvisibility.window);
+	    break;
+	  case VisibilityPartiallyObscured:
+	    g_message ("visibility notify:\twindow: %ld	 partial",
+		       xevent->xvisibility.window);
+	    break;
+	  case VisibilityUnobscured:
+	    g_message ("visibility notify:\twindow: %ld	 full",
+		       xevent->xvisibility.window);
+	    break;
+	  }
+#endif /* G_ENABLE_DEBUG */
+
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      event->visibility.type = GDK_VISIBILITY_NOTIFY;
+      event->visibility.window = window;
+
+      switch (xevent->xvisibility.state)
+	{
+	case VisibilityFullyObscured:
+	  event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
+	  break;
+
+	case VisibilityPartiallyObscured:
+	  event->visibility.state = GDK_VISIBILITY_PARTIAL;
+	  break;
+
+	case VisibilityUnobscured:
+	  event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
+	  break;
+	}
+
+      break;
+
+    case CreateNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("create notify:\twindow: %ld  x,y: %d %d	w,h: %d %d  b-w: %d  parent: %ld	 ovr: %d",
+			   xevent->xcreatewindow.window,
+			   xevent->xcreatewindow.x,
+			   xevent->xcreatewindow.y,
+			   xevent->xcreatewindow.width,
+			   xevent->xcreatewindow.height,
+			   xevent->xcreatewindow.border_width,
+			   xevent->xcreatewindow.parent,
+			   xevent->xcreatewindow.override_redirect));
+      /* not really handled */
+      break;
+
+    case DestroyNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("destroy notify:\twindow: %ld",
+			   xevent->xdestroywindow.window));
+
+      /* Ignore DestroyNotify from SubstructureNotifyMask */
+      if (xevent->xdestroywindow.window == xevent->xdestroywindow.event)
+	{
+	  event->any.type = GDK_DESTROY;
+	  event->any.window = window;
+
+	  return_val = window_private && !GDK_WINDOW_DESTROYED (window);
+
+	  if (window && GDK_WINDOW_XID (window) != screen_x11->xroot_window)
+	    gdk_window_destroy_notify (window);
+	}
+      else
+	return_val = FALSE;
+
+      break;
+
+    case UnmapNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("unmap notify:\t\twindow: %ld",
+			   xevent->xmap.window));
+
+      event->any.type = GDK_UNMAP;
+      event->any.window = window;
+
+      /* If we are shown (not withdrawn) and get an unmap, it means we
+       * were iconified in the X sense. If we are withdrawn, and get
+       * an unmap, it means we hid the window ourselves, so we
+       * will have already flipped the iconified bit off.
+       */
+      if (window)
+	{
+	  if (GDK_WINDOW_IS_MAPPED (window))
+	    gdk_synthesize_window_state (window,
+					 0,
+					 GDK_WINDOW_STATE_ICONIFIED);
+
+	  _gdk_xgrab_check_unmap (window, xevent->xany.serial);
+	}
+
+      break;
+
+    case MapNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("map notify:\t\twindow: %ld",
+			   xevent->xmap.window));
+
+      event->any.type = GDK_MAP;
+      event->any.window = window;
+
+      /* Unset iconified if it was set */
+      if (window && (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED))
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_ICONIFIED,
+                                     0);
+
+      break;
+
+    case ReparentNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld	ovr: %d",
+			   xevent->xreparent.window,
+			   xevent->xreparent.x,
+			   xevent->xreparent.y,
+			   xevent->xreparent.parent,
+			   xevent->xreparent.override_redirect));
+
+      /* Not currently handled */
+      return_val = FALSE;
+      break;
+
+    case ConfigureNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("configure notify:\twindow: %ld  x,y: %d %d	w,h: %d %d  b-w: %d  above: %ld	 ovr: %d%s",
+			   xevent->xconfigure.window,
+			   xevent->xconfigure.x,
+			   xevent->xconfigure.y,
+			   xevent->xconfigure.width,
+			   xevent->xconfigure.height,
+			   xevent->xconfigure.border_width,
+			   xevent->xconfigure.above,
+			   xevent->xconfigure.override_redirect,
+			   !window
+			   ? " (discarding)"
+			   : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
+			   ? " (discarding child)"
+			   : xevent->xconfigure.event != xevent->xconfigure.window
+			   ? " (discarding substructure)"
+			   : ""));
+      if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
+        {
+	  window_private->width = xevent->xconfigure.width;
+	  window_private->height = xevent->xconfigure.height;
+
+	  _gdk_window_update_size (window);
+	  _gdk_x11_drawable_update_size (window_private->impl);
+	  _gdk_x11_screen_size_changed (screen, xevent);
+        }
+
+#ifdef HAVE_XSYNC
+      if (toplevel && display_x11->use_sync && !XSyncValueIsZero (toplevel->pending_counter_value))
+	{
+	  toplevel->current_counter_value = toplevel->pending_counter_value;
+	  XSyncIntToValue (&toplevel->pending_counter_value, 0);
+	}
+#endif
+
+    if (!window ||
+	  xevent->xconfigure.event != xevent->xconfigure.window ||
+          GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
+          GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
+	return_val = FALSE;
+      else
+	{
+	  event->configure.type = GDK_CONFIGURE;
+	  event->configure.window = window;
+	  event->configure.width = xevent->xconfigure.width;
+	  event->configure.height = xevent->xconfigure.height;
+
+	  if (!xevent->xconfigure.send_event &&
+	      !xevent->xconfigure.override_redirect &&
+	      !GDK_WINDOW_DESTROYED (window))
+	    {
+	      gint tx = 0;
+	      gint ty = 0;
+	      Window child_window = 0;
+
+	      gdk_error_trap_push ();
+	      if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
+					 GDK_DRAWABLE_XID (window),
+					 screen_x11->xroot_window,
+					 0, 0,
+					 &tx, &ty,
+					 &child_window))
+		{
+		  event->configure.x = tx;
+		  event->configure.y = ty;
+		}
+	      gdk_error_trap_pop_ignored ();
+	    }
+	  else
+	    {
+	      event->configure.x = xevent->xconfigure.x;
+	      event->configure.y = xevent->xconfigure.y;
+	    }
+	  window_private->x = event->configure.x;
+	  window_private->y = event->configure.y;
+	  window_private->width = xevent->xconfigure.width;
+	  window_private->height = xevent->xconfigure.height;
+
+	  _gdk_window_update_size (window);
+	  _gdk_x11_drawable_update_size (window_private->impl);
+
+	  if (window_private->resize_count >= 1)
+	    {
+	      window_private->resize_count -= 1;
+
+	      if (window_private->resize_count == 0)
+		_gdk_moveresize_configure_done (display, window);
+	    }
+	}
+      break;
+
+    case PropertyNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
+			   xevent->xproperty.window,
+			   xevent->xproperty.atom,
+			   "\"",
+			   gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom),
+			   "\""));
+
+      if (window_private == NULL)
+        {
+	  return_val = FALSE;
+          break;
+        }
+
+      /* We compare with the serial of the last time we mapped the
+       * window to avoid refetching properties that we set ourselves
+       */
+      if (toplevel &&
+	  xevent->xproperty.serial >= toplevel->map_serial)
+	{
+	  if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"))
+	    gdk_check_wm_state_changed (window);
+
+	  if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
+	    gdk_check_wm_desktop_changed (window);
+	}
+
+      if (window_private->event_mask & GDK_PROPERTY_CHANGE_MASK)
+	{
+	  event->property.type = GDK_PROPERTY_NOTIFY;
+	  event->property.window = window;
+	  event->property.atom = gdk_x11_xatom_to_atom_for_display (display, xevent->xproperty.atom);
+	  event->property.time = xevent->xproperty.time;
+	  event->property.state = xevent->xproperty.state;
+	}
+      else
+	return_val = FALSE;
+
+      break;
+
+    case SelectionClear:
+      GDK_NOTE (EVENTS,
+		g_message ("selection clear:\twindow: %ld",
+			   xevent->xproperty.window));
+
+      if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
+	{
+	  event->selection.type = GDK_SELECTION_CLEAR;
+	  event->selection.window = window;
+	  event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionclear.selection);
+	  event->selection.time = xevent->xselectionclear.time;
+	}
+      else
+	return_val = FALSE;
+
+      break;
+
+    case SelectionRequest:
+      GDK_NOTE (EVENTS,
+		g_message ("selection request:\twindow: %ld",
+			   xevent->xproperty.window));
+
+      event->selection.type = GDK_SELECTION_REQUEST;
+      event->selection.window = window;
+      event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection);
+      event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.target);
+      event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.property);
+      event->selection.requestor = xevent->xselectionrequest.requestor;
+      event->selection.time = xevent->xselectionrequest.time;
+
+      break;
+
+    case SelectionNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("selection notify:\twindow: %ld",
+			   xevent->xproperty.window));
+
+      event->selection.type = GDK_SELECTION_NOTIFY;
+      event->selection.window = window;
+      event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.selection);
+      event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.target);
+      if (xevent->xselection.property == None)
+        event->selection.property = GDK_NONE;
+      else
+        event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
+      event->selection.time = xevent->xselection.time;
+
+      break;
+
+    case ColormapNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("colormap notify:\twindow: %ld",
+			   xevent->xcolormap.window));
+
+      /* Not currently handled */
+      return_val = FALSE;
+      break;
+
+    case ClientMessage:
+      {
+	GList *tmp_list;
+	GdkFilterReturn result = GDK_FILTER_CONTINUE;
+	GdkAtom message_type = gdk_x11_xatom_to_atom_for_display (display, xevent->xclient.message_type);
+
+	GDK_NOTE (EVENTS,
+		  g_message ("client message:\twindow: %ld",
+			     xevent->xclient.window));
+
+	tmp_list = display_x11->client_filters;
+	while (tmp_list)
+	  {
+	    GdkClientFilter *filter = tmp_list->data;
+	    tmp_list = tmp_list->next;
+
+	    if (filter->type == message_type)
+	      {
+		result = (*filter->function) (xevent, event, filter->data);
+		if (result != GDK_FILTER_CONTINUE)
+		  break;
+	      }
+	  }
+
+	switch (result)
+	  {
+	  case GDK_FILTER_REMOVE:
+	    return_val = FALSE;
+	    break;
+	  case GDK_FILTER_TRANSLATE:
+	    return_val = TRUE;
+	    break;
+	  case GDK_FILTER_CONTINUE:
+	    /* Send unknown ClientMessage's on to Gtk for it to use */
+            if (window_private == NULL)
+              {
+                return_val = FALSE;
+              }
+            else
+              {
+                event->client.type = GDK_CLIENT_EVENT;
+                event->client.window = window;
+                event->client.message_type = message_type;
+                event->client.data_format = xevent->xclient.format;
+                memcpy(&event->client.data, &xevent->xclient.data,
+                       sizeof(event->client.data));
+              }
+            break;
+          }
+      }
+
+      break;
+
+    case MappingNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("mapping notify"));
+
+      /* Let XLib know that there is a new keyboard mapping.
+       */
+      XRefreshKeyboardMapping (&xevent->xmapping);
+      _gdk_keymap_keys_changed (display);
+      return_val = FALSE;
+      break;
+
+    default:
+#ifdef HAVE_XFIXES
+      if (xevent->type - display_x11->xfixes_event_base == XFixesSelectionNotify)
+	{
+	  XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)xevent;
+
+	  _gdk_x11_screen_process_owner_change (screen, xevent);
+	  
+	  event->owner_change.type = GDK_OWNER_CHANGE;
+	  event->owner_change.window = window;
+	  event->owner_change.owner = selection_notify->owner;
+	  event->owner_change.reason = selection_notify->subtype;
+	  event->owner_change.selection = 
+	    gdk_x11_xatom_to_atom_for_display (display, 
+					       selection_notify->selection);
+	  event->owner_change.time = selection_notify->timestamp;
+	  event->owner_change.selection_time = selection_notify->selection_timestamp;
+	  
+	  return_val = TRUE;
+	}
+      else
+#endif
+#ifdef HAVE_RANDR
+      if (xevent->type - display_x11->xrandr_event_base == RRScreenChangeNotify ||
+          xevent->type - display_x11->xrandr_event_base == RRNotify)
+	{
+          if (screen)
+            _gdk_x11_screen_size_changed (screen, xevent);
+	}
+      else
+#endif
+#if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+      if (display_x11->have_xdamage && window_private && window_private->composited &&
+	  xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
+	  ((XDamageNotifyEvent *) xevent)->damage == window_impl->damage)
+	{
+	  XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent;
+	  XserverRegion repair;
+	  GdkRectangle rect;
+
+	  rect.x = window_private->x + damage_event->area.x;
+	  rect.y = window_private->y + damage_event->area.y;
+	  rect.width = damage_event->area.width;
+	  rect.height = damage_event->area.height;
+
+	  repair = XFixesCreateRegion (display_x11->xdisplay,
+				       &damage_event->area, 1);
+	  XDamageSubtract (display_x11->xdisplay,
+			   window_impl->damage,
+			   repair, None);
+	  XFixesDestroyRegion (display_x11->xdisplay, repair);
+
+	  if (window_private->parent != NULL)
+	    _gdk_window_process_expose (GDK_WINDOW (window_private->parent),
+					damage_event->serial, &rect);
+
+	  return_val = TRUE;
+	}
+      else
+#endif
+#ifdef HAVE_XKB
+      if (xevent->type == display_x11->xkb_event_type)
+	{
+	  XkbEvent *xkb_event = (XkbEvent *) xevent;
+
+	  switch (xkb_event->any.xkb_type)
+	    {
+	    case XkbNewKeyboardNotify:
+	    case XkbMapNotify:
+	      _gdk_keymap_keys_changed (display);
+
+	      return_val = FALSE;
+	      break;
+
+	    case XkbStateNotify:
+	      _gdk_keymap_state_changed (display, xevent);
+	      break;
+	    }
+	}
+      else
+#endif
+        return_val = FALSE;
+    }
+
+ done:
+  if (return_val)
+    {
+      if (event->any.window)
+	g_object_ref (event->any.window);
+    }
+  else
+    {
+      /* Mark this event as having no resources to be freed */
+      event->any.window = NULL;
+      event->any.type = GDK_NOTHING;
+    }
+
+  if (window)
+    g_object_unref (window);
+
+  return return_val;
+}
+
+static GdkFilterReturn
+gdk_wm_protocols_filter (GdkXEvent *xev,
+			 GdkEvent  *event,
+			 gpointer data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  GdkWindow *win = event->any.window;
+  GdkDisplay *display;
+  Atom atom;
+
+  if (!win)
+      return GDK_FILTER_REMOVE;
+
+  display = GDK_WINDOW_DISPLAY (win);
+  atom = (Atom)xevent->xclient.data.l[0];
+
+  if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
+    {
+  /* The delete window request specifies a window
+   *  to delete. We don't actually destroy the
+   *  window because "it is only a request". (The
+   *  window might contain vital data that the
+   *  program does not want destroyed). Instead
+   *  the event is passed along to the program,
+   *  which should then destroy the window.
+   */
+      GDK_NOTE (EVENTS,
+		g_message ("delete window:\t\twindow: %ld",
+			   xevent->xclient.window));
+
+      event->any.type = GDK_DELETE;
+
+      gdk_x11_window_set_user_time (win, xevent->xclient.data.l[1]);
+
+      return GDK_FILTER_TRANSLATE;
+    }
+  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
+    {
+      GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
+      GdkWindowObject *private = (GdkWindowObject *)win;
+
+      /* There is no way of knowing reliably whether we are viewable;
+       * _gdk_x11_set_input_focus_safe() traps errors asynchronously.
+       */
+      if (toplevel && private->accept_focus)
+	_gdk_x11_set_input_focus_safe (display, toplevel->focus_window,
+				       RevertToParent,
+				       xevent->xclient.data.l[1]);
+
+      return GDK_FILTER_REMOVE;
+    }
+  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING") &&
+	   !_gdk_x11_display_is_root_window (display,
+					     xevent->xclient.window))
+    {
+      XClientMessageEvent xclient = xevent->xclient;
+
+      xclient.window = GDK_WINDOW_XROOTWIN (win);
+      XSendEvent (GDK_WINDOW_XDISPLAY (win),
+		  xclient.window,
+		  False,
+		  SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
+
+      return GDK_FILTER_REMOVE;
+    }
+  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST") &&
+	   GDK_DISPLAY_X11 (display)->use_sync)
+    {
+      GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
+      if (toplevel)
+	{
+#ifdef HAVE_XSYNC
+	  XSyncIntsToValue (&toplevel->pending_counter_value,
+			    xevent->xclient.data.l[2],
+			    xevent->xclient.data.l[3]);
+#endif
+	}
+      return GDK_FILTER_REMOVE;
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+_gdk_event_init (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11;
+  GdkDeviceManager *device_manager;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+  display_x11->event_source = gdk_event_source_new (display);
+
+  gdk_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
+                                   GDK_EVENT_TRANSLATOR (display));
+
+  device_manager = gdk_display_get_device_manager (display);
+  gdk_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
+                                   GDK_EVENT_TRANSLATOR (device_manager));
+
+  gdk_display_add_client_message_filter (display,
+					 gdk_atom_intern_static_string ("WM_PROTOCOLS"),
+					 gdk_wm_protocols_filter,
+					 NULL);
+}
+
+static void
+_gdk_input_init (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11;
+  GdkDeviceManager *device_manager;
+  GdkDevice *device;
+  GList *list, *l;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+  device_manager = gdk_display_get_device_manager (display);
+
+  /* For backwards compatibility, just add
+   * floating devices that are not keyboards.
+   */
+  list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING);
+
+  for (l = list; l; l = l->next)
+    {
+      device = l->data;
+
+      if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
+        continue;
+
+      display_x11->input_devices = g_list_prepend (display_x11->input_devices,
+                                                   g_object_ref (l->data));
+    }
+
+  g_list_free (list);
+
+  /* Now set "core" pointer to the first
+   * master device that is a pointer.
+   */
+  list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+  for (l = list; l; l = l->next)
+    {
+      device = list->data;
+
+      if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
+        continue;
+
+      display->core_pointer = device;
+      break;
+    }
+
+  /* Add the core pointer to the devices list */
+  display_x11->input_devices = g_list_prepend (display_x11->input_devices,
+                                               g_object_ref (display->core_pointer));
+
+  g_list_free (list);
+}
+
+/**
+ * gdk_display_open:
+ * @display_name: the name of the display to open
+ * @returns: a #GdkDisplay, or %NULL if the display
+ *  could not be opened.
+ *
+ * Opens a display.
+ *
+ * Since: 2.2
+ */
+GdkDisplay *
+gdk_display_open (const gchar *display_name)
+{
+  Display *xdisplay;
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+  GdkWindowAttr attr;
+  gint argc;
+  gchar *argv[1];
+  const char *sm_client_id;
+  
+  XClassHint *class_hint;
+  gulong pid;
+  gint i;
+  gint ignore;
+  gint maj, min;
+
+  xdisplay = XOpenDisplay (display_name);
+  if (!xdisplay)
+    return NULL;
+  
+  display = g_object_new (GDK_TYPE_DISPLAY_X11, NULL);
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  display_x11->xdisplay = xdisplay;
+
+#ifdef HAVE_X11R6  
+  /* Set up handlers for Xlib internal connections */
+  XAddConnectionWatch (xdisplay, gdk_internal_connection_watch, NULL);
+#endif /* HAVE_X11R6 */
+  
+  _gdk_x11_precache_atoms (display, precache_atoms, G_N_ELEMENTS (precache_atoms));
+
+  /* RandR must be initialized before we initialize the screens */
+  display_x11->have_randr13 = FALSE;
+#ifdef HAVE_RANDR
+  if (XRRQueryExtension (display_x11->xdisplay,
+			 &display_x11->xrandr_event_base, &ignore))
+  {
+      int major, minor;
+      
+      XRRQueryVersion (display_x11->xdisplay, &major, &minor);
+
+      if ((major == 1 && minor >= 3) || major > 1)
+	  display_x11->have_randr13 = TRUE;
+
+       gdk_x11_register_standard_event_type (display, display_x11->xrandr_event_base, RRNumberEvents);
+  }
+#endif
+  
+  /* initialize the display's screens */ 
+  display_x11->screens = g_new (GdkScreen *, ScreenCount (display_x11->xdisplay));
+  for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
+    display_x11->screens[i] = _gdk_x11_screen_new (display, i);
+
+  /* We need to initialize events after we have the screen
+   * structures in places
+   */
+  for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
+    _gdk_screen_x11_events_init (display_x11->screens[i]);
+
+  /*set the default screen */
+  display_x11->default_screen = display_x11->screens[DefaultScreen (display_x11->xdisplay)];
+
+  display->device_manager = _gdk_device_manager_new (display);
+
+  _gdk_event_init (display);
+
+  attr.window_type = GDK_WINDOW_TOPLEVEL;
+  attr.wclass = GDK_INPUT_OUTPUT;
+  attr.x = 10;
+  attr.y = 10;
+  attr.width = 10;
+  attr.height = 10;
+  attr.event_mask = 0;
+
+  display_x11->leader_gdk_window = gdk_window_new (GDK_SCREEN_X11 (display_x11->default_screen)->root_window, 
+						   &attr, GDK_WA_X | GDK_WA_Y);
+  (_gdk_x11_window_get_toplevel (display_x11->leader_gdk_window))->is_leader = TRUE;
+
+  display_x11->leader_window = GDK_WINDOW_XID (display_x11->leader_gdk_window);
+
+  display_x11->leader_window_title_set = FALSE;
+
+#ifdef HAVE_XFIXES
+  if (XFixesQueryExtension (display_x11->xdisplay, 
+			    &display_x11->xfixes_event_base, 
+			    &ignore))
+    {
+      display_x11->have_xfixes = TRUE;
+
+      gdk_x11_register_standard_event_type (display,
+					    display_x11->xfixes_event_base, 
+					    XFixesNumberEvents);
+    }
+  else
+#endif
+    display_x11->have_xfixes = FALSE;
+
+#ifdef HAVE_XCOMPOSITE
+  if (XCompositeQueryExtension (display_x11->xdisplay,
+				&ignore, &ignore))
+    {
+      int major, minor;
+
+      XCompositeQueryVersion (display_x11->xdisplay, &major, &minor);
+
+      /* Prior to Composite version 0.4, composited windows clipped their
+       * parents, so you had to use IncludeInferiors to draw to the parent
+       * This isn't useful for our purposes, so require 0.4
+       */
+      display_x11->have_xcomposite = major > 0 || (major == 0 && minor >= 4);
+    }
+  else
+#endif
+    display_x11->have_xcomposite = FALSE;
+
+#ifdef HAVE_XDAMAGE
+  if (XDamageQueryExtension (display_x11->xdisplay,
+			     &display_x11->xdamage_event_base,
+			     &ignore))
+    {
+      display_x11->have_xdamage = TRUE;
+
+      gdk_x11_register_standard_event_type (display,
+					    display_x11->xdamage_event_base,
+					    XDamageNumberEvents);
+    }
+  else
+#endif
+    display_x11->have_xdamage = FALSE;
+
+  display_x11->have_shapes = FALSE;
+  display_x11->have_input_shapes = FALSE;
+
+  if (XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), &display_x11->shape_event_base, &ignore))
+    {
+      display_x11->have_shapes = TRUE;
+#ifdef ShapeInput
+      if (XShapeQueryVersion (GDK_DISPLAY_XDISPLAY (display), &maj, &min))
+	display_x11->have_input_shapes = (maj == 1 && min >= 1);
+#endif
+    }
+
+  display_x11->trusted_client = TRUE;
+  {
+    Window root, child;
+    int rootx, rooty, winx, winy;
+    unsigned int xmask;
+
+    gdk_error_trap_push ();
+    XQueryPointer (display_x11->xdisplay, 
+		   GDK_SCREEN_X11 (display_x11->default_screen)->xroot_window,
+		   &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+    if (G_UNLIKELY (gdk_error_trap_pop () == BadWindow)) 
+      {
+	g_warning ("Connection to display %s appears to be untrusted. Pointer and keyboard grabs and inter-client communication may not work as expected.", gdk_display_get_name (display));
+	display_x11->trusted_client = FALSE;
+      }
+  }
+
+  if (_gdk_synchronize)
+    XSynchronize (display_x11->xdisplay, True);
+  
+  class_hint = XAllocClassHint();
+  class_hint->res_name = g_get_prgname ();
+  
+  class_hint->res_class = (char *)gdk_get_program_class ();
+
+  /* XmbSetWMProperties sets the RESOURCE_NAME environment variable
+   * from argv[0], so we just synthesize an argument array here.
+   */
+  argc = 1;
+  argv[0] = g_get_prgname ();
+  
+  XmbSetWMProperties (display_x11->xdisplay,
+		      display_x11->leader_window,
+		      NULL, NULL, argv, argc, NULL, NULL,
+		      class_hint);
+  XFree (class_hint);
+
+  sm_client_id = _gdk_get_sm_client_id ();
+  if (sm_client_id)
+    _gdk_windowing_display_set_sm_client_id (display, sm_client_id);
+
+  pid = getpid ();
+  XChangeProperty (display_x11->xdisplay,
+		   display_x11->leader_window,
+		   gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"),
+		   XA_CARDINAL, 32, PropModeReplace, (guchar *) & pid, 1);
+
+  /* We don't yet know a valid time. */
+  display_x11->user_time = 0;
+  
+#ifdef HAVE_XKB
+  {
+    gint xkb_major = XkbMajorVersion;
+    gint xkb_minor = XkbMinorVersion;
+    if (XkbLibraryVersion (&xkb_major, &xkb_minor))
+      {
+        xkb_major = XkbMajorVersion;
+        xkb_minor = XkbMinorVersion;
+	    
+        if (XkbQueryExtension (display_x11->xdisplay, 
+			       NULL, &display_x11->xkb_event_type, NULL,
+                               &xkb_major, &xkb_minor))
+          {
+	    Bool detectable_autorepeat_supported;
+	    
+	    display_x11->use_xkb = TRUE;
+
+            XkbSelectEvents (display_x11->xdisplay,
+                             XkbUseCoreKbd,
+                             XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
+                             XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
+
+	    /* keep this in sync with _gdk_keymap_state_changed() */ 
+	    XkbSelectEventDetails (display_x11->xdisplay,
+				   XkbUseCoreKbd, XkbStateNotify,
+				   XkbAllStateComponentsMask,
+                                   XkbGroupLockMask|XkbModifierLockMask);
+
+	    XkbSetDetectableAutoRepeat (display_x11->xdisplay,
+					True,
+					&detectable_autorepeat_supported);
+
+	    GDK_NOTE (MISC, g_message ("Detectable autorepeat %s.",
+				       detectable_autorepeat_supported ? 
+				       "supported" : "not supported"));
+	    
+	    display_x11->have_xkb_autorepeat = detectable_autorepeat_supported;
+          }
+      }
+  }
+#endif
+
+  display_x11->use_sync = FALSE;
+#ifdef HAVE_XSYNC
+  {
+    int major, minor;
+    int error_base, event_base;
+    
+    if (XSyncQueryExtension (display_x11->xdisplay,
+			     &event_base, &error_base) &&
+        XSyncInitialize (display_x11->xdisplay,
+                         &major, &minor))
+      display_x11->use_sync = TRUE;
+  }
+#endif
+
+  _gdk_input_init (display);
+  _gdk_dnd_init (display);
+
+  for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
+    _gdk_x11_screen_setup (display_x11->screens[i]);
+
+  g_signal_emit_by_name (display, "opened");
+  g_signal_emit_by_name (gdk_display_manager_get (), "display-opened", display);
+
+  return display;
+}
+
+#ifdef HAVE_X11R6
+/*
+ * XLib internal connection handling
+ */
+typedef struct _GdkInternalConnection GdkInternalConnection;
+
+struct _GdkInternalConnection
+{
+  gint	         fd;
+  GSource	*source;
+  Display	*display;
+};
+
+static gboolean
+process_internal_connection (GIOChannel  *gioc,
+			     GIOCondition cond,
+			     gpointer     data)
+{
+  GdkInternalConnection *connection = (GdkInternalConnection *)data;
+
+  GDK_THREADS_ENTER ();
+
+  XProcessInternalConnection ((Display*)connection->display, connection->fd);
+
+  GDK_THREADS_LEAVE ();
+
+  return TRUE;
+}
+
+gulong
+_gdk_windowing_window_get_next_serial (GdkDisplay *display)
+{
+  return NextRequest (GDK_DISPLAY_XDISPLAY (display));
+}
+
+
+static GdkInternalConnection *
+gdk_add_connection_handler (Display *display,
+			    guint    fd)
+{
+  GIOChannel *io_channel;
+  GdkInternalConnection *connection;
+
+  connection = g_new (GdkInternalConnection, 1);
+
+  connection->fd = fd;
+  connection->display = display;
+  
+  io_channel = g_io_channel_unix_new (fd);
+  
+  connection->source = g_io_create_watch (io_channel, G_IO_IN);
+  g_source_set_callback (connection->source,
+			 (GSourceFunc)process_internal_connection, connection, NULL);
+  g_source_attach (connection->source, NULL);
+  
+  g_io_channel_unref (io_channel);
+  
+  return connection;
+}
+
+static void
+gdk_remove_connection_handler (GdkInternalConnection *connection)
+{
+  g_source_destroy (connection->source);
+  g_free (connection);
+}
+
+static void
+gdk_internal_connection_watch (Display  *display,
+			       XPointer  arg,
+			       gint      fd,
+			       gboolean  opening,
+			       XPointer *watch_data)
+{
+  if (opening)
+    *watch_data = (XPointer)gdk_add_connection_handler (display, fd);
+  else
+    gdk_remove_connection_handler ((GdkInternalConnection *)*watch_data);
+}
+#endif /* HAVE_X11R6 */
+
+/**
+ * gdk_display_get_name:
+ * @display: a #GdkDisplay
+ *
+ * Gets the name of the display.
+ * 
+ * Returns: a string representing the display name. This string is owned
+ * by GDK and should not be modified or freed.
+ * 
+ * Since: 2.2
+ */
+G_CONST_RETURN gchar *
+gdk_display_get_name (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  
+  return (gchar *) DisplayString (GDK_DISPLAY_X11 (display)->xdisplay);
+}
+
+/**
+ * gdk_display_get_n_screens:
+ * @display: a #GdkDisplay
+ *
+ * Gets the number of screen managed by the @display.
+ * 
+ * Returns: number of screens.
+ * 
+ * Since: 2.2
+ */
+gint
+gdk_display_get_n_screens (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
+  
+  return ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay);
+}
+
+/**
+ * gdk_display_get_screen:
+ * @display: a #GdkDisplay
+ * @screen_num: the screen number
+ *
+ * Returns a screen object for one of the screens of the display.
+ *
+ * Returns: the #GdkScreen object
+ *
+ * Since: 2.2
+ */
+GdkScreen *
+gdk_display_get_screen (GdkDisplay *display, 
+			gint        screen_num)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay) > screen_num, NULL);
+  
+  return GDK_DISPLAY_X11 (display)->screens[screen_num];
+}
+
+/**
+ * gdk_display_get_default_screen:
+ * @display: a #GdkDisplay
+ *
+ * Get the default #GdkScreen for @display.
+ * 
+ * Returns: the default #GdkScreen object for @display
+ *
+ * Since: 2.2
+ */
+GdkScreen *
+gdk_display_get_default_screen (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  
+  return GDK_DISPLAY_X11 (display)->default_screen;
+}
+
+gboolean
+_gdk_x11_display_is_root_window (GdkDisplay *display,
+				 Window      xroot_window)
+{
+  GdkDisplayX11 *display_x11;
+  gint i;
+  
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+  
+  display_x11 = GDK_DISPLAY_X11 (display);
+  
+  for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
+    {
+      if (GDK_SCREEN_XROOTWIN (display_x11->screens[i]) == xroot_window)
+	return TRUE;
+    }
+  return FALSE;
+}
+
+struct XPointerUngrabInfo {
+  GdkDisplay *display;
+  guint32 time;
+};
+
+static void
+device_ungrab_callback (GdkDisplay *display,
+                        gpointer    data,
+                        gulong      serial)
+{
+  GdkDevice *device = data;
+
+  _gdk_display_device_grab_update (display, device, serial);
+}
+
+
+#define XSERVER_TIME_IS_LATER(time1, time2)                        \
+  ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) ||  \
+    (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 ))     \
+  )
+
+/**
+ * gdk_device_ungrab:
+ * @device: a #GdkDevice
+ * @time_: a timestap (e.g. %GDK_CURRENT_TIME).
+ *
+ * Release any grab on @device.
+ *
+ * Since: 3.0
+ */
+void
+gdk_device_ungrab (GdkDevice  *device,
+                   guint32     time_)
+{
+  GdkDisplay *display;
+  Display *xdisplay;
+  GdkDeviceGrabInfo *grab;
+  unsigned long serial;
+
+  g_return_if_fail (GDK_IS_DEVICE (device));
+
+  display = gdk_device_get_display (device);
+  xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+  serial = NextRequest (xdisplay);
+
+  GDK_DEVICE_GET_CLASS (device)->ungrab (device, time_);
+  XFlush (xdisplay);
+
+  grab = _gdk_display_get_last_device_grab (display, device);
+  if (grab &&
+      (time_ == GDK_CURRENT_TIME ||
+       grab->time == GDK_CURRENT_TIME ||
+       !XSERVER_TIME_IS_LATER (grab->time, time_)))
+    {
+      grab->serial_end = serial;
+      _gdk_x11_roundtrip_async (display,
+				device_ungrab_callback,
+				device);
+    }
+}
+
+/**
+ * gdk_display_beep:
+ * @display: a #GdkDisplay
+ *
+ * Emits a short beep on @display
+ *
+ * Since: 2.2
+ */
+void
+gdk_display_beep (GdkDisplay *display)
+{
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+
+#ifdef HAVE_XKB
+  XkbBell (GDK_DISPLAY_XDISPLAY (display), None, 0, None);
+#else
+  XBell (GDK_DISPLAY_XDISPLAY (display), 0);
+#endif
+}
+
+/**
+ * gdk_display_sync:
+ * @display: a #GdkDisplay
+ *
+ * Flushes any requests queued for the windowing system and waits until all
+ * requests have been handled. This is often used for making sure that the
+ * display is synchronized with the current state of the program. Calling
+ * gdk_display_sync() before gdk_error_trap_pop() makes sure that any errors
+ * generated from earlier requests are handled before the error trap is 
+ * removed.
+ *
+ * This is most useful for X11. On windowing systems where requests are
+ * handled synchronously, this function will do nothing.
+ *
+ * Since: 2.2
+ */
+void
+gdk_display_sync (GdkDisplay *display)
+{
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+  
+  XSync (GDK_DISPLAY_XDISPLAY (display), False);
+}
+
+/**
+ * gdk_display_flush:
+ * @display: a #GdkDisplay
+ *
+ * Flushes any requests queued for the windowing system; this happens automatically
+ * when the main loop blocks waiting for new events, but if your application
+ * is drawing without returning control to the main loop, you may need
+ * to call this function explicitely. A common case where this function
+ * needs to be called is when an application is executing drawing commands
+ * from a thread other than the thread where the main loop is running.
+ *
+ * This is most useful for X11. On windowing systems where requests are
+ * handled synchronously, this function will do nothing.
+ *
+ * Since: 2.4
+ */
+void 
+gdk_display_flush (GdkDisplay *display)
+{
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+
+  if (!display->closed)
+    XFlush (GDK_DISPLAY_XDISPLAY (display));
+}
+
+/**
+ * gdk_display_get_default_group:
+ * @display: a #GdkDisplay
+ * 
+ * Returns the default group leader window for all toplevel windows
+ * on @display. This window is implicitly created by GDK. 
+ * See gdk_window_set_group().
+ * 
+ * Return value: The default group leader window for @display
+ *
+ * Since: 2.4
+ **/
+GdkWindow *
+gdk_display_get_default_group (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+  return GDK_DISPLAY_X11 (display)->leader_gdk_window;
+}
+
+/**
+ * gdk_x11_display_grab:
+ * @display: a #GdkDisplay 
+ * 
+ * Call XGrabServer() on @display. 
+ * To ungrab the display again, use gdk_x11_display_ungrab(). 
+ *
+ * gdk_x11_display_grab()/gdk_x11_display_ungrab() calls can be nested.
+ *
+ * Since: 2.2
+ **/
+void
+gdk_x11_display_grab (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11;
+  
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+  
+  display_x11 = GDK_DISPLAY_X11 (display);
+  
+  if (display_x11->grab_count == 0)
+    XGrabServer (display_x11->xdisplay);
+  display_x11->grab_count++;
+}
+
+/**
+ * gdk_x11_display_ungrab:
+ * @display: a #GdkDisplay
+ * 
+ * Ungrab @display after it has been grabbed with 
+ * gdk_x11_display_grab(). 
+ *
+ * Since: 2.2
+ **/
+void
+gdk_x11_display_ungrab (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11;
+  
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+  
+  display_x11 = GDK_DISPLAY_X11 (display);;
+  g_return_if_fail (display_x11->grab_count > 0);
+  
+  display_x11->grab_count--;
+  if (display_x11->grab_count == 0)
+    {
+      XUngrabServer (display_x11->xdisplay);
+      XFlush (display_x11->xdisplay);
+    }
+}
+
+static void
+gdk_display_x11_dispose (GObject *object)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (object);
+  gint           i;
+
+  g_list_foreach (display_x11->input_devices, (GFunc) g_object_run_dispose, NULL);
+
+  for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
+    _gdk_screen_close (display_x11->screens[i]);
+
+  if (display_x11->event_source)
+    {
+      g_source_destroy (display_x11->event_source);
+      g_source_unref (display_x11->event_source);
+      display_x11->event_source = NULL;
+    }
+
+  G_OBJECT_CLASS (_gdk_display_x11_parent_class)->dispose (object);
+}
+
+static void
+gdk_display_x11_finalize (GObject *object)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (object);
+  gint           i;
+
+  /* Keymap */
+  if (display_x11->keymap)
+    g_object_unref (display_x11->keymap);
+
+  /* Free motif Dnd */
+  if (display_x11->motif_target_lists)
+    {
+      for (i = 0; i < display_x11->motif_n_target_lists; i++)
+        g_list_free (display_x11->motif_target_lists[i]);
+      g_free (display_x11->motif_target_lists);
+    }
+
+  _gdk_x11_cursor_display_finalize (GDK_DISPLAY_OBJECT(display_x11));
+
+  /* Atom Hashtable */
+  g_hash_table_destroy (display_x11->atom_from_virtual);
+  g_hash_table_destroy (display_x11->atom_to_virtual);
+
+  /* Leader Window */
+  XDestroyWindow (display_x11->xdisplay, display_x11->leader_window);
+
+  /* list of filters for client messages */
+  g_list_foreach (display_x11->client_filters, (GFunc) g_free, NULL);
+  g_list_free (display_x11->client_filters);
+
+  /* List of event window extraction functions */
+  g_slist_foreach (display_x11->event_types, (GFunc)g_free, NULL);
+  g_slist_free (display_x11->event_types);
+
+  /* input GdkDevice list */
+  g_list_foreach (display_x11->input_devices, (GFunc) g_object_unref, NULL);
+  g_list_free (display_x11->input_devices);
+
+  /* input GdkWindow list */
+  g_list_foreach (display_x11->input_windows, (GFunc) g_free, NULL);
+  g_list_free (display_x11->input_windows);
+
+  /* Free all GdkScreens */
+  for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
+    g_object_unref (display_x11->screens[i]);
+  g_free (display_x11->screens);
+
+  g_free (display_x11->startup_notification_id);
+
+  /* X ID hashtable */
+  g_hash_table_destroy (display_x11->xid_ht);
+
+  XCloseDisplay (display_x11->xdisplay);
+
+  /* error traps */
+  while (display_x11->error_traps != NULL)
+    {
+      GdkErrorTrap *trap = display_x11->error_traps->data;
+
+      display_x11->error_traps =
+        g_slist_delete_link (display_x11->error_traps,
+                             display_x11->error_traps);
+
+      if (trap->end_sequence == 0)
+        g_warning ("Display finalized with an unpopped error trap");
+
+      g_slice_free (GdkErrorTrap, trap);
+    }
+
+  G_OBJECT_CLASS (_gdk_display_x11_parent_class)->finalize (object);
+}
+
+/**
+ * gdk_x11_lookup_xdisplay:
+ * @xdisplay: a pointer to an X Display
+ * 
+ * Find the #GdkDisplay corresponding to @display, if any exists.
+ * 
+ * Return value: the #GdkDisplay, if found, otherwise %NULL.
+ *
+ * Since: 2.2
+ **/
+GdkDisplay *
+gdk_x11_lookup_xdisplay (Display *xdisplay)
+{
+  GSList *tmp_list;
+
+  for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next)
+    {
+      if (GDK_DISPLAY_XDISPLAY (tmp_list->data) == xdisplay)
+	return tmp_list->data;
+    }
+  
+  return NULL;
+}
+
+/**
+ * _gdk_x11_display_screen_for_xrootwin:
+ * @display: a #GdkDisplay
+ * @xrootwin: window ID for one of of the screen's of the display.
+ * 
+ * Given the root window ID of one of the screen's of a #GdkDisplay,
+ * finds the screen.
+ * 
+ * Return value: the #GdkScreen corresponding to @xrootwin, or %NULL.
+ **/
+GdkScreen *
+_gdk_x11_display_screen_for_xrootwin (GdkDisplay *display,
+				      Window      xrootwin)
+{
+  gint i;
+
+  for (i = 0; i < ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay); i++)
+    {
+      GdkScreen *screen = gdk_display_get_screen (display, i);
+      if (GDK_SCREEN_XROOTWIN (screen) == xrootwin)
+	return screen;
+    }
+
+  return NULL;
+}
+
+/**
+ * gdk_x11_display_get_xdisplay:
+ * @display: a #GdkDisplay
+ * @returns: an X display.
+ *
+ * Returns the X display of a #GdkDisplay.
+ *
+ * Since: 2.2
+ */
+Display *
+gdk_x11_display_get_xdisplay (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  return GDK_DISPLAY_X11 (display)->xdisplay;
+}
+
+void
+_gdk_windowing_set_default_display (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  const gchar *startup_id;
+  
+  if (!display)
+    return;
+
+  g_free (display_x11->startup_notification_id);
+  display_x11->startup_notification_id = NULL;
+  
+  startup_id = g_getenv ("DESKTOP_STARTUP_ID");
+  if (startup_id && *startup_id != '\0')
+    {
+      if (!g_utf8_validate (startup_id, -1, NULL))
+        g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
+      else
+        gdk_x11_display_set_startup_notification_id (display, startup_id);
+      
+      /* Clear the environment variable so it won't be inherited by
+       * child processes and confuse things.  
+       */
+      g_unsetenv ("DESKTOP_STARTUP_ID");
+    }
+}
+
+static void
+broadcast_xmessage (GdkDisplay *display,
+		    const char *message_type,
+		    const char *message_type_begin,
+		    const char *message)
+{
+  Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+  GdkScreen *screen = gdk_display_get_default_screen (display);
+  GdkWindow *root_window = gdk_screen_get_root_window (screen);
+  Window xroot_window = GDK_WINDOW_XID (root_window);
+  
+  Atom type_atom;
+  Atom type_atom_begin;
+  Window xwindow;
+
+  if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+    return;
+
+  {
+    XSetWindowAttributes attrs;
+
+    attrs.override_redirect = True;
+    attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
+
+    xwindow =
+      XCreateWindow (xdisplay,
+                     xroot_window,
+                     -100, -100, 1, 1,
+                     0,
+                     CopyFromParent,
+                     CopyFromParent,
+                     (Visual *)CopyFromParent,
+                     CWOverrideRedirect | CWEventMask,
+                     &attrs);
+  }
+
+  type_atom = gdk_x11_get_xatom_by_name_for_display (display,
+                                                     message_type);
+  type_atom_begin = gdk_x11_get_xatom_by_name_for_display (display,
+                                                           message_type_begin);
+  
+  {
+    XClientMessageEvent xclient;
+    const char *src;
+    const char *src_end;
+    char *dest;
+    char *dest_end;
+    
+		memset(&xclient, 0, sizeof (xclient));
+    xclient.type = ClientMessage;
+    xclient.message_type = type_atom_begin;
+    xclient.display =xdisplay;
+    xclient.window = xwindow;
+    xclient.format = 8;
+
+    src = message;
+    src_end = message + strlen (message) + 1; /* +1 to include nul byte */
+    
+    while (src != src_end)
+      {
+        dest = &xclient.data.b[0];
+        dest_end = dest + 20;        
+        
+        while (dest != dest_end &&
+               src != src_end)
+          {
+            *dest = *src;
+            ++dest;
+            ++src;
+          }
+
+	while (dest != dest_end)
+	  {
+	    *dest = 0;
+	    ++dest;
+	  }
+        
+        XSendEvent (xdisplay,
+                    xroot_window,
+                    False,
+                    PropertyChangeMask,
+                    (XEvent *)&xclient);
+
+        xclient.message_type = type_atom;
+      }
+  }
+
+  XDestroyWindow (xdisplay, xwindow);
+  XFlush (xdisplay);
+}
+
+/**
+ * gdk_x11_display_broadcast_startup_message:
+ * @display: a #GdkDisplay
+ * @message_type: startup notification message type ("new", "change",
+ * or "remove")
+ * @...: a list of key/value pairs (as strings), terminated by a
+ * %NULL key. (A %NULL value for a key will cause that key to be
+ * skipped in the output.)
+ *
+ * Sends a startup notification message of type @message_type to
+ * @display. 
+ *
+ * This is a convenience function for use by code that implements the
+ * freedesktop startup notification specification. Applications should
+ * not normally need to call it directly. See the <ulink
+ * url="http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt";>Startup
+ * Notification Protocol specification</ulink> for
+ * definitions of the message types and keys that can be used.
+ *
+ * Since: 2.12
+ **/
+void
+gdk_x11_display_broadcast_startup_message (GdkDisplay *display,
+					   const char *message_type,
+					   ...)
+{
+  GString *message;
+  va_list ap;
+  const char *key, *value, *p;
+
+  message = g_string_new (message_type);
+  g_string_append_c (message, ':');
+
+  va_start (ap, message_type);
+  while ((key = va_arg (ap, const char *)))
+    {
+      value = va_arg (ap, const char *);
+      if (!value)
+	continue;
+
+      g_string_append_printf (message, " %s=\"", key);
+      for (p = value; *p; p++)
+	{
+	  switch (*p)
+	    {
+	    case ' ':
+	    case '"':
+	    case '\\':
+	      g_string_append_c (message, '\\');
+	      break;
+	    }
+
+	  g_string_append_c (message, *p);
+	}
+      g_string_append_c (message, '\"');
+    }
+  va_end (ap);
+
+  broadcast_xmessage (display,
+		      "_NET_STARTUP_INFO",
+                      "_NET_STARTUP_INFO_BEGIN",
+                      message->str);
+
+  g_string_free (message, TRUE);
+}
+
+/**
+ * gdk_notify_startup_complete:
+ * 
+ * Indicates to the GUI environment that the application has finished
+ * loading. If the applications opens windows, this function is
+ * normally called after opening the application's initial set of
+ * windows.
+ * 
+ * GTK+ will call this function automatically after opening the first
+ * #GtkWindow unless gtk_window_set_auto_startup_notification() is called 
+ * to disable that feature.
+ *
+ * Since: 2.2
+ **/
+void
+gdk_notify_startup_complete (void)
+{
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+
+  display = gdk_display_get_default ();
+  if (!display)
+    return;
+  
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (display_x11->startup_notification_id == NULL)
+    return;
+
+  gdk_notify_startup_complete_with_id (display_x11->startup_notification_id);
+}
+
+/**
+ * gdk_notify_startup_complete_with_id:
+ * @startup_id: a startup-notification identifier, for which notification
+ *              process should be completed
+ * 
+ * Indicates to the GUI environment that the application has finished
+ * loading, using a given identifier.
+ * 
+ * GTK+ will call this function automatically for #GtkWindow with custom
+ * startup-notification identifier unless
+ * gtk_window_set_auto_startup_notification() is called to disable
+ * that feature.
+ *
+ * Since: 2.12
+ **/
+void
+gdk_notify_startup_complete_with_id (const gchar* startup_id)
+{
+  GdkDisplay *display;
+
+  display = gdk_display_get_default ();
+  if (!display)
+    return;
+
+  gdk_x11_display_broadcast_startup_message (display, "remove",
+					     "ID", startup_id,
+					     NULL);
+}
+
+/**
+ * gdk_display_supports_selection_notification:
+ * @display: a #GdkDisplay
+ * 
+ * Returns whether #GdkEventOwnerChange events will be 
+ * sent when the owner of a selection changes.
+ * 
+ * Return value: whether #GdkEventOwnerChange events will 
+ *               be sent.
+ *
+ * Since: 2.6
+ **/
+gboolean 
+gdk_display_supports_selection_notification (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  return display_x11->have_xfixes;
+}
+
+/**
+ * gdk_display_request_selection_notification:
+ * @display: a #GdkDisplay
+ * @selection: the #GdkAtom naming the selection for which
+ *             ownership change notification is requested
+ * 
+ * Request #GdkEventOwnerChange events for ownership changes
+ * of the selection named by the given atom.
+ * 
+ * Return value: whether #GdkEventOwnerChange events will 
+ *               be sent.
+ *
+ * Since: 2.6
+ **/
+gboolean
+gdk_display_request_selection_notification (GdkDisplay *display,
+					    GdkAtom     selection)
+
+{
+#ifdef HAVE_XFIXES
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  Atom atom;
+
+  if (display_x11->have_xfixes)
+    {
+      atom = gdk_x11_atom_to_xatom_for_display (display, 
+						selection);
+      XFixesSelectSelectionInput (display_x11->xdisplay, 
+				  display_x11->leader_window,
+				  atom,
+				  XFixesSetSelectionOwnerNotifyMask |
+				  XFixesSelectionWindowDestroyNotifyMask |
+				  XFixesSelectionClientCloseNotifyMask);
+      return TRUE;
+    }
+  else
+#endif
+    return FALSE;
+}
+
+/**
+ * gdk_display_supports_clipboard_persistence
+ * @display: a #GdkDisplay
+ *
+ * Returns whether the speicifed display supports clipboard
+ * persistance; i.e. if it's possible to store the clipboard data after an
+ * application has quit. On X11 this checks if a clipboard daemon is
+ * running.
+ *
+ * Returns: %TRUE if the display supports clipboard persistance.
+ *
+ * Since: 2.6
+ */
+gboolean
+gdk_display_supports_clipboard_persistence (GdkDisplay *display)
+{
+  Atom clipboard_manager;
+
+  /* It might make sense to cache this */
+  clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
+  return XGetSelectionOwner (GDK_DISPLAY_X11 (display)->xdisplay, clipboard_manager) != None;
+}
+
+/**
+ * gdk_display_store_clipboard
+ * @display:          a #GdkDisplay
+ * @clipboard_window: a #GdkWindow belonging to the clipboard owner
+ * @time_:            a timestamp
+ * @targets:	      an array of targets that should be saved, or %NULL 
+ *                    if all available targets should be saved.
+ * @n_targets:        length of the @targets array
+ *
+ * Issues a request to the clipboard manager to store the
+ * clipboard data. On X11, this is a special program that works
+ * according to the freedesktop clipboard specification, available at
+ * <ulink url="http://www.freedesktop.org/Standards/clipboard-manager-spec";>
+ * http://www.freedesktop.org/Standards/clipboard-manager-spec</ulink>.
+ *
+ * Since: 2.6
+ */
+void
+gdk_display_store_clipboard (GdkDisplay    *display,
+			     GdkWindow     *clipboard_window,
+			     guint32        time_,
+			     const GdkAtom *targets,
+			     gint           n_targets)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  Atom clipboard_manager, save_targets;
+
+  g_return_if_fail (GDK_WINDOW_IS_X11 (clipboard_window));
+
+  clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
+  save_targets = gdk_x11_get_xatom_by_name_for_display (display, "SAVE_TARGETS");
+
+  gdk_error_trap_push ();
+
+  if (XGetSelectionOwner (display_x11->xdisplay, clipboard_manager) != None)
+    {
+      Atom property_name = None;
+      Atom *xatoms;
+      int i;
+      
+      if (n_targets > 0)
+	{
+	  property_name = gdk_x11_atom_to_xatom_for_display (display, _gdk_selection_property);
+
+	  xatoms = g_new (Atom, n_targets);
+	  for (i = 0; i < n_targets; i++)
+	    xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, targets[i]);
+
+	  XChangeProperty (display_x11->xdisplay, GDK_WINDOW_XID (clipboard_window),
+			   property_name, XA_ATOM,
+			   32, PropModeReplace, (guchar *)xatoms, n_targets);
+	  g_free (xatoms);
+
+	}
+      
+      XConvertSelection (display_x11->xdisplay,
+			 clipboard_manager, save_targets, property_name,
+			 GDK_WINDOW_XID (clipboard_window), time_);
+      
+    }
+  gdk_error_trap_pop_ignored ();
+
+}
+
+/**
+ * gdk_x11_display_get_user_time:
+ * @display: a #GdkDisplay
+ *
+ * Returns the timestamp of the last user interaction on 
+ * @display. The timestamp is taken from events caused
+ * by user interaction such as key presses or pointer 
+ * movements. See gdk_x11_window_set_user_time().
+ *
+ * Returns: the timestamp of the last user interaction 
+ *
+ * Since: 2.8
+ */
+guint32
+gdk_x11_display_get_user_time (GdkDisplay *display)
+{
+  return GDK_DISPLAY_X11 (display)->user_time;
+}
+
+/**
+ * gdk_display_supports_shapes:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if gdk_window_shape_combine_mask() can
+ * be used to create shaped windows on @display.
+ *
+ * Returns: %TRUE if shaped windows are supported 
+ *
+ * Since: 2.10
+ */
+gboolean 
+gdk_display_supports_shapes (GdkDisplay *display)
+{
+  return GDK_DISPLAY_X11 (display)->have_shapes;
+}
+
+/**
+ * gdk_display_supports_input_shapes:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if gdk_window_input_shape_combine_mask() can
+ * be used to modify the input shape of windows on @display.
+ *
+ * Returns: %TRUE if windows with modified input shape are supported 
+ *
+ * Since: 2.10
+ */
+gboolean 
+gdk_display_supports_input_shapes (GdkDisplay *display)
+{
+  return GDK_DISPLAY_X11 (display)->have_input_shapes;
+}
+
+
+/**
+ * gdk_x11_display_get_startup_notification_id:
+ * @display: a #GdkDisplay
+ *
+ * Gets the startup notification ID for a display.
+ * 
+ * Returns: the startup notification ID for @display
+ *
+ * Since: 2.12
+ */
+G_CONST_RETURN gchar *
+gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
+{
+  return GDK_DISPLAY_X11 (display)->startup_notification_id;
+}
+
+/**
+ * gdk_x11_display_set_startup_notification_id:
+ * @display: a #GdkDisplay
+ * @startup_id: the startup notification ID (must be valid utf8)
+ *
+ * Sets the startup notification ID for a display.
+ *
+ * This is usually taken from the value of the DESKTOP_STARTUP_ID
+ * environment variable, but in some cases (such as the application not
+ * being launched using exec()) it can come from other sources.
+ *
+ * If the ID contains the string "_TIME" then the portion following that
+ * string is taken to be the X11 timestamp of the event that triggered
+ * the application to be launched and the GDK current event time is set
+ * accordingly.
+ *
+ * The startup ID is also what is used to signal that the startup is
+ * complete (for example, when opening a window or when calling
+ * gdk_notify_startup_complete()).
+ *
+ * Since: 3.0
+ **/
+void
+gdk_x11_display_set_startup_notification_id (GdkDisplay  *display,
+                                             const gchar *startup_id)
+{
+  GdkDisplayX11 *display_x11;
+  gchar *time_str;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  g_free (display_x11->startup_notification_id);
+  display_x11->startup_notification_id = g_strdup (startup_id);
+
+  /* Find the launch time from the startup_id, if it's there.  Newer spec
+   * states that the startup_id is of the form <unique>_TIME<timestamp>
+   */
+  time_str = g_strrstr (startup_id, "_TIME");
+  if (time_str != NULL)
+    {
+      gulong retval;
+      gchar *end;
+      errno = 0;
+
+      /* Skip past the "_TIME" part */
+      time_str += 5;
+
+      retval = strtoul (time_str, &end, 0);
+      if (end != time_str && errno == 0)
+        display_x11->user_time = retval;
+    }
+
+  /* Set the startup id on the leader window so it
+   * applies to all windows we create on this display
+   */
+  XChangeProperty (display_x11->xdisplay,
+                   display_x11->leader_window,
+                   gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
+                   gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+                   PropModeReplace,
+                   (guchar *)startup_id, strlen (startup_id));
+}
+
+/**
+ * gdk_display_supports_composite:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if gdk_window_set_composited() can be used
+ * to redirect drawing on the window using compositing.
+ *
+ * Currently this only works on X11 with XComposite and
+ * XDamage extensions available.
+ *
+ * Returns: %TRUE if windows may be composited.
+ *
+ * Since: 2.12
+ */
+gboolean
+gdk_display_supports_composite (GdkDisplay *display)
+{
+  GdkDisplayX11 *x11_display = GDK_DISPLAY_X11 (display);
+
+  return x11_display->have_xcomposite &&
+	 x11_display->have_xdamage &&
+	 x11_display->have_xfixes;
+}
+
+/**
+ * gdk_display_list_devices:
+ * @display: a #GdkDisplay
+ *
+ * Returns the list of available input devices attached to @display.
+ * The list is statically allocated and should not be freed.
+ *
+ * Return value: (transfer none) (element-type GdkDevice):
+ *     a list of #GdkDevice
+ *
+ * Since: 2.2
+ *
+ * Deprecated: 3.0: Use gdk_device_manager_list_devices() instead.
+ **/
+GList *
+gdk_display_list_devices (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+  return GDK_DISPLAY_X11 (display)->input_devices;
+}
+
+/**
+ * gdk_event_send_client_message_for_display:
+ * @display: the #GdkDisplay for the window where the message is to be sent.
+ * @event: the #GdkEvent to send, which should be a #GdkEventClient.
+ * @winid: the window to send the client message to.
+ *
+ * On X11, sends an X ClientMessage event to a given window. On
+ * Windows, sends a message registered with the name
+ * GDK_WIN32_CLIENT_MESSAGE.
+ *
+ * This could be used for communicating between different
+ * applications, though the amount of data is limited to 20 bytes on
+ * X11, and to just four bytes on Windows.
+ *
+ * Returns: non-zero on success.
+ *
+ * Since: 2.2
+ */
+gboolean
+gdk_event_send_client_message_for_display (GdkDisplay     *display,
+					   GdkEvent       *event,
+					   GdkNativeWindow winid)
+{
+  XEvent sev;
+
+  g_return_val_if_fail(event != NULL, FALSE);
+
+  /* Set up our event to send, with the exception of its target window */
+  sev.xclient.type = ClientMessage;
+  sev.xclient.display = GDK_DISPLAY_XDISPLAY (display);
+  sev.xclient.format = event->client.data_format;
+  sev.xclient.window = winid;
+  memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
+  sev.xclient.message_type = gdk_x11_atom_to_xatom_for_display (display, event->client.message_type);
+
+  return _gdk_send_xevent (display, winid, False, NoEventMask, &sev);
+}
+
+/**
+ * gdk_display_add_client_message_filter:
+ * @display: a #GdkDisplay for which this message filter applies
+ * @message_type: the type of ClientMessage events to receive.
+ *   This will be checked against the @message_type field
+ *   of the XClientMessage event struct.
+ * @func: the function to call to process the event.
+ * @data: user data to pass to @func.
+ *
+ * Adds a filter to be called when X ClientMessage events are received.
+ * See gdk_window_add_filter() if you are interested in filtering other
+ * types of events.
+ *
+ * Since: 2.2
+ **/
+void
+gdk_display_add_client_message_filter (GdkDisplay   *display,
+				       GdkAtom       message_type,
+				       GdkFilterFunc func,
+				       gpointer      data)
+{
+  GdkClientFilter *filter;
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+  filter = g_new (GdkClientFilter, 1);
+
+  filter->type = message_type;
+  filter->function = func;
+  filter->data = data;
+
+  GDK_DISPLAY_X11(display)->client_filters =
+    g_list_append (GDK_DISPLAY_X11 (display)->client_filters,
+		   filter);
+}
+
+/**
+ * gdk_add_client_message_filter:
+ * @message_type: the type of ClientMessage events to receive. This will be
+ *     checked against the <structfield>message_type</structfield> field of the
+ *     XClientMessage event struct.
+ * @func: the function to call to process the event.
+ * @data: user data to pass to @func.
+ *
+ * Adds a filter to the default display to be called when X ClientMessage events
+ * are received. See gdk_display_add_client_message_filter().
+ **/
+void
+gdk_add_client_message_filter (GdkAtom       message_type,
+			       GdkFilterFunc func,
+			       gpointer      data)
+{
+  gdk_display_add_client_message_filter (gdk_display_get_default (),
+					 message_type, func, data);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_flush
+ *
+ *   Flushes the Xlib output buffer and then waits
+ *   until all requests have been received and processed
+ *   by the X server. The only real use for this function
+ *   is in dealing with XShm.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+void
+gdk_flush (void)
+{
+  GSList *tmp_list = _gdk_displays;
+
+  while (tmp_list)
+    {
+      XSync (GDK_DISPLAY_XDISPLAY (tmp_list->data), False);
+      tmp_list = tmp_list->next;
+    }
+}
+
+/**
+ * gdk_x11_register_standard_event_type:
+ * @display: a #GdkDisplay
+ * @event_base: first event type code to register
+ * @n_events: number of event type codes to register
+ *
+ * Registers interest in receiving extension events with type codes
+ * between @event_base and <literal>event_base + n_events - 1</literal>.
+ * The registered events must have the window field in the same place
+ * as core X events (this is not the case for e.g. XKB extension events).
+ *
+ * If an event type is registered, events of this type will go through
+ * global and window-specific filters (see gdk_window_add_filter()).
+ * Unregistered events will only go through global filters.
+ * GDK may register the events of some X extensions on its own.
+ *
+ * This function should only be needed in unusual circumstances, e.g.
+ * when filtering XInput extension events on the root window.
+ *
+ * Since: 2.4
+ **/
+void
+gdk_x11_register_standard_event_type (GdkDisplay *display,
+				      gint        event_base,
+				      gint        n_events)
+{
+  GdkEventTypeX11 *event_type;
+  GdkDisplayX11 *display_x11;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+  event_type = g_new (GdkEventTypeX11, 1);
+
+  event_type->base = event_base;
+  event_type->n_events = n_events;
+
+  display_x11->event_types = g_slist_prepend (display_x11->event_types, event_type);
+}
+
+/* compare X sequence numbers handling wraparound */
+#define SEQUENCE_COMPARE(a,op,b) (((long) (a) - (long) (b)) op 0)
+
+/* delivers an error event from the error handler in gdkmain-x11.c */
+void
+_gdk_x11_display_error_event (GdkDisplay  *display,
+                              XErrorEvent *error)
+{
+  GdkDisplayX11 *display_x11;
+  GSList *tmp_list;
+  gboolean ignore;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  ignore = FALSE;
+  for (tmp_list = display_x11->error_traps;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      GdkErrorTrap *trap;
+
+      trap = tmp_list->data;
+
+      if (SEQUENCE_COMPARE (trap->start_sequence, <=, error->serial) &&
+          (trap->end_sequence == 0 ||
+           SEQUENCE_COMPARE (trap->end_sequence, >, error->serial)))
+        {
+          ignore = TRUE;
+          trap->error_code = error->error_code;
+          break; /* only innermost trap gets the error code */
+        }
+    }
+
+  if (!ignore)
+    {
+      gchar buf[64];
+      gchar *msg;
+
+      XGetErrorText (display_x11->xdisplay, error->error_code, buf, 63);
+
+      msg =
+        g_strdup_printf ("The program '%s' received an X Window System error.\n"
+                         "This probably reflects a bug in the program.\n"
+                         "The error was '%s'.\n"
+                         "  (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
+                         "  (Note to programmers: normally, X errors are reported asynchronously;\n"
+                         "   that is, you will receive the error a while after causing it.\n"
+                         "   To debug your program, run it with the --sync command line\n"
+                         "   option to change this behavior. You can then get a meaningful\n"
+                         "   backtrace from your debugger if you break on the gdk_x_error() function.)",
+                         g_get_prgname (),
+                         buf,
+                         error->serial,
+                         error->error_code,
+                         error->request_code,
+                         error->minor_code);
+
+#ifdef G_ENABLE_DEBUG
+      g_error ("%s", msg);
+#else /* !G_ENABLE_DEBUG */
+      g_warning ("%s\n", msg);
+
+      exit (1);
+#endif /* G_ENABLE_DEBUG */
+    }
+}
+
+static void
+delete_outdated_error_traps (GdkDisplayX11 *display_x11)
+{
+  GSList *tmp_list;
+  gulong processed_sequence;
+
+  processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
+
+  tmp_list = display_x11->error_traps;
+  while (tmp_list != NULL)
+    {
+      GdkErrorTrap *trap = tmp_list->data;
+
+      if (trap->end_sequence != 0 &&
+          SEQUENCE_COMPARE (trap->end_sequence, <=, processed_sequence))
+        {
+          GSList *free_me = tmp_list;
+
+          tmp_list = tmp_list->next;
+          display_x11->error_traps =
+            g_slist_delete_link (display_x11->error_traps, free_me);
+          g_slice_free (GdkErrorTrap, trap);
+        }
+      else
+        {
+          tmp_list = tmp_list->next;
+        }
+    }
+}
+
+/**
+ * gdk_x11_display_error_trap_push:
+ * @display: a #GdkDisplay
+ *
+ * Begins a range of X requests on @display for which X error events
+ * will be ignored. Unignored errors (when no trap is pushed) will abort
+ * the application. Use gdk_x11_display_error_trap_pop() or
+ * gdk_x11_display_error_trap_pop_ignored()to lift a trap pushed
+ * with this function.
+ *
+ * See also gdk_error_trap_push() to push a trap on all displays.
+ *
+ * Since: 3.0
+ */
+void
+gdk_x11_display_error_trap_push (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11;
+  GdkErrorTrap *trap;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  delete_outdated_error_traps (display_x11);
+
+  /* set up the Xlib callback to tell us about errors */
+  _gdk_x11_error_handler_push ();
+
+  trap = g_slice_new0 (GdkErrorTrap);
+
+  trap->start_sequence = XNextRequest (display_x11->xdisplay);
+  trap->error_code = Success;
+
+  display_x11->error_traps =
+    g_slist_prepend (display_x11->error_traps, trap);
+}
+
+static gint
+gdk_x11_display_error_trap_pop_internal (GdkDisplay *display,
+                                         gboolean    need_code)
+{
+  GdkDisplayX11 *display_x11;
+  GdkErrorTrap *trap;
+  GSList *tmp_list;
+  int result;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  g_return_val_if_fail (display_x11->error_traps != NULL, Success);
+
+  /* Find the first trap that hasn't been popped already */
+  trap = NULL; /* quiet gcc */
+  for (tmp_list = display_x11->error_traps;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      trap = tmp_list->data;
+
+      if (trap->end_sequence == 0)
+        break;
+    }
+
+  g_return_val_if_fail (trap != NULL, Success);
+  g_assert (trap->end_sequence == 0);
+
+  /* May need to sync to fill in trap->error_code if we care about
+   * getting an error code.
+   */
+  if (need_code)
+    {
+      gulong processed_sequence;
+      gulong next_sequence;
+
+      next_sequence = XNextRequest (display_x11->xdisplay);
+      processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
+
+      /* If our last request was already processed, there is no point
+       * in syncing. i.e. if last request was a round trip (or even if
+       * we got an event with the serial of a non-round-trip)
+       */
+      if ((next_sequence - 1) != processed_sequence)
+        {
+          XSync (display_x11->xdisplay, False);
+        }
+
+      result = trap->error_code;
+    }
+  else
+    {
+      result = Success;
+    }
+
+  /* record end of trap, giving us a range of
+   * error sequences we'll ignore.
+   */
+  trap->end_sequence = XNextRequest (display_x11->xdisplay);
+
+  /* remove the Xlib callback */
+  _gdk_x11_error_handler_pop ();
+
+  /* we may already be outdated */
+  delete_outdated_error_traps (display_x11);
+
+  return result;
+}
+
+/**
+ * gdk_x11_display_error_trap_pop:
+ * @display: the display
+ *
+ * Pops the error trap pushed by gdk_x11_display_error_trap_push().
+ * Will XSync() if necessary and will always block until
+ * the error is known to have occurred or not occurred,
+ * so the error code can be returned.
+ *
+ * If you don't need to use the return value,
+ * gdk_x11_display_error_trap_pop_ignored() would be more efficient.
+ *
+ * See gdk_error_trap_pop() for the all-displays-at-once
+ * equivalent.
+ *
+ * Since: 3.0
+ *
+ * Return value: X error code or 0 on success
+ */
+gint
+gdk_x11_display_error_trap_pop (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY_X11 (display), Success);
+
+  return gdk_x11_display_error_trap_pop_internal (display, TRUE);
+}
+
+/**
+ * gdk_x11_display_error_trap_pop_ignored:
+ * @display: the display
+ *
+ * Pops the error trap pushed by gdk_x11_display_error_trap_push().
+ * Does not block to see if an error occurred; merely records the
+ * range of requests to ignore errors for, and ignores those errors
+ * if they arrive asynchronously.
+ *
+ * See gdk_error_trap_pop_ignored() for the all-displays-at-once
+ * equivalent.
+ *
+ * Since: 3.0
+ */
+void
+gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display)
+{
+  g_return_if_fail (GDK_IS_DISPLAY_X11 (display));
+
+  gdk_x11_display_error_trap_pop_internal (display, FALSE);
+}
diff --git a/gdk/broadway/gdkdisplay-broadway.h b/gdk/broadway/gdkdisplay-broadway.h
new file mode 100644
index 0000000..9ac0c3a
--- /dev/null
+++ b/gdk/broadway/gdkdisplay-broadway.h
@@ -0,0 +1,160 @@
+/*
+ * gdkdisplay-x11.h
+ * 
+ * Copyright 2001 Sun Microsystems Inc. 
+ *
+ * Erwann Chenede <erwann chenede sun com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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_DISPLAY_X11__
+#define __GDK_DISPLAY_X11__
+
+#include <gdk/gdkdisplay.h>
+#include <gdk/gdkkeys.h>
+#include <gdk/gdkwindow.h>
+#include <gdk/gdkinternals.h>
+#include <gdk/gdkmain.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkDisplayX11 GdkDisplayX11;
+typedef struct _GdkDisplayX11Class GdkDisplayX11Class;
+
+#define GDK_TYPE_DISPLAY_X11              (_gdk_display_x11_get_type())
+#define GDK_DISPLAY_X11(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_DISPLAY_X11, GdkDisplayX11))
+#define GDK_DISPLAY_X11_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DISPLAY_X11, GdkDisplayX11Class))
+#define GDK_IS_DISPLAY_X11(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_DISPLAY_X11))
+#define GDK_IS_DISPLAY_X11_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DISPLAY_X11))
+#define GDK_DISPLAY_X11_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DISPLAY_X11, GdkDisplayX11Class))
+
+struct _GdkDisplayX11
+{
+  GdkDisplay parent_instance;
+  Display *xdisplay;
+  GdkScreen *default_screen;
+  GdkScreen **screens;
+
+  GSource *event_source;
+
+  gint grab_count;
+
+  /* Keyboard related information */
+
+  gint xkb_event_type;
+  gboolean use_xkb;
+  
+  /* Whether we were able to turn on detectable-autorepeat using
+   * XkbSetDetectableAutorepeat. If FALSE, we'll fall back
+   * to checking the next event with XPending(). */
+  gboolean have_xkb_autorepeat;
+
+  GdkKeymap *keymap;
+  guint	    keymap_serial;
+
+  gboolean have_xfixes;
+  gint xfixes_event_base;
+
+  gboolean have_xcomposite;
+  gboolean have_xdamage;
+  gint xdamage_event_base;
+
+  gboolean have_randr13;
+  gint xrandr_event_base;
+
+  /* If the SECURITY extension is in place, whether this client holds 
+   * a trusted authorization and so is allowed to make various requests 
+   * (grabs, properties etc.) Otherwise always TRUE. */
+  gboolean trusted_client;
+
+  /* drag and drop information */
+  GdkDragContext *current_dest_drag;
+
+  /* data needed for MOTIF DnD */
+
+  Window motif_drag_window;
+  GdkWindow *motif_drag_gdk_window;
+  GList **motif_target_lists;
+  gint motif_n_target_lists;
+
+  /* Mapping to/from virtual atoms */
+
+  GHashTable *atom_from_virtual;
+  GHashTable *atom_to_virtual;
+
+  /* Session Management leader window see ICCCM */
+  Window leader_window;
+  GdkWindow *leader_gdk_window;
+  gboolean leader_window_title_set;
+  
+  /* list of filters for client messages */
+  GList *client_filters;
+
+  /* List of functions to go from extension event => X window */
+  GSList *event_types;
+  
+  /* X ID hashtable */
+  GHashTable *xid_ht;
+
+  /* translation queue */
+  GQueue *translate_queue;
+
+  /* Input device */
+  /* input GdkDevice list */
+  GList *input_devices;
+
+  /* input GdkWindow list */
+  GList *input_windows;
+
+  /* Startup notification */
+  gchar *startup_notification_id;
+
+  /* Time of most recent user interaction. */
+  gulong user_time;
+
+  /* Sets of atoms for DND */
+  guint base_dnd_atoms_precached : 1;
+  guint xdnd_atoms_precached : 1;
+  guint motif_atoms_precached : 1;
+  guint use_sync : 1;
+
+  guint have_shapes : 1;
+  guint have_input_shapes : 1;
+  gint shape_event_base;
+
+  /* The offscreen window that has the pointer in it (if any) */
+  GdkWindow *active_offscreen_window;
+
+  GSList *error_traps;
+};
+
+struct _GdkDisplayX11Class
+{
+  GdkDisplayClass parent_class;
+};
+
+GType      _gdk_display_x11_get_type            (void);
+GdkScreen *_gdk_x11_display_screen_for_xrootwin (GdkDisplay  *display,
+						 Window       xrootwin);
+void       _gdk_x11_display_error_event         (GdkDisplay  *display,
+                                                 XErrorEvent *error);
+
+G_END_DECLS
+
+#endif				/* __GDK_DISPLAY_X11__ */
diff --git a/gdk/broadway/gdkdnd-broadway.c b/gdk/broadway/gdkdnd-broadway.c
new file mode 100644
index 0000000..b10d787
--- /dev/null
+++ b/gdk/broadway/gdkdnd-broadway.c
@@ -0,0 +1,4035 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkdnd.h"
+
+#include "gdkmain.h"
+#include "gdkx.h"
+#include "gdkasync.h"
+#include "gdkproperty.h"
+#include "gdkprivate-broadway.h"
+#include "gdkinternals.h"
+#include "gdkscreen-broadway.h"
+#include "gdkdisplay-broadway.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xcomposite.h>
+
+#include <string.h>
+
+typedef struct _GdkDragContextPrivateX11 GdkDragContextPrivateX11;
+
+typedef enum {
+  GDK_DRAG_STATUS_DRAG,
+  GDK_DRAG_STATUS_MOTION_WAIT,
+  GDK_DRAG_STATUS_ACTION_WAIT,
+  GDK_DRAG_STATUS_DROP
+} GtkDragStatus;
+
+typedef struct {
+  guint32 xid;
+  gint x, y, width, height;
+  gboolean mapped;
+  gboolean shape_selected;
+  gboolean shape_valid;
+  cairo_region_t *shape;
+} GdkCacheChild;
+
+typedef struct {
+  GList *children;
+  GHashTable *child_hash;
+  guint old_event_mask;
+  GdkScreen *screen;
+} GdkWindowCache;
+
+/* Structure that holds information about a drag in progress.
+ * this is used on both source and destination sides.
+ */
+struct _GdkDragContextPrivateX11 {
+  GdkDragContext context;
+
+  Atom motif_selection;
+  guint   ref_count;
+
+  guint16 last_x;		/* Coordinates from last event */
+  guint16 last_y;
+  GdkDragAction old_action;	  /* The last action we sent to the source */
+  GdkDragAction old_actions;	  /* The last actions we sent to the source */
+  GdkDragAction xdnd_actions;     /* What is currently set in XdndActionList */
+
+  Window dest_xid;              /* The last window we looked up */
+  Window drop_xid;            /* The (non-proxied) window that is receiving drops */
+  guint xdnd_targets_set : 1;   /* Whether we've already set XdndTypeList */
+  guint xdnd_actions_set : 1;   /* Whether we've already set XdndActionList */
+  guint xdnd_have_actions : 1;  /* Whether an XdndActionList was provided */
+  guint motif_targets_set : 1;  /* Whether we've already set motif initiator info */
+  guint drag_status : 4;	/* current status of drag */
+  
+  guint drop_failed : 1;        /* Whether the drop was unsuccessful */
+  guint version;                /* Xdnd protocol version */
+
+  GSList *window_caches;
+  GdkDevice *device;
+};
+
+#define PRIVATE_DATA(context) ((GdkDragContextPrivateX11 *) GDK_DRAG_CONTEXT (context)->windowing_data)
+
+/* Forward declarations */
+
+static void gdk_window_cache_destroy (GdkWindowCache *cache);
+
+static void motif_read_target_table (GdkDisplay *display);
+
+static GdkFilterReturn motif_dnd_filter (GdkXEvent *xev,
+					 GdkEvent  *event,
+					 gpointer   data);
+
+static GdkFilterReturn xdnd_enter_filter    (GdkXEvent *xev,
+					     GdkEvent  *event,
+					     gpointer   data);
+static GdkFilterReturn xdnd_leave_filter    (GdkXEvent *xev,
+					     GdkEvent  *event,
+					     gpointer   data);
+static GdkFilterReturn xdnd_position_filter (GdkXEvent *xev,
+					     GdkEvent  *event,
+					     gpointer   data);
+static GdkFilterReturn xdnd_status_filter   (GdkXEvent *xev,
+					     GdkEvent  *event,
+					     gpointer   data);
+static GdkFilterReturn xdnd_finished_filter (GdkXEvent *xev,
+					     GdkEvent  *event,
+					     gpointer   data);
+static GdkFilterReturn xdnd_drop_filter     (GdkXEvent *xev,
+					     GdkEvent  *event,
+					     gpointer   data);
+
+static void   xdnd_manage_source_filter (GdkDragContext *context,
+					 GdkWindow      *window,
+					 gboolean        add_filter);
+
+static void gdk_drag_context_finalize   (GObject              *object);
+
+static GList *contexts;
+
+static const struct {
+  const char *atom_name;
+  GdkFilterFunc func;
+} xdnd_filters[] = {
+  { "XdndEnter",    xdnd_enter_filter },
+  { "XdndLeave",    xdnd_leave_filter },
+  { "XdndPosition", xdnd_position_filter },
+  { "XdndStatus",   xdnd_status_filter },
+  { "XdndFinished", xdnd_finished_filter },
+  { "XdndDrop",     xdnd_drop_filter },
+};
+	      
+G_DEFINE_TYPE (GdkDragContext, gdk_drag_context, G_TYPE_OBJECT)
+
+static void
+gdk_drag_context_init (GdkDragContext *dragcontext)
+{
+  GdkDragContextPrivateX11 *private;
+
+  private = G_TYPE_INSTANCE_GET_PRIVATE (dragcontext, 
+					 GDK_TYPE_DRAG_CONTEXT, 
+					 GdkDragContextPrivateX11);
+  
+  dragcontext->windowing_data = private;
+
+  contexts = g_list_prepend (contexts, dragcontext);
+}
+
+static void
+gdk_drag_context_class_init (GdkDragContextClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gdk_drag_context_finalize;
+
+  g_type_class_add_private (object_class, sizeof (GdkDragContextPrivateX11));
+}
+
+static void
+gdk_drag_context_finalize (GObject *object)
+{
+  GdkDragContext *context = GDK_DRAG_CONTEXT (object);
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GSList *tmp_list;
+  
+  g_list_free (context->targets);
+
+  if (context->source_window)
+    {
+      if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
+          !context->is_source)
+        xdnd_manage_source_filter (context, context->source_window, FALSE);
+      
+      g_object_unref (context->source_window);
+    }
+  
+  if (context->dest_window)
+    g_object_unref (context->dest_window);
+
+  for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
+    gdk_window_cache_destroy (tmp_list->data);
+  g_slist_free (private->window_caches);
+  
+  contexts = g_list_remove (contexts, context);
+
+  G_OBJECT_CLASS (gdk_drag_context_parent_class)->finalize (object);
+}
+
+/* Drag Contexts */
+
+/**
+ * gdk_drag_context_new:
+ * 
+ * Creates a new #GdkDragContext.
+ * 
+ * Return value: the newly created #GdkDragContext.
+ **/
+GdkDragContext *
+gdk_drag_context_new (void)
+{
+  return g_object_new (GDK_TYPE_DRAG_CONTEXT, NULL);
+}
+
+/**
+ * gdk_drag_context_set_device:
+ * @context: a #GdkDragContext
+ * @device: a #GdkDevice
+ *
+ * Associates a #GdkDevice to @context, so all Drag and Drop events
+ * for @context are emitted as if they came from this device.
+ **/
+void
+gdk_drag_context_set_device (GdkDragContext *context,
+                             GdkDevice      *device)
+{
+  GdkDragContextPrivateX11 *private;
+
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (GDK_IS_DEVICE (device));
+
+  private = PRIVATE_DATA (context);
+
+  if (private->device)
+    {
+      g_object_unref (private->device);
+      private->device = NULL;
+    }
+
+  if (device)
+    private->device = g_object_ref (device);
+}
+
+/**
+ * gdk_drag_context_get_device:
+ * @context: a #GdkDragContext
+ *
+ * Returns the #GdkDevice associated to the drag context.
+ *
+ * Returns: The #GdkDevice associated to @context.
+ **/
+GdkDevice *
+gdk_drag_context_get_device (GdkDragContext *context)
+{
+  GdkDragContextPrivateX11 *private;
+
+  g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), NULL);
+
+  private = PRIVATE_DATA (context);
+
+  return private->device;
+}
+
+static GdkDragContext *
+gdk_drag_context_find (GdkDisplay *display,
+		       gboolean    is_source,
+		       Window      source_xid,
+		       Window      dest_xid)
+{
+  GList *tmp_list = contexts;
+  GdkDragContext *context;
+  GdkDragContextPrivateX11 *private;
+  Window context_dest_xid;
+
+  while (tmp_list)
+    {
+      context = (GdkDragContext *)tmp_list->data;
+      private = PRIVATE_DATA (context);
+
+      if ((context->source_window && gdk_window_get_display (context->source_window) != display) ||
+	  (context->dest_window && gdk_window_get_display (context->dest_window) != display))
+	continue;
+
+      context_dest_xid = context->dest_window ? 
+                            (private->drop_xid ?
+                              private->drop_xid :
+                              GDK_DRAWABLE_XID (context->dest_window)) :
+	                     None;
+
+      if ((!context->is_source == !is_source) &&
+	  ((source_xid == None) || (context->source_window &&
+	    (GDK_DRAWABLE_XID (context->source_window) == source_xid))) &&
+	  ((dest_xid == None) || (context_dest_xid == dest_xid)))
+	return context;
+      
+      tmp_list = tmp_list->next;
+    }
+  
+  return NULL;
+}
+
+static void
+precache_target_list (GdkDragContext *context)
+{
+  if (context->targets)
+    {
+      GPtrArray *targets = g_ptr_array_new ();
+      GList *tmp_list;
+      int i;
+
+      for (tmp_list = context->targets; tmp_list; tmp_list = tmp_list->next)
+	g_ptr_array_add (targets, gdk_atom_name (GDK_POINTER_TO_ATOM (tmp_list->data)));
+
+      _gdk_x11_precache_atoms (GDK_WINDOW_DISPLAY (context->source_window),
+			       (const gchar **)targets->pdata,
+			       targets->len);
+
+      for (i =0; i < targets->len; i++)
+	g_free (targets->pdata[i]);
+
+      g_ptr_array_free (targets, TRUE);
+    }
+}
+
+/* Utility functions */
+
+static void
+free_cache_child (GdkCacheChild *child,
+                  GdkDisplay    *display)
+{
+  if (child->shape)
+    cairo_region_destroy (child->shape);
+
+  if (child->shape_selected && display)
+    {
+      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+      XShapeSelectInput (display_x11->xdisplay, child->xid, 0);
+    }
+
+  g_free (child);
+}
+
+static void
+gdk_window_cache_add (GdkWindowCache *cache,
+		      guint32 xid,
+		      gint x, gint y, gint width, gint height, 
+		      gboolean mapped)
+{
+  GdkCacheChild *child = g_new (GdkCacheChild, 1);
+
+  child->xid = xid;
+  child->x = x;
+  child->y = y;
+  child->width = width;
+  child->height = height;
+  child->mapped = mapped;
+  child->shape_selected = FALSE;
+  child->shape_valid = FALSE;
+  child->shape = NULL;
+
+  cache->children = g_list_prepend (cache->children, child);
+  g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid), 
+		       cache->children);
+}
+
+static GdkFilterReturn
+gdk_window_cache_shape_filter (GdkXEvent *xev,
+                               GdkEvent  *event,
+                               gpointer   data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  GdkWindowCache *cache = data;
+
+  GdkDisplayX11 *display = GDK_DISPLAY_X11 (gdk_screen_get_display (cache->screen));
+
+  if (display->have_shapes &&
+      xevent->type == display->shape_event_base + ShapeNotify)
+    {
+      XShapeEvent *xse = (XShapeEvent*)xevent;
+      GList *node;
+
+      node = g_hash_table_lookup (cache->child_hash,
+                                  GUINT_TO_POINTER (xse->window));
+      if (node)
+        {
+          GdkCacheChild *child = node->data;
+          child->shape_valid = FALSE;
+          if (child->shape)
+            {
+              cairo_region_destroy (child->shape);
+              child->shape = NULL;
+            }
+        }
+
+      return GDK_FILTER_REMOVE;
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
+
+static GdkFilterReturn
+gdk_window_cache_filter (GdkXEvent *xev,
+			 GdkEvent  *event,
+			 gpointer   data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  GdkWindowCache *cache = data;
+
+  switch (xevent->type)
+    {
+    case CirculateNotify:
+      break;
+    case ConfigureNotify:
+      {
+	XConfigureEvent *xce = &xevent->xconfigure;
+	GList *node;
+
+	node = g_hash_table_lookup (cache->child_hash, 
+				    GUINT_TO_POINTER (xce->window));
+	if (node) 
+	  {
+	    GdkCacheChild *child = node->data;
+	    child->x = xce->x; 
+	    child->y = xce->y;
+	    child->width = xce->width; 
+	    child->height = xce->height;
+	    if (xce->above == None && (node->next))
+	      {
+		GList *last = g_list_last (cache->children);
+		cache->children = g_list_remove_link (cache->children, node);
+		last->next = node;
+		node->next = NULL;
+		node->prev = last;
+	      }
+	    else
+	      {
+		GList *above_node = g_hash_table_lookup (cache->child_hash, 
+							 GUINT_TO_POINTER (xce->above));
+		if (above_node && node->next != above_node)
+		  {
+		    /* Put the window above (before in the list) above_node
+		     */
+		    cache->children = g_list_remove_link (cache->children, node);
+		    node->prev = above_node->prev;
+		    if (node->prev)
+		      node->prev->next = node;
+		    else
+		      cache->children = node;
+		    node->next = above_node;
+		    above_node->prev = node;
+		  }
+	      }
+	  }
+	break;
+      }
+    case CreateNotify:
+      {
+	XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
+
+	if (!g_hash_table_lookup (cache->child_hash, 
+				  GUINT_TO_POINTER (xcwe->window))) 
+	  gdk_window_cache_add (cache, xcwe->window, 
+				xcwe->x, xcwe->y, xcwe->width, xcwe->height,
+				FALSE);
+	break;
+      }
+    case DestroyNotify:
+      {
+	XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
+	GList *node;
+
+	node = g_hash_table_lookup (cache->child_hash, 
+				    GUINT_TO_POINTER (xdwe->window));
+	if (node) 
+	  {
+	    GdkCacheChild *child = node->data;
+
+	    g_hash_table_remove (cache->child_hash,
+				 GUINT_TO_POINTER (xdwe->window));
+	    cache->children = g_list_remove_link (cache->children, node);
+	    /* window is destroyed, no need to disable ShapeNotify */
+	    free_cache_child (child, NULL);
+	    g_list_free_1 (node);
+	  }
+	break;
+      }
+    case MapNotify:
+      {
+	XMapEvent *xme = &xevent->xmap;
+	GList *node;
+
+	node = g_hash_table_lookup (cache->child_hash, 
+				    GUINT_TO_POINTER (xme->window));
+	if (node) 
+	  {
+	    GdkCacheChild *child = node->data;
+	    child->mapped = TRUE;
+	  }
+	break;
+      }
+    case ReparentNotify:
+      break;
+    case UnmapNotify:
+      {
+	XMapEvent *xume = &xevent->xmap;
+	GList *node;
+
+	node = g_hash_table_lookup (cache->child_hash, 
+				    GUINT_TO_POINTER (xume->window));
+	if (node)
+	  {
+	    GdkCacheChild *child = node->data;
+	    child->mapped = FALSE;
+	  }
+	break;
+      }
+    default:
+      return GDK_FILTER_CONTINUE;
+    }
+  return GDK_FILTER_REMOVE;
+}
+
+static GdkWindowCache *
+gdk_window_cache_new (GdkScreen *screen)
+{
+  XWindowAttributes xwa;
+  Display *xdisplay = GDK_SCREEN_XDISPLAY (screen);
+  GdkWindow *root_window = gdk_screen_get_root_window (screen);
+  GdkChildInfoX11 *children;
+  guint nchildren, i;
+  Window cow;
+  
+  GdkWindowCache *result = g_new (GdkWindowCache, 1);
+
+  result->children = NULL;
+  result->child_hash = g_hash_table_new (g_direct_hash, NULL);
+  result->screen = screen;
+
+  XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa);
+  result->old_event_mask = xwa.your_event_mask;
+
+  if (G_UNLIKELY (!GDK_DISPLAY_X11 (GDK_SCREEN_X11 (screen)->display)->trusted_client)) 
+    {
+      GList *toplevel_windows, *list;
+      GdkWindow *window;
+      gint x, y, width, height;
+      
+      toplevel_windows = gdk_screen_get_toplevel_windows (screen);
+      for (list = toplevel_windows; list; list = list->next) {
+	window = GDK_WINDOW (list->data);
+	gdk_window_get_geometry (window, &x, &y, &width, &height, NULL);
+	gdk_window_cache_add (result, GDK_WINDOW_XID (window), 
+			      x, y, width, height, 
+			      gdk_window_is_visible (window));
+      }
+      g_list_free (toplevel_windows);
+      return result;
+    }
+
+  XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
+		result->old_event_mask | SubstructureNotifyMask);
+  gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
+  gdk_window_add_filter (NULL, gdk_window_cache_shape_filter, result);
+
+  if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen),
+				       GDK_WINDOW_XWINDOW (root_window),
+				       FALSE, NULL,
+				       &children, &nchildren))
+    return result;
+
+  for (i = 0; i < nchildren ; i++)
+    {
+      gdk_window_cache_add (result, children[i].window,
+			    children[i].x, children[i].y, children[i].width, children[i].height,
+			    children[i].is_mapped);
+    }
+
+  g_free (children);
+
+#ifdef HAVE_XCOMPOSITE
+  /*
+   * Add the composite overlay window to the cache, as this can be a reasonable
+   * Xdnd proxy as well.
+   * This is only done when the screen is composited in order to avoid mapping
+   * the COW. We assume that the CM is using the COW (which is true for pretty
+   * much any CM currently in use).
+   */
+  if (gdk_screen_is_composited (screen))
+    {
+      cow = XCompositeGetOverlayWindow (xdisplay, GDK_WINDOW_XWINDOW (root_window));
+      gdk_window_cache_add (result, cow, 0, 0, gdk_screen_get_width (screen), gdk_screen_get_height (screen), TRUE);
+      XCompositeReleaseOverlayWindow (xdisplay, GDK_WINDOW_XWINDOW (root_window));
+    }
+#endif
+
+  return result;
+}
+
+static void
+gdk_window_cache_destroy (GdkWindowCache *cache)
+{
+  GdkWindow *root_window = gdk_screen_get_root_window (cache->screen);
+
+  XSelectInput (GDK_WINDOW_XDISPLAY (root_window),
+		GDK_WINDOW_XWINDOW (root_window),
+		cache->old_event_mask);
+  gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache);
+  gdk_window_remove_filter (NULL, gdk_window_cache_shape_filter, cache);
+
+  gdk_error_trap_push ();
+
+  g_list_foreach (cache->children, (GFunc)free_cache_child,
+      gdk_screen_get_display (cache->screen));
+
+  gdk_error_trap_pop_ignored ();
+
+  g_list_free (cache->children);
+  g_hash_table_destroy (cache->child_hash);
+
+  g_free (cache);
+}
+
+static gboolean
+is_pointer_within_shape (GdkDisplay    *display,
+                         GdkCacheChild *child,
+                         gint           x_pos,
+                         gint           y_pos)
+{
+  if (!child->shape_selected)
+    {
+      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+      XShapeSelectInput (display_x11->xdisplay, child->xid, ShapeNotifyMask);
+      child->shape_selected = TRUE;
+    }
+  if (!child->shape_valid)
+    {
+      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+      cairo_region_t *input_shape;
+
+      child->shape = _xwindow_get_shape (display_x11->xdisplay,
+                                         child->xid, ShapeBounding);
+#ifdef ShapeInput
+      input_shape = _xwindow_get_shape (display_x11->xdisplay,
+                                        child->xid, ShapeInput);
+      if (child->shape && input_shape)
+        {
+          cairo_region_intersect (child->shape, input_shape);
+          cairo_region_destroy (input_shape);
+        }
+      else if (input_shape)
+        {
+          child->shape = input_shape;
+        }
+#endif
+
+      child->shape_valid = TRUE;
+    }
+
+  return child->shape == NULL ||
+         cairo_region_contains_point (child->shape, x_pos, y_pos);
+}
+
+static Window
+get_client_window_at_coords_recurse (GdkDisplay *display,
+				     Window      win,
+				     gboolean    is_toplevel,
+				     gint        x,
+				     gint        y)
+{
+  GdkChildInfoX11 *children;
+  unsigned int nchildren;
+  int i;
+  gboolean found_child = FALSE;
+  GdkChildInfoX11 child = { 0, };
+  gboolean has_wm_state = FALSE;
+
+  if (!_gdk_x11_get_window_child_info (display, win, TRUE,
+				       is_toplevel? &has_wm_state : NULL,
+				       &children, &nchildren))
+    return None;
+
+  if (has_wm_state)
+    {
+      g_free (children);
+
+      return win;
+    }
+
+  for (i = nchildren - 1; (i >= 0) && !found_child; i--)
+    {
+      GdkChildInfoX11 *cur_child = &children[i];
+       
+      if ((cur_child->is_mapped) && (cur_child->window_class == InputOutput) &&
+	  (x >= cur_child->x) && (x < cur_child->x + cur_child->width) &&
+	  (y >= cur_child->y) && (y < cur_child->y + cur_child->height))
+ 	{
+	  x -= cur_child->x;
+	  y -= cur_child->y;
+	  child = *cur_child;
+	  found_child = TRUE;
+ 	}
+    }
+   
+  g_free (children);
+ 
+  if (found_child)
+    {
+      if (child.has_wm_state)
+	return child.window;
+      else
+	return get_client_window_at_coords_recurse (display, child.window, FALSE, x, y);
+    }
+  else
+    return None;
+}
+
+static Window 
+get_client_window_at_coords (GdkWindowCache *cache,
+			     Window          ignore,
+			     gint            x_root,
+			     gint            y_root)
+{
+  GList *tmp_list;
+  Window retval = None;
+
+  gdk_error_trap_push ();
+  
+  tmp_list = cache->children;
+
+  while (tmp_list && !retval)
+    {
+      GdkCacheChild *child = tmp_list->data;
+
+      if ((child->xid != ignore) && (child->mapped))
+        {
+          if ((x_root >= child->x) && (x_root < child->x + child->width) &&
+              (y_root >= child->y) && (y_root < child->y + child->height))
+            {
+              GdkDisplay *display = gdk_screen_get_display (cache->screen);
+
+              if (!is_pointer_within_shape (display, child,
+                                            x_root - child->x,
+                                            y_root - child->y))
+                {
+                  tmp_list = tmp_list->next;
+                  continue;
+                }
+
+              retval = get_client_window_at_coords_recurse (display,
+                  child->xid, TRUE,
+                  x_root - child->x,
+                  y_root - child->y);
+              if (!retval)
+                retval = child->xid;
+            }
+        }
+      tmp_list = tmp_list->next;
+    }
+
+  gdk_error_trap_pop_ignored ();
+  
+  if (retval)
+    return retval;
+  else
+    return GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (cache->screen));
+}
+
+/*************************************************************
+ ***************************** MOTIF *************************
+ *************************************************************/
+
+/* values used in the message type for Motif DND */
+enum {
+    XmTOP_LEVEL_ENTER,
+    XmTOP_LEVEL_LEAVE,
+    XmDRAG_MOTION,
+    XmDROP_SITE_ENTER,
+    XmDROP_SITE_LEAVE,
+    XmDROP_START,
+    XmDROP_FINISH,
+    XmDRAG_DROP_FINISH,
+    XmOPERATION_CHANGED
+};
+
+/* Values used to specify type of protocol to use */
+enum {
+    XmDRAG_NONE,
+    XmDRAG_DROP_ONLY,
+    XmDRAG_PREFER_PREREGISTER,
+    XmDRAG_PREREGISTER,
+    XmDRAG_PREFER_DYNAMIC,
+    XmDRAG_DYNAMIC,
+    XmDRAG_PREFER_RECEIVER
+};
+
+/* Operation codes */
+enum {
+  XmDROP_NOOP,
+  XmDROP_MOVE = 0x01,
+  XmDROP_COPY = 0x02,
+  XmDROP_LINK = 0x04
+};
+
+/* Drop site status */
+enum {
+  XmNO_DROP_SITE = 0x01,
+  XmDROP_SITE_INVALID = 0x02,
+  XmDROP_SITE_VALID = 0x03
+};
+
+/* completion status */
+enum {
+  XmDROP,
+  XmDROP_HELP,
+  XmDROP_CANCEL,
+  XmDROP_INTERRUPT
+};
+
+/* Byte swapping routines. The motif specification leaves it
+ * up to us to save a few bytes in the client messages
+ */
+static gchar local_byte_order = '\0';
+
+#ifdef G_ENABLE_DEBUG
+static void
+print_target_list (GList *targets)
+{
+  while (targets)
+    {
+      gchar *name = gdk_atom_name (GDK_POINTER_TO_ATOM (targets->data));
+      g_message ("\t%s", name);
+      g_free (name);
+      targets = targets->next;
+    }
+}
+#endif /* G_ENABLE_DEBUG */
+
+static void
+init_byte_order (void)
+{
+  guint32 myint = 0x01020304;
+  local_byte_order = (*(gchar *)&myint == 1) ? 'B' : 'l';
+}
+
+static guint16
+card16_to_host (guint16 x, gchar byte_order) {
+  if (byte_order == local_byte_order)
+    return x;
+  else
+    return (x << 8) | (x >> 8);
+}
+
+static guint32
+card32_to_host (guint32 x, gchar byte_order) {
+  if (byte_order == local_byte_order)
+    return x;
+  else
+    return (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
+}
+
+/* Motif packs together fields of varying length into the
+ * client message. We can't rely on accessing these
+ * through data.s[], data.l[], etc, because on some architectures
+ * (i.e., Alpha) these won't be valid for format == 8. 
+ */
+
+#define MOTIF_XCLIENT_BYTE(xevent,i) \
+  (xevent)->xclient.data.b[i]
+#define MOTIF_XCLIENT_SHORT(xevent,i) \
+  ((gint16 *)&((xevent)->xclient.data.b[0]))[i]
+#define MOTIF_XCLIENT_LONG(xevent,i) \
+  ((gint32 *)&((xevent)->xclient.data.b[0]))[i]
+
+#define MOTIF_UNPACK_BYTE(xevent,i) MOTIF_XCLIENT_BYTE(xevent,i)
+#define MOTIF_UNPACK_SHORT(xevent,i) \
+  card16_to_host (MOTIF_XCLIENT_SHORT(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
+#define MOTIF_UNPACK_LONG(xevent,i) \
+  card32_to_host (MOTIF_XCLIENT_LONG(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
+
+/***** Dest side ***********/
+
+/* Property placed on source windows */
+typedef struct _MotifDragInitiatorInfo {
+  guint8 byte_order;
+  guint8 protocol_version;
+  guint16 targets_index;
+  guint32 selection_atom;
+} MotifDragInitiatorInfo;
+
+/* Header for target table on the drag window */
+typedef struct _MotifTargetTableHeader {
+  guchar byte_order;
+  guchar protocol_version;
+  guint16 n_lists;
+  guint32 total_size;
+} MotifTargetTableHeader;
+
+/* Property placed on target windows */
+typedef struct _MotifDragReceiverInfo {
+  guint8 byte_order;
+  guint8 protocol_version;
+  guint8 protocol_style;
+  guint8 pad;
+  guint32 proxy_window;
+  guint16 num_drop_sites;
+  guint16 padding;
+  guint32 total_size;
+} MotifDragReceiverInfo;
+
+/* Target table handling */
+
+static GdkFilterReturn
+motif_drag_window_filter (GdkXEvent *xevent,
+			  GdkEvent  *event,
+			  gpointer data)
+{
+  XEvent *xev = (XEvent *)xevent;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (event->any.window); 
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  switch (xev->xany.type)
+    {
+    case DestroyNotify:
+      display_x11->motif_drag_window = None;
+      display_x11->motif_drag_gdk_window = NULL;
+      break;
+    case PropertyNotify:
+      if (display_x11->motif_target_lists &&
+	  (xev->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS")))
+	motif_read_target_table (display);
+      break;
+    }
+  return GDK_FILTER_REMOVE;
+}
+
+static Window
+motif_lookup_drag_window (GdkDisplay *display,
+			  Display    *lookup_xdisplay)
+{
+  Window retval = None;
+  gulong bytes_after, nitems;
+  Atom type;
+  gint format;
+  guchar *data;
+
+  XGetWindowProperty (lookup_xdisplay, RootWindow (lookup_xdisplay, 0),
+		      gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW"),
+		      0, 1, FALSE,
+		      XA_WINDOW, &type, &format, &nitems, &bytes_after,
+		      &data);
+  
+  if ((format == 32) && (nitems == 1) && (bytes_after == 0))
+    {
+      retval = *(Window *)data;
+      GDK_NOTE (DND, 
+		g_message ("Found drag window %#lx\n", GDK_DISPLAY_X11 (display)->motif_drag_window));
+    }
+
+  if (type != None)
+    XFree (data);
+
+  return retval;
+}
+
+/* Finds the window where global Motif drag information is stored.
+ * If it doesn't exist and 'create' is TRUE, create one.
+ */
+static Window 
+motif_find_drag_window (GdkDisplay *display,
+			gboolean    create)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  
+  if (!display_x11->motif_drag_window)
+    {
+      Atom motif_drag_window_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW");
+      display_x11->motif_drag_window = motif_lookup_drag_window (display, display_x11->xdisplay);
+      
+      if (!display_x11->motif_drag_window && create)
+	{
+	  /* Create a persistant window. (Copied from LessTif) */
+	  
+	  Display *persistant_xdisplay;
+	  XSetWindowAttributes attr;
+	  persistant_xdisplay = XOpenDisplay (gdk_display_get_name (display));
+	  XSetCloseDownMode (persistant_xdisplay, RetainPermanent);
+
+	  XGrabServer (persistant_xdisplay);
+	  
+	  display_x11->motif_drag_window = motif_lookup_drag_window (display, persistant_xdisplay);
+
+	  if (!display_x11->motif_drag_window)
+	    {
+	      attr.override_redirect = True;
+	      attr.event_mask = PropertyChangeMask;
+	      
+	       display_x11->motif_drag_window = 
+		XCreateWindow (persistant_xdisplay, 
+			       RootWindow (persistant_xdisplay, 0),
+			      -100, -100, 10, 10, 0, 0,
+			      InputOnly, (Visual *)CopyFromParent,
+			      (CWOverrideRedirect | CWEventMask), &attr);
+	      
+	      GDK_NOTE (DND,
+			g_message ("Created drag window %#lx\n", display_x11->motif_drag_window));
+	      
+	      XChangeProperty (persistant_xdisplay, 
+			       RootWindow (persistant_xdisplay, 0),
+			       motif_drag_window_atom, XA_WINDOW,
+			       32, PropModeReplace,
+			       (guchar *)&motif_drag_window_atom, 1);
+
+	    }
+	  XUngrabServer (persistant_xdisplay);
+	  XCloseDisplay (persistant_xdisplay);
+	}
+
+      /* There is a miniscule race condition here if the drag window
+       * gets destroyed exactly now.
+       */
+      if (display_x11->motif_drag_window)
+	{
+	  display_x11->motif_drag_gdk_window = 
+	    gdk_window_foreign_new_for_display (display, display_x11->motif_drag_window);
+	  gdk_window_add_filter (display_x11->motif_drag_gdk_window,
+				 motif_drag_window_filter,
+				 NULL);
+	}
+    }
+
+  return display_x11->motif_drag_window;
+}
+
+static void 
+motif_read_target_table (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  gulong bytes_after, nitems;
+  Atom type;
+  gint format;
+  gint i, j;
+  
+  Atom motif_drag_targets_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS");
+
+  if (display_x11->motif_target_lists)
+    {
+      for (i=0; i<display_x11->motif_n_target_lists; i++)
+	g_list_free (display_x11->motif_target_lists[i]);
+      
+      g_free (display_x11->motif_target_lists);
+      display_x11->motif_target_lists = NULL;
+      display_x11->motif_n_target_lists = 0;
+    }
+
+  if (motif_find_drag_window (display, FALSE))
+    {
+      guchar *data;
+      MotifTargetTableHeader *header = NULL;
+      guchar *target_bytes = NULL;
+      guchar *p;
+      gboolean success = FALSE;
+
+      gdk_error_trap_push ();
+      XGetWindowProperty (display_x11->xdisplay, 
+			  display_x11->motif_drag_window, 
+			  motif_drag_targets_atom,
+			  0, (sizeof(MotifTargetTableHeader)+3)/4, FALSE,
+			  motif_drag_targets_atom, 
+			  &type, &format, &nitems, &bytes_after,
+			  &data);
+
+      if (gdk_error_trap_pop () || (format != 8) || (nitems < sizeof (MotifTargetTableHeader)))
+	goto error;
+
+      header = (MotifTargetTableHeader *)data;
+
+      header->n_lists = card16_to_host (header->n_lists, header->byte_order);
+      header->total_size = card32_to_host (header->total_size, header->byte_order);
+
+      gdk_error_trap_push ();
+      XGetWindowProperty (display_x11->xdisplay, 
+			  display_x11->motif_drag_window, 
+		          motif_drag_targets_atom,
+			  (sizeof(MotifTargetTableHeader)+3)/4, 
+			  (header->total_size + 3)/4 - (sizeof(MotifTargetTableHeader) + 3)/4,
+			  FALSE,
+			  motif_drag_targets_atom, &type, &format, &nitems, 
+			  &bytes_after, &target_bytes);
+      
+      if (gdk_error_trap_pop () || (format != 8) || (bytes_after != 0) || 
+	  (nitems != header->total_size - sizeof(MotifTargetTableHeader)))
+	  goto error;
+
+      display_x11->motif_n_target_lists = header->n_lists;
+      display_x11->motif_target_lists = g_new0 (GList *, display_x11->motif_n_target_lists);
+
+      p = target_bytes;
+      for (i=0; i<header->n_lists; i++)
+	{
+	  gint n_targets;
+	  guint32 *targets;
+	  
+	  if (p + sizeof(guint16) - target_bytes > nitems)
+	    goto error;
+
+	  n_targets = card16_to_host (*(gushort *)p, header->byte_order);
+
+	  /* We need to make a copy of the targets, since it may
+	   * be unaligned
+	   */
+	  targets = g_new (guint32, n_targets);
+	  memcpy (targets, p + sizeof(guint16), sizeof(guint32) * n_targets);
+
+	  p +=  sizeof(guint16) + n_targets * sizeof(guint32);
+	  if (p - target_bytes > nitems)
+	    goto error;
+
+	  for (j=0; j<n_targets; j++)
+	    display_x11->motif_target_lists[i] = 
+	      g_list_prepend (display_x11->motif_target_lists[i],
+			      GUINT_TO_POINTER (card32_to_host (targets[j],
+								header->byte_order)));
+	  g_free (targets);
+	  display_x11->motif_target_lists[i] = g_list_reverse (display_x11->motif_target_lists[i]);
+	}
+
+      success = TRUE;
+      
+    error:
+      if (header)
+	XFree (header);
+      
+      if (target_bytes)
+	XFree (target_bytes);
+
+      if (!success)
+	{
+	  if (display_x11->motif_target_lists)
+	    {
+	      g_free (display_x11->motif_target_lists);
+	      display_x11->motif_target_lists = NULL;
+	      display_x11->motif_n_target_lists = 0;
+	    }
+	  g_warning ("Error reading Motif target table\n");
+	}
+    }
+}
+
+static gint
+targets_sort_func (gconstpointer a, gconstpointer b)
+{
+  return (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b)) ?
+    -1 : ((GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b)) ? 1 : 0);
+}
+
+/* Check if given (sorted) list is in the targets table */
+static gint
+motif_target_table_check (GdkDisplay *display,
+			  GList      *sorted)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  GList *tmp_list1, *tmp_list2;
+  gint i;
+
+  for (i=0; i<display_x11->motif_n_target_lists; i++)
+    {
+      tmp_list1 = display_x11->motif_target_lists[i];
+      tmp_list2 = sorted;
+      
+      while (tmp_list1 && tmp_list2)
+	{
+	  if (tmp_list1->data != tmp_list2->data)
+	    break;
+
+	  tmp_list1 = tmp_list1->next;
+	  tmp_list2 = tmp_list2->next;
+	}
+      if (!tmp_list1 && !tmp_list2)	/* Found it */
+	return i;
+    }
+
+  return -1;
+}
+
+static gint
+motif_add_to_target_table (GdkDisplay *display,
+			   GList      *targets) /* targets is list of GdkAtom */
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  GList *sorted = NULL;
+  gint index = -1;
+  gint i;
+  GList *tmp_list;
+  
+  /* make a sorted copy of the list */
+  
+  while (targets)
+    {
+      Atom xatom = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (targets->data));
+      sorted = g_list_insert_sorted (sorted, GUINT_TO_POINTER (xatom), targets_sort_func);
+      targets = targets->next;
+    }
+
+  /* First check if it is there already */
+
+  if (display_x11->motif_target_lists)
+    index = motif_target_table_check (display, sorted);
+
+  /* We need to grab the server while doing this, to ensure
+   * atomiticity. Ugh
+   */
+
+  if (index < 0)
+    {
+      /* We need to make sure that it exists _before_ we grab the
+       * server, since we can't open a new connection after we
+       * grab the server. 
+       */
+      motif_find_drag_window (display, TRUE);
+
+      gdk_x11_display_grab (display);
+      motif_read_target_table (display);
+    
+      /* Check again, in case it was added in the meantime */
+      
+      if (display_x11->motif_target_lists)
+	index = motif_target_table_check (display, sorted);
+
+      if (index < 0)
+	{
+	  guint32 total_size = 0;
+	  guchar *data;
+	  guchar *p;
+	  guint16 *p16;
+	  MotifTargetTableHeader *header;
+	  
+	  if (!display_x11->motif_target_lists)
+	    {
+	      display_x11->motif_target_lists = g_new (GList *, 1);
+	      display_x11->motif_n_target_lists = 1;
+	    }
+	  else
+	    {
+	      display_x11->motif_n_target_lists++;
+	      display_x11->motif_target_lists = g_realloc (display_x11->motif_target_lists,
+							   sizeof(GList *) * display_x11->motif_n_target_lists);
+	    }
+	  display_x11->motif_target_lists[display_x11->motif_n_target_lists - 1] = sorted;
+	  sorted = NULL;
+	  index = display_x11->motif_n_target_lists - 1;
+
+	  total_size = sizeof (MotifTargetTableHeader);
+	  for (i = 0; i < display_x11->motif_n_target_lists ; i++)
+	    total_size += sizeof(guint16) + sizeof(guint32) * g_list_length (display_x11->motif_target_lists[i]);
+
+	  data = g_malloc (total_size);
+
+	  header = (MotifTargetTableHeader *)data;
+	  p = data + sizeof(MotifTargetTableHeader);
+
+	  header->byte_order = local_byte_order;
+	  header->protocol_version = 0;
+	  header->n_lists = display_x11->motif_n_target_lists;
+	  header->total_size = total_size;
+
+	  for (i = 0; i < display_x11->motif_n_target_lists ; i++)
+	    {
+	      guint16 n_targets = g_list_length (display_x11->motif_target_lists[i]);
+	      guint32 *targets = g_new (guint32, n_targets);
+	      guint32 *p32 = targets;
+	      
+	      tmp_list = display_x11->motif_target_lists[i];
+	      while (tmp_list)
+		{
+		  *p32 = GPOINTER_TO_UINT (tmp_list->data);
+		  
+		  tmp_list = tmp_list->next;
+		  p32++;
+		}
+
+	      p16 = (guint16 *)p;
+	      p += sizeof(guint16);
+
+	      memcpy (p, targets, n_targets * sizeof(guint32));
+
+	      *p16 = n_targets;
+	      p += sizeof(guint32) * n_targets;
+	      g_free (targets);
+	    }
+
+	  XChangeProperty (display_x11->xdisplay,
+			   display_x11->motif_drag_window,
+			   gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
+			   gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
+			   8, PropModeReplace,
+			   data, total_size);
+	}
+      gdk_x11_display_ungrab (display);
+    }
+
+  g_list_free (sorted);
+  return index;
+}
+
+/* Translate flags */
+
+static void
+motif_dnd_translate_flags (GdkDragContext *context, guint16 flags)
+{
+  guint recommended_op = flags & 0x000f;
+  guint possible_ops = (flags & 0x0f0) >> 4;
+  
+  switch (recommended_op)
+    {
+    case XmDROP_MOVE:
+      context->suggested_action = GDK_ACTION_MOVE;
+      break;
+    case XmDROP_COPY:
+      context->suggested_action = GDK_ACTION_COPY;
+      break;
+    case XmDROP_LINK:
+      context->suggested_action = GDK_ACTION_LINK;
+      break;
+    default:
+      context->suggested_action = GDK_ACTION_COPY;
+      break;
+    }
+
+  context->actions = 0;
+  if (possible_ops & XmDROP_MOVE)
+    context->actions |= GDK_ACTION_MOVE;
+  if (possible_ops & XmDROP_COPY)
+    context->actions |= GDK_ACTION_COPY;
+  if (possible_ops & XmDROP_LINK)
+    context->actions |= GDK_ACTION_LINK;
+}
+
+static guint16
+motif_dnd_get_flags (GdkDragContext *context)
+{
+  guint16 flags = 0;
+  
+  switch (context->suggested_action)
+    {
+    case GDK_ACTION_MOVE:
+      flags = XmDROP_MOVE;
+      break;
+    case GDK_ACTION_COPY:
+      flags = XmDROP_COPY;
+      break;
+    case GDK_ACTION_LINK:
+      flags = XmDROP_LINK;
+      break;
+    default:
+      flags = XmDROP_NOOP;
+      break;
+    }
+  
+  if (context->actions & GDK_ACTION_MOVE)
+    flags |= XmDROP_MOVE << 8;
+  if (context->actions & GDK_ACTION_COPY)
+    flags |= XmDROP_COPY << 8;
+  if (context->actions & GDK_ACTION_LINK)
+    flags |= XmDROP_LINK << 8;
+
+  return flags;
+}
+
+/* Source Side */
+
+static void
+motif_set_targets (GdkDragContext *context)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  MotifDragInitiatorInfo info;
+  gint i;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  
+  info.byte_order = local_byte_order;
+  info.protocol_version = 0;
+  
+  info.targets_index = motif_add_to_target_table (display, context->targets);
+
+  for (i=0; ; i++)
+    {
+      gchar buf[20];
+      g_snprintf(buf, 20, "_GDK_SELECTION_%d", i);
+      
+      private->motif_selection = gdk_x11_get_xatom_by_name_for_display (display, buf);
+      if (!XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), private->motif_selection))
+	break;
+    }
+
+  info.selection_atom = private->motif_selection;
+
+  XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
+		   GDK_DRAWABLE_XID (context->source_window),
+		   private->motif_selection,
+		   gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
+		   8, PropModeReplace,
+		   (guchar *)&info, sizeof (info));
+
+  private->motif_targets_set = 1;
+}
+
+static guint32
+motif_check_dest (GdkDisplay *display,
+		  Window      win)
+{
+  gboolean retval = FALSE;
+  guchar *data;
+  MotifDragReceiverInfo *info;
+  Atom type = None;
+  int format;
+  unsigned long nitems, after;
+  Atom motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO");
+
+  gdk_error_trap_push ();
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win, 
+		      motif_drag_receiver_info_atom, 
+		      0, (sizeof(*info)+3)/4, False, AnyPropertyType,
+		      &type, &format, &nitems, &after, 
+		      &data);
+
+  if (gdk_error_trap_pop() == 0)
+    {
+      if (type != None)
+	{
+	  info = (MotifDragReceiverInfo *)data;
+	  
+	  if ((format == 8) && (nitems == sizeof(*info)))
+	    {
+	      if ((info->protocol_version == 0) &&
+		  ((info->protocol_style == XmDRAG_PREFER_PREREGISTER) ||
+		   (info->protocol_style == XmDRAG_PREFER_DYNAMIC) ||
+		   (info->protocol_style == XmDRAG_DYNAMIC)))
+		retval = TRUE;
+	    }
+	  else
+	    {
+	      GDK_NOTE (DND, 
+			g_warning ("Invalid Motif drag receiver property on window %ld\n", win));
+	    }
+	  
+	  XFree (info);
+	}
+    }
+
+  return retval ? win : None;
+}
+
+static void
+motif_send_enter (GdkDragContext  *context,
+		  guint32          time)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  XEvent xev;
+
+  if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+    return; /* Motif Dnd requires getting properties on the root window */
+
+  xev.xclient.type = ClientMessage;
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
+  xev.xclient.format = 8;
+  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
+
+  MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_ENTER;
+  MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+  MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
+  MOTIF_XCLIENT_LONG (&xev, 1) = time;
+  MOTIF_XCLIENT_LONG (&xev, 2) = GDK_DRAWABLE_XID (context->source_window);
+
+  if (!private->motif_targets_set)
+    motif_set_targets (context);
+
+  MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
+  MOTIF_XCLIENT_LONG (&xev, 4) = 0;
+
+  if (!_gdk_send_xevent (display,
+			 GDK_DRAWABLE_XID (context->dest_window),
+			 FALSE, 0, &xev))
+    GDK_NOTE (DND, 
+	      g_message ("Send event to %lx failed",
+			 GDK_DRAWABLE_XID (context->dest_window)));
+}
+
+static void
+motif_send_leave (GdkDragContext  *context,
+		  guint32          time)
+{
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  XEvent xev;
+
+  xev.xclient.type = ClientMessage;
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
+  xev.xclient.format = 8;
+  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
+
+  MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_LEAVE;
+  MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+  MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
+  MOTIF_XCLIENT_LONG (&xev, 1) = time;
+  MOTIF_XCLIENT_LONG (&xev, 2) = 0;
+  MOTIF_XCLIENT_LONG (&xev, 3) = 0;
+  MOTIF_XCLIENT_LONG (&xev, 4) = 0;
+
+  if (!_gdk_send_xevent (display,
+			 GDK_DRAWABLE_XID (context->dest_window),
+			 FALSE, 0, &xev))
+    GDK_NOTE (DND, 
+	      g_message ("Send event to %lx failed",
+			 GDK_DRAWABLE_XID (context->dest_window)));
+}
+
+static gboolean
+motif_send_motion (GdkDragContext  *context,
+		    gint            x_root, 
+		    gint            y_root,
+		    GdkDragAction   action,
+		    guint32         time)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  gboolean retval;
+  XEvent xev;
+
+  xev.xclient.type = ClientMessage;
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
+  xev.xclient.format = 8;
+  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
+
+  MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+  MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
+  MOTIF_XCLIENT_LONG (&xev, 1) = time;
+  MOTIF_XCLIENT_LONG (&xev, 3) = 0;
+  MOTIF_XCLIENT_LONG (&xev, 4) = 0;
+
+  if ((context->suggested_action != private->old_action) ||
+      (context->actions != private->old_actions))
+    {
+      MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
+
+      /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
+      retval = TRUE;
+    }
+  else
+    {
+      MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION;
+
+      MOTIF_XCLIENT_SHORT (&xev, 4) = x_root;
+      MOTIF_XCLIENT_SHORT (&xev, 5) = y_root;
+      
+      private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
+      retval = FALSE;
+    }
+
+  if (!_gdk_send_xevent (display,
+			 GDK_DRAWABLE_XID (context->dest_window),
+			 FALSE, 0, &xev))
+    GDK_NOTE (DND, 
+	      g_message ("Send event to %lx failed",
+			 GDK_DRAWABLE_XID (context->dest_window)));
+
+  return retval;
+}
+
+static void
+motif_send_drop (GdkDragContext *context, guint32 time)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  XEvent xev;
+
+  xev.xclient.type = ClientMessage;
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
+  xev.xclient.format = 8;
+  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
+
+  MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START;
+  MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+  MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
+  MOTIF_XCLIENT_LONG (&xev, 1)  = time;
+
+  MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
+  MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
+
+  MOTIF_XCLIENT_LONG (&xev, 3)  = private->motif_selection;
+  MOTIF_XCLIENT_LONG (&xev, 4)  = GDK_DRAWABLE_XID (context->source_window);
+
+  if (!_gdk_send_xevent (display,
+			 GDK_DRAWABLE_XID (context->dest_window),
+			 FALSE, 0, &xev))
+    GDK_NOTE (DND, 
+	      g_message ("Send event to %lx failed",
+			 GDK_DRAWABLE_XID (context->dest_window)));
+}
+
+/* Target Side */
+
+static gboolean
+motif_read_initiator_info (GdkDisplay *display,
+			   Window      source_window, 
+			   Atom        atom,
+			   GList     **targets,
+			   Atom       *selection)
+{
+  GList *tmp_list;
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  guchar *data;
+  MotifDragInitiatorInfo *initiator_info;
+  
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  
+  gdk_error_trap_push ();
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), source_window, atom,
+		      0, sizeof(*initiator_info), FALSE,
+		      gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
+		      &type, &format, &nitems, &bytes_after,
+		      &data);
+
+  if (gdk_error_trap_pop () || (format != 8) || (nitems != sizeof (MotifDragInitiatorInfo)) || (bytes_after != 0))
+    {
+      g_warning ("Error reading initiator info\n");
+      return FALSE;
+    }
+
+  initiator_info = (MotifDragInitiatorInfo *)data;
+
+  motif_read_target_table (display);
+
+  initiator_info->targets_index = 
+    card16_to_host (initiator_info->targets_index, initiator_info->byte_order);
+  initiator_info->selection_atom = 
+    card32_to_host (initiator_info->selection_atom, initiator_info->byte_order);
+  
+  if (initiator_info->targets_index >= display_x11->motif_n_target_lists)
+    {
+      g_warning ("Invalid target index in TOP_LEVEL_ENTER MESSAGE");
+      XFree (initiator_info);
+      return FALSE;
+    }
+
+  tmp_list = g_list_last (display_x11->motif_target_lists[initiator_info->targets_index]);
+
+  *targets = NULL;
+  while (tmp_list)
+    {
+      GdkAtom atom = gdk_x11_xatom_to_atom_for_display (display, GPOINTER_TO_UINT (tmp_list->data));
+      *targets = g_list_prepend (*targets, GDK_ATOM_TO_POINTER (atom));
+      tmp_list = tmp_list->prev;
+    }
+
+#ifdef G_ENABLE_DEBUG
+  if (_gdk_debug_flags & GDK_DEBUG_DND)
+    print_target_list (*targets);
+#endif /* G_ENABLE_DEBUG */
+
+  *selection = initiator_info->selection_atom;
+
+  XFree (initiator_info);
+
+  return TRUE;
+}
+
+static GdkDragContext *
+motif_drag_context_new (GdkWindow *dest_window,
+			guint32    timestamp,
+			guint32    source_window,
+			guint32    atom)
+{
+  GdkDragContext *new_context;
+  GdkDragContextPrivateX11 *private;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  /* FIXME, current_dest_drag really shouldn't be NULL'd
+   * if we error below.
+   */
+  if (display_x11->current_dest_drag != NULL)
+    {
+      if (timestamp >= display_x11->current_dest_drag->start_time)
+	{
+	  g_object_unref (display_x11->current_dest_drag);
+	  display_x11->current_dest_drag = NULL;
+	}
+      else
+	return NULL;
+    }
+
+  new_context = gdk_drag_context_new ();
+  private = PRIVATE_DATA (new_context);
+
+  new_context->protocol = GDK_DRAG_PROTO_MOTIF;
+  new_context->is_source = FALSE;
+
+  new_context->source_window = gdk_window_lookup_for_display (display, source_window);
+  if (new_context->source_window)
+    g_object_ref (new_context->source_window);
+  else
+    {
+      new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
+      if (!new_context->source_window)
+	{
+	  g_object_unref (new_context);
+	  return NULL;
+	}
+    }
+
+  new_context->dest_window = dest_window;
+  g_object_ref (dest_window);
+  new_context->start_time = timestamp;
+
+  if (!motif_read_initiator_info (GDK_WINDOW_DISPLAY (dest_window),
+				  source_window,
+				  atom,
+				  &new_context->targets,
+				  &private->motif_selection))
+    {
+      g_object_unref (new_context);
+      return NULL;
+    }
+
+  return new_context;
+}
+
+/*
+ * The MOTIF drag protocol has no real provisions for distinguishing
+ * multiple simultaneous drops. If the sources grab the pointer
+ * when doing drags, that shouldn't happen, in any case. If it
+ * does, we can't do much except hope for the best.
+ */
+
+static GdkFilterReturn
+motif_top_level_enter (GdkEvent *event,
+		       guint16   flags, 
+		       guint32   timestamp, 
+		       guint32   source_window, 
+		       guint32   atom)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (event->any.window));
+  GdkDragContext *new_context;
+
+  GDK_NOTE(DND, g_message ("Motif DND top level enter: flags: %#4x time: %d source_widow: %#4x atom: %d",
+			   flags, timestamp, source_window, atom));
+
+  new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
+  if (!new_context)
+    return GDK_FILTER_REMOVE;
+
+  event->dnd.type = GDK_DRAG_ENTER;
+  event->dnd.context = new_context;
+  g_object_ref (new_context);
+
+  display_x11->current_dest_drag = new_context;
+
+  return GDK_FILTER_TRANSLATE;
+}
+
+static GdkFilterReturn
+motif_top_level_leave (GdkEvent *event,
+		       guint16   flags, 
+		       guint32   timestamp)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (event->any.window));
+
+  GDK_NOTE(DND, g_message ("Motif DND top level leave: flags: %#4x time: %d",
+			   flags, timestamp));
+
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
+      (timestamp >= display_x11->current_dest_drag->start_time))
+    {
+      event->dnd.type = GDK_DRAG_LEAVE;
+      /* Pass ownership of context to the event */
+      event->dnd.context = display_x11->current_dest_drag;
+
+      display_x11->current_dest_drag = NULL;
+
+      return GDK_FILTER_TRANSLATE;
+    }
+  else
+    return GDK_FILTER_REMOVE;
+}
+
+static GdkFilterReturn
+motif_motion (GdkEvent *event,
+	      guint16   flags, 
+	      guint32   timestamp,
+	      gint16    x_root,
+	      gint16    y_root)
+{
+  GdkDragContextPrivateX11 *private;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (event->any.window));
+  
+  GDK_NOTE(DND, g_message ("Motif DND motion: flags: %#4x time: %d (%d, %d)",
+			   flags, timestamp, x_root, y_root));
+
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
+      (timestamp >= display_x11->current_dest_drag->start_time))
+    {
+      private = PRIVATE_DATA (display_x11->current_dest_drag);
+
+      event->dnd.type = GDK_DRAG_MOTION;
+      event->dnd.context = display_x11->current_dest_drag;
+      g_object_ref (display_x11->current_dest_drag);
+
+      event->dnd.time = timestamp;
+
+      motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
+
+      event->dnd.x_root = x_root;
+      event->dnd.y_root = y_root;
+
+      private->last_x = x_root;
+      private->last_y = y_root;
+
+      private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
+
+      return GDK_FILTER_TRANSLATE;
+    }
+
+  return GDK_FILTER_REMOVE;
+}
+
+static GdkFilterReturn
+motif_operation_changed (GdkEvent *event,
+			 guint16   flags, 
+			 guint32   timestamp)
+{
+  GdkDragContextPrivateX11 *private;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (event->any.window));
+  GDK_NOTE(DND, g_message ("Motif DND operation changed: flags: %#4x time: %d",
+			   flags, timestamp));
+
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
+      (timestamp >= display_x11->current_dest_drag->start_time))
+    {
+      event->dnd.type = GDK_DRAG_MOTION;
+      event->dnd.send_event = FALSE;
+      event->dnd.context = display_x11->current_dest_drag;
+      g_object_ref (display_x11->current_dest_drag);
+
+      event->dnd.time = timestamp;
+      private = PRIVATE_DATA (display_x11->current_dest_drag);
+
+      motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
+
+      event->dnd.x_root = private->last_x;
+      event->dnd.y_root = private->last_y;
+
+      private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
+
+      return GDK_FILTER_TRANSLATE;
+    }
+
+  return GDK_FILTER_REMOVE;
+}
+
+static GdkFilterReturn
+motif_drop_start (GdkEvent *event,
+		  guint16   flags,
+		  guint32   timestamp,
+		  guint32   source_window,
+		  guint32   atom,
+		  gint16    x_root,
+		  gint16    y_root)
+{
+  GdkDragContext *new_context;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (event->any.window));
+
+  GDK_NOTE(DND, g_message ("Motif DND drop start: flags: %#4x time: %d (%d, %d) source_widow: %#4x atom: %d",
+			   flags, timestamp, x_root, y_root, source_window, atom));
+
+  new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
+  if (!new_context)
+    return GDK_FILTER_REMOVE;
+
+  motif_dnd_translate_flags (new_context, flags);
+
+  event->dnd.type = GDK_DROP_START;
+  event->dnd.context = new_context;
+  event->dnd.time = timestamp;
+  event->dnd.x_root = x_root;
+  event->dnd.y_root = y_root;
+
+  gdk_x11_window_set_user_time (event->any.window, timestamp);
+
+  g_object_ref (new_context);
+  display_x11->current_dest_drag = new_context;
+
+  return GDK_FILTER_TRANSLATE;
+}  
+
+static GdkFilterReturn
+motif_drag_status (GdkEvent *event,
+		   guint16   flags,
+		   guint32   timestamp)
+{
+  GdkDragContext *context;
+  GdkDisplay *display;
+  
+  GDK_NOTE (DND, 
+	    g_message ("Motif status message: flags %x", flags));
+
+  display = gdk_window_get_display (event->any.window);
+  if (!display)
+    return GDK_FILTER_REMOVE;
+  
+  context = gdk_drag_context_find (display, TRUE, GDK_DRAWABLE_XID (event->any.window), None);
+
+  if (context)
+    {
+      GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+      if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
+	  (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
+	private->drag_status = GDK_DRAG_STATUS_DRAG;
+      
+      event->dnd.type = GDK_DRAG_STATUS;
+      event->dnd.send_event = FALSE;
+      event->dnd.context = context;
+      g_object_ref (context);
+
+      event->dnd.time = timestamp;
+
+      if ((flags & 0x00f0) >> 4 == XmDROP_SITE_VALID)
+	{
+	  switch (flags & 0x000f)
+	    {
+	    case XmDROP_NOOP:
+	      context->action = 0;
+	      break;
+	    case XmDROP_MOVE:
+		context->action = GDK_ACTION_MOVE;
+		break;
+	    case XmDROP_COPY:
+	      context->action = GDK_ACTION_COPY;
+	      break;
+	    case XmDROP_LINK:
+	      context->action = GDK_ACTION_LINK;
+	      break;
+	    }
+	}
+      else
+	context->action = 0;
+
+      return GDK_FILTER_TRANSLATE;
+    }
+  return GDK_FILTER_REMOVE;
+}
+
+static GdkFilterReturn
+motif_dnd_filter (GdkXEvent *xev,
+		  GdkEvent  *event,
+		  gpointer data)
+{
+  XEvent *xevent = (XEvent *)xev;
+
+  guint8 reason;
+  guint16 flags;
+  guint32 timestamp;
+  guint32 source_window;
+  Atom atom;
+  gint16 x_root, y_root;
+  gboolean is_reply;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;			/* Not for us */
+  
+  /* First read some fields common to all Motif DND messages */
+
+  reason = MOTIF_UNPACK_BYTE (xevent, 0);
+  flags = MOTIF_UNPACK_SHORT (xevent, 1);
+  timestamp = MOTIF_UNPACK_LONG (xevent, 1);
+
+  is_reply = ((reason & 0x80) != 0);
+
+  switch (reason & 0x7f)
+    {
+    case XmTOP_LEVEL_ENTER:
+      source_window = MOTIF_UNPACK_LONG (xevent, 2);
+      atom = MOTIF_UNPACK_LONG (xevent, 3);
+      return motif_top_level_enter (event, flags, timestamp, source_window, atom);
+    case XmTOP_LEVEL_LEAVE:
+      return motif_top_level_leave (event, flags, timestamp);
+
+    case XmDRAG_MOTION:
+      x_root = MOTIF_UNPACK_SHORT (xevent, 4);
+      y_root = MOTIF_UNPACK_SHORT (xevent, 5);
+      
+      if (!is_reply)
+	return motif_motion (event, flags, timestamp, x_root, y_root);
+      else
+	return motif_drag_status (event, flags, timestamp);
+
+    case XmDROP_SITE_ENTER:
+      return motif_drag_status (event, flags, timestamp);
+
+    case XmDROP_SITE_LEAVE:
+      return motif_drag_status (event,
+				XmNO_DROP_SITE << 8 | XmDROP_NOOP, 
+				timestamp);
+    case XmDROP_START:
+      x_root = MOTIF_UNPACK_SHORT (xevent, 4);
+      y_root = MOTIF_UNPACK_SHORT (xevent, 5);
+      atom = MOTIF_UNPACK_LONG (xevent, 3);
+      source_window = MOTIF_UNPACK_LONG (xevent, 4);
+
+      if (!is_reply)
+	return motif_drop_start (event, flags, timestamp, source_window, atom, x_root, y_root);
+      
+     break;
+    case XmOPERATION_CHANGED:
+      if (!is_reply)
+	return motif_operation_changed (event, flags, timestamp);
+      else
+	return motif_drag_status (event, flags, timestamp);
+
+      break;
+      /* To the best of my knowledge, these next two messages are 
+       * not part of the protocol, though they are defined in
+       * the header files.
+       */
+    case XmDROP_FINISH:
+    case XmDRAG_DROP_FINISH:
+      break;
+    }
+
+  return GDK_FILTER_REMOVE;
+}
+
+/*************************************************************
+ ***************************** XDND **************************
+ *************************************************************/
+
+/* Utility functions */
+
+static struct {
+  const gchar *name;
+  GdkAtom atom;
+  GdkDragAction action;
+} xdnd_actions_table[] = {
+    { "XdndActionCopy",    None, GDK_ACTION_COPY },
+    { "XdndActionMove",    None, GDK_ACTION_MOVE },
+    { "XdndActionLink",    None, GDK_ACTION_LINK },
+    { "XdndActionAsk",     None, GDK_ACTION_ASK  },
+    { "XdndActionPrivate", None, GDK_ACTION_COPY },
+  };
+
+static const gint xdnd_n_actions = sizeof(xdnd_actions_table) / sizeof(xdnd_actions_table[0]);
+static gboolean xdnd_actions_initialized = FALSE;
+
+static void
+xdnd_initialize_actions (void)
+{
+  gint i;
+  
+  xdnd_actions_initialized = TRUE;
+  for (i=0; i < xdnd_n_actions; i++)
+    xdnd_actions_table[i].atom = gdk_atom_intern_static_string (xdnd_actions_table[i].name);
+}
+
+static GdkDragAction
+xdnd_action_from_atom (GdkDisplay *display,
+		       Atom        xatom)
+{
+  GdkAtom atom;
+  gint i;
+
+  if (xatom == None)
+    return 0;
+
+  atom = gdk_x11_xatom_to_atom_for_display (display, xatom);
+
+  if (!xdnd_actions_initialized)
+    xdnd_initialize_actions();
+
+  for (i=0; i<xdnd_n_actions; i++)
+    if (atom == xdnd_actions_table[i].atom)
+      return xdnd_actions_table[i].action;
+
+  return 0;
+}
+
+static Atom
+xdnd_action_to_atom (GdkDisplay    *display,
+		     GdkDragAction  action)
+{
+  gint i;
+
+  if (!xdnd_actions_initialized)
+    xdnd_initialize_actions();
+
+  for (i=0; i<xdnd_n_actions; i++)
+    if (action == xdnd_actions_table[i].action)
+      return gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
+
+  return None;
+}
+
+/* Source side */
+
+static GdkFilterReturn 
+xdnd_status_filter (GdkXEvent *xev,
+		    GdkEvent  *event,
+		    gpointer   data)
+{
+  GdkDisplay *display;
+  XEvent *xevent = (XEvent *)xev;
+  guint32 dest_window = xevent->xclient.data.l[0];
+  guint32 flags = xevent->xclient.data.l[1];
+  Atom action = xevent->xclient.data.l[4];
+  GdkDragContext *context;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;			/* Not for us */
+  
+  GDK_NOTE (DND, 
+	    g_message ("XdndStatus: dest_window: %#x  action: %ld",
+		       dest_window, action));
+
+  display = gdk_window_get_display (event->any.window);
+  context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
+  
+  if (context)
+    {
+      GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+      if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+	private->drag_status = GDK_DRAG_STATUS_DRAG;
+      
+      event->dnd.send_event = FALSE;
+      event->dnd.type = GDK_DRAG_STATUS;
+      event->dnd.context = context;
+      gdk_event_set_device (event, gdk_drag_context_get_device (context));
+      g_object_ref (context);
+
+      event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+      if (!(action != 0) != !(flags & 1))
+	{
+	  GDK_NOTE (DND,
+		    g_warning ("Received status event with flags not corresponding to action!\n"));
+	  action = 0;
+	}
+
+      context->action = xdnd_action_from_atom (display, action);
+
+      return GDK_FILTER_TRANSLATE;
+    }
+
+  return GDK_FILTER_REMOVE;
+}
+
+static GdkFilterReturn 
+xdnd_finished_filter (GdkXEvent *xev,
+		      GdkEvent  *event,
+		      gpointer   data)
+{
+  GdkDisplay *display;
+  XEvent *xevent = (XEvent *)xev;
+  guint32 dest_window = xevent->xclient.data.l[0];
+  GdkDragContext *context;
+  GdkDragContextPrivateX11 *private;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;			/* Not for us */
+  
+  GDK_NOTE (DND, 
+	    g_message ("XdndFinished: dest_window: %#x", dest_window));
+
+  display = gdk_window_get_display (event->any.window);
+  context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
+  
+  if (context)
+    {
+      private = PRIVATE_DATA (context);
+      if (private->version == 5)
+	private->drop_failed = xevent->xclient.data.l[1] == 0;
+      
+      event->dnd.type = GDK_DROP_FINISHED;
+      event->dnd.context = context;
+      gdk_event_set_device (event, gdk_drag_context_get_device (context));
+      g_object_ref (context);
+
+      event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+
+      return GDK_FILTER_TRANSLATE;
+    }
+
+  return GDK_FILTER_REMOVE;
+}
+
+static void
+xdnd_set_targets (GdkDragContext *context)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  Atom *atomlist;
+  GList *tmp_list = context->targets;
+  gint i;
+  gint n_atoms = g_list_length (context->targets);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+
+  atomlist = g_new (Atom, n_atoms);
+  i = 0;
+  while (tmp_list)
+    {
+      atomlist[i] = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (tmp_list->data));
+      tmp_list = tmp_list->next;
+      i++;
+    }
+
+  XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
+		   GDK_DRAWABLE_XID (context->source_window),
+		   gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
+		   XA_ATOM, 32, PropModeReplace,
+		   (guchar *)atomlist, n_atoms);
+
+  g_free (atomlist);
+
+  private->xdnd_targets_set = 1;
+}
+
+static void
+xdnd_set_actions (GdkDragContext *context)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  Atom *atomlist;
+  gint i;
+  gint n_atoms;
+  guint actions;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+
+  if (!xdnd_actions_initialized)
+    xdnd_initialize_actions();
+  
+  actions = context->actions;
+  n_atoms = 0;
+  for (i=0; i<xdnd_n_actions; i++)
+    {
+      if (actions & xdnd_actions_table[i].action)
+	{
+	  actions &= ~xdnd_actions_table[i].action;
+	  n_atoms++;
+	}
+    }
+
+  atomlist = g_new (Atom, n_atoms);
+
+  actions = context->actions;
+  n_atoms = 0;
+  for (i=0; i<xdnd_n_actions; i++)
+    {
+      if (actions & xdnd_actions_table[i].action)
+	{
+	  actions &= ~xdnd_actions_table[i].action;
+	  atomlist[n_atoms] = gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
+	  n_atoms++;
+	}
+    }
+
+  XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
+		   GDK_DRAWABLE_XID (context->source_window),
+		   gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
+		   XA_ATOM, 32, PropModeReplace,
+		   (guchar *)atomlist, n_atoms);
+
+  g_free (atomlist);
+
+  private->xdnd_actions_set = TRUE;
+  private->xdnd_actions = context->actions;
+}
+
+static void
+send_client_message_async_cb (Window   window,
+			      gboolean success,
+			      gpointer data)
+{
+  GdkDragContext *context = data;
+  GDK_NOTE (DND,
+	    g_message ("Got async callback for #%lx, success = %d",
+		       window, success));
+
+  /* On failure, we immediately continue with the protocol
+   * so we don't end up blocking for a timeout
+   */
+  if (!success &&
+      context->dest_window &&
+      window == GDK_WINDOW_XID (context->dest_window))
+    {
+      GdkEvent *temp_event;
+      GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+
+      g_object_unref (context->dest_window);
+      context->dest_window = NULL;
+      context->action = 0;
+
+      private->drag_status = GDK_DRAG_STATUS_DRAG;
+
+      temp_event = gdk_event_new (GDK_DRAG_STATUS);
+      temp_event->dnd.window = g_object_ref (context->source_window);
+      temp_event->dnd.send_event = TRUE;
+      temp_event->dnd.context = g_object_ref (context);
+      temp_event->dnd.time = GDK_CURRENT_TIME;
+      gdk_event_set_device (temp_event, gdk_drag_context_get_device (context));
+
+      gdk_event_put (temp_event);
+
+      gdk_event_free (temp_event);
+    }
+
+  g_object_unref (context);
+}
+
+
+static GdkDisplay *
+gdk_drag_context_get_display (GdkDragContext *context)
+{
+  if (context->source_window)
+    return GDK_WINDOW_DISPLAY (context->source_window);
+  else if (context->dest_window)
+    return GDK_WINDOW_DISPLAY (context->dest_window);
+
+  g_assert_not_reached ();
+  return NULL;
+}
+
+static void
+send_client_message_async (GdkDragContext      *context,
+			   Window               window, 
+			   gboolean             propagate,
+			   glong                event_mask,
+			   XClientMessageEvent *event_send)
+{
+  GdkDisplay *display = gdk_drag_context_get_display (context);
+  
+  g_object_ref (context);
+
+  _gdk_x11_send_client_message_async (display, window,
+				      propagate, event_mask, event_send,
+				      send_client_message_async_cb, context);
+}
+
+static gboolean
+xdnd_send_xevent (GdkDragContext *context,
+		  GdkWindow      *window, 
+		  gboolean        propagate,
+		  XEvent         *event_send)
+{
+  GdkDisplay *display = gdk_drag_context_get_display (context);
+  Window xwindow;
+  glong event_mask;
+
+  g_assert (event_send->xany.type == ClientMessage);
+
+  /* We short-circuit messages to ourselves */
+  if (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
+    {
+      gint i;
+      
+      for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
+	{
+	  if (gdk_x11_get_xatom_by_name_for_display (display, xdnd_filters[i].atom_name) ==
+	      event_send->xclient.message_type)
+	    {
+	      GdkEvent *temp_event;
+
+              temp_event = gdk_event_new (GDK_NOTHING);
+              temp_event->any.window = g_object_ref (window);
+
+	      if ((*xdnd_filters[i].func) (event_send, temp_event, NULL) == GDK_FILTER_TRANSLATE)
+		{
+		  gdk_event_put (temp_event);
+                  gdk_event_free (temp_event);
+		}
+	      
+	      return TRUE;
+	    }
+	}
+    }
+
+  xwindow = GDK_WINDOW_XWINDOW (window);
+  
+  if (_gdk_x11_display_is_root_window (display, xwindow))
+    event_mask = ButtonPressMask;
+  else
+    event_mask = 0;
+  
+  send_client_message_async (context, xwindow, propagate, event_mask,
+			     &event_send->xclient);
+
+  return TRUE;
+}
+ 
+static void
+xdnd_send_enter (GdkDragContext *context)
+{
+  XEvent xev;
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->dest_window);
+
+  xev.xclient.type = ClientMessage;
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndEnter");
+  xev.xclient.format = 32;
+  xev.xclient.window = private->drop_xid ? 
+                           private->drop_xid : 
+                           GDK_DRAWABLE_XID (context->dest_window);
+  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
+  xev.xclient.data.l[1] = (private->version << 24); /* version */
+  xev.xclient.data.l[2] = 0;
+  xev.xclient.data.l[3] = 0;
+  xev.xclient.data.l[4] = 0;
+
+  GDK_NOTE(DND,
+	   g_message ("Sending enter source window %#lx XDND protocol version %d\n",
+		      GDK_DRAWABLE_XID (context->source_window), private->version));
+  if (g_list_length (context->targets) > 3)
+    {
+      if (!private->xdnd_targets_set)
+	xdnd_set_targets (context);
+      xev.xclient.data.l[1] |= 1;
+    }
+  else
+    {
+      GList *tmp_list = context->targets;
+      gint i = 2;
+
+      while (tmp_list)
+	{
+	  xev.xclient.data.l[i] = gdk_x11_atom_to_xatom_for_display (display,
+								     GDK_POINTER_TO_ATOM (tmp_list->data));
+	  tmp_list = tmp_list->next;
+	  i++;
+	}
+    }
+
+  if (!xdnd_send_xevent (context, context->dest_window,
+			 FALSE, &xev))
+    {
+      GDK_NOTE (DND, 
+		g_message ("Send event to %lx failed",
+			   GDK_DRAWABLE_XID (context->dest_window)));
+      g_object_unref (context->dest_window);
+      context->dest_window = NULL;
+    }
+}
+
+static void
+xdnd_send_leave (GdkDragContext *context)
+{
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  XEvent xev;
+
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+
+  xev.xclient.type = ClientMessage;
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndLeave");
+  xev.xclient.format = 32;
+  xev.xclient.window = private->drop_xid ? 
+                           private->drop_xid : 
+                           GDK_DRAWABLE_XID (context->dest_window);
+  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
+  xev.xclient.data.l[1] = 0;
+  xev.xclient.data.l[2] = 0;
+  xev.xclient.data.l[3] = 0;
+  xev.xclient.data.l[4] = 0;
+
+  if (!xdnd_send_xevent (context, context->dest_window,
+			 FALSE, &xev))
+    {
+      GDK_NOTE (DND, 
+		g_message ("Send event to %lx failed",
+			   GDK_DRAWABLE_XID (context->dest_window)));
+      g_object_unref (context->dest_window);
+      context->dest_window = NULL;
+    }
+}
+
+static void
+xdnd_send_drop (GdkDragContext *context, guint32 time)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  XEvent xev;
+
+  xev.xclient.type = ClientMessage;
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndDrop");
+  xev.xclient.format = 32;
+  xev.xclient.window = private->drop_xid ? 
+                           private->drop_xid : 
+                           GDK_DRAWABLE_XID (context->dest_window);
+  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
+  xev.xclient.data.l[1] = 0;
+  xev.xclient.data.l[2] = time;
+  xev.xclient.data.l[3] = 0;
+  xev.xclient.data.l[4] = 0;
+
+  if (!xdnd_send_xevent (context, context->dest_window,
+			 FALSE, &xev))
+    {
+      GDK_NOTE (DND, 
+		g_message ("Send event to %lx failed",
+			   GDK_DRAWABLE_XID (context->dest_window)));
+      g_object_unref (context->dest_window);
+      context->dest_window = NULL;
+    }
+}
+
+static void
+xdnd_send_motion (GdkDragContext *context,
+		  gint            x_root, 
+		  gint            y_root,
+		  GdkDragAction   action,
+		  guint32         time)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  XEvent xev;
+
+  xev.xclient.type = ClientMessage;
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndPosition");
+  xev.xclient.format = 32;
+  xev.xclient.window = private->drop_xid ? 
+                           private->drop_xid : 
+                           GDK_DRAWABLE_XID (context->dest_window);
+  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
+  xev.xclient.data.l[1] = 0;
+  xev.xclient.data.l[2] = (x_root << 16) | y_root;
+  xev.xclient.data.l[3] = time;
+  xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
+
+  if (!xdnd_send_xevent (context, context->dest_window,
+			 FALSE, &xev))
+    {
+      GDK_NOTE (DND, 
+		g_message ("Send event to %lx failed",
+			   GDK_DRAWABLE_XID (context->dest_window)));
+      g_object_unref (context->dest_window);
+      context->dest_window = NULL;
+    }
+  private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
+}
+
+static guint32
+xdnd_check_dest (GdkDisplay *display,
+		 Window      win,
+		 guint      *xdnd_version)
+{
+  gboolean retval = FALSE;
+  Atom type = None;
+  int format;
+  unsigned long nitems, after;
+  guchar *data;
+  Atom *version;
+  Window *proxy_data;
+  Window proxy;
+  Atom xdnd_proxy_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndProxy");
+  Atom xdnd_aware_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndAware");
+
+  proxy = None;
+
+  gdk_error_trap_push ();
+  
+  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win, 
+			  xdnd_proxy_atom, 0, 
+			  1, False, AnyPropertyType,
+			  &type, &format, &nitems, &after, 
+			  &data) == Success)
+    {
+      if (type != None)
+	{
+	  proxy_data = (Window *)data;
+	  
+	  if ((format == 32) && (nitems == 1))
+	    {
+	      proxy = *proxy_data;
+	    }
+	  else
+	    GDK_NOTE (DND, 
+		      g_warning ("Invalid XdndProxy "
+				 "property on window %ld\n", win));
+	  
+	  XFree (proxy_data);
+	}
+      
+      if ((XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), proxy ? proxy : win,
+			       xdnd_aware_atom, 0, 
+			       1, False, AnyPropertyType,
+			       &type, &format, &nitems, &after, 
+			       &data) == Success) &&
+	  type != None)
+	{
+	  version = (Atom *)data;
+	  
+	  if ((format == 32) && (nitems == 1))
+	    {
+	      if (*version >= 3)
+		retval = TRUE;
+	      if (xdnd_version)
+		*xdnd_version = *version;
+	    }
+	  else
+	    GDK_NOTE (DND, 
+		      g_warning ("Invalid XdndAware "
+				 "property on window %ld\n", win));
+	  
+	  XFree (version);
+	}
+    }
+
+  gdk_error_trap_pop_ignored ();
+  
+  return retval ? (proxy ? proxy : win) : None;
+}
+
+/* Target side */
+
+static void
+xdnd_read_actions (GdkDragContext *context)
+{
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  Atom type;
+  int format;
+  gulong nitems, after;
+  guchar *data;
+  Atom *atoms;
+
+  gint i;
+  
+  PRIVATE_DATA (context)->xdnd_have_actions = FALSE;
+
+  if (gdk_window_get_window_type (context->source_window) == GDK_WINDOW_FOREIGN)
+    {
+      /* Get the XdndActionList, if set */
+      
+      gdk_error_trap_push ();
+      
+      if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+			      GDK_DRAWABLE_XID (context->source_window),
+			      gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
+			      0, 65536,
+			      False, XA_ATOM, &type, &format, &nitems,
+			      &after, &data) == Success &&
+	  type == XA_ATOM)
+	{
+	  atoms = (Atom *)data;
+	  
+	  context->actions = 0;
+	  
+	  for (i=0; i<nitems; i++)
+	    context->actions |= xdnd_action_from_atom (display, atoms[i]);
+	  
+	  PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
+	  
+#ifdef G_ENABLE_DEBUG
+	  if (_gdk_debug_flags & GDK_DEBUG_DND)
+	    {
+	      GString *action_str = g_string_new (NULL);
+	      if (context->actions & GDK_ACTION_MOVE)
+		g_string_append(action_str, "MOVE ");
+	      if (context->actions & GDK_ACTION_COPY)
+		g_string_append(action_str, "COPY ");
+	      if (context->actions & GDK_ACTION_LINK)
+		g_string_append(action_str, "LINK ");
+	      if (context->actions & GDK_ACTION_ASK)
+		g_string_append(action_str, "ASK ");
+	      
+	      g_message("Xdnd actions = %s", action_str->str);
+	      g_string_free (action_str, TRUE);
+	    }
+#endif /* G_ENABLE_DEBUG */
+	  
+	}
+
+      if (data)
+	XFree (data);
+      
+      gdk_error_trap_pop_ignored ();
+    }
+  else
+    {
+      /* Local drag
+       */
+      GdkDragContext *source_context;
+
+      source_context = gdk_drag_context_find (display, TRUE,
+					      GDK_DRAWABLE_XID (context->source_window),
+					      GDK_DRAWABLE_XID (context->dest_window));
+
+      if (source_context)
+	{
+	  context->actions = source_context->actions;
+	  PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
+	}
+    }
+}
+
+/* We have to make sure that the XdndActionList we keep internally
+ * is up to date with the XdndActionList on the source window
+ * because we get no notification, because Xdnd wasn't meant
+ * to continually send actions. So we select on PropertyChangeMask
+ * and add this filter.
+ */
+static GdkFilterReturn 
+xdnd_source_window_filter (GdkXEvent *xev,
+			   GdkEvent  *event,
+			   gpointer   cb_data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  GdkDragContext *context = cb_data;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY(event->any.window);
+
+  if ((xevent->xany.type == PropertyNotify) &&
+      (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList")))
+    {
+      xdnd_read_actions (context);
+
+      return GDK_FILTER_REMOVE;
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+xdnd_manage_source_filter (GdkDragContext *context,
+			   GdkWindow      *window,
+			   gboolean        add_filter)
+{
+  if (!GDK_WINDOW_DESTROYED (window) &&
+      gdk_window_get_window_type (window) == GDK_WINDOW_FOREIGN)
+    {
+      gdk_error_trap_push ();
+
+      if (add_filter)
+	{
+	  gdk_window_set_events (window,
+				 gdk_window_get_events (window) |
+				 GDK_PROPERTY_CHANGE_MASK);
+	  gdk_window_add_filter (window, xdnd_source_window_filter, context);
+	}
+      else
+	{
+	  gdk_window_remove_filter (window,
+				    xdnd_source_window_filter,
+				    context);
+	  /* Should we remove the GDK_PROPERTY_NOTIFY mask?
+	   * but we might want it for other reasons. (Like
+	   * INCR selection transactions).
+	   */
+	}
+      
+      gdk_error_trap_pop_ignored ();  
+    }
+}
+
+static void
+base_precache_atoms (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (!display_x11->base_dnd_atoms_precached)
+    {
+      static const char *const precache_atoms[] = {
+	"ENLIGHTENMENT_DESKTOP",
+	"WM_STATE",
+	"XdndAware",
+	"XdndProxy",
+	"_MOTIF_DRAG_RECEIVER_INFO"
+      };
+
+      _gdk_x11_precache_atoms (display,
+			       precache_atoms, G_N_ELEMENTS (precache_atoms));
+
+      display_x11->base_dnd_atoms_precached = TRUE;
+    }
+}
+
+static void
+xdnd_precache_atoms (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (!display_x11->xdnd_atoms_precached)
+    {
+      static const char *const precache_atoms[] = {
+	"XdndActionAsk",
+	"XdndActionCopy",
+	"XdndActionLink",
+	"XdndActionList",
+	"XdndActionMove",
+	"XdndActionPrivate",
+	"XdndDrop",
+	"XdndEnter",
+	"XdndFinished",
+	"XdndLeave",
+	"XdndPosition",
+	"XdndSelection",
+	"XdndStatus",
+	"XdndTypeList"
+      };
+
+      _gdk_x11_precache_atoms (display,
+			       precache_atoms, G_N_ELEMENTS (precache_atoms));
+
+      display_x11->xdnd_atoms_precached = TRUE;
+    }
+}
+
+static GdkFilterReturn 
+xdnd_enter_filter (GdkXEvent *xev,
+		   GdkEvent  *event,
+		   gpointer   cb_data)
+{
+  GdkDeviceManager *device_manager;
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+  XEvent *xevent = (XEvent *)xev;
+  GdkDragContext *new_context;
+  gint i;
+  
+  Atom type;
+  int format;
+  gulong nitems, after;
+  guchar *data;
+  Atom *atoms;
+
+  guint32 source_window;
+  gboolean get_types;
+  gint version;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;			/* Not for us */
+
+  source_window = xevent->xclient.data.l[0];
+  get_types = ((xevent->xclient.data.l[1] & 1) != 0);
+  version = (xevent->xclient.data.l[1] & 0xff000000) >> 24;
+  
+  display = GDK_WINDOW_DISPLAY (event->any.window);
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  xdnd_precache_atoms (display);
+
+  GDK_NOTE (DND, 
+	    g_message ("XdndEnter: source_window: %#x, version: %#x",
+		       source_window, version));
+
+  if (version < 3)
+    {
+      /* Old source ignore */
+      GDK_NOTE (DND, g_message ("Ignored old XdndEnter message"));
+      return GDK_FILTER_REMOVE;
+    }
+  
+  if (display_x11->current_dest_drag != NULL)
+    {
+      g_object_unref (display_x11->current_dest_drag);
+      display_x11->current_dest_drag = NULL;
+    }
+
+  new_context = gdk_drag_context_new ();
+  new_context->protocol = GDK_DRAG_PROTO_XDND;
+  PRIVATE_DATA(new_context)->version = version;
+
+  /* FIXME: Should extend DnD protocol to have device info */
+  device_manager = gdk_display_get_device_manager (display);
+  gdk_drag_context_set_device (new_context, gdk_device_manager_get_client_pointer (device_manager));
+
+  new_context->source_window = gdk_window_lookup_for_display (display, source_window);
+  if (new_context->source_window)
+    g_object_ref (new_context->source_window);
+  else
+    {
+      new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
+      if (!new_context->source_window)
+	{
+	  g_object_unref (new_context);
+	  return GDK_FILTER_REMOVE;
+	}
+    }
+  new_context->dest_window = event->any.window;
+  g_object_ref (new_context->dest_window);
+
+  new_context->targets = NULL;
+  if (get_types)
+    {
+      gdk_error_trap_push ();
+      XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (event->any.window), 
+			  source_window, 
+			  gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
+			  0, 65536,
+			  False, XA_ATOM, &type, &format, &nitems,
+			  &after, &data);
+
+      if (gdk_error_trap_pop () || (format != 32) || (type != XA_ATOM))
+	{
+	  g_object_unref (new_context);
+
+	  if (data)
+	    XFree (data);
+
+	  return GDK_FILTER_REMOVE;
+	}
+
+      atoms = (Atom *)data;
+
+      for (i=0; i<nitems; i++)
+	new_context->targets = 
+	  g_list_append (new_context->targets,
+			 GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display,
+										 atoms[i])));
+
+      XFree(atoms);
+    }
+  else
+    {
+      for (i=0; i<3; i++)
+	if (xevent->xclient.data.l[2+i])
+	  new_context->targets =
+	    g_list_append (new_context->targets,
+			   GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display, 
+										   xevent->xclient.data.l[2+i])));
+    }
+
+#ifdef G_ENABLE_DEBUG
+  if (_gdk_debug_flags & GDK_DEBUG_DND)
+    print_target_list (new_context->targets);
+#endif /* G_ENABLE_DEBUG */
+
+  xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
+  xdnd_read_actions (new_context);
+
+  event->dnd.type = GDK_DRAG_ENTER;
+  event->dnd.context = new_context;
+  gdk_event_set_device (event, gdk_drag_context_get_device (new_context));
+  g_object_ref (new_context);
+
+  display_x11->current_dest_drag = new_context;
+
+  return GDK_FILTER_TRANSLATE;
+}
+
+static GdkFilterReturn 
+xdnd_leave_filter (GdkXEvent *xev,
+		   GdkEvent  *event,
+		   gpointer   data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  guint32 source_window = xevent->xclient.data.l[0];
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;			/* Not for us */
+ 
+  GDK_NOTE (DND, 
+	    g_message ("XdndLeave: source_window: %#x",
+		       source_window));
+
+  display = GDK_WINDOW_DISPLAY (event->any.window);
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  xdnd_precache_atoms (display);
+
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
+      (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
+    {
+      event->dnd.type = GDK_DRAG_LEAVE;
+      /* Pass ownership of context to the event */
+      event->dnd.context = display_x11->current_dest_drag;
+      gdk_event_set_device (event, gdk_drag_context_get_device (event->dnd.context));
+
+      display_x11->current_dest_drag = NULL;
+
+      return GDK_FILTER_TRANSLATE;
+    }
+  else
+    return GDK_FILTER_REMOVE;
+}
+
+static GdkFilterReturn 
+xdnd_position_filter (GdkXEvent *xev,
+		      GdkEvent  *event,
+		      gpointer   data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  guint32 source_window = xevent->xclient.data.l[0];
+  gint16 x_root = xevent->xclient.data.l[2] >> 16;
+  gint16 y_root = xevent->xclient.data.l[2] & 0xffff;
+  guint32 time = xevent->xclient.data.l[3];
+  Atom action = xevent->xclient.data.l[4];
+
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+
+   if (!event->any.window ||
+       gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+     return GDK_FILTER_CONTINUE;			/* Not for us */
+   
+  GDK_NOTE (DND, 
+	    g_message ("XdndPosition: source_window: %#x position: (%d, %d)  time: %d  action: %ld",
+		       source_window, x_root, y_root, time, action));
+
+  display = GDK_WINDOW_DISPLAY (event->any.window);
+  display_x11 = GDK_DISPLAY_X11 (display);
+  
+  xdnd_precache_atoms (display);
+
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
+      (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
+    {
+      event->dnd.type = GDK_DRAG_MOTION;
+      event->dnd.context = display_x11->current_dest_drag;
+      gdk_event_set_device (event, gdk_drag_context_get_device (event->dnd.context));
+      g_object_ref (display_x11->current_dest_drag);
+
+      event->dnd.time = time;
+
+      display_x11->current_dest_drag->suggested_action = xdnd_action_from_atom (display, action);
+      
+      if (!(PRIVATE_DATA (display_x11->current_dest_drag))->xdnd_have_actions)
+	display_x11->current_dest_drag->actions = display_x11->current_dest_drag->suggested_action;
+
+      event->dnd.x_root = x_root;
+      event->dnd.y_root = y_root;
+
+      (PRIVATE_DATA (display_x11->current_dest_drag))->last_x = x_root;
+      (PRIVATE_DATA (display_x11->current_dest_drag))->last_y = y_root;
+      
+      return GDK_FILTER_TRANSLATE;
+    }
+
+  return GDK_FILTER_REMOVE;
+}
+
+static GdkFilterReturn 
+xdnd_drop_filter (GdkXEvent *xev,
+		  GdkEvent  *event,
+		  gpointer   data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  guint32 source_window = xevent->xclient.data.l[0];
+  guint32 time = xevent->xclient.data.l[2];
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+  
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;			/* Not for us */
+  
+  GDK_NOTE (DND, 
+	    g_message ("XdndDrop: source_window: %#x  time: %d",
+		       source_window, time));
+
+  display = GDK_WINDOW_DISPLAY (event->any.window);
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  xdnd_precache_atoms (display);
+
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
+      (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
+    {
+      GdkDragContextPrivateX11 *private;
+      private = PRIVATE_DATA (display_x11->current_dest_drag);
+
+      event->dnd.type = GDK_DROP_START;
+
+      event->dnd.context = display_x11->current_dest_drag;
+      gdk_event_set_device (event, gdk_drag_context_get_device (event->dnd.context));
+      g_object_ref (display_x11->current_dest_drag);
+
+      event->dnd.time = time;
+      event->dnd.x_root = private->last_x;
+      event->dnd.y_root = private->last_y;
+
+      gdk_x11_window_set_user_time (event->any.window, time);
+      
+      return GDK_FILTER_TRANSLATE;
+    }
+
+  return GDK_FILTER_REMOVE;
+}
+
+/*************************************************************
+ ************************** Public API ***********************
+ *************************************************************/
+void
+_gdk_dnd_init (GdkDisplay *display)
+{
+  int i;
+  init_byte_order ();
+
+  gdk_display_add_client_message_filter (
+	display,
+	gdk_atom_intern_static_string ("_MOTIF_DRAG_AND_DROP_MESSAGE"),
+	motif_dnd_filter, NULL);
+  
+  for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
+    {
+      gdk_display_add_client_message_filter (
+	display,
+	gdk_atom_intern_static_string (xdnd_filters[i].atom_name),
+	xdnd_filters[i].func, NULL);
+    }
+}		      
+
+/* Source side */
+
+static void
+gdk_drag_do_leave (GdkDragContext *context, guint32 time)
+{
+  if (context->dest_window)
+    {
+      switch (context->protocol)
+	{
+	case GDK_DRAG_PROTO_MOTIF:
+	  motif_send_leave (context, time);
+	  break;
+	case GDK_DRAG_PROTO_XDND:
+	  xdnd_send_leave (context);
+	  break;
+	case GDK_DRAG_PROTO_ROOTWIN:
+	case GDK_DRAG_PROTO_NONE:
+	default:
+	  break;
+	}
+
+      g_object_unref (context->dest_window);
+      context->dest_window = NULL;
+    }
+}
+
+/**
+ * gdk_drag_begin:
+ * @window: the source window for this drag.
+ * @targets: (transfer none) (element-type GdkAtom): the offered targets,
+ *     as list of #GdkAtom<!-- -->s
+ * 
+ * Starts a drag and creates a new drag context for it.
+ *
+ * This function is called by the drag source.
+ * 
+ * Return value: a newly created #GdkDragContext.
+ **/
+GdkDragContext * 
+gdk_drag_begin (GdkWindow     *window,
+		GList         *targets)
+{
+  GdkDragContext *new_context;
+  GdkDisplay *display;
+  GdkDevice *device;
+  GdkDeviceManager *device_manager;
+
+  g_return_val_if_fail (window != NULL, NULL);
+  g_return_val_if_fail (GDK_WINDOW_IS_X11 (window), NULL);
+
+  new_context = gdk_drag_context_new ();
+  new_context->is_source = TRUE;
+  new_context->source_window = window;
+  g_object_ref (window);
+
+  new_context->targets = g_list_copy (targets);
+  precache_target_list (new_context);
+  
+  new_context->actions = 0;
+
+  display = gdk_window_get_display (window);
+  device_manager = gdk_display_get_device_manager (display);
+  device = gdk_device_manager_get_client_pointer (device_manager);
+  gdk_drag_context_set_device (new_context, device);
+
+  return new_context;
+}
+
+static GdkNativeWindow
+_gdk_drag_get_protocol_for_display (GdkDisplay      *display,
+				    GdkNativeWindow  xid,
+				    GdkDragProtocol *protocol,
+				    guint           *version)
+
+{
+  GdkWindow *window;
+  GdkNativeWindow retval;
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
+
+  base_precache_atoms (display);
+
+  /* Check for a local drag
+   */
+  window = gdk_window_lookup_for_display (display, xid);
+  if (window &&
+      gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
+    {
+      if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
+	{
+	  *protocol = GDK_DRAG_PROTO_XDND;
+	  *version = 5;
+	  xdnd_precache_atoms (display);
+	  GDK_NOTE (DND, g_message ("Entering local Xdnd window %#x\n", xid));
+	  return xid;
+	}
+      else if (_gdk_x11_display_is_root_window (display, (Window) xid))
+	{
+	  *protocol = GDK_DRAG_PROTO_ROOTWIN;
+	  GDK_NOTE (DND, g_message ("Entering root window\n"));
+	  return xid;
+	}
+    }
+  else if ((retval = xdnd_check_dest (display, xid, version)))
+    {
+      *protocol = GDK_DRAG_PROTO_XDND;
+      xdnd_precache_atoms (display);
+      GDK_NOTE (DND, g_message ("Entering Xdnd window %#x\n", xid));
+      return retval;
+    }
+  else if ((retval = motif_check_dest (display, xid)))
+    {
+      *protocol = GDK_DRAG_PROTO_MOTIF;
+      GDK_NOTE (DND, g_message ("Entering motif window %#x\n", xid));
+      return retval;
+    }
+  else
+    {
+      /* Check if this is a root window */
+
+      gboolean rootwin = FALSE;
+      Atom type = None;
+      int format;
+      unsigned long nitems, after;
+      unsigned char *data;
+
+      if (_gdk_x11_display_is_root_window (display, (Window) xid))
+	rootwin = TRUE;
+
+      gdk_error_trap_push ();
+      
+      if (!rootwin)
+	{
+	  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
+				  gdk_x11_get_xatom_by_name_for_display (display, "ENLIGHTENMENT_DESKTOP"),
+				  0, 0, False, AnyPropertyType,
+				  &type, &format, &nitems, &after, &data) == Success &&
+	      type != None)
+	    {
+	      XFree (data);
+	      rootwin = TRUE;
+	    }
+	}
+
+      /* Until I find out what window manager the next one is for,
+       * I'm leaving it commented out. It's supported in the
+       * xscreensaver sources, though.
+       */
+#if 0
+      if (!rootwin)
+	{
+	  if (XGetWindowProperty (gdk_display, win,
+				  gdk_x11_get_xatom_by_name ("__SWM_VROOT"),
+				  0, 0, False, AnyPropertyType,
+				  &type, &format, &nitems, &data) &&
+	      type != None)
+	    {
+	      XFree (data);
+	      rootwin = TRUE;
+	    }
+	}
+#endif      
+
+      gdk_error_trap_pop_ignored ();
+
+      if (rootwin)
+	{
+	  GDK_NOTE (DND, g_message ("Entering root window\n"));
+	  *protocol = GDK_DRAG_PROTO_ROOTWIN;
+	  return xid;
+	}
+    }
+
+  *protocol = GDK_DRAG_PROTO_NONE;
+
+  return 0; /* a.k.a. None */
+}
+
+/**
+ * gdk_drag_get_protocol_for_display:
+ * @display: the #GdkDisplay where the destination window resides
+ * @xid: the windowing system id of the destination window.
+ * @protocol: location where the supported DND protocol is returned.
+ * @returns: the windowing system id of the window where the drop should happen. This 
+ *     may be @xid or the id of a proxy window, or zero if @xid doesn't
+ *     support Drag and Drop.
+ *
+ * Finds out the DND protocol supported by a window.
+ *
+ * Since: 2.2
+ */ 
+GdkNativeWindow
+gdk_drag_get_protocol_for_display (GdkDisplay      *display,
+				   GdkNativeWindow  xid,
+				   GdkDragProtocol *protocol)
+{
+  return _gdk_drag_get_protocol_for_display (display, xid, protocol, NULL);
+}
+
+static GdkWindowCache *
+drag_context_find_window_cache (GdkDragContext  *context,
+				GdkScreen       *screen)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GSList *tmp_list;
+  GdkWindowCache *cache;
+
+  for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
+    {
+      cache = tmp_list->data;
+      if (cache->screen == screen)
+	return cache;
+    }
+
+  cache = gdk_window_cache_new (screen);
+  private->window_caches = g_slist_prepend (private->window_caches, cache);
+  
+  return cache;
+}
+
+/**
+ * gdk_drag_find_window_for_screen:
+ * @context: a #GdkDragContext
+ * @drag_window: a window which may be at the pointer position, but
+ * should be ignored, since it is put up by the drag source as an icon.
+ * @screen: the screen where the destination window is sought. 
+ * @x_root: the x position of the pointer in root coordinates.
+ * @y_root: the y position of the pointer in root coordinates.
+ * @dest_window: (out): location to store the destination window in.
+ * @protocol: (out): location to store the DND protocol in.
+ *
+ * Finds the destination window and DND protocol to use at the
+ * given pointer position.
+ *
+ * This function is called by the drag source to obtain the 
+ * @dest_window and @protocol parameters for gdk_drag_motion().
+ *
+ * Since: 2.2
+ **/
+void
+gdk_drag_find_window_for_screen (GdkDragContext  *context,
+				 GdkWindow       *drag_window,
+				 GdkScreen       *screen,
+				 gint             x_root,
+				 gint             y_root,
+				 GdkWindow      **dest_window,
+				 GdkDragProtocol *protocol)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkWindowCache *window_cache;
+  GdkDisplay *display;
+  Window dest;
+
+  g_return_if_fail (context != NULL);
+
+  display = GDK_WINDOW_DISPLAY (context->source_window);
+
+  window_cache = drag_context_find_window_cache (context, screen);
+
+  dest = get_client_window_at_coords (window_cache,
+				      drag_window && GDK_WINDOW_IS_X11 (drag_window) ? 
+				      GDK_DRAWABLE_XID (drag_window) : None,
+				      x_root, y_root);
+
+  if (private->dest_xid != dest)
+    {
+      Window recipient;
+      private->dest_xid = dest;
+
+      /* Check if new destination accepts drags, and which protocol */
+
+      /* There is some ugliness here. We actually need to pass
+       * _three_ pieces of information to drag_motion - dest_window,
+       * protocol, and the XID of the unproxied window. The first
+       * two are passed explicitely, the third implicitly through
+       * protocol->dest_xid.
+       */
+      if ((recipient = _gdk_drag_get_protocol_for_display (display, dest, 
+							   protocol, &private->version)))
+	{
+	  *dest_window = gdk_window_lookup_for_display (display, recipient);
+	  if (*dest_window)
+	    g_object_ref (*dest_window);
+	  else
+	    *dest_window = gdk_window_foreign_new_for_display (display, recipient);
+	}
+      else
+	*dest_window = NULL;
+    }
+  else
+    {
+      *dest_window = context->dest_window;
+      if (*dest_window)
+	g_object_ref (*dest_window);
+      *protocol = context->protocol;
+    }
+}
+
+/**
+ * gdk_drag_motion:
+ * @context: a #GdkDragContext.
+ * @dest_window: the new destination window, obtained by 
+ *     gdk_drag_find_window().
+ * @protocol: the DND protocol in use, obtained by gdk_drag_find_window().
+ * @x_root: the x position of the pointer in root coordinates.
+ * @y_root: the y position of the pointer in root coordinates.
+ * @suggested_action: the suggested action.
+ * @possible_actions: the possible actions.
+ * @time_: the timestamp for this operation.
+ * 
+ * Updates the drag context when the pointer moves or the 
+ * set of actions changes.
+ *
+ * This function is called by the drag source.
+ * 
+ * Return value: FIXME
+ **/
+gboolean        
+gdk_drag_motion (GdkDragContext *context,
+		 GdkWindow      *dest_window,
+		 GdkDragProtocol protocol,
+		 gint            x_root, 
+		 gint            y_root,
+		 GdkDragAction   suggested_action,
+		 GdkDragAction   possible_actions,
+		 guint32         time)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+
+  g_return_val_if_fail (context != NULL, FALSE);
+  g_return_val_if_fail (dest_window == NULL || GDK_WINDOW_IS_X11 (dest_window), FALSE);
+
+  private->old_actions = context->actions;
+  context->actions = possible_actions;
+  
+  if (private->old_actions != possible_actions)
+    private->xdnd_actions_set = FALSE;
+  
+  if (protocol == GDK_DRAG_PROTO_XDND && private->version == 0)
+    {
+      /* This ugly hack is necessary since GTK+ doesn't know about
+       * the XDND protocol version, and in particular doesn't know 
+       * that gdk_drag_find_window_for_screen() has the side-effect 
+       * of setting private->version, and therefore sometimes call
+       * gdk_drag_motion() without a prior call to 
+       * gdk_drag_find_window_for_screen(). This happens, e.g.
+       * when GTK+ is proxying DND events to embedded windows.
+       */ 
+      if (dest_window)
+	{
+	  GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
+	  
+	  xdnd_check_dest (display, 
+			   GDK_DRAWABLE_XID (dest_window), 
+			   &private->version);
+	}
+    }
+
+  /* When we have a Xdnd target, make sure our XdndActionList
+   * matches the current actions;
+   */
+  if (protocol == GDK_DRAG_PROTO_XDND && !private->xdnd_actions_set)
+    {
+      if (dest_window)
+	{
+	  if (gdk_window_get_window_type (dest_window) == GDK_WINDOW_FOREIGN)
+	    xdnd_set_actions (context);
+	  else if (context->dest_window == dest_window)
+	    {
+	      GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
+	      GdkDragContext *dest_context;
+		    
+	      dest_context = gdk_drag_context_find (display, FALSE,
+						    GDK_DRAWABLE_XID (context->source_window),
+						    GDK_DRAWABLE_XID (dest_window));
+
+	      if (dest_context)
+		{
+		  dest_context->actions = context->actions;
+		  PRIVATE_DATA (dest_context)->xdnd_have_actions = TRUE;
+		}
+	    }
+	}
+    }
+
+  if (context->dest_window != dest_window)
+    {
+      GdkEvent *temp_event;
+
+      /* Send a leave to the last destination */
+      gdk_drag_do_leave (context, time);
+      private->drag_status = GDK_DRAG_STATUS_DRAG;
+
+      /* Check if new destination accepts drags, and which protocol */
+
+      if (dest_window)
+	{
+	  context->dest_window = dest_window;
+	  private->drop_xid = private->dest_xid;
+	  g_object_ref (context->dest_window);
+	  context->protocol = protocol;
+
+	  switch (protocol)
+	    {
+	    case GDK_DRAG_PROTO_MOTIF:
+	      motif_send_enter (context, time);
+	      break;
+
+	    case GDK_DRAG_PROTO_XDND:
+	      xdnd_send_enter (context);
+	      break;
+
+	    case GDK_DRAG_PROTO_ROOTWIN:
+	    case GDK_DRAG_PROTO_NONE:
+	    default:
+	      break;
+	    }
+	  private->old_action = suggested_action;
+	  context->suggested_action = suggested_action;
+	  private->old_actions = possible_actions;
+	}
+      else
+	{
+	  context->dest_window = NULL;
+	  private->drop_xid = None;
+	  context->action = 0;
+	}
+
+      /* Push a status event, to let the client know that
+       * the drag changed 
+       */
+      temp_event = gdk_event_new (GDK_DRAG_STATUS);
+      temp_event->dnd.window = g_object_ref (context->source_window);
+      /* We use this to signal a synthetic status. Perhaps
+       * we should use an extra field...
+       */
+      temp_event->dnd.send_event = TRUE;
+
+      temp_event->dnd.context = g_object_ref (context);
+      temp_event->dnd.time = time;
+      gdk_event_set_device (temp_event, gdk_drag_context_get_device (context));
+
+      gdk_event_put (temp_event);
+      gdk_event_free (temp_event);
+    }
+  else
+    {
+      private->old_action = context->suggested_action;
+      context->suggested_action = suggested_action;
+    }
+
+  /* Send a drag-motion event */
+
+  private->last_x = x_root;
+  private->last_y = y_root;
+      
+  if (context->dest_window)
+    {
+      if (private->drag_status == GDK_DRAG_STATUS_DRAG)
+	{
+	  switch (context->protocol)
+	    {
+	    case GDK_DRAG_PROTO_MOTIF:
+	      motif_send_motion (context, x_root, y_root, suggested_action, time);
+	      break;
+	      
+	    case GDK_DRAG_PROTO_XDND:
+	      xdnd_send_motion (context, x_root, y_root, suggested_action, time);
+	      break;
+
+	    case GDK_DRAG_PROTO_ROOTWIN:
+	      {
+		GdkEvent *temp_event;
+		/* GTK+ traditionally has used application/x-rootwin-drop,
+		 * but the XDND spec specifies x-rootwindow-drop.
+		 */
+		GdkAtom target1 = gdk_atom_intern_static_string ("application/x-rootwindow-drop");
+		GdkAtom target2 = gdk_atom_intern_static_string ("application/x-rootwin-drop");
+
+		if (g_list_find (context->targets,
+				 GDK_ATOM_TO_POINTER (target1)) ||
+		    g_list_find (context->targets,
+				 GDK_ATOM_TO_POINTER (target2)))
+		  context->action = context->suggested_action;
+		else
+		  context->action = 0;
+
+                temp_event = gdk_event_new (GDK_DRAG_STATUS);
+		temp_event->dnd.window = g_object_ref (context->source_window);
+		temp_event->dnd.send_event = FALSE;
+		temp_event->dnd.context = g_object_ref (context);
+		temp_event->dnd.time = time;
+                gdk_event_set_device (temp_event, gdk_drag_context_get_device (context));
+
+		gdk_event_put (temp_event);
+                gdk_event_free (temp_event);
+	      }
+	      break;
+	    case GDK_DRAG_PROTO_NONE:
+	      g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
+	      break;
+	    default:
+	      break;
+	    }
+	}
+      else
+	return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * gdk_drag_drop:
+ * @context: a #GdkDragContext.
+ * @time_: the timestamp for this operation.
+ * 
+ * Drops on the current destination.
+ * 
+ * This function is called by the drag source.
+ **/
+void
+gdk_drag_drop (GdkDragContext *context,
+	       guint32         time)
+{
+  g_return_if_fail (context != NULL);
+
+  if (context->dest_window)
+    {
+      switch (context->protocol)
+	{
+	case GDK_DRAG_PROTO_MOTIF:
+	  motif_send_leave (context, time);
+	  motif_send_drop (context, time);
+	  break;
+	  
+	case GDK_DRAG_PROTO_XDND:
+	  xdnd_send_drop (context, time);
+	  break;
+
+	case GDK_DRAG_PROTO_ROOTWIN:
+	  g_warning ("Drops for GDK_DRAG_PROTO_ROOTWIN must be handled internally");
+	  break;
+	case GDK_DRAG_PROTO_NONE:
+	  g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
+	  break;
+	default:
+	  break;
+	}
+    }
+}
+
+/**
+ * gdk_drag_abort:
+ * @context: a #GdkDragContext.
+ * @time_: the timestamp for this operation.
+ * 
+ * Aborts a drag without dropping. 
+ *
+ * This function is called by the drag source.
+ **/
+void
+gdk_drag_abort (GdkDragContext *context,
+		guint32         time)
+{
+  g_return_if_fail (context != NULL);
+
+  gdk_drag_do_leave (context, time);
+}
+
+/* Destination side */
+
+/**
+ * gdk_drag_status:
+ * @context: a #GdkDragContext.
+ * @action: the selected action which will be taken when a drop happens, 
+ *    or 0 to indicate that a drop will not be accepted.
+ * @time_: the timestamp for this operation.
+ * 
+ * Selects one of the actions offered by the drag source.
+ *
+ * This function is called by the drag destination in response to
+ * gdk_drag_motion() called by the drag source.
+ **/
+void             
+gdk_drag_status (GdkDragContext   *context,
+		 GdkDragAction     action,
+		 guint32           time)
+{
+  GdkDragContextPrivateX11 *private;
+  XEvent xev;
+  GdkDisplay *display;
+
+  g_return_if_fail (context != NULL);
+
+  private = PRIVATE_DATA (context);
+  display = GDK_WINDOW_DISPLAY (context->source_window);
+  
+  context->action = action;
+
+  if (context->protocol == GDK_DRAG_PROTO_MOTIF)
+    {
+      gboolean need_coords = FALSE;
+      
+      xev.xclient.type = ClientMessage;
+      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
+									"_MOTIF_DRAG_AND_DROP_MESSAGE");
+      xev.xclient.format = 8;
+      xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
+
+      if (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT)
+	{
+	  MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED | 0x80;
+	}
+      else
+	{
+	  if ((action != 0) != (private->old_action != 0))
+	    {
+	      if (action != 0)
+		{
+		  MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_ENTER | 0x80;
+		  need_coords = TRUE;
+		}
+	      else
+		MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_LEAVE | 0x80;
+	    }
+	  else
+	    {
+	      MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION | 0x80;
+	      need_coords = TRUE;
+	    }
+	}
+
+      MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+
+      switch (action)
+	{
+	case GDK_ACTION_MOVE:
+	  MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_MOVE;
+	  break;
+	case GDK_ACTION_COPY:
+	  MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY;
+	  break;
+	case GDK_ACTION_LINK:
+	  MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_LINK;
+	  break;
+	default:
+	  MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP;
+	  break;
+	}
+
+      if (action)
+	MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmDROP_SITE_VALID << 4);
+      else
+	MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmNO_DROP_SITE << 4);
+
+      MOTIF_XCLIENT_LONG (&xev, 1) = time;
+      
+      if (need_coords)
+	{
+	  MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
+	  MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
+	}
+      else
+	MOTIF_XCLIENT_LONG (&xev, 2) = 0;
+      
+      MOTIF_XCLIENT_LONG (&xev, 3) = 0;
+      MOTIF_XCLIENT_LONG (&xev, 4) = 0;
+
+      if (!_gdk_send_xevent (display,
+			     GDK_DRAWABLE_XID (context->source_window),
+			     FALSE, 0, &xev))
+	GDK_NOTE (DND, 
+		  g_message ("Send event to %lx failed",
+			     GDK_DRAWABLE_XID (context->source_window)));
+    }
+  else if (context->protocol == GDK_DRAG_PROTO_XDND)
+    {
+      xev.xclient.type = ClientMessage;
+      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndStatus");
+      xev.xclient.format = 32;
+      xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
+
+      xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
+      xev.xclient.data.l[1] = (action != 0) ? (2 | 1) : 0;
+      xev.xclient.data.l[2] = 0;
+      xev.xclient.data.l[3] = 0;
+      xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
+      
+      if (!xdnd_send_xevent (context, context->source_window,
+			     FALSE, &xev))
+	GDK_NOTE (DND, 
+		  g_message ("Send event to %lx failed",
+			     GDK_DRAWABLE_XID (context->source_window)));
+    }
+
+  private->old_action = action;
+}
+
+/**
+ * gdk_drop_reply:
+ * @context: a #GdkDragContext.
+ * @ok: %TRUE if the drop is accepted.
+ * @time_: the timestamp for this operation.
+ * 
+ * Accepts or rejects a drop. 
+ *
+ * This function is called by the drag destination in response
+ * to a drop initiated by the drag source.
+ **/
+void 
+gdk_drop_reply (GdkDragContext   *context,
+		gboolean          ok,
+		guint32           time)
+{
+  GdkDragContextPrivateX11 *private;
+
+  g_return_if_fail (context != NULL);
+
+  private = PRIVATE_DATA (context);
+  
+  if (context->protocol == GDK_DRAG_PROTO_MOTIF)
+    {
+      GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+      XEvent xev;
+
+      xev.xclient.type = ClientMessage;
+      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
+									"_MOTIF_DRAG_AND_DROP_MESSAGE");
+      xev.xclient.format = 8;
+
+      MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START | 0x80;
+      MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+      if (ok)
+	MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY | 
+	                               (XmDROP_SITE_VALID << 4) |
+	                               (XmDROP_NOOP << 8) |
+	                               (XmDROP << 12);
+      else
+	MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP | 
+	                               (XmNO_DROP_SITE << 4) |
+	                               (XmDROP_NOOP << 8) |
+	                               (XmDROP_CANCEL << 12);
+      MOTIF_XCLIENT_SHORT (&xev, 2) = private->last_x;
+      MOTIF_XCLIENT_SHORT (&xev, 3) = private->last_y;
+      MOTIF_XCLIENT_LONG (&xev, 2) = 0;
+      MOTIF_XCLIENT_LONG (&xev, 3) = 0;
+      MOTIF_XCLIENT_LONG (&xev, 4) = 0;
+      
+      _gdk_send_xevent (display,
+			GDK_DRAWABLE_XID (context->source_window),
+			FALSE, 0, &xev);
+    }
+}
+
+/**
+ * gdk_drop_finish:
+ * @context: a #GtkDragContext.
+ * @success: %TRUE if the data was successfully received.
+ * @time_: the timestamp for this operation.
+ * 
+ * Ends the drag operation after a drop.
+ *
+ * This function is called by the drag destination.
+ **/
+void             
+gdk_drop_finish (GdkDragContext   *context,
+		 gboolean          success,
+		 guint32           time)
+{
+  g_return_if_fail (context != NULL);
+
+  if (context->protocol == GDK_DRAG_PROTO_XDND)
+    {
+      GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+      XEvent xev;
+
+      xev.xclient.type = ClientMessage;
+      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndFinished");
+      xev.xclient.format = 32;
+      xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
+      
+      xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
+      if (success)
+	{
+	  xev.xclient.data.l[1] = 1;
+	  xev.xclient.data.l[2] = xdnd_action_to_atom (display, 
+						       context->action);
+	}
+      else
+	{
+	  xev.xclient.data.l[1] = 0;
+	  xev.xclient.data.l[2] = None;
+	}
+      xev.xclient.data.l[3] = 0;
+      xev.xclient.data.l[4] = 0;
+
+      if (!xdnd_send_xevent (context, context->source_window,
+			     FALSE, &xev))
+	GDK_NOTE (DND, 
+		  g_message ("Send event to %lx failed",
+			     GDK_DRAWABLE_XID (context->source_window)));
+    }
+}
+
+
+/**
+ * gdk_window_register_dnd:
+ * @window: a #GdkWindow.
+ *
+ * Registers a window as a potential drop destination.
+ */
+void            
+gdk_window_register_dnd (GdkWindow      *window)
+{
+  static const gulong xdnd_version = 5;
+  MotifDragReceiverInfo info;
+  Atom motif_drag_receiver_info_atom;
+  GdkDisplay *display = gdk_window_get_display (window);
+
+  g_return_if_fail (window != NULL);
+
+  if (gdk_window_get_window_type (window) == GDK_WINDOW_OFFSCREEN)
+    return;
+
+  base_precache_atoms (display);
+
+  if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
+    return;
+  else
+    g_object_set_data (G_OBJECT (window), "gdk-dnd-registered", GINT_TO_POINTER (TRUE));
+  
+  /* Set Motif drag receiver information property */
+
+  motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display,
+									 "_MOTIF_DRAG_RECEIVER_INFO");
+  /* initialize to zero to avoid writing uninitialized data to socket */
+  memset(&info, 0, sizeof(info));
+  info.byte_order = local_byte_order;
+  info.protocol_version = 0;
+  info.protocol_style = XmDRAG_DYNAMIC;
+  info.proxy_window = None;
+  info.num_drop_sites = 0;
+  info.total_size = sizeof(info);
+
+  XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_DRAWABLE_XID (window),
+		   motif_drag_receiver_info_atom,
+		   motif_drag_receiver_info_atom,
+		   8, PropModeReplace,
+		   (guchar *)&info,
+		   sizeof (info));
+
+  /* Set XdndAware */
+
+  /* The property needs to be of type XA_ATOM, not XA_INTEGER. Blech */
+  XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+		   GDK_DRAWABLE_XID (window),
+		   gdk_x11_get_xatom_by_name_for_display (display, "XdndAware"),
+		   XA_ATOM, 32, PropModeReplace,
+		   (guchar *)&xdnd_version, 1);
+}
+
+/**
+ * gdk_drag_get_selection:
+ * @context: a #GdkDragContext.
+ * 
+ * Returns the selection atom for the current source window.
+ * 
+ * Return value: the selection atom.
+ **/
+GdkAtom
+gdk_drag_get_selection (GdkDragContext *context)
+{
+  g_return_val_if_fail (context != NULL, GDK_NONE);
+
+  if (context->protocol == GDK_DRAG_PROTO_MOTIF)
+    return gdk_x11_xatom_to_atom_for_display (GDK_WINDOW_DISPLAY (context->source_window),
+					      (PRIVATE_DATA (context))->motif_selection);
+  else if (context->protocol == GDK_DRAG_PROTO_XDND)
+    return gdk_atom_intern_static_string ("XdndSelection");
+  else
+    return GDK_NONE;
+}
+
+/**
+ * gdk_drag_drop_succeeded:
+ * @context: a #GdkDragContext
+ * 
+ * Returns whether the dropped data has been successfully 
+ * transferred. This function is intended to be used while 
+ * handling a %GDK_DROP_FINISHED event, its return value is
+ * meaningless at other times.
+ * 
+ * Return value: %TRUE if the drop was successful.
+ *
+ * Since: 2.6
+ **/
+gboolean 
+gdk_drag_drop_succeeded (GdkDragContext *context)
+{
+  GdkDragContextPrivateX11 *private;
+
+  g_return_val_if_fail (context != NULL, FALSE);
+
+  private = PRIVATE_DATA (context);
+
+  return !private->drop_failed;
+}
diff --git a/gdk/broadway/gdkdrawable-broadway.c b/gdk/broadway/gdkdrawable-broadway.c
new file mode 100644
index 0000000..e481d13
--- /dev/null
+++ b/gdk/broadway/gdkdrawable-broadway.c
@@ -0,0 +1,235 @@
+/* GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkdrawable-broadway.h"
+
+#include "gdkx.h"
+#include "gdkprivate-broadway.h"
+#include "gdkscreen-broadway.h"
+#include "gdkdisplay-broadway.h"
+
+#include <cairo-xlib.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static cairo_surface_t *gdk_x11_ref_cairo_surface (GdkDrawable *drawable);
+static cairo_surface_t *gdk_x11_create_cairo_surface (GdkDrawable *drawable,
+                                                      int          width,
+                                                      int          height);
+     
+static const cairo_user_data_key_t gdk_x11_cairo_key;
+
+G_DEFINE_TYPE (GdkDrawableImplX11, _gdk_drawable_impl_x11, GDK_TYPE_DRAWABLE)
+
+static void
+_gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass)
+{
+  GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
+  
+  drawable_class->ref_cairo_surface = gdk_x11_ref_cairo_surface;
+  drawable_class->create_cairo_surface = gdk_x11_create_cairo_surface;
+}
+
+static void
+_gdk_drawable_impl_x11_init (GdkDrawableImplX11 *impl)
+{
+}
+
+/**
+ * _gdk_x11_drawable_finish:
+ * @drawable: a #GdkDrawableImplX11.
+ * 
+ * Performs necessary cleanup prior to destroying a window.
+ **/
+void
+_gdk_x11_drawable_finish (GdkDrawable *drawable)
+{
+  GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
+  
+  if (impl->cairo_surface)
+    {
+      cairo_surface_finish (impl->cairo_surface);
+      cairo_surface_set_user_data (impl->cairo_surface, &gdk_x11_cairo_key,
+				   NULL, NULL);
+    }
+}
+
+/**
+ * _gdk_x11_drawable_update_size:
+ * @drawable: a #GdkDrawableImplX11.
+ * 
+ * Updates the state of the drawable (in particular the drawable's
+ * cairo surface) when its size has changed.
+ **/
+void
+_gdk_x11_drawable_update_size (GdkDrawable *drawable)
+{
+  GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
+  
+  if (impl->cairo_surface)
+    {
+      cairo_xlib_surface_set_size (impl->cairo_surface,
+                                   gdk_window_get_width (impl->wrapper),
+                                   gdk_window_get_height (impl->wrapper));
+    }
+}
+
+/*****************************************************
+ * X11 specific implementations of generic functions *
+ *****************************************************/
+
+static GdkDrawable *
+get_impl_drawable (GdkDrawable *drawable)
+{
+  if (GDK_IS_WINDOW (drawable))
+    return ((GdkWindowObject *)drawable)->impl;
+  else
+    {
+      g_warning (G_STRLOC " drawable is not a window");
+      return NULL;
+    }
+}
+
+/**
+ * gdk_x11_drawable_get_xdisplay:
+ * @drawable: a #GdkDrawable.
+ * 
+ * Returns the display of a #GdkDrawable.
+ * 
+ * Return value: an Xlib <type>Display*</type>.
+ **/
+Display *
+gdk_x11_drawable_get_xdisplay (GdkDrawable *drawable)
+{
+  if (GDK_IS_DRAWABLE_IMPL_X11 (drawable))
+    return GDK_SCREEN_XDISPLAY (GDK_DRAWABLE_IMPL_X11 (drawable)->screen);
+  else
+    return GDK_SCREEN_XDISPLAY (GDK_DRAWABLE_IMPL_X11 (get_impl_drawable (drawable))->screen);
+}
+
+/**
+ * gdk_x11_drawable_get_xid:
+ * @drawable: a #GdkDrawable.
+ * 
+ * Returns the X resource (window) belonging to a #GdkDrawable.
+ * 
+ * Return value: the ID of @drawable's X resource.
+ **/
+XID
+gdk_x11_drawable_get_xid (GdkDrawable *drawable)
+{
+  GdkDrawable *impl;
+  
+  if (GDK_IS_WINDOW (drawable))
+    {
+      GdkWindow *window = (GdkWindow *)drawable;
+      
+      /* Try to ensure the window has a native window */
+      if (!_gdk_window_has_impl (window))
+	{
+	  gdk_window_ensure_native (window);
+
+	  /* We sync here to ensure the window is created in the Xserver when
+	   * this function returns. This is required because the returned XID
+	   * for this window must be valid immediately, even with another
+	   * connection to the Xserver */
+	  gdk_display_sync (gdk_window_get_display (window));
+	}
+      
+      if (!GDK_WINDOW_IS_X11 (window))
+        {
+          g_warning (G_STRLOC " drawable is not a native X11 window");
+          return None;
+        }
+      
+      impl = ((GdkWindowObject *)drawable)->impl;
+    }
+  else
+    {
+      g_warning (G_STRLOC " drawable is not a window");
+      return None;
+    }
+
+  return ((GdkDrawableImplX11 *)impl)->xid;
+}
+
+GdkDrawable *
+gdk_x11_window_get_drawable_impl (GdkWindow *window)
+{
+  return ((GdkWindowObject *)window)->impl;
+}
+
+static void
+gdk_x11_cairo_surface_destroy (void *data)
+{
+  GdkDrawableImplX11 *impl = data;
+
+  impl->cairo_surface = NULL;
+}
+
+static cairo_surface_t *
+gdk_x11_create_cairo_surface (GdkDrawable *drawable,
+			      int width,
+			      int height)
+{
+  GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
+  GdkVisual *visual;
+    
+  visual = gdk_window_get_visual (impl->wrapper);
+  return cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (impl->screen),
+                                    impl->xid,
+                                    GDK_VISUAL_XVISUAL (visual),
+                                    width, height);
+}
+
+static cairo_surface_t *
+gdk_x11_ref_cairo_surface (GdkDrawable *drawable)
+{
+  GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
+
+  if (GDK_IS_WINDOW_IMPL_X11 (drawable) &&
+      GDK_WINDOW_DESTROYED (impl->wrapper))
+    return NULL;
+
+  if (!impl->cairo_surface)
+    {
+      impl->cairo_surface = gdk_x11_create_cairo_surface (drawable,
+                                                          gdk_window_get_width (impl->wrapper),
+                                                          gdk_window_get_height (impl->wrapper));
+      
+      if (impl->cairo_surface)
+	cairo_surface_set_user_data (impl->cairo_surface, &gdk_x11_cairo_key,
+				     drawable, gdk_x11_cairo_surface_destroy);
+    }
+  else
+    cairo_surface_reference (impl->cairo_surface);
+
+  return impl->cairo_surface;
+}
diff --git a/gdk/broadway/gdkdrawable-broadway.h b/gdk/broadway/gdkdrawable-broadway.h
new file mode 100644
index 0000000..7aca727
--- /dev/null
+++ b/gdk/broadway/gdkdrawable-broadway.h
@@ -0,0 +1,75 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_DRAWABLE_BROADWAY_H__
+#define __GDK_DRAWABLE_BROADWAY_H__
+
+#include <gdk/gdkdrawable.h>
+#include <X11/Xlib.h>
+
+G_BEGIN_DECLS
+
+/* Drawable implementation for X11
+ */
+
+typedef struct _GdkDrawableImplX11 GdkDrawableImplX11;
+typedef struct _GdkDrawableImplX11Class GdkDrawableImplX11Class;
+
+#define GDK_TYPE_DRAWABLE_IMPL_X11              (_gdk_drawable_impl_x11_get_type ())
+#define GDK_DRAWABLE_IMPL_X11(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_DRAWABLE_IMPL_X11, GdkDrawableImplX11))
+#define GDK_DRAWABLE_IMPL_X11_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DRAWABLE_IMPL_X11, GdkDrawableImplX11Class))
+#define GDK_IS_DRAWABLE_IMPL_X11(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_DRAWABLE_IMPL_X11))
+#define GDK_IS_DRAWABLE_IMPL_X11_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DRAWABLE_IMPL_X11))
+#define GDK_DRAWABLE_IMPL_X11_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DRAWABLE_IMPL_X11, GdkDrawableImplX11Class))
+
+struct _GdkDrawableImplX11
+{
+  GdkDrawable parent_instance;
+
+  GdkDrawable *wrapper;
+  
+  Window xid;
+  GdkScreen *screen;
+
+  cairo_surface_t *cairo_surface;
+};
+ 
+struct _GdkDrawableImplX11Class 
+{
+  GdkDrawableClass parent_class;
+
+};
+
+GType _gdk_drawable_impl_x11_get_type (void);
+
+/* Note that the following take GdkDrawableImplX11, not the wrapper drawable */
+void _gdk_x11_drawable_finish           (GdkDrawable  *drawable);
+void _gdk_x11_drawable_update_size      (GdkDrawable  *drawable);
+GdkDrawable *gdk_x11_window_get_drawable_impl (GdkWindow *window);
+
+G_END_DECLS
+
+#endif /* __GDK_DRAWABLE_BROADWAY_H__ */
diff --git a/gdk/broadway/gdkeventsource.c b/gdk/broadway/gdkeventsource.c
new file mode 100644
index 0000000..f3b850e
--- /dev/null
+++ b/gdk/broadway/gdkeventsource.c
@@ -0,0 +1,435 @@
+/* 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 "config.h"
+
+#include "gdkeventsource.h"
+
+#include "gdkinternals.h"
+#include "gdkx.h"
+
+
+static gboolean gdk_event_source_prepare  (GSource     *source,
+                                           gint        *timeout);
+static gboolean gdk_event_source_check    (GSource     *source);
+static gboolean gdk_event_source_dispatch (GSource     *source,
+                                           GSourceFunc  callback,
+                                           gpointer     user_data);
+static void     gdk_event_source_finalize (GSource     *source);
+
+#define HAS_FOCUS(toplevel)                           \
+  ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
+
+struct _GdkEventSource
+{
+  GSource source;
+
+  GdkDisplay *display;
+  GPollFD event_poll_fd;
+  GList *translators;
+};
+
+static GSourceFuncs event_funcs = {
+  gdk_event_source_prepare,
+  gdk_event_source_check,
+  gdk_event_source_dispatch,
+  gdk_event_source_finalize
+};
+
+static GList *event_sources = NULL;
+
+static gint
+gdk_event_apply_filters (XEvent   *xevent,
+			 GdkEvent *event,
+			 GList    *filters)
+{
+  GList *tmp_list;
+  GdkFilterReturn result;
+
+  tmp_list = filters;
+
+  while (tmp_list)
+    {
+      GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
+
+      tmp_list = tmp_list->next;
+      result = filter->function (xevent, event, filter->data);
+
+      if (result != GDK_FILTER_CONTINUE)
+	return result;
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
+
+static GdkWindow *
+gdk_event_source_get_filter_window (GdkEventSource *event_source,
+                                    XEvent         *xevent)
+{
+  GdkWindow *window;
+
+  window = gdk_window_lookup_for_display (event_source->display,
+                                          xevent->xany.window);
+
+  if (window && !GDK_IS_WINDOW (window))
+    window = NULL;
+
+  return window;
+}
+
+static void
+handle_focus_change (GdkEventCrossing *event)
+{
+  GdkToplevelX11 *toplevel;
+  gboolean focus_in, had_focus;
+
+  toplevel = _gdk_x11_window_get_toplevel (event->window);
+  focus_in = (event->type == GDK_ENTER_NOTIFY);
+
+  if (!toplevel || event->detail == GDK_NOTIFY_INFERIOR)
+    return;
+
+  toplevel->has_pointer = focus_in;
+
+  if (!event->focus || toplevel->has_focus_window)
+    return;
+
+  had_focus = HAS_FOCUS (toplevel);
+  toplevel->has_pointer_focus = focus_in;
+
+  if (HAS_FOCUS (toplevel) != had_focus)
+    {
+      GdkEvent *focus_event;
+
+      focus_event = gdk_event_new (GDK_FOCUS_CHANGE);
+      focus_event->focus_change.window = g_object_ref (event->window);
+      focus_event->focus_change.send_event = FALSE;
+      focus_event->focus_change.in = focus_in;
+      gdk_event_set_device (focus_event, gdk_event_get_device ((GdkEvent *) event));
+
+      gdk_event_put (focus_event);
+      gdk_event_free (focus_event);
+    }
+}
+
+static GdkEvent *
+gdk_event_source_translate_event (GdkEventSource *event_source,
+                                  XEvent         *xevent)
+{
+  GdkEvent *event = gdk_event_new (GDK_NOTHING);
+  GList *list = event_source->translators;
+  GdkFilterReturn result;
+  GdkWindow *filter_window;
+
+  /* Run default filters */
+  if (_gdk_default_filters)
+    {
+      /* Apply global filters */
+
+      result = gdk_event_apply_filters (xevent, event,
+                                        _gdk_default_filters);
+
+      if (result == GDK_FILTER_REMOVE)
+        {
+          gdk_event_free (event);
+          return NULL;
+        }
+      else if (result == GDK_FILTER_TRANSLATE)
+        return event;
+    }
+
+  filter_window = gdk_event_source_get_filter_window (event_source, xevent);
+
+  if (filter_window)
+    {
+      /* Apply per-window filters */
+      GdkWindowObject *filter_private = (GdkWindowObject *) filter_window;
+      GdkFilterReturn result;
+
+      event->any.window = g_object_ref (filter_window);
+
+      if (filter_private->filters)
+	{
+	  result = gdk_event_apply_filters (xevent, event,
+					    filter_private->filters);
+
+          if (result == GDK_FILTER_REMOVE)
+            {
+              gdk_event_free (event);
+              return NULL;
+            }
+          else if (result == GDK_FILTER_TRANSLATE)
+            return event;
+	}
+    }
+
+  gdk_event_free (event);
+  event = NULL;
+
+  while (list && !event)
+    {
+      GdkEventTranslator *translator = list->data;
+
+      list = list->next;
+      event = gdk_event_translator_translate (translator,
+                                              event_source->display,
+                                              xevent);
+    }
+
+  if (event &&
+      (event->type == GDK_ENTER_NOTIFY ||
+       event->type == GDK_LEAVE_NOTIFY) &&
+      event->crossing.window != NULL)
+    {
+      /* Handle focusing (in the case where no window manager is running */
+      handle_focus_change (&event->crossing);
+    }
+
+  return event;
+}
+
+static gboolean
+gdk_check_xpending (GdkDisplay *display)
+{
+  return XPending (GDK_DISPLAY_XDISPLAY (display));
+}
+
+static gboolean
+gdk_event_source_prepare (GSource *source,
+                          gint    *timeout)
+{
+  GdkDisplay *display = ((GdkEventSource*) source)->display;
+  gboolean retval;
+
+  GDK_THREADS_ENTER ();
+
+  *timeout = -1;
+  retval = (_gdk_event_queue_find_first (display) != NULL ||
+	    gdk_check_xpending (display));
+
+  GDK_THREADS_LEAVE ();
+
+  return retval;
+}
+
+static gboolean
+gdk_event_source_check (GSource *source)
+{
+  GdkEventSource *event_source = (GdkEventSource*) source;
+  gboolean retval;
+
+  GDK_THREADS_ENTER ();
+
+  if (event_source->event_poll_fd.revents & G_IO_IN)
+    retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
+	      gdk_check_xpending (event_source->display));
+  else
+    retval = FALSE;
+
+  GDK_THREADS_LEAVE ();
+
+  return retval;
+}
+
+void
+_gdk_events_queue (GdkDisplay *display)
+{
+  GdkEvent *event;
+  XEvent xevent;
+  Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+  GdkEventSource *event_source;
+  GdkDisplayX11 *display_x11;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+  event_source = (GdkEventSource *) display_x11->event_source;
+
+  while (!_gdk_event_queue_find_first (display) && XPending (xdisplay))
+    {
+      XNextEvent (xdisplay, &xevent);
+
+      switch (xevent.type)
+	{
+	case KeyPress:
+	case KeyRelease:
+	  break;
+	default:
+	  if (XFilterEvent (&xevent, None))
+	    continue;
+	}
+
+      event = gdk_event_source_translate_event (event_source, &xevent);
+
+      if (event)
+        {
+          GList *node;
+
+          node = _gdk_event_queue_append (display, event);
+          _gdk_windowing_got_event (display, node, event, xevent.xany.serial);
+        }
+    }
+}
+
+static gboolean
+gdk_event_source_dispatch (GSource     *source,
+                           GSourceFunc  callback,
+                           gpointer     user_data)
+{
+  GdkDisplay *display = ((GdkEventSource*) source)->display;
+  GdkEvent *event;
+
+  GDK_THREADS_ENTER ();
+
+  event = gdk_display_get_event (display);
+
+  if (event)
+    {
+      if (_gdk_event_func)
+	(*_gdk_event_func) (event, _gdk_event_data);
+
+      gdk_event_free (event);
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  return TRUE;
+}
+
+static void
+gdk_event_source_finalize (GSource *source)
+{
+  GdkEventSource *event_source = (GdkEventSource *)source;
+
+  g_list_free (event_source->translators);
+  event_source->translators = NULL;
+
+  event_sources = g_list_remove (event_sources, source);
+}
+
+GSource *
+gdk_event_source_new (GdkDisplay *display)
+{
+  GSource *source;
+  GdkEventSource *event_source;
+  GdkDisplayX11 *display_x11;
+  int connection_number;
+  char *name;
+
+  source = g_source_new (&event_funcs, sizeof (GdkEventSource));
+  name = g_strdup_printf ("GDK X11 Event source (%s)",
+			  gdk_display_get_name (display));
+  g_source_set_name (source, name);
+  g_free (name);
+  event_source = (GdkEventSource *) source;
+  event_source->display = display;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+  connection_number = ConnectionNumber (display_x11->xdisplay);
+
+  event_source->event_poll_fd.fd = connection_number;
+  event_source->event_poll_fd.events = G_IO_IN;
+  g_source_add_poll (source, &event_source->event_poll_fd);
+
+  g_source_set_priority (source, GDK_PRIORITY_EVENTS);
+  g_source_set_can_recurse (source, TRUE);
+  g_source_attach (source, NULL);
+
+  event_sources = g_list_prepend (event_sources, source);
+
+  return source;
+}
+
+void
+gdk_event_source_add_translator (GdkEventSource     *source,
+                                 GdkEventTranslator *translator)
+{
+  g_return_if_fail (GDK_IS_EVENT_TRANSLATOR (translator));
+
+  source->translators = g_list_append (source->translators, translator);
+}
+
+void
+gdk_event_source_select_events (GdkEventSource *source,
+                                Window          window,
+                                GdkEventMask    event_mask,
+                                unsigned int    extra_x_mask)
+{
+  unsigned int xmask = extra_x_mask;
+  GList *list;
+  gint i;
+
+  list = source->translators;
+
+  while (list)
+    {
+      GdkEventTranslator *translator = list->data;
+      GdkEventMask translator_mask, mask;
+
+      translator_mask = gdk_event_translator_get_handled_events (translator);
+      mask = event_mask & translator_mask;
+
+      if (mask != 0)
+        {
+          gdk_event_translator_select_window_events (translator, window, mask);
+          event_mask &= ~mask;
+        }
+
+      list = list->next;
+    }
+
+  for (i = 0; i < _gdk_nenvent_masks; i++)
+    {
+      if (event_mask & (1 << (i + 1)))
+        xmask |= _gdk_event_mask_table[i];
+    }
+
+  XSelectInput (GDK_DISPLAY_XDISPLAY (source->display), window, xmask);
+}
+
+/**
+ * gdk_events_pending:
+ *
+ * Checks if any events are ready to be processed for any display.
+ *
+ * Return value:  %TRUE if any events are pending.
+ **/
+gboolean
+gdk_events_pending (void)
+{
+  GList *tmp_list;
+
+  for (tmp_list = event_sources; tmp_list; tmp_list = tmp_list->next)
+    {
+      GdkEventSource *tmp_source = tmp_list->data;
+      GdkDisplay *display = tmp_source->display;
+
+      if (_gdk_event_queue_find_first (display))
+	return TRUE;
+    }
+
+  for (tmp_list = event_sources; tmp_list; tmp_list = tmp_list->next)
+    {
+      GdkEventSource *tmp_source = tmp_list->data;
+      GdkDisplay *display = tmp_source->display;
+
+      if (gdk_check_xpending (display))
+	return TRUE;
+    }
+
+  return FALSE;
+}
diff --git a/gdk/broadway/gdkeventsource.h b/gdk/broadway/gdkeventsource.h
new file mode 100644
index 0000000..424338c
--- /dev/null
+++ b/gdk/broadway/gdkeventsource.h
@@ -0,0 +1,46 @@
+/* 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_EVENT_SOURCE_H__
+#define __GDK_EVENT_SOURCE_H__
+
+#include "gdkeventtranslator.h"
+#include "gdkprivate-broadway.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GdkEventSource GdkEventSource;
+
+G_GNUC_INTERNAL
+GSource * gdk_event_source_new            (GdkDisplay *display);
+
+G_GNUC_INTERNAL
+void      gdk_event_source_add_translator (GdkEventSource     *source,
+                                           GdkEventTranslator *translator);
+
+G_GNUC_INTERNAL
+void      gdk_event_source_select_events  (GdkEventSource *source,
+                                           Window          window,
+                                           GdkEventMask    event_mask,
+                                           unsigned int    extra_x_mask);
+
+
+G_END_DECLS
+
+#endif /* __GDK_EVENT_SOURCE_H__ */
diff --git a/gdk/broadway/gdkeventtranslator.c b/gdk/broadway/gdkeventtranslator.c
new file mode 100644
index 0000000..b4a285a
--- /dev/null
+++ b/gdk/broadway/gdkeventtranslator.c
@@ -0,0 +1,89 @@
+/* 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 "config.h"
+
+#include "gdkeventtranslator.h"
+
+
+typedef GdkEventTranslatorIface GdkEventTranslatorInterface;
+G_DEFINE_INTERFACE (GdkEventTranslator, gdk_event_translator, G_TYPE_OBJECT);
+
+
+static void
+gdk_event_translator_default_init (GdkEventTranslatorInterface *iface)
+{
+}
+
+
+GdkEvent *
+gdk_event_translator_translate (GdkEventTranslator *translator,
+                                GdkDisplay         *display,
+                                XEvent             *xevent)
+{
+  GdkEventTranslatorIface *iface;
+  GdkEvent *event;
+
+  g_return_val_if_fail (GDK_IS_EVENT_TRANSLATOR (translator), NULL);
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+  iface = GDK_EVENT_TRANSLATOR_GET_IFACE (translator);
+
+  if (!iface->translate_event)
+    return NULL;
+
+  event = gdk_event_new (GDK_NOTHING);
+
+  if ((iface->translate_event) (translator, display, event, xevent))
+    return event;
+
+  gdk_event_free (event);
+
+  return NULL;
+}
+
+GdkEventMask
+gdk_event_translator_get_handled_events (GdkEventTranslator *translator)
+{
+  GdkEventTranslatorIface *iface;
+
+  g_return_val_if_fail (GDK_IS_EVENT_TRANSLATOR (translator), 0);
+
+  iface = GDK_EVENT_TRANSLATOR_GET_IFACE (translator);
+
+  if (iface->get_handled_events)
+    return iface->get_handled_events (translator);
+
+  return 0;
+}
+
+void
+gdk_event_translator_select_window_events (GdkEventTranslator *translator,
+                                           Window              window,
+                                           GdkEventMask        event_mask)
+{
+  GdkEventTranslatorIface *iface;
+
+  g_return_if_fail (GDK_IS_EVENT_TRANSLATOR (translator));
+
+  iface = GDK_EVENT_TRANSLATOR_GET_IFACE (translator);
+
+  if (iface->select_window_events)
+    iface->select_window_events (translator, window, event_mask);
+}
diff --git a/gdk/broadway/gdkeventtranslator.h b/gdk/broadway/gdkeventtranslator.h
new file mode 100644
index 0000000..55d2dc8
--- /dev/null
+++ b/gdk/broadway/gdkeventtranslator.h
@@ -0,0 +1,65 @@
+/* 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_EVENT_TRANSLATOR_H__
+#define __GDK_EVENT_TRANSLATOR_H__
+
+#include <gdk/gdktypes.h>
+#include <gdk/gdkdisplay.h>
+#include "gdkprivate-broadway.h"
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_EVENT_TRANSLATOR         (gdk_event_translator_get_type ())
+#define GDK_EVENT_TRANSLATOR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_EVENT_TRANSLATOR, GdkEventTranslator))
+#define GDK_IS_EVENT_TRANSLATOR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_EVENT_TRANSLATOR))
+#define GDK_EVENT_TRANSLATOR_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE  ((o), GDK_TYPE_EVENT_TRANSLATOR, GdkEventTranslatorIface))
+
+typedef struct _GdkEventTranslatorIface GdkEventTranslatorIface;
+typedef struct _GdkEventTranslator GdkEventTranslator; /* Dummy typedef */
+
+struct _GdkEventTranslatorIface
+{
+  GTypeInterface iface;
+
+  /* VMethods */
+  gboolean (* translate_event) (GdkEventTranslator *translator,
+                                GdkDisplay         *display,
+                                GdkEvent           *event,
+                                XEvent             *xevent);
+
+  GdkEventMask (* get_handled_events)   (GdkEventTranslator *translator);
+  void         (* select_window_events) (GdkEventTranslator *translator,
+                                         Window              window,
+                                         GdkEventMask        event_mask);
+};
+
+GType      gdk_event_translator_get_type (void) G_GNUC_CONST;
+
+GdkEvent * gdk_event_translator_translate (GdkEventTranslator *translator,
+                                           GdkDisplay         *display,
+                                           XEvent             *xevent);
+GdkEventMask gdk_event_translator_get_handled_events   (GdkEventTranslator *translator);
+void         gdk_event_translator_select_window_events (GdkEventTranslator *translator,
+                                                        Window              window,
+                                                        GdkEventMask        event_mask);
+
+G_END_DECLS
+
+#endif /* __GDK_EVENT_TRANSLATOR_H__ */
diff --git a/gdk/broadway/gdkgeometry-broadway.c b/gdk/broadway/gdkgeometry-broadway.c
new file mode 100644
index 0000000..e0e62d6
--- /dev/null
+++ b/gdk/broadway/gdkgeometry-broadway.c
@@ -0,0 +1,390 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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 "config.h"
+
+#include "gdkrectangle.h"
+#include "gdkprivate-broadway.h"
+#include "gdkx.h"
+#include "gdkinternals.h"
+#include "gdkscreen-broadway.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkwindow-broadway.h"
+
+
+typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
+typedef struct _GdkWindowParentPos GdkWindowParentPos;
+
+typedef enum {
+  GDK_WINDOW_QUEUE_TRANSLATE,
+  GDK_WINDOW_QUEUE_ANTIEXPOSE
+} GdkWindowQueueType;
+
+struct _GdkWindowQueueItem
+{
+  GdkWindow *window;
+  gulong serial;
+  GdkWindowQueueType type;
+  union {
+    struct {
+      cairo_region_t *area;
+      gint dx;
+      gint dy;
+    } translate;
+    struct {
+      cairo_region_t *area;
+    } antiexpose;
+  } u;
+};
+
+void
+_gdk_window_move_resize_child (GdkWindow *window,
+			       gint       x,
+			       gint       y,
+			       gint       width,
+			       gint       height)
+{
+  GdkWindowObject *obj;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  obj = GDK_WINDOW_OBJECT (window);
+
+  if (width > 65535 ||
+      height > 65535)
+    {
+      g_warning ("Native children wider or taller than 65535 pixels are not supported");
+
+      if (width > 65535)
+	width = 65535;
+      if (height > 65535)
+	height = 65535;
+    }
+
+  obj->x = x;
+  obj->y = y;
+  obj->width = width;
+  obj->height = height;
+
+  /* We don't really care about origin overflow, because on overflow
+     the window won't be visible anyway and thus it will be shaped
+     to nothing */
+
+  _gdk_x11_window_tmp_unset_parent_bg (window);
+  _gdk_x11_window_tmp_unset_bg (window, TRUE);
+  XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
+		     GDK_WINDOW_XID (window),
+		     obj->x + obj->parent->abs_x,
+		     obj->y + obj->parent->abs_y,
+		     width, height);
+  _gdk_x11_window_tmp_reset_parent_bg (window);
+  _gdk_x11_window_tmp_reset_bg (window, TRUE);
+}
+
+static Bool
+expose_serial_predicate (Display *xdisplay,
+			 XEvent  *xev,
+			 XPointer arg)
+{
+  gulong *serial = (gulong *)arg;
+
+  if (xev->xany.type == Expose || xev->xany.type == GraphicsExpose)
+    *serial = MIN (*serial, xev->xany.serial);
+
+  return False;
+}
+
+/* Find oldest possible serial for an outstanding expose event
+ */
+static gulong
+find_current_serial (Display *xdisplay)
+{
+  XEvent xev;
+  gulong serial = NextRequest (xdisplay);
+  
+  XSync (xdisplay, False);
+
+  XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
+
+  return serial;
+}
+
+static void
+queue_delete_link (GQueue *queue,
+		   GList  *link)
+{
+  if (queue->tail == link)
+    queue->tail = link->prev;
+  
+  queue->head = g_list_remove_link (queue->head, link);
+  g_list_free_1 (link);
+  queue->length--;
+}
+
+static void
+queue_item_free (GdkWindowQueueItem *item)
+{
+  if (item->window)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (item->window),
+				    (gpointer *)&(item->window));
+    }
+  
+  if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
+    cairo_region_destroy (item->u.antiexpose.area);
+  else
+    {
+      if (item->u.translate.area)
+	cairo_region_destroy (item->u.translate.area);
+    }
+  
+  g_free (item);
+}
+
+static void
+gdk_window_queue (GdkWindow          *window,
+		  GdkWindowQueueItem *item)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
+  
+  if (!display_x11->translate_queue)
+    display_x11->translate_queue = g_queue_new ();
+
+  /* Keep length of queue finite by, if it grows too long,
+   * figuring out the latest relevant serial and discarding
+   * irrelevant queue items.
+   */
+  if (display_x11->translate_queue->length >= 64)
+    {
+      gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
+      GList *tmp_list = display_x11->translate_queue->head;
+      
+      while (tmp_list)
+	{
+	  GdkWindowQueueItem *item = tmp_list->data;
+	  GList *next = tmp_list->next;
+	  
+	  /* an overflow-safe (item->serial < serial) */
+	  if (item->serial - serial > (gulong) G_MAXLONG)
+	    {
+	      queue_delete_link (display_x11->translate_queue, tmp_list);
+	      queue_item_free (item);
+	    }
+
+	  tmp_list = next;
+	}
+    }
+
+  /* Catch the case where someone isn't processing events and there
+   * is an event stuck in the event queue with an old serial:
+   * If we can't reduce the queue length by the above method,
+   * discard anti-expose items. (We can't discard translate
+   * items 
+   */
+  if (display_x11->translate_queue->length >= 64)
+    {
+      GList *tmp_list = display_x11->translate_queue->head;
+      
+      while (tmp_list)
+	{
+	  GdkWindowQueueItem *item = tmp_list->data;
+	  GList *next = tmp_list->next;
+	  
+	  if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
+	    {
+	      queue_delete_link (display_x11->translate_queue, tmp_list);
+	      queue_item_free (item);
+	    }
+
+	  tmp_list = next;
+	}
+    }
+
+  item->window = window;
+  item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
+  
+  g_object_add_weak_pointer (G_OBJECT (window),
+			     (gpointer *)&(item->window));
+
+  g_queue_push_tail (display_x11->translate_queue, item);
+}
+
+static GC
+_get_scratch_gc (GdkWindowObject *window, cairo_region_t *clip_region)
+{
+  GdkScreenX11 *screen;
+  XRectangle *rectangles;
+  gint n_rects;
+  gint depth;
+
+  screen = GDK_SCREEN_X11 (gdk_window_get_screen (GDK_WINDOW (window)));
+  depth = gdk_visual_get_depth (gdk_window_get_visual (GDK_WINDOW (window))) - 1;
+
+  if (!screen->subwindow_gcs[depth])
+    {
+      XGCValues values;
+      
+      values.graphics_exposures = True;
+      values.subwindow_mode = IncludeInferiors;
+      
+      screen->subwindow_gcs[depth] = XCreateGC (screen->xdisplay,
+                                                GDK_WINDOW_XID (window),
+                                                GCSubwindowMode | GCGraphicsExposures,
+                                                &values);
+    }
+  
+  _gdk_region_get_xrectangles (clip_region,
+                               0, 0,
+                               &rectangles,
+                               &n_rects);
+  
+  XSetClipRectangles (screen->xdisplay,
+                      screen->subwindow_gcs[depth],
+                      0, 0,
+                      rectangles, n_rects,
+                      YXBanded);
+  
+  g_free (rectangles);
+  return screen->subwindow_gcs[depth];
+}
+
+
+
+void
+_gdk_x11_window_translate (GdkWindow      *window,
+                           cairo_region_t *area,
+                           gint            dx,
+                           gint            dy)
+{
+  GdkWindowQueueItem *item;
+  GC xgc;
+  GdkRectangle extents;
+  GdkWindowObject *private, *impl;
+  int px, py;
+
+  /* We need to get data from subwindows here, because we might have
+   * shaped a native window over the moving region (with bg none,
+   * so the pixels are still there). In fact we might need to get data
+   * from overlapping native window that are not children of this window,
+   * so we copy from the toplevel with INCLUDE_INFERIORS.
+   */
+  private = impl = (GdkWindowObject *) window;
+  px = py = 0;
+  while (private->parent != NULL &&
+         private->parent->window_type != GDK_WINDOW_ROOT)
+    {
+      dx -= private->parent->abs_x + private->x;
+      dy -= private->parent->abs_y + private->y;
+      private = (GdkWindowObject *) _gdk_window_get_impl_window ((GdkWindow *) private->parent);
+    }
+
+  cairo_region_get_extents (area, &extents);
+
+  xgc = _get_scratch_gc (impl, area);
+
+  cairo_region_translate (area, -dx, -dy); /* Move to source region */
+
+  item = g_new (GdkWindowQueueItem, 1);
+  item->type = GDK_WINDOW_QUEUE_TRANSLATE;
+  item->u.translate.area = cairo_region_copy (area);
+  item->u.translate.dx = dx;
+  item->u.translate.dy = dy;
+  gdk_window_queue (window, item);
+
+  XCopyArea (GDK_WINDOW_XDISPLAY (impl),
+             GDK_DRAWABLE_IMPL_X11 (private->impl)->xid,
+             GDK_DRAWABLE_IMPL_X11 (impl->impl)->xid,
+             xgc,
+             extents.x - dx, extents.y - dy,
+             extents.width, extents.height,
+             extents.x, extents.y);
+}
+
+gboolean
+_gdk_x11_window_queue_antiexpose (GdkWindow *window,
+				  cairo_region_t *area)
+{
+  GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
+  item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
+  item->u.antiexpose.area = area;
+
+  gdk_window_queue (window, item);
+
+  return TRUE;
+}
+
+void
+_gdk_window_process_expose (GdkWindow    *window,
+			    gulong        serial,
+			    GdkRectangle *area)
+{
+  cairo_region_t *invalidate_region = cairo_region_create_rectangle (area);
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
+
+  if (display_x11->translate_queue)
+    {
+      GList *tmp_list = display_x11->translate_queue->head;
+
+      while (tmp_list)
+	{
+	  GdkWindowQueueItem *item = tmp_list->data;
+          GList *next = tmp_list->next;
+
+	  /* an overflow-safe (serial < item->serial) */
+	  if (serial - item->serial > (gulong) G_MAXLONG)
+	    {
+	      if (item->window == window)
+		{
+		  if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
+		    {
+		      if (item->u.translate.area)
+			{
+			  cairo_region_t *intersection;
+
+			  intersection = cairo_region_copy (invalidate_region);
+			  cairo_region_intersect (intersection, item->u.translate.area);
+			  cairo_region_subtract (invalidate_region, intersection);
+			  cairo_region_translate (intersection, item->u.translate.dx, item->u.translate.dy);
+			  cairo_region_union (invalidate_region, intersection);
+			  cairo_region_destroy (intersection);
+			}
+		      else
+			cairo_region_translate (invalidate_region, item->u.translate.dx, item->u.translate.dy);
+		    }
+		  else		/* anti-expose */
+		    {
+		      cairo_region_subtract (invalidate_region, item->u.antiexpose.area);
+		    }
+		}
+	    }
+	  else
+	    {
+	      queue_delete_link (display_x11->translate_queue, tmp_list);
+	      queue_item_free (item);
+	    }
+	  tmp_list = next;
+	}
+    }
+
+  if (!cairo_region_is_empty (invalidate_region))
+    _gdk_window_invalidate_for_expose (window, invalidate_region);
+
+  cairo_region_destroy (invalidate_region);
+}
diff --git a/gdk/broadway/gdkglobals-broadway.c b/gdk/broadway/gdkglobals-broadway.c
new file mode 100644
index 0000000..f55375b
--- /dev/null
+++ b/gdk/broadway/gdkglobals-broadway.c
@@ -0,0 +1,37 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdktypes.h"
+#include "gdkprivate-broadway.h"
+
+#include <stdio.h>
+
+
+gboolean          _gdk_use_xshm = TRUE;  /* used as a cmd line arg */
+GdkAtom           _gdk_selection_property;
+gboolean          _gdk_synchronize = FALSE;
diff --git a/gdk/broadway/gdkim-broadway.c b/gdk/broadway/gdkim-broadway.c
new file mode 100644
index 0000000..b027f4b
--- /dev/null
+++ b/gdk/broadway/gdkim-broadway.c
@@ -0,0 +1,103 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkx.h"
+#include "gdkmain.h"
+#include "gdkinternals.h"
+#include "gdkdisplay-broadway.h"
+
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* If this variable is FALSE, it indicates that we should
+ * avoid trying to use multibyte conversion functions and
+ * assume everything is 1-byte per character
+ */
+static gboolean gdk_use_mb;
+
+void
+_gdk_x11_initialize_locale (void)
+{
+  wchar_t result;
+  gchar *current_locale;
+  static char *last_locale = NULL;
+
+  gdk_use_mb = FALSE;
+
+  current_locale = setlocale (LC_ALL, NULL);
+
+  if (last_locale && strcmp (last_locale, current_locale) == 0)
+    return;
+
+  g_free (last_locale);
+  last_locale = g_strdup (current_locale);
+
+  if (XSupportsLocale ())
+    XSetLocaleModifiers ("");
+
+  if ((strcmp (current_locale, "C")) && (strcmp (current_locale, "POSIX")))
+    {
+      gdk_use_mb = TRUE;
+
+#ifndef X_LOCALE
+      /* Detect ancient GNU libc, where mb == UTF8. Not useful unless it's
+       * really a UTF8 locale. The below still probably will
+       * screw up on Greek, Cyrillic, etc, encoded as UTF8.
+       */
+      
+      if ((MB_CUR_MAX == 2) &&
+	  (mbstowcs (&result, "\xdd\xa5", 1) > 0) &&
+	  result == 0x765)
+	{
+	  if ((strlen (current_locale) < 4) ||
+	      g_ascii_strcasecmp (current_locale + strlen(current_locale) - 4,
+				  "utf8"))
+	    gdk_use_mb = FALSE;
+	}
+#endif /* X_LOCALE */
+    }
+
+  GDK_NOTE (XIM,
+	    g_message ("%s multi-byte string functions.", 
+		       gdk_use_mb ? "Using" : "Not using"));
+  
+  return;
+}
+
+gchar*
+gdk_set_locale (void)
+{
+  if (!setlocale (LC_ALL,""))
+    g_warning ("locale not supported by C library");
+
+  _gdk_x11_initialize_locale ();
+  
+  return setlocale (LC_ALL, NULL);
+}
diff --git a/gdk/broadway/gdkinput.c b/gdk/broadway/gdkinput.c
new file mode 100644
index 0000000..24b32ea
--- /dev/null
+++ b/gdk/broadway/gdkinput.c
@@ -0,0 +1,231 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gdkscreen-broadway.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkwindow.h"
+
+#include <stdlib.h>
+
+
+/* Addition used for extension_events mask */
+#define GDK_ALL_DEVICES_MASK (1<<30)
+
+struct _GdkInputWindow
+{
+  GList *windows; /* GdkWindow:s with extension_events set */
+
+  /* gdk window */
+  GdkWindow *impl_window; /* an impl window */
+};
+
+
+/**
+ * gdk_devices_list:
+ *
+ * Returns the list of available input devices for the default display.
+ * The list is statically allocated and should not be freed.
+ *
+ * Return value: (transfer none) (element-type GdkDevice): a list of #GdkDevice
+ *
+ * Deprecated: 3.0: Use gdk_device_manager_list_devices() instead.
+ **/
+GList *
+gdk_devices_list (void)
+{
+  return gdk_display_list_devices (gdk_display_get_default ());
+}
+
+static void
+_gdk_input_select_device_events (GdkWindow *impl_window,
+                                 GdkDevice *device)
+{
+  guint event_mask;
+  GdkWindowObject *w;
+  GdkInputWindow *iw;
+  GdkInputMode mode;
+  gboolean has_cursor;
+  GdkDeviceType type;
+  GList *l;
+
+  event_mask = 0;
+  iw = ((GdkWindowObject *)impl_window)->input_window;
+
+  g_object_get (device,
+                "type", &type,
+                "input-mode", &mode,
+                "has-cursor", &has_cursor,
+                NULL);
+
+  if (iw == NULL ||
+      mode == GDK_MODE_DISABLED ||
+      type == GDK_DEVICE_TYPE_MASTER)
+    return;
+
+  for (l = iw->windows; l != NULL; l = l->next)
+    {
+      w = l->data;
+
+      if (has_cursor || (w->extension_events & GDK_ALL_DEVICES_MASK))
+        {
+          event_mask = w->extension_events;
+
+          if (event_mask)
+            event_mask |= GDK_PROXIMITY_OUT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
+
+          gdk_window_set_device_events ((GdkWindow *) w, device, event_mask);
+        }
+    }
+}
+
+static void
+unset_extension_events (GdkWindow *window)
+{
+  GdkWindowObject *window_private;
+  GdkWindowObject *impl_window;
+  GdkDisplayX11 *display_x11;
+  GdkInputWindow *iw;
+
+  window_private = (GdkWindowObject*) window;
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
+  iw = impl_window->input_window;
+
+  display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
+
+  if (window_private->extension_events != 0)
+    {
+      g_assert (iw != NULL);
+      g_assert (g_list_find (iw->windows, window) != NULL);
+
+      iw->windows = g_list_remove (iw->windows, window);
+      if (iw->windows == NULL)
+	{
+	  impl_window->input_window = NULL;
+	  display_x11->input_windows = g_list_remove (display_x11->input_windows, iw);
+	  g_free (iw);
+	}
+    }
+
+  window_private->extension_events = 0;
+}
+
+/**
+ * gdk_input_set_extension_events:
+ * @window: a #GdkWindow.
+ * @mask: the event mask
+ * @mode: the type of extension events that are desired.
+ *
+ * Turns extension events on or off for a particular window,
+ * and specifies the event mask for extension events.
+ *
+ * Deprecated: 3.0: Use gdk_window_set_device_events() instead.
+ **/
+void
+gdk_input_set_extension_events (GdkWindow        *window,
+                                gint              mask,
+				GdkExtensionMode  mode)
+{
+  GdkWindowObject *window_private;
+  GdkWindowObject *impl_window;
+  GdkInputWindow *iw;
+  GdkDisplayX11 *display_x11;
+#ifndef XINPUT_NONE
+  GList *tmp_list;
+#endif
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_WINDOW_IS_X11 (window));
+
+  window_private = (GdkWindowObject*) window;
+  display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
+
+  if (mode == GDK_EXTENSION_EVENTS_ALL && mask != 0)
+    mask |= GDK_ALL_DEVICES_MASK;
+
+  if (mode == GDK_EXTENSION_EVENTS_NONE)
+    mask = 0;
+
+  iw = impl_window->input_window;
+
+  if (mask != 0)
+    {
+      if (!iw)
+	{
+	  iw = g_new0 (GdkInputWindow,1);
+
+	  iw->impl_window = (GdkWindow *)impl_window;
+
+	  iw->windows = NULL;
+
+	  display_x11->input_windows = g_list_append (display_x11->input_windows, iw);
+	  impl_window->input_window = iw;
+	}
+
+      if (window_private->extension_events == 0)
+	iw->windows = g_list_append (iw->windows, window);
+      window_private->extension_events = mask;
+    }
+  else
+    {
+      unset_extension_events (window);
+    }
+
+#ifndef XINPUT_NONE
+  for (tmp_list = display_x11->input_devices; tmp_list; tmp_list = tmp_list->next)
+    {
+      GdkDevice *dev = tmp_list->data;
+      _gdk_input_select_device_events (GDK_WINDOW (impl_window), dev);
+    }
+#endif /* !XINPUT_NONE */
+}
+
+void
+_gdk_input_window_destroy (GdkWindow *window)
+{
+  unset_extension_events (window);
+}
+
+void
+_gdk_input_check_extension_events (GdkDevice *device)
+{
+  GdkDisplayX11 *display_impl;
+  GdkInputWindow *input_window;
+  GList *tmp_list;
+
+  display_impl = GDK_DISPLAY_X11 (gdk_device_get_display (device));
+
+  for (tmp_list = display_impl->input_windows; tmp_list; tmp_list = tmp_list->next)
+    {
+      input_window = tmp_list->data;
+      _gdk_input_select_device_events (input_window->impl_window, device);
+    }
+}
diff --git a/gdk/broadway/gdkkeys-broadway.c b/gdk/broadway/gdkkeys-broadway.c
new file mode 100644
index 0000000..aa9a456
--- /dev/null
+++ b/gdk/broadway/gdkkeys-broadway.c
@@ -0,0 +1,1859 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gdkx.h"
+#include "gdkprivate-broadway.h"
+#include "gdkinternals.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkkeysyms.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+
+/* OSF-4.0 is apparently missing this macro
+ */
+#  ifndef XkbKeySymEntry
+#    define XkbKeySymEntry(d,k,sl,g) \
+ 	(XkbKeySym(d,k,((XkbKeyGroupsWidth(d,k)*(g))+(sl))))
+#  endif
+#endif /* HAVE_XKB */
+
+typedef struct _GdkKeymapX11   GdkKeymapX11;
+typedef struct _GdkKeymapClass GdkKeymapX11Class;
+
+#define GDK_TYPE_KEYMAP_X11          (gdk_keymap_x11_get_type ())
+#define GDK_KEYMAP_X11(object)       (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_KEYMAP_X11, GdkKeymapX11))
+#define GDK_IS_KEYMAP_X11(object)    (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_KEYMAP_X11))
+
+typedef struct _DirectionCacheEntry DirectionCacheEntry;
+
+struct _DirectionCacheEntry
+{
+  guint serial;
+  Atom group_atom;
+  PangoDirection direction;
+};
+
+struct _GdkKeymapX11
+{
+  GdkKeymap     parent_instance;
+
+  gint min_keycode;
+  gint max_keycode;
+  KeySym* keymap;
+  gint keysyms_per_keycode;
+  XModifierKeymap* mod_keymap;
+  guint lock_keysym;
+  GdkModifierType group_switch_mask;
+  GdkModifierType num_lock_mask;
+  GdkModifierType modmap[8];
+  PangoDirection current_direction;
+  guint sun_keypad      : 1;
+  guint have_direction  : 1;
+  guint caps_lock_state : 1;
+  guint num_lock_state : 1;
+  guint current_serial;
+
+#ifdef HAVE_XKB
+  XkbDescPtr xkb_desc;
+  /* We cache the directions */
+  Atom current_group_atom;
+  guint current_cache_serial;
+  /* A cache of size four should be more than enough, people usually
+   * have two groups around, and the xkb limit is four.  It still
+   * works correct for more than four groups.  It's just the
+   * cache.
+   */
+  DirectionCacheEntry group_direction_cache[4];
+#endif
+};
+
+#define KEYMAP_USE_XKB(keymap) GDK_DISPLAY_X11 ((keymap)->display)->use_xkb
+#define KEYMAP_XDISPLAY(keymap) GDK_DISPLAY_XDISPLAY ((keymap)->display)
+
+static GType gdk_keymap_x11_get_type   (void);
+static void  gdk_keymap_x11_class_init (GdkKeymapX11Class *klass);
+static void  gdk_keymap_x11_init       (GdkKeymapX11      *keymap);
+static void  gdk_keymap_x11_finalize   (GObject           *object);
+
+static GdkKeymapClass *parent_class = NULL;
+
+static GType
+gdk_keymap_x11_get_type (void)
+{
+  static GType object_type = 0;
+
+  if (!object_type)
+    {
+      const GTypeInfo object_info =
+	{
+	  sizeof (GdkKeymapClass),
+	  (GBaseInitFunc) NULL,
+	  (GBaseFinalizeFunc) NULL,
+	  (GClassInitFunc) gdk_keymap_x11_class_init,
+	  NULL,           /* class_finalize */
+	  NULL,           /* class_data */
+	  sizeof (GdkKeymapX11),
+	  0,              /* n_preallocs */
+	  (GInstanceInitFunc) gdk_keymap_x11_init,
+	};
+      
+      object_type = g_type_register_static (GDK_TYPE_KEYMAP,
+                                            g_intern_static_string ("GdkKeymapX11"),
+                                            &object_info, 0);
+    }
+  
+  return object_type;
+}
+
+static void
+gdk_keymap_x11_class_init (GdkKeymapX11Class *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->finalize = gdk_keymap_x11_finalize;
+}
+
+static void
+gdk_keymap_x11_init (GdkKeymapX11 *keymap)
+{
+  keymap->min_keycode = 0;
+  keymap->max_keycode = 0;
+
+  keymap->keymap = NULL;
+  keymap->keysyms_per_keycode = 0;
+  keymap->mod_keymap = NULL;
+  
+  keymap->num_lock_mask = 0;
+  keymap->sun_keypad = FALSE;
+  keymap->group_switch_mask = 0;
+  keymap->lock_keysym = GDK_KEY_Caps_Lock;
+  keymap->have_direction = FALSE;
+  keymap->current_serial = 0;
+
+#ifdef HAVE_XKB
+  keymap->xkb_desc = NULL;
+  keymap->current_group_atom = 0;
+  keymap->current_cache_serial = 0;
+#endif
+
+}
+
+static void
+gdk_keymap_x11_finalize (GObject *object)
+{
+  GdkKeymapX11 *keymap_x11 = GDK_KEYMAP_X11 (object);
+
+  if (keymap_x11->keymap)
+    XFree (keymap_x11->keymap);
+
+  if (keymap_x11->mod_keymap)
+    XFreeModifiermap (keymap_x11->mod_keymap);
+
+#ifdef HAVE_XKB
+  if (keymap_x11->xkb_desc)
+    XkbFreeKeyboard (keymap_x11->xkb_desc, XkbAllComponentsMask, True);
+#endif
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static inline void
+update_keyrange (GdkKeymapX11 *keymap_x11)
+{
+  if (keymap_x11->max_keycode == 0)
+    XDisplayKeycodes (KEYMAP_XDISPLAY (GDK_KEYMAP (keymap_x11)),
+		      &keymap_x11->min_keycode, &keymap_x11->max_keycode);
+}
+
+#ifdef HAVE_XKB
+
+static void
+update_modmap (Display      *display,
+	       GdkKeymapX11 *keymap_x11)
+{
+  static struct {
+    const gchar *name;
+    Atom atom;
+    GdkModifierType mask;
+  } vmods[] = {
+    { "Meta", 0, GDK_META_MASK },
+    { "Super", 0, GDK_SUPER_MASK },
+    { "Hyper", 0, GDK_HYPER_MASK },
+    { NULL, 0, 0 }
+  };
+
+  gint i, j, k;
+
+  if (!vmods[0].atom)
+    for (i = 0; vmods[i].name; i++)
+      vmods[i].atom = XInternAtom (display, vmods[i].name, FALSE);
+
+  for (i = 0; i < 8; i++)
+    keymap_x11->modmap[i] = 1 << i;
+
+  for (i = 0; i < XkbNumVirtualMods; i++)
+    {
+      for (j = 0; vmods[j].atom; j++)
+	{
+	  if (keymap_x11->xkb_desc->names->vmods[i] == vmods[j].atom)
+	    {
+	      for (k = 0; k < 8; k++)
+		{
+		  if (keymap_x11->xkb_desc->server->vmods[i] & (1 << k))
+		    keymap_x11->modmap[k] |= vmods[j].mask;
+		}
+	    }
+	}
+    }
+}
+
+static XkbDescPtr
+get_xkb (GdkKeymapX11 *keymap_x11)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_KEYMAP (keymap_x11)->display);
+  Display *xdisplay = display_x11->xdisplay;
+  
+  update_keyrange (keymap_x11);
+  
+  if (keymap_x11->xkb_desc == NULL)
+    {
+      keymap_x11->xkb_desc = XkbGetMap (xdisplay, XkbKeySymsMask | XkbKeyTypesMask | XkbModifierMapMask | XkbVirtualModsMask, XkbUseCoreKbd);
+      if (keymap_x11->xkb_desc == NULL)
+        {
+	  g_error ("Failed to get keymap");
+          return NULL;
+        }
+
+      XkbGetNames (xdisplay, XkbGroupNamesMask | XkbVirtualModNamesMask, keymap_x11->xkb_desc);
+
+      update_modmap (xdisplay, keymap_x11);
+    }
+  else if (keymap_x11->current_serial != display_x11->keymap_serial)
+    {
+      XkbGetUpdatedMap (xdisplay, XkbKeySymsMask | XkbKeyTypesMask | XkbModifierMapMask | XkbVirtualModsMask,
+			keymap_x11->xkb_desc);
+      XkbGetNames (xdisplay, XkbGroupNamesMask | XkbVirtualModNamesMask, keymap_x11->xkb_desc);
+
+      update_modmap (xdisplay, keymap_x11);
+    }
+
+  keymap_x11->current_serial = display_x11->keymap_serial;
+
+  if (keymap_x11->num_lock_mask == 0)
+    keymap_x11->num_lock_mask = XkbKeysymToModifiers (KEYMAP_XDISPLAY (GDK_KEYMAP (keymap_x11)), XK_Num_Lock);
+
+  return keymap_x11->xkb_desc;
+}
+#endif /* HAVE_XKB */
+
+/* Whether we were able to turn on detectable-autorepeat using
+ * XkbSetDetectableAutorepeat. If FALSE, we'll fall back
+ * to checking the next event with XPending().
+ */
+
+/** 
+ * gdk_keymap_get_for_display:
+ * @display: the #GdkDisplay.
+ * @returns: the #GdkKeymap attached to @display.
+ *
+ * Returns the #GdkKeymap attached to @display.
+ *
+ * Since: 2.2
+ **/
+GdkKeymap*
+gdk_keymap_get_for_display (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11;
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  display_x11 = GDK_DISPLAY_X11 (display);
+  
+  if (!display_x11->keymap)
+    display_x11->keymap = g_object_new (gdk_keymap_x11_get_type (), NULL);
+
+  display_x11->keymap->display = display;
+
+  return display_x11->keymap;
+}
+
+/* Find the index of the group/level pair within the keysyms for a key.
+ * We round up the number of keysyms per keycode to the next even number,
+ * otherwise we lose a whole group of keys
+ */
+#define KEYSYM_INDEX(keymap_impl, group, level) \
+  (2 * ((group) % (gint)((keymap_impl->keysyms_per_keycode + 1) / 2)) + (level))
+#define KEYSYM_IS_KEYPAD(s) (((s) >= 0xff80 && (s) <= 0xffbd) || \
+                             ((s) >= 0x11000000 && (s) <= 0x1100ffff))
+
+static gint
+get_symbol (const KeySym *syms,
+	    GdkKeymapX11 *keymap_x11,
+	    gint group,
+	    gint level)
+{
+  gint index;
+
+  index = KEYSYM_INDEX(keymap_x11, group, level);
+  if (index >= keymap_x11->keysyms_per_keycode)
+      return NoSymbol;
+
+  return syms[index];
+}
+
+static void
+set_symbol (KeySym       *syms, 
+	    GdkKeymapX11 *keymap_x11, 
+	    gint          group, 
+	    gint          level, 
+	    KeySym        sym)
+{
+  gint index;
+
+  index = KEYSYM_INDEX(keymap_x11, group, level);
+  if (index >= keymap_x11->keysyms_per_keycode)
+      return;
+
+  syms[index] = sym;
+}
+
+static void
+update_keymaps (GdkKeymapX11 *keymap_x11)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_KEYMAP (keymap_x11)->display);
+  Display *xdisplay = display_x11->xdisplay;
+  
+#ifdef HAVE_XKB
+  g_assert (!KEYMAP_USE_XKB (GDK_KEYMAP (keymap_x11)));
+#endif
+  
+  if (keymap_x11->keymap == NULL ||
+      keymap_x11->current_serial != display_x11->keymap_serial)
+    {
+      gint i;
+      gint map_size;
+      gint keycode;
+
+      keymap_x11->current_serial = display_x11->keymap_serial;
+      
+      update_keyrange (keymap_x11);
+      
+      if (keymap_x11->keymap)
+        XFree (keymap_x11->keymap);
+
+      if (keymap_x11->mod_keymap)
+        XFreeModifiermap (keymap_x11->mod_keymap);
+      
+      keymap_x11->keymap = XGetKeyboardMapping (xdisplay, keymap_x11->min_keycode,
+						keymap_x11->max_keycode - keymap_x11->min_keycode + 1,
+						&keymap_x11->keysyms_per_keycode);
+
+
+      /* GDK_KEY_ISO_Left_Tab, as usually configured through XKB, really messes
+       * up the whole idea of "consumed modifiers" because shift is consumed.
+       * However, <shift>Tab is not usually GDK_KEY_ISO_Left_Tab without XKB,
+       * we we fudge the map here.
+       */
+      keycode = keymap_x11->min_keycode;
+      while (keycode <= keymap_x11->max_keycode)
+        {
+          KeySym *syms = keymap_x11->keymap + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
+	  /* Check both groups */
+	  for (i = 0 ; i < 2 ; i++)
+	    {
+	      if (get_symbol (syms, keymap_x11, i, 0) == GDK_KEY_Tab)
+		set_symbol (syms, keymap_x11, i, 1, GDK_KEY_ISO_Left_Tab);
+	    }
+
+          /*
+           * If there is one keysym and the key symbol has upper and lower
+           * case variants fudge the keymap
+           */
+          if (get_symbol (syms, keymap_x11, 0, 1) == 0)
+            {
+              guint lower;
+              guint upper;
+
+              gdk_keyval_convert_case (get_symbol (syms, keymap_x11, 0, 0), &lower, &upper);
+              if (lower != upper)
+                {
+		  set_symbol (syms, keymap_x11, 0, 0, lower);
+		  set_symbol (syms, keymap_x11, 0, 1, upper);
+                }
+            }
+      
+          
+          ++keycode;
+        }
+
+      keymap_x11->mod_keymap = XGetModifierMapping (xdisplay);
+
+      keymap_x11->lock_keysym = GDK_KEY_VoidSymbol;
+      keymap_x11->group_switch_mask = 0;
+      keymap_x11->num_lock_mask = 0;
+
+      for (i = 0; i < 8; i++)
+	keymap_x11->modmap[i] = 1 << i;
+      
+      /* There are 8 sets of modifiers, with each set containing
+       * max_keypermod keycodes.
+       */
+      map_size = 8 * keymap_x11->mod_keymap->max_keypermod;
+      for (i = 0; i < map_size; i++)
+        {
+          /* Get the key code at this point in the map. */
+          gint keycode = keymap_x11->mod_keymap->modifiermap[i];
+          gint j;
+          KeySym *syms;
+	  guint mask;
+
+          /* Ignore invalid keycodes. */
+          if (keycode < keymap_x11->min_keycode ||
+              keycode > keymap_x11->max_keycode)
+            continue;
+
+          syms = keymap_x11->keymap + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
+
+	  mask = 0;
+	  for (j = 0; j < keymap_x11->keysyms_per_keycode; j++)
+	    {
+	      if (syms[j] == GDK_KEY_Meta_L ||
+		  syms[j] == GDK_KEY_Meta_R)
+		mask |= GDK_META_MASK;
+	      else if (syms[j] == GDK_KEY_Hyper_L ||
+		       syms[j] == GDK_KEY_Hyper_R)
+		mask |= GDK_HYPER_MASK;
+	      else if (syms[j] == GDK_KEY_Super_L ||
+		       syms[j] == GDK_KEY_Super_R)
+		mask |= GDK_SUPER_MASK;
+	    }
+
+	  keymap_x11->modmap[i/keymap_x11->mod_keymap->max_keypermod] |= mask;
+
+          /* The fourth modifier, GDK_MOD1_MASK is 1 << 3.
+	   * Each group of max_keypermod entries refers to the same modifier.
+           */
+          mask = 1 << (i / keymap_x11->mod_keymap->max_keypermod);
+
+          switch (mask)
+            {
+            case GDK_LOCK_MASK:
+              /* Get the Lock keysym.  If any keysym bound to the Lock modifier
+               * is Caps_Lock, we will interpret the modifier as Caps_Lock;
+               * otherwise, if any is bound to Shift_Lock, we will interpret
+               * the modifier as Shift_Lock. Otherwise, the lock modifier
+	       * has no effect.
+               */
+	      for (j = 0; j < keymap_x11->keysyms_per_keycode; j++)
+		{
+		  if (syms[j] == GDK_KEY_Caps_Lock)
+		    keymap_x11->lock_keysym = GDK_KEY_Caps_Lock;
+		  else if (syms[j] == GDK_KEY_Shift_Lock &&
+			   keymap_x11->lock_keysym == GDK_KEY_VoidSymbol)
+		    keymap_x11->lock_keysym = GDK_KEY_Shift_Lock;
+		}
+              break;
+
+            case GDK_CONTROL_MASK:
+            case GDK_SHIFT_MASK:
+            case GDK_MOD1_MASK:
+              /* Some keyboard maps are known to map Mode_Switch as an
+               * extra Mod1 key. In circumstances like that, it won't be
+               * used to switch groups.
+               */
+              break;
+
+            default:
+              /* Find the Mode_Switch and Num_Lock modifiers. */
+              for (j = 0; j < keymap_x11->keysyms_per_keycode; j++)
+                {
+                  if (syms[j] == GDK_KEY_Mode_switch)
+                    {
+                      /* This modifier swaps groups */
+                      keymap_x11->group_switch_mask |= mask;
+                    }
+                  else if (syms[j] == GDK_KEY_Num_Lock)
+                    {
+                      /* This modifier is used for Num_Lock */
+                      keymap_x11->num_lock_mask |= mask;
+                    }
+                }
+              break;
+            }
+        }
+
+      /* Hack: The Sun X server puts the keysym to use when the Num Lock
+       * modifier is on in the third element of the keysym array, instead
+       * of the second.
+       */
+      if ((strcmp (ServerVendor (xdisplay), "Sun Microsystems, Inc.") == 0) &&
+          (keymap_x11->keysyms_per_keycode > 2))
+        keymap_x11->sun_keypad = TRUE;
+      else
+        keymap_x11->sun_keypad = FALSE;
+    }
+}
+
+static const KeySym*
+get_keymap (GdkKeymapX11 *keymap_x11)
+{
+  update_keymaps (keymap_x11);
+  
+  return keymap_x11->keymap;
+}
+
+#define GET_EFFECTIVE_KEYMAP(keymap) get_effective_keymap ((keymap), G_STRFUNC)
+
+static GdkKeymap *
+get_effective_keymap (GdkKeymap  *keymap,
+		      const char *function)
+{
+  if (!keymap)
+    {
+      GDK_NOTE (MULTIHEAD,
+		g_message ("reverting to default display keymap in %s",
+			   function));
+      return gdk_keymap_get_default ();
+    }
+
+  return keymap;
+}
+
+#if HAVE_XKB
+static PangoDirection
+get_direction (XkbDescRec *xkb, 
+	       gint group)
+{
+  gint code;
+
+  gint rtl_minus_ltr = 0; /* total number of RTL keysyms minus LTR ones */
+
+  for (code = xkb->min_key_code; code <= xkb->max_key_code; code++)
+    {
+      gint level = 0;
+      KeySym sym = XkbKeySymEntry (xkb, code, level, group);
+      PangoDirection dir = pango_unichar_direction (gdk_keyval_to_unicode (sym));
+
+      switch (dir)
+	{
+	case PANGO_DIRECTION_RTL:
+	  rtl_minus_ltr++;
+	  break;
+	case PANGO_DIRECTION_LTR:
+	  rtl_minus_ltr--;
+	  break;
+	default:
+	  break;
+	}
+    }
+
+  if (rtl_minus_ltr > 0)
+    return PANGO_DIRECTION_RTL;
+  else
+    return PANGO_DIRECTION_LTR;
+}
+
+static PangoDirection
+get_direction_from_cache (GdkKeymapX11 *keymap_x11,
+			  XkbDescPtr xkb,
+			  gint group)
+{
+  Atom group_atom = xkb->names->groups[group];
+
+  gboolean cache_hit = FALSE;
+  DirectionCacheEntry *cache = keymap_x11->group_direction_cache;
+
+  PangoDirection direction = PANGO_DIRECTION_NEUTRAL;
+  gint i;
+
+  if (keymap_x11->have_direction)
+    {
+      /* lookup in cache */
+      for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
+      {
+	if (cache[i].group_atom == group_atom)
+	  {
+	    cache_hit = TRUE;
+	    cache[i].serial = keymap_x11->current_cache_serial++; /* freshen */
+	    direction = cache[i].direction;
+	    group_atom = cache[i].group_atom;
+	    break;
+	  }
+      }
+    }
+  else
+    {
+      /* initialize cache */
+      for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
+	{
+	  cache[i].group_atom = 0;
+	  cache[i].serial = keymap_x11->current_cache_serial;
+	}
+      keymap_x11->current_cache_serial++;
+    }
+
+  /* insert in cache */
+  if (!cache_hit)
+    {
+      gint oldest = 0;
+
+      direction = get_direction (xkb, group);
+
+      /* remove the oldest entry */
+      for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
+	{
+	  if (cache[i].serial < cache[oldest].serial)
+	    oldest = i;
+	}
+      
+      cache[oldest].group_atom = group_atom;
+      cache[oldest].direction = direction;
+      cache[oldest].serial = keymap_x11->current_cache_serial++;
+    }
+
+  return direction;
+}
+
+static int
+get_num_groups (GdkKeymap *keymap,
+		XkbDescPtr xkb)
+{
+      Display *display = KEYMAP_XDISPLAY (keymap);
+      XkbGetControls(display, XkbSlowKeysMask, xkb);
+      XkbGetUpdatedMap (display, XkbKeySymsMask | XkbKeyTypesMask |
+			XkbModifierMapMask | XkbVirtualModsMask, xkb);
+      return xkb->ctrls->num_groups;
+}
+
+static gboolean
+update_direction (GdkKeymapX11 *keymap_x11,
+		  gint          group)
+{
+  XkbDescPtr xkb = get_xkb (keymap_x11);
+  Atom group_atom;
+  gboolean had_direction;
+  PangoDirection old_direction;
+      
+  had_direction = keymap_x11->have_direction;
+  old_direction = keymap_x11->current_direction;
+
+  group_atom = xkb->names->groups[group];
+
+  /* a group change? */
+  if (!keymap_x11->have_direction || keymap_x11->current_group_atom != group_atom)
+    {
+      keymap_x11->current_direction = get_direction_from_cache (keymap_x11, xkb, group);
+      keymap_x11->current_group_atom = group_atom;
+      keymap_x11->have_direction = TRUE;
+    }
+
+  return !had_direction || old_direction != keymap_x11->current_direction;
+}
+
+static gboolean
+update_lock_state (GdkKeymapX11 *keymap_x11,
+                   gint          locked_mods)
+{
+  gboolean caps_lock_state;
+  gboolean num_lock_state;
+
+  caps_lock_state = keymap_x11->caps_lock_state;
+  num_lock_state = keymap_x11->num_lock_state;
+
+  keymap_x11->caps_lock_state = (locked_mods & GDK_LOCK_MASK) != 0;
+  keymap_x11->num_lock_state = (locked_mods & keymap_x11->num_lock_mask) != 0;
+
+  return (caps_lock_state != keymap_x11->caps_lock_state)
+    || (num_lock_state != keymap_x11->num_lock_state);
+}
+
+/* keep this in sync with the XkbSelectEventDetails() call 
+ * in gdk_display_open()
+ */
+void
+_gdk_keymap_state_changed (GdkDisplay *display,
+			   XEvent     *xevent)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  XkbEvent *xkb_event = (XkbEvent *)xevent;
+  
+  if (display_x11->keymap)
+    {
+      GdkKeymapX11 *keymap_x11 = GDK_KEYMAP_X11 (display_x11->keymap);
+      
+      if (update_direction (keymap_x11, XkbStateGroup (&xkb_event->state)))
+	g_signal_emit_by_name (keymap_x11, "direction-changed");      
+
+      if (update_lock_state (keymap_x11, xkb_event->state.locked_mods))
+        g_signal_emit_by_name (keymap_x11, "state-changed");
+    }
+}
+
+#endif /* HAVE_XKB */
+
+void
+_gdk_keymap_keys_changed (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  
+  ++display_x11->keymap_serial;
+  
+  if (display_x11->keymap)
+    g_signal_emit_by_name (display_x11->keymap, "keys_changed", 0);
+}
+
+/** 
+ * gdk_keymap_get_direction:
+ * @keymap: a #GdkKeymap or %NULL to use the default keymap
+ *
+ * Returns the direction of effective layout of the keymap.
+ *
+ * Returns: %PANGO_DIRECTION_LTR or %PANGO_DIRECTION_RTL 
+ *   if it can determine the direction. %PANGO_DIRECTION_NEUTRAL 
+ *   otherwise.
+ **/
+PangoDirection
+gdk_keymap_get_direction (GdkKeymap *keymap)
+{
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+  
+#if HAVE_XKB
+  if (KEYMAP_USE_XKB (keymap))
+    {
+      GdkKeymapX11 *keymap_x11 = GDK_KEYMAP_X11 (keymap);
+
+      if (!keymap_x11->have_direction)
+	{
+	  GdkDisplay *display = GDK_KEYMAP (keymap_x11)->display;
+	  XkbStateRec state_rec;
+
+	  XkbGetState (GDK_DISPLAY_XDISPLAY (display), XkbUseCoreKbd, 
+		       &state_rec);
+	  update_direction (keymap_x11, XkbStateGroup (&state_rec));
+	}
+  
+      return keymap_x11->current_direction;
+    }
+  else
+#endif /* HAVE_XKB */
+    return PANGO_DIRECTION_NEUTRAL;
+}
+
+/** 
+ * gdk_keymap_have_bidi_layouts:
+ * @keymap: a #GdkKeymap or %NULL to use the default keymap
+ *
+ * Determines if keyboard layouts for both right-to-left and left-to-right
+ * languages are in use.
+ *
+ * Returns: %TRUE if there are layouts in both directions, %FALSE otherwise
+ *
+ * Since: 2.12
+ **/
+gboolean
+gdk_keymap_have_bidi_layouts (GdkKeymap *keymap)
+{
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+
+#if HAVE_XKB
+  if (KEYMAP_USE_XKB (keymap))
+    {
+      GdkKeymapX11 *keymap_x11 = GDK_KEYMAP_X11 (keymap);
+      XkbDescPtr xkb = get_xkb (keymap_x11);
+      int num_groups = get_num_groups (keymap, xkb);
+
+      int i;
+      gboolean have_ltr_keyboard = FALSE;
+      gboolean have_rtl_keyboard = FALSE;
+
+      for (i = 0; i < num_groups; i++)
+      {
+	if (get_direction_from_cache (keymap_x11, xkb, i) == PANGO_DIRECTION_RTL)
+	  have_rtl_keyboard = TRUE;
+	else
+	  have_ltr_keyboard = TRUE;
+      }
+
+      return have_ltr_keyboard && have_rtl_keyboard;
+    }
+  else
+#endif /* HAVE_XKB */
+    return FALSE;
+}
+
+/**
+ * gdk_keymap_get_caps_lock_state:
+ * @keymap: a #GdkKeymap
+ *
+ * Returns whether the Caps Lock modifer is locked. 
+ *
+ * Returns: %TRUE if Caps Lock is on
+ *
+ * Since: 2.16
+ */
+gboolean
+gdk_keymap_get_caps_lock_state (GdkKeymap *keymap)
+{
+  GdkKeymapX11 *keymap_x11;
+  
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+  
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+  
+  return keymap_x11->caps_lock_state;
+}
+
+/**
+ * gdk_keymap_get_num_lock_state:
+ * @keymap: a #GdkKeymap
+ *
+ * Returns whether the Num Lock modifer is locked.
+ *
+ * Returns: %TRUE if Num Lock is on
+ *
+ * Since: 3.0
+ */
+gboolean
+gdk_keymap_get_num_lock_state (GdkKeymap *keymap)
+{
+  GdkKeymapX11 *keymap_x11;
+
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+
+  return keymap_x11->num_lock_state;
+}
+
+/**
+ * gdk_keymap_get_entries_for_keyval:
+ * @keymap: (allow-none): a #GdkKeymap, or %NULL to use the default keymap
+ * @keyval: a keyval, such as %GDK_a, %GDK_Up, %GDK_Return, etc.
+ * @keys: (out): return location for an array of #GdkKeymapKey
+ * @n_keys: (out): return location for number of elements in returned array
+ *
+ * Obtains a list of keycode/group/level combinations that will
+ * generate @keyval. Groups and levels are two kinds of keyboard mode;
+ * in general, the level determines whether the top or bottom symbol
+ * on a key is used, and the group determines whether the left or
+ * right symbol is used. On US keyboards, the shift key changes the
+ * keyboard level, and there are no groups. A group switch key might
+ * convert a keyboard between Hebrew to English modes, for example.
+ * #GdkEventKey contains a %group field that indicates the active
+ * keyboard group. The level is computed from the modifier mask.
+ * The returned array should be freed
+ * with g_free().
+ *
+ * Return value: %TRUE if keys were found and returned
+ **/
+gboolean
+gdk_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
+                                   guint          keyval,
+                                   GdkKeymapKey **keys,
+                                   gint          *n_keys)
+{
+  GArray *retval;
+  GdkKeymapX11 *keymap_x11;
+
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
+  g_return_val_if_fail (keys != NULL, FALSE);
+  g_return_val_if_fail (n_keys != NULL, FALSE);
+  g_return_val_if_fail (keyval != 0, FALSE);
+
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+  
+  retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
+
+#ifdef HAVE_XKB
+  if (KEYMAP_USE_XKB (keymap))
+    {
+      /* See sec 15.3.4 in XKB docs */
+
+      XkbDescRec *xkb = get_xkb (keymap_x11);
+      gint keycode;
+      
+      keycode = keymap_x11->min_keycode;
+
+      while (keycode <= keymap_x11->max_keycode)
+        {
+          gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode); /* "key width" */
+          gint group = 0;
+          gint level = 0;
+          gint total_syms = XkbKeyNumSyms (xkb, keycode);
+          gint i = 0;
+          KeySym *entry;
+
+          /* entry is an array with all syms for group 0, all
+           * syms for group 1, etc. and for each group the
+           * shift level syms are in order
+           */
+          entry = XkbKeySymsPtr (xkb, keycode);
+
+          while (i < total_syms)
+            {
+              /* check out our cool loop invariant */
+              g_assert (i == (group * max_shift_levels + level));
+
+              if (entry[i] == keyval)
+                {
+                  /* Found a match */
+                  GdkKeymapKey key;
+
+                  key.keycode = keycode;
+                  key.group = group;
+                  key.level = level;
+
+                  g_array_append_val (retval, key);
+
+                  g_assert (XkbKeySymEntry (xkb, keycode, level, group) == 
+			    keyval);
+                }
+
+              ++level;
+
+              if (level == max_shift_levels)
+                {
+                  level = 0;
+                  ++group;
+                }
+
+              ++i;
+            }
+
+          ++keycode;
+        }
+    }
+  else
+#endif
+    {
+      const KeySym *map = get_keymap (keymap_x11);
+      gint keycode;
+      
+      keycode = keymap_x11->min_keycode;
+      while (keycode <= keymap_x11->max_keycode)
+        {
+          const KeySym *syms = map + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
+          gint i = 0;
+
+          while (i < keymap_x11->keysyms_per_keycode)
+            {
+              if (syms[i] == keyval)
+                {
+                  /* found a match */
+                  GdkKeymapKey key;
+
+                  key.keycode = keycode;
+
+                  /* The "classic" non-XKB keymap has 2 levels per group */
+                  key.group = i / 2;
+                  key.level = i % 2;
+
+                  g_array_append_val (retval, key);
+                }
+              
+              ++i;
+            }
+          
+          ++keycode;
+        }
+    }
+
+  if (retval->len > 0)
+    {
+      *keys = (GdkKeymapKey*) retval->data;
+      *n_keys = retval->len;
+    }
+  else
+    {
+      *keys = NULL;
+      *n_keys = 0;
+    }
+      
+  g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
+
+  return *n_keys > 0;
+}
+
+/**
+ * gdk_keymap_get_entries_for_keycode:
+ * @keymap: (allow-none): a #GdkKeymap or %NULL to use the default keymap
+ * @hardware_keycode: a keycode
+ * @keys: (out): return location for array of #GdkKeymapKey, or %NULL
+ * @keyvals: (out): return location for array of keyvals, or %NULL
+ * @n_entries: length of @keys and @keyvals
+ *
+ * Returns the keyvals bound to @hardware_keycode.
+ * The Nth #GdkKeymapKey in @keys is bound to the Nth
+ * keyval in @keyvals. Free the returned arrays with g_free().
+ * When a keycode is pressed by the user, the keyval from
+ * this list of entries is selected by considering the effective
+ * keyboard group and level. See gdk_keymap_translate_keyboard_state().
+ *
+ * Returns: %TRUE if there were any entries
+ **/
+gboolean
+gdk_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
+                                    guint          hardware_keycode,
+                                    GdkKeymapKey **keys,
+                                    guint        **keyvals,
+                                    gint          *n_entries)
+{
+  GdkKeymapX11 *keymap_x11;
+  
+  GArray *key_array;
+  GArray *keyval_array;
+
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
+  g_return_val_if_fail (n_entries != NULL, FALSE);
+
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+
+  update_keyrange (keymap_x11);
+
+  if (hardware_keycode < keymap_x11->min_keycode ||
+      hardware_keycode > keymap_x11->max_keycode)
+    {
+      if (keys)
+        *keys = NULL;
+      if (keyvals)
+        *keyvals = NULL;
+
+      *n_entries = 0;
+      return FALSE;
+    }
+  
+  if (keys)
+    key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
+  else
+    key_array = NULL;
+  
+  if (keyvals)
+    keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
+  else
+    keyval_array = NULL;
+  
+#ifdef HAVE_XKB
+  if (KEYMAP_USE_XKB (keymap))
+    {
+      /* See sec 15.3.4 in XKB docs */
+
+      XkbDescRec *xkb = get_xkb (keymap_x11);
+      gint max_shift_levels;
+      gint group = 0;
+      gint level = 0;
+      gint total_syms;
+      gint i = 0;
+      KeySym *entry;
+      
+      max_shift_levels = XkbKeyGroupsWidth (xkb, hardware_keycode); /* "key width" */
+      total_syms = XkbKeyNumSyms (xkb, hardware_keycode);
+
+      /* entry is an array with all syms for group 0, all
+       * syms for group 1, etc. and for each group the
+       * shift level syms are in order
+       */
+      entry = XkbKeySymsPtr (xkb, hardware_keycode);
+
+      while (i < total_syms)
+        {          
+          /* check out our cool loop invariant */          
+          g_assert (i == (group * max_shift_levels + level));
+
+          if (key_array)
+            {
+              GdkKeymapKey key;
+              
+              key.keycode = hardware_keycode;
+              key.group = group;
+              key.level = level;
+              
+              g_array_append_val (key_array, key);
+            }
+
+          if (keyval_array)
+            g_array_append_val (keyval_array, entry[i]);
+          
+          ++level;
+          
+          if (level == max_shift_levels)
+            {
+              level = 0;
+              ++group;
+            }
+          
+          ++i;
+        }
+    }
+  else
+#endif
+    {
+      const KeySym *map = get_keymap (keymap_x11);
+      const KeySym *syms;
+      gint i = 0;
+
+      syms = map + (hardware_keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
+
+      while (i < keymap_x11->keysyms_per_keycode)
+        {
+          if (key_array)
+            {
+              GdkKeymapKey key;
+          
+              key.keycode = hardware_keycode;
+              
+              /* The "classic" non-XKB keymap has 2 levels per group */
+              key.group = i / 2;
+              key.level = i % 2;
+              
+              g_array_append_val (key_array, key);
+            }
+
+          if (keyval_array)
+            g_array_append_val (keyval_array, syms[i]);
+          
+          ++i;
+        }
+    }
+
+  *n_entries = 0;
+
+  if (keys)
+    {
+      *n_entries = key_array->len;
+      *keys = (GdkKeymapKey*) g_array_free (key_array, FALSE);
+    }
+  
+  if (keyvals)
+    {
+      *n_entries = keyval_array->len;
+      *keyvals = (guint*) g_array_free (keyval_array, FALSE);
+    }
+
+  return *n_entries > 0;
+}
+
+
+/**
+ * gdk_keymap_lookup_key:
+ * @keymap: a #GdkKeymap or %NULL to use the default keymap
+ * @key: a #GdkKeymapKey with keycode, group, and level initialized
+ * 
+ * Looks up the keyval mapped to a keycode/group/level triplet.
+ * If no keyval is bound to @key, returns 0. For normal user input,
+ * you want to use gdk_keymap_translate_keyboard_state() instead of
+ * this function, since the effective group/level may not be
+ * the same as the current keyboard state.
+ * 
+ * Return value: a keyval, or 0 if none was mapped to the given @key
+ **/
+guint
+gdk_keymap_lookup_key (GdkKeymap          *keymap,
+                       const GdkKeymapKey *key)
+{
+  GdkKeymapX11 *keymap_x11;
+  
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0);
+  g_return_val_if_fail (key != NULL, 0);
+  g_return_val_if_fail (key->group < 4, 0);
+
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+  
+#ifdef HAVE_XKB
+  if (KEYMAP_USE_XKB (keymap))
+    {
+      XkbDescRec *xkb = get_xkb (keymap_x11);
+      
+      return XkbKeySymEntry (xkb, key->keycode, key->level, key->group);
+    }
+  else
+#endif
+    {
+      const KeySym *map = get_keymap (keymap_x11);
+      const KeySym *syms = map + (key->keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
+      return get_symbol (syms, keymap_x11, key->group, key->level);
+    }
+}
+
+#ifdef HAVE_XKB
+/* This is copied straight from XFree86 Xlib, to:
+ *  - add the group and level return.
+ *  - change the interpretation of mods_rtrn as described
+ *    in the docs for gdk_keymap_translate_keyboard_state()
+ * It's unchanged for ease of diff against the Xlib sources; don't
+ * reformat it.
+ */
+static Bool
+MyEnhancedXkbTranslateKeyCode(register XkbDescPtr     xkb,
+                              KeyCode                 key,
+                              register unsigned int   mods,
+                              unsigned int *          mods_rtrn,
+                              KeySym *                keysym_rtrn,
+                              int *                   group_rtrn,
+                              int *                   level_rtrn)
+{
+    XkbKeyTypeRec *type;
+    int col,nKeyGroups;
+    unsigned preserve,effectiveGroup;
+    KeySym *syms;
+
+    if (mods_rtrn!=NULL)
+        *mods_rtrn = 0;
+
+    nKeyGroups= XkbKeyNumGroups(xkb,key);
+    if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
+        if (keysym_rtrn!=NULL)
+            *keysym_rtrn = NoSymbol;
+        return False;
+    }
+
+    syms = XkbKeySymsPtr(xkb,key);
+
+    /* find the offset of the effective group */
+    col = 0;
+    effectiveGroup= XkbGroupForCoreState(mods);
+    if ( effectiveGroup>=nKeyGroups ) {
+        unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
+        switch (XkbOutOfRangeGroupAction(groupInfo)) {
+            default:
+                effectiveGroup %= nKeyGroups;
+                break;
+            case XkbClampIntoRange:
+                effectiveGroup = nKeyGroups-1;
+                break;
+            case XkbRedirectIntoRange:
+                effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
+                if (effectiveGroup>=nKeyGroups)
+                    effectiveGroup= 0;
+                break;
+        }
+    }
+    col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
+    type = XkbKeyKeyType(xkb,key,effectiveGroup);
+
+    preserve= 0;
+    if (type->map) { /* find the column (shift level) within the group */
+        register int i;
+        register XkbKTMapEntryPtr entry;
+	/* ---- Begin section modified for GDK  ---- */
+	int found = 0;
+	
+        for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
+	    if (mods_rtrn) {
+		int bits = 0;
+		unsigned long tmp = entry->mods.mask;
+		while (tmp) {
+		    if ((tmp & 1) == 1)
+			bits++;
+		    tmp >>= 1;
+		}
+		/* We always add one-modifiers levels to mods_rtrn since
+		 * they can't wipe out bits in the state unless the
+		 * level would be triggered. But return other modifiers
+		 * 
+		 */
+		if (bits == 1 || (mods&type->mods.mask)==entry->mods.mask)
+		    *mods_rtrn |= entry->mods.mask;
+	    }
+	    
+            if (!found&&entry->active&&((mods&type->mods.mask)==entry->mods.mask)) {
+                col+= entry->level;
+                if (type->preserve)
+                    preserve= type->preserve[i].mask;
+
+                if (level_rtrn)
+                  *level_rtrn = entry->level;
+                
+                found = 1;
+            }
+        }
+	/* ---- End section modified for GDK ---- */
+    }
+
+    if (keysym_rtrn!=NULL)
+        *keysym_rtrn= syms[col];
+    if (mods_rtrn) {
+	/* ---- Begin section modified for GDK  ---- */
+        *mods_rtrn &= ~preserve;
+	/* ---- End section modified for GDK ---- */
+	
+        /* ---- Begin stuff GDK comments out of the original Xlib version ---- */
+        /* This is commented out because xkb_info is a private struct */
+
+#if 0
+        /* The Motif VTS doesn't get the help callback called if help
+         * is bound to Shift+<whatever>, and it appears as though it 
+         * is XkbTranslateKeyCode that is causing the problem.  The 
+         * core X version of XTranslateKey always OR's in ShiftMask 
+         * and LockMask for mods_rtrn, so this "fix" keeps this behavior 
+         * and solves the VTS problem.
+         */
+        if ((xkb->dpy)&&(xkb->dpy->xkb_info)&&
+            (xkb->dpy->xkb_info->xlib_ctrls&XkbLC_AlwaysConsumeShiftAndLock)) {            *mods_rtrn|= (ShiftMask|LockMask);
+        }
+#endif
+        
+        /* ---- End stuff GDK comments out of the original Xlib version ---- */
+    }
+
+    /* ---- Begin stuff GDK adds to the original Xlib version ---- */
+
+    if (group_rtrn)
+      *group_rtrn = effectiveGroup;
+    
+    /* ---- End stuff GDK adds to the original Xlib version ---- */
+    
+    return (syms[col] != NoSymbol);
+}
+#endif /* HAVE_XKB */
+
+/* Translates from keycode/state to keysymbol using the traditional interpretation
+ * of the keyboard map. See section 12.7 of the Xlib reference manual
+ */
+static guint
+translate_keysym (GdkKeymapX11   *keymap_x11,
+		  guint           hardware_keycode,
+		  gint            group,
+		  GdkModifierType state,
+		  gint           *effective_group,
+		  gint           *effective_level)
+{
+  const KeySym *map = get_keymap (keymap_x11);
+  const KeySym *syms = map + (hardware_keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
+
+#define SYM(k,g,l) get_symbol (syms, k,g,l)
+
+  GdkModifierType shift_modifiers;
+  gint shift_level;
+  guint tmp_keyval;
+  gint num_lock_index;
+
+  shift_modifiers = GDK_SHIFT_MASK;
+  if (keymap_x11->lock_keysym == GDK_KEY_Shift_Lock)
+    shift_modifiers |= GDK_LOCK_MASK;
+
+  /* Fall back to the first group if the passed in group is empty
+   */
+  if (!(SYM (keymap_x11, group, 0) || SYM (keymap_x11, group, 1)) &&
+      (SYM (keymap_x11, 0, 0) || SYM (keymap_x11, 0, 1)))
+    group = 0;
+
+  /* Hack: On Sun, the Num Lock modifier uses the third element in the
+   * keysym array, and Mode_Switch does not apply for a keypad key.
+   */
+  if (keymap_x11->sun_keypad)
+    {
+      num_lock_index = 2;
+      
+      if (group != 0)
+	{
+	  gint i;
+	  
+	  for (i = 0; i < keymap_x11->keysyms_per_keycode; i++)
+	    if (KEYSYM_IS_KEYPAD (SYM (keymap_x11, 0, i)))
+	      group = 0;
+	}
+    }
+  else
+    num_lock_index = 1;
+
+  if ((state & keymap_x11->num_lock_mask) &&
+      KEYSYM_IS_KEYPAD (SYM (keymap_x11, group, num_lock_index)))
+    {
+      /* Shift, Shift_Lock cancel Num_Lock
+       */
+      shift_level = (state & shift_modifiers) ? 0 : num_lock_index;
+      if (!SYM (keymap_x11, group, shift_level) && SYM (keymap_x11, group, 0))
+        shift_level = 0;
+
+       tmp_keyval = SYM (keymap_x11, group, shift_level);
+    }
+  else
+    {
+      /* Fall back to the first level if no symbol for the level
+       * we were passed.
+       */
+      shift_level = (state & shift_modifiers) ? 1 : 0;
+      if (!SYM (keymap_x11, group, shift_level) && SYM (keymap_x11, group, 0))
+	shift_level = 0;
+  
+      tmp_keyval = SYM (keymap_x11, group, shift_level);
+      
+      if (keymap_x11->lock_keysym == GDK_KEY_Caps_Lock && (state & GDK_LOCK_MASK) != 0)
+	{
+	  guint upper = gdk_keyval_to_upper (tmp_keyval);
+	  if (upper != tmp_keyval)
+	    tmp_keyval = upper;
+	}
+    }
+
+  if (effective_group)
+    *effective_group = group;
+      
+  if (effective_level)
+    *effective_level = shift_level;
+
+  return tmp_keyval;
+  
+#undef SYM
+}
+
+/**
+ * gdk_keymap_translate_keyboard_state:
+ * @keymap: (allow-none): a #GdkKeymap, or %NULL to use the default
+ * @hardware_keycode: a keycode
+ * @state: a modifier state
+ * @group: active keyboard group
+ * @keyval: (out) (allow-none): return location for keyval, or %NULL
+ * @effective_group: (out) (allow-none): return location for effective group, or %NULL
+ * @level: (out) (allow-none):  return location for level, or %NULL
+ * @consumed_modifiers: (out) (allow-none):  return location for modifiers that were used to
+ *     determine the group or level, or %NULL
+ *
+ * Translates the contents of a #GdkEventKey into a keyval, effective
+ * group, and level. Modifiers that affected the translation and
+ * are thus unavailable for application use are returned in
+ * @consumed_modifiers.  See <xref linkend="key-group-explanation"/> for an explanation of
+ * groups and levels.  The @effective_group is the group that was
+ * actually used for the translation; some keys such as Enter are not
+ * affected by the active keyboard group. The @level is derived from
+ * @state. For convenience, #GdkEventKey already contains the translated
+ * keyval, so this function isn't as useful as you might think.
+ *
+ * <note><para>
+ * @consumed_modifiers gives modifiers that should be masked out
+ * from @state when comparing this key press to a hot key. For
+ * instance, on a US keyboard, the <literal>plus</literal>
+ * symbol is shifted, so when comparing a key press to a
+ * <literal>&lt;Control&gt;plus</literal> accelerator &lt;Shift&gt; should
+ * be masked out.
+ * </para>
+ * <informalexample><programlisting>
+ * &sol;* We want to ignore irrelevant modifiers like ScrollLock *&sol;
+ * &num;define ALL_ACCELS_MASK (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK)
+ * gdk_keymap_translate_keyboard_state (keymap, event->hardware_keycode,
+ *                                      event->state, event->group,
+ *                                      &amp;keyval, NULL, NULL, &amp;consumed);
+ * if (keyval == GDK_PLUS &&
+ *     (event->state &amp; ~consumed &amp; ALL_ACCELS_MASK) == GDK_CONTROL_MASK)
+ *   &sol;* Control was pressed *&sol;
+ * </programlisting></informalexample>
+ * <para>
+ * An older interpretation @consumed_modifiers was that it contained
+ * all modifiers that might affect the translation of the key;
+ * this allowed accelerators to be stored with irrelevant consumed
+ * modifiers, by doing:</para>
+ * <informalexample><programlisting>
+ * &sol;* XXX Don't do this XXX *&sol;
+ * if (keyval == accel_keyval &&
+ *     (event->state &amp; ~consumed &amp; ALL_ACCELS_MASK) == (accel_mods &amp; ~consumed))
+ *   &sol;* Accelerator was pressed *&sol;
+ * </programlisting></informalexample>
+ * <para>
+ * However, this did not work if multi-modifier combinations were
+ * used in the keymap, since, for instance, <literal>&lt;Control&gt;</literal>
+ * would be masked out even if only <literal>&lt;Control&gt;&lt;Alt&gt;</literal>
+ * was used in the keymap. To support this usage as well as well as
+ * possible, all <emphasis>single modifier</emphasis> combinations
+ * that could affect the key for any combination of modifiers will
+ * be returned in @consumed_modifiers; multi-modifier combinations
+ * are returned only when actually found in @state. When you store
+ * accelerators, you should always store them with consumed modifiers
+ * removed. Store <literal>&lt;Control&gt;plus</literal>,
+ * not <literal>&lt;Control&gt;&lt;Shift&gt;plus</literal>,
+ * </para></note>
+ * 
+ * Return value: %TRUE if there was a keyval bound to the keycode/state/group
+ **/
+gboolean
+gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
+                                     guint            hardware_keycode,
+                                     GdkModifierType  state,
+                                     gint             group,
+                                     guint           *keyval,
+                                     gint            *effective_group,
+                                     gint            *level,
+                                     GdkModifierType *consumed_modifiers)
+{
+  GdkKeymapX11 *keymap_x11;
+  KeySym tmp_keyval = NoSymbol;
+  guint tmp_modifiers;
+
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
+  g_return_val_if_fail (group < 4, FALSE);
+
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);  
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+
+  if (keyval)
+    *keyval = NoSymbol;
+  if (effective_group)
+    *effective_group = 0;
+  if (level)
+    *level = 0;
+  if (consumed_modifiers)
+    *consumed_modifiers = 0;
+
+  update_keyrange (keymap_x11);
+  
+  if (hardware_keycode < keymap_x11->min_keycode ||
+      hardware_keycode > keymap_x11->max_keycode)
+    return FALSE;
+
+#ifdef HAVE_XKB
+  if (KEYMAP_USE_XKB (keymap))
+    {
+      XkbDescRec *xkb = get_xkb (keymap_x11);
+
+      /* replace bits 13 and 14 with the provided group */
+      state &= ~(1 << 13 | 1 << 14);
+      state |= group << 13;
+      
+      MyEnhancedXkbTranslateKeyCode (xkb,
+                                     hardware_keycode,
+                                     state,
+                                     &tmp_modifiers,
+                                     &tmp_keyval,
+                                     effective_group,
+                                     level);
+
+      if (state & ~tmp_modifiers & LockMask)
+	tmp_keyval = gdk_keyval_to_upper (tmp_keyval);
+
+      /* We need to augment the consumed modifiers with LockMask, since
+       * we handle that ourselves, and also with the group bits
+       */
+      tmp_modifiers |= LockMask | 1 << 13 | 1 << 14;
+    }
+  else
+#endif
+    {
+      GdkModifierType bit;
+      
+      tmp_modifiers = 0;
+
+      /* We see what modifiers matter by trying the translation with
+       * and without each possible modifier
+       */
+      for (bit = GDK_SHIFT_MASK; bit < GDK_BUTTON1_MASK; bit <<= 1)
+	{
+	  /* Handling of the group here is a bit funky; a traditional
+	   * X keyboard map can have more than two groups, but no way
+	   * of accessing the extra groups is defined. We allow a
+	   * caller to pass in any group to this function, but we 
+	   * only can represent switching between group 0 and 1 in
+	   * consumed modifiers.
+	   */
+	  if (translate_keysym (keymap_x11, hardware_keycode,
+				(bit == keymap_x11->group_switch_mask) ? 0 : group,
+				state & ~bit,
+				NULL, NULL) !=
+	      translate_keysym (keymap_x11, hardware_keycode,
+				(bit == keymap_x11->group_switch_mask) ? 1 : group,
+				state | bit,
+				NULL, NULL))
+	    tmp_modifiers |= bit;
+	}
+      
+      tmp_keyval = translate_keysym (keymap_x11, hardware_keycode,
+				     group, state,
+				     level, effective_group);
+    }
+
+  if (consumed_modifiers)
+    *consumed_modifiers = tmp_modifiers;
+				
+  if (keyval)
+    *keyval = tmp_keyval;
+
+  return tmp_keyval != NoSymbol;
+}
+
+
+/* Key handling not part of the keymap */
+/**
+ * gdk_keyval_name:
+ *
+ * Converts a key value into a symbolic name.
+ * The names are the same as those in the 
+ * <filename>&lt;gdk/gdkkeysyms.h&gt;</filename> header file
+ * but without the leading "GDK_KEY_".
+ *
+ * @keyval: a key value.
+ * 
+ * Return value: (transfer none): a string containing the name of the key, or 
+ * %NULL if @keyval is not a valid key. The string should not be modified.
+ **/
+gchar*
+gdk_keyval_name (guint	      keyval)
+{
+  switch (keyval)
+    {
+    case GDK_KEY_Page_Up:
+      return "Page_Up";
+    case GDK_KEY_Page_Down:
+      return "Page_Down";
+    case GDK_KEY_KP_Page_Up:
+      return "KP_Page_Up";
+    case GDK_KEY_KP_Page_Down:
+      return "KP_Page_Down";
+    }
+  
+  return XKeysymToString (keyval);
+}
+
+guint
+gdk_keyval_from_name (const gchar *keyval_name)
+{
+  g_return_val_if_fail (keyval_name != NULL, 0);
+  
+  return XStringToKeysym (keyval_name);
+}
+
+#ifdef HAVE_XCONVERTCASE
+void
+gdk_keyval_convert_case (guint symbol,
+			 guint *lower,
+			 guint *upper)
+{
+  KeySym xlower = 0;
+  KeySym xupper = 0;
+
+  /* Check for directly encoded 24-bit UCS characters: */
+  if ((symbol & 0xff000000) == 0x01000000)
+    {
+      if (lower)
+	*lower = gdk_unicode_to_keyval (g_unichar_tolower (symbol & 0x00ffffff));
+      if (upper)
+	*upper = gdk_unicode_to_keyval (g_unichar_toupper (symbol & 0x00ffffff));
+      return;
+    }
+  
+  if (symbol)
+    XConvertCase (symbol, &xlower, &xupper);
+
+  if (lower)
+    *lower = xlower;
+  if (upper)
+    *upper = xupper;
+}  
+#endif /* HAVE_XCONVERTCASE */
+
+gint
+_gdk_x11_get_group_for_state (GdkDisplay      *display,
+			      GdkModifierType  state)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  
+#ifdef HAVE_XKB
+  if (display_x11->use_xkb)
+    {
+      return XkbGroupForCoreState (state);
+    }
+  else
+#endif
+    {
+      GdkKeymapX11 *keymap_impl = GDK_KEYMAP_X11 (gdk_keymap_get_for_display (display));
+      update_keymaps (keymap_impl);
+      return (state & keymap_impl->group_switch_mask) ? 1 : 0;
+    }
+}
+
+void
+_gdk_keymap_add_virtual_modifiers_compat (GdkKeymap       *keymap,
+				          GdkModifierType *modifiers)
+{
+  GdkKeymapX11 *keymap_x11;
+  int i;
+  
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+
+  for (i = 3; i < 8; i++)
+    {
+      if ((1 << i) & *modifiers)
+        {
+	  if (keymap_x11->modmap[i] & GDK_MOD1_MASK)
+	    *modifiers |= GDK_MOD1_MASK;
+	  else if (keymap_x11->modmap[i] & GDK_SUPER_MASK)
+	    *modifiers |= GDK_SUPER_MASK;
+	  else if (keymap_x11->modmap[i] & GDK_HYPER_MASK)
+	    *modifiers |= GDK_HYPER_MASK;
+	  else if (keymap_x11->modmap[i] & GDK_META_MASK)
+	    *modifiers |= GDK_META_MASK;
+        }
+    }
+}
+
+/**
+ * gdk_keymap_add_virtual_modifiers:
+ * @keymap: a #GdkKeymap
+ * @state: pointer to the modifier mask to change
+ *
+ * Adds virtual modifiers (i.e. Super, Hyper and Meta) which correspond
+ * to the real modifiers (i.e Mod2, Mod3, ...) in @modifiers.
+ * are set in @state to their non-virtual counterparts (i.e. Mod2,
+ * Mod3,...) and set the corresponding bits in @state.
+ *
+ * GDK already does this before delivering key events, but for
+ * compatibility reasons, it only sets the first virtual modifier
+ * it finds, whereas this function sets all matching virtual modifiers.
+ *
+ * This function is useful when matching key events against
+ * accelerators.
+ *
+ * Since: 2.20
+ */
+void
+gdk_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
+			          GdkModifierType *state)
+{
+  GdkKeymapX11 *keymap_x11;
+  int i;
+
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+
+  for (i = 3; i < 8; i++)
+    {
+      if ((1 << i) & *state)
+        {
+	  if (keymap_x11->modmap[i] & GDK_MOD1_MASK)
+	    *state |= GDK_MOD1_MASK;
+	  if (keymap_x11->modmap[i] & GDK_SUPER_MASK)
+	    *state |= GDK_SUPER_MASK;
+	  if (keymap_x11->modmap[i] & GDK_HYPER_MASK)
+	    *state |= GDK_HYPER_MASK;
+	  if (keymap_x11->modmap[i] & GDK_META_MASK)
+	    *state |= GDK_META_MASK;
+        }
+    }
+}
+
+gboolean
+_gdk_keymap_key_is_modifier (GdkKeymap *keymap,
+			     guint      keycode)
+{
+  GdkKeymapX11 *keymap_x11;
+  gint i;
+
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);  
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+
+  if (keycode < keymap_x11->min_keycode ||
+      keycode > keymap_x11->max_keycode)
+    return FALSE;
+
+#ifdef HAVE_XKB
+  if (KEYMAP_USE_XKB (keymap))
+    {
+      XkbDescRec *xkb = get_xkb (keymap_x11);
+      
+      if (xkb->map->modmap && xkb->map->modmap[keycode] != 0)
+	return TRUE;
+    }
+  else
+#endif
+    {
+      for (i = 0; i < 8 * keymap_x11->mod_keymap->max_keypermod; i++)
+	{
+	  if (keycode == keymap_x11->mod_keymap->modifiermap[i])
+	    return TRUE;
+	}
+    }
+
+  return FALSE;
+}
+
+/**
+ * gdk_keymap_map_virtual_modifiers:
+ * @keymap: a #GdkKeymap
+ * @state: pointer to the modifier state to map
+ *
+ * Maps the virtual modifiers (i.e. Super, Hyper and Meta) which
+ * are set in @state to their non-virtual counterparts (i.e. Mod2,
+ * Mod3,...) and set the corresponding bits in @state.
+ *
+ * This function is useful when matching key events against
+ * accelerators.
+ *
+ * Returns: %TRUE if no virtual modifiers were mapped to the
+ *     same non-virtual modifier. Note that %FALSE is also returned
+ *     if a virtual modifier is mapped to a non-virtual modifier that
+ *     was already set in @state.
+ *
+ * Since: 2.20
+ */
+gboolean
+gdk_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
+                                  GdkModifierType *state)
+{
+  GdkKeymapX11 *keymap_x11;
+  const guint vmods[] = {
+    GDK_SUPER_MASK, GDK_HYPER_MASK, GDK_META_MASK
+  };
+  int i, j;
+  gboolean retval;
+
+  keymap = GET_EFFECTIVE_KEYMAP (keymap);
+  keymap_x11 = GDK_KEYMAP_X11 (keymap);
+
+  if (KEYMAP_USE_XKB (keymap))
+    get_xkb (keymap_x11);
+
+  retval = TRUE;
+
+  for (j = 0; j < 3; j++)
+    {
+      if (*state & vmods[j])
+        {
+          for (i = 3; i < 8; i++)
+            {
+              if (keymap_x11->modmap[i] & vmods[j])
+                {
+                  if (*state & (1 << i))
+                    retval = FALSE;
+                  else
+                    *state |= 1 << i;
+                }
+            }
+        }
+    }
+
+  return retval;
+}
diff --git a/gdk/broadway/gdkmain-broadway.c b/gdk/broadway/gdkmain-broadway.c
new file mode 100644
index 0000000..8dd7f1f
--- /dev/null
+++ b/gdk/broadway/gdkmain-broadway.c
@@ -0,0 +1,698 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkx.h"
+#include "gdkasync.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkinternals.h"
+#include "gdkprivate-broadway.h"
+#include "gdkintl.h"
+#include "gdkdeviceprivate.h"
+
+#include <glib/gprintf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+
+typedef struct _GdkPredicate        GdkPredicate;
+typedef struct _GdkGlobalErrorTrap  GdkGlobalErrorTrap;
+
+struct _GdkPredicate
+{
+  GdkEventFunc func;
+  gpointer data;
+};
+
+/* non-GDK previous error handler */
+typedef int (*GdkXErrorHandler) (Display *, XErrorEvent *);
+static GdkXErrorHandler _gdk_old_error_handler;
+/* number of times we've pushed the GDK error handler */
+static int _gdk_error_handler_push_count = 0;
+
+struct _GdkGlobalErrorTrap
+{
+  GSList *displays;
+};
+
+/* 
+ * Private function declarations
+ */
+
+#ifndef HAVE_XCONVERTCASE
+static void	 gdkx_XConvertCase	(KeySym	       symbol,
+					 KeySym	      *lower,
+					 KeySym	      *upper);
+#define XConvertCase gdkx_XConvertCase
+#endif
+
+static int	    gdk_x_error			 (Display     *display, 
+						  XErrorEvent *error);
+static int	    gdk_x_io_error		 (Display     *display);
+
+/* Private variable declarations
+ */
+static GQueue gdk_error_traps;
+
+const GOptionEntry _gdk_windowing_args[] = {
+  { "sync", 0, 0, G_OPTION_ARG_NONE, &_gdk_synchronize, 
+    /* Description of --sync in --help output */ N_("Make X calls synchronous"), NULL },
+  { NULL }
+};
+
+void
+_gdk_windowing_init (void)
+{
+  _gdk_x11_initialize_locale ();
+
+  g_queue_init (&gdk_error_traps);
+  XSetErrorHandler (gdk_x_error);
+  XSetIOErrorHandler (gdk_x_io_error);
+
+  _gdk_selection_property = gdk_atom_intern_static_string ("GDK_SELECTION");
+}
+
+GdkGrabStatus
+_gdk_x11_convert_grab_status (gint status)
+{
+  switch (status)
+    {
+    case GrabSuccess:
+      return GDK_GRAB_SUCCESS;
+    case AlreadyGrabbed:
+      return GDK_GRAB_ALREADY_GRABBED;
+    case GrabInvalidTime:
+      return GDK_GRAB_INVALID_TIME;
+    case GrabNotViewable:
+      return GDK_GRAB_NOT_VIEWABLE;
+    case GrabFrozen:
+      return GDK_GRAB_FROZEN;
+    }
+
+  g_assert_not_reached();
+
+  return 0;
+}
+
+static void
+has_pointer_grab_callback (GdkDisplay *display,
+			   gpointer data,
+			   gulong serial)
+{
+  GdkDevice *device = data;
+
+  _gdk_display_device_grab_update (display, device, serial);
+}
+
+GdkGrabStatus
+_gdk_windowing_device_grab (GdkDevice    *device,
+                            GdkWindow    *window,
+                            GdkWindow    *native,
+                            gboolean      owner_events,
+                            GdkEventMask  event_mask,
+                            GdkWindow    *confine_to,
+                            GdkCursor    *cursor,
+                            guint32       time)
+{
+  GdkDisplay *display;
+  GdkGrabStatus status = GDK_GRAB_SUCCESS;
+
+  if (!window || GDK_WINDOW_DESTROYED (window))
+    return GDK_GRAB_NOT_VIEWABLE;
+
+  display = gdk_device_get_display (device);
+
+#ifdef G_ENABLE_DEBUG
+  if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
+    status = GrabSuccess;
+  else
+#endif
+    status = GDK_DEVICE_GET_CLASS (device)->grab (device,
+                                                  native,
+                                                  owner_events,
+                                                  event_mask,
+                                                  confine_to,
+                                                  cursor,
+                                                  time);
+  if (status == GDK_GRAB_SUCCESS)
+    _gdk_x11_roundtrip_async (display,
+			      has_pointer_grab_callback,
+                              device);
+  return status;
+}
+
+/**
+ * _gdk_xgrab_check_unmap:
+ * @window: a #GdkWindow
+ * @serial: serial from Unmap event (or from NextRequest(display)
+ *   if the unmap is being done by this client.)
+ * 
+ * Checks to see if an unmap request or event causes the current
+ * grab window to become not viewable, and if so, clear the
+ * the pointer we keep to it.
+ **/
+void
+_gdk_xgrab_check_unmap (GdkWindow *window,
+			gulong     serial)
+{
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkDeviceManager *device_manager;
+  GList *devices, *d;
+
+  device_manager = gdk_display_get_device_manager (display);
+
+  /* Get all devices */
+  devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+  devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
+  devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
+
+  /* End all grabs on the newly hidden window */
+  for (d = devices; d; d = d->next)
+    _gdk_display_end_device_grab (display, d->data, serial, window, TRUE);
+
+  g_list_free (devices);
+}
+
+/**
+ * _gdk_xgrab_check_destroy:
+ * @window: a #GdkWindow
+ * 
+ * Checks to see if window is the current grab window, and if
+ * so, clear the current grab window.
+ **/
+void
+_gdk_xgrab_check_destroy (GdkWindow *window)
+{
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkDeviceManager *device_manager;
+  GdkDeviceGrabInfo *grab;
+  GList *devices, *d;
+
+  device_manager = gdk_display_get_device_manager (display);
+
+  /* Get all devices */
+  devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+  devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
+  devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
+
+  for (d = devices; d; d = d->next)
+    {
+      /* Make sure there is no lasting grab in this native window */
+      grab = _gdk_display_get_last_device_grab (display, d->data);
+
+      if (grab && grab->native_window == window)
+        {
+          /* We don't know the actual serial to end, but it
+             doesn't really matter as this only happens
+             after we get told of the destroy from the
+             server so we know its ended in the server,
+             just make sure its ended. */
+          grab->serial_end = grab->serial_start;
+          grab->implicit_ungrab = TRUE;
+        }
+    }
+
+  g_list_free (devices);
+}
+
+void
+_gdk_windowing_display_set_sm_client_id (GdkDisplay  *display,
+					 const gchar *sm_client_id)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (display->closed)
+    return;
+
+  if (sm_client_id && strcmp (sm_client_id, ""))
+    {
+      XChangeProperty (display_x11->xdisplay, display_x11->leader_window,
+		       gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"),
+		       XA_STRING, 8, PropModeReplace, (guchar *)sm_client_id,
+		       strlen (sm_client_id));
+    }
+  else
+    XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
+		     gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
+}
+
+/* Close all open displays
+ */
+void
+_gdk_windowing_exit (void)
+{
+  GSList *tmp_list = _gdk_displays;
+    
+  while (tmp_list)
+    {
+      XCloseDisplay (GDK_DISPLAY_XDISPLAY (tmp_list->data));
+      
+      tmp_list = tmp_list->next;
+  }
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_x_io_error
+ *
+ *   The X I/O error handling routine.
+ *
+ * Arguments:
+ *   "display" is the X display the error orignated from.
+ *
+ * Results:
+ *   An X I/O error basically means we lost our connection
+ *   to the X server. There is not much we can do to
+ *   continue, so simply print an error message and exit.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+gdk_x_io_error (Display *display)
+{
+  /* This is basically modelled after the code in XLib. We need
+   * an explicit error handler here, so we can disable our atexit()
+   * which would otherwise cause a nice segfault.
+   * We fprintf(stderr, instead of g_warning() because g_warning()
+   * could possibly be redirected to a dialog
+   */
+  if (errno == EPIPE)
+    {
+      g_warning ("The application '%s' lost its connection to the display %s;\n"
+                 "most likely the X server was shut down or you killed/destroyed\n"
+                 "the application.\n",
+                 g_get_prgname (),
+                 display ? DisplayString (display) : gdk_get_display_arg_name ());
+    }
+  else
+    {
+      g_warning ("%s: Fatal IO error %d (%s) on X server %s.\n",
+                 g_get_prgname (),
+                 errno, g_strerror (errno),
+                 display ? DisplayString (display) : gdk_get_display_arg_name ());
+    }
+
+  exit(1);
+}
+
+/* X error handler. Keep the name the same because people are used to
+ * breaking on it in the debugger.
+ */
+static int
+gdk_x_error (Display	 *xdisplay,
+	     XErrorEvent *error)
+{
+  if (error->error_code)
+    {
+      GdkDisplay *error_display;
+      GdkDisplayManager *manager;
+      GSList *displays;
+
+      /* Figure out which GdkDisplay if any got the error. */
+      error_display = NULL;
+      manager = gdk_display_manager_get ();
+      displays = gdk_display_manager_list_displays (manager);
+      while (displays != NULL)
+        {
+          GdkDisplayX11 *gdk_display = displays->data;
+
+          if (xdisplay == gdk_display->xdisplay)
+            {
+              error_display = GDK_DISPLAY_OBJECT (gdk_display);
+              g_slist_free (displays);
+              displays = NULL;
+            }
+          else
+            {
+              displays = g_slist_delete_link (displays, displays);
+            }
+        }
+
+      if (error_display == NULL)
+        {
+          /* Error on an X display not opened by GDK. Ignore. */
+
+          return 0;
+        }
+      else
+        {
+          _gdk_x11_display_error_event (error_display, error);
+        }
+    }
+
+  return 0;
+}
+
+void
+_gdk_x11_error_handler_push (void)
+{
+  GdkXErrorHandler previous;
+
+  previous = XSetErrorHandler (gdk_x_error);
+
+  if (_gdk_error_handler_push_count > 0)
+    {
+      if (previous != gdk_x_error)
+        g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
+    }
+  else
+    {
+      _gdk_old_error_handler = previous;
+    }
+
+  _gdk_error_handler_push_count += 1;
+}
+
+void
+_gdk_x11_error_handler_pop  (void)
+{
+  g_return_if_fail (_gdk_error_handler_push_count > 0);
+
+  _gdk_error_handler_push_count -= 1;
+
+  if (_gdk_error_handler_push_count == 0)
+    {
+      XSetErrorHandler (_gdk_old_error_handler);
+      _gdk_old_error_handler = NULL;
+    }
+}
+
+/**
+ * gdk_error_trap_push:
+ *
+ * This function allows X errors to be trapped instead of the normal
+ * behavior of exiting the application. It should only be used if it
+ * is not possible to avoid the X error in any other way. Errors are
+ * ignored on all #GdkDisplay currently known to the
+ * #GdkDisplayManager. If you don't care which error happens and just
+ * want to ignore everything, pop with gdk_error_trap_pop_ignored().
+ * If you need the error code, use gdk_error_trap_pop() which may have
+ * to block and wait for the error to arrive from the X server.
+ *
+ * This API exists on all platforms but only does anything on X.
+ *
+ * You can use gdk_x11_display_error_trap_push() to ignore errors
+ * on only a single display.
+ *
+ * <example>
+ * <title>Trapping an X error</title>
+ * <programlisting>
+ * gdk_error_trap_push (<!-- -->);
+ *
+ *  // ... Call the X function which may cause an error here ...
+ *
+ *
+ * if (gdk_error_trap_pop (<!-- -->))
+ *  {
+ *    // ... Handle the error here ...
+ *  }
+ * </programlisting>
+ * </example>
+ *
+ */
+void
+gdk_error_trap_push (void)
+{
+  GdkGlobalErrorTrap *trap;
+  GdkDisplayManager *manager;
+  GSList *tmp_list;
+
+  trap = g_slice_new (GdkGlobalErrorTrap);
+  manager = gdk_display_manager_get ();
+  trap->displays = gdk_display_manager_list_displays (manager);
+
+  g_slist_foreach (trap->displays, (GFunc) g_object_ref, NULL);
+  for (tmp_list = trap->displays;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      gdk_x11_display_error_trap_push (tmp_list->data);
+    }
+
+  g_queue_push_head (&gdk_error_traps, trap);
+}
+
+static gint
+gdk_error_trap_pop_internal (gboolean need_code)
+{
+  GdkGlobalErrorTrap *trap;
+  gint result;
+  GSList *tmp_list;
+
+  trap = g_queue_pop_head (&gdk_error_traps);
+
+  g_return_val_if_fail (trap != NULL, Success);
+
+  result = Success;
+  for (tmp_list = trap->displays;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      gint code = Success;
+
+      if (need_code)
+        code = gdk_x11_display_error_trap_pop (tmp_list->data);
+      else
+        gdk_x11_display_error_trap_pop_ignored (tmp_list->data);
+
+      /* we use the error on the last display listed, why not. */
+      if (code != Success)
+        result = code;
+    }
+
+  g_slist_foreach (trap->displays, (GFunc) g_object_unref, NULL);
+  g_slist_free (trap->displays);
+
+  g_slice_free (GdkGlobalErrorTrap, trap);
+
+  return result;
+}
+
+/**
+ * gdk_error_trap_pop_ignored:
+ *
+ * Removes an error trap pushed with gdk_error_trap_push(), but
+ * without bothering to wait and see whether an error occurred.  If an
+ * error arrives later asynchronously that was triggered while the
+ * trap was pushed, that error will be ignored.
+ *
+ * Since: 3.0
+ */
+void
+gdk_error_trap_pop_ignored (void)
+{
+  gdk_error_trap_pop_internal (FALSE);
+}
+
+/**
+ * gdk_error_trap_pop:
+ *
+ * Removes an error trap pushed with gdk_error_trap_push().
+ * May block until an error has been definitively received
+ * or not received from the X server. gdk_error_trap_pop_ignored()
+ * is preferred if you don't need to know whether an error
+ * occurred, because it never has to block. If you don't
+ * need the return value of gdk_error_trap_pop(), use
+ * gdk_error_trap_pop_ignored().
+ *
+ * Prior to GDK 3.0, this function would not automatically
+ * sync for you, so you had to gdk_flush() if your last
+ * call to Xlib was not a blocking round trip.
+ *
+ * Return value: X error code or 0 on success
+ */
+gint
+gdk_error_trap_pop (void)
+{
+  return gdk_error_trap_pop_internal (TRUE);
+}
+
+gchar *
+gdk_get_display (void)
+{
+  return g_strdup (gdk_display_get_name (gdk_display_get_default ()));
+}
+
+/**
+ * _gdk_send_xevent:
+ * @display: #GdkDisplay which @window is on
+ * @window: window ID to which to send the event
+ * @propagate: %TRUE if the event should be propagated if the target window
+ *             doesn't handle it.
+ * @event_mask: event mask to match against, or 0 to send it to @window
+ *              without regard to event masks.
+ * @event_send: #XEvent to send
+ * 
+ * Send an event, like XSendEvent(), but trap errors and check
+ * the result.
+ * 
+ * Return value: %TRUE if sending the event succeeded.
+ **/
+gint 
+_gdk_send_xevent (GdkDisplay *display,
+		  Window      window, 
+		  gboolean    propagate, 
+		  glong       event_mask,
+		  XEvent     *event_send)
+{
+  gboolean result;
+
+  if (display->closed)
+    return FALSE;
+
+  gdk_error_trap_push ();
+  result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window, 
+		       propagate, event_mask, event_send);
+  XSync (GDK_DISPLAY_XDISPLAY (display), False);
+  
+  if (gdk_error_trap_pop ())
+    return FALSE;
+ 
+  return result;
+}
+
+void
+_gdk_region_get_xrectangles (const cairo_region_t *region,
+                             gint             x_offset,
+                             gint             y_offset,
+                             XRectangle     **rects,
+                             gint            *n_rects)
+{
+  XRectangle *rectangles;
+  cairo_rectangle_int_t box;
+  gint i, n;
+  
+  n = cairo_region_num_rectangles (region);
+  rectangles = g_new (XRectangle, n);
+
+  for (i = 0; i < n; i++)
+    {
+      cairo_region_get_rectangle (region, i, &box);
+      rectangles[i].x = CLAMP (box.x + x_offset, G_MINSHORT, G_MAXSHORT);
+      rectangles[i].y = CLAMP (box.y + y_offset, G_MINSHORT, G_MAXSHORT);
+      rectangles[i].width = CLAMP (box.width, G_MINSHORT, G_MAXSHORT);
+      rectangles[i].height = CLAMP (box.height, G_MINSHORT, G_MAXSHORT);
+    }
+
+  *n_rects = n;
+  *rects = rectangles;
+}
+
+/**
+ * gdk_x11_grab_server:
+ * 
+ * Call gdk_x11_display_grab() on the default display. 
+ * To ungrab the server again, use gdk_x11_ungrab_server(). 
+ *
+ * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
+ **/ 
+void
+gdk_x11_grab_server (void)
+{
+  gdk_x11_display_grab (gdk_display_get_default ());
+}
+
+/**
+ * gdk_x11_ungrab_server:
+ *
+ * Ungrab the default display after it has been grabbed with 
+ * gdk_x11_grab_server(). 
+ **/
+void
+gdk_x11_ungrab_server (void)
+{
+  gdk_x11_display_ungrab (gdk_display_get_default ());
+}
+
+/**
+ * gdk_x11_get_default_screen:
+ * 
+ * Gets the default GTK+ screen number.
+ * 
+ * Return value: returns the screen number specified by
+ *   the --display command line option or the DISPLAY environment
+ *   variable when gdk_init() calls XOpenDisplay().
+ **/
+gint
+gdk_x11_get_default_screen (void)
+{
+  return gdk_screen_get_number (gdk_screen_get_default ());
+}
+
+/**
+ * gdk_x11_get_default_root_xwindow:
+ * 
+ * Gets the root window of the default screen 
+ * (see gdk_x11_get_default_screen()).  
+ * 
+ * Return value: an Xlib <type>Window</type>.
+ **/
+Window
+gdk_x11_get_default_root_xwindow (void)
+{
+  return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
+}
+
+/**
+ * gdk_x11_get_default_xdisplay:
+ * 
+ * Gets the default GTK+ display.
+ * 
+ * Return value: the Xlib <type>Display*</type> for the display
+ * specified in the <option>--display</option> command line option 
+ * or the <envar>DISPLAY</envar> environment variable.
+ **/
+Display *
+gdk_x11_get_default_xdisplay (void)
+{
+  return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+}
+
+void
+_gdk_windowing_event_data_copy (const GdkEvent *src,
+                                GdkEvent       *dst)
+{
+}
+
+void
+_gdk_windowing_event_data_free (GdkEvent *event)
+{
+}
diff --git a/gdk/broadway/gdkprivate-broadway.h b/gdk/broadway/gdkprivate-broadway.h
new file mode 100644
index 0000000..0f957ac
--- /dev/null
+++ b/gdk/broadway/gdkprivate-broadway.h
@@ -0,0 +1,162 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+/*
+ * Private uninstalled header defining things local to X windowing code
+ */
+
+#ifndef __GDK_PRIVATE_BROADWAY_H__
+#define __GDK_PRIVATE_BROADWAY_H__
+
+#include <gdk/gdkcursor.h>
+#include <gdk/gdkprivate.h>
+#include <gdk/gdkinternals.h>
+#include "gdkwindow-broadway.h"
+#include "gdkdisplay-broadway.h"
+#include <cairo-xlib.h>
+
+typedef struct _GdkCursorPrivate       GdkCursorPrivate;
+
+struct _GdkCursorPrivate
+{
+  GdkCursor cursor;
+  Cursor xcursor;
+  GdkDisplay *display;
+  gchar *name;
+  guint serial;
+};
+
+void _gdk_x11_error_handler_push (void);
+void _gdk_x11_error_handler_pop  (void);
+
+Colormap _gdk_visual_get_x11_colormap (GdkVisual *visual);
+
+void _gdk_xid_table_insert (GdkDisplay *display,
+			    XID        *xid,
+			    gpointer    data);
+void _gdk_xid_table_remove (GdkDisplay *display,
+			    XID         xid);
+gint _gdk_send_xevent      (GdkDisplay *display,
+			    Window      window,
+			    gboolean    propagate,
+			    glong       event_mask,
+			    XEvent     *event_send);
+
+/* Routines from gdkgeometry-broadway.c */
+void _gdk_window_move_resize_child (GdkWindow     *window,
+                                    gint           x,
+                                    gint           y,
+                                    gint           width,
+                                    gint           height);
+void _gdk_window_process_expose    (GdkWindow     *window,
+                                    gulong         serial,
+                                    GdkRectangle  *area);
+
+gboolean _gdk_x11_window_queue_antiexpose  (GdkWindow *window,
+					    cairo_region_t *area);
+void     _gdk_x11_window_translate         (GdkWindow *window,
+					    cairo_region_t *area,
+					    gint       dx,
+					    gint       dy);
+
+void     _gdk_selection_window_destroyed   (GdkWindow            *window);
+gboolean _gdk_selection_filter_clear_event (XSelectionClearEvent *event);
+
+cairo_region_t* _xwindow_get_shape              (Display *xdisplay,
+                                            Window window,
+                                            gint shape_type);
+
+void     _gdk_region_get_xrectangles       (const cairo_region_t      *region,
+                                            gint                  x_offset,
+                                            gint                  y_offset,
+                                            XRectangle          **rects,
+                                            gint                 *n_rects);
+
+gboolean _gdk_moveresize_handle_event   (XEvent     *event);
+gboolean _gdk_moveresize_configure_done (GdkDisplay *display,
+					 GdkWindow  *window);
+
+void _gdk_keymap_state_changed    (GdkDisplay      *display,
+				   XEvent          *event);
+void _gdk_keymap_keys_changed     (GdkDisplay      *display);
+gint _gdk_x11_get_group_for_state (GdkDisplay      *display,
+				   GdkModifierType  state);
+void _gdk_keymap_add_virtual_modifiers_compat (GdkKeymap       *keymap,
+                                               GdkModifierType *modifiers);
+gboolean _gdk_keymap_key_is_modifier   (GdkKeymap       *keymap,
+					guint            keycode);
+
+void _gdk_x11_initialize_locale (void);
+
+void _gdk_xgrab_check_unmap        (GdkWindow *window,
+				    gulong     serial);
+void _gdk_xgrab_check_destroy      (GdkWindow *window);
+
+gboolean _gdk_x11_display_is_root_window (GdkDisplay *display,
+					  Window      xroot_window);
+
+void _gdk_x11_precache_atoms (GdkDisplay          *display,
+			      const gchar * const *atom_names,
+			      gint                 n_atoms);
+
+void _gdk_screen_x11_events_init   (GdkScreen *screen);
+
+void _gdk_events_init           (GdkDisplay *display);
+void _gdk_events_uninit         (GdkDisplay *display);
+void _gdk_windowing_window_init (GdkScreen *screen);
+void _gdk_visual_init           (GdkScreen *screen);
+void _gdk_dnd_init		(GdkDisplay *display);
+
+void _gdk_x11_cursor_update_theme (GdkCursor *cursor);
+void _gdk_x11_cursor_display_finalize (GdkDisplay *display);
+
+gboolean _gdk_x11_get_xft_setting (GdkScreen   *screen,
+				   const gchar *name,
+				   GValue      *value);
+
+GdkGrabStatus _gdk_x11_convert_grab_status (gint status);
+
+cairo_surface_t * _gdk_x11_window_create_bitmap_surface (GdkWindow *window,
+                                                         int        width,
+                                                         int        height);
+
+extern GdkDrawableClass  _gdk_x11_drawable_class;
+extern gboolean	         _gdk_use_xshm;
+extern const int         _gdk_nenvent_masks;
+extern const int         _gdk_event_mask_table[];
+extern GdkAtom		 _gdk_selection_property;
+extern gboolean          _gdk_synchronize;
+
+#define GDK_DRAWABLE_XROOTWIN(win)    (GDK_WINDOW_XROOTWIN (win))
+#define GDK_SCREEN_DISPLAY(screen)    (GDK_SCREEN_X11 (screen)->display)
+#define GDK_SCREEN_XROOTWIN(screen)   (GDK_SCREEN_X11 (screen)->xroot_window)
+#define GDK_WINDOW_SCREEN(win)	      (GDK_DRAWABLE_IMPL_X11 (((GdkWindowObject *)win)->impl)->screen)
+#define GDK_WINDOW_DISPLAY(win)       (GDK_SCREEN_X11 (GDK_WINDOW_SCREEN (win))->display)
+#define GDK_WINDOW_XROOTWIN(win)      (GDK_SCREEN_X11 (GDK_WINDOW_SCREEN (win))->xroot_window)
+#define GDK_GC_DISPLAY(gc)            (GDK_SCREEN_DISPLAY (GDK_GC_X11(gc)->screen))
+#define GDK_WINDOW_IS_X11(win)        (GDK_IS_WINDOW_IMPL_X11 (((GdkWindowObject *)win)->impl))
+
+#endif /* __GDK_PRIVATE_BROADWAY_H__ */
diff --git a/gdk/broadway/gdkproperty-broadway.c b/gdk/broadway/gdkproperty-broadway.c
new file mode 100644
index 0000000..49a6e75
--- /dev/null
+++ b/gdk/broadway/gdkproperty-broadway.c
@@ -0,0 +1,761 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkproperty.h"
+
+#include "gdkmain.h"
+#include "gdkx.h"
+#include "gdkprivate.h"
+#include "gdkinternals.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkscreen-broadway.h"
+#include "gdkselection.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <string.h>
+
+
+static GPtrArray *virtual_atom_array;
+static GHashTable *virtual_atom_hash;
+
+static const gchar xatoms_string[] = 
+  /* These are all the standard predefined X atoms */
+  "\0"  /* leave a space for None, even though it is not a predefined atom */
+  "PRIMARY\0"
+  "SECONDARY\0"
+  "ARC\0"
+  "ATOM\0"
+  "BITMAP\0"
+  "CARDINAL\0"
+  "COLORMAP\0"
+  "CURSOR\0"
+  "CUT_BUFFER0\0"
+  "CUT_BUFFER1\0"
+  "CUT_BUFFER2\0"
+  "CUT_BUFFER3\0"
+  "CUT_BUFFER4\0"
+  "CUT_BUFFER5\0"
+  "CUT_BUFFER6\0"
+  "CUT_BUFFER7\0"
+  "DRAWABLE\0"
+  "FONT\0"
+  "INTEGER\0"
+  "PIXMAP\0"
+  "POINT\0"
+  "RECTANGLE\0"
+  "RESOURCE_MANAGER\0"
+  "RGB_COLOR_MAP\0"
+  "RGB_BEST_MAP\0"
+  "RGB_BLUE_MAP\0"
+  "RGB_DEFAULT_MAP\0"
+  "RGB_GRAY_MAP\0"
+  "RGB_GREEN_MAP\0"
+  "RGB_RED_MAP\0"
+  "STRING\0"
+  "VISUALID\0"
+  "WINDOW\0"
+  "WM_COMMAND\0"
+  "WM_HINTS\0"
+  "WM_CLIENT_MACHINE\0"
+  "WM_ICON_NAME\0"
+  "WM_ICON_SIZE\0"
+  "WM_NAME\0"
+  "WM_NORMAL_HINTS\0"
+  "WM_SIZE_HINTS\0"
+  "WM_ZOOM_HINTS\0"
+  "MIN_SPACE\0"
+  "NORM_SPACE\0"
+  "MAX_SPACE\0"
+  "END_SPACE\0"
+  "SUPERSCRIPT_X\0"
+  "SUPERSCRIPT_Y\0"
+  "SUBSCRIPT_X\0"
+  "SUBSCRIPT_Y\0"
+  "UNDERLINE_POSITION\0"
+  "UNDERLINE_THICKNESS\0"
+  "STRIKEOUT_ASCENT\0"
+  "STRIKEOUT_DESCENT\0"
+  "ITALIC_ANGLE\0"
+  "X_HEIGHT\0"
+  "QUAD_WIDTH\0"
+  "WEIGHT\0"
+  "POINT_SIZE\0"
+  "RESOLUTION\0"
+  "COPYRIGHT\0"
+  "NOTICE\0"
+  "FONT_NAME\0"
+  "FAMILY_NAME\0"
+  "FULL_NAME\0"
+  "CAP_HEIGHT\0"
+  "WM_CLASS\0"
+  "WM_TRANSIENT_FOR\0"
+  /* Below here, these are our additions. Increment N_CUSTOM_PREDEFINED
+   * if you add any.
+   */
+  "CLIPBOARD\0"			/* = 69 */
+;
+
+static const gint xatoms_offset[] = {
+    0,   1,   9,  19,  23,  28,  35,  44,  53,  60,  72,  84,
+   96, 108, 120, 132, 144, 156, 165, 170, 178, 185, 189, 201,
+  218, 232, 245, 258, 274, 287, 301, 313, 320, 329, 336, 347,
+  356, 374, 387, 400, 408, 424, 438, 452, 462, 473, 483, 493,
+  507, 521, 533, 545, 564, 584, 601, 619, 632, 641, 652, 659,
+  670, 681, 691, 698, 708, 720, 730, 741, 750, 767
+};
+
+#define N_CUSTOM_PREDEFINED 1
+
+#define ATOM_TO_INDEX(atom) (GPOINTER_TO_UINT(atom))
+#define INDEX_TO_ATOM(atom) ((GdkAtom)GUINT_TO_POINTER(atom))
+
+static void
+insert_atom_pair (GdkDisplay *display,
+		  GdkAtom     virtual_atom,
+		  Atom        xatom)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);  
+  
+  if (!display_x11->atom_from_virtual)
+    {
+      display_x11->atom_from_virtual = g_hash_table_new (g_direct_hash, NULL);
+      display_x11->atom_to_virtual = g_hash_table_new (g_direct_hash, NULL);
+    }
+  
+  g_hash_table_insert (display_x11->atom_from_virtual, 
+		       GDK_ATOM_TO_POINTER (virtual_atom), 
+		       GUINT_TO_POINTER (xatom));
+  g_hash_table_insert (display_x11->atom_to_virtual,
+		       GUINT_TO_POINTER (xatom), 
+		       GDK_ATOM_TO_POINTER (virtual_atom));
+}
+
+static Atom
+lookup_cached_xatom (GdkDisplay *display,
+		     GdkAtom     atom)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (ATOM_TO_INDEX (atom) < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
+    return ATOM_TO_INDEX (atom);
+  
+  if (display_x11->atom_from_virtual)
+    return GPOINTER_TO_UINT (g_hash_table_lookup (display_x11->atom_from_virtual,
+						  GDK_ATOM_TO_POINTER (atom)));
+
+  return None;
+}
+
+/**
+ * gdk_x11_atom_to_xatom_for_display:
+ * @display: A #GdkDisplay
+ * @atom: A #GdkAtom, or %GDK_NONE
+ *
+ * Converts from a #GdkAtom to the X atom for a #GdkDisplay
+ * with the same string value. The special value %GDK_NONE
+ * is converted to %None.
+ *
+ * Return value: the X atom corresponding to @atom, or %None
+ *
+ * Since: 2.2
+ **/
+Atom
+gdk_x11_atom_to_xatom_for_display (GdkDisplay *display,
+				   GdkAtom     atom)
+{
+  Atom xatom = None;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
+
+  if (atom == GDK_NONE)
+    return None;
+
+  if (display->closed)
+    return None;
+
+  xatom = lookup_cached_xatom (display, atom);
+
+  if (!xatom)
+    {
+      char *name;
+
+      g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
+
+      name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
+
+      xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), name, FALSE);
+      insert_atom_pair (display, atom, xatom);
+    }
+
+  return xatom;
+}
+
+void
+_gdk_x11_precache_atoms (GdkDisplay          *display,
+			 const gchar * const *atom_names,
+			 gint                 n_atoms)
+{
+  Atom *xatoms;
+  GdkAtom *atoms;
+  const gchar **xatom_names;
+  gint n_xatoms;
+  gint i;
+
+  xatoms = g_new (Atom, n_atoms);
+  xatom_names = g_new (const gchar *, n_atoms);
+  atoms = g_new (GdkAtom, n_atoms);
+
+  n_xatoms = 0;
+  for (i = 0; i < n_atoms; i++)
+    {
+      GdkAtom atom = gdk_atom_intern_static_string (atom_names[i]);
+      if (lookup_cached_xatom (display, atom) == None)
+	{
+	  atoms[n_xatoms] = atom;
+	  xatom_names[n_xatoms] = atom_names[i];
+	  n_xatoms++;
+	}
+    }
+
+  if (n_xatoms)
+    {
+#ifdef HAVE_XINTERNATOMS
+      XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
+		    (char **)xatom_names, n_xatoms, False, xatoms);
+#else
+      for (i = 0; i < n_xatoms; i++)
+	xatoms[i] = XInternAtom (GDK_DISPLAY_XDISPLAY (display),
+				 xatom_names[i], False);
+#endif
+    }
+
+  for (i = 0; i < n_xatoms; i++)
+    insert_atom_pair (display, atoms[i], xatoms[i]);
+
+  g_free (xatoms);
+  g_free (xatom_names);
+  g_free (atoms);
+}
+
+/**
+ * gdk_x11_atom_to_xatom:
+ * @atom: A #GdkAtom 
+ * 
+ * Converts from a #GdkAtom to the X atom for the default GDK display
+ * with the same string value.
+ * 
+ * Return value: the X atom corresponding to @atom.
+ **/
+Atom
+gdk_x11_atom_to_xatom (GdkAtom atom)
+{
+  return gdk_x11_atom_to_xatom_for_display (gdk_display_get_default (), atom);
+}
+
+/**
+ * gdk_x11_xatom_to_atom_for_display:
+ * @display: A #GdkDisplay
+ * @xatom: an X atom 
+ * 
+ * Convert from an X atom for a #GdkDisplay to the corresponding
+ * #GdkAtom.
+ * 
+ * Return value: the corresponding #GdkAtom.
+ *
+ * Since: 2.2
+ **/
+GdkAtom
+gdk_x11_xatom_to_atom_for_display (GdkDisplay *display,
+				   Atom	       xatom)
+{
+  GdkDisplayX11 *display_x11;
+  GdkAtom virtual_atom = GDK_NONE;
+  
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), GDK_NONE);
+
+  if (xatom == None)
+    return GDK_NONE;
+
+  if (display->closed)
+    return GDK_NONE;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+  
+  if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
+    return INDEX_TO_ATOM (xatom);
+  
+  if (display_x11->atom_to_virtual)
+    virtual_atom = GDK_POINTER_TO_ATOM (g_hash_table_lookup (display_x11->atom_to_virtual,
+							     GUINT_TO_POINTER (xatom)));
+  
+  if (!virtual_atom)
+    {
+      /* If this atom doesn't exist, we'll die with an X error unless
+       * we take precautions
+       */
+      char *name;
+      gdk_error_trap_push ();
+      name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
+      if (gdk_error_trap_pop ())
+	{
+	  g_warning (G_STRLOC " invalid X atom: %ld", xatom);
+	}
+      else
+	{
+	  virtual_atom = gdk_atom_intern (name, FALSE);
+	  XFree (name);
+	  
+	  insert_atom_pair (display, virtual_atom, xatom);
+	}
+    }
+
+  return virtual_atom;
+}
+
+/**
+ * gdk_x11_xatom_to_atom:
+ * @xatom: an X atom for the default GDK display
+ * 
+ * Convert from an X atom for the default display to the corresponding
+ * #GdkAtom.
+ * 
+ * Return value: the corresponding G#dkAtom.
+ **/
+GdkAtom
+gdk_x11_xatom_to_atom (Atom xatom)
+{
+  return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
+}
+
+static void
+virtual_atom_check_init (void)
+{
+  if (!virtual_atom_hash)
+    {
+      gint i;
+      
+      virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
+      virtual_atom_array = g_ptr_array_new ();
+      
+      for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
+	{
+	  g_ptr_array_add (virtual_atom_array, (gchar *)(xatoms_string + xatoms_offset[i]));
+	  g_hash_table_insert (virtual_atom_hash, (gchar *)(xatoms_string + xatoms_offset[i]),
+			       GUINT_TO_POINTER (i));
+	}
+    }
+}
+
+static GdkAtom
+intern_atom (const gchar *atom_name, 
+	     gboolean     dup)
+{
+  GdkAtom result;
+
+  virtual_atom_check_init ();
+  
+  result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
+  if (!result)
+    {
+      result = INDEX_TO_ATOM (virtual_atom_array->len);
+      
+      g_ptr_array_add (virtual_atom_array, dup ? g_strdup (atom_name) : (gchar *)atom_name);
+      g_hash_table_insert (virtual_atom_hash, 
+			   g_ptr_array_index (virtual_atom_array,
+					      ATOM_TO_INDEX (result)),
+			   GDK_ATOM_TO_POINTER (result));
+    }
+
+  return result;
+}
+
+GdkAtom
+gdk_atom_intern (const gchar *atom_name, 
+		 gboolean     only_if_exists)
+{
+  return intern_atom (atom_name, TRUE);
+}
+
+/**
+ * gdk_atom_intern_static_string:
+ * @atom_name: a static string
+ *
+ * Finds or creates an atom corresponding to a given string.
+ *
+ * Note that this function is identical to gdk_atom_intern() except
+ * that if a new #GdkAtom is created the string itself is used rather 
+ * than a copy. This saves memory, but can only be used if the string 
+ * will <emphasis>always</emphasis> exist. It can be used with statically
+ * allocated strings in the main program, but not with statically 
+ * allocated memory in dynamically loaded modules, if you expect to
+ * ever unload the module again (e.g. do not use this function in
+ * GTK+ theme engines).
+ *
+ * Returns: the atom corresponding to @atom_name
+ * 
+ * Since: 2.10
+ */
+GdkAtom
+gdk_atom_intern_static_string (const gchar *atom_name)
+{
+  return intern_atom (atom_name, FALSE);
+}
+
+static G_CONST_RETURN char *
+get_atom_name (GdkAtom atom)
+{
+  virtual_atom_check_init ();
+
+  if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
+    return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
+  else
+    return NULL;
+}
+
+gchar *
+gdk_atom_name (GdkAtom atom)
+{
+  return g_strdup (get_atom_name (atom));
+}
+
+/**
+ * gdk_x11_get_xatom_by_name_for_display:
+ * @display: a #GdkDisplay
+ * @atom_name: a string
+ * 
+ * Returns the X atom for a #GdkDisplay corresponding to @atom_name.
+ * This function caches the result, so if called repeatedly it is much
+ * faster than XInternAtom(), which is a round trip to the server each time.
+ * 
+ * Return value: a X atom for a #GdkDisplay
+ *
+ * Since: 2.2
+ **/
+Atom
+gdk_x11_get_xatom_by_name_for_display (GdkDisplay  *display,
+				       const gchar *atom_name)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
+  return gdk_x11_atom_to_xatom_for_display (display,
+					    gdk_atom_intern (atom_name, FALSE));
+}
+
+/**
+ * gdk_x11_get_xatom_by_name:
+ * @atom_name: a string
+ * 
+ * Returns the X atom for GDK's default display corresponding to @atom_name.
+ * This function caches the result, so if called repeatedly it is much
+ * faster than XInternAtom(), which is a round trip to the server each time.
+ * 
+ * Return value: a X atom for GDK's default display.
+ **/
+Atom
+gdk_x11_get_xatom_by_name (const gchar *atom_name)
+{
+  return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
+						atom_name);
+}
+
+/**
+ * gdk_x11_get_xatom_name_for_display:
+ * @display: the #GdkDisplay where @xatom is defined
+ * @xatom: an X atom 
+ * 
+ * Returns the name of an X atom for its display. This
+ * function is meant mainly for debugging, so for convenience, unlike
+ * XAtomName() and gdk_atom_name(), the result doesn't need to
+ * be freed. 
+ *
+ * Return value: name of the X atom; this string is owned by GDK,
+ *   so it shouldn't be modifed or freed. 
+ *
+ * Since: 2.2
+ **/
+G_CONST_RETURN gchar *
+gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
+				    Atom        xatom)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+  return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
+}
+
+/**
+ * gdk_x11_get_xatom_name:
+ * @xatom: an X atom for GDK's default display
+ * 
+ * Returns the name of an X atom for GDK's default display. This
+ * function is meant mainly for debugging, so for convenience, unlike
+ * <function>XAtomName()</function> and gdk_atom_name(), the result 
+ * doesn't need to be freed. Also, this function will never return %NULL, 
+ * even if @xatom is invalid.
+ * 
+ * Return value: name of the X atom; this string is owned by GTK+,
+ *   so it shouldn't be modifed or freed. 
+ **/
+G_CONST_RETURN gchar *
+gdk_x11_get_xatom_name (Atom xatom)
+{
+  return get_atom_name (gdk_x11_xatom_to_atom (xatom));
+}
+
+gboolean
+gdk_property_get (GdkWindow   *window,
+		  GdkAtom      property,
+		  GdkAtom      type,
+		  gulong       offset,
+		  gulong       length,
+		  gint         pdelete,
+		  GdkAtom     *actual_property_type,
+		  gint        *actual_format_type,
+		  gint        *actual_length,
+		  guchar     **data)
+{
+  GdkDisplay *display;
+  Atom ret_prop_type;
+  gint ret_format;
+  gulong ret_nitems;
+  gulong ret_bytes_after;
+  gulong get_length;
+  gulong ret_length;
+  guchar *ret_data;
+  Atom xproperty;
+  Atom xtype;
+  int res;
+
+  g_return_val_if_fail (!window || GDK_WINDOW_IS_X11 (window), FALSE);
+
+  if (!window)
+    {
+      GdkScreen *screen = gdk_screen_get_default ();
+      window = gdk_screen_get_root_window (screen);
+      
+      GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
+    }
+  else if (!GDK_WINDOW_IS_X11 (window))
+    return FALSE;
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return FALSE;
+
+  display = gdk_window_get_display (window);
+  xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
+  if (type == GDK_NONE)
+    xtype = AnyPropertyType;
+  else
+    xtype = gdk_x11_atom_to_xatom_for_display (display, type);
+
+  ret_data = NULL;
+  
+  /* 
+   * Round up length to next 4 byte value.  Some code is in the (bad?)
+   * habit of passing G_MAXLONG as the length argument, causing an
+   * overflow to negative on the add.  In this case, we clamp the
+   * value to G_MAXLONG.
+   */
+  get_length = length + 3;
+  if (get_length > G_MAXLONG)
+    get_length = G_MAXLONG;
+
+  /* To fail, either the user passed 0 or G_MAXULONG */
+  get_length = get_length / 4;
+  if (get_length == 0)
+    {
+      g_warning ("gdk_propery-get(): invalid length 0");
+      return FALSE;
+    }
+
+  res = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+			    GDK_WINDOW_XWINDOW (window), xproperty,
+			    offset, get_length, pdelete,
+			    xtype, &ret_prop_type, &ret_format,
+			    &ret_nitems, &ret_bytes_after,
+			    &ret_data);
+
+  if (res != Success || (ret_prop_type == None && ret_format == 0))
+    {
+      return FALSE;
+    }
+
+  if (actual_property_type)
+    *actual_property_type = gdk_x11_xatom_to_atom_for_display (display, ret_prop_type);
+  if (actual_format_type)
+    *actual_format_type = ret_format;
+
+  if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
+    {
+      XFree (ret_data);
+      g_warning ("Couldn't match property type %s to %s\n", 
+		 gdk_x11_get_xatom_name_for_display (display, ret_prop_type), 
+		 gdk_x11_get_xatom_name_for_display (display, xtype));
+      return FALSE;
+    }
+
+  /* FIXME: ignoring bytes_after could have very bad effects */
+
+  if (data)
+    {
+      if (ret_prop_type == XA_ATOM ||
+	  ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
+	{
+	  /*
+	   * data is an array of X atom, we need to convert it
+	   * to an array of GDK Atoms
+	   */
+	  gint i;
+	  GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
+	  Atom *xatoms = (Atom *)ret_data;
+
+	  *data = (guchar *)ret_atoms;
+
+	  for (i = 0; i < ret_nitems; i++)
+	    ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
+	  
+	  if (actual_length)
+	    *actual_length = ret_nitems * sizeof (GdkAtom);
+	}
+      else
+	{
+	  switch (ret_format)
+	    {
+	    case 8:
+	      ret_length = ret_nitems;
+	      break;
+	    case 16:
+	      ret_length = sizeof(short) * ret_nitems;
+	      break;
+	    case 32:
+	      ret_length = sizeof(long) * ret_nitems;
+	      break;
+	    default:
+	      g_warning ("unknown property return format: %d", ret_format);
+	      XFree (ret_data);
+	      return FALSE;
+	    }
+	  
+	  *data = g_new (guchar, ret_length);
+	  memcpy (*data, ret_data, ret_length);
+	  if (actual_length)
+	    *actual_length = ret_length;
+	}
+    }
+
+  XFree (ret_data);
+
+  return TRUE;
+}
+
+void
+gdk_property_change (GdkWindow    *window,
+		     GdkAtom       property,
+		     GdkAtom       type,
+		     gint          format,
+		     GdkPropMode   mode,
+		     const guchar *data,
+		     gint          nelements)
+{
+  GdkDisplay *display;
+  Window xwindow;
+  Atom xproperty;
+  Atom xtype;
+
+  g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
+
+  if (!window)
+    {
+      GdkScreen *screen;
+      
+      screen = gdk_screen_get_default ();
+      window = gdk_screen_get_root_window (screen);
+      
+      GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
+    }
+  else if (!GDK_WINDOW_IS_X11 (window))
+    return;
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  gdk_window_ensure_native (window);
+
+  display = gdk_window_get_display (window);
+  xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
+  xtype = gdk_x11_atom_to_xatom_for_display (display, type);
+  xwindow = GDK_WINDOW_XID (window);
+
+  if (xtype == XA_ATOM ||
+      xtype == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
+    {
+      /*
+       * data is an array of GdkAtom, we need to convert it
+       * to an array of X Atoms
+       */
+      gint i;
+      GdkAtom *atoms = (GdkAtom*) data;
+      Atom *xatoms;
+
+      xatoms = g_new (Atom, nelements);
+      for (i = 0; i < nelements; i++)
+	xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, atoms[i]);
+
+      XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
+		       xproperty, xtype,
+		       format, mode, (guchar *)xatoms, nelements);
+      g_free (xatoms);
+    }
+  else
+    XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, xproperty, 
+		     xtype, format, mode, (guchar *)data, nelements);
+}
+
+void
+gdk_property_delete (GdkWindow *window,
+		     GdkAtom    property)
+{
+  g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
+
+  if (!window)
+    {
+      GdkScreen *screen = gdk_screen_get_default ();
+      window = gdk_screen_get_root_window (screen);
+      
+      GDK_NOTE (MULTIHEAD, 
+		g_message ("gdk_property_delete(): window is NULL\n"));
+    }
+  else if (!GDK_WINDOW_IS_X11 (window))
+    return;
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XWINDOW (window),
+		   gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),
+						      property));
+}
diff --git a/gdk/broadway/gdkscreen-broadway.c b/gdk/broadway/gdkscreen-broadway.c
new file mode 100644
index 0000000..9bb2259
--- /dev/null
+++ b/gdk/broadway/gdkscreen-broadway.c
@@ -0,0 +1,2003 @@
+ /*
+ * gdkscreen-broadway.c
+ * 
+ * Copyright 2001 Sun Microsystems Inc. 
+ *
+ * Erwann Chenede <erwann chenede sun com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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 "config.h"
+
+#include "gdkscreen-broadway.h"
+
+#include "gdkscreen.h"
+#include "gdkdisplay.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkx.h"
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xatom.h>
+
+#ifdef HAVE_SOLARIS_XINERAMA
+#include <X11/extensions/xinerama.h>
+#endif
+#ifdef HAVE_XFREE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
+#ifdef HAVE_RANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+#include "gdksettings.c"
+
+static void         gdk_screen_x11_dispose     (GObject		  *object);
+static void         gdk_screen_x11_finalize    (GObject		  *object);
+static void	    init_randr_support	       (GdkScreen	  *screen);
+static void	    deinit_multihead           (GdkScreen         *screen);
+
+enum
+{
+  WINDOW_MANAGER_CHANGED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GdkScreenX11, _gdk_screen_x11, GDK_TYPE_SCREEN)
+
+typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
+
+struct _NetWmSupportedAtoms
+{
+  Atom *atoms;
+  gulong n_atoms;
+};
+
+struct _GdkX11Monitor
+{
+  GdkRectangle  geometry;
+  XID		output;
+  int		width_mm;
+  int		height_mm;
+  char *	output_name;
+  char *	manufacturer;
+};
+
+static void
+_gdk_screen_x11_class_init (GdkScreenX11Class *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  object_class->dispose = gdk_screen_x11_dispose;
+  object_class->finalize = gdk_screen_x11_finalize;
+
+  signals[WINDOW_MANAGER_CHANGED] =
+    g_signal_new (g_intern_static_string ("window_manager_changed"),
+                  G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GdkScreenX11Class, window_manager_changed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE,
+                  0);
+}
+
+static void
+_gdk_screen_x11_init (GdkScreenX11 *screen)
+{
+}
+
+/**
+ * gdk_screen_get_display:
+ * @screen: a #GdkScreen
+ *
+ * Gets the display to which the @screen belongs.
+ * 
+ * Returns: the display to which @screen belongs
+ *
+ * Since: 2.2
+ **/
+GdkDisplay *
+gdk_screen_get_display (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  return GDK_SCREEN_X11 (screen)->display;
+}
+/**
+ * gdk_screen_get_width:
+ * @screen: a #GdkScreen
+ *
+ * Gets the width of @screen in pixels
+ * 
+ * Returns: the width of @screen in pixels.
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_width (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+  return WidthOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
+}
+
+/**
+ * gdk_screen_get_height:
+ * @screen: a #GdkScreen
+ *
+ * Gets the height of @screen in pixels
+ * 
+ * Returns: the height of @screen in pixels.
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_height (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+  return HeightOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
+}
+
+/**
+ * gdk_screen_get_width_mm:
+ * @screen: a #GdkScreen
+ *
+ * Gets the width of @screen in millimeters. 
+ * Note that on some X servers this value will not be correct.
+ * 
+ * Returns: the width of @screen in millimeters.
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_width_mm (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
+
+  return WidthMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
+}
+
+/**
+ * gdk_screen_get_height_mm:
+ * @screen: a #GdkScreen
+ *
+ * Returns the height of @screen in millimeters. 
+ * Note that on some X servers this value will not be correct.
+ * 
+ * Returns: the heigth of @screen in millimeters.
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_height_mm (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+  return HeightMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
+}
+
+/**
+ * gdk_screen_get_number:
+ * @screen: a #GdkScreen
+ *
+ * Gets the index of @screen among the screens in the display
+ * to which it belongs. (See gdk_screen_get_display())
+ * 
+ * Returns: the index
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_number (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+  
+  return GDK_SCREEN_X11 (screen)->screen_num;
+}
+
+/**
+ * gdk_screen_get_root_window:
+ * @screen: a #GdkScreen
+ *
+ * Gets the root window of @screen.
+ *
+ * Returns: (transfer none): the root window
+ *
+ * Since: 2.2
+ **/
+GdkWindow *
+gdk_screen_get_root_window (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  return GDK_SCREEN_X11 (screen)->root_window;
+}
+
+static void
+_gdk_screen_x11_events_uninit (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  if (screen_x11->xsettings_client)
+    {
+      xsettings_client_destroy (screen_x11->xsettings_client);
+      screen_x11->xsettings_client = NULL;
+    }
+}
+
+static void
+gdk_screen_x11_dispose (GObject *object)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
+  int i;
+
+  for (i = 0; i < 32; ++i)
+    {
+      if (screen_x11->subwindow_gcs[i])
+        {
+          XFreeGC (screen_x11->xdisplay, screen_x11->subwindow_gcs[i]);
+          screen_x11->subwindow_gcs[i] = 0;
+        }
+    }
+
+  _gdk_screen_x11_events_uninit (GDK_SCREEN (object));
+
+  if (screen_x11->root_window)
+    _gdk_window_destroy (screen_x11->root_window, TRUE);
+
+  G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->dispose (object);
+
+  screen_x11->xdisplay = NULL;
+  screen_x11->xscreen = NULL;
+  screen_x11->screen_num = -1;
+  screen_x11->xroot_window = None;
+  screen_x11->wmspec_check_window = None;
+}
+
+static void
+gdk_screen_x11_finalize (GObject *object)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
+  gint          i;
+
+  if (screen_x11->root_window)
+    g_object_unref (screen_x11->root_window);
+
+  /* Visual Part */
+  for (i = 0; i < screen_x11->nvisuals; i++)
+    g_object_unref (screen_x11->visuals[i]);
+  g_free (screen_x11->visuals);
+  g_hash_table_destroy (screen_x11->visual_hash);
+
+  g_free (screen_x11->window_manager_name);
+
+  deinit_multihead (GDK_SCREEN (object));
+  
+  G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->finalize (object);
+}
+
+/**
+ * gdk_screen_get_n_monitors:
+ * @screen: a #GdkScreen
+ *
+ * Returns the number of monitors which @screen consists of.
+ *
+ * Returns: number of monitors which @screen consists of
+ *
+ * Since: 2.2
+ */
+gint
+gdk_screen_get_n_monitors (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+  return GDK_SCREEN_X11 (screen)->n_monitors;
+}
+
+/**
+ * gdk_screen_get_primary_monitor:
+ * @screen: a #GdkScreen.
+ *
+ * Gets the primary monitor for @screen.  The primary monitor
+ * is considered the monitor where the 'main desktop' lives.
+ * While normal application windows typically allow the window
+ * manager to place the windows, specialized desktop applications
+ * such as panels should place themselves on the primary monitor.
+ *
+ * If no primary monitor is configured by the user, the return value
+ * will be 0, defaulting to the first monitor.
+ *
+ * Returns: An integer index for the primary monitor, or 0 if none is configured.
+ *
+ * Since: 2.20
+ */
+gint
+gdk_screen_get_primary_monitor (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+  return GDK_SCREEN_X11 (screen)->primary_monitor;
+}
+
+/**
+ * gdk_screen_get_monitor_width_mm:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
+ *
+ * Gets the width in millimeters of the specified monitor, if available.
+ *
+ * Returns: the width of the monitor, or -1 if not available
+ *
+ * Since: 2.14
+ */
+gint
+gdk_screen_get_monitor_width_mm	(GdkScreen *screen,
+				 gint       monitor_num)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
+  g_return_val_if_fail (monitor_num >= 0, -1);
+  g_return_val_if_fail (monitor_num < screen_x11->n_monitors, -1);
+
+  return screen_x11->monitors[monitor_num].width_mm;
+}
+
+/**
+ * gdk_screen_get_monitor_height_mm:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
+ *
+ * Gets the height in millimeters of the specified monitor.
+ *
+ * Returns: the height of the monitor, or -1 if not available
+ *
+ * Since: 2.14
+ */
+gint
+gdk_screen_get_monitor_height_mm (GdkScreen *screen,
+                                  gint       monitor_num)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
+  g_return_val_if_fail (monitor_num >= 0, -1);
+  g_return_val_if_fail (monitor_num < screen_x11->n_monitors, -1);
+
+  return screen_x11->monitors[monitor_num].height_mm;
+}
+
+/**
+ * gdk_screen_get_monitor_plug_name:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
+ *
+ * Returns the output name of the specified monitor.
+ * Usually something like VGA, DVI, or TV, not the actual
+ * product name of the display device.
+ *
+ * Returns: a newly-allocated string containing the name of the monitor,
+ *   or %NULL if the name cannot be determined
+ *
+ * Since: 2.14
+ */
+gchar *
+gdk_screen_get_monitor_plug_name (GdkScreen *screen,
+				  gint       monitor_num)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+  g_return_val_if_fail (monitor_num >= 0, NULL);
+  g_return_val_if_fail (monitor_num < screen_x11->n_monitors, NULL);
+
+  return g_strdup (screen_x11->monitors[monitor_num].output_name);
+}
+
+/**
+ * gdk_x11_screen_get_monitor_output:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
+ *
+ * Gets the XID of the specified output/monitor.
+ * If the X server does not support version 1.2 of the RANDR
+ * extension, 0 is returned.
+ *
+ * Returns: the XID of the monitor
+ *
+ * Since: 2.14
+ */
+XID
+gdk_x11_screen_get_monitor_output (GdkScreen *screen,
+                                   gint       monitor_num)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), None);
+  g_return_val_if_fail (monitor_num >= 0, None);
+  g_return_val_if_fail (monitor_num < screen_x11->n_monitors, None);
+
+  return screen_x11->monitors[monitor_num].output;
+}
+
+/**
+ * gdk_screen_get_monitor_geometry:
+ * @screen: a #GdkScreen
+ * @monitor_num: the monitor number, between 0 and gdk_screen_get_n_monitors (screen)
+ * @dest: a #GdkRectangle to be filled with the monitor geometry
+ *
+ * Retrieves the #GdkRectangle representing the size and position of
+ * the individual monitor within the entire screen area.
+ *
+ * Note that the size of the entire screen area can be retrieved via
+ * gdk_screen_get_width() and gdk_screen_get_height().
+ *
+ * Since: 2.2
+ */
+void
+gdk_screen_get_monitor_geometry (GdkScreen    *screen,
+				 gint          monitor_num,
+				 GdkRectangle *dest)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+  g_return_if_fail (monitor_num >= 0);
+  g_return_if_fail (monitor_num < screen_x11->n_monitors);
+
+  if (dest)
+    *dest = screen_x11->monitors[monitor_num].geometry;
+}
+
+/**
+ * gdk_screen_get_rgba_visual:
+ * @screen: a #GdkScreen
+ * 
+ * Gets a visual to use for creating windows with an alpha channel.
+ * The windowing system on which GTK+ is running
+ * may not support this capability, in which case %NULL will
+ * be returned. Even if a non-%NULL value is returned, its
+ * possible that the window's alpha channel won't be honored
+ * when displaying the window on the screen: in particular, for
+ * X an appropriate windowing manager and compositing manager
+ * must be running to provide appropriate display.
+ *
+ * This functionality is not implemented in the Windows backend.
+ *
+ * For setting an overall opacity for a top-level window, see
+ * gdk_window_set_opacity().
+ * 
+ * Return value: (transfer none): a visual to use for windows with an
+ *     alpha channel or %NULL if the capability is not available.
+ *
+ * Since: 2.8
+ **/
+GdkVisual *
+gdk_screen_get_rgba_visual (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+
+  return screen_x11->rgba_visual;
+}
+
+/**
+ * gdk_x11_screen_get_xscreen:
+ * @screen: a #GdkScreen.
+ * @returns: (transfer none): an Xlib <type>Screen*</type>
+ *
+ * Returns the screen of a #GdkScreen.
+ *
+ * Since: 2.2
+ */
+Screen *
+gdk_x11_screen_get_xscreen (GdkScreen *screen)
+{
+  return GDK_SCREEN_X11 (screen)->xscreen;
+}
+
+/**
+ * gdk_x11_screen_get_screen_number:
+ * @screen: a #GdkScreen.
+ * @returns: the position of @screen among the screens of
+ *   its display.
+ *
+ * Returns the index of a #GdkScreen.
+ *
+ * Since: 2.2
+ */
+int
+gdk_x11_screen_get_screen_number (GdkScreen *screen)
+{
+  return GDK_SCREEN_X11 (screen)->screen_num;
+}
+
+static gboolean
+check_is_composited (GdkDisplay *display,
+		     GdkScreenX11 *screen_x11)
+{
+  Atom xselection = gdk_x11_atom_to_xatom_for_display (display, screen_x11->cm_selection_atom);
+  Window xwindow;
+  
+  xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), xselection);
+
+  return xwindow != None;
+}
+
+static GdkAtom
+make_cm_atom (int screen_number)
+{
+  gchar *name = g_strdup_printf ("_NET_WM_CM_S%d", screen_number);
+  GdkAtom atom = gdk_atom_intern (name, FALSE);
+  g_free (name);
+  return atom;
+}
+
+static void
+init_monitor_geometry (GdkX11Monitor *monitor,
+		       int x, int y, int width, int height)
+{
+  monitor->geometry.x = x;
+  monitor->geometry.y = y;
+  monitor->geometry.width = width;
+  monitor->geometry.height = height;
+
+  monitor->output = None;
+  monitor->width_mm = -1;
+  monitor->height_mm = -1;
+  monitor->output_name = NULL;
+  monitor->manufacturer = NULL;
+}
+
+static gboolean
+init_fake_xinerama (GdkScreen *screen)
+{
+#ifdef G_ENABLE_DEBUG
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  XSetWindowAttributes atts;
+  Window win;
+  gint w, h;
+
+  if (!(_gdk_debug_flags & GDK_DEBUG_XINERAMA))
+    return FALSE;
+  
+  /* Fake Xinerama mode by splitting the screen into 4 monitors.
+   * Also draw a little cross to make the monitor boundaries visible.
+   */
+  w = WidthOfScreen (screen_x11->xscreen);
+  h = HeightOfScreen (screen_x11->xscreen);
+
+  screen_x11->n_monitors = 4;
+  screen_x11->monitors = g_new0 (GdkX11Monitor, 4);
+  init_monitor_geometry (&screen_x11->monitors[0], 0, 0, w / 2, h / 2);
+  init_monitor_geometry (&screen_x11->monitors[1], w / 2, 0, w / 2, h / 2);
+  init_monitor_geometry (&screen_x11->monitors[2], 0, h / 2, w / 2, h / 2);
+  init_monitor_geometry (&screen_x11->monitors[3], w / 2, h / 2, w / 2, h / 2);
+  
+  atts.override_redirect = 1;
+  atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen), 
+				     screen_x11->screen_num);
+  win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
+		      screen_x11->xroot_window, 0, h / 2, w, 1, 0, 
+		      DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
+				   screen_x11->screen_num),
+		      InputOutput, 
+		      DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
+				    screen_x11->screen_num),
+		      CWOverrideRedirect|CWBackPixel, 
+		      &atts);
+  XMapRaised(GDK_SCREEN_XDISPLAY (screen), win); 
+  win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
+		      screen_x11->xroot_window, w/2 , 0, 1, h, 0, 
+		      DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
+				   screen_x11->screen_num),
+		      InputOutput, 
+		      DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
+				    screen_x11->screen_num),
+		      CWOverrideRedirect|CWBackPixel, 
+		      &atts);
+  XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
+  return TRUE;
+#endif
+  
+  return FALSE;
+}
+
+static void
+free_monitors (GdkX11Monitor *monitors,
+               gint           n_monitors)
+{
+  int i;
+
+  for (i = 0; i < n_monitors; ++i)
+    {
+      g_free (monitors[i].output_name);
+      g_free (monitors[i].manufacturer);
+    }
+
+  g_free (monitors);
+}
+
+#ifdef HAVE_RANDR
+static int
+monitor_compare_function (GdkX11Monitor *monitor1,
+                          GdkX11Monitor *monitor2)
+{
+  /* Sort the leftmost/topmost monitors first.
+   * For "cloned" monitors, sort the bigger ones first
+   * (giving preference to taller monitors over wider
+   * monitors)
+   */
+
+  if (monitor1->geometry.x != monitor2->geometry.x)
+    return monitor1->geometry.x - monitor2->geometry.x;
+
+  if (monitor1->geometry.y != monitor2->geometry.y)
+    return monitor1->geometry.y - monitor2->geometry.y;
+
+  if (monitor1->geometry.height != monitor2->geometry.height)
+    return - (monitor1->geometry.height - monitor2->geometry.height);
+
+  if (monitor1->geometry.width != monitor2->geometry.width)
+    return - (monitor1->geometry.width - monitor2->geometry.width);
+
+  return 0;
+}
+#endif
+
+static gboolean
+init_randr13 (GdkScreen *screen)
+{
+#ifdef HAVE_RANDR
+  GdkDisplay *display = gdk_screen_get_display (screen);
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+  XRRScreenResources *resources;
+  RROutput primary_output;
+  RROutput first_output = None;
+  int i;
+  GArray *monitors;
+  gboolean randr12_compat = FALSE;
+
+  if (!display_x11->have_randr13)
+      return FALSE;
+
+  resources = XRRGetScreenResourcesCurrent (screen_x11->xdisplay,
+				            screen_x11->xroot_window);
+  if (!resources)
+    return FALSE;
+
+  monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor),
+                                resources->noutput);
+
+  for (i = 0; i < resources->noutput; ++i)
+    {
+      XRROutputInfo *output =
+	XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
+
+      /* Non RandR1.2 X driver have output name "default" */
+      randr12_compat |= !g_strcmp0 (output->name, "default");
+
+      if (output->connection == RR_Disconnected)
+        {
+          XRRFreeOutputInfo (output);
+          continue;
+        }
+
+      if (output->crtc)
+	{
+	  GdkX11Monitor monitor;
+	  XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, output->crtc);
+
+	  monitor.geometry.x = crtc->x;
+	  monitor.geometry.y = crtc->y;
+	  monitor.geometry.width = crtc->width;
+	  monitor.geometry.height = crtc->height;
+
+	  monitor.output = resources->outputs[i];
+	  monitor.width_mm = output->mm_width;
+	  monitor.height_mm = output->mm_height;
+	  monitor.output_name = g_strdup (output->name);
+	  /* FIXME: need EDID parser */
+	  monitor.manufacturer = NULL;
+
+	  g_array_append_val (monitors, monitor);
+
+          XRRFreeCrtcInfo (crtc);
+	}
+
+      XRRFreeOutputInfo (output);
+    }
+
+  if (resources->noutput > 0)
+    first_output = resources->outputs[0];
+
+  XRRFreeScreenResources (resources);
+
+  /* non RandR 1.2 X driver doesn't return any usable multihead data */
+  if (randr12_compat)
+    {
+      guint n_monitors = monitors->len;
+
+      free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE),
+		     n_monitors);
+
+      return FALSE;
+    }
+
+  g_array_sort (monitors,
+                (GCompareFunc) monitor_compare_function);
+  screen_x11->n_monitors = monitors->len;
+  screen_x11->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);
+
+  screen_x11->primary_monitor = 0;
+
+  primary_output = XRRGetOutputPrimary (screen_x11->xdisplay,
+                                        screen_x11->xroot_window);
+
+  for (i = 0; i < screen_x11->n_monitors; ++i)
+    {
+      if (screen_x11->monitors[i].output == primary_output)
+	{
+	  screen_x11->primary_monitor = i;
+	  break;
+	}
+
+      /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
+      if (primary_output == None &&
+          g_ascii_strncasecmp (screen_x11->monitors[i].output_name, "LVDS", 4) == 0)
+	{
+	  screen_x11->primary_monitor = i;
+	  break;
+	}
+
+      /* No primary specified and no LVDS found */
+      if (screen_x11->monitors[i].output == first_output)
+	screen_x11->primary_monitor = i;
+    }
+
+  return screen_x11->n_monitors > 0;
+#endif
+
+  return FALSE;
+}
+
+static gboolean
+init_solaris_xinerama (GdkScreen *screen)
+{
+#ifdef HAVE_SOLARIS_XINERAMA
+  Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+  int screen_no = gdk_screen_get_number (screen);
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  XRectangle monitors[MAXFRAMEBUFFERS];
+  unsigned char hints[16];
+  gint result;
+  int n_monitors;
+  int i;
+  
+  if (!XineramaGetState (dpy, screen_no))
+    return FALSE;
+
+  result = XineramaGetInfo (dpy, screen_no, monitors, hints, &n_monitors);
+
+  /* Yes I know it should be Success but the current implementation 
+   * returns the num of monitor
+   */
+  if (result == 0)
+    {
+      return FALSE;
+    }
+
+  screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
+  screen_x11->n_monitors = n_monitors;
+
+  for (i = 0; i < n_monitors; i++)
+    {
+      init_monitor_geometry (&screen_x11->monitors[i],
+			     monitors[i].x, monitors[i].y,
+			     monitors[i].width, monitors[i].height);
+    }
+
+  screen_x11->primary_monitor = 0;
+
+  return TRUE;
+#endif /* HAVE_SOLARIS_XINERAMA */
+
+  return FALSE;
+}
+
+static gboolean
+init_xfree_xinerama (GdkScreen *screen)
+{
+#ifdef HAVE_XFREE_XINERAMA
+  Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  XineramaScreenInfo *monitors;
+  int i, n_monitors;
+  
+  if (!XineramaIsActive (dpy))
+    return FALSE;
+
+  monitors = XineramaQueryScreens (dpy, &n_monitors);
+  
+  if (n_monitors <= 0 || monitors == NULL)
+    {
+      /* If Xinerama doesn't think we have any monitors, try acting as
+       * though we had no Xinerama. If the "no monitors" condition
+       * is because XRandR 1.2 is currently switching between CRTCs,
+       * we'll be notified again when we have our monitor back,
+       * and can go back into Xinerama-ish mode at that point.
+       */
+      if (monitors)
+	XFree (monitors);
+      
+      return FALSE;
+    }
+
+  screen_x11->n_monitors = n_monitors;
+  screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
+  
+  for (i = 0; i < n_monitors; ++i)
+    {
+      init_monitor_geometry (&screen_x11->monitors[i],
+			     monitors[i].x_org, monitors[i].y_org,
+			     monitors[i].width, monitors[i].height);
+    }
+  
+  XFree (monitors);
+  
+  screen_x11->primary_monitor = 0;
+
+  return TRUE;
+#endif /* HAVE_XFREE_XINERAMA */
+  
+  return FALSE;
+}
+
+static void
+deinit_multihead (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  free_monitors (screen_x11->monitors, screen_x11->n_monitors);
+
+  screen_x11->n_monitors = 0;
+  screen_x11->monitors = NULL;
+}
+
+static gboolean
+compare_monitor (GdkX11Monitor *m1,
+                 GdkX11Monitor *m2)
+{
+  if (m1->geometry.x != m2->geometry.x ||
+      m1->geometry.y != m2->geometry.y ||
+      m1->geometry.width != m2->geometry.width ||
+      m1->geometry.height != m2->geometry.height)
+    return FALSE;
+
+  if (m1->width_mm != m2->width_mm ||
+      m1->height_mm != m2->height_mm)
+    return FALSE;
+
+  if (g_strcmp0 (m1->output_name, m2->output_name) != 0)
+    return FALSE;
+
+  if (g_strcmp0 (m1->manufacturer, m2->manufacturer) != 0)
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+compare_monitors (GdkX11Monitor *monitors1, gint n_monitors1,
+                  GdkX11Monitor *monitors2, gint n_monitors2)
+{
+  gint i;
+
+  if (n_monitors1 != n_monitors2)
+    return FALSE;
+
+  for (i = 0; i < n_monitors1; i++)
+    {
+      if (!compare_monitor (monitors1 + i, monitors2 + i))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+init_multihead (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  int opcode, firstevent, firsterror;
+
+  /* There are four different implementations of multihead support: 
+   *
+   *  1. Fake Xinerama for debugging purposes
+   *  2. RandR 1.2
+   *  3. Solaris Xinerama
+   *  4. XFree86/Xorg Xinerama
+   *
+   * We use them in that order.
+   */
+  if (init_fake_xinerama (screen))
+    return;
+
+  if (init_randr13 (screen))
+    return;
+
+  if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
+		       &opcode, &firstevent, &firsterror))
+    {
+      if (init_solaris_xinerama (screen))
+	return;
+      
+      if (init_xfree_xinerama (screen))
+	return;
+    }
+
+  /* No multihead support of any kind for this screen */
+  screen_x11->n_monitors = 1;
+  screen_x11->monitors = g_new0 (GdkX11Monitor, 1);
+  screen_x11->primary_monitor = 0;
+
+  init_monitor_geometry (screen_x11->monitors, 0, 0,
+			 WidthOfScreen (screen_x11->xscreen),
+			 HeightOfScreen (screen_x11->xscreen));
+}
+
+GdkScreen *
+_gdk_x11_screen_new (GdkDisplay *display,
+		     gint	 screen_number) 
+{
+  GdkScreen *screen;
+  GdkScreenX11 *screen_x11;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  screen = g_object_new (GDK_TYPE_SCREEN_X11, NULL);
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+  screen_x11->display = display;
+  screen_x11->xdisplay = display_x11->xdisplay;
+  screen_x11->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
+  screen_x11->screen_num = screen_number;
+  screen_x11->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
+  screen_x11->wmspec_check_window = None;
+  /* we want this to be always non-null */
+  screen_x11->window_manager_name = g_strdup ("unknown");
+  
+  init_multihead (screen);
+  init_randr_support (screen);
+  
+  _gdk_visual_init (screen);
+  _gdk_windowing_window_init (screen);
+  
+  return screen;
+}
+
+/*
+ * It is important that we first request the selection
+ * notification, and then setup the initial state of
+ * is_composited to avoid a race condition here.
+ */
+void
+_gdk_x11_screen_setup (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  screen_x11->cm_selection_atom = make_cm_atom (screen_x11->screen_num);
+  gdk_display_request_selection_notification (screen_x11->display,
+					      screen_x11->cm_selection_atom);
+  screen_x11->is_composited = check_is_composited (screen_x11->display, screen_x11);
+}
+
+/**
+ * gdk_screen_is_composited:
+ * @screen: a #GdkScreen
+ * 
+ * Returns whether windows with an RGBA visual can reasonably
+ * be expected to have their alpha channel drawn correctly on
+ * the screen.
+ *
+ * On X11 this function returns whether a compositing manager is
+ * compositing @screen.
+ * 
+ * Return value: Whether windows with RGBA visuals can reasonably be
+ * expected to have their alpha channels drawn correctly on the screen.
+ * 
+ * Since: 2.10
+ **/
+gboolean
+gdk_screen_is_composited (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+
+  return screen_x11->is_composited;
+}
+
+static void
+init_randr_support (GdkScreen * screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  
+  XSelectInput (GDK_SCREEN_XDISPLAY (screen),
+		screen_x11->xroot_window,
+		StructureNotifyMask);
+
+#ifdef HAVE_RANDR
+  XRRSelectInput (GDK_SCREEN_XDISPLAY (screen),
+		  screen_x11->xroot_window,
+		  RRScreenChangeNotifyMask	|
+		  RRCrtcChangeNotifyMask	|
+		  RROutputPropertyNotifyMask);
+#endif
+}
+
+static void
+process_monitors_change (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  gint		 n_monitors;
+  GdkX11Monitor	*monitors;
+  gboolean changed;
+
+  n_monitors = screen_x11->n_monitors;
+  monitors = screen_x11->monitors;
+
+  screen_x11->n_monitors = 0;
+  screen_x11->monitors = NULL;
+
+  init_multihead (screen);
+
+  changed = !compare_monitors (monitors, n_monitors,
+                               screen_x11->monitors, screen_x11->n_monitors);
+
+  free_monitors (monitors, n_monitors);
+
+  if (changed)
+    g_signal_emit_by_name (screen, "monitors-changed");
+}
+
+void
+_gdk_x11_screen_size_changed (GdkScreen *screen,
+			      XEvent    *event)
+{
+  gint width, height;
+#ifdef HAVE_RANDR
+  GdkDisplayX11 *display_x11;
+#endif
+
+  width = gdk_screen_get_width (screen);
+  height = gdk_screen_get_height (screen);
+
+#ifdef HAVE_RANDR
+  display_x11 = GDK_DISPLAY_X11 (gdk_screen_get_display (screen));
+
+  if (display_x11->have_randr13 && event->type == ConfigureNotify)
+    {
+      g_signal_emit_by_name (screen, "monitors-changed");
+      return;
+    }
+
+  XRRUpdateConfiguration (event);
+#else
+  if (event->type == ConfigureNotify)
+    {
+      XConfigureEvent *rcevent = (XConfigureEvent *) event;
+      Screen	    *xscreen = gdk_x11_screen_get_xscreen (screen);
+
+      xscreen->width   = rcevent->width;
+      xscreen->height  = rcevent->height;
+    }
+  else
+    return;
+#endif
+
+  process_monitors_change (screen);
+
+  if (width != gdk_screen_get_width (screen) ||
+      height != gdk_screen_get_height (screen))
+    g_signal_emit_by_name (screen, "size-changed");
+}
+
+void
+_gdk_x11_screen_window_manager_changed (GdkScreen *screen)
+{
+  g_signal_emit (screen, signals[WINDOW_MANAGER_CHANGED], 0);
+}
+
+void
+_gdk_x11_screen_process_owner_change (GdkScreen *screen,
+				      XEvent *event)
+{
+#ifdef HAVE_XFIXES
+  XFixesSelectionNotifyEvent *selection_event = (XFixesSelectionNotifyEvent *)event;
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  Atom xcm_selection_atom = gdk_x11_atom_to_xatom_for_display (screen_x11->display,
+							       screen_x11->cm_selection_atom);
+
+  if (selection_event->selection == xcm_selection_atom)
+    {
+      gboolean composited = selection_event->owner != None;
+
+      if (composited != screen_x11->is_composited)
+	{
+	  screen_x11->is_composited = composited;
+
+	  g_signal_emit_by_name (screen, "composited-changed");
+	}
+    }
+#endif
+}
+
+/**
+ * _gdk_windowing_substitute_screen_number:
+ * @display_name: The name of a display, in the form used by 
+ *                gdk_display_open (). If %NULL a default value
+ *                will be used. On X11, this is derived from the DISPLAY
+ *                environment variable.
+ * @screen_number: The number of a screen within the display
+ *                 referred to by @display_name.
+ *
+ * Modifies a @display_name to make @screen_number the default
+ * screen when the display is opened.
+ *
+ * Return value: a newly allocated string holding the resulting
+ *   display name. Free with g_free().
+ */
+gchar * 
+_gdk_windowing_substitute_screen_number (const gchar *display_name,
+					 gint         screen_number)
+{
+  GString *str;
+  gchar   *p;
+
+  if (!display_name)
+    display_name = getenv ("DISPLAY");
+
+  if (!display_name)
+    return NULL;
+
+  str = g_string_new (display_name);
+
+  p = strrchr (str->str, '.');
+  if (p && p >	strchr (str->str, ':'))
+    g_string_truncate (str, p - str->str);
+
+  g_string_append_printf (str, ".%d", screen_number);
+
+  return g_string_free (str, FALSE);
+}
+
+/**
+ * gdk_screen_make_display_name:
+ * @screen: a #GdkScreen
+ * 
+ * Determines the name to pass to gdk_display_open() to get
+ * a #GdkDisplay with this screen as the default screen.
+ * 
+ * Return value: a newly allocated string, free with g_free()
+ *
+ * Since: 2.2
+ **/
+gchar *
+gdk_screen_make_display_name (GdkScreen *screen)
+{
+  const gchar *old_display;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  old_display = gdk_display_get_name (gdk_screen_get_display (screen));
+
+  return _gdk_windowing_substitute_screen_number (old_display, 
+						  gdk_screen_get_number (screen));
+}
+
+/**
+ * gdk_screen_get_active_window
+ * @screen: a #GdkScreen
+ *
+ * Returns the screen's currently active window.
+ *
+ * On X11, this is done by inspecting the _NET_ACTIVE_WINDOW property
+ * on the root window, as described in the <ulink
+ * url="http://www.freedesktop.org/Standards/wm-spec";>Extended Window
+ * Manager Hints</ulink>. If there is no currently currently active
+ * window, or the window manager does not support the
+ * _NET_ACTIVE_WINDOW hint, this function returns %NULL.
+ *
+ * On other platforms, this function may return %NULL, depending on whether
+ * it is implementable on that platform.
+ *
+ * The returned window should be unrefed using g_object_unref() when
+ * no longer needed.
+ *
+ * Return value: the currently active window, or %NULL.
+ *
+ * Since: 2.10
+ **/
+GdkWindow *
+gdk_screen_get_active_window (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11;
+  GdkWindow *ret = NULL;
+  Atom type_return;
+  gint format_return;
+  gulong nitems_return;
+  gulong bytes_after_return;
+  guchar *data = NULL;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  if (!gdk_x11_screen_supports_net_wm_hint (screen,
+                                            gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW")))
+    return NULL;
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+
+  if (XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
+	                  gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+			                                         "_NET_ACTIVE_WINDOW"),
+		          0, 1, False, XA_WINDOW, &type_return,
+		          &format_return, &nitems_return,
+                          &bytes_after_return, &data)
+      == Success)
+    {
+      if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
+        {
+          GdkNativeWindow window = *(GdkNativeWindow *) data;
+
+          if (window != None)
+            {
+              ret = gdk_window_foreign_new_for_display (screen_x11->display,
+                                                        *(GdkNativeWindow *) data);
+            }
+        }
+    }
+
+  if (data)
+    XFree (data);
+
+  return ret;
+}
+
+/**
+ * gdk_screen_get_window_stack:
+ * @screen: a #GdkScreen
+ *
+ * Returns a #GList of #GdkWindow<!-- -->s representing the current
+ * window stack.
+ *
+ * On X11, this is done by inspecting the _NET_CLIENT_LIST_STACKING
+ * property on the root window, as described in the <ulink
+ * url="http://www.freedesktop.org/Standards/wm-spec";>Extended Window
+ * Manager Hints</ulink>. If the window manager does not support the
+ * _NET_CLIENT_LIST_STACKING hint, this function returns %NULL.
+ *
+ * On other platforms, this function may return %NULL, depending on whether
+ * it is implementable on that platform.
+ *
+ * The returned list is newly allocated and owns references to the
+ * windows it contains, so it should be freed using g_list_free() and
+ * its windows unrefed using g_object_unref() when no longer needed.
+ *
+ * Return value: (transfer full) (element-type GdkWindow):
+ *     a list of #GdkWindow<!-- -->s for the current window stack,
+ *               or %NULL.
+ *
+ * Since: 2.10
+ **/
+GList *
+gdk_screen_get_window_stack (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11;
+  GList *ret = NULL;
+  Atom type_return;
+  gint format_return;
+  gulong nitems_return;
+  gulong bytes_after_return;
+  guchar *data = NULL;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  if (!gdk_x11_screen_supports_net_wm_hint (screen,
+                                            gdk_atom_intern_static_string ("_NET_CLIENT_LIST_STACKING")))
+    return NULL;
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+
+  if (XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
+	                  gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+			                                         "_NET_CLIENT_LIST_STACKING"),
+		          0, G_MAXLONG, False, XA_WINDOW, &type_return,
+		          &format_return, &nitems_return,
+                          &bytes_after_return, &data)
+      == Success)
+    {
+      if ((type_return == XA_WINDOW) && (format_return == 32) &&
+          (data) && (nitems_return > 0))
+        {
+          gulong *stack = (gulong *) data;
+          GdkWindow *win;
+          int i;
+
+          for (i = 0; i < nitems_return; i++)
+            {
+              win = gdk_window_foreign_new_for_display (screen_x11->display,
+                                                        (GdkNativeWindow)stack[i]);
+
+              if (win != NULL)
+                ret = g_list_append (ret, win);
+            }
+        }
+    }
+
+  if (data)
+    XFree (data);
+
+  return ret;
+}
+
+/* Sends a ClientMessage to all toplevel client windows */
+static gboolean
+gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
+					      XEvent     *xev,
+					      guint32     xid,
+					      guint       level)
+{
+  Atom type = None;
+  int format;
+  unsigned long nitems, after;
+  unsigned char *data;
+  Window *ret_children, ret_root, ret_parent;
+  unsigned int ret_nchildren;
+  gboolean send = FALSE;
+  gboolean found = FALSE;
+  gboolean result = FALSE;
+  int i;
+
+  gdk_error_trap_push ();
+
+  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
+			  gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE"),
+			  0, 0, False, AnyPropertyType,
+			  &type, &format, &nitems, &after, &data) != Success)
+    goto out;
+
+  if (type)
+    {
+      send = TRUE;
+      XFree (data);
+    }
+  else
+    {
+      /* OK, we're all set, now let's find some windows to send this to */
+      if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xid,
+		      &ret_root, &ret_parent,
+		      &ret_children, &ret_nchildren))
+	goto out;
+
+      for(i = 0; i < ret_nchildren; i++)
+	if (gdk_event_send_client_message_to_all_recurse (display, xev, ret_children[i], level + 1))
+	  found = TRUE;
+
+      XFree (ret_children);
+    }
+
+  if (send || (!found && (level == 1)))
+    {
+      xev->xclient.window = xid;
+      _gdk_send_xevent (display, xid, False, NoEventMask, xev);
+    }
+
+  result = send || found;
+
+ out:
+  gdk_error_trap_pop_ignored ();
+
+  return result;
+}
+
+/**
+ * gdk_screen_broadcast_client_message:
+ * @screen: the #GdkScreen where the event will be broadcasted.
+ * @event: the #GdkEvent.
+ *
+ * On X11, sends an X ClientMessage event to all toplevel windows on
+ * @screen.
+ *
+ * Toplevel windows are determined by checking for the WM_STATE property,
+ * as described in the Inter-Client Communication Conventions Manual (ICCCM).
+ * If no windows are found with the WM_STATE property set, the message is
+ * sent to all children of the root window.
+ *
+ * On Windows, broadcasts a message registered with the name
+ * GDK_WIN32_CLIENT_MESSAGE to all top-level windows. The amount of
+ * data is limited to one long, i.e. four bytes.
+ *
+ * Since: 2.2
+ */
+
+void
+gdk_screen_broadcast_client_message (GdkScreen *screen,
+				     GdkEvent  *event)
+{
+  XEvent sev;
+  GdkWindow *root_window;
+
+  g_return_if_fail (event != NULL);
+
+  root_window = gdk_screen_get_root_window (screen);
+
+  /* Set up our event to send, with the exception of its target window */
+  sev.xclient.type = ClientMessage;
+  sev.xclient.display = GDK_WINDOW_XDISPLAY (root_window);
+  sev.xclient.format = event->client.data_format;
+  memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
+  sev.xclient.message_type =
+    gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (root_window),
+				       event->client.message_type);
+
+  gdk_event_send_client_message_to_all_recurse (gdk_screen_get_display (screen),
+						&sev,
+						GDK_WINDOW_XID (root_window),
+						0);
+}
+
+static gboolean
+check_transform (const gchar *xsettings_name,
+		 GType        src_type,
+		 GType        dest_type)
+{
+  if (!g_value_type_transformable (src_type, dest_type))
+    {
+      g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
+		 xsettings_name,
+		 g_type_name (src_type),
+		 g_type_name (dest_type));
+      return FALSE;
+    }
+  else
+    return TRUE;
+}
+
+/**
+ * gdk_screen_get_setting:
+ * @screen: the #GdkScreen where the setting is located
+ * @name: the name of the setting
+ * @value: location to store the value of the setting
+ *
+ * Retrieves a desktop-wide setting such as double-click time
+ * for the #GdkScreen @screen.
+ *
+ * FIXME needs a list of valid settings here, or a link to
+ * more information.
+ *
+ * Returns: %TRUE if the setting existed and a value was stored
+ *   in @value, %FALSE otherwise.
+ *
+ * Since: 2.2
+ **/
+gboolean
+gdk_screen_get_setting (GdkScreen   *screen,
+			const gchar *name,
+			GValue      *value)
+{
+
+  const char *xsettings_name = NULL;
+  XSettingsResult result;
+  XSettingsSetting *setting = NULL;
+  GdkScreenX11 *screen_x11;
+  gboolean success = FALSE;
+  gint i;
+  GValue tmp_val = { 0, };
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+
+  for (i = 0; i < GDK_SETTINGS_N_ELEMENTS(); i++)
+    if (strcmp (GDK_SETTINGS_GDK_NAME (i), name) == 0)
+      {
+	xsettings_name = GDK_SETTINGS_X_NAME (i);
+	break;
+      }
+
+  if (!xsettings_name)
+    goto out;
+
+  result = xsettings_client_get_setting (screen_x11->xsettings_client,
+					 xsettings_name, &setting);
+  if (result != XSETTINGS_SUCCESS)
+    goto out;
+
+  switch (setting->type)
+    {
+    case XSETTINGS_TYPE_INT:
+      if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
+	{
+	  g_value_init (&tmp_val, G_TYPE_INT);
+	  g_value_set_int (&tmp_val, setting->data.v_int);
+	  g_value_transform (&tmp_val, value);
+
+	  success = TRUE;
+	}
+      break;
+    case XSETTINGS_TYPE_STRING:
+      if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
+	{
+	  g_value_init (&tmp_val, G_TYPE_STRING);
+	  g_value_set_string (&tmp_val, setting->data.v_string);
+	  g_value_transform (&tmp_val, value);
+
+	  success = TRUE;
+	}
+      break;
+    case XSETTINGS_TYPE_COLOR:
+      if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
+	{
+	  GdkColor color;
+
+	  g_value_init (&tmp_val, GDK_TYPE_COLOR);
+
+	  color.pixel = 0;
+	  color.red = setting->data.v_color.red;
+	  color.green = setting->data.v_color.green;
+	  color.blue = setting->data.v_color.blue;
+
+	  g_value_set_boxed (&tmp_val, &color);
+
+	  g_value_transform (&tmp_val, value);
+
+	  success = TRUE;
+	}
+      break;
+    }
+
+  g_value_unset (&tmp_val);
+
+ out:
+  if (setting)
+    xsettings_setting_free (setting);
+
+  if (success)
+    return TRUE;
+  else
+    return _gdk_x11_get_xft_setting (screen, name, value);
+}
+
+static void
+cleanup_atoms(gpointer data)
+{
+  NetWmSupportedAtoms *supported_atoms = data;
+  if (supported_atoms->atoms)
+      XFree (supported_atoms->atoms);
+  g_free (supported_atoms);
+}
+
+static void
+fetch_net_wm_check_window (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11;
+  GdkDisplay *display;
+  Atom type;
+  gint format;
+  gulong n_items;
+  gulong bytes_after;
+  guchar *data;
+  Window *xwindow;
+  GTimeVal tv;
+  gint error;
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+  display = screen_x11->display;
+
+  g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client);
+  
+  g_get_current_time (&tv);
+
+  if (ABS  (tv.tv_sec - screen_x11->last_wmspec_check_time) < 15)
+    return; /* we've checked recently */
+
+  screen_x11->last_wmspec_check_time = tv.tv_sec;
+
+  data = NULL;
+  XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
+		      gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
+		      0, G_MAXLONG, False, XA_WINDOW, &type, &format,
+		      &n_items, &bytes_after, &data);
+  
+  if (type != XA_WINDOW)
+    {
+      if (data)
+        XFree (data);
+      return;
+    }
+
+  xwindow = (Window *)data;
+
+  if (screen_x11->wmspec_check_window == *xwindow)
+    {
+      XFree (xwindow);
+      return;
+    }
+
+  gdk_error_trap_push ();
+
+  /* Find out if this WM goes away, so we can reset everything. */
+  XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask);
+
+  error = gdk_error_trap_pop ();
+  if (!error)
+    {
+      screen_x11->wmspec_check_window = *xwindow;
+      screen_x11->need_refetch_net_supported = TRUE;
+      screen_x11->need_refetch_wm_name = TRUE;
+
+      /* Careful, reentrancy */
+      _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
+    }
+  else if (error == BadWindow)
+    {
+      /* Leftover property, try again immediately, new wm may be starting up */
+      screen_x11->last_wmspec_check_time = 0;
+    }
+
+  XFree (xwindow);
+}
+
+/**
+ * gdk_x11_screen_supports_net_wm_hint:
+ * @screen: the relevant #GdkScreen.
+ * @property: a property atom.
+ *
+ * This function is specific to the X11 backend of GDK, and indicates
+ * whether the window manager supports a certain hint from the
+ * Extended Window Manager Hints Specification. You can find this
+ * specification on
+ * <ulink url="http://www.freedesktop.org";>http://www.freedesktop.org</ulink>.
+ *
+ * When using this function, keep in mind that the window manager
+ * can change over time; so you shouldn't use this function in
+ * a way that impacts persistent application state. A common bug
+ * is that your application can start up before the window manager
+ * does when the user logs in, and before the window manager starts
+ * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
+ * You can monitor the window_manager_changed signal on #GdkScreen to detect
+ * a window manager change.
+ *
+ * Return value: %TRUE if the window manager supports @property
+ *
+ * Since: 2.2
+ **/
+gboolean
+gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
+				     GdkAtom    property)
+{
+  gulong i;
+  GdkScreenX11 *screen_x11;
+  NetWmSupportedAtoms *supported_atoms;
+  GdkDisplay *display;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+  display = screen_x11->display;
+
+  if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+    return FALSE;
+
+  supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
+  if (!supported_atoms)
+    {
+      supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
+      g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
+    }
+
+  fetch_net_wm_check_window (screen);
+
+  if (screen_x11->wmspec_check_window == None)
+    return FALSE;
+
+  if (screen_x11->need_refetch_net_supported)
+    {
+      /* WM has changed since we last got the supported list,
+       * refetch it.
+       */
+      Atom type;
+      gint format;
+      gulong bytes_after;
+
+      screen_x11->need_refetch_net_supported = FALSE;
+
+      if (supported_atoms->atoms)
+        XFree (supported_atoms->atoms);
+
+      supported_atoms->atoms = NULL;
+      supported_atoms->n_atoms = 0;
+
+      XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window,
+                          gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"),
+                          0, G_MAXLONG, False, XA_ATOM, &type, &format,
+                          &supported_atoms->n_atoms, &bytes_after,
+                          (guchar **)&supported_atoms->atoms);
+
+      if (type != XA_ATOM)
+        return FALSE;
+    }
+
+  if (supported_atoms->atoms == NULL)
+    return FALSE;
+
+  i = 0;
+  while (i < supported_atoms->n_atoms)
+    {
+      if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property))
+        return TRUE;
+
+      ++i;
+    }
+
+  return FALSE;
+}
+
+/**
+ * gdk_net_wm_supports:
+ * @property: a property atom.
+ *
+ * This function is specific to the X11 backend of GDK, and indicates
+ * whether the window manager for the default screen supports a certain
+ * hint from the Extended Window Manager Hints Specification. See
+ * gdk_x11_screen_supports_net_wm_hint() for complete details.
+ *
+ * Return value: %TRUE if the window manager supports @property
+ **/
+gboolean
+gdk_net_wm_supports (GdkAtom property)
+{
+  return gdk_x11_screen_supports_net_wm_hint (gdk_screen_get_default (), property);
+}
+
+static void
+refcounted_grab_server (Display *xdisplay)
+{
+  GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
+
+  gdk_x11_display_grab (display);
+}
+
+static void
+refcounted_ungrab_server (Display *xdisplay)
+{
+  GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
+
+  gdk_x11_display_ungrab (display);
+}
+
+static GdkFilterReturn
+gdk_xsettings_client_event_filter (GdkXEvent *xevent,
+				   GdkEvent  *event,
+				   gpointer   data)
+{
+  GdkScreenX11 *screen = data;
+
+  if (xsettings_client_process_event (screen->xsettings_client, (XEvent *)xevent))
+    return GDK_FILTER_REMOVE;
+  else
+    return GDK_FILTER_CONTINUE;
+}
+
+static Bool
+gdk_xsettings_watch_cb (Window   window,
+			Bool	 is_start,
+			long     mask,
+			void    *cb_data)
+{
+  GdkWindow *gdkwin;
+  GdkScreen *screen = cb_data;
+
+  gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window);
+
+  if (is_start)
+    {
+      if (gdkwin)
+	g_object_ref (gdkwin);
+      else
+	{
+	  gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
+	  
+	  /* gdk_window_foreign_new_for_display() can fail and return NULL if the
+	   * window has already been destroyed.
+	   */
+	  if (!gdkwin)
+	    return False;
+	}
+
+      gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+    }
+  else
+    {
+      if (!gdkwin)
+	{
+	  /* gdkwin should not be NULL here, since if starting the watch succeeded
+	   * we have a reference on the window. It might mean that the caller didn't
+	   * remove the watch when it got a DestroyNotify event. Or maybe the
+	   * caller ignored the return value when starting the watch failed.
+	   */
+	  g_warning ("gdk_xsettings_watch_cb(): Couldn't find window to unwatch");
+	  return False;
+	}
+      
+      gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+      g_object_unref (gdkwin);
+    }
+
+  return True;
+}
+
+static void
+gdk_xsettings_notify_cb (const char       *name,
+			 XSettingsAction   action,
+			 XSettingsSetting *setting,
+			 void             *data)
+{
+  GdkEvent new_event;
+  GdkScreen *screen = data;
+  GdkScreenX11 *screen_x11 = data;
+  int i;
+
+  if (screen_x11->xsettings_in_init)
+    return;
+  
+  new_event.type = GDK_SETTING;
+  new_event.setting.window = gdk_screen_get_root_window (screen);
+  new_event.setting.send_event = FALSE;
+  new_event.setting.name = NULL;
+
+  for (i = 0; i < GDK_SETTINGS_N_ELEMENTS() ; i++)
+    if (strcmp (GDK_SETTINGS_X_NAME (i), name) == 0)
+      {
+	new_event.setting.name = (char*) GDK_SETTINGS_GDK_NAME (i);
+	break;
+      }
+  
+  if (!new_event.setting.name)
+    return;
+  
+  switch (action)
+    {
+    case XSETTINGS_ACTION_NEW:
+      new_event.setting.action = GDK_SETTING_ACTION_NEW;
+      break;
+    case XSETTINGS_ACTION_CHANGED:
+      new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
+      break;
+    case XSETTINGS_ACTION_DELETED:
+      new_event.setting.action = GDK_SETTING_ACTION_DELETED;
+      break;
+    }
+
+  gdk_event_put (&new_event);
+}
+
+void
+_gdk_screen_x11_events_init (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  /* Keep a flag to avoid extra notifies that we don't need
+   */
+  screen_x11->xsettings_in_init = TRUE;
+  screen_x11->xsettings_client = xsettings_client_new_with_grab_funcs (screen_x11->xdisplay,
+						                       screen_x11->screen_num,
+						                       gdk_xsettings_notify_cb,
+						                       gdk_xsettings_watch_cb,
+						                       screen,
+                                                                       refcounted_grab_server,
+                                                                       refcounted_ungrab_server);
+  screen_x11->xsettings_in_init = FALSE;
+}
+
+/**
+ * gdk_x11_screen_get_window_manager_name:
+ * @screen: a #GdkScreen
+ *
+ * Returns the name of the window manager for @screen.
+ *
+ * Return value: the name of the window manager screen @screen, or
+ * "unknown" if the window manager is unknown. The string is owned by GDK
+ * and should not be freed.
+ *
+ * Since: 2.2
+ **/
+const char*
+gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11;
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+
+  if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client))
+    return screen_x11->window_manager_name;
+
+  fetch_net_wm_check_window (screen);
+
+  if (screen_x11->need_refetch_wm_name)
+    {
+      /* Get the name of the window manager */
+      screen_x11->need_refetch_wm_name = FALSE;
+
+      g_free (screen_x11->window_manager_name);
+      screen_x11->window_manager_name = g_strdup ("unknown");
+
+      if (screen_x11->wmspec_check_window != None)
+        {
+          Atom type;
+          gint format;
+          gulong n_items;
+          gulong bytes_after;
+          gchar *name;
+
+          name = NULL;
+
+	  gdk_error_trap_push ();
+
+          XGetWindowProperty (GDK_DISPLAY_XDISPLAY (screen_x11->display),
+                              screen_x11->wmspec_check_window,
+                              gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+                                                                     "_NET_WM_NAME"),
+                              0, G_MAXLONG, False,
+                              gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+                                                                     "UTF8_STRING"),
+                              &type, &format,
+                              &n_items, &bytes_after,
+                              (guchar **)&name);
+
+          gdk_error_trap_pop_ignored ();
+
+          if (name != NULL)
+            {
+              g_free (screen_x11->window_manager_name);
+              screen_x11->window_manager_name = g_strdup (name);
+              XFree (name);
+            }
+        }
+    }
+
+  return GDK_SCREEN_X11 (screen)->window_manager_name;
+}
diff --git a/gdk/broadway/gdkscreen-broadway.h b/gdk/broadway/gdkscreen-broadway.h
new file mode 100644
index 0000000..1b9d95e
--- /dev/null
+++ b/gdk/broadway/gdkscreen-broadway.h
@@ -0,0 +1,129 @@
+/*
+ * gdkscreen-broadway.h
+ * 
+ * Copyright 2001 Sun Microsystems Inc. 
+ *
+ * Erwann Chenede <erwann chenede sun com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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_SCREEN_BROADWAY_H__
+#define __GDK_SCREEN_BROADWAY_H__
+
+#include <gdk/gdkscreen.h>
+#include <gdk/gdkvisual.h>
+#include "gdkprivate-broadway.h"
+#include "xsettings-client.h"
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+G_BEGIN_DECLS
+  
+typedef struct _GdkScreenX11 GdkScreenX11;
+typedef struct _GdkScreenX11Class GdkScreenX11Class;
+
+#define GDK_TYPE_SCREEN_X11              (_gdk_screen_x11_get_type ())
+#define GDK_SCREEN_X11(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SCREEN_X11, GdkScreenX11))
+#define GDK_SCREEN_X11_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SCREEN_X11, GdkScreenX11Class))
+#define GDK_IS_SCREEN_X11(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SCREEN_X11))
+#define GDK_IS_SCREEN_X11_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SCREEN_X11))
+#define GDK_SCREEN_X11_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SCREEN_X11, GdkScreenX11Class))
+
+typedef struct _GdkX11Monitor GdkX11Monitor;
+
+struct _GdkScreenX11
+{
+  GdkScreen parent_instance;
+  
+  GdkDisplay *display;
+  Display *xdisplay;
+  Screen *xscreen;
+  gint screen_num;
+  Window xroot_window;
+  GdkWindow *root_window;
+
+  /* Window manager */
+  long last_wmspec_check_time;
+  Window wmspec_check_window;
+  char *window_manager_name;
+  /* TRUE if wmspec_check_window has changed since last
+   * fetch of _NET_SUPPORTED
+   */
+  guint need_refetch_net_supported : 1;
+  /* TRUE if wmspec_check_window has changed since last
+   * fetch of window manager name
+   */
+  guint need_refetch_wm_name : 1;
+  
+  /* Visual Part */
+  GdkVisual *system_visual;
+  GdkVisual **visuals;
+  gint nvisuals;
+  gint available_depths[7];
+  gint navailable_depths;
+  GdkVisualType available_types[6];
+  gint navailable_types;
+  GHashTable *visual_hash;
+  GdkVisual *rgba_visual;
+  
+  /* X settings */
+  XSettingsClient *xsettings_client;
+  guint xsettings_in_init : 1;
+  
+  /* Xinerama/RandR 1.2 */
+  gint		 n_monitors;
+  GdkX11Monitor	*monitors;
+  gint           primary_monitor;
+
+  /* cache for window->translate vfunc */
+  GC subwindow_gcs[32];
+
+  /* Xft resources for the display, used for default values for
+   * the Xft/ XSETTINGS
+   */
+  gboolean xft_init;		/* Whether we've intialized these values yet */
+  gboolean xft_antialias;
+  gboolean xft_hinting;
+  gint xft_hintstyle;
+  gint xft_rgba;
+  gint xft_dpi;
+
+  GdkAtom cm_selection_atom;
+  gboolean is_composited;
+};
+  
+struct _GdkScreenX11Class
+{
+  GdkScreenClass parent_class;
+
+  void (* window_manager_changed) (GdkScreenX11 *screen_x11);
+};
+
+GType       _gdk_screen_x11_get_type (void);
+GdkScreen * _gdk_x11_screen_new      (GdkDisplay *display,
+				      gint	  screen_number);
+
+void _gdk_x11_screen_setup                  (GdkScreen *screen);
+void _gdk_x11_screen_window_manager_changed (GdkScreen *screen);
+void _gdk_x11_screen_size_changed           (GdkScreen *screen,
+					     XEvent    *event);
+void _gdk_x11_screen_process_owner_change   (GdkScreen *screen,
+					     XEvent    *event);
+
+G_END_DECLS
+
+#endif /* __GDK_SCREEN_BROADWAY_H__ */
diff --git a/gdk/broadway/gdkselection-broadway.c b/gdk/broadway/gdkselection-broadway.c
new file mode 100644
index 0000000..10509bf
--- /dev/null
+++ b/gdk/broadway/gdkselection-broadway.c
@@ -0,0 +1,891 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkselection.h"
+
+#include "gdkx.h"
+#include "gdkproperty.h"
+#include "gdkprivate.h"
+#include "gdkprivate-broadway.h"
+#include "gdkdisplay-broadway.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <string.h>
+
+
+typedef struct _OwnerInfo OwnerInfo;
+
+struct _OwnerInfo
+{
+  GdkAtom    selection;
+  GdkWindow *owner;
+  gulong     serial;
+};
+
+static GSList *owner_list;
+
+/* When a window is destroyed we check if it is the owner
+ * of any selections. This is somewhat inefficient, but
+ * owner_list is typically short, and it is a low memory,
+ * low code solution
+ */
+void
+_gdk_selection_window_destroyed (GdkWindow *window)
+{
+  GSList *tmp_list = owner_list;
+  while (tmp_list)
+    {
+      OwnerInfo *info = tmp_list->data;
+      tmp_list = tmp_list->next;
+      
+      if (info->owner == window)
+	{
+	  owner_list = g_slist_remove (owner_list, info);
+	  g_free (info);
+	}
+    }
+}
+
+/* We only pass through those SelectionClear events that actually
+ * reflect changes to the selection owner that we didn't make ourself.
+ */
+gboolean
+_gdk_selection_filter_clear_event (XSelectionClearEvent *event)
+{
+  GSList *tmp_list = owner_list;
+  GdkDisplay *display = gdk_x11_lookup_xdisplay (event->display);
+  
+  while (tmp_list)
+    {
+      OwnerInfo *info = tmp_list->data;
+
+      if (gdk_window_get_display (info->owner) == display &&
+	  info->selection == gdk_x11_xatom_to_atom_for_display (display, event->selection))
+	{
+	  if ((GDK_DRAWABLE_XID (info->owner) == event->window &&
+	       event->serial >= info->serial))
+	    {
+	      owner_list = g_slist_remove (owner_list, info);
+	      g_free (info);
+	      return TRUE;
+	    }
+	  else
+	    return FALSE;
+	}
+      tmp_list = tmp_list->next;
+    }
+
+  return FALSE;
+}
+/**
+ * gdk_selection_owner_set_for_display:
+ * @display: the #GdkDisplay.
+ * @owner: a #GdkWindow or %NULL to indicate that the owner for
+ *         the given should be unset.
+ * @selection: an atom identifying a selection.
+ * @time_: timestamp to use when setting the selection. 
+ *         If this is older than the timestamp given last time the owner was 
+ *         set for the given selection, the request will be ignored.
+ * @send_event: if %TRUE, and the new owner is different from the current
+ *              owner, the current owner will be sent a SelectionClear event.
+ *
+ * Sets the #GdkWindow @owner as the current owner of the selection @selection.
+ * 
+ * Returns: %TRUE if the selection owner was successfully changed to owner,
+ *	    otherwise %FALSE. 
+ *
+ * Since: 2.2
+ */
+gboolean
+gdk_selection_owner_set_for_display (GdkDisplay *display,
+				     GdkWindow  *owner,
+				     GdkAtom     selection,
+				     guint32     time, 
+				     gboolean    send_event)
+{
+  Display *xdisplay;
+  Window xwindow;
+  Atom xselection;
+  GSList *tmp_list;
+  OwnerInfo *info;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+  g_return_val_if_fail (selection != GDK_NONE, FALSE);
+
+  if (display->closed)
+    return FALSE;
+
+  if (owner) 
+    {
+      if (GDK_WINDOW_DESTROYED (owner) || !GDK_WINDOW_IS_X11 (owner))
+	return FALSE;
+      
+      gdk_window_ensure_native (owner);
+      xdisplay = GDK_WINDOW_XDISPLAY (owner);
+      xwindow = GDK_WINDOW_XID (owner);
+    }
+  else 
+    {
+      xdisplay = GDK_DISPLAY_XDISPLAY (display);
+      xwindow = None;
+    }
+  
+  xselection = gdk_x11_atom_to_xatom_for_display (display, selection);
+
+  tmp_list = owner_list;
+  while (tmp_list)
+    {
+      info = tmp_list->data;
+      if (info->selection == selection) 
+	{
+	  owner_list = g_slist_remove (owner_list, info);
+	  g_free (info);
+	  break;
+	}
+      tmp_list = tmp_list->next;
+    }
+
+  if (owner)
+    {
+      info = g_new (OwnerInfo, 1);
+      info->owner = owner;
+      info->serial = NextRequest (GDK_WINDOW_XDISPLAY (owner));
+      info->selection = selection;
+
+      owner_list = g_slist_prepend (owner_list, info);
+    }
+
+  XSetSelectionOwner (xdisplay, xselection, xwindow, time);
+
+  return (XGetSelectionOwner (xdisplay, xselection) == xwindow);
+}
+
+/**
+ * gdk_selection_owner_get_for_display:
+ * @display: a #GdkDisplay.
+ * @selection: an atom indentifying a selection.
+ *
+ * Determine the owner of the given selection.
+ *
+ * Note that the return value may be owned by a different 
+ * process if a foreign window was previously created for that
+ * window, but a new foreign window will never be created by this call. 
+ *
+ * Returns: if there is a selection owner for this window, and it is a 
+ *    window known to the current process, the #GdkWindow that owns the 
+ *    selection, otherwise %NULL.
+ *
+ * Since: 2.2
+ */ 
+GdkWindow *
+gdk_selection_owner_get_for_display (GdkDisplay *display,
+				     GdkAtom     selection)
+{
+  Window xwindow;
+  
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (selection != GDK_NONE, NULL);
+  
+  if (display->closed)
+    return NULL;
+  
+  xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
+				gdk_x11_atom_to_xatom_for_display (display, 
+								   selection));
+  if (xwindow == None)
+    return NULL;
+
+  return gdk_window_lookup_for_display (display, xwindow);
+}
+
+void
+gdk_selection_convert (GdkWindow *requestor,
+		       GdkAtom    selection,
+		       GdkAtom    target,
+		       guint32    time)
+{
+  GdkDisplay *display;
+
+  g_return_if_fail (selection != GDK_NONE);
+
+  if (GDK_WINDOW_DESTROYED (requestor) || !GDK_WINDOW_IS_X11 (requestor))
+    return;
+
+  gdk_window_ensure_native (requestor);
+  display = GDK_WINDOW_DISPLAY (requestor);
+
+  XConvertSelection (GDK_WINDOW_XDISPLAY (requestor),
+		     gdk_x11_atom_to_xatom_for_display (display, selection),
+		     gdk_x11_atom_to_xatom_for_display (display, target),
+		     gdk_x11_atom_to_xatom_for_display (display, _gdk_selection_property), 
+		     GDK_WINDOW_XID (requestor), time);
+}
+
+/**
+ * gdk_selection_property_get:
+ * @requestor: the window on which the data is stored
+ * @data: location to store a pointer to the retrieved data.
+       If the retrieval failed, %NULL we be stored here, otherwise, it
+       will be non-%NULL and the returned data should be freed with g_free()
+       when you are finished using it. The length of the
+       allocated memory is one more than the length
+       of the returned data, and the final byte will always
+       be zero, to ensure nul-termination of strings.
+ * @prop_type: location to store the type of the property.
+ * @prop_format: location to store the format of the property.
+ * 
+ * Retrieves selection data that was stored by the selection
+ * data in response to a call to gdk_selection_convert(). This function
+ * will not be used by applications, who should use the #GtkClipboard
+ * API instead.
+ * 
+ * Return value: the length of the retrieved data.
+ **/
+gint
+gdk_selection_property_get (GdkWindow  *requestor,
+			    guchar    **data,
+			    GdkAtom    *ret_type,
+			    gint       *ret_format)
+{
+  gulong nitems;
+  gulong nbytes;
+  gulong length = 0;		/* Quiet GCC */
+  Atom prop_type;
+  gint prop_format;
+  guchar *t = NULL;
+  GdkDisplay *display; 
+
+  g_return_val_if_fail (requestor != NULL, 0);
+  g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
+  g_return_val_if_fail (GDK_WINDOW_IS_X11 (requestor), 0);
+  
+  display = GDK_WINDOW_DISPLAY (requestor);
+
+  if (GDK_WINDOW_DESTROYED (requestor) || !GDK_WINDOW_IS_X11 (requestor))
+    goto err;
+
+  t = NULL;
+
+  /* We can't delete the selection here, because it might be the INCR
+     protocol, in which case the client has to make sure they'll be
+     notified of PropertyChange events _before_ the property is deleted.
+     Otherwise there's no guarantee we'll win the race ... */
+  if (XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (requestor),
+			  GDK_DRAWABLE_XID (requestor),
+			  gdk_x11_atom_to_xatom_for_display (display, _gdk_selection_property),
+			  0, 0x1FFFFFFF /* MAXINT32 / 4 */, False, 
+			  AnyPropertyType, &prop_type, &prop_format,
+			  &nitems, &nbytes, &t) != Success)
+    goto err;
+    
+  if (prop_type != None)
+    {
+      if (ret_type)
+	*ret_type = gdk_x11_xatom_to_atom_for_display (display, prop_type);
+      if (ret_format)
+	*ret_format = prop_format;
+
+      if (prop_type == XA_ATOM ||
+	  prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
+	{
+	  Atom* atoms = (Atom*) t;
+	  GdkAtom* atoms_dest;
+	  gint num_atom, i;
+
+	  if (prop_format != 32)
+	    goto err;
+	  
+	  num_atom = nitems;
+	  length = sizeof (GdkAtom) * num_atom + 1;
+
+	  if (data)
+	    {
+	      *data = g_malloc (length);
+	      (*data)[length - 1] = '\0';
+	      atoms_dest = (GdkAtom *)(*data);
+	  
+	      for (i=0; i < num_atom; i++)
+		atoms_dest[i] = gdk_x11_xatom_to_atom_for_display (display, atoms[i]);
+	    }
+	}
+      else
+	{
+	  switch (prop_format)
+	    {
+	    case 8:
+	      length = nitems;
+	      break;
+	    case 16:
+	      length = sizeof(short) * nitems;
+	      break;
+	    case 32:
+	      length = sizeof(long) * nitems;
+	      break;
+	    default:
+	      g_assert_not_reached ();
+	      break;
+	    }
+	  
+	  /* Add on an extra byte to handle null termination.  X guarantees
+	     that t will be 1 longer than nitems and null terminated */
+	  length += 1;
+
+	  if (data)
+	    *data = g_memdup (t, length);
+	}
+      
+      if (t)
+	XFree (t);
+      
+      return length - 1;
+    }
+
+ err:
+  if (ret_type)
+    *ret_type = GDK_NONE;
+  if (ret_format)
+    *ret_format = 0;
+  if (data)
+    *data = NULL;
+  
+  return 0;
+}
+
+/**
+ * gdk_selection_send_notify_for_display:
+ * @display: the #GdkDisplay where @requestor is realized
+ * @requestor: window to which to deliver response.
+ * @selection: selection that was requested.
+ * @target: target that was selected.
+ * @property: property in which the selection owner stored the data,
+ *            or %GDK_NONE to indicate that the request was rejected.
+ * @time_: timestamp. 
+ *
+ * Send a response to SelectionRequest event.
+ *
+ * Since: 2.2
+ **/
+void
+gdk_selection_send_notify_for_display (GdkDisplay       *display,
+				       GdkNativeWindow  requestor,
+				       GdkAtom          selection,
+				       GdkAtom          target,
+				       GdkAtom          property, 
+				       guint32          time)
+{
+  XSelectionEvent xevent;
+  
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+  
+  xevent.type = SelectionNotify;
+  xevent.serial = 0;
+  xevent.send_event = True;
+  xevent.requestor = requestor;
+  xevent.selection = gdk_x11_atom_to_xatom_for_display (display, selection);
+  xevent.target = gdk_x11_atom_to_xatom_for_display (display, target);
+  if (property == GDK_NONE)
+    xevent.property = None;
+  else
+    xevent.property = gdk_x11_atom_to_xatom_for_display (display, property);
+  xevent.time = time;
+
+  _gdk_send_xevent (display, requestor, False, NoEventMask, (XEvent*) & xevent);
+}
+
+/**
+ * gdk_text_property_to_text_list_for_display:
+ * @display: The #GdkDisplay where the encoding is defined.
+ * @encoding: an atom representing the encoding. The most 
+ *    common values for this are STRING, or COMPOUND_TEXT. 
+ *    This is value used as the type for the property.
+ * @format: the format of the property.
+ * @text: The text data.
+ * @length: The number of items to transform.
+ * @list: location to store a terminated array of strings in 
+ *    the encoding of the current locale. This array should be 
+ *    freed using gdk_free_text_list().
+ *
+ * Convert a text string from the encoding as it is stored 
+ * in a property into an array of strings in the encoding of
+ * the current locale. (The elements of the array represent the
+ * nul-separated elements of the original text string.)
+ *
+ * Returns: the number of strings stored in list, or 0, 
+ * if the conversion failed. 
+ *
+ * Since: 2.2
+ */
+gint
+gdk_text_property_to_text_list_for_display (GdkDisplay   *display,
+					    GdkAtom       encoding,
+					    gint          format, 
+					    const guchar *text,
+					    gint          length,
+					    gchar      ***list)
+{
+  XTextProperty property;
+  gint count = 0;
+  gint res;
+  gchar **local_list;
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
+
+  if (list)
+    *list = NULL;
+
+  if (display->closed)
+    return 0;
+
+  property.value = (guchar *)text;
+  property.encoding = gdk_x11_atom_to_xatom_for_display (display, encoding);
+  property.format = format;
+  property.nitems = length;
+  res = XmbTextPropertyToTextList (GDK_DISPLAY_XDISPLAY (display), &property, 
+				   &local_list, &count);
+  if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound)
+    return 0;
+  else
+    {
+      if (list)
+	*list = local_list;
+      else
+	XFreeStringList (local_list);
+      
+      return count;
+    }
+}
+
+void
+gdk_free_text_list (gchar **list)
+{
+  g_return_if_fail (list != NULL);
+
+  XFreeStringList (list);
+}
+
+static gint
+make_list (const gchar  *text,
+	   gint          length,
+	   gboolean      latin1,
+	   gchar      ***list)
+{
+  GSList *strings = NULL;
+  gint n_strings = 0;
+  gint i;
+  const gchar *p = text;
+  const gchar *q;
+  GSList *tmp_list;
+  GError *error = NULL;
+
+  while (p < text + length)
+    {
+      gchar *str;
+      
+      q = p;
+      while (*q && q < text + length)
+	q++;
+
+      if (latin1)
+	{
+	  str = g_convert (p, q - p,
+			   "UTF-8", "ISO-8859-1",
+			   NULL, NULL, &error);
+
+	  if (!str)
+	    {
+	      g_warning ("Error converting selection from STRING: %s",
+			 error->message);
+	      g_error_free (error);
+	    }
+	}
+      else
+	{
+	  str = g_strndup (p, q - p);
+	  if (!g_utf8_validate (str, -1, NULL))
+	    {
+	      g_warning ("Error converting selection from UTF8_STRING");
+	      g_free (str);
+	      str = NULL;
+	    }
+	}
+
+      if (str)
+	{
+	  strings = g_slist_prepend (strings, str);
+	  n_strings++;
+	}
+
+      p = q + 1;
+    }
+
+  if (list)
+    {
+      *list = g_new (gchar *, n_strings + 1);
+      (*list)[n_strings] = NULL;
+    }
+     
+  i = n_strings;
+  tmp_list = strings;
+  while (tmp_list)
+    {
+      if (list)
+	(*list)[--i] = tmp_list->data;
+      else
+	g_free (tmp_list->data);
+      
+      tmp_list = tmp_list->next;
+    }
+  
+  g_slist_free (strings);
+
+  return n_strings;
+}
+
+/**
+ * gdk_text_property_to_utf8_list_for_display:
+ * @display:  a #GdkDisplay
+ * @encoding: an atom representing the encoding of the text
+ * @format:   the format of the property
+ * @text:     the text to convert
+ * @length:   the length of @text, in bytes
+ * @list:     location to store the list of strings or %NULL. The
+ *            list should be freed with g_strfreev().
+ * 
+ * Converts a text property in the given encoding to
+ * a list of UTF-8 strings. 
+ * 
+ * Return value: the number of strings in the resulting
+ *               list.
+ *
+ * Since: 2.2
+ **/
+gint 
+gdk_text_property_to_utf8_list_for_display (GdkDisplay    *display,
+					    GdkAtom        encoding,
+					    gint           format,
+					    const guchar  *text,
+					    gint           length,
+					    gchar       ***list)
+{
+  g_return_val_if_fail (text != NULL, 0);
+  g_return_val_if_fail (length >= 0, 0);
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
+  
+  if (encoding == GDK_TARGET_STRING)
+    {
+      return make_list ((gchar *)text, length, TRUE, list);
+    }
+  else if (encoding == gdk_atom_intern_static_string ("UTF8_STRING"))
+    {
+      return make_list ((gchar *)text, length, FALSE, list);
+    }
+  else
+    {
+      gchar **local_list;
+      gint local_count;
+      gint i;
+      const gchar *charset = NULL;
+      gboolean need_conversion = !g_get_charset (&charset);
+      gint count = 0;
+      GError *error = NULL;
+      
+      /* Probably COMPOUND text, we fall back to Xlib routines
+       */
+      local_count = gdk_text_property_to_text_list_for_display (display,
+								encoding,
+								format, 
+								text,
+								length,
+								&local_list);
+      if (list)
+	*list = g_new (gchar *, local_count + 1);
+      
+      for (i=0; i<local_count; i++)
+	{
+	  /* list contains stuff in our default encoding
+	   */
+	  if (need_conversion)
+	    {
+	      gchar *utf = g_convert (local_list[i], -1,
+				      "UTF-8", charset,
+				      NULL, NULL, &error);
+	      if (utf)
+		{
+		  if (list)
+		    (*list)[count++] = utf;
+		  else
+		    g_free (utf);
+		}
+	      else
+		{
+		  g_warning ("Error converting to UTF-8 from '%s': %s",
+			     charset, error->message);
+		  g_error_free (error);
+		  error = NULL;
+		}
+	    }
+	  else
+	    {
+	      if (list)
+		{
+		  if (g_utf8_validate (local_list[i], -1, NULL))
+		    (*list)[count++] = g_strdup (local_list[i]);
+		  else
+		    g_warning ("Error converting selection");
+		}
+	    }
+	}
+
+      if (local_count)
+	gdk_free_text_list (local_list);
+      
+      if (list)
+	(*list)[count] = NULL;
+
+      return count;
+    }
+}
+
+/**
+ * gdk_string_to_compound_text_for_display:
+ * @display:  the #GdkDisplay where the encoding is defined.
+ * @str:      a nul-terminated string.
+ * @encoding: location to store the encoding atom 
+ *	      (to be used as the type for the property).
+ * @format:   location to store the format of the property
+ * @ctext:    location to store newly allocated data for the property.
+ * @length:   the length of @text, in bytes
+ * 
+ * Convert a string from the encoding of the current 
+ * locale into a form suitable for storing in a window property.
+ * 
+ * Returns: 0 upon success, non-zero upon failure. 
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_string_to_compound_text_for_display (GdkDisplay  *display,
+					 const gchar *str,
+					 GdkAtom     *encoding,
+					 gint        *format,
+					 guchar     **ctext,
+					 gint        *length)
+{
+  gint res;
+  XTextProperty property;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
+
+  if (display->closed)
+    res = XLocaleNotSupported;
+  else
+    res = XmbTextListToTextProperty (GDK_DISPLAY_XDISPLAY (display), 
+				     (char **)&str, 1, XCompoundTextStyle,
+				     &property);
+  if (res != Success)
+    {
+      property.encoding = None;
+      property.format = None;
+      property.value = NULL;
+      property.nitems = 0;
+    }
+
+  if (encoding)
+    *encoding = gdk_x11_xatom_to_atom_for_display (display, property.encoding);
+  if (format)
+    *format = property.format;
+  if (ctext)
+    *ctext = property.value;
+  if (length)
+    *length = property.nitems;
+
+  return res;
+}
+
+/* The specifications for COMPOUND_TEXT and STRING specify that C0 and
+ * C1 are not allowed except for \n and \t, however the X conversions
+ * routines for COMPOUND_TEXT only enforce this in one direction,
+ * causing cut-and-paste of \r and \r\n separated text to fail.
+ * This routine strips out all non-allowed C0 and C1 characters
+ * from the input string and also canonicalizes \r, and \r\n to \n
+ */
+static gchar * 
+sanitize_utf8 (const gchar *src,
+	       gboolean return_latin1)
+{
+  gint len = strlen (src);
+  GString *result = g_string_sized_new (len);
+  const gchar *p = src;
+
+  while (*p)
+    {
+      if (*p == '\r')
+	{
+	  p++;
+	  if (*p == '\n')
+	    p++;
+
+	  g_string_append_c (result, '\n');
+	}
+      else
+	{
+	  gunichar ch = g_utf8_get_char (p);
+	  
+	  if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
+	    {
+	      if (return_latin1)
+		{
+		  if (ch <= 0xff)
+		    g_string_append_c (result, ch);
+		  else
+		    g_string_append_printf (result,
+					    ch < 0x10000 ? "\\u%04x" : "\\U%08x",
+					    ch);
+		}
+	      else
+		{
+		  char buf[7];
+		  gint buflen;
+		  
+		  buflen = g_unichar_to_utf8 (ch, buf);
+		  g_string_append_len (result, buf, buflen);
+		}
+	    }
+
+	  p = g_utf8_next_char (p);
+	}
+    }
+
+  return g_string_free (result, FALSE);
+}
+
+/**
+ * gdk_utf8_to_string_target:
+ * @str: a UTF-8 string
+ * 
+ * Converts an UTF-8 string into the best possible representation
+ * as a STRING. The representation of characters not in STRING
+ * is not specified; it may be as pseudo-escape sequences
+ * \x{ABCD}, or it may be in some other form of approximation.
+ * 
+ * Return value: the newly-allocated string, or %NULL if the
+ *               conversion failed. (It should not fail for
+ *               any properly formed UTF-8 string unless system
+ *               limits like memory or file descriptors are exceeded.)
+ **/
+gchar *
+gdk_utf8_to_string_target (const gchar *str)
+{
+  return sanitize_utf8 (str, TRUE);
+}
+
+/**
+ * gdk_utf8_to_compound_text_for_display:
+ * @display:  a #GdkDisplay
+ * @str:      a UTF-8 string
+ * @encoding: location to store resulting encoding
+ * @format:   location to store format of the result
+ * @ctext:    location to store the data of the result
+ * @length:   location to store the length of the data
+ *            stored in @ctext
+ * 
+ * Converts from UTF-8 to compound text. 
+ * 
+ * Return value: %TRUE if the conversion succeeded, otherwise
+ *               %FALSE.
+ *
+ * Since: 2.2
+ **/
+gboolean
+gdk_utf8_to_compound_text_for_display (GdkDisplay  *display,
+				       const gchar *str,
+				       GdkAtom     *encoding,
+				       gint        *format,
+				       guchar     **ctext,
+				       gint        *length)
+{
+  gboolean need_conversion;
+  const gchar *charset;
+  gchar *locale_str, *tmp_str;
+  GError *error = NULL;
+  gboolean result;
+
+  g_return_val_if_fail (str != NULL, FALSE);
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  need_conversion = !g_get_charset (&charset);
+
+  tmp_str = sanitize_utf8 (str, FALSE);
+
+  if (need_conversion)
+    {
+      locale_str = g_convert (tmp_str, -1,
+			      charset, "UTF-8",
+			      NULL, NULL, &error);
+      g_free (tmp_str);
+
+      if (!locale_str)
+	{
+	  if (!(error->domain = G_CONVERT_ERROR &&
+		error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
+	    {
+	      g_warning ("Error converting from UTF-8 to '%s': %s",
+			 charset, error->message);
+	    }
+	  g_error_free (error);
+
+	  if (encoding)
+	    *encoding = None;
+	  if (format)
+	    *format = None;
+	  if (ctext)
+	    *ctext = NULL;
+	  if (length)
+	    *length = 0;
+
+	  return FALSE;
+	}
+    }
+  else
+    locale_str = tmp_str;
+    
+  result = gdk_string_to_compound_text_for_display (display, locale_str,
+						    encoding, format, 
+						    ctext, length);
+  result = (result == Success? TRUE : FALSE);
+  
+  g_free (locale_str);
+
+  return result;
+}
+
+void gdk_free_compound_text (guchar *ctext)
+{
+  if (ctext)
+    XFree (ctext);
+}
diff --git a/gdk/broadway/gdksettings.c b/gdk/broadway/gdksettings.c
new file mode 100644
index 0000000..0e98816
--- /dev/null
+++ b/gdk/broadway/gdksettings.c
@@ -0,0 +1,128 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+
+#define GDK_SETTINGS_N_ELEMENTS()       G_N_ELEMENTS (gdk_settings_map)
+#define GDK_SETTINGS_X_NAME(nth)        (gdk_settings_names + gdk_settings_map[nth].xsettings_offset)
+#define GDK_SETTINGS_GDK_NAME(nth)      (gdk_settings_names + gdk_settings_map[nth].gdk_offset)
+
+static const char gdk_settings_names[] =
+  "Net/DoubleClickTime\0"     "gtk-double-click-time\0"
+  "Net/DoubleClickDistance\0" "gtk-double-click-distance\0"
+  "Net/DndDragThreshold\0"    "gtk-dnd-drag-threshold\0"
+  "Net/CursorBlink\0"         "gtk-cursor-blink\0"
+  "Net/CursorBlinkTime\0"     "gtk-cursor-blink-time\0"
+  "Net/ThemeName\0"           "gtk-theme-name\0"
+  "Net/IconThemeName\0"       "gtk-icon-theme-name\0"
+  "Gtk/CanChangeAccels\0"     "gtk-can-change-accels\0"
+  "Gtk/ColorPalette\0"        "gtk-color-palette\0"
+  "Gtk/FontName\0"            "gtk-font-name\0"
+  "Gtk/IconSizes\0"           "gtk-icon-sizes\0"
+  "Gtk/KeyThemeName\0"        "gtk-key-theme-name\0"
+  "Gtk/ToolbarStyle\0"        "gtk-toolbar-style\0"
+  "Gtk/ToolbarIconSize\0"     "gtk-toolbar-icon-size\0"
+  "Gtk/IMPreeditStyle\0"      "gtk-im-preedit-style\0"
+  "Gtk/IMStatusStyle\0"       "gtk-im-status-style\0"
+  "Gtk/Modules\0"             "gtk-modules\0"
+  "Gtk/FileChooserBackend\0"  "gtk-file-chooser-backend\0"
+  "Gtk/ButtonImages\0"        "gtk-button-images\0"
+  "Gtk/MenuImages\0"          "gtk-menu-images\0"
+  "Gtk/MenuBarAccel\0"        "gtk-menu-bar-accel\0"
+  "Gtk/CursorThemeName\0"     "gtk-cursor-theme-name\0"
+  "Gtk/CursorThemeSize\0"     "gtk-cursor-theme-size\0"
+  "Gtk/ShowInputMethodMenu\0" "gtk-show-input-method-menu\0"
+  "Gtk/ShowUnicodeMenu\0"     "gtk-show-unicode-menu\0"
+  "Gtk/TimeoutInitial\0"      "gtk-timeout-initial\0"
+  "Gtk/TimeoutRepeat\0"       "gtk-timeout-repeat\0"
+  "Gtk/ColorScheme\0"         "gtk-color-scheme\0"
+  "Gtk/EnableAnimations\0"    "gtk-enable-animations\0"
+  "Xft/Antialias\0"           "gtk-xft-antialias\0"
+  "Xft/Hinting\0"             "gtk-xft-hinting\0"
+  "Xft/HintStyle\0"           "gtk-xft-hintstyle\0"
+  "Xft/RGBA\0"                "gtk-xft-rgba\0"
+  "Xft/DPI\0"                 "gtk-xft-dpi\0"
+  "Net/FallbackIconTheme\0"   "gtk-fallback-icon-theme\0"
+  "Gtk/TouchscreenMode\0"     "gtk-touchscreen-mode\0"
+  "Gtk/EnableAccels\0"        "gtk-enable-accels\0"
+  "Gtk/EnableMnemonics\0"     "gtk-enable-mnemonics\0"
+  "Gtk/ScrolledWindowPlacement\0" "gtk-scrolled-window-placement\0"
+  "Gtk/IMModule\0"            "gtk-im-module\0"
+  "Fontconfig/Timestamp\0"    "gtk-fontconfig-timestamp\0"
+  "Net/SoundThemeName\0"      "gtk-sound-theme-name\0"
+  "Net/EnableInputFeedbackSounds\0" "gtk-enable-input-feedback-sounds\0"
+  "Net/EnableEventSounds\0"  "gtk-enable-event-sounds\0";
+
+
+static const struct
+{
+  gint xsettings_offset;
+  gint gdk_offset;
+} gdk_settings_map[] = {
+  {    0,   20 },
+  {   42,   66 },
+  {   92,  113 },
+  {  136,  152 },
+  {  169,  189 },
+  {  211,  225 },
+  {  240,  258 },
+  {  278,  298 },
+  {  320,  337 },
+  {  355,  368 },
+  {  382,  396 },
+  {  411,  428 },
+  {  447,  464 },
+  {  482,  502 },
+  {  524,  543 },
+  {  564,  582 },
+  {  602,  614 },
+  {  626,  649 },
+  {  674,  691 },
+  {  709,  724 },
+  {  740,  757 },
+  {  776,  796 },
+  {  818,  838 },
+  {  860,  884 },
+  {  911,  931 },
+  {  953,  972 },
+  {  992, 1010 },
+  { 1029, 1045 },
+  { 1062, 1083 },
+  { 1105, 1119 },
+  { 1137, 1149 },
+  { 1165, 1179 },
+  { 1197, 1206 },
+  { 1219, 1227 },
+  { 1239, 1261 },
+  { 1285, 1305 },
+  { 1326, 1343 },
+  { 1361, 1381 },
+  { 1402, 1430 },
+  { 1460, 1473 },
+  { 1487, 1508 },
+  { 1533, 1552 },
+  { 1573, 1603 },
+  { 1636, 1658 }
+};
diff --git a/gdk/broadway/gdkspawn-broadway.c b/gdk/broadway/gdkspawn-broadway.c
new file mode 100644
index 0000000..7f97b4e
--- /dev/null
+++ b/gdk/broadway/gdkspawn-broadway.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ *
+ * Authors: Mark McLoughlin <mark skynet ie>
+ */
+
+#include "config.h"
+
+#include "gdkspawn.h"
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+typedef struct {
+  char *display;
+  GSpawnChildSetupFunc child_setup;
+  gpointer user_data;
+} UserChildSetup;
+
+/*
+ * Set the DISPLAY variable, and then call the user-specified child setup
+ * function.  This is required so that applications can use gdk_spawn_* and 
+ * call putenv() in their child_setup functions.
+ */
+static void
+set_environment (gpointer user_data)
+{
+  UserChildSetup *setup = user_data;
+  
+  g_setenv ("DISPLAY", setup->display, TRUE);
+  
+  if (setup->child_setup)
+    setup->child_setup (setup->user_data);
+}
+
+/**
+ * gdk_spawn_on_screen:
+ * @screen: a #GdkScreen
+ * @working_directory: child's current working directory, or %NULL to 
+ *   inherit parent's
+ * @argv: child's argument vector
+ * @envp: child's environment, or %NULL to inherit parent's
+ * @flags: flags from #GSpawnFlags
+ * @child_setup: function to run in the child just before exec()
+ * @user_data: user data for @child_setup
+ * @child_pid: return location for child process ID, or %NULL
+ * @error: return location for error
+ *
+ * Like g_spawn_async(), except the child process is spawned in such
+ * an environment that on calling gdk_display_open() it would be
+ * returned a #GdkDisplay with @screen as the default screen.
+ *
+ * This is useful for applications which wish to launch an application
+ * on a specific screen.
+ *
+ * Return value: %TRUE on success, %FALSE if error is set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_spawn_on_screen (GdkScreen             *screen,
+		     const gchar           *working_directory,
+		     gchar                **argv,
+		     gchar                **envp,
+		     GSpawnFlags            flags,
+		     GSpawnChildSetupFunc   child_setup,
+		     gpointer               user_data,
+		     GPid                  *child_pid,
+		     GError               **error)
+{
+  UserChildSetup setup_data;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+  setup_data.display = gdk_screen_make_display_name (screen);
+  setup_data.child_setup = child_setup;
+  setup_data.user_data = user_data;
+
+  return g_spawn_async (working_directory,
+			  argv,
+			  envp,
+			  flags,
+			  set_environment,
+			  &setup_data,
+			  child_pid,
+			  error);
+}
+
+/**
+ * gdk_spawn_on_screen_with_pipes:
+ * @screen: a #GdkScreen
+ * @working_directory: child's current working directory, or %NULL to 
+ *   inherit parent's
+ * @argv: child's argument vector
+ * @envp: child's environment, or %NULL to inherit parent's
+ * @flags: flags from #GSpawnFlags
+ * @child_setup: function to run in the child just before exec()
+ * @user_data: user data for @child_setup
+ * @child_pid: return location for child process ID, or %NULL
+ * @standard_input: return location for file descriptor to write to 
+ *   child's stdin, or %NULL
+ * @standard_output: return location for file descriptor to read child's 
+ *   stdout, or %NULL
+ * @standard_error: return location for file descriptor to read child's 
+ *   stderr, or %NULL
+ * @error: return location for error
+ *
+ * Like g_spawn_async_with_pipes(), except the child process is
+ * spawned in such an environment that on calling gdk_display_open()
+ * it would be returned a #GdkDisplay with @screen as the default
+ * screen.
+ *
+ * This is useful for applications which wish to launch an application
+ * on a specific screen.
+ *
+ * Return value: %TRUE on success, %FALSE if an error was set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_spawn_on_screen_with_pipes (GdkScreen            *screen,
+				const gchar          *working_directory,
+				gchar               **argv,
+				gchar               **envp,
+				GSpawnFlags           flags,
+				GSpawnChildSetupFunc  child_setup,
+				gpointer              user_data,
+				GPid                 *child_pid,
+				gint                 *standard_input,
+				gint                 *standard_output,
+				gint                 *standard_error,
+				GError              **error)
+{
+  UserChildSetup setup_data;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+  setup_data.display = gdk_screen_make_display_name (screen);
+  setup_data.child_setup = child_setup;
+  setup_data.user_data = user_data;
+
+  return g_spawn_async_with_pipes (working_directory,
+				     argv,
+				     envp,
+				     flags,
+				     set_environment,
+				     &setup_data,
+				     child_pid,
+				     standard_input,
+				     standard_output,
+				     standard_error,
+				     error);
+
+}
+
+/**
+ * gdk_spawn_command_line_on_screen:
+ * @screen: a #GdkScreen
+ * @command_line: a command line
+ * @error: return location for errors
+ *
+ * Like g_spawn_command_line_async(), except the child process is
+ * spawned in such an environment that on calling gdk_display_open()
+ * it would be returned a #GdkDisplay with @screen as the default
+ * screen.
+ *
+ * This is useful for applications which wish to launch an application
+ * on a specific screen.
+ *
+ * Return value: %TRUE on success, %FALSE if error is set.
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_spawn_command_line_on_screen (GdkScreen    *screen,
+				  const gchar  *command_line,
+				  GError      **error)
+{
+  gchar    **argv = NULL;
+  gboolean   retval;
+
+  g_return_val_if_fail (command_line != NULL, FALSE);
+
+  if (!g_shell_parse_argv (command_line,
+			   NULL, &argv,
+			   error))
+    return FALSE;
+
+  retval = gdk_spawn_on_screen (screen,
+				NULL, argv, NULL,
+				G_SPAWN_SEARCH_PATH,
+				NULL, NULL, NULL,
+				error);
+  g_strfreev (argv);
+
+  return retval;
+}
diff --git a/gdk/broadway/gdktestutils-broadway.c b/gdk/broadway/gdktestutils-broadway.c
new file mode 100644
index 0000000..d4d47fb
--- /dev/null
+++ b/gdk/broadway/gdktestutils-broadway.c
@@ -0,0 +1,254 @@
+/* Gtk+ testing utilities
+ * Copyright (C) 2007 Imendio AB
+ * Authors: Tim Janik
+ *
+ * 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 "config.h"
+
+#include "gdktestutils.h"
+
+#include "gdkkeysyms.h"
+#include "gdkx.h"
+
+#include <X11/Xlib.h>
+
+/**
+ * gdk_test_render_sync:
+ * @window: a mapped #GdkWindow
+ *
+ * This function retrieves a pixel from @window to force the windowing
+ * system to carry out any pending rendering commands.
+ * This function is intended to be used to syncronize with rendering
+ * pipelines, to benchmark windowing system rendering operations.
+ *
+ * Since: 2.14
+ **/
+void
+gdk_test_render_sync (GdkWindow *window)
+{
+  Display *display = gdk_x11_drawable_get_xdisplay (window);
+  XImage *ximage;
+
+  /* syncronize to X drawing queue, see:
+   * http://mail.gnome.org/archives/gtk-devel-list/2006-October/msg00103.html
+   */
+  ximage = XGetImage (display, DefaultRootWindow (display),
+	     	      0, 0, 1, 1, AllPlanes, ZPixmap);
+  if (ximage != NULL)
+    XDestroyImage (ximage);
+}
+
+/**
+ * gdk_test_simulate_key
+ * @window: a #GdkWindow to simulate a key event for.
+ * @x:      x coordinate within @window for the key event.
+ * @y:      y coordinate within @window for the key event.
+ * @keyval: A GDK keyboard value.
+ * @modifiers: Keyboard modifiers the event is setup with.
+ * @key_pressrelease: either %GDK_KEY_PRESS or %GDK_KEY_RELEASE
+ *
+ * This function is intended to be used in GTK+ test programs.
+ * If (@x,@y) are > (-1,-1), it will warp the mouse pointer to
+ * the given (@x,@y) corrdinates within @window and simulate a
+ * key press or release event.
+ *
+ * When the mouse pointer is warped to the target location, use
+ * of this function outside of test programs that run in their
+ * own virtual windowing system (e.g. Xvfb) is not recommended.
+ * If (@x,@y) are passed as (-1,-1), the mouse pointer will not
+ * be warped and @window origin will be used as mouse pointer
+ * location for the event.
+ *
+ * Also, gtk_test_simulate_key() is a fairly low level function,
+ * for most testing purposes, gtk_test_widget_send_key() is the
+ * right function to call which will generate a key press event
+ * followed by its accompanying key release event.
+ *
+ * Returns: whether all actions neccessary for a key event simulation 
+ *     were carried out successfully.
+ *
+ * Since: 2.14
+ **/
+gboolean
+gdk_test_simulate_key (GdkWindow      *window,
+                       gint            x,
+                       gint            y,
+                       guint           keyval,
+                       GdkModifierType modifiers,
+                       GdkEventType    key_pressrelease)
+{
+  GdkScreen *screen;
+  GdkKeymapKey *keys = NULL;
+  GdkWindowObject *priv;
+  gboolean success;
+  gint n_keys = 0;
+  XKeyEvent xev = {
+    0,  /* type */
+    0,  /* serial */
+    1,  /* send_event */
+  };
+  g_return_val_if_fail (key_pressrelease == GDK_KEY_PRESS || key_pressrelease == GDK_KEY_RELEASE, FALSE);
+  g_return_val_if_fail (window != NULL, FALSE);
+  if (!GDK_WINDOW_IS_MAPPED (window))
+    return FALSE;
+
+  screen = gdk_window_get_screen (window);
+  priv = (GdkWindowObject *)window;
+
+  if (x < 0 && y < 0)
+    {
+      x = priv->width / 2;
+      y = priv->height / 2;
+    }
+
+  /* Convert to impl coordinates */
+  x = x + priv->abs_x;
+  y = y + priv->abs_y;
+
+  xev.type = key_pressrelease == GDK_KEY_PRESS ? KeyPress : KeyRelease;
+  xev.display = GDK_DRAWABLE_XDISPLAY (window);
+  xev.window = GDK_WINDOW_XID (window);
+  xev.root = RootWindow (xev.display, GDK_SCREEN_XNUMBER (screen));
+  xev.subwindow = 0;
+  xev.time = 0;
+  xev.x = MAX (x, 0);
+  xev.y = MAX (y, 0);
+  xev.x_root = 0;
+  xev.y_root = 0;
+  xev.state = modifiers;
+  xev.keycode = 0;
+  success = gdk_keymap_get_entries_for_keyval (gdk_keymap_get_for_display (gdk_window_get_display (window)), keyval, &keys, &n_keys);
+  success &= n_keys > 0;
+  if (success)
+    {
+      gint i;
+      for (i = 0; i < n_keys; i++)
+        if (keys[i].group == 0 && keys[i].level == 0)
+          {
+            xev.keycode = keys[i].keycode;
+            break;
+          }
+      if (i >= n_keys) /* no match for group==0 and level==0 */
+        xev.keycode = keys[0].keycode;
+    }
+  g_free (keys);
+  if (!success)
+    return FALSE;
+  gdk_error_trap_push ();
+  xev.same_screen = XTranslateCoordinates (xev.display, xev.window, xev.root,
+                                           xev.x, xev.y, &xev.x_root, &xev.y_root,
+                                           &xev.subwindow);
+  if (!xev.subwindow)
+    xev.subwindow = xev.window;
+  success &= xev.same_screen;
+  if (x >= 0 && y >= 0)
+    success &= 0 != XWarpPointer (xev.display, None, xev.window, 0, 0, 0, 0, xev.x, xev.y);
+  success &= 0 != XSendEvent (xev.display, xev.window, True, key_pressrelease == GDK_KEY_PRESS ? KeyPressMask : KeyReleaseMask, (XEvent*) &xev);
+  XSync (xev.display, False);
+  success &= 0 == gdk_error_trap_pop();
+  return success;
+}
+
+/**
+ * gdk_test_simulate_button
+ * @window: a #GdkWindow to simulate a button event for.
+ * @x:      x coordinate within @window for the button event.
+ * @y:      y coordinate within @window for the button event.
+ * @button: Number of the pointer button for the event, usually 1, 2 or 3.
+ * @modifiers: Keyboard modifiers the event is setup with.
+ * @button_pressrelease: either %GDK_BUTTON_PRESS or %GDK_BUTTON_RELEASE
+ *
+ * This function is intended to be used in GTK+ test programs.
+ * It will warp the mouse pointer to the given (@x,@y) corrdinates
+ * within @window and simulate a button press or release event.
+ * Because the mouse pointer needs to be warped to the target
+ * location, use of this function outside of test programs that
+ * run in their own virtual windowing system (e.g. Xvfb) is not
+ * recommended.
+ *
+ * Also, gtk_test_simulate_button() is a fairly low level function,
+ * for most testing purposes, gtk_test_widget_click() is the right
+ * function to call which will generate a button press event followed
+ * by its accompanying button release event.
+ *
+ * Returns: whether all actions neccessary for a button event simulation 
+ *     were carried out successfully.
+ *
+ * Since: 2.14
+ **/
+gboolean
+gdk_test_simulate_button (GdkWindow      *window,
+                          gint            x,
+                          gint            y,
+                          guint           button, /*1..3*/
+                          GdkModifierType modifiers,
+                          GdkEventType    button_pressrelease)
+{
+  GdkScreen *screen;
+  XButtonEvent xev = {
+    0,  /* type */
+    0,  /* serial */
+    1,  /* send_event */
+  };
+  gboolean success;
+  GdkWindowObject *priv;
+
+  g_return_val_if_fail (button_pressrelease == GDK_BUTTON_PRESS || button_pressrelease == GDK_BUTTON_RELEASE, FALSE);
+  g_return_val_if_fail (window != NULL, FALSE);
+
+  if (!GDK_WINDOW_IS_MAPPED (window))
+    return FALSE;
+
+  screen = gdk_window_get_screen (window);
+  priv = (GdkWindowObject *)window;
+
+  if (x < 0 && y < 0)
+    {
+      x = priv->width / 2;
+      y = priv->height / 2;
+    }
+
+  /* Convert to impl coordinates */
+  x = x + priv->abs_x;
+  y = y + priv->abs_y;
+
+  xev.type = button_pressrelease == GDK_BUTTON_PRESS ? ButtonPress : ButtonRelease;
+  xev.display = GDK_DRAWABLE_XDISPLAY (window);
+  xev.window = GDK_WINDOW_XID (window);
+  xev.root = RootWindow (xev.display, GDK_SCREEN_XNUMBER (screen));
+  xev.subwindow = 0;
+  xev.time = 0;
+  xev.x = x;
+  xev.y = y;
+  xev.x_root = 0;
+  xev.y_root = 0;
+  xev.state = modifiers;
+  xev.button = button;
+  gdk_error_trap_push ();
+  xev.same_screen = XTranslateCoordinates (xev.display, xev.window, xev.root,
+                                           xev.x, xev.y, &xev.x_root, &xev.y_root,
+                                           &xev.subwindow);
+  if (!xev.subwindow)
+    xev.subwindow = xev.window;
+  success = xev.same_screen;
+  success &= 0 != XWarpPointer (xev.display, None, xev.window, 0, 0, 0, 0, xev.x, xev.y);
+  success &= 0 != XSendEvent (xev.display, xev.window, True, button_pressrelease == GDK_BUTTON_PRESS ? ButtonPressMask : ButtonReleaseMask, (XEvent*) &xev);
+  XSync (xev.display, False);
+  success &= 0 == gdk_error_trap_pop();
+  return success;
+}
diff --git a/gdk/broadway/gdkvisual-broadway.c b/gdk/broadway/gdkvisual-broadway.c
new file mode 100644
index 0000000..350e8a2
--- /dev/null
+++ b/gdk/broadway/gdkvisual-broadway.c
@@ -0,0 +1,730 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkvisual.h"
+
+#include "gdkx.h"
+#include "gdkprivate-broadway.h"
+#include "gdkscreen-broadway.h"
+#include "gdkinternals.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+struct _GdkVisualPrivate
+{
+  Visual *xvisual;
+  GdkScreen *screen;
+  Colormap colormap;
+};
+
+struct _GdkVisualClass
+{
+  GObjectClass parent_class;
+};
+
+static void     gdk_visual_add            (GdkVisual *visual);
+static void     gdk_visual_decompose_mask (gulong     mask,
+					   gint      *shift,
+					   gint      *prec);
+static guint    gdk_visual_hash           (Visual    *key);
+static gboolean gdk_visual_equal          (Visual    *a,
+					   Visual    *b);
+
+
+#ifdef G_ENABLE_DEBUG
+
+static const gchar *const visual_names[] =
+{
+  "static gray",
+  "grayscale",
+  "static color",
+  "pseudo color",
+  "true color",
+  "direct color",
+};
+
+#endif /* G_ENABLE_DEBUG */
+
+G_DEFINE_TYPE (GdkVisual, gdk_visual, G_TYPE_OBJECT)
+
+static void
+gdk_visual_finalize (GObject *object)
+{
+  GdkVisualPrivate *priv = (GdkVisualPrivate *) object;
+
+  if (priv->colormap != None)
+    XFreeColormap (GDK_SCREEN_XDISPLAY (priv->screen),
+                   priv->colormap);
+
+  G_OBJECT_CLASS (gdk_visual_parent_class)->finalize (object);
+}
+
+static void
+gdk_visual_class_init (GdkVisualClass *visual_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (visual_class);
+
+  g_type_class_add_private (object_class, sizeof (GdkVisualPrivate));
+
+  object_class->finalize = gdk_visual_finalize;
+}
+
+static void
+gdk_visual_init (GdkVisual *visual)
+{
+  visual->priv = G_TYPE_INSTANCE_GET_PRIVATE (visual,
+                                              GDK_TYPE_VISUAL,
+                                              GdkVisualPrivate);
+
+  visual->priv->colormap = None;
+}
+
+void
+_gdk_visual_init (GdkScreen *screen)
+{
+  static const gint possible_depths[8] = { 32, 30, 24, 16, 15, 8, 4, 1 };
+  static const GdkVisualType possible_types[6] =
+    {
+      GDK_VISUAL_DIRECT_COLOR,
+      GDK_VISUAL_TRUE_COLOR,
+      GDK_VISUAL_PSEUDO_COLOR,
+      GDK_VISUAL_STATIC_COLOR,
+      GDK_VISUAL_GRAYSCALE,
+      GDK_VISUAL_STATIC_GRAY
+    };
+
+  GdkScreenX11 *screen_x11;
+  XVisualInfo *visual_list;
+  XVisualInfo visual_template;
+  GdkVisual *temp_visual;
+  Visual *default_xvisual;
+  GdkVisual **visuals;
+  int nxvisuals;
+  int nvisuals;
+  int i, j;
+  
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+  screen_x11 = GDK_SCREEN_X11 (screen);
+
+  nxvisuals = 0;
+  visual_template.screen = screen_x11->screen_num;
+  visual_list = XGetVisualInfo (screen_x11->xdisplay, VisualScreenMask, &visual_template, &nxvisuals);
+  
+  visuals = g_new (GdkVisual *, nxvisuals);
+  for (i = 0; i < nxvisuals; i++)
+    visuals[i] = g_object_new (GDK_TYPE_VISUAL, NULL);
+
+  default_xvisual = DefaultVisual (screen_x11->xdisplay, screen_x11->screen_num);
+
+  nvisuals = 0;
+  for (i = 0; i < nxvisuals; i++)
+    {
+      visuals[nvisuals]->priv->screen = screen;
+      
+      if (visual_list[i].depth >= 1)
+	{
+#ifdef __cplusplus
+	  switch (visual_list[i].c_class)
+#else /* __cplusplus */
+	  switch (visual_list[i].class)
+#endif /* __cplusplus */
+	    {
+	    case StaticGray:
+	      visuals[nvisuals]->type = GDK_VISUAL_STATIC_GRAY;
+	      break;
+	    case GrayScale:
+	      visuals[nvisuals]->type = GDK_VISUAL_GRAYSCALE;
+	      break;
+	    case StaticColor:
+	      visuals[nvisuals]->type = GDK_VISUAL_STATIC_COLOR;
+	      break;
+	    case PseudoColor:
+	      visuals[nvisuals]->type = GDK_VISUAL_PSEUDO_COLOR;
+	      break;
+	    case TrueColor:
+	      visuals[nvisuals]->type = GDK_VISUAL_TRUE_COLOR;
+	      break;
+	    case DirectColor:
+	      visuals[nvisuals]->type = GDK_VISUAL_DIRECT_COLOR;
+	      break;
+	    }
+
+	  visuals[nvisuals]->depth = visual_list[i].depth;
+	  visuals[nvisuals]->byte_order =
+	    (ImageByteOrder(screen_x11->xdisplay) == LSBFirst) ?
+	    GDK_LSB_FIRST : GDK_MSB_FIRST;
+	  visuals[nvisuals]->red_mask = visual_list[i].red_mask;
+	  visuals[nvisuals]->green_mask = visual_list[i].green_mask;
+	  visuals[nvisuals]->blue_mask = visual_list[i].blue_mask;
+	  visuals[nvisuals]->colormap_size = visual_list[i].colormap_size;
+	  visuals[nvisuals]->bits_per_rgb = visual_list[i].bits_per_rgb;
+	  visuals[nvisuals]->priv->xvisual = visual_list[i].visual;
+
+	  if ((visuals[nvisuals]->type == GDK_VISUAL_TRUE_COLOR) ||
+	      (visuals[nvisuals]->type == GDK_VISUAL_DIRECT_COLOR))
+	    {
+	      gdk_visual_decompose_mask (visuals[nvisuals]->red_mask,
+					 &visuals[nvisuals]->red_shift,
+					 &visuals[nvisuals]->red_prec);
+
+	      gdk_visual_decompose_mask (visuals[nvisuals]->green_mask,
+					 &visuals[nvisuals]->green_shift,
+					 &visuals[nvisuals]->green_prec);
+
+	      gdk_visual_decompose_mask (visuals[nvisuals]->blue_mask,
+					 &visuals[nvisuals]->blue_shift,
+					 &visuals[nvisuals]->blue_prec);
+	    }
+	  else
+	    {
+	      visuals[nvisuals]->red_mask = 0;
+	      visuals[nvisuals]->red_shift = 0;
+	      visuals[nvisuals]->red_prec = 0;
+
+	      visuals[nvisuals]->green_mask = 0;
+	      visuals[nvisuals]->green_shift = 0;
+	      visuals[nvisuals]->green_prec = 0;
+
+	      visuals[nvisuals]->blue_mask = 0;
+	      visuals[nvisuals]->blue_shift = 0;
+	      visuals[nvisuals]->blue_prec = 0;
+	    }
+	  
+	  nvisuals += 1;
+	}
+    }
+
+  if (visual_list)
+    XFree (visual_list);
+
+  for (i = 0; i < nvisuals; i++)
+    {
+      for (j = i+1; j < nvisuals; j++)
+	{
+	  if (visuals[j]->depth >= visuals[i]->depth)
+	    {
+	      if ((visuals[j]->depth == 8) && (visuals[i]->depth == 8))
+		{
+		  if (visuals[j]->type == GDK_VISUAL_PSEUDO_COLOR)
+		    {
+		      temp_visual = visuals[j];
+		      visuals[j] = visuals[i];
+		      visuals[i] = temp_visual;
+		    }
+		  else if ((visuals[i]->type != GDK_VISUAL_PSEUDO_COLOR) &&
+			   visuals[j]->type > visuals[i]->type)
+		    {
+		      temp_visual = visuals[j];
+		      visuals[j] = visuals[i];
+		      visuals[i] = temp_visual;
+		    }
+		}
+	      else if ((visuals[j]->depth > visuals[i]->depth) ||
+		       ((visuals[j]->depth == visuals[i]->depth) &&
+			(visuals[j]->type > visuals[i]->type)))
+		{
+		  temp_visual = visuals[j];
+		  visuals[j] = visuals[i];
+		  visuals[i] = temp_visual;
+		}
+	    }
+	}
+    }
+
+  for (i = 0; i < nvisuals; i++)
+    {
+      if (default_xvisual->visualid == visuals[i]->priv->xvisual->visualid)
+         {
+ 	   screen_x11->system_visual = visuals[i];
+           visuals[i]->priv->colormap = DefaultColormap (screen_x11->xdisplay,
+                                                         screen_x11->screen_num);
+         }
+
+      /* For now, we only support 8888 ARGB for the "rgba visual".
+       * Additional formats (like ABGR) could be added later if they
+       * turn up.
+       */
+      if (visuals[i]->depth == 32 &&
+	  (visuals[i]->red_mask   == 0xff0000 &&
+	   visuals[i]->green_mask == 0x00ff00 &&
+	   visuals[i]->blue_mask  == 0x0000ff))
+	{
+	  screen_x11->rgba_visual = GDK_VISUAL (visuals[i]);
+	}
+    }
+
+#ifdef G_ENABLE_DEBUG 
+  if (_gdk_debug_flags & GDK_DEBUG_MISC)
+    {
+      static const gchar *const visual_names[] =
+      {
+        "static gray",
+        "grayscale",
+        "static color",
+        "pseudo color",
+        "true color",
+        "direct color",
+      };
+
+      for (i = 0; i < nvisuals; i++)
+        g_message ("visual: %s: %d",
+                   visual_names[visuals[i]->type],
+                   visuals[i]->depth);
+    }
+#endif /* G_ENABLE_DEBUG */
+
+  screen_x11->navailable_depths = 0;
+  for (i = 0; i < G_N_ELEMENTS (possible_depths); i++)
+    {
+      for (j = 0; j < nvisuals; j++)
+	{
+	  if (visuals[j]->depth == possible_depths[i])
+	    {
+	      screen_x11->available_depths[screen_x11->navailable_depths++] = visuals[j]->depth;
+	      break;
+	    }
+	}
+    }
+
+  if (screen_x11->navailable_depths == 0)
+    g_error ("unable to find a usable depth");
+
+  screen_x11->navailable_types = 0;
+  for (i = 0; i < G_N_ELEMENTS (possible_types); i++)
+    {
+      for (j = 0; j < nvisuals; j++)
+	{
+	  if (visuals[j]->type == possible_types[i])
+	    {
+	      screen_x11->available_types[screen_x11->navailable_types++] = visuals[j]->type;
+	      break;
+	    }
+	}
+    }
+
+  for (i = 0; i < nvisuals; i++)
+    gdk_visual_add ((GdkVisual*) visuals[i]);
+
+  if (screen_x11->navailable_types == 0)
+    g_error ("unable to find a usable visual type");
+
+  screen_x11->visuals = visuals;
+  screen_x11->nvisuals = nvisuals;
+}
+
+/**
+ * gdk_visual_get_best_depth:
+ * 
+ * Get the best available depth for the default GDK screen.  "Best"
+ * means "largest," i.e. 32 preferred over 24 preferred over 8 bits
+ * per pixel.
+ * 
+ * Return value: best available depth
+ **/
+gint
+gdk_visual_get_best_depth (void)
+{
+  GdkScreen *screen = gdk_screen_get_default();
+  
+  return GDK_SCREEN_X11 (screen)->available_depths[0];
+}
+
+/**
+ * gdk_visual_get_best_type:
+ * 
+ * Return the best available visual type for the default GDK screen.
+ * 
+ * Return value: best visual type
+ **/
+GdkVisualType
+gdk_visual_get_best_type (void)
+{
+  GdkScreen *screen = gdk_screen_get_default();
+  
+  return GDK_SCREEN_X11 (screen)->available_types[0];
+}
+
+/**
+ * gdk_screen_get_system_visual:
+ * @screen: a #GdkScreen.
+ * 
+ * Get the system's default visual for @screen.
+ * This is the visual for the root window of the display.
+ * The return value should not be freed.
+ * 
+ * Return value: (transfer none): the system visual
+ *
+ * Since: 2.2
+ **/
+GdkVisual *
+gdk_screen_get_system_visual (GdkScreen * screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  return ((GdkVisual *) GDK_SCREEN_X11 (screen)->system_visual);
+}
+
+/**
+ * gdk_visual_get_best:
+ *
+ * Get the visual with the most available colors for the default
+ * GDK screen. The return value should not be freed.
+ * 
+ * Return value: (transfer none): best visual
+ **/
+GdkVisual*
+gdk_visual_get_best (void)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default());
+
+  return (GdkVisual *)screen_x11->visuals[0];
+}
+
+/**
+ * gdk_visual_get_best_with_depth:
+ * @depth: a bit depth
+ * 
+ * Get the best visual with depth @depth for the default GDK screen.
+ * Color visuals and visuals with mutable colormaps are preferred
+ * over grayscale or fixed-colormap visuals. The return value should not
+ * be freed. %NULL may be returned if no visual supports @depth.
+ * 
+ * Return value: (transfer none): best visual for the given depth
+ **/
+GdkVisual*
+gdk_visual_get_best_with_depth (gint depth)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
+  GdkVisual *return_val;
+  int i;
+  
+  return_val = NULL;
+  for (i = 0; i < screen_x11->nvisuals; i++)
+    if (depth == screen_x11->visuals[i]->depth)
+      {
+	return_val = (GdkVisual *) screen_x11->visuals[i];
+	break;
+      }
+
+  return return_val;
+}
+
+/**
+ * gdk_visual_get_best_with_type:
+ * @visual_type: a visual type
+ *
+ * Get the best visual of the given @visual_type for the default GDK screen.
+ * Visuals with higher color depths are considered better. The return value
+ * should not be freed. %NULL may be returned if no visual has type
+ * @visual_type.
+ * 
+ * Return value: (transfer none): best visual of the given type
+ **/
+GdkVisual*
+gdk_visual_get_best_with_type (GdkVisualType visual_type)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
+  GdkVisual *return_val;
+  int i;
+
+  return_val = NULL;
+  for (i = 0; i < screen_x11->nvisuals; i++)
+    if (visual_type == screen_x11->visuals[i]->type)
+      {
+	return_val = (GdkVisual *) screen_x11->visuals[i];
+	break;
+      }
+
+  return return_val;
+}
+
+/**
+ * gdk_visual_get_best_with_both:
+ * @depth: a bit depth
+ * @visual_type: a visual type
+ *
+ * Combines gdk_visual_get_best_with_depth() and gdk_visual_get_best_with_type().
+ * 
+ * Return value: (transfer none): best visual with both @depth and
+ *     @visual_type, or %NULL if none
+ **/
+GdkVisual*
+gdk_visual_get_best_with_both (gint          depth,
+			       GdkVisualType visual_type)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
+  GdkVisual *return_val;
+  int i;
+
+  return_val = NULL;
+  for (i = 0; i < screen_x11->nvisuals; i++)
+    if ((depth == screen_x11->visuals[i]->depth) &&
+	(visual_type == screen_x11->visuals[i]->type))
+      {
+	return_val = (GdkVisual *) screen_x11->visuals[i];
+	break;
+      }
+
+  return return_val;
+}
+
+/**
+ * gdk_query_depths:
+ * @depths: (out) (array): return location for available depths
+ * @count: (out): return location for number of available depths
+ *
+ * This function returns the available bit depths for the default
+ * screen. It's equivalent to listing the visuals
+ * (gdk_list_visuals()) and then looking at the depth field in each
+ * visual, removing duplicates.
+ * 
+ * The array returned by this function should not be freed.
+ * 
+ **/
+void
+gdk_query_depths  (gint **depths,
+		   gint  *count)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
+  
+  *count = screen_x11->navailable_depths;
+  *depths = screen_x11->available_depths;
+}
+
+/**
+ * gdk_query_visual_types:
+ * @visual_types: return location for the available visual types
+ * @count: return location for the number of available visual types
+ *
+ * This function returns the available visual types for the default
+ * screen. It's equivalent to listing the visuals
+ * (gdk_list_visuals()) and then looking at the type field in each
+ * visual, removing duplicates.
+ * 
+ * The array returned by this function should not be freed.
+ **/
+void
+gdk_query_visual_types (GdkVisualType **visual_types,
+			gint           *count)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
+  
+  *count = screen_x11->navailable_types;
+  *visual_types = screen_x11->available_types;
+}
+
+/**
+ * gdk_screen_list_visuals:
+ * @screen: the relevant #GdkScreen.
+ *  
+ * Lists the available visuals for the specified @screen.
+ * A visual describes a hardware image data format.
+ * For example, a visual might support 24-bit color, or 8-bit color,
+ * and might expect pixels to be in a certain format.
+ *
+ * Call g_list_free() on the return value when you're finished with it.
+ * 
+ * Return value: (transfer container) (element-type GdkVisual):
+ *     a list of visuals; the list must be freed, but not its contents
+ *
+ * Since: 2.2
+ **/
+GList *
+gdk_screen_list_visuals (GdkScreen *screen)
+{
+  GList *list;
+  GdkScreenX11 *screen_x11;
+  guint i;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+  screen_x11 = GDK_SCREEN_X11 (screen);
+  
+  list = NULL;
+
+  for (i = 0; i < screen_x11->nvisuals; ++i)
+    list = g_list_append (list, screen_x11->visuals[i]);
+
+  return list;
+}
+
+/**
+ * gdk_x11_screen_lookup_visual:
+ * @screen: a #GdkScreen.
+ * @xvisualid: an X Visual ID.
+ *
+ * Looks up the #GdkVisual for a particular screen and X Visual ID.
+ *
+ * Returns: the #GdkVisual (owned by the screen object), or %NULL
+ *   if the visual ID wasn't found.
+ *
+ * Since: 2.2
+ */
+GdkVisual *
+gdk_x11_screen_lookup_visual (GdkScreen *screen,
+			      VisualID   xvisualid)
+{
+  int i;
+  GdkScreenX11 *screen_x11;
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+  screen_x11 = GDK_SCREEN_X11 (screen);
+
+  for (i = 0; i < screen_x11->nvisuals; i++)
+    if (xvisualid == screen_x11->visuals[i]->priv->xvisual->visualid)
+      return (GdkVisual *)  screen_x11->visuals[i];
+
+  return NULL;
+}
+
+/**
+ * gdkx_visual_get:
+ * @xvisualid: a X visual id.
+ * 
+ * Returns a #GdkVisual corresponding to a X visual. 
+ * 
+ * Return value: the #GdkVisual.
+ **/
+GdkVisual*
+gdkx_visual_get (VisualID xvisualid)
+{
+  return gdk_x11_screen_lookup_visual (gdk_screen_get_default (), xvisualid);
+}
+
+static void
+gdk_visual_add (GdkVisual *visual)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (visual->priv->screen);
+  
+  if (!screen_x11->visual_hash)
+    screen_x11->visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash,
+                                                (GEqualFunc) gdk_visual_equal);
+
+  g_hash_table_insert (screen_x11->visual_hash, visual->priv->xvisual, visual);
+}
+
+static void
+gdk_visual_decompose_mask (gulong  mask,
+			   gint   *shift,
+			   gint   *prec)
+{
+  *shift = 0;
+  *prec = 0;
+
+  if (mask == 0)
+    {
+      g_warning ("Mask is 0 in visual. Server bug ?");
+      return;
+    }
+
+  while (!(mask & 0x1))
+    {
+      (*shift)++;
+      mask >>= 1;
+    }
+
+  while (mask & 0x1)
+    {
+      (*prec)++;
+      mask >>= 1;
+    }
+}
+
+static guint
+gdk_visual_hash (Visual *key)
+{
+  return key->visualid;
+}
+
+static gboolean
+gdk_visual_equal (Visual *a,
+		  Visual *b)
+{
+  return (a->visualid == b->visualid);
+}
+
+/**
+ * _gdk_visual_get_x11_colormap:
+ * @visual: the visual to get the colormap from
+ *
+ * Gets the colormap to use
+ *
+ * Returns: the X Colormap to use for new windows using @visual
+ **/
+Colormap
+_gdk_visual_get_x11_colormap (GdkVisual *visual)
+{
+  GdkVisualPrivate *priv;
+
+  g_return_val_if_fail (GDK_IS_VISUAL (visual), None);
+
+  priv = visual->priv;
+
+  if (priv->colormap == None)
+    {
+      priv->colormap = XCreateColormap (GDK_SCREEN_XDISPLAY (priv->screen),
+                                        GDK_SCREEN_XROOTWIN (priv->screen),
+                                        GDK_VISUAL_XVISUAL (visual),
+                                        AllocNone);
+    }
+
+  return priv->colormap;
+}
+
+/**
+ * gdk_x11_visual_get_xvisual:
+ * @visual: a #GdkVisual.
+ * 
+ * Returns the X visual belonging to a #GdkVisual.
+ * 
+ * Return value: an Xlib <type>Visual*</type>.
+ **/
+Visual *
+gdk_x11_visual_get_xvisual (GdkVisual *visual)
+{
+  g_return_val_if_fail (visual != NULL, NULL);
+
+  return visual->priv->xvisual;
+}
+
+/**
+ * gdk_visual_get_screen:
+ * @visual: a #GdkVisual
+ * 
+ * Gets the screen to which this visual belongs
+ * 
+ * Return value: (transfer none): the screen to which this visual belongs.
+ *
+ * Since: 2.2
+ **/
+GdkScreen *
+gdk_visual_get_screen (GdkVisual *visual)
+{
+  g_return_val_if_fail (GDK_IS_VISUAL (visual), NULL);
+
+  return visual->priv->screen;
+}
diff --git a/gdk/broadway/gdkwindow-broadway.c b/gdk/broadway/gdkwindow-broadway.c
new file mode 100644
index 0000000..cb87793
--- /dev/null
+++ b/gdk/broadway/gdkwindow-broadway.c
@@ -0,0 +1,5583 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
+ * Josh MacDonald, Ryan Lortie
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkwindow-broadway.h"
+
+#include "gdkx.h"
+#include "gdkwindow.h"
+#include "gdkwindowimpl.h"
+#include "gdkasync.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkprivate-broadway.h"
+#include "gdkinternals.h"
+#include "gdkdeviceprivate.h"
+#include "gdkeventsource.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include <cairo-xlib.h>
+
+#include "MwmUtil.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+#include <X11/extensions/shape.h>
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+#ifdef HAVE_XCOMPOSITE
+#include <X11/extensions/Xcomposite.h>
+#endif
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+
+const int _gdk_event_mask_table[21] =
+{
+  ExposureMask,
+  PointerMotionMask,
+  PointerMotionHintMask,
+  ButtonMotionMask,
+  Button1MotionMask,
+  Button2MotionMask,
+  Button3MotionMask,
+  ButtonPressMask,
+  ButtonReleaseMask,
+  KeyPressMask,
+  KeyReleaseMask,
+  EnterWindowMask,
+  LeaveWindowMask,
+  FocusChangeMask,
+  StructureNotifyMask,
+  PropertyChangeMask,
+  VisibilityChangeMask,
+  0,				/* PROXIMITY_IN */
+  0,				/* PROXIMTY_OUT */
+  SubstructureNotifyMask,
+  ButtonPressMask      /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
+};
+const int _gdk_nenvent_masks = sizeof (_gdk_event_mask_table) / sizeof (int);
+
+/* Forward declarations */
+static void     gdk_window_set_static_win_gravity (GdkWindow  *window,
+						   gboolean    on);
+static gboolean gdk_window_icon_name_set          (GdkWindow  *window);
+static void     set_wm_name                       (GdkDisplay  *display,
+						   Window       xwindow,
+						   const gchar *name);
+static void     move_to_current_desktop           (GdkWindow *window);
+static void     gdk_window_x11_set_background     (GdkWindow      *window,
+                                                   cairo_pattern_t *pattern);
+
+static void        gdk_window_impl_x11_finalize   (GObject            *object);
+static void        gdk_window_impl_iface_init     (GdkWindowImplIface *iface);
+
+#define WINDOW_IS_TOPLEVEL_OR_FOREIGN(window) \
+  (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&   \
+   GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
+
+#define WINDOW_IS_TOPLEVEL(window)		     \
+  (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&   \
+   GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \
+   GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
+
+/* Return whether time1 is considered later than time2 as far as xserver
+ * time is concerned.  Accounts for wraparound.
+ */
+#define XSERVER_TIME_IS_LATER(time1, time2)                        \
+  ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) ||  \
+    (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 ))     \
+  )
+
+G_DEFINE_TYPE_WITH_CODE (GdkWindowImplX11,
+                         gdk_window_impl_x11,
+                         GDK_TYPE_DRAWABLE_IMPL_X11,
+                         G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL,
+                                                gdk_window_impl_iface_init));
+
+GType
+_gdk_window_impl_get_type (void)
+{
+  return gdk_window_impl_x11_get_type ();
+}
+
+static void
+gdk_window_impl_x11_init (GdkWindowImplX11 *impl)
+{  
+  impl->toplevel_window_type = -1;
+  impl->device_cursor = g_hash_table_new_full (NULL, NULL, NULL,
+                                               (GDestroyNotify) gdk_cursor_unref);
+}
+
+GdkToplevelX11 *
+_gdk_x11_window_get_toplevel (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  GdkWindowImplX11 *impl;
+  
+  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+
+  if (!WINDOW_IS_TOPLEVEL (window))
+    return NULL;
+
+  private = (GdkWindowObject *)window;
+  impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+  if (!impl->toplevel)
+    impl->toplevel = g_new0 (GdkToplevelX11, 1);
+
+  return impl->toplevel;
+}
+
+static void
+gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  object_class->finalize = gdk_window_impl_x11_finalize;
+}
+
+static void
+gdk_window_impl_x11_finalize (GObject *object)
+{
+  GdkWindowObject *wrapper;
+  GdkDrawableImplX11 *draw_impl;
+  GdkWindowImplX11 *window_impl;
+  
+  g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (object));
+
+  draw_impl = GDK_DRAWABLE_IMPL_X11 (object);
+  window_impl = GDK_WINDOW_IMPL_X11 (object);
+  
+  wrapper = (GdkWindowObject*) draw_impl->wrapper;
+
+  _gdk_xgrab_check_destroy (GDK_WINDOW (wrapper));
+
+  if (!GDK_WINDOW_DESTROYED (wrapper))
+    {
+      GdkDisplay *display = GDK_WINDOW_DISPLAY (wrapper);
+      
+      _gdk_xid_table_remove (display, draw_impl->xid);
+      if (window_impl->toplevel && window_impl->toplevel->focus_window)
+	_gdk_xid_table_remove (display, window_impl->toplevel->focus_window);
+    }
+
+  g_free (window_impl->toplevel);
+
+  if (window_impl->cursor)
+    gdk_cursor_unref (window_impl->cursor);
+
+  g_hash_table_destroy (window_impl->device_cursor);
+
+  G_OBJECT_CLASS (gdk_window_impl_x11_parent_class)->finalize (object);
+}
+
+typedef struct {
+  GdkDisplay *display;
+  Pixmap pixmap;
+} FreePixmapData;
+
+static void
+free_pixmap (gpointer datap)
+{
+  FreePixmapData *data = datap;
+
+  if (!gdk_display_is_closed (data->display))
+    {
+      XFreePixmap (GDK_DISPLAY_XDISPLAY (data->display),
+                   data->pixmap);
+    }
+
+  g_object_unref (data->display);
+  g_slice_free (FreePixmapData, data);
+}
+
+static void
+attach_free_pixmap_handler (cairo_surface_t *surface,
+                            GdkDisplay      *display,
+                            Pixmap           pixmap)
+{
+  static const cairo_user_data_key_t key;
+  FreePixmapData *data;
+  
+  data = g_slice_new (FreePixmapData);
+  data->display = g_object_ref (display);
+  data->pixmap = pixmap;
+
+  cairo_surface_set_user_data (surface, &key, data, free_pixmap);
+}
+
+/* Cairo does not guarantee we get an xlib surface if we call
+ * cairo_surface_create_similar(). In some cases however, we must use a
+ * pixmap or bitmap in the X11 API.
+ * These functions ensure an Xlib surface.
+ */
+cairo_surface_t *
+_gdk_x11_window_create_bitmap_surface (GdkWindow *window,
+                                       int        width,
+                                       int        height)
+{
+  cairo_surface_t *surface;
+  Pixmap pixmap;
+
+  pixmap = XCreatePixmap (GDK_WINDOW_XDISPLAY (window),
+                          GDK_WINDOW_XID (window),
+                          width, height, 1);
+  surface = cairo_xlib_surface_create_for_bitmap (GDK_WINDOW_XDISPLAY (window),
+                                                  pixmap,
+                                                  GDK_SCREEN_XSCREEN (GDK_WINDOW_SCREEN (window)),
+                                                  width, height);
+  attach_free_pixmap_handler (surface, GDK_WINDOW_DISPLAY (window), pixmap);
+
+  return surface;
+}
+
+static cairo_surface_t *
+gdk_x11_window_create_pixmap_surface (GdkWindow *window,
+                                      int        width,
+                                      int        height)
+{
+  cairo_surface_t *surface;
+  Pixmap pixmap;
+
+  pixmap = XCreatePixmap (GDK_WINDOW_XDISPLAY (window),
+                          GDK_WINDOW_XID (window),
+                          width, height,
+                          DefaultDepthOfScreen (GDK_SCREEN_XSCREEN (GDK_WINDOW_SCREEN (window))));
+  surface = cairo_xlib_surface_create (GDK_WINDOW_XDISPLAY (window),
+                                       pixmap,
+                                       GDK_VISUAL_XVISUAL (gdk_window_get_visual (window)),
+                                       width, height);
+  attach_free_pixmap_handler (surface, GDK_WINDOW_DISPLAY (window), pixmap);
+
+  return surface;
+}
+
+static void
+tmp_unset_bg (GdkWindow *window)
+{
+  GdkWindowImplX11 *impl;
+  GdkWindowObject *obj;
+
+  obj = (GdkWindowObject *) window;
+  impl = GDK_WINDOW_IMPL_X11 (obj->impl);
+
+  impl->no_bg = TRUE;
+
+  XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window),
+                              GDK_DRAWABLE_XID (window), None);
+}
+
+static void
+tmp_reset_bg (GdkWindow *window)
+{
+  GdkWindowImplX11 *impl;
+  GdkWindowObject *obj;
+
+  obj = (GdkWindowObject *) window;
+  impl = GDK_WINDOW_IMPL_X11 (obj->impl);
+
+  impl->no_bg = FALSE;
+
+  gdk_window_x11_set_background (window, obj->background);
+}
+
+/* Unsetting and resetting window backgrounds.
+ *
+ * In many cases it is possible to avoid flicker by unsetting the
+ * background of windows. For example if the background of the
+ * parent window is unset when a window is unmapped, a brief flicker
+ * of background painting is avoided.
+ */
+void
+_gdk_x11_window_tmp_unset_bg (GdkWindow *window,
+			      gboolean   recurse)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+  private = (GdkWindowObject *)window;
+
+  if (private->input_only || private->destroyed ||
+      (private->window_type != GDK_WINDOW_ROOT &&
+       !GDK_WINDOW_IS_MAPPED (window)))
+    return;
+  
+  if (_gdk_window_has_impl (window) &&
+      GDK_WINDOW_IS_X11 (window) &&
+      private->window_type != GDK_WINDOW_ROOT &&
+      private->window_type != GDK_WINDOW_FOREIGN)
+    tmp_unset_bg (window);
+
+  if (recurse)
+    {
+      GList *l;
+
+      for (l = private->children; l != NULL; l = l->next)
+	_gdk_x11_window_tmp_unset_bg (l->data, TRUE);
+    }
+}
+
+void
+_gdk_x11_window_tmp_unset_parent_bg (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  private = (GdkWindowObject*) window;
+
+  if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+    return;
+  
+  window = _gdk_window_get_impl_window ((GdkWindow *)private->parent);
+  _gdk_x11_window_tmp_unset_bg (window,	FALSE);
+}
+
+void
+_gdk_x11_window_tmp_reset_bg (GdkWindow *window,
+			      gboolean   recurse)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *)window;
+
+  if (private->input_only || private->destroyed ||
+      (private->window_type != GDK_WINDOW_ROOT &&
+       !GDK_WINDOW_IS_MAPPED (window)))
+    return;
+
+  
+  if (_gdk_window_has_impl (window) &&
+      GDK_WINDOW_IS_X11 (window) &&
+      private->window_type != GDK_WINDOW_ROOT &&
+      private->window_type != GDK_WINDOW_FOREIGN)
+    tmp_reset_bg (window);
+
+  if (recurse)
+    {
+      GList *l;
+
+      for (l = private->children; l != NULL; l = l->next)
+	_gdk_x11_window_tmp_reset_bg (l->data, TRUE);
+    }
+}
+
+void
+_gdk_x11_window_tmp_reset_parent_bg (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  private = (GdkWindowObject*) window;
+
+  if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+    return;
+  
+  window = _gdk_window_get_impl_window ((GdkWindow *)private->parent);
+
+  _gdk_x11_window_tmp_reset_bg (window, FALSE);
+}
+
+void
+_gdk_windowing_window_init (GdkScreen * screen)
+{
+  GdkWindowObject *private;
+  GdkDrawableImplX11 *draw_impl;
+  GdkScreenX11 *screen_x11;
+
+  screen_x11 = GDK_SCREEN_X11 (screen);
+
+  g_assert (screen_x11->root_window == NULL);
+
+  screen_x11->root_window = g_object_new (GDK_TYPE_WINDOW, NULL);
+
+  private = (GdkWindowObject *) screen_x11->root_window;
+  private->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
+  private->impl_window = private;
+  private->visual = gdk_screen_get_system_visual (screen);
+
+  draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
+  
+  draw_impl->screen = screen;
+  draw_impl->xid = screen_x11->xroot_window;
+  draw_impl->wrapper = GDK_DRAWABLE (private);
+  
+  private->window_type = GDK_WINDOW_ROOT;
+  private->depth = DefaultDepthOfScreen (screen_x11->xscreen);
+
+  private->x = 0;
+  private->y = 0;
+  private->abs_x = 0;
+  private->abs_y = 0;
+  private->width = WidthOfScreen (screen_x11->xscreen);
+  private->height = HeightOfScreen (screen_x11->xscreen);
+  private->viewable = TRUE;
+
+  /* see init_randr_support() in gdkscreen-broadway.c */
+  private->event_mask = GDK_STRUCTURE_MASK;
+
+  _gdk_window_update_size (screen_x11->root_window);
+  
+  _gdk_xid_table_insert (screen_x11->display,
+			 &screen_x11->xroot_window,
+			 screen_x11->root_window);
+}
+
+static void
+set_wm_protocols (GdkWindow *window)
+{
+  GdkDisplay *display = gdk_window_get_display (window);
+  Atom protocols[4];
+  int n = 0;
+  
+  protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW");
+  protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
+  protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING");
+
+#ifdef HAVE_XSYNC
+  if (GDK_DISPLAY_X11 (display)->use_sync)
+    protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST");
+#endif
+  
+  XSetWMProtocols (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), protocols, n);
+}
+
+static const gchar *
+get_default_title (void)
+{
+  const char *title;
+
+  title = g_get_application_name ();
+  if (!title)
+    title = g_get_prgname ();
+  if (!title)
+    title = "";
+
+  return title;
+}
+
+static void
+check_leader_window_title (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (display_x11->leader_window && !display_x11->leader_window_title_set)
+    {
+      set_wm_name (display,
+		   display_x11->leader_window,
+		   get_default_title ());
+      
+      display_x11->leader_window_title_set = TRUE;
+    }
+}
+
+static Window
+create_focus_window (GdkDisplay *display,
+		     XID         parent)
+{
+  GdkDisplayX11 *display_x11;
+  GdkEventMask event_mask;
+  Display *xdisplay;
+  Window focus_window;
+
+  xdisplay = GDK_DISPLAY_XDISPLAY (display);
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  focus_window = XCreateSimpleWindow (xdisplay, parent,
+                                      -1, -1, 1, 1, 0,
+                                      0, 0);
+
+  /* FIXME: probably better to actually track the requested event mask for the toplevel
+   */
+  event_mask = (GDK_KEY_PRESS_MASK |
+                GDK_KEY_RELEASE_MASK |
+                GDK_FOCUS_CHANGE_MASK);
+
+  gdk_event_source_select_events ((GdkEventSource *) display_x11->event_source,
+                                  focus_window,
+                                  event_mask, 0);
+
+  XMapWindow (xdisplay, focus_window);
+
+  return focus_window;
+}
+
+static void
+ensure_sync_counter (GdkWindow *window)
+{
+#ifdef HAVE_XSYNC
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+      GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+      GdkWindowObject *private = (GdkWindowObject *)window;
+      GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+      if (toplevel && impl->use_synchronized_configure &&
+	  toplevel->update_counter == None &&
+	  GDK_DISPLAY_X11 (display)->use_sync)
+	{
+	  Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+	  XSyncValue value;
+	  Atom atom;
+
+	  XSyncIntToValue (&value, 0);
+	  
+	  toplevel->update_counter = XSyncCreateCounter (xdisplay, value);
+	  
+	  atom = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_SYNC_REQUEST_COUNTER");
+	  
+	  XChangeProperty (xdisplay, GDK_WINDOW_XID (window),
+			   atom, XA_CARDINAL,
+			   32, PropModeReplace,
+			   (guchar *)&toplevel->update_counter, 1);
+	  
+	  XSyncIntToValue (&toplevel->current_counter_value, 0);
+	}
+    }
+#endif
+}
+
+static void
+setup_toplevel_window (GdkWindow *window, 
+		       GdkWindow *parent)
+{
+  GdkWindowObject *obj = (GdkWindowObject *)window;
+  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+  GdkDisplay *display = gdk_window_get_display (window);
+  Display *xdisplay = GDK_WINDOW_XDISPLAY (window);
+  XID xid = GDK_WINDOW_XID (window);
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (GDK_WINDOW_SCREEN (parent));
+  XSizeHints size_hints;
+  long pid;
+  Window leader_window;
+
+  set_wm_protocols (window);
+
+  if (!obj->input_only)
+    {
+      /* The focus window is off the visible area, and serves to receive key
+       * press events so they don't get sent to child windows.
+       */
+      toplevel->focus_window = create_focus_window (display, xid);
+      _gdk_xid_table_insert (screen_x11->display, &toplevel->focus_window, window);
+    }
+  
+  check_leader_window_title (screen_x11->display);
+  
+  /* FIXME: Is there any point in doing this? Do any WM's pay
+   * attention to PSize, and even if they do, is this the
+   * correct value???
+   */
+  size_hints.flags = PSize;
+  size_hints.width = obj->width;
+  size_hints.height = obj->height;
+  
+  XSetWMNormalHints (xdisplay, xid, &size_hints);
+  
+  /* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
+  XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
+  
+  pid = getpid ();
+  XChangeProperty (xdisplay, xid,
+		   gdk_x11_get_xatom_by_name_for_display (screen_x11->display, "_NET_WM_PID"),
+		   XA_CARDINAL, 32,
+		   PropModeReplace,
+		   (guchar *)&pid, 1);
+
+  leader_window = GDK_DISPLAY_X11 (screen_x11->display)->leader_window;
+  if (!leader_window)
+    leader_window = xid;
+  XChangeProperty (xdisplay, xid, 
+		   gdk_x11_get_xatom_by_name_for_display (screen_x11->display, "WM_CLIENT_LEADER"),
+		   XA_WINDOW, 32, PropModeReplace,
+		   (guchar *) &leader_window, 1);
+
+  if (toplevel->focus_window != None)
+    XChangeProperty (xdisplay, xid, 
+                     gdk_x11_get_xatom_by_name_for_display (screen_x11->display, "_NET_WM_USER_TIME_WINDOW"),
+                     XA_WINDOW, 32, PropModeReplace,
+                     (guchar *) &toplevel->focus_window, 1);
+
+  if (!obj->focus_on_map)
+    gdk_x11_window_set_user_time (window, 0);
+  else if (GDK_DISPLAY_X11 (screen_x11->display)->user_time != 0)
+    gdk_x11_window_set_user_time (window, GDK_DISPLAY_X11 (screen_x11->display)->user_time);
+
+  ensure_sync_counter (window);
+}
+
+void
+_gdk_window_impl_new (GdkWindow     *window,
+		      GdkWindow     *real_parent,
+		      GdkScreen     *screen,
+		      GdkEventMask   event_mask,
+		      GdkWindowAttr *attributes,
+		      gint           attributes_mask)
+{
+  GdkWindowObject *private;
+  GdkWindowImplX11 *impl;
+  GdkDrawableImplX11 *draw_impl;
+  GdkScreenX11 *screen_x11;
+  GdkDisplayX11 *display_x11;
+  
+  Window xparent;
+  Visual *xvisual;
+  Display *xdisplay;
+  Window xid;
+
+  XSetWindowAttributes xattributes;
+  long xattributes_mask;
+  XClassHint *class_hint;
+  
+  unsigned int class;
+  const char *title;
+  
+  private = (GdkWindowObject *) window;
+  
+  screen_x11 = GDK_SCREEN_X11 (screen);
+  xparent = GDK_WINDOW_XID (real_parent);
+  display_x11 = GDK_DISPLAY_X11 (GDK_SCREEN_DISPLAY (screen));
+  
+  impl = g_object_new (_gdk_window_impl_get_type (), NULL);
+  private->impl = (GdkDrawable *)impl;
+  draw_impl = GDK_DRAWABLE_IMPL_X11 (impl);
+  draw_impl->wrapper = GDK_DRAWABLE (window);
+  
+  draw_impl->screen = screen;
+  xdisplay = screen_x11->xdisplay;
+
+  xattributes_mask = 0;
+
+  xvisual = gdk_x11_visual_get_xvisual (private->visual);
+  
+  if (attributes_mask & GDK_WA_NOREDIR)
+    {
+      xattributes.override_redirect =
+	(attributes->override_redirect == FALSE)?False:True;
+      xattributes_mask |= CWOverrideRedirect;
+    } 
+  else
+    xattributes.override_redirect = False;
+
+  impl->override_redirect = xattributes.override_redirect;
+  
+  if (private->parent && private->parent->guffaw_gravity)
+    {
+      xattributes.win_gravity = StaticGravity;
+      xattributes_mask |= CWWinGravity;
+    }
+  
+  /* Sanity checks */
+  switch (private->window_type)
+    {
+    case GDK_WINDOW_TOPLEVEL:
+    case GDK_WINDOW_TEMP:
+      if (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+	{
+	  /* The common code warns for this case */
+	  xparent = GDK_SCREEN_XROOTWIN (screen);
+	}
+    }
+	  
+  if (!private->input_only)
+    {
+      class = InputOutput;
+
+      xattributes.background_pixel = BlackPixel (xdisplay, screen_x11->screen_num);
+
+      xattributes.border_pixel = BlackPixel (xdisplay, screen_x11->screen_num);
+      xattributes_mask |= CWBorderPixel | CWBackPixel;
+
+      if (private->guffaw_gravity)
+	xattributes.bit_gravity = StaticGravity;
+      else
+	xattributes.bit_gravity = NorthWestGravity;
+      
+      xattributes_mask |= CWBitGravity;
+
+      xattributes.colormap = _gdk_visual_get_x11_colormap (private->visual);
+      xattributes_mask |= CWColormap;
+
+      if (private->window_type == GDK_WINDOW_TEMP)
+	{
+	  xattributes.save_under = True;
+	  xattributes.override_redirect = True;
+	  xattributes.cursor = None;
+	  xattributes_mask |= CWSaveUnder | CWOverrideRedirect;
+
+	  impl->override_redirect = TRUE;
+	}
+    }
+  else
+    {
+      class = InputOnly;
+    }
+
+  if (private->width > 65535 ||
+      private->height > 65535)
+    {
+      g_warning ("Native Windows wider or taller than 65535 pixels are not supported");
+      
+      if (private->width > 65535)
+	private->width = 65535;
+      if (private->height > 65535)
+	private->height = 65535;
+    }
+  
+  xid = draw_impl->xid = XCreateWindow (xdisplay, xparent,
+					private->x + private->parent->abs_x,
+					private->y + private->parent->abs_y,
+					private->width, private->height,
+					0, private->depth, class, xvisual,
+					xattributes_mask, &xattributes);
+
+  g_object_ref (window);
+  _gdk_xid_table_insert (screen_x11->display, &draw_impl->xid, window);
+
+  switch (GDK_WINDOW_TYPE (private))
+    {
+    case GDK_WINDOW_TOPLEVEL:
+    case GDK_WINDOW_TEMP:
+      if (attributes_mask & GDK_WA_TITLE)
+	title = attributes->title;
+      else
+	title = get_default_title ();
+      
+      gdk_window_set_title (window, title);
+      
+      if (attributes_mask & GDK_WA_WMCLASS)
+	{
+	  class_hint = XAllocClassHint ();
+	  class_hint->res_name = attributes->wmclass_name;
+	  class_hint->res_class = attributes->wmclass_class;
+	  XSetClassHint (xdisplay, xid, class_hint);
+	  XFree (class_hint);
+	}
+  
+      setup_toplevel_window (window, (GdkWindow *)private->parent);
+      break;
+
+    case GDK_WINDOW_CHILD:
+    default:
+      break;
+    }
+
+  if (attributes_mask & GDK_WA_TYPE_HINT)
+    gdk_window_set_type_hint (window, attributes->type_hint);
+
+  gdk_event_source_select_events ((GdkEventSource *) display_x11->event_source,
+                                  GDK_WINDOW_XWINDOW (window), event_mask,
+                                  StructureNotifyMask | PropertyChangeMask);
+}
+
+static GdkEventMask
+x_event_mask_to_gdk_event_mask (long mask)
+{
+  GdkEventMask event_mask = 0;
+  int i;
+
+  for (i = 0; i < _gdk_nenvent_masks; i++)
+    {
+      if (mask & _gdk_event_mask_table[i])
+	event_mask |= 1 << (i + 1);
+    }
+
+  return event_mask;
+}
+
+/**
+ * gdk_window_foreign_new_for_display:
+ * @display: the #GdkDisplay where the window handle comes from.
+ * @anid: a native window handle.
+ * 
+ * Wraps a native window in a #GdkWindow.
+ * This may fail if the window has been destroyed. If the window
+ * was already known to GDK, a new reference to the existing 
+ * #GdkWindow is returned.
+ *
+ * For example in the X backend, a native window handle is an Xlib
+ * <type>XID</type>.
+ * 
+ * Return value: a #GdkWindow wrapper for the native window or 
+ *   %NULL if the window has been destroyed. The wrapper will be
+ *   newly created, if one doesn't exist already.
+ *
+ * Since: 2.2
+ **/
+GdkWindow *
+gdk_window_foreign_new_for_display (GdkDisplay     *display,
+				    GdkNativeWindow anid)
+{
+  GdkScreen *screen;
+  GdkWindow *window;
+  GdkWindowObject *private;
+  GdkWindowImplX11 *impl;
+  GdkDrawableImplX11 *draw_impl;
+  GdkDisplayX11 *display_x11;
+  XWindowAttributes attrs;
+  Window root, parent;
+  Window *children = NULL;
+  guint nchildren;
+  gboolean result;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  if ((window = gdk_xid_table_lookup_for_display (display, anid)) != NULL)
+    return g_object_ref (window);
+
+  gdk_error_trap_push ();
+  result = XGetWindowAttributes (display_x11->xdisplay, anid, &attrs);
+  if (gdk_error_trap_pop () || !result)
+    return NULL;
+
+  /* FIXME: This is pretty expensive. Maybe the caller should supply
+   *        the parent */
+  gdk_error_trap_push ();
+  result = XQueryTree (display_x11->xdisplay, anid, &root, &parent, &children, &nchildren);
+  if (gdk_error_trap_pop () || !result)
+    return NULL;
+
+  if (children)
+    XFree (children);
+  
+  screen = _gdk_x11_display_screen_for_xrootwin (display, root);
+
+  window = g_object_new (GDK_TYPE_WINDOW, NULL);
+
+  private = (GdkWindowObject *) window;
+  private->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
+  private->impl_window = private;
+  private->visual = gdk_x11_screen_lookup_visual (screen,
+                                                  XVisualIDFromVisual (attrs.visual));
+
+  impl = GDK_WINDOW_IMPL_X11 (private->impl);
+  draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
+  draw_impl->wrapper = GDK_DRAWABLE (window);
+  draw_impl->screen = screen;
+  
+  private->parent = gdk_xid_table_lookup_for_display (display, parent);
+  
+  if (!private->parent || GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_FOREIGN)
+    private->parent = (GdkWindowObject *) gdk_screen_get_root_window (draw_impl->screen);
+  
+  private->parent->children = g_list_prepend (private->parent->children, window);
+
+  draw_impl->xid = anid;
+
+  private->x = attrs.x;
+  private->y = attrs.y;
+  private->width = attrs.width;
+  private->height = attrs.height;
+  private->window_type = GDK_WINDOW_FOREIGN;
+  private->destroyed = FALSE;
+
+  private->event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
+
+  if (attrs.map_state == IsUnmapped)
+    private->state = GDK_WINDOW_STATE_WITHDRAWN;
+  else
+    private->state = 0;
+  private->viewable = TRUE;
+
+  private->depth = attrs.depth;
+  
+  g_object_ref (window);
+  _gdk_xid_table_insert (display, &GDK_WINDOW_XID (window), window);
+
+  /* Update the clip region, etc */
+  _gdk_window_update_size (window);
+
+  return window;
+}
+
+/**
+ * gdk_window_lookup_for_display:
+ * @display: the #GdkDisplay corresponding to the window handle
+ * @anid: a native window handle.
+ *
+ * Looks up the #GdkWindow that wraps the given native window handle.
+ *
+ * For example in the X backend, a native window handle is an Xlib
+ * <type>XID</type>.
+ *
+ * Return value: the #GdkWindow wrapper for the native window, 
+ *    or %NULL if there is none.
+ *
+ * Since: 2.2
+ **/
+GdkWindow *
+gdk_window_lookup_for_display (GdkDisplay *display, GdkNativeWindow anid)
+{
+  return (GdkWindow*) gdk_xid_table_lookup_for_display (display, anid);
+}
+
+/**
+ * gdk_window_lookup:
+ * @anid: a native window handle.
+ *
+ * Looks up the #GdkWindow that wraps the given native window handle. 
+ *
+ * For example in the X backend, a native window handle is an Xlib
+ * <type>XID</type>.
+ *
+ * Return value: the #GdkWindow wrapper for the native window, 
+ *    or %NULL if there is none.
+ **/
+GdkWindow *
+gdk_window_lookup (GdkNativeWindow anid)
+{
+  return (GdkWindow*) gdk_xid_table_lookup (anid);
+}
+
+static void
+gdk_toplevel_x11_free_contents (GdkDisplay *display,
+				GdkToplevelX11 *toplevel)
+{
+  if (toplevel->icon_pixmap)
+    {
+      cairo_surface_destroy (toplevel->icon_pixmap);
+      toplevel->icon_pixmap = NULL;
+    }
+  if (toplevel->icon_mask)
+    {
+      cairo_surface_destroy (toplevel->icon_mask);
+      toplevel->icon_mask = NULL;
+    }
+  if (toplevel->group_leader)
+    {
+      g_object_unref (toplevel->group_leader);
+      toplevel->group_leader = NULL;
+    }
+#ifdef HAVE_XSYNC
+  if (toplevel->update_counter != None)
+    {
+      XSyncDestroyCounter (GDK_DISPLAY_XDISPLAY (display), 
+			   toplevel->update_counter);
+      toplevel->update_counter = None;
+
+      XSyncIntToValue (&toplevel->current_counter_value, 0);
+    }
+#endif
+}
+
+static void
+_gdk_x11_window_destroy (GdkWindow *window,
+			 gboolean   recursing,
+			 gboolean   foreign_destroy)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkToplevelX11 *toplevel;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  _gdk_selection_window_destroyed (window);
+  
+  toplevel = _gdk_x11_window_get_toplevel (window);
+  if (toplevel)
+    gdk_toplevel_x11_free_contents (GDK_WINDOW_DISPLAY (window), toplevel);
+
+  _gdk_x11_drawable_finish (private->impl);
+
+  if (!recursing && !foreign_destroy)
+    {
+      XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
+    }
+}
+
+static cairo_surface_t *
+gdk_window_x11_resize_cairo_surface (GdkWindow       *window,
+                                     cairo_surface_t *surface,
+                                     gint             width,
+                                     gint             height)
+{
+  cairo_xlib_surface_set_size (surface, width, height);
+
+  return surface;
+}
+
+void
+_gdk_windowing_window_destroy_foreign (GdkWindow *window)
+{
+  /* It's somebody else's window, but in our hierarchy,
+   * so reparent it to the root window, and then send
+   * it a delete event, as if we were a WM
+   */
+  XClientMessageEvent xclient;
+  
+  gdk_error_trap_push ();
+  gdk_window_hide (window);
+  gdk_window_reparent (window, NULL, 0, 0);
+  
+  memset (&xclient, 0, sizeof (xclient));
+  xclient.type = ClientMessage;
+  xclient.window = GDK_WINDOW_XID (window);
+  xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
+							       "WM_PROTOCOLS");
+  xclient.format = 32;
+  xclient.data.l[0] = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
+							    "WM_DELETE_WINDOW");
+  xclient.data.l[1] = CurrentTime;
+  xclient.data.l[2] = 0;
+  xclient.data.l[3] = 0;
+  xclient.data.l[4] = 0;
+  
+  XSendEvent (GDK_WINDOW_XDISPLAY (window),
+	      GDK_WINDOW_XID (window),
+	      False, 0, (XEvent *)&xclient);
+  gdk_error_trap_pop_ignored ();
+}
+
+static GdkWindow *
+get_root (GdkWindow *window)
+{
+  GdkScreen *screen = gdk_window_get_screen (window);
+
+  return gdk_screen_get_root_window (screen);
+}
+
+/* This function is called when the XWindow is really gone.
+ */
+void
+gdk_window_destroy_notify (GdkWindow *window)
+{
+  GdkWindowImplX11 *window_impl;
+
+  window_impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl);
+
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_FOREIGN)
+	g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_WINDOW_XID (window));
+
+      _gdk_window_destroy (window, TRUE);
+    }
+  
+  _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), GDK_WINDOW_XID (window));
+  if (window_impl->toplevel && window_impl->toplevel->focus_window)
+    _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), window_impl->toplevel->focus_window);
+
+  _gdk_xgrab_check_destroy (window);
+  
+  g_object_unref (window);
+}
+
+static void
+update_wm_hints (GdkWindow *window,
+		 gboolean   force)
+{
+  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+  XWMHints wm_hints;
+
+  if (!force &&
+      !toplevel->is_leader &&
+      private->state & GDK_WINDOW_STATE_WITHDRAWN)
+    return;
+
+  wm_hints.flags = StateHint | InputHint;
+  wm_hints.input = private->accept_focus ? True : False;
+  wm_hints.initial_state = NormalState;
+  
+  if (private->state & GDK_WINDOW_STATE_ICONIFIED)
+    {
+      wm_hints.flags |= StateHint;
+      wm_hints.initial_state = IconicState;
+    }
+
+  if (toplevel->icon_pixmap)
+    {
+      wm_hints.flags |= IconPixmapHint;
+      wm_hints.icon_pixmap = cairo_xlib_surface_get_drawable (toplevel->icon_pixmap);
+    }
+
+  if (toplevel->icon_mask)
+    {
+      wm_hints.flags |= IconMaskHint;
+      wm_hints.icon_mask = cairo_xlib_surface_get_drawable (toplevel->icon_mask);
+    }
+  
+  wm_hints.flags |= WindowGroupHint;
+  if (toplevel->group_leader && !GDK_WINDOW_DESTROYED (toplevel->group_leader))
+    {
+      wm_hints.flags |= WindowGroupHint;
+      wm_hints.window_group = GDK_WINDOW_XID (toplevel->group_leader);
+    }
+  else
+    wm_hints.window_group = GDK_DISPLAY_X11 (display)->leader_window;
+
+  if (toplevel->urgency_hint)
+    wm_hints.flags |= XUrgencyHint;
+  
+  XSetWMHints (GDK_WINDOW_XDISPLAY (window),
+	       GDK_WINDOW_XID (window),
+	       &wm_hints);
+}
+
+static void
+set_initial_hints (GdkWindow *window)
+{
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+  Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+  Window xwindow = GDK_WINDOW_XID (window);  
+  GdkWindowObject *private;
+  GdkToplevelX11 *toplevel;
+  Atom atoms[9];
+  gint i;
+
+  private = (GdkWindowObject*) window;
+  toplevel = _gdk_x11_window_get_toplevel (window);
+
+  if (!toplevel)
+    return;
+
+  update_wm_hints (window, TRUE);
+  
+  /* We set the spec hints regardless of whether the spec is supported,
+   * since it can't hurt and it's kind of expensive to check whether
+   * it's supported.
+   */
+  
+  i = 0;
+
+  if (private->state & GDK_WINDOW_STATE_MAXIMIZED)
+    {
+      atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_STATE_MAXIMIZED_VERT");
+      ++i;
+      atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_STATE_MAXIMIZED_HORZ");
+      ++i;
+      toplevel->have_maxhorz = toplevel->have_maxvert = TRUE;
+    }
+
+  if (private->state & GDK_WINDOW_STATE_ABOVE)
+    {
+      atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_STATE_ABOVE");
+      ++i;
+    }
+  
+  if (private->state & GDK_WINDOW_STATE_BELOW)
+    {
+      atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_STATE_BELOW");
+      ++i;
+    }
+  
+  if (private->state & GDK_WINDOW_STATE_STICKY)
+    {
+      atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_STATE_STICKY");
+      ++i;
+      toplevel->have_sticky = TRUE;
+    }
+
+  if (private->state & GDK_WINDOW_STATE_FULLSCREEN)
+    {
+      atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_STATE_FULLSCREEN");
+      ++i;
+      toplevel->have_fullscreen = TRUE;
+    }
+
+  if (private->modal_hint)
+    {
+      atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_STATE_MODAL");
+      ++i;
+    }
+
+  if (toplevel->skip_taskbar_hint)
+    {
+      atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_STATE_SKIP_TASKBAR");
+      ++i;
+    }
+
+  if (toplevel->skip_pager_hint)
+    {
+      atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+							"_NET_WM_STATE_SKIP_PAGER");
+      ++i;
+    }
+
+  if (i > 0)
+    {
+      XChangeProperty (xdisplay,
+                       xwindow,
+		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
+                       XA_ATOM, 32, PropModeReplace,
+                       (guchar*) atoms, i);
+    }
+  else 
+    {
+      XDeleteProperty (xdisplay,
+                       xwindow,
+		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"));
+    }
+
+  if (private->state & GDK_WINDOW_STATE_STICKY)
+    {
+      atoms[0] = 0xFFFFFFFF;
+      XChangeProperty (xdisplay,
+                       xwindow,
+		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
+                       XA_CARDINAL, 32, PropModeReplace,
+                       (guchar*) atoms, 1);
+      toplevel->on_all_desktops = TRUE;
+    }
+  else
+    {
+      XDeleteProperty (xdisplay,
+                       xwindow,
+		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"));
+    }
+
+  toplevel->map_serial = NextRequest (xdisplay);
+}
+
+static void
+gdk_window_x11_show (GdkWindow *window, gboolean already_mapped)
+{
+  GdkWindowObject *private = (GdkWindowObject*) window;
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+  GdkToplevelX11 *toplevel;
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
+  Display *xdisplay = GDK_WINDOW_XDISPLAY (window);
+  Window xwindow = GDK_WINDOW_XID (window);
+  gboolean unset_bg;
+
+  if (!already_mapped)
+    set_initial_hints (window);
+      
+  if (WINDOW_IS_TOPLEVEL (window))
+    {
+      display = gdk_window_get_display (window);
+      display_x11 = GDK_DISPLAY_X11 (display);
+      toplevel = _gdk_x11_window_get_toplevel (window);
+      
+      if (toplevel->user_time != 0 &&
+	      display_x11->user_time != 0 &&
+	  XSERVER_TIME_IS_LATER (display_x11->user_time, toplevel->user_time))
+	gdk_x11_window_set_user_time (window, display_x11->user_time);
+    }
+  
+  unset_bg = !private->input_only &&
+    (private->window_type == GDK_WINDOW_CHILD ||
+     impl->override_redirect) &&
+    gdk_window_is_viewable (window);
+  
+  if (unset_bg)
+    _gdk_x11_window_tmp_unset_bg (window, TRUE);
+  
+  XMapWindow (xdisplay, xwindow);
+  
+  if (unset_bg)
+    _gdk_x11_window_tmp_reset_bg (window, TRUE);
+}
+
+static void
+pre_unmap (GdkWindow *window)
+{
+  GdkWindow *start_window = NULL;
+  GdkWindowObject *private = (GdkWindowObject *)window;
+
+  if (private->input_only)
+    return;
+
+  if (private->window_type == GDK_WINDOW_CHILD)
+    start_window = _gdk_window_get_impl_window ((GdkWindow *)private->parent);
+  else if (private->window_type == GDK_WINDOW_TEMP)
+    start_window = get_root (window);
+
+  if (start_window)
+    _gdk_x11_window_tmp_unset_bg (start_window, TRUE);
+}
+
+static void
+post_unmap (GdkWindow *window)
+{
+  GdkWindow *start_window = NULL;
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  
+  if (private->input_only)
+    return;
+
+  if (private->window_type == GDK_WINDOW_CHILD)
+    start_window = _gdk_window_get_impl_window ((GdkWindow *)private->parent);
+  else if (private->window_type == GDK_WINDOW_TEMP)
+    start_window = get_root (window);
+
+  if (start_window)
+    {
+      _gdk_x11_window_tmp_reset_bg (start_window, TRUE);
+
+      if (private->window_type == GDK_WINDOW_CHILD && private->parent)
+	{
+	  GdkRectangle invalid_rect;
+      
+	  gdk_window_get_position (window, &invalid_rect.x, &invalid_rect.y);
+	  invalid_rect.width = gdk_window_get_width (window);
+	  invalid_rect.height = gdk_window_get_height (window);
+	  gdk_window_invalidate_rect ((GdkWindow *)private->parent,
+				      &invalid_rect, TRUE);
+	}
+    }
+}
+
+static void
+gdk_window_x11_hide (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  
+  private = (GdkWindowObject*) window;
+
+  /* We'll get the unmap notify eventually, and handle it then,
+   * but checking here makes things more consistent if we are
+   * just doing stuff ourself.
+   */
+  _gdk_xgrab_check_unmap (window,
+			  NextRequest (GDK_WINDOW_XDISPLAY (window)));
+
+  /* You can't simply unmap toplevel windows. */
+  switch (private->window_type)
+    {
+    case GDK_WINDOW_TOPLEVEL:
+    case GDK_WINDOW_TEMP: /* ? */
+      gdk_window_withdraw (window);
+      return;
+      
+    case GDK_WINDOW_FOREIGN:
+    case GDK_WINDOW_ROOT:
+    case GDK_WINDOW_CHILD:
+      break;
+    }
+  
+  _gdk_window_clear_update_area (window);
+  
+  pre_unmap (window);
+  XUnmapWindow (GDK_WINDOW_XDISPLAY (window),
+		GDK_WINDOW_XID (window));
+  post_unmap (window);
+}
+
+static void
+gdk_window_x11_withdraw (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  
+  private = (GdkWindowObject*) window;
+  if (!private->destroyed)
+    {
+      if (GDK_WINDOW_IS_MAPPED (window))
+        gdk_synthesize_window_state (window,
+                                     0,
+                                     GDK_WINDOW_STATE_WITHDRAWN);
+
+      g_assert (!GDK_WINDOW_IS_MAPPED (window));
+
+      pre_unmap (window);
+      
+      XWithdrawWindow (GDK_WINDOW_XDISPLAY (window),
+                       GDK_WINDOW_XID (window), 0);
+
+      post_unmap (window);
+    }
+}
+
+static inline void
+window_x11_move (GdkWindow *window,
+                 gint       x,
+                 gint       y)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+  if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
+    {
+      _gdk_window_move_resize_child (window,
+                                     x, y,
+                                     private->width, private->height);
+    }
+  else
+    {
+      XMoveWindow (GDK_WINDOW_XDISPLAY (window),
+                   GDK_WINDOW_XID (window),
+                   x, y);
+
+      if (impl->override_redirect)
+        {
+          private->x = x;
+          private->y = y;
+        }
+    }
+}
+
+static inline void
+window_x11_resize (GdkWindow *window,
+                   gint       width,
+                   gint       height)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+
+  if (width < 1)
+    width = 1;
+
+  if (height < 1)
+    height = 1;
+
+  if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
+    {
+      _gdk_window_move_resize_child (window,
+                                     private->x, private->y,
+                                     width, height);
+    }
+  else
+    {
+      GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+      XResizeWindow (GDK_WINDOW_XDISPLAY (window),
+                     GDK_WINDOW_XID (window),
+                     width, height);
+
+      if (impl->override_redirect)
+        {
+          private->width = width;
+          private->height = height;
+          _gdk_x11_drawable_update_size (private->impl);
+        }
+      else
+        {
+          if (width != private->width || height != private->height)
+            private->resize_count += 1;
+        }
+    }
+
+  _gdk_x11_drawable_update_size (private->impl);
+}
+
+static inline void
+window_x11_move_resize (GdkWindow *window,
+                        gint       x,
+                        gint       y,
+                        gint       width,
+                        gint       height)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;;
+  
+  if (width < 1)
+    width = 1;
+
+  if (height < 1)
+    height = 1;
+
+  if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
+    {
+      _gdk_window_move_resize_child (window, x, y, width, height);
+      _gdk_x11_drawable_update_size (private->impl);
+    }
+  else
+    {
+      GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+      XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
+                         GDK_WINDOW_XID (window),
+                         x, y, width, height);
+
+      if (impl->override_redirect)
+        {
+          private->x = x;
+          private->y = y;
+
+          private->width = width;
+          private->height = height;
+
+          _gdk_x11_drawable_update_size (private->impl);
+        }
+      else
+        {
+          if (width != private->width || height != private->height)
+            private->resize_count += 1;
+        }
+    }
+}
+
+static void
+gdk_window_x11_move_resize (GdkWindow *window,
+                            gboolean   with_move,
+                            gint       x,
+                            gint       y,
+                            gint       width,
+                            gint       height)
+{
+  if (with_move && (width < 0 && height < 0))
+    window_x11_move (window, x, y);
+  else
+    {
+      if (with_move)
+        window_x11_move_resize (window, x, y, width, height);
+      else
+        window_x11_resize (window, width, height);
+    }
+}
+
+static gboolean
+gdk_window_x11_reparent (GdkWindow *window,
+                         GdkWindow *new_parent,
+                         gint       x,
+                         gint       y)
+{
+  GdkWindowObject *window_private;
+  GdkWindowObject *parent_private;
+  GdkWindowImplX11 *impl;
+
+  window_private = (GdkWindowObject*) window;
+  parent_private = (GdkWindowObject*) new_parent;
+  impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+
+  _gdk_x11_window_tmp_unset_bg (window, TRUE);
+  _gdk_x11_window_tmp_unset_parent_bg (window);
+  XReparentWindow (GDK_WINDOW_XDISPLAY (window),
+		   GDK_WINDOW_XID (window),
+		   GDK_WINDOW_XID (new_parent),
+		   parent_private->abs_x + x, parent_private->abs_y + y);
+  _gdk_x11_window_tmp_reset_parent_bg (window);
+  _gdk_x11_window_tmp_reset_bg (window, TRUE);
+
+  if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
+    new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
+
+  window_private->parent = parent_private;
+
+  /* Switch the window type as appropriate */
+
+  switch (GDK_WINDOW_TYPE (new_parent))
+    {
+    case GDK_WINDOW_ROOT:
+    case GDK_WINDOW_FOREIGN:
+      /* Reparenting to toplevel */
+      
+      if (!WINDOW_IS_TOPLEVEL (window) &&
+	  GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
+	{
+	  /* This is also done in common code at a later stage, but we
+	     need it in setup_toplevel, so do it here too */
+	  if (window_private->toplevel_window_type != -1)
+	    GDK_WINDOW_TYPE (window) = window_private->toplevel_window_type;
+	  else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
+	    GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
+	  
+	  /* Wasn't a toplevel, set up */
+	  setup_toplevel_window (window, new_parent);
+	}
+
+      break;
+      
+    case GDK_WINDOW_TOPLEVEL:
+    case GDK_WINDOW_CHILD:
+    case GDK_WINDOW_TEMP:
+      if (WINDOW_IS_TOPLEVEL (window) &&
+	  impl->toplevel)
+	{
+	  if (impl->toplevel->focus_window)
+	    {
+	      XDestroyWindow (GDK_WINDOW_XDISPLAY (window), impl->toplevel->focus_window);
+	      _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), impl->toplevel->focus_window);
+	    }
+	  
+	  gdk_toplevel_x11_free_contents (GDK_WINDOW_DISPLAY (window), 
+					  impl->toplevel);
+	  g_free (impl->toplevel);
+	  impl->toplevel = NULL;
+	}
+    }
+
+  return FALSE;
+}
+
+static void
+gdk_window_x11_raise (GdkWindow *window)
+{
+  XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
+}
+
+static void
+gdk_window_x11_restack_under (GdkWindow *window,
+			      GList *native_siblings /* in requested order, first is bottom-most */)
+{
+  Window *windows;
+  int n_windows, i;
+  GList *l;
+
+  n_windows = g_list_length (native_siblings) + 1;
+  windows = g_new (Window, n_windows);
+
+  windows[0] = GDK_WINDOW_XID (window);
+  /* Reverse order, as input order is bottom-most first */
+  i = n_windows - 1;
+  for (l = native_siblings; l != NULL; l = l->next)
+    windows[i--] = GDK_WINDOW_XID (l->data);
+ 
+  XRestackWindows (GDK_WINDOW_XDISPLAY (window), windows, n_windows);
+  
+  g_free (windows);
+}
+
+static void
+gdk_window_x11_restack_toplevel (GdkWindow *window,
+				 GdkWindow *sibling,
+				 gboolean   above)
+{
+  XWindowChanges changes;
+
+  changes.sibling = GDK_WINDOW_XID (sibling);
+  changes.stack_mode = above ? Above : Below;
+  XReconfigureWMWindow (GDK_WINDOW_XDISPLAY (window),
+			GDK_WINDOW_XID (window),
+			gdk_screen_get_number (GDK_WINDOW_SCREEN (window)),
+			CWStackMode | CWSibling, &changes);
+}
+
+static void
+gdk_window_x11_lower (GdkWindow *window)
+{
+  XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
+}
+
+/**
+ * gdk_x11_window_move_to_current_desktop:
+ * @window: a #GdkWindow
+ * 
+ * Moves the window to the correct workspace when running under a 
+ * window manager that supports multiple workspaces, as described
+ * in the <ulink url="http://www.freedesktop.org/Standards/wm-spec";>Extended 
+ * Window Manager Hints</ulink>.  Will not do anything if the
+ * window is already on all workspaces.
+ * 
+ * Since: 2.8
+ */
+void
+gdk_x11_window_move_to_current_desktop (GdkWindow *window)
+{
+  GdkToplevelX11 *toplevel;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
+
+  toplevel = _gdk_x11_window_get_toplevel (window);
+
+  if (toplevel->on_all_desktops)
+    return;
+  
+  move_to_current_desktop (window);
+}
+
+static void
+move_to_current_desktop (GdkWindow *window)
+{
+  if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
+					   gdk_atom_intern_static_string ("_NET_WM_DESKTOP")))
+    {
+      Atom type;
+      gint format;
+      gulong nitems;
+      gulong bytes_after;
+      guchar *data;
+      gulong *current_desktop;
+      GdkDisplay *display;
+      
+      display = gdk_window_get_display (window);
+
+      /* Get current desktop, then set it; this is a race, but not
+       * one that matters much in practice.
+       */
+      XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), 
+                          GDK_WINDOW_XROOTWIN (window),
+			  gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"),
+                          0, G_MAXLONG,
+                          False, XA_CARDINAL, &type, &format, &nitems,
+                          &bytes_after, &data);
+
+      if (type == XA_CARDINAL)
+        {
+	  XClientMessageEvent xclient;
+	  current_desktop = (gulong *)data;
+	  
+	  memset (&xclient, 0, sizeof (xclient));
+          xclient.type = ClientMessage;
+          xclient.serial = 0;
+          xclient.send_event = True;
+          xclient.window = GDK_WINDOW_XWINDOW (window);
+	  xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP");
+          xclient.format = 32;
+
+          xclient.data.l[0] = *current_desktop;
+          xclient.data.l[1] = 0;
+          xclient.data.l[2] = 0;
+          xclient.data.l[3] = 0;
+          xclient.data.l[4] = 0;
+      
+          XSendEvent (GDK_DISPLAY_XDISPLAY (display), 
+                      GDK_WINDOW_XROOTWIN (window), 
+                      False,
+                      SubstructureRedirectMask | SubstructureNotifyMask,
+                      (XEvent *)&xclient);
+
+          XFree (current_desktop);
+        }
+    }
+}
+
+/**
+ * gdk_window_focus:
+ * @window: a #GdkWindow
+ * @timestamp: timestamp of the event triggering the window focus
+ *
+ * Sets keyboard focus to @window. In most cases, gtk_window_present() 
+ * should be used on a #GtkWindow, rather than calling this function.
+ * 
+ **/
+void
+gdk_window_focus (GdkWindow *window,
+                  guint32    timestamp)
+{
+  GdkDisplay *display;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  display = GDK_WINDOW_DISPLAY (window);
+
+  if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
+					   gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW")))
+    {
+      XClientMessageEvent xclient;
+
+      memset (&xclient, 0, sizeof (xclient));
+      xclient.type = ClientMessage;
+      xclient.window = GDK_WINDOW_XWINDOW (window);
+      xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
+									"_NET_ACTIVE_WINDOW");
+      xclient.format = 32;
+      xclient.data.l[0] = 1; /* requestor type; we're an app */
+      xclient.data.l[1] = timestamp;
+      xclient.data.l[2] = None; /* currently active window */
+      xclient.data.l[3] = 0;
+      xclient.data.l[4] = 0;
+      
+      XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
+                  SubstructureRedirectMask | SubstructureNotifyMask,
+                  (XEvent *)&xclient);
+    }
+  else
+    {
+      XRaiseWindow (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window));
+
+      /* There is no way of knowing reliably whether we are viewable;
+       * _gdk_x11_set_input_focus_safe() traps errors asynchronously.
+       */
+      _gdk_x11_set_input_focus_safe (display, GDK_WINDOW_XID (window),
+				     RevertToParent,
+				     timestamp);
+    }
+}
+
+/**
+ * gdk_window_set_type_hint:
+ * @window: A toplevel #GdkWindow
+ * @hint: A hint of the function this window will have
+ *
+ * The application can use this call to provide a hint to the window
+ * manager about the functionality of a window. The window manager
+ * can use this information when determining the decoration and behaviour
+ * of the window.
+ *
+ * The hint must be set before the window is mapped.
+ **/
+void
+gdk_window_set_type_hint (GdkWindow        *window,
+			  GdkWindowTypeHint hint)
+{
+  GdkDisplay *display;
+  Atom atom;
+  
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  display = gdk_window_get_display (window);
+
+  switch (hint)
+    {
+    case GDK_WINDOW_TYPE_HINT_DIALOG:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG");
+      break;
+    case GDK_WINDOW_TYPE_HINT_MENU:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU");
+      break;
+    case GDK_WINDOW_TYPE_HINT_TOOLBAR:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR");
+      break;
+    case GDK_WINDOW_TYPE_HINT_UTILITY:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY");
+      break;
+    case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH");
+      break;
+    case GDK_WINDOW_TYPE_HINT_DOCK:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK");
+      break;
+    case GDK_WINDOW_TYPE_HINT_DESKTOP:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP");
+      break;
+    case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU");
+      break;
+    case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_POPUP_MENU");
+      break;
+    case GDK_WINDOW_TYPE_HINT_TOOLTIP:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLTIP");
+      break;
+    case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NOTIFICATION");
+      break;
+    case GDK_WINDOW_TYPE_HINT_COMBO:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_COMBO");
+      break;
+    case GDK_WINDOW_TYPE_HINT_DND:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DND");
+      break;
+    default:
+      g_warning ("Unknown hint %d passed to gdk_window_set_type_hint", hint);
+      /* Fall thru */
+    case GDK_WINDOW_TYPE_HINT_NORMAL:
+      atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NORMAL");
+      break;
+    }
+
+  XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+		   gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
+		   XA_ATOM, 32, PropModeReplace,
+		   (guchar *)&atom, 1);
+}
+
+/**
+ * gdk_window_get_type_hint:
+ * @window: A toplevel #GdkWindow
+ *
+ * This function returns the type hint set for a window.
+ *
+ * Return value: The type hint set for @window
+ *
+ * Since: 2.10
+ **/
+GdkWindowTypeHint
+gdk_window_get_type_hint (GdkWindow *window)
+{
+  GdkDisplay *display;
+  GdkWindowTypeHint type;
+  Atom type_return;
+  gint format_return;
+  gulong nitems_return;
+  gulong bytes_after_return;
+  guchar *data = NULL;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return GDK_WINDOW_TYPE_HINT_NORMAL;
+
+  type = GDK_WINDOW_TYPE_HINT_NORMAL;
+
+  display = gdk_window_get_display (window);
+
+  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+                          gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
+                          0, G_MAXLONG, False, XA_ATOM, &type_return,
+                          &format_return, &nitems_return, &bytes_after_return,
+                          &data) == Success)
+    {
+      if ((type_return == XA_ATOM) && (format_return == 32) &&
+          (data) && (nitems_return == 1))
+        {
+          Atom atom = *(Atom*)data;
+
+          if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG"))
+            type = GDK_WINDOW_TYPE_HINT_DIALOG;
+          else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU"))
+            type = GDK_WINDOW_TYPE_HINT_MENU;
+          else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR"))
+            type = GDK_WINDOW_TYPE_HINT_TOOLBAR;
+          else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY"))
+            type = GDK_WINDOW_TYPE_HINT_UTILITY;
+          else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH"))
+            type = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
+          else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK"))
+            type = GDK_WINDOW_TYPE_HINT_DOCK;
+          else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP"))
+            type = GDK_WINDOW_TYPE_HINT_DESKTOP;
+	  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"))
+	    type = GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU;
+	  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_POPUP_MENU"))
+	    type = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
+	  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLTIP"))
+	    type = GDK_WINDOW_TYPE_HINT_TOOLTIP;
+	  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NOTIFICATION"))
+	    type = GDK_WINDOW_TYPE_HINT_NOTIFICATION;
+	  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_COMBO"))
+	    type = GDK_WINDOW_TYPE_HINT_COMBO;
+	  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DND"))
+	    type = GDK_WINDOW_TYPE_HINT_DND;
+        }
+
+      if (type_return != None && data != NULL)
+        XFree (data);
+    }
+
+  return type;
+}
+
+static void
+gdk_wmspec_change_state (gboolean   add,
+			 GdkWindow *window,
+			 GdkAtom    state1,
+			 GdkAtom    state2)
+{
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+  XClientMessageEvent xclient;
+  
+#define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
+#define _NET_WM_STATE_ADD           1    /* add/set property */
+#define _NET_WM_STATE_TOGGLE        2    /* toggle property  */  
+  
+  memset (&xclient, 0, sizeof (xclient));
+  xclient.type = ClientMessage;
+  xclient.window = GDK_WINDOW_XID (window);
+  xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE");
+  xclient.format = 32;
+  xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+  xclient.data.l[1] = gdk_x11_atom_to_xatom_for_display (display, state1);
+  xclient.data.l[2] = gdk_x11_atom_to_xatom_for_display (display, state2);
+  xclient.data.l[3] = 0;
+  xclient.data.l[4] = 0;
+  
+  XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
+	      SubstructureRedirectMask | SubstructureNotifyMask,
+	      (XEvent *)&xclient);
+}
+
+/**
+ * gdk_window_set_modal_hint:
+ * @window: A toplevel #GdkWindow
+ * @modal: %TRUE if the window is modal, %FALSE otherwise.
+ *
+ * The application can use this hint to tell the window manager
+ * that a certain window has modal behaviour. The window manager
+ * can use this information to handle modal windows in a special
+ * way.
+ *
+ * You should only use this on windows for which you have
+ * previously called gdk_window_set_transient_for()
+ **/
+void
+gdk_window_set_modal_hint (GdkWindow *window,
+			   gboolean   modal)
+{
+  GdkWindowObject *private;
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  private = (GdkWindowObject*) window;
+
+  private->modal_hint = modal;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    gdk_wmspec_change_state (modal, window,
+			     gdk_atom_intern_static_string ("_NET_WM_STATE_MODAL"), 
+			     GDK_NONE);
+}
+
+/**
+ * gdk_window_set_skip_taskbar_hint:
+ * @window: a toplevel #GdkWindow
+ * @skips_taskbar: %TRUE to skip the taskbar
+ * 
+ * Toggles whether a window should appear in a task list or window
+ * list. If a window's semantic type as specified with
+ * gdk_window_set_type_hint() already fully describes the window, this
+ * function should <emphasis>not</emphasis> be called in addition, 
+ * instead you should allow the window to be treated according to 
+ * standard policy for its semantic type.
+ *
+ * Since: 2.2
+ **/
+void
+gdk_window_set_skip_taskbar_hint (GdkWindow *window,
+                                  gboolean   skips_taskbar)
+{
+  GdkToplevelX11 *toplevel;
+  
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
+  
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  toplevel = _gdk_x11_window_get_toplevel (window);
+  toplevel->skip_taskbar_hint = skips_taskbar;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    gdk_wmspec_change_state (skips_taskbar, window,
+			     gdk_atom_intern_static_string ("_NET_WM_STATE_SKIP_TASKBAR"),
+			     GDK_NONE);
+}
+
+/**
+ * gdk_window_set_skip_pager_hint:
+ * @window: a toplevel #GdkWindow
+ * @skips_pager: %TRUE to skip the pager
+ * 
+ * Toggles whether a window should appear in a pager (workspace
+ * switcher, or other desktop utility program that displays a small
+ * thumbnail representation of the windows on the desktop). If a
+ * window's semantic type as specified with gdk_window_set_type_hint()
+ * already fully describes the window, this function should 
+ * <emphasis>not</emphasis> be called in addition, instead you should 
+ * allow the window to be treated according to standard policy for 
+ * its semantic type.
+ *
+ * Since: 2.2
+ **/
+void
+gdk_window_set_skip_pager_hint (GdkWindow *window,
+                                gboolean   skips_pager)
+{
+  GdkToplevelX11 *toplevel;
+    
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
+  
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  toplevel = _gdk_x11_window_get_toplevel (window);
+  toplevel->skip_pager_hint = skips_pager;
+  
+  if (GDK_WINDOW_IS_MAPPED (window))
+    gdk_wmspec_change_state (skips_pager, window,
+			     gdk_atom_intern_static_string ("_NET_WM_STATE_SKIP_PAGER"), 
+			     GDK_NONE);
+}
+
+/**
+ * gdk_window_set_urgency_hint:
+ * @window: a toplevel #GdkWindow
+ * @urgent: %TRUE if the window is urgent
+ * 
+ * Toggles whether a window needs the user's
+ * urgent attention.
+ *
+ * Since: 2.8
+ **/
+void
+gdk_window_set_urgency_hint (GdkWindow *window,
+			     gboolean   urgent)
+{
+  GdkToplevelX11 *toplevel;
+    
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
+  
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  toplevel = _gdk_x11_window_get_toplevel (window);
+  toplevel->urgency_hint = urgent;
+  
+  update_wm_hints (window, FALSE);
+}
+
+/**
+ * gdk_window_set_geometry_hints:
+ * @window: a toplevel #GdkWindow
+ * @geometry: geometry hints
+ * @geom_mask: bitmask indicating fields of @geometry to pay attention to
+ *
+ * Sets the geometry hints for @window. Hints flagged in @geom_mask
+ * are set, hints not flagged in @geom_mask are unset.
+ * To unset all hints, use a @geom_mask of 0 and a @geometry of %NULL.
+ *
+ * This function provides hints to the windowing system about
+ * acceptable sizes for a toplevel window. The purpose of 
+ * this is to constrain user resizing, but the windowing system
+ * will typically  (but is not required to) also constrain the
+ * current size of the window to the provided values and
+ * constrain programatic resizing via gdk_window_resize() or
+ * gdk_window_move_resize().
+ * 
+ * Note that on X11, this effect has no effect on windows
+ * of type %GDK_WINDOW_TEMP or windows where override redirect
+ * has been turned on via gdk_window_set_override_redirect()
+ * since these windows are not resizable by the user.
+ * 
+ * Since you can't count on the windowing system doing the
+ * constraints for programmatic resizes, you should generally
+ * call gdk_window_constrain_size() yourself to determine
+ * appropriate sizes.
+ *
+ **/
+void 
+gdk_window_set_geometry_hints (GdkWindow         *window,
+			       const GdkGeometry *geometry,
+			       GdkWindowHints     geom_mask)
+{
+  XSizeHints size_hints;
+  
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+  
+  size_hints.flags = 0;
+  
+  if (geom_mask & GDK_HINT_POS)
+    {
+      size_hints.flags |= PPosition;
+      /* We need to initialize the following obsolete fields because KWM 
+       * apparently uses these fields if they are non-zero.
+       * # #!#!$! 
+       */
+      size_hints.x = 0;
+      size_hints.y = 0;
+    }
+
+  if (geom_mask & GDK_HINT_USER_POS)
+    {
+      size_hints.flags |= USPosition;
+    }
+
+  if (geom_mask & GDK_HINT_USER_SIZE)
+    {
+      size_hints.flags |= USSize;
+    }
+  
+  if (geom_mask & GDK_HINT_MIN_SIZE)
+    {
+      size_hints.flags |= PMinSize;
+      size_hints.min_width = geometry->min_width;
+      size_hints.min_height = geometry->min_height;
+    }
+  
+  if (geom_mask & GDK_HINT_MAX_SIZE)
+    {
+      size_hints.flags |= PMaxSize;
+      size_hints.max_width = MAX (geometry->max_width, 1);
+      size_hints.max_height = MAX (geometry->max_height, 1);
+    }
+  
+  if (geom_mask & GDK_HINT_BASE_SIZE)
+    {
+      size_hints.flags |= PBaseSize;
+      size_hints.base_width = geometry->base_width;
+      size_hints.base_height = geometry->base_height;
+    }
+  
+  if (geom_mask & GDK_HINT_RESIZE_INC)
+    {
+      size_hints.flags |= PResizeInc;
+      size_hints.width_inc = geometry->width_inc;
+      size_hints.height_inc = geometry->height_inc;
+    }
+  
+  if (geom_mask & GDK_HINT_ASPECT)
+    {
+      size_hints.flags |= PAspect;
+      if (geometry->min_aspect <= 1)
+	{
+	  size_hints.min_aspect.x = 65536 * geometry->min_aspect;
+	  size_hints.min_aspect.y = 65536;
+	}
+      else
+	{
+	  size_hints.min_aspect.x = 65536;
+	  size_hints.min_aspect.y = 65536 / geometry->min_aspect;;
+	}
+      if (geometry->max_aspect <= 1)
+	{
+	  size_hints.max_aspect.x = 65536 * geometry->max_aspect;
+	  size_hints.max_aspect.y = 65536;
+	}
+      else
+	{
+	  size_hints.max_aspect.x = 65536;
+	  size_hints.max_aspect.y = 65536 / geometry->max_aspect;;
+	}
+    }
+
+  if (geom_mask & GDK_HINT_WIN_GRAVITY)
+    {
+      size_hints.flags |= PWinGravity;
+      size_hints.win_gravity = geometry->win_gravity;
+    }
+  
+  /* FIXME: Would it be better to delete this property if
+   *        geom_mask == 0? It would save space on the server
+   */
+  XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
+		     GDK_WINDOW_XID (window),
+		     &size_hints);
+}
+
+static void
+gdk_window_get_geometry_hints (GdkWindow      *window,
+                               GdkGeometry    *geometry,
+                               GdkWindowHints *geom_mask)
+{
+  XSizeHints *size_hints;  
+  glong junk_supplied_mask = 0;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (geometry != NULL);
+  g_return_if_fail (geom_mask != NULL);
+
+  *geom_mask = 0;
+  
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  size_hints = XAllocSizeHints ();
+  if (!size_hints)
+    return;
+  
+  if (!XGetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
+                          GDK_WINDOW_XID (window),
+                          size_hints,
+                          &junk_supplied_mask))
+    size_hints->flags = 0;
+
+  if (size_hints->flags & PMinSize)
+    {
+      *geom_mask |= GDK_HINT_MIN_SIZE;
+      geometry->min_width = size_hints->min_width;
+      geometry->min_height = size_hints->min_height;
+    }
+
+  if (size_hints->flags & PMaxSize)
+    {
+      *geom_mask |= GDK_HINT_MAX_SIZE;
+      geometry->max_width = MAX (size_hints->max_width, 1);
+      geometry->max_height = MAX (size_hints->max_height, 1);
+    }
+
+  if (size_hints->flags & PResizeInc)
+    {
+      *geom_mask |= GDK_HINT_RESIZE_INC;
+      geometry->width_inc = size_hints->width_inc;
+      geometry->height_inc = size_hints->height_inc;
+    }
+
+  if (size_hints->flags & PAspect)
+    {
+      *geom_mask |= GDK_HINT_ASPECT;
+
+      geometry->min_aspect = (gdouble) size_hints->min_aspect.x / (gdouble) size_hints->min_aspect.y;
+      geometry->max_aspect = (gdouble) size_hints->max_aspect.x / (gdouble) size_hints->max_aspect.y;
+    }
+
+  if (size_hints->flags & PWinGravity)
+    {
+      *geom_mask |= GDK_HINT_WIN_GRAVITY;
+      geometry->win_gravity = size_hints->win_gravity;
+    }
+
+  XFree (size_hints);
+}
+
+static gboolean
+utf8_is_latin1 (const gchar *str)
+{
+  const char *p = str;
+
+  while (*p)
+    {
+      gunichar ch = g_utf8_get_char (p);
+
+      if (ch > 0xff)
+	return FALSE;
+      
+      p = g_utf8_next_char (p);
+    }
+
+  return TRUE;
+}
+
+/* Set the property to @utf8_str as STRING if the @utf8_str is fully
+ * convertable to STRING, otherwise, set it as compound text
+ */
+static void
+set_text_property (GdkDisplay  *display,
+		   Window       xwindow,
+		   Atom         property,
+		   const gchar *utf8_str)
+{
+  gchar *prop_text = NULL;
+  Atom prop_type;
+  gint prop_length;
+  gint prop_format;
+  gboolean is_compound_text;
+  
+  if (utf8_is_latin1 (utf8_str))
+    {
+      prop_type = XA_STRING;
+      prop_text = gdk_utf8_to_string_target (utf8_str);
+      prop_length = prop_text ? strlen (prop_text) : 0;
+      prop_format = 8;
+      is_compound_text = FALSE;
+    }
+  else
+    {
+      GdkAtom gdk_type;
+      
+      gdk_utf8_to_compound_text_for_display (display,
+					     utf8_str, &gdk_type, &prop_format,
+					     (guchar **)&prop_text, &prop_length);
+      prop_type = gdk_x11_atom_to_xatom_for_display (display, gdk_type);
+      is_compound_text = TRUE;
+    }
+
+  if (prop_text)
+    {
+      XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+		       xwindow,
+		       property,
+		       prop_type, prop_format,
+		       PropModeReplace, (guchar *)prop_text,
+		       prop_length);
+
+      if (is_compound_text)
+	gdk_free_compound_text ((guchar *)prop_text);
+      else
+	g_free (prop_text);
+    }
+}
+
+/* Set WM_NAME and _NET_WM_NAME
+ */
+static void
+set_wm_name (GdkDisplay  *display,
+	     Window       xwindow,
+	     const gchar *name)
+{
+  XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
+		   gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME"),
+		   gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+		   PropModeReplace, (guchar *)name, strlen (name));
+  
+  set_text_property (display, xwindow,
+		     gdk_x11_get_xatom_by_name_for_display (display, "WM_NAME"),
+		     name);
+}
+
+/**
+ * gdk_window_set_title:
+ * @window: a toplevel #GdkWindow
+ * @title: title of @window
+ *
+ * Sets the title of a toplevel window, to be displayed in the titlebar.
+ * If you haven't explicitly set the icon name for the window
+ * (using gdk_window_set_icon_name()), the icon name will be set to
+ * @title as well. @title must be in UTF-8 encoding (as with all
+ * user-readable strings in GDK/GTK+). @title may not be %NULL.
+ **/
+void
+gdk_window_set_title (GdkWindow   *window,
+		      const gchar *title)
+{
+  GdkDisplay *display;
+  Display *xdisplay;
+  Window xwindow;
+  
+  g_return_if_fail (title != NULL);
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+  
+  display = gdk_window_get_display (window);
+  xdisplay = GDK_DISPLAY_XDISPLAY (display);
+  xwindow = GDK_WINDOW_XID (window);
+
+  set_wm_name (display, xwindow, title);
+  
+  if (!gdk_window_icon_name_set (window))
+    {
+      XChangeProperty (xdisplay, xwindow,
+		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
+		       gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+		       PropModeReplace, (guchar *)title, strlen (title));
+      
+      set_text_property (display, xwindow,
+			 gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
+			 title);
+    }
+}
+
+/**
+ * gdk_window_set_role:
+ * @window: a toplevel #GdkWindow
+ * @role: a string indicating its role
+ *
+ * When using GTK+, typically you should use gtk_window_set_role() instead
+ * of this low-level function.
+ * 
+ * The window manager and session manager use a window's role to
+ * distinguish it from other kinds of window in the same application.
+ * When an application is restarted after being saved in a previous
+ * session, all windows with the same title and role are treated as
+ * interchangeable.  So if you have two windows with the same title
+ * that should be distinguished for session management purposes, you
+ * should set the role on those windows. It doesn't matter what string
+ * you use for the role, as long as you have a different role for each
+ * non-interchangeable kind of window.
+ * 
+ **/
+void          
+gdk_window_set_role (GdkWindow   *window,
+		     const gchar *role)
+{
+  GdkDisplay *display;
+
+  display = gdk_window_get_display (window);
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (role)
+    XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+                     gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"),
+                     XA_STRING, 8, PropModeReplace, (guchar *)role, strlen (role));
+  else
+    XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+                     gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"));
+}
+
+/**
+ * gdk_window_set_startup_id:
+ * @window: a toplevel #GdkWindow
+ * @startup_id: a string with startup-notification identifier
+ *
+ * When using GTK+, typically you should use gtk_window_set_startup_id()
+ * instead of this low-level function.
+ *
+ * Since: 2.12
+ *
+ **/
+void
+gdk_window_set_startup_id (GdkWindow   *window,
+			   const gchar *startup_id)
+{
+  GdkDisplay *display;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  display = gdk_window_get_display (window);
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (startup_id)
+    XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+                     gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"), 
+                     gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+                     PropModeReplace, (unsigned char *)startup_id, strlen (startup_id));
+  else
+    XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+                     gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"));
+}
+
+/**
+ * gdk_window_set_transient_for:
+ * @window: a toplevel #GdkWindow
+ * @parent: another toplevel #GdkWindow
+ *
+ * Indicates to the window manager that @window is a transient dialog
+ * associated with the application window @parent. This allows the
+ * window manager to do things like center @window on @parent and
+ * keep @window above @parent.
+ *
+ * See gtk_window_set_transient_for() if you're using #GtkWindow or
+ * #GtkDialog.
+ **/
+void
+gdk_window_set_transient_for (GdkWindow *window,
+			      GdkWindow *parent)
+{
+  if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent) &&
+      WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), 
+			  GDK_WINDOW_XID (window),
+			  GDK_WINDOW_XID (parent));
+}
+
+static gboolean
+gdk_window_x11_set_back_color (GdkWindow *window,
+                               double     red,
+                               double     green,
+                               double     blue,
+                               double     alpha)
+{
+  GdkVisual *visual = gdk_window_get_visual (window);
+
+  /* I suppose we could handle these, but that'd require fiddling with 
+   * xrender formats... */
+  if (alpha != 1.0)
+    return FALSE;
+
+  switch (visual->type)
+    {
+    case GDK_VISUAL_DIRECT_COLOR:
+    case GDK_VISUAL_TRUE_COLOR:
+	{
+	  /* If bits not used for color are used for something other than padding,
+	   * it's likely alpha, so we set them to 1s.
+	   */
+	  guint padding, pixel;
+
+	  /* Shifting by >= width-of-type isn't defined in C */
+	  if (visual->depth >= 32)
+	    padding = 0;
+	  else
+	    padding = ((~(guint32)0)) << visual->depth;
+	  
+	  pixel = ~ (visual->red_mask | visual->green_mask | visual->blue_mask | padding);
+	  
+	  pixel += (((int) (red   * ((1 << visual->red_prec  ) - 1))) << visual->red_shift  ) +
+		   (((int) (green * ((1 << visual->green_prec) - 1))) << visual->green_shift) +
+		   (((int) (blue  * ((1 << visual->blue_prec ) - 1))) << visual->blue_shift );
+
+          XSetWindowBackground (GDK_WINDOW_XDISPLAY (window),
+                                GDK_WINDOW_XID (window), pixel);
+	}
+      return TRUE;
+
+    /* These require fiddling with the colormap, and as they're essentially unused
+     * we're just gonna skip them for now.
+     */
+    case GDK_VISUAL_PSEUDO_COLOR:
+    case GDK_VISUAL_GRAYSCALE:
+    case GDK_VISUAL_STATIC_GRAY:
+    case GDK_VISUAL_STATIC_COLOR:
+    default:
+      break;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+matrix_is_identity (cairo_matrix_t *matrix)
+{
+  return matrix->xx == 1.0 && matrix->yy == 1.0 &&
+    matrix->yx == 0.0 && matrix->xy == 0.0 &&
+    matrix->x0 == 0.0 && matrix->y0 == 0.0;
+}
+
+static void
+gdk_window_x11_set_background (GdkWindow      *window,
+                               cairo_pattern_t *pattern)
+{
+  double r, g, b, a;
+  cairo_surface_t *surface;
+  cairo_matrix_t matrix;
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  if (pattern == NULL)
+    {
+      GdkWindow *parent;
+
+      /* X throws BadMatch if the parent has a different visual when
+       * using ParentRelative */
+      parent = gdk_window_get_parent (window);
+      if (parent && gdk_window_get_visual (parent) == gdk_window_get_visual (window))
+        XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
+                                    GDK_WINDOW_XID (window), ParentRelative);
+      else
+        XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
+                                    GDK_WINDOW_XID (window), None);
+      return;
+    }
+
+  switch (cairo_pattern_get_type (pattern))
+    {
+    case CAIRO_PATTERN_TYPE_SOLID:
+      cairo_pattern_get_rgba (pattern, &r, &g, &b, &a);
+      if (gdk_window_x11_set_back_color (window, r, g, b, a))
+        return;
+      break;
+    case CAIRO_PATTERN_TYPE_SURFACE:
+      cairo_pattern_get_matrix (pattern, &matrix);
+      if (cairo_pattern_get_surface (pattern, &surface) == CAIRO_STATUS_SUCCESS &&
+          matrix_is_identity (&matrix) &&
+          cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB &&
+          cairo_xlib_surface_get_visual (surface) == GDK_VISUAL_XVISUAL (gdk_window_get_visual ((window))) &&
+          cairo_xlib_surface_get_display (surface) == GDK_WINDOW_XDISPLAY (window))
+        {
+          double x, y;
+
+          cairo_surface_get_device_offset (surface, &x, &y);
+          /* XXX: This still bombs for non-pixmaps, but there's no way to
+           * detect we're not a pixmap in Cairo... */
+          if (x == 0.0 && y == 0.0)
+            {
+              XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
+                                          GDK_WINDOW_XID (window),
+                                          cairo_xlib_surface_get_drawable (surface));
+              return;
+            }
+        }
+      /* fall through */
+    case CAIRO_PATTERN_TYPE_LINEAR:
+    case CAIRO_PATTERN_TYPE_RADIAL:
+    default:
+      /* fallback: just use black */
+      break;
+    }
+
+  XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
+                              GDK_WINDOW_XID (window), None);
+}
+
+static void
+gdk_window_x11_set_device_cursor (GdkWindow *window,
+                                  GdkDevice *device,
+                                  GdkCursor *cursor)
+{
+  GdkWindowObject *private;
+  GdkWindowImplX11 *impl;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_DEVICE (device));
+
+  private = (GdkWindowObject *) window;
+  impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+  if (!cursor)
+    g_hash_table_remove (impl->device_cursor, device);
+  else
+    {
+      _gdk_x11_cursor_update_theme (cursor);
+      g_hash_table_replace (impl->device_cursor,
+                            device, gdk_cursor_ref (cursor));
+    }
+
+  if (!GDK_WINDOW_DESTROYED (window))
+    GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
+}
+
+GdkCursor *
+_gdk_x11_window_get_cursor (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  GdkWindowImplX11 *impl;
+  
+  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+    
+  private = (GdkWindowObject *)window;
+  impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+  return impl->cursor;
+}
+
+static void
+gdk_window_x11_get_geometry (GdkWindow *window,
+                             gint      *x,
+                             gint      *y,
+                             gint      *width,
+                             gint      *height,
+                             gint      *depth)
+{
+  Window root;
+  gint tx;
+  gint ty;
+  guint twidth;
+  guint theight;
+  guint tborder_width;
+  guint tdepth;
+  
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      XGetGeometry (GDK_WINDOW_XDISPLAY (window),
+		    GDK_WINDOW_XID (window),
+		    &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
+      
+      if (x)
+	*x = tx;
+      if (y)
+	*y = ty;
+      if (width)
+	*width = twidth;
+      if (height)
+	*height = theight;
+      if (depth)
+	*depth = tdepth;
+    }
+}
+
+static gint
+gdk_window_x11_get_root_coords (GdkWindow *window,
+				gint       x,
+				gint       y,
+				gint      *root_x,
+				gint      *root_y)
+{
+  gint return_val;
+  Window child;
+  gint tx;
+  gint ty;
+  
+  return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
+				      GDK_WINDOW_XID (window),
+				      GDK_WINDOW_XROOTWIN (window),
+				      x, y, &tx, &ty,
+				      &child);
+  
+  if (root_x)
+    *root_x = tx;
+  if (root_y)
+    *root_y = ty;
+  
+  return return_val;
+}
+
+/**
+ * gdk_window_get_root_origin:
+ * @window: a toplevel #GdkWindow
+ * @x: return location for X position of window frame
+ * @y: return location for Y position of window frame
+ *
+ * Obtains the top-left corner of the window manager frame in root
+ * window coordinates.
+ * 
+ **/
+void
+gdk_window_get_root_origin (GdkWindow *window,
+			    gint      *x,
+			    gint      *y)
+{
+  GdkRectangle rect;
+
+  gdk_window_get_frame_extents (window, &rect);
+
+  if (x)
+    *x = rect.x;
+
+  if (y)
+    *y = rect.y;
+}
+
+/**
+ * gdk_window_get_frame_extents:
+ * @window: a toplevel #GdkWindow
+ * @rect: rectangle to fill with bounding box of the window frame
+ *
+ * Obtains the bounding box of the window, including window manager
+ * titlebar/borders if any. The frame position is given in root window
+ * coordinates. To get the position of the window itself (rather than
+ * the frame) in root window coordinates, use gdk_window_get_origin().
+ * 
+ **/
+void
+gdk_window_get_frame_extents (GdkWindow    *window,
+                              GdkRectangle *rect)
+{
+  GdkDisplay *display;
+  GdkWindowObject *private;
+  GdkWindowImplX11 *impl;
+  Window xwindow;
+  Window xparent;
+  Window root;
+  Window child;
+  Window *children;
+  guchar *data;
+  Window *vroots;
+  Atom type_return;
+  guint nchildren;
+  guint nvroots;
+  gulong nitems_return;
+  gulong bytes_after_return;
+  gint format_return;
+  gint i;
+  guint ww, wh, wb, wd;
+  gint wx, wy;
+  gboolean got_frame_extents = FALSE;
+  
+  g_return_if_fail (rect != NULL);
+  
+  private = (GdkWindowObject*) window;
+  
+  rect->x = 0;
+  rect->y = 0;
+  rect->width = 1;
+  rect->height = 1;
+  
+  while (private->parent && ((GdkWindowObject*) private->parent)->parent)
+    private = (GdkWindowObject*) private->parent;
+
+  /* Refine our fallback answer a bit using local information */
+  rect->x = private->x;
+  rect->y = private->y;
+  rect->width = private->width;
+  rect->height = private->height;
+
+  impl = GDK_WINDOW_IMPL_X11 (private->impl);
+  if (GDK_WINDOW_DESTROYED (private) || impl->override_redirect)
+    return;
+
+  nvroots = 0;
+  vroots = NULL;
+
+  gdk_error_trap_push();
+  
+  display = gdk_window_get_display (window);
+  xwindow = GDK_WINDOW_XID (window);
+
+  /* first try: use _NET_FRAME_EXTENTS */
+  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
+			  gdk_x11_get_xatom_by_name_for_display (display,
+								 "_NET_FRAME_EXTENTS"),
+			  0, G_MAXLONG, False, XA_CARDINAL, &type_return,
+			  &format_return, &nitems_return, &bytes_after_return,
+			  &data)
+      == Success)
+    {
+      if ((type_return == XA_CARDINAL) && (format_return == 32) &&
+	  (nitems_return == 4) && (data))
+        {
+	  gulong *ldata = (gulong *) data;
+	  got_frame_extents = TRUE;
+
+	  /* try to get the real client window geometry */
+	  if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow,
+			    &root, &wx, &wy, &ww, &wh, &wb, &wd) &&
+              XTranslateCoordinates (GDK_DISPLAY_XDISPLAY (display),
+	  			     xwindow, root, 0, 0, &wx, &wy, &child))
+            {
+	      rect->x = wx;
+	      rect->y = wy;
+	      rect->width = ww;
+	      rect->height = wh;
+	    }
+
+	  /* _NET_FRAME_EXTENTS format is left, right, top, bottom */
+	  rect->x -= ldata[0];
+	  rect->y -= ldata[2];
+	  rect->width += ldata[0] + ldata[1];
+	  rect->height += ldata[2] + ldata[3];
+	}
+
+      if (data)
+	XFree (data);
+    }
+
+  if (got_frame_extents)
+    goto out;
+
+  /* no frame extents property available, which means we either have a WM that
+     is not EWMH compliant or is broken - try fallback and walk up the window
+     tree to get our window's parent which hopefully is the window frame */
+
+  /* use NETWM_VIRTUAL_ROOTS if available */
+  root = GDK_WINDOW_XROOTWIN (window);
+
+  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), root,
+			  gdk_x11_get_xatom_by_name_for_display (display, 
+								 "_NET_VIRTUAL_ROOTS"),
+			  0, G_MAXLONG, False, XA_WINDOW, &type_return,
+			  &format_return, &nitems_return, &bytes_after_return,
+			  &data)
+      == Success)
+    {
+      if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
+	{
+	  nvroots = nitems_return;
+	  vroots = (Window *)data;
+	}
+    }
+
+  xparent = GDK_WINDOW_XID (window);
+
+  do
+    {
+      xwindow = xparent;
+
+      if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xwindow,
+		       &root, &xparent,
+		       &children, &nchildren))
+	goto out;
+      
+      if (children)
+	XFree (children);
+
+      /* check virtual roots */
+      for (i = 0; i < nvroots; i++)
+	{
+	  if (xparent == vroots[i])
+	    {
+	      root = xparent;
+	      break;
+           }
+	}
+    }
+  while (xparent != root);
+  
+  if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow, 
+		    &root, &wx, &wy, &ww, &wh, &wb, &wd))
+    {
+      rect->x = wx;
+      rect->y = wy;
+      rect->width = ww;
+      rect->height = wh;
+    }
+
+ out:
+  if (vroots)
+    XFree (vroots);
+
+  gdk_error_trap_pop_ignored ();
+}
+
+void
+_gdk_windowing_get_device_state (GdkDisplay       *display,
+                                 GdkDevice        *device,
+                                 GdkScreen       **screen,
+                                 gint             *x,
+                                 gint             *y,
+                                 GdkModifierType  *mask)
+{
+  GdkScreen *default_screen;
+
+  if (display->closed)
+    return;
+
+  default_screen = gdk_display_get_default_screen (display);
+
+
+  if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+    {
+      GdkWindow *root;
+
+      GDK_DEVICE_GET_CLASS (device)->query_state (device,
+                                                  gdk_screen_get_root_window (default_screen),
+                                                  &root, NULL,
+                                                  x, y,
+                                                  NULL, NULL,
+                                                  mask);
+      *screen = gdk_window_get_screen (root);
+    }
+  else
+    {
+      XSetWindowAttributes attributes;
+      Display *xdisplay;
+      Window xwindow, w, root, child;
+      int rootx, rooty, winx, winy;
+      unsigned int xmask;
+
+      /* FIXME: untrusted clients not multidevice-safe */
+
+      xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
+      xwindow = GDK_SCREEN_XROOTWIN (default_screen);
+
+      w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
+			 CopyFromParent, InputOnly, CopyFromParent,
+			 0, &attributes);
+      XQueryPointer (xdisplay, w,
+		     &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+      XDestroyWindow (xdisplay, w);
+
+      if (root != None)
+        {
+          GdkWindow *gdk_root = gdk_window_lookup_for_display (display, root);
+          *screen = gdk_window_get_screen (gdk_root);
+        }
+
+      *x = rootx;
+      *y = rooty;
+      *mask = xmask;
+    }
+}
+
+static gboolean
+gdk_window_x11_get_device_state (GdkWindow       *window,
+                                 GdkDevice       *device,
+                                 gint            *x,
+                                 gint            *y,
+                                 GdkModifierType *mask)
+{
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+  gboolean return_val;
+
+  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
+
+  return_val = TRUE;
+
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+	{
+          GdkWindow *child;
+
+          GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
+                                                      NULL, &child,
+                                                      NULL, NULL,
+                                                      x, y, mask);
+          return_val = (child != NULL);
+	}
+      else
+	{
+	  GdkScreen *screen;
+	  int originx, originy;
+          int rootx, rooty;
+          int winx = 0;
+          int winy = 0;
+          unsigned int xmask = 0;
+
+          _gdk_windowing_get_device_state (gdk_window_get_display (window), device,
+                                           &screen, &rootx, &rooty, &xmask);
+	  gdk_window_get_origin (window, &originx, &originy);
+	  winx = rootx - originx;
+	  winy = rooty - originy;
+
+          *x = winx;
+          *y = winy;
+          *mask = xmask;
+	}
+    }
+
+  return return_val;
+}
+
+/**
+ * gdk_display_warp_pointer:
+ * @display: a #GdkDisplay
+ * @screen: the screen of @display to warp the pointer to
+ * @x: the x coordinate of the destination
+ * @y: the y coordinate of the destination
+ * 
+ * Warps the pointer of @display to the point @x,@y on 
+ * the screen @screen, unless the pointer is confined
+ * to a window by a grab, in which case it will be moved
+ * as far as allowed by the grab. Warping the pointer 
+ * creates events as if the user had moved the mouse 
+ * instantaneously to the destination.
+ * 
+ * Note that the pointer should normally be under the
+ * control of the user. This function was added to cover
+ * some rare use cases like keyboard navigation support
+ * for the color picker in the #GtkColorSelectionDialog.
+ *
+ * Since: 2.8
+ *
+ * Deprecated: 3.0: Use gdk_display_warp_device() instead.
+ */ 
+void
+gdk_display_warp_pointer (GdkDisplay *display,
+			  GdkScreen  *screen,
+			  gint        x,
+			  gint        y)
+{
+  GdkDevice *device;
+
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+
+  device = display->core_pointer;
+  GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
+}
+
+/**
+ * gdk_display_warp_device:
+ * @display: a #GdkDisplay.
+ * @device: a #GdkDevice.
+ * @screen: the screen of @display to warp @device to.
+ * @x: the X coordinate of the destination.
+ * @y: the Y coordinate of the destination.
+ *
+ * Warps @device in @display to the point @x,@y on
+ * the screen @screen, unless the device is confined
+ * to a window by a grab, in which case it will be moved
+ * as far as allowed by the grab. Warping the pointer
+ * creates events as if the user had moved the mouse
+ * instantaneously to the destination.
+ *
+ * Note that the pointer should normally be under the
+ * control of the user. This function was added to cover
+ * some rare use cases like keyboard navigation support
+ * for the color picker in the #GtkColorSelectionDialog.
+ *
+ * Since: 3.0
+ **/
+void
+gdk_display_warp_device (GdkDisplay *display,
+                         GdkDevice  *device,
+                         GdkScreen  *screen,
+                         gint        x,
+                         gint        y)
+{
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+  g_return_if_fail (GDK_IS_DEVICE (device));
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+  g_return_if_fail (display == gdk_device_get_display (device));
+
+  GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
+}
+
+GdkWindow*
+_gdk_windowing_window_at_device_position (GdkDisplay      *display,
+                                          GdkDevice       *device,
+                                          gint            *win_x,
+                                          gint            *win_y,
+                                          GdkModifierType *mask,
+                                          gboolean         get_toplevel)
+{
+  GdkWindow *window;
+  GdkScreen *screen;
+
+  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);
+  if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+    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;
+      Window pointer_window, root, xwindow, child;
+      Window xwindow_last = 0;
+      Display *xdisplay;
+      int rootx = -1, rooty = -1;
+      int winx, winy;
+      unsigned int xmask;
+
+      /* FIXME: untrusted clients case not multidevice-safe */
+
+      xwindow = GDK_SCREEN_XROOTWIN (screen);
+      xdisplay = GDK_SCREEN_XDISPLAY (screen);
+
+      pointer_window = None;
+      screens = gdk_display_get_n_screens (display);
+      for (i = 0; i < screens; ++i) {
+	screen = gdk_display_get_screen (display, i);
+	toplevels = gdk_screen_get_toplevel_windows (screen);
+	for (list = toplevels; list != NULL; list = g_list_next (list)) {
+	  window = GDK_WINDOW (list->data);
+	  xwindow = GDK_WINDOW_XWINDOW (window);
+	  gdk_error_trap_push ();
+	  XQueryPointer (xdisplay, xwindow,
+			 &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+	  if (gdk_error_trap_pop ())
+	    continue;
+	  if (child != None) 
+	    {
+	      pointer_window = child;
+	      break;
+	    }
+	  gdk_window_get_geometry (window, NULL, NULL, &width, &height, NULL);
+	  if (winx >= 0 && winy >= 0 && winx < width && winy < height) 
+	    {
+	      /* A childless toplevel, or below another window? */
+	      XSetWindowAttributes attributes;
+	      Window w;
+	      
+	      w = XCreateWindow (xdisplay, xwindow, winx, winy, 1, 1, 0, 
+				 CopyFromParent, InputOnly, CopyFromParent, 
+				 0, &attributes);
+	      XMapWindow (xdisplay, w);
+	      XQueryPointer (xdisplay, xwindow, 
+			     &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+	      XDestroyWindow (xdisplay, w);
+	      if (child == w) 
+		{
+		  pointer_window = xwindow;
+		  break;
+		}
+	    }
+	}
+	g_list_free (toplevels);
+	if (pointer_window != None)
+	  break;
+      }
+      xwindow = pointer_window;
+
+      while (xwindow)
+	{
+	  xwindow_last = xwindow;
+	  gdk_error_trap_push ();
+	  XQueryPointer (xdisplay, xwindow,
+			 &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
+	  if (gdk_error_trap_pop ())
+	    break;
+	  if (get_toplevel && xwindow_last != root &&
+	      (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);
+
+  return window;
+}
+
+static GdkEventMask
+gdk_window_x11_get_events (GdkWindow *window)
+{
+  XWindowAttributes attrs;
+  GdkEventMask event_mask;
+  GdkEventMask filtered;
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return 0;
+  else
+    {
+      XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
+			    GDK_WINDOW_XID (window),
+			    &attrs);
+      event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
+      /* if property change was filtered out before, keep it filtered out */
+      filtered = GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK;
+      GDK_WINDOW_OBJECT (window)->event_mask = event_mask & ((GDK_WINDOW_OBJECT (window)->event_mask & filtered) | ~filtered);
+
+      return event_mask;
+    }
+}
+static void
+gdk_window_x11_set_events (GdkWindow    *window,
+                           GdkEventMask  event_mask)
+{
+  long xevent_mask = 0;
+  
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      GdkDisplayX11 *display_x11;
+
+      if (GDK_WINDOW_XID (window) != GDK_WINDOW_XROOTWIN (window))
+        xevent_mask = StructureNotifyMask | PropertyChangeMask;
+
+      display_x11 = GDK_DISPLAY_X11 (gdk_window_get_display (window));
+      gdk_event_source_select_events ((GdkEventSource *) display_x11->event_source,
+                                      GDK_WINDOW_XWINDOW (window), event_mask,
+                                      xevent_mask);
+    }
+}
+
+static inline void
+do_shape_combine_region (GdkWindow       *window,
+			 const cairo_region_t *shape_region,
+			 gint             offset_x,
+			 gint             offset_y,
+			 gint             shape)
+{
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  if (shape_region == NULL)
+    {
+      /* Use NULL mask to unset the shape */
+      if (shape == ShapeBounding
+	  ? gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))
+	  : gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window)))
+	{
+	  if (shape == ShapeBounding)
+	    {
+	      _gdk_x11_window_tmp_unset_parent_bg (window);
+	      _gdk_x11_window_tmp_unset_bg (window, TRUE);
+	    }
+	  XShapeCombineMask (GDK_WINDOW_XDISPLAY (window),
+			     GDK_WINDOW_XID (window),
+			     shape,
+			     0, 0,
+			     None,
+			     ShapeSet);
+ 	  if (shape == ShapeBounding)
+	    {
+	      _gdk_x11_window_tmp_reset_parent_bg (window);
+	      _gdk_x11_window_tmp_reset_bg (window, TRUE);
+	    }
+	}
+      return;
+    }
+  
+  if (shape == ShapeBounding
+      ? gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))
+      : gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window)))
+    {
+      gint n_rects = 0;
+      XRectangle *xrects = NULL;
+
+      _gdk_region_get_xrectangles (shape_region,
+                                   0, 0,
+                                   &xrects, &n_rects);
+      
+      if (shape == ShapeBounding)
+	{
+	  _gdk_x11_window_tmp_unset_parent_bg (window);
+	  _gdk_x11_window_tmp_unset_bg (window, TRUE);
+	}
+      XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window),
+                               GDK_WINDOW_XID (window),
+                               shape,
+                               offset_x, offset_y,
+                               xrects, n_rects,
+                               ShapeSet,
+                               YXBanded);
+
+      if (shape == ShapeBounding)
+	{
+	  _gdk_x11_window_tmp_reset_parent_bg (window);
+	  _gdk_x11_window_tmp_reset_bg (window, TRUE);
+	}
+      
+      g_free (xrects);
+    }
+}
+
+static void
+gdk_window_x11_shape_combine_region (GdkWindow       *window,
+                                     const cairo_region_t *shape_region,
+                                     gint             offset_x,
+                                     gint             offset_y)
+{
+  do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeBounding);
+}
+
+static void 
+gdk_window_x11_input_shape_combine_region (GdkWindow       *window,
+					   const cairo_region_t *shape_region,
+					   gint             offset_x,
+					   gint             offset_y)
+{
+#ifdef ShapeInput
+  do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeInput);
+#endif
+}
+
+
+/**
+ * gdk_window_set_override_redirect:
+ * @window: a toplevel #GdkWindow
+ * @override_redirect: %TRUE if window should be override redirect
+ *
+ * An override redirect window is not under the control of the window manager.
+ * This means it won't have a titlebar, won't be minimizable, etc. - it will
+ * be entirely under the control of the application. The window manager
+ * can't see the override redirect window at all.
+ *
+ * Override redirect should only be used for short-lived temporary
+ * windows, such as popup menus. #GtkMenu uses an override redirect
+ * window in its implementation, for example.
+ * 
+ **/
+void
+gdk_window_set_override_redirect (GdkWindow *window,
+				  gboolean override_redirect)
+{
+  XSetWindowAttributes attr;
+  
+  if (!GDK_WINDOW_DESTROYED (window) &&
+      WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    {
+      GdkWindowObject *private = (GdkWindowObject *)window;
+      GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+      attr.override_redirect = (override_redirect? True : False);
+      XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
+			       GDK_WINDOW_XID (window),
+			       CWOverrideRedirect,
+			       &attr);
+
+      impl->override_redirect = attr.override_redirect;
+    }
+}
+
+/**
+ * gdk_window_set_accept_focus:
+ * @window: a toplevel #GdkWindow
+ * @accept_focus: %TRUE if the window should receive input focus
+ *
+ * Setting @accept_focus to %FALSE hints the desktop environment that the
+ * window doesn't want to receive input focus. 
+ *
+ * On X, it is the responsibility of the window manager to interpret this 
+ * hint. ICCCM-compliant window manager usually respect it.
+ *
+ * Since: 2.4 
+ **/
+void
+gdk_window_set_accept_focus (GdkWindow *window,
+			     gboolean accept_focus)
+{
+  GdkWindowObject *private;
+
+  private = (GdkWindowObject *)window;  
+  
+  accept_focus = accept_focus != FALSE;
+
+  if (private->accept_focus != accept_focus)
+    {
+      private->accept_focus = accept_focus;
+
+      if (!GDK_WINDOW_DESTROYED (window) &&
+	  WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+	update_wm_hints (window, FALSE);
+    }
+}
+
+/**
+ * gdk_window_set_focus_on_map:
+ * @window: a toplevel #GdkWindow
+ * @focus_on_map: %TRUE if the window should receive input focus when mapped
+ *
+ * Setting @focus_on_map to %FALSE hints the desktop environment that the
+ * window doesn't want to receive input focus when it is mapped.  
+ * focus_on_map should be turned off for windows that aren't triggered
+ * interactively (such as popups from network activity).
+ *
+ * On X, it is the responsibility of the window manager to interpret
+ * this hint. Window managers following the freedesktop.org window
+ * manager extension specification should respect it.
+ *
+ * Since: 2.6 
+ **/
+void
+gdk_window_set_focus_on_map (GdkWindow *window,
+			     gboolean focus_on_map)
+{
+  GdkWindowObject *private;
+
+  private = (GdkWindowObject *)window;  
+  
+  focus_on_map = focus_on_map != FALSE;
+
+  if (private->focus_on_map != focus_on_map)
+    {
+      private->focus_on_map = focus_on_map;
+      
+      if ((!GDK_WINDOW_DESTROYED (window)) &&
+	  (!private->focus_on_map) &&
+	  WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+	gdk_x11_window_set_user_time (window, 0);
+    }
+}
+
+/**
+ * gdk_x11_window_set_user_time:
+ * @window: A toplevel #GdkWindow
+ * @timestamp: An XServer timestamp to which the property should be set
+ *
+ * The application can use this call to update the _NET_WM_USER_TIME
+ * property on a toplevel window.  This property stores an Xserver
+ * time which represents the time of the last user input event
+ * received for this window.  This property may be used by the window
+ * manager to alter the focus, stacking, and/or placement behavior of
+ * windows when they are mapped depending on whether the new window
+ * was created by a user action or is a "pop-up" window activated by a
+ * timer or some other event.
+ *
+ * Note that this property is automatically updated by GDK, so this
+ * function should only be used by applications which handle input
+ * events bypassing GDK.
+ *
+ * Since: 2.6
+ **/
+void
+gdk_x11_window_set_user_time (GdkWindow *window,
+                              guint32    timestamp)
+{
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+  GdkToplevelX11 *toplevel;
+  glong timestamp_long = (glong)timestamp;
+  Window xid;
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  display = gdk_window_get_display (window);
+  display_x11 = GDK_DISPLAY_X11 (display);
+  toplevel = _gdk_x11_window_get_toplevel (window);
+
+  if (!toplevel)
+    {
+      g_warning ("gdk_window_set_user_time called on non-toplevel\n");
+      return;
+    }
+
+  if (toplevel->focus_window != None &&
+      gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
+                                           gdk_atom_intern_static_string ("_NET_WM_USER_TIME_WINDOW")))
+    xid = toplevel->focus_window;
+  else
+    xid = GDK_WINDOW_XID (window);
+
+  XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xid,
+                   gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_USER_TIME"),
+                   XA_CARDINAL, 32, PropModeReplace,
+                   (guchar *)&timestamp_long, 1);
+
+  if (timestamp_long != GDK_CURRENT_TIME &&
+      (display_x11->user_time == GDK_CURRENT_TIME ||
+       XSERVER_TIME_IS_LATER (timestamp_long, display_x11->user_time)))
+    display_x11->user_time = timestamp_long;
+
+  if (toplevel)
+    toplevel->user_time = timestamp_long;
+}
+
+#define GDK_SELECTION_MAX_SIZE(display)                                 \
+  MIN(262144,                                                           \
+      XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0     \
+       ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100         \
+       : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
+
+static void
+gdk_window_update_icon (GdkWindow *window,
+                        GList     *icon_list)
+{
+  GdkToplevelX11 *toplevel;
+  GdkPixbuf *best_icon;
+  GList *tmp_list;
+  int best_size;
+  
+  toplevel = _gdk_x11_window_get_toplevel (window);
+
+  if (toplevel->icon_pixmap != NULL)
+    {
+      cairo_surface_destroy (toplevel->icon_pixmap);
+      toplevel->icon_pixmap = NULL;
+    }
+  
+  if (toplevel->icon_mask != NULL)
+    {
+      cairo_surface_destroy (toplevel->icon_mask);
+      toplevel->icon_mask = NULL;
+    }
+  
+#define IDEAL_SIZE 48
+  
+  best_size = G_MAXINT;
+  best_icon = NULL;
+  for (tmp_list = icon_list; tmp_list; tmp_list = tmp_list->next)
+    {
+      GdkPixbuf *pixbuf = tmp_list->data;
+      int this;
+  
+      /* average width and height - if someone passes in a rectangular
+       * icon they deserve what they get.
+       */
+      this = gdk_pixbuf_get_width (pixbuf) + gdk_pixbuf_get_height (pixbuf);
+      this /= 2;
+  
+      if (best_icon == NULL)
+        {
+          best_icon = pixbuf;
+          best_size = this;
+        }
+      else
+        {
+          /* icon is better if it's 32 pixels or larger, and closer to
+           * the ideal size than the current best.
+           */
+          if (this >= 32 &&
+              (ABS (best_size - IDEAL_SIZE) <
+               ABS (this - IDEAL_SIZE)))
+            {
+              best_icon = pixbuf;
+              best_size = this;
+            }
+        }
+    }
+
+  if (best_icon)
+    {
+      int width = gdk_pixbuf_get_width (best_icon);
+      int height = gdk_pixbuf_get_height (best_icon);
+      cairo_t *cr;
+
+      toplevel->icon_pixmap = gdk_x11_window_create_pixmap_surface (window,
+                                                                    width,
+                                                                    height);
+
+      cr = cairo_create (toplevel->icon_pixmap);
+      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+      gdk_cairo_set_source_pixbuf (cr, best_icon, 0, 0);
+      if (gdk_pixbuf_get_has_alpha (best_icon))
+        {
+          /* Saturate the image, so it has bilevel alpha */
+          cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
+          cairo_paint (cr);
+          cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
+          cairo_paint (cr);
+          cairo_pop_group_to_source (cr);
+        }
+      cairo_paint (cr);
+      cairo_destroy (cr);
+
+      if (gdk_pixbuf_get_has_alpha (best_icon))
+        {
+          toplevel->icon_mask = _gdk_x11_window_create_bitmap_surface (window,
+                                                                       width,
+                                                                       height);
+
+          cr = cairo_create (toplevel->icon_mask);
+          gdk_cairo_set_source_pixbuf (cr, best_icon, 0, 0);
+          cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+          cairo_paint (cr);
+          cairo_destroy (cr);
+        }
+    }
+
+  update_wm_hints (window, FALSE);
+}
+
+/**
+ * gdk_window_set_icon_list:
+ * @window: The #GdkWindow toplevel window to set the icon of.
+ * @pixbufs: (transfer none) (element-type GdkPixbuf):
+ *     A list of pixbufs, of different sizes.
+ *
+ * Sets a list of icons for the window. One of these will be used
+ * to represent the window when it has been iconified. The icon is
+ * usually shown in an icon box or some sort of task bar. Which icon
+ * size is shown depends on the window manager. The window manager
+ * can scale the icon  but setting several size icons can give better
+ * image quality since the window manager may only need to scale the
+ * icon by a small amount or not at all.
+ *
+ **/
+void
+gdk_window_set_icon_list (GdkWindow *window,
+			  GList     *pixbufs)
+{
+  gulong *data;
+  guchar *pixels;
+  gulong *p;
+  gint size;
+  GList *l;
+  GdkPixbuf *pixbuf;
+  gint width, height, stride;
+  gint x, y;
+  gint n_channels;
+  GdkDisplay *display;
+  gint n;
+  
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  display = gdk_window_get_display (window);
+  
+  l = pixbufs;
+  size = 0;
+  n = 0;
+  while (l)
+    {
+      pixbuf = l->data;
+      g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+
+      width = gdk_pixbuf_get_width (pixbuf);
+      height = gdk_pixbuf_get_height (pixbuf);
+      
+      /* silently ignore overlarge icons */
+      if (size + 2 + width * height > GDK_SELECTION_MAX_SIZE(display))
+	{
+	  g_warning ("gdk_window_set_icon_list: icons too large");
+	  break;
+	}
+     
+      n++;
+      size += 2 + width * height;
+      
+      l = g_list_next (l);
+    }
+
+  data = g_malloc (size * sizeof (gulong));
+
+  l = pixbufs;
+  p = data;
+  while (l && n > 0)
+    {
+      pixbuf = l->data;
+      
+      width = gdk_pixbuf_get_width (pixbuf);
+      height = gdk_pixbuf_get_height (pixbuf);
+      stride = gdk_pixbuf_get_rowstride (pixbuf);
+      n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+      
+      *p++ = width;
+      *p++ = height;
+
+      pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+      for (y = 0; y < height; y++)
+	{
+	  for (x = 0; x < width; x++)
+	    {
+	      guchar r, g, b, a;
+	      
+	      r = pixels[y*stride + x*n_channels + 0];
+	      g = pixels[y*stride + x*n_channels + 1];
+	      b = pixels[y*stride + x*n_channels + 2];
+	      if (n_channels >= 4)
+		a = pixels[y*stride + x*n_channels + 3];
+	      else
+		a = 255;
+	      
+	      *p++ = a << 24 | r << 16 | g << 8 | b ;
+	    }
+	}
+
+      l = g_list_next (l);
+      n--;
+    }
+
+  if (size > 0)
+    {
+      XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+                       GDK_WINDOW_XID (window),
+		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"),
+                       XA_CARDINAL, 32,
+                       PropModeReplace,
+                       (guchar*) data, size);
+    }
+  else
+    {
+      XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+                       GDK_WINDOW_XID (window),
+		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"));
+    }
+  
+  g_free (data);
+
+  gdk_window_update_icon (window, pixbufs);
+}
+
+static gboolean
+gdk_window_icon_name_set (GdkWindow *window)
+{
+  return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window),
+					       g_quark_from_static_string ("gdk-icon-name-set")));
+}
+
+/**
+ * gdk_window_set_icon_name:
+ * @window: a toplevel #GdkWindow
+ * @name: name of window while iconified (minimized)
+ *
+ * Windows may have a name used while minimized, distinct from the
+ * name they display in their titlebar. Most of the time this is a bad
+ * idea from a user interface standpoint. But you can set such a name
+ * with this function, if you like.
+ *
+ * After calling this with a non-%NULL @name, calls to gdk_window_set_title()
+ * will not update the icon title.
+ *
+ * Using %NULL for @name unsets the icon title; further calls to
+ * gdk_window_set_title() will again update the icon title as well.
+ **/
+void
+gdk_window_set_icon_name (GdkWindow   *window, 
+			  const gchar *name)
+{
+  GdkDisplay *display;
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  display = gdk_window_get_display (window);
+
+  g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
+                      GUINT_TO_POINTER (name != NULL));
+
+  if (name != NULL)
+    {
+      XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+                       GDK_WINDOW_XID (window),
+                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
+                       gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+                       PropModeReplace, (guchar *)name, strlen (name));
+
+      set_text_property (display, GDK_WINDOW_XID (window),
+                         gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
+                         name);
+    }
+  else
+    {
+      XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+                       GDK_WINDOW_XID (window),
+                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"));
+      XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+                       GDK_WINDOW_XID (window),
+                       gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"));
+    }
+}
+
+/**
+ * gdk_window_iconify:
+ * @window: a toplevel #GdkWindow
+ * 
+ * Asks to iconify (minimize) @window. The window manager may choose
+ * to ignore the request, but normally will honor it. Using
+ * gtk_window_iconify() is preferred, if you have a #GtkWindow widget.
+ *
+ * This function only makes sense when @window is a toplevel window.
+ *
+ **/
+void
+gdk_window_iconify (GdkWindow *window)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    {  
+      XIconifyWindow (GDK_WINDOW_XDISPLAY (window),
+		      GDK_WINDOW_XWINDOW (window),
+		      gdk_screen_get_number (GDK_WINDOW_SCREEN (window)));
+    }
+  else
+    {
+      /* Flip our client side flag, the real work happens on map. */
+      gdk_synthesize_window_state (window,
+                                   0,
+                                   GDK_WINDOW_STATE_ICONIFIED);
+    }
+}
+
+/**
+ * gdk_window_deiconify:
+ * @window: a toplevel #GdkWindow
+ *
+ * Attempt to deiconify (unminimize) @window. On X11 the window manager may
+ * choose to ignore the request to deiconify. When using GTK+,
+ * use gtk_window_deiconify() instead of the #GdkWindow variant. Or better yet,
+ * you probably want to use gtk_window_present(), which raises the window, focuses it,
+ * unminimizes it, and puts it on the current desktop.
+ *
+ **/
+void
+gdk_window_deiconify (GdkWindow *window)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    {  
+      gdk_window_show (window);
+    }
+  else
+    {
+      /* Flip our client side flag, the real work happens on map. */
+      gdk_synthesize_window_state (window,
+                                   GDK_WINDOW_STATE_ICONIFIED,
+                                   0);
+    }
+}
+
+/**
+ * gdk_window_stick:
+ * @window: a toplevel #GdkWindow
+ *
+ * "Pins" a window such that it's on all workspaces and does not scroll
+ * with viewports, for window managers that have scrollable viewports.
+ * (When using #GtkWindow, gtk_window_stick() may be more useful.)
+ *
+ * On the X11 platform, this function depends on window manager
+ * support, so may have no effect with many window managers. However,
+ * GDK will do the best it can to convince the window manager to stick
+ * the window. For window managers that don't support this operation,
+ * there's nothing you can do to force it to happen.
+ * 
+ **/
+void
+gdk_window_stick (GdkWindow *window)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    {
+      /* "stick" means stick to all desktops _and_ do not scroll with the
+       * viewport. i.e. glue to the monitor glass in all cases.
+       */
+      
+      XClientMessageEvent xclient;
+
+      /* Request stick during viewport scroll */
+      gdk_wmspec_change_state (TRUE, window,
+			       gdk_atom_intern_static_string ("_NET_WM_STATE_STICKY"),
+			       GDK_NONE);
+
+      /* Request desktop 0xFFFFFFFF */
+      memset (&xclient, 0, sizeof (xclient));
+      xclient.type = ClientMessage;
+      xclient.window = GDK_WINDOW_XWINDOW (window);
+      xclient.display = GDK_WINDOW_XDISPLAY (window);
+      xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), 
+									"_NET_WM_DESKTOP");
+      xclient.format = 32;
+
+      xclient.data.l[0] = 0xFFFFFFFF;
+      xclient.data.l[1] = 0;
+      xclient.data.l[2] = 0;
+      xclient.data.l[3] = 0;
+      xclient.data.l[4] = 0;
+
+      XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
+                  SubstructureRedirectMask | SubstructureNotifyMask,
+                  (XEvent *)&xclient);
+    }
+  else
+    {
+      /* Flip our client side flag, the real work happens on map. */
+      gdk_synthesize_window_state (window,
+                                   0,
+                                   GDK_WINDOW_STATE_STICKY);
+    }
+}
+
+/**
+ * gdk_window_unstick:
+ * @window: a toplevel #GdkWindow
+ *
+ * Reverse operation for gdk_window_stick(); see gdk_window_stick(),
+ * and gtk_window_unstick().
+ * 
+ **/
+void
+gdk_window_unstick (GdkWindow *window)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    {
+      /* Request unstick from viewport */
+      gdk_wmspec_change_state (FALSE, window,
+			       gdk_atom_intern_static_string ("_NET_WM_STATE_STICKY"),
+			       GDK_NONE);
+
+      move_to_current_desktop (window);
+    }
+  else
+    {
+      /* Flip our client side flag, the real work happens on map. */
+      gdk_synthesize_window_state (window,
+                                   GDK_WINDOW_STATE_STICKY,
+                                   0);
+
+    }
+}
+
+/**
+ * gdk_window_maximize:
+ * @window: a toplevel #GdkWindow
+ *
+ * Maximizes the window. If the window was already maximized, then
+ * this function does nothing.
+ * 
+ * On X11, asks the window manager to maximize @window, if the window
+ * manager supports this operation. Not all window managers support
+ * this, and some deliberately ignore it or don't have a concept of
+ * "maximized"; so you can't rely on the maximization actually
+ * happening. But it will happen with most standard window managers,
+ * and GDK makes a best effort to get it to happen.
+ *
+ * On Windows, reliably maximizes the window.
+ * 
+ **/
+void
+gdk_window_maximize (GdkWindow *window)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    gdk_wmspec_change_state (TRUE, window,
+			     gdk_atom_intern_static_string ("_NET_WM_STATE_MAXIMIZED_VERT"),
+			     gdk_atom_intern_static_string ("_NET_WM_STATE_MAXIMIZED_HORZ"));
+  else
+    gdk_synthesize_window_state (window,
+				 0,
+				 GDK_WINDOW_STATE_MAXIMIZED);
+}
+
+/**
+ * gdk_window_unmaximize:
+ * @window: a toplevel #GdkWindow
+ *
+ * Unmaximizes the window. If the window wasn't maximized, then this
+ * function does nothing.
+ * 
+ * On X11, asks the window manager to unmaximize @window, if the
+ * window manager supports this operation. Not all window managers
+ * support this, and some deliberately ignore it or don't have a
+ * concept of "maximized"; so you can't rely on the unmaximization
+ * actually happening. But it will happen with most standard window
+ * managers, and GDK makes a best effort to get it to happen.
+ *
+ * On Windows, reliably unmaximizes the window.
+ * 
+ **/
+void
+gdk_window_unmaximize (GdkWindow *window)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    gdk_wmspec_change_state (FALSE, window,
+			     gdk_atom_intern_static_string ("_NET_WM_STATE_MAXIMIZED_VERT"),
+			     gdk_atom_intern_static_string ("_NET_WM_STATE_MAXIMIZED_HORZ"));
+  else
+    gdk_synthesize_window_state (window,
+				 GDK_WINDOW_STATE_MAXIMIZED,
+				 0);
+}
+
+/**
+ * gdk_window_fullscreen:
+ * @window: a toplevel #GdkWindow
+ *
+ * Moves the window into fullscreen mode. This means the
+ * window covers the entire screen and is above any panels
+ * or task bars.
+ *
+ * If the window was already fullscreen, then this function does nothing.
+ * 
+ * On X11, asks the window manager to put @window in a fullscreen
+ * state, if the window manager supports this operation. Not all
+ * window managers support this, and some deliberately ignore it or
+ * don't have a concept of "fullscreen"; so you can't rely on the
+ * fullscreenification actually happening. But it will happen with
+ * most standard window managers, and GDK makes a best effort to get
+ * it to happen.
+ *
+ * Since: 2.2
+ **/
+void
+gdk_window_fullscreen (GdkWindow *window)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    gdk_wmspec_change_state (TRUE, window,
+			     gdk_atom_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
+                             GDK_NONE);
+
+  else
+    gdk_synthesize_window_state (window,
+                                 0,
+                                 GDK_WINDOW_STATE_FULLSCREEN);
+}
+
+/**
+ * gdk_window_unfullscreen:
+ * @window: a toplevel #GdkWindow
+ *
+ * Moves the window out of fullscreen mode. If the window was not
+ * fullscreen, does nothing.
+ * 
+ * On X11, asks the window manager to move @window out of the fullscreen
+ * state, if the window manager supports this operation. Not all
+ * window managers support this, and some deliberately ignore it or
+ * don't have a concept of "fullscreen"; so you can't rely on the
+ * unfullscreenification actually happening. But it will happen with
+ * most standard window managers, and GDK makes a best effort to get
+ * it to happen. 
+ *
+ * Since: 2.2
+ **/
+void
+gdk_window_unfullscreen (GdkWindow *window)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    gdk_wmspec_change_state (FALSE, window,
+			     gdk_atom_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
+                             GDK_NONE);
+
+  else
+    gdk_synthesize_window_state (window,
+				 GDK_WINDOW_STATE_FULLSCREEN,
+				 0);
+}
+
+/**
+ * gdk_window_set_keep_above:
+ * @window: a toplevel #GdkWindow
+ * @setting: whether to keep @window above other windows
+ *
+ * Set if @window must be kept above other windows. If the
+ * window was already above, then this function does nothing.
+ * 
+ * On X11, asks the window manager to keep @window above, if the window
+ * manager supports this operation. Not all window managers support
+ * this, and some deliberately ignore it or don't have a concept of
+ * "keep above"; so you can't rely on the window being kept above.
+ * But it will happen with most standard window managers,
+ * and GDK makes a best effort to get it to happen.
+ *
+ * Since: 2.4
+ **/
+void
+gdk_window_set_keep_above (GdkWindow *window,
+                           gboolean   setting)
+{
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    {
+      if (setting)
+	gdk_wmspec_change_state (FALSE, window,
+				 gdk_atom_intern_static_string ("_NET_WM_STATE_BELOW"),
+				 GDK_NONE);
+      gdk_wmspec_change_state (setting, window,
+			       gdk_atom_intern_static_string ("_NET_WM_STATE_ABOVE"),
+			       GDK_NONE);
+    }
+  else
+    gdk_synthesize_window_state (window,
+    				 setting ? GDK_WINDOW_STATE_BELOW : GDK_WINDOW_STATE_ABOVE,
+				 setting ? GDK_WINDOW_STATE_ABOVE : 0);
+}
+
+/**
+ * gdk_window_set_keep_below:
+ * @window: a toplevel #GdkWindow
+ * @setting: whether to keep @window below other windows
+ *
+ * Set if @window must be kept below other windows. If the
+ * window was already below, then this function does nothing.
+ * 
+ * On X11, asks the window manager to keep @window below, if the window
+ * manager supports this operation. Not all window managers support
+ * this, and some deliberately ignore it or don't have a concept of
+ * "keep below"; so you can't rely on the window being kept below.
+ * But it will happen with most standard window managers,
+ * and GDK makes a best effort to get it to happen.
+ *
+ * Since: 2.4
+ **/
+void
+gdk_window_set_keep_below (GdkWindow *window, gboolean setting)
+{
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    {
+      if (setting)
+	gdk_wmspec_change_state (FALSE, window,
+				 gdk_atom_intern_static_string ("_NET_WM_STATE_ABOVE"),
+				 GDK_NONE);
+      gdk_wmspec_change_state (setting, window,
+			       gdk_atom_intern_static_string ("_NET_WM_STATE_BELOW"),
+			       GDK_NONE);
+    }
+  else
+    gdk_synthesize_window_state (window,
+				 setting ? GDK_WINDOW_STATE_ABOVE : GDK_WINDOW_STATE_BELOW,
+				 setting ? GDK_WINDOW_STATE_BELOW : 0);
+}
+
+/**
+ * gdk_window_get_group:
+ * @window: a toplevel #GdkWindow
+ * 
+ * Returns the group leader window for @window. See gdk_window_set_group().
+ * 
+ * Return value: (transfer none): the group leader window for @window
+ *
+ * Since: 2.4
+ **/
+GdkWindow *
+gdk_window_get_group (GdkWindow *window)
+{
+  GdkToplevelX11 *toplevel;
+  
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL (window))
+    return NULL;
+  
+  toplevel = _gdk_x11_window_get_toplevel (window);
+
+  return toplevel->group_leader;
+}
+
+/**
+ * gdk_window_set_group:
+ * @window: a toplevel #GdkWindow
+ * @leader: group leader window, or %NULL to restore the default group leader window
+ *
+ * Sets the group leader window for @window. By default,
+ * GDK sets the group leader for all toplevel windows
+ * to a global window implicitly created by GDK. With this function
+ * you can override this default.
+ *
+ * The group leader window allows the window manager to distinguish
+ * all windows that belong to a single application. It may for example
+ * allow users to minimize/unminimize all windows belonging to an
+ * application at once. You should only set a non-default group window
+ * if your application pretends to be multiple applications.
+ **/
+void          
+gdk_window_set_group (GdkWindow *window,
+		      GdkWindow *leader)
+{
+  GdkToplevelX11 *toplevel;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
+  g_return_if_fail (leader == NULL || GDK_IS_WINDOW (leader));
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      (leader != NULL && GDK_WINDOW_DESTROYED (leader)) ||
+      !WINDOW_IS_TOPLEVEL (window))
+    return;
+
+  toplevel = _gdk_x11_window_get_toplevel (window);
+
+  if (leader == NULL)
+    leader = gdk_display_get_default_group (gdk_window_get_display (window));
+  
+  if (toplevel->group_leader != leader)
+    {
+      if (toplevel->group_leader)
+	g_object_unref (toplevel->group_leader);
+      toplevel->group_leader = g_object_ref (leader);
+      (_gdk_x11_window_get_toplevel (leader))->is_leader = TRUE;      
+    }
+
+  update_wm_hints (window, FALSE);
+}
+
+static MotifWmHints *
+gdk_window_get_mwm_hints (GdkWindow *window)
+{
+  GdkDisplay *display;
+  Atom hints_atom = None;
+  guchar *data;
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  
+  if (GDK_WINDOW_DESTROYED (window))
+    return NULL;
+
+  display = gdk_window_get_display (window);
+  
+  hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
+
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+		      hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
+		      False, AnyPropertyType, &type, &format, &nitems,
+		      &bytes_after, &data);
+
+  if (type == None)
+    return NULL;
+  
+  return (MotifWmHints *)data;
+}
+
+static void
+gdk_window_set_mwm_hints (GdkWindow *window,
+			  MotifWmHints *new_hints)
+{
+  GdkDisplay *display;
+  Atom hints_atom = None;
+  guchar *data;
+  MotifWmHints *hints;
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+  
+  display = gdk_window_get_display (window);
+  
+  hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
+
+  XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
+		      hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
+		      False, AnyPropertyType, &type, &format, &nitems,
+		      &bytes_after, &data);
+  
+  if (type == None)
+    hints = new_hints;
+  else
+    {
+      hints = (MotifWmHints *)data;
+	
+      if (new_hints->flags & MWM_HINTS_FUNCTIONS)
+	{
+	  hints->flags |= MWM_HINTS_FUNCTIONS;
+	  hints->functions = new_hints->functions;
+	}
+      if (new_hints->flags & MWM_HINTS_DECORATIONS)
+	{
+	  hints->flags |= MWM_HINTS_DECORATIONS;
+	  hints->decorations = new_hints->decorations;
+	}
+    }
+  
+  XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
+		   hints_atom, hints_atom, 32, PropModeReplace,
+		   (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
+  
+  if (hints != new_hints)
+    XFree (hints);
+}
+
+/**
+ * gdk_window_set_decorations:
+ * @window: a toplevel #GdkWindow
+ * @decorations: decoration hint mask
+ *
+ * "Decorations" are the features the window manager adds to a toplevel #GdkWindow.
+ * This function sets the traditional Motif window manager hints that tell the
+ * window manager which decorations you would like your window to have.
+ * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of
+ * using the GDK function directly.
+ *
+ * The @decorations argument is the logical OR of the fields in
+ * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the
+ * mask, the other bits indicate which decorations should be turned off.
+ * If #GDK_DECOR_ALL is not included, then the other bits indicate
+ * which decorations should be turned on.
+ *
+ * Most window managers honor a decorations hint of 0 to disable all decorations,
+ * but very few honor all possible combinations of bits.
+ * 
+ **/
+void
+gdk_window_set_decorations (GdkWindow      *window,
+			    GdkWMDecoration decorations)
+{
+  MotifWmHints hints;
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+  
+  /* initialize to zero to avoid writing uninitialized data to socket */
+  memset(&hints, 0, sizeof(hints));
+  hints.flags = MWM_HINTS_DECORATIONS;
+  hints.decorations = decorations;
+  
+  gdk_window_set_mwm_hints (window, &hints);
+}
+
+/**
+ * gdk_window_get_decorations:
+ * @window: The toplevel #GdkWindow to get the decorations from
+ * @decorations: The window decorations will be written here
+ *
+ * Returns the decorations set on the GdkWindow with
+ * gdk_window_set_decorations().
+ *
+ * Returns: %TRUE if the window has decorations set, %FALSE otherwise.
+ **/
+gboolean
+gdk_window_get_decorations(GdkWindow       *window,
+			   GdkWMDecoration *decorations)
+{
+  MotifWmHints *hints;
+  gboolean result = FALSE;
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return FALSE;
+  
+  hints = gdk_window_get_mwm_hints (window);
+  
+  if (hints)
+    {
+      if (hints->flags & MWM_HINTS_DECORATIONS)
+	{
+	  if (decorations)
+	    *decorations = hints->decorations;
+	  result = TRUE;
+	}
+      
+      XFree (hints);
+    }
+
+  return result;
+}
+
+/**
+ * gdk_window_set_functions:
+ * @window: a toplevel #GdkWindow
+ * @functions: bitmask of operations to allow on @window
+ *
+ * Sets hints about the window management functions to make available
+ * via buttons on the window frame.
+ * 
+ * On the X backend, this function sets the traditional Motif window 
+ * manager hint for this purpose. However, few window managers do
+ * anything reliable or interesting with this hint. Many ignore it
+ * entirely.
+ *
+ * The @functions argument is the logical OR of values from the
+ * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL,
+ * then the other bits indicate which functions to disable; if
+ * it doesn't include #GDK_FUNC_ALL, it indicates which functions to
+ * enable.
+ * 
+ **/
+void
+gdk_window_set_functions (GdkWindow    *window,
+			  GdkWMFunction functions)
+{
+  MotifWmHints hints;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+  
+  /* initialize to zero to avoid writing uninitialized data to socket */
+  memset(&hints, 0, sizeof(hints));
+  hints.flags = MWM_HINTS_FUNCTIONS;
+  hints.functions = functions;
+  
+  gdk_window_set_mwm_hints (window, &hints);
+}
+
+cairo_region_t *
+_xwindow_get_shape (Display *xdisplay,
+		    Window window,
+		    gint shape_type)
+{
+  cairo_region_t *shape;
+  GdkRectangle *rl;
+  XRectangle *xrl;
+  gint rn, ord, i;
+
+  shape = NULL;
+  rn = 0;
+
+  xrl = XShapeGetRectangles (xdisplay,
+			     window,
+			     shape_type, &rn, &ord);
+
+  if (xrl == NULL || rn == 0)
+    return cairo_region_create (); /* Empty */
+
+  if (ord != YXBanded)
+    {
+      /* This really shouldn't happen with any xserver, as they
+	 generally convert regions to YXBanded internally */
+      g_warning ("non YXBanded shape masks not supported");
+      XFree (xrl);
+      return NULL;
+    }
+
+  rl = g_new (GdkRectangle, rn);
+  for (i = 0; i < rn; i++)
+    {
+      rl[i].x = xrl[i].x;
+      rl[i].y = xrl[i].y;
+      rl[i].width = xrl[i].width;
+      rl[i].height = xrl[i].height;
+    }
+  XFree (xrl);
+  
+  shape = cairo_region_create_rectangles (rl, rn);
+  g_free (rl);
+  
+  return shape;
+}
+
+
+cairo_region_t *
+_gdk_windowing_window_get_shape (GdkWindow *window)
+{
+  if (!GDK_WINDOW_DESTROYED (window) &&
+      gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
+    return _xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
+			      GDK_WINDOW_XID (window), ShapeBounding);
+
+  return NULL;
+}
+
+cairo_region_t *
+_gdk_windowing_window_get_input_shape (GdkWindow *window)
+{
+#if defined(ShapeInput)
+  if (!GDK_WINDOW_DESTROYED (window) &&
+      gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
+    return _xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
+			      GDK_WINDOW_XID (window),
+			      ShapeInput);
+#endif
+
+  return NULL;
+}
+
+static void
+gdk_window_set_static_bit_gravity (GdkWindow *window,
+                                   gboolean   on)
+{
+  XSetWindowAttributes xattributes;
+  GdkWindowObject *private;
+  guint xattributes_mask = 0;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = GDK_WINDOW_OBJECT (window);
+  if (private->input_only)
+    return;
+  
+  xattributes.bit_gravity = StaticGravity;
+  xattributes_mask |= CWBitGravity;
+  xattributes.bit_gravity = on ? StaticGravity : ForgetGravity;
+  XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
+			   GDK_WINDOW_XID (window),
+			   CWBitGravity,  &xattributes);
+}
+
+static void
+gdk_window_set_static_win_gravity (GdkWindow *window,
+                                   gboolean   on)
+{
+  XSetWindowAttributes xattributes;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+  xattributes.win_gravity = on ? StaticGravity : NorthWestGravity;
+  
+  XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
+			   GDK_WINDOW_XID (window),
+			   CWWinGravity,  &xattributes);
+}
+
+static gboolean
+gdk_window_x11_set_static_gravities (GdkWindow *window,
+                                     gboolean   use_static)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GList *tmp_list;
+  
+  if (!use_static == !private->guffaw_gravity)
+    return TRUE;
+
+  private->guffaw_gravity = use_static;
+  
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      gdk_window_set_static_bit_gravity (window, use_static);
+      
+      tmp_list = private->children;
+      while (tmp_list)
+	{
+	  gdk_window_set_static_win_gravity (tmp_list->data, use_static);
+	  
+	  tmp_list = tmp_list->next;
+	}
+    }
+  
+  return TRUE;
+}
+
+static void
+wmspec_moveresize (GdkWindow *window,
+                   gint       direction,
+                   gint       root_x,
+                   gint       root_y,
+                   guint32    timestamp)     
+{
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+  
+  XClientMessageEvent xclient;
+
+  /* Release passive grab */
+  gdk_display_pointer_ungrab (display, timestamp);
+
+  memset (&xclient, 0, sizeof (xclient));
+  xclient.type = ClientMessage;
+  xclient.window = GDK_WINDOW_XID (window);
+  xclient.message_type =
+    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
+  xclient.format = 32;
+  xclient.data.l[0] = root_x;
+  xclient.data.l[1] = root_y;
+  xclient.data.l[2] = direction;
+  xclient.data.l[3] = 0;
+  xclient.data.l[4] = 0;
+  
+  XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
+	      SubstructureRedirectMask | SubstructureNotifyMask,
+	      (XEvent *)&xclient);
+}
+
+typedef struct _MoveResizeData MoveResizeData;
+
+struct _MoveResizeData
+{
+  GdkDisplay *display;
+  
+  GdkWindow *moveresize_window;
+  GdkWindow *moveresize_emulation_window;
+  gboolean is_resize;
+  GdkWindowEdge resize_edge;
+  gint moveresize_button;
+  gint moveresize_x;
+  gint moveresize_y;
+  gint moveresize_orig_x;
+  gint moveresize_orig_y;
+  gint moveresize_orig_width;
+  gint moveresize_orig_height;
+  GdkWindowHints moveresize_geom_mask;
+  GdkGeometry moveresize_geometry;
+  Time moveresize_process_time;
+  XEvent *moveresize_pending_event;
+};
+
+/* From the WM spec */
+#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
+#define _NET_WM_MOVERESIZE_SIZE_TOP          1
+#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
+#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
+#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
+#define _NET_WM_MOVERESIZE_MOVE              8
+
+static void
+wmspec_resize_drag (GdkWindow     *window,
+                    GdkWindowEdge  edge,
+                    gint           button,
+                    gint           root_x,
+                    gint           root_y,
+                    guint32        timestamp)
+{
+  gint direction;
+  
+  /* Let the compiler turn a switch into a table, instead
+   * of doing the table manually, this way is easier to verify.
+   */
+  switch (edge)
+    {
+    case GDK_WINDOW_EDGE_NORTH_WEST:
+      direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
+      break;
+
+    case GDK_WINDOW_EDGE_NORTH:
+      direction = _NET_WM_MOVERESIZE_SIZE_TOP;
+      break;
+
+    case GDK_WINDOW_EDGE_NORTH_EAST:
+      direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
+      break;
+
+    case GDK_WINDOW_EDGE_WEST:
+      direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
+      break;
+
+    case GDK_WINDOW_EDGE_EAST:
+      direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
+      break;
+
+    case GDK_WINDOW_EDGE_SOUTH_WEST:
+      direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
+      break;
+
+    case GDK_WINDOW_EDGE_SOUTH:
+      direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
+      break;
+
+    case GDK_WINDOW_EDGE_SOUTH_EAST:
+      direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
+      break;
+
+    default:
+      g_warning ("gdk_window_begin_resize_drag: bad resize edge %d!",
+                 edge);
+      return;
+    }
+  
+  wmspec_moveresize (window, direction, root_x, root_y, timestamp);
+}
+
+static MoveResizeData *
+get_move_resize_data (GdkDisplay *display,
+		      gboolean    create)
+{
+  MoveResizeData *mv_resize;
+  static GQuark move_resize_quark = 0;
+
+  if (!move_resize_quark)
+    move_resize_quark = g_quark_from_static_string ("gdk-window-moveresize");
+  
+  mv_resize = g_object_get_qdata (G_OBJECT (display), move_resize_quark);
+
+  if (!mv_resize && create)
+    {
+      mv_resize = g_new0 (MoveResizeData, 1);
+      mv_resize->display = display;
+      
+      g_object_set_qdata (G_OBJECT (display), move_resize_quark, mv_resize);
+    }
+
+  return mv_resize;
+}
+
+static void
+update_pos (MoveResizeData *mv_resize,
+	    gint            new_root_x,
+	    gint            new_root_y)
+{
+  gint dx, dy;
+
+  dx = new_root_x - mv_resize->moveresize_x;
+  dy = new_root_y - mv_resize->moveresize_y;
+
+  if (mv_resize->is_resize)
+    {
+      gint x, y, w, h;
+
+      x = mv_resize->moveresize_orig_x;
+      y = mv_resize->moveresize_orig_y;
+
+      w = mv_resize->moveresize_orig_width;
+      h = mv_resize->moveresize_orig_height;
+
+      switch (mv_resize->resize_edge)
+	{
+	case GDK_WINDOW_EDGE_NORTH_WEST:
+	  x += dx;
+	  y += dy;
+	  w -= dx;
+	  h -= dy;
+	  break;
+	case GDK_WINDOW_EDGE_NORTH:
+	  y += dy;
+	  h -= dy;
+	  break;
+	case GDK_WINDOW_EDGE_NORTH_EAST:
+	  y += dy;
+	  h -= dy;
+	  w += dx;
+	  break;
+	case GDK_WINDOW_EDGE_SOUTH_WEST:
+	  h += dy;
+	  x += dx;
+	  w -= dx;
+	  break;
+	case GDK_WINDOW_EDGE_SOUTH_EAST:
+	  w += dx;
+	  h += dy;
+	  break;
+	case GDK_WINDOW_EDGE_SOUTH:
+	  h += dy;
+	  break;
+	case GDK_WINDOW_EDGE_EAST:
+	  w += dx;
+	  break;
+	case GDK_WINDOW_EDGE_WEST:
+	  x += dx;
+	  w -= dx;
+	  break;
+	}
+
+      x = MAX (x, 0);
+      y = MAX (y, 0);
+      w = MAX (w, 1);
+      h = MAX (h, 1);
+
+      if (mv_resize->moveresize_geom_mask)
+	{
+	  gdk_window_constrain_size (&mv_resize->moveresize_geometry,
+				     mv_resize->moveresize_geom_mask,
+				     w, h, &w, &h);
+	}
+
+      gdk_window_move_resize (mv_resize->moveresize_window, x, y, w, h);
+    }
+  else
+    {
+      gint x, y;
+
+      x = mv_resize->moveresize_orig_x + dx;
+      y = mv_resize->moveresize_orig_y + dy;
+
+      gdk_window_move (mv_resize->moveresize_window, x, y);
+    }
+}
+
+static void
+finish_drag (MoveResizeData *mv_resize)
+{
+  gdk_window_destroy (mv_resize->moveresize_emulation_window);
+  mv_resize->moveresize_emulation_window = NULL;
+  g_object_unref (mv_resize->moveresize_window);
+  mv_resize->moveresize_window = NULL;
+
+  if (mv_resize->moveresize_pending_event)
+    {
+      g_free (mv_resize->moveresize_pending_event);
+      mv_resize->moveresize_pending_event = NULL;
+    }
+}
+
+static int
+lookahead_motion_predicate (Display *xdisplay,
+			    XEvent  *event,
+			    XPointer arg)
+{
+  gboolean *seen_release = (gboolean *)arg;
+  GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
+  MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
+
+  if (*seen_release)
+    return False;
+
+  switch (event->xany.type)
+    {
+    case ButtonRelease:
+      *seen_release = TRUE;
+      break;
+    case MotionNotify:
+      mv_resize->moveresize_process_time = event->xmotion.time;
+      break;
+    default:
+      break;
+    }
+
+  return False;
+}
+
+static gboolean
+moveresize_lookahead (MoveResizeData *mv_resize,
+		      XEvent         *event)
+{
+  XEvent tmp_event;
+  gboolean seen_release = FALSE;
+
+  if (mv_resize->moveresize_process_time)
+    {
+      if (event->xmotion.time == mv_resize->moveresize_process_time)
+	{
+	  mv_resize->moveresize_process_time = 0;
+	  return TRUE;
+	}
+      else
+	return FALSE;
+    }
+
+  XCheckIfEvent (event->xany.display, &tmp_event,
+		 lookahead_motion_predicate, (XPointer) & seen_release);
+
+  return mv_resize->moveresize_process_time == 0;
+}
+	
+gboolean
+_gdk_moveresize_handle_event (XEvent *event)
+{
+  guint button_mask = 0;
+  GdkWindowObject *window_private;
+  GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
+  MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
+
+  if (!mv_resize || !mv_resize->moveresize_window)
+    return FALSE;
+
+  window_private = (GdkWindowObject *) mv_resize->moveresize_window;
+
+  button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
+
+  switch (event->xany.type)
+    {
+    case MotionNotify:
+      if (window_private->resize_count > 0)
+	{
+	  if (mv_resize->moveresize_pending_event)
+	    *mv_resize->moveresize_pending_event = *event;
+	  else
+	    mv_resize->moveresize_pending_event =
+	      g_memdup (event, sizeof (XEvent));
+
+	  break;
+	}
+      if (!moveresize_lookahead (mv_resize, event))
+	break;
+
+      update_pos (mv_resize,
+		  event->xmotion.x_root,
+		  event->xmotion.y_root);
+
+      /* This should never be triggered in normal cases, but in the
+       * case where the drag started without an implicit grab being
+       * in effect, we could miss the release if it occurs before
+       * we grab the pointer; this ensures that we will never
+       * get a permanently stuck grab.
+       */
+      if ((event->xmotion.state & button_mask) == 0)
+	finish_drag (mv_resize);
+      break;
+
+    case ButtonRelease:
+      update_pos (mv_resize,
+		  event->xbutton.x_root,
+		  event->xbutton.y_root);
+
+      if (event->xbutton.button == mv_resize->moveresize_button)
+	finish_drag (mv_resize);
+      break;
+    }
+  return TRUE;
+}
+
+gboolean 
+_gdk_moveresize_configure_done (GdkDisplay *display,
+				GdkWindow  *window)
+{
+  XEvent *tmp_event;
+  MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
+  
+  if (!mv_resize || window != mv_resize->moveresize_window)
+    return FALSE;
+
+  if (mv_resize->moveresize_pending_event)
+    {
+      tmp_event = mv_resize->moveresize_pending_event;
+      mv_resize->moveresize_pending_event = NULL;
+      _gdk_moveresize_handle_event (tmp_event);
+      g_free (tmp_event);
+    }
+  
+  return TRUE;
+}
+
+static void
+create_moveresize_window (MoveResizeData *mv_resize,
+			  guint32         timestamp)
+{
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  GdkGrabStatus status;
+
+  g_assert (mv_resize->moveresize_emulation_window == NULL);
+
+  attributes.x = -100;
+  attributes.y = -100;
+  attributes.width = 10;
+  attributes.height = 10;
+  attributes.window_type = GDK_WINDOW_TEMP;
+  attributes.wclass = GDK_INPUT_ONLY;
+  attributes.override_redirect = TRUE;
+  attributes.event_mask = 0;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
+
+  mv_resize->moveresize_emulation_window = 
+    gdk_window_new (gdk_screen_get_root_window (gdk_display_get_default_screen (mv_resize->display)),
+		    &attributes,
+		    attributes_mask);
+
+  gdk_window_show (mv_resize->moveresize_emulation_window);
+
+  status = gdk_pointer_grab (mv_resize->moveresize_emulation_window,
+                             FALSE,
+                             GDK_BUTTON_RELEASE_MASK |
+                             GDK_POINTER_MOTION_MASK,
+                             NULL,
+                             NULL,
+                             timestamp);
+
+  if (status != GDK_GRAB_SUCCESS)
+    {
+      /* If this fails, some other client has grabbed the window
+       * already.
+       */
+      finish_drag (mv_resize);
+    }
+
+  mv_resize->moveresize_process_time = 0;
+}
+
+/* 
+   Calculate mv_resize->moveresize_orig_x and mv_resize->moveresize_orig_y
+   so that calling XMoveWindow with these coordinates will not move the 
+   window.
+   Note that this depends on the WM to implement ICCCM-compliant reference
+   point handling.
+*/
+static void 
+calculate_unmoving_origin (MoveResizeData *mv_resize)
+{
+  GdkRectangle rect;
+  gint width, height;
+
+  if (mv_resize->moveresize_geom_mask & GDK_HINT_WIN_GRAVITY &&
+      mv_resize->moveresize_geometry.win_gravity == GDK_GRAVITY_STATIC)
+    {
+      gdk_window_get_origin (mv_resize->moveresize_window,
+			     &mv_resize->moveresize_orig_x,
+			     &mv_resize->moveresize_orig_y);
+    }
+  else
+    {
+      gdk_window_get_frame_extents (mv_resize->moveresize_window, &rect);
+      gdk_window_get_geometry (mv_resize->moveresize_window, 
+			       NULL, NULL, &width, &height, NULL);
+      
+      switch (mv_resize->moveresize_geometry.win_gravity) 
+	{
+	case GDK_GRAVITY_NORTH_WEST:
+	  mv_resize->moveresize_orig_x = rect.x;
+	  mv_resize->moveresize_orig_y = rect.y;
+	  break;
+	case GDK_GRAVITY_NORTH:
+	  mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
+	  mv_resize->moveresize_orig_y = rect.y;
+	  break;	  
+	case GDK_GRAVITY_NORTH_EAST:
+	  mv_resize->moveresize_orig_x = rect.x + rect.width - width;
+	  mv_resize->moveresize_orig_y = rect.y;
+	  break;
+	case GDK_GRAVITY_WEST:
+	  mv_resize->moveresize_orig_x = rect.x;
+	  mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
+	  break;
+	case GDK_GRAVITY_CENTER:
+	  mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
+	  mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
+	  break;
+	case GDK_GRAVITY_EAST:
+	  mv_resize->moveresize_orig_x = rect.x + rect.width - width;
+	  mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
+	  break;
+	case GDK_GRAVITY_SOUTH_WEST:
+	  mv_resize->moveresize_orig_x = rect.x;
+	  mv_resize->moveresize_orig_y = rect.y + rect.height - height;
+	  break;
+	case GDK_GRAVITY_SOUTH:
+	  mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
+	  mv_resize->moveresize_orig_y = rect.y + rect.height - height;
+	  break;
+	case GDK_GRAVITY_SOUTH_EAST:
+	  mv_resize->moveresize_orig_x = rect.x + rect.width - width;
+	  mv_resize->moveresize_orig_y = rect.y + rect.height - height;
+	  break;
+	default:
+	  mv_resize->moveresize_orig_x = rect.x;
+	  mv_resize->moveresize_orig_y = rect.y;
+	  break; 
+	}
+    }  
+}
+
+static void
+emulate_resize_drag (GdkWindow     *window,
+                     GdkWindowEdge  edge,
+                     gint           button,
+                     gint           root_x,
+                     gint           root_y,
+                     guint32        timestamp)
+{
+  MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window), TRUE);
+
+  mv_resize->is_resize = TRUE;
+  mv_resize->moveresize_button = button;
+  mv_resize->resize_edge = edge;
+  mv_resize->moveresize_x = root_x;
+  mv_resize->moveresize_y = root_y;
+  mv_resize->moveresize_window = g_object_ref (window);
+
+  mv_resize->moveresize_orig_width = gdk_window_get_width (window);
+  mv_resize->moveresize_orig_height = gdk_window_get_height (window);
+
+  mv_resize->moveresize_geom_mask = 0;
+  gdk_window_get_geometry_hints (window,
+				 &mv_resize->moveresize_geometry,
+				 &mv_resize->moveresize_geom_mask);
+
+  calculate_unmoving_origin (mv_resize);
+
+  create_moveresize_window (mv_resize, timestamp);
+}
+
+static void
+emulate_move_drag (GdkWindow     *window,
+                   gint           button,
+                   gint           root_x,
+                   gint           root_y,
+                   guint32        timestamp)
+{
+  MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window), TRUE);
+  
+  mv_resize->is_resize = FALSE;
+  mv_resize->moveresize_button = button;
+  mv_resize->moveresize_x = root_x;
+  mv_resize->moveresize_y = root_y;
+
+  mv_resize->moveresize_window = g_object_ref (window);
+
+  calculate_unmoving_origin (mv_resize);
+
+  create_moveresize_window (mv_resize, timestamp);
+}
+
+/**
+ * gdk_window_begin_resize_drag:
+ * @window: a toplevel #GdkWindow
+ * @edge: the edge or corner from which the drag is started
+ * @button: the button being used to drag
+ * @root_x: root window X coordinate of mouse click that began the drag
+ * @root_y: root window Y coordinate of mouse click that began the drag
+ * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
+ *
+ * Begins a window resize operation (for a toplevel window).
+ * You might use this function to implement a "window resize grip," for
+ * example; in fact #GtkStatusbar uses it. The function works best
+ * with window managers that support the <ulink url="http://www.freedesktop.org/Standards/wm-spec";>Extended Window Manager Hints</ulink>, but has a 
+ * fallback implementation for other window managers.
+ * 
+ **/
+void
+gdk_window_begin_resize_drag (GdkWindow     *window,
+                              GdkWindowEdge  edge,
+                              gint           button,
+                              gint           root_x,
+                              gint           root_y,
+                              guint32        timestamp)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+    return;
+
+  if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
+					   gdk_atom_intern_static_string ("_NET_WM_MOVERESIZE")))
+    wmspec_resize_drag (window, edge, button, root_x, root_y, timestamp);
+  else
+    emulate_resize_drag (window, edge, button, root_x, root_y, timestamp);
+}
+
+/**
+ * gdk_window_begin_move_drag:
+ * @window: a toplevel #GdkWindow
+ * @button: the button being used to drag
+ * @root_x: root window X coordinate of mouse click that began the drag
+ * @root_y: root window Y coordinate of mouse click that began the drag
+ * @timestamp: timestamp of mouse click that began the drag
+ *
+ * Begins a window move operation (for a toplevel window).  You might
+ * use this function to implement a "window move grip," for
+ * example. The function works best with window managers that support
+ * the <ulink url="http://www.freedesktop.org/Standards/wm-spec";>Extended 
+ * Window Manager Hints</ulink>, but has a fallback implementation for
+ * other window managers.
+ * 
+ **/
+void
+gdk_window_begin_move_drag (GdkWindow *window,
+                            gint       button,
+                            gint       root_x,
+                            gint       root_y,
+                            guint32    timestamp)
+{
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL (window))
+    return;
+
+  if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
+					   gdk_atom_intern_static_string ("_NET_WM_MOVERESIZE")))
+    wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE, root_x, root_y,
+		       timestamp);
+  else
+    emulate_move_drag (window, button, root_x, root_y, timestamp);
+}
+
+/**
+ * gdk_window_enable_synchronized_configure:
+ * @window: a toplevel #GdkWindow
+ * 
+ * Indicates that the application will cooperate with the window
+ * system in synchronizing the window repaint with the window
+ * manager during resizing operations. After an application calls
+ * this function, it must call gdk_window_configure_finished() every
+ * time it has finished all processing associated with a set of
+ * Configure events. Toplevel GTK+ windows automatically use this
+ * protocol.
+ * 
+ * On X, calling this function makes @window participate in the
+ * _NET_WM_SYNC_REQUEST window manager protocol.
+ * 
+ * Since: 2.6
+ **/
+void
+gdk_window_enable_synchronized_configure (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowImplX11 *impl;
+
+  if (!GDK_IS_WINDOW_IMPL_X11 (private->impl))
+    return;
+  
+  impl = GDK_WINDOW_IMPL_X11 (private->impl);
+	  
+  if (!impl->use_synchronized_configure)
+    {
+      /* This basically means you want to do fancy X specific stuff, so
+	 ensure we have a native window */
+      gdk_window_ensure_native (window);
+
+      impl->use_synchronized_configure = TRUE;
+      ensure_sync_counter (window);
+    }
+}
+
+/**
+ * gdk_window_configure_finished:
+ * @window: a toplevel #GdkWindow
+ * 
+ * Signal to the window system that the application has finished
+ * handling Configure events it has received. Window Managers can
+ * use this to better synchronize the frame repaint with the
+ * application. GTK+ applications will automatically call this
+ * function when appropriate.
+ *
+ * This function can only be called if gdk_window_enable_synchronized_configure()
+ * was called previously.
+ *
+ * Since: 2.6
+ **/
+void
+gdk_window_configure_finished (GdkWindow *window)
+{
+  GdkWindowImplX11 *impl;
+
+  if (!WINDOW_IS_TOPLEVEL (window))
+    return;
+  
+  impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl);
+  if (!impl->use_synchronized_configure)
+    return;
+  
+#ifdef HAVE_XSYNC
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+      GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+
+      if (toplevel && toplevel->update_counter != None &&
+	  GDK_DISPLAY_X11 (display)->use_sync &&
+	  !XSyncValueIsZero (toplevel->current_counter_value))
+	{
+	  XSyncSetCounter (GDK_WINDOW_XDISPLAY (window), 
+			   toplevel->update_counter,
+			   toplevel->current_counter_value);
+	  
+	  XSyncIntToValue (&toplevel->current_counter_value, 0);
+	}
+    }
+#endif
+}
+
+void
+_gdk_windowing_window_beep (GdkWindow *window)
+{
+  GdkDisplay *display;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  display = GDK_WINDOW_DISPLAY (window);
+
+#ifdef HAVE_XKB
+  if (GDK_DISPLAY_X11 (display)->use_xkb)
+    XkbBell (GDK_DISPLAY_XDISPLAY (display),
+	     GDK_WINDOW_XID (window),
+	     0,
+	     None);
+  else
+#endif
+    gdk_display_beep (display);
+}
+
+/**
+ * gdk_window_set_opacity:
+ * @window: a top-level #GdkWindow
+ * @opacity: opacity
+ *
+ * Request the windowing system to make @window partially transparent,
+ * with opacity 0 being fully transparent and 1 fully opaque. (Values
+ * of the opacity parameter are clamped to the [0,1] range.) 
+ *
+ * On X11, this works only on X screens with a compositing manager 
+ * running.
+ *
+ * For setting up per-pixel alpha, see gdk_screen_get_rgba_visual().
+ * For making non-toplevel windows translucent, see 
+ * gdk_window_set_composited().
+ *
+ * Since: 2.12
+ */
+void
+gdk_window_set_opacity (GdkWindow *window,
+			gdouble    opacity)
+{
+  GdkDisplay *display;
+  guint32 cardinal;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      !WINDOW_IS_TOPLEVEL (window))
+    return;
+
+  display = gdk_window_get_display (window);
+
+  if (opacity < 0)
+    opacity = 0;
+  else if (opacity > 1)
+    opacity = 1;
+
+  cardinal = opacity * 0xffffffff;
+
+  if (cardinal == 0xffffffff)
+    XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+		     GDK_WINDOW_XID (window),
+		     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"));
+  else
+    XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+		     GDK_WINDOW_XID (window),
+		     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"),
+		     XA_CARDINAL, 32,
+		     PropModeReplace,
+		     (guchar *) &cardinal, 1);
+}
+
+void
+_gdk_windowing_window_set_composited (GdkWindow *window,
+                                      gboolean   composited)
+{
+#if defined(HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+  GdkWindowObject *private = (GdkWindowObject *) window;
+  GdkWindowImplX11 *impl;
+  GdkDisplay *display;
+  Display *dpy;
+  Window xid;
+
+  impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+  display = gdk_screen_get_display (GDK_DRAWABLE_IMPL_X11 (impl)->screen);
+  dpy = GDK_DISPLAY_XDISPLAY (display);
+  xid = GDK_WINDOW_XWINDOW (private);
+
+  if (composited)
+    {
+      XCompositeRedirectWindow (dpy, xid, CompositeRedirectManual);
+      impl->damage = XDamageCreate (dpy, xid, XDamageReportBoundingBox);
+    }
+  else
+    {
+      XCompositeUnredirectWindow (dpy, xid, CompositeRedirectManual);
+      XDamageDestroy (dpy, impl->damage);
+      impl->damage = None;
+    }
+#endif
+}
+
+void
+_gdk_windowing_window_process_updates_recurse (GdkWindow *window,
+                                               cairo_region_t *region)
+{
+  _gdk_window_process_updates_recurse (window, region);
+}
+
+void
+_gdk_windowing_before_process_all_updates (void)
+{
+}
+
+void
+_gdk_windowing_after_process_all_updates (void)
+{
+}
+
+static void
+gdk_window_impl_iface_init (GdkWindowImplIface *iface)
+{
+  iface->show = gdk_window_x11_show;
+  iface->hide = gdk_window_x11_hide;
+  iface->withdraw = gdk_window_x11_withdraw;
+  iface->set_events = gdk_window_x11_set_events;
+  iface->get_events = gdk_window_x11_get_events;
+  iface->raise = gdk_window_x11_raise;
+  iface->lower = gdk_window_x11_lower;
+  iface->restack_under = gdk_window_x11_restack_under;
+  iface->restack_toplevel = gdk_window_x11_restack_toplevel;
+  iface->move_resize = gdk_window_x11_move_resize;
+  iface->set_background = gdk_window_x11_set_background;
+  iface->reparent = gdk_window_x11_reparent;
+  iface->set_device_cursor = gdk_window_x11_set_device_cursor;
+  iface->get_geometry = gdk_window_x11_get_geometry;
+  iface->get_root_coords = gdk_window_x11_get_root_coords;
+  iface->get_device_state = gdk_window_x11_get_device_state;
+  iface->shape_combine_region = gdk_window_x11_shape_combine_region;
+  iface->input_shape_combine_region = gdk_window_x11_input_shape_combine_region;
+  iface->set_static_gravities = gdk_window_x11_set_static_gravities;
+  iface->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
+  iface->translate = _gdk_x11_window_translate;
+  iface->destroy = _gdk_x11_window_destroy;
+  iface->resize_cairo_surface = gdk_window_x11_resize_cairo_surface;
+}
+
+static Bool
+timestamp_predicate (Display *display,
+		     XEvent  *xevent,
+		     XPointer arg)
+{
+  Window xwindow = GPOINTER_TO_UINT (arg);
+  GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (display);
+
+  if (xevent->type == PropertyNotify &&
+      xevent->xproperty.window == xwindow &&
+      xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (gdk_display,
+								       "GDK_TIMESTAMP_PROP"))
+    return True;
+
+  return False;
+}
+
+/**
+ * gdk_x11_get_server_time:
+ * @window: a #GdkWindow, used for communication with the server.
+ *          The window must have GDK_PROPERTY_CHANGE_MASK in its
+ *          events mask or a hang will result.
+ *
+ * Routine to get the current X server time stamp.
+ *
+ * Return value: the time stamp.
+ **/
+guint32
+gdk_x11_get_server_time (GdkWindow *window)
+{
+  Display *xdisplay;
+  Window   xwindow;
+  guchar c = 'a';
+  XEvent xevent;
+  Atom timestamp_prop_atom;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+  g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
+
+  xdisplay = GDK_WINDOW_XDISPLAY (window);
+  xwindow = GDK_WINDOW_XWINDOW (window);
+  timestamp_prop_atom =
+    gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
+					   "GDK_TIMESTAMP_PROP");
+
+  XChangeProperty (xdisplay, xwindow, timestamp_prop_atom,
+		   timestamp_prop_atom,
+		   8, PropModeReplace, &c, 1);
+
+  XIfEvent (xdisplay, &xevent,
+	    timestamp_predicate, GUINT_TO_POINTER(xwindow));
+
+  return xevent.xproperty.time;
+}
diff --git a/gdk/broadway/gdkwindow-broadway.h b/gdk/broadway/gdkwindow-broadway.h
new file mode 100644
index 0000000..392c357
--- /dev/null
+++ b/gdk/broadway/gdkwindow-broadway.h
@@ -0,0 +1,162 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_WINDOW_BROADWAY_H__
+#define __GDK_WINDOW_BROADWAY_H__
+
+#include <gdk/broadway/gdkdrawable-broadway.h>
+
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+
+#ifdef HAVE_XSYNC
+#include <X11/extensions/sync.h>
+#endif
+
+G_BEGIN_DECLS
+
+typedef struct _GdkToplevelX11 GdkToplevelX11;
+typedef struct _GdkWindowImplX11 GdkWindowImplX11;
+typedef struct _GdkWindowImplX11Class GdkWindowImplX11Class;
+typedef struct _GdkXPositionInfo GdkXPositionInfo;
+
+/* Window implementation for X11
+ */
+
+#define GDK_TYPE_WINDOW_IMPL_X11              (gdk_window_impl_x11_get_type ())
+#define GDK_WINDOW_IMPL_X11(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WINDOW_IMPL_X11, GdkWindowImplX11))
+#define GDK_WINDOW_IMPL_X11_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW_IMPL_X11, GdkWindowImplX11Class))
+#define GDK_IS_WINDOW_IMPL_X11(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WINDOW_IMPL_X11))
+#define GDK_IS_WINDOW_IMPL_X11_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_IMPL_X11))
+#define GDK_WINDOW_IMPL_X11_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_IMPL_X11, GdkWindowImplX11Class))
+
+struct _GdkWindowImplX11
+{
+  GdkDrawableImplX11 parent_instance;
+
+  GdkToplevelX11 *toplevel;	/* Toplevel-specific information */
+  GdkCursor *cursor;
+  GHashTable *device_cursor;
+
+  gint8 toplevel_window_type;
+  guint no_bg : 1;	        /* Set when the window background is temporarily
+				 * unset during resizing and scaling */
+  guint override_redirect : 1;
+  guint use_synchronized_configure : 1;
+
+#if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+  Damage damage;
+#endif
+};
+ 
+struct _GdkWindowImplX11Class 
+{
+  GdkDrawableImplX11Class parent_class;
+};
+
+struct _GdkToplevelX11
+{
+
+  /* Set if the window, or any descendent of it, is the server's focus window
+   */
+  guint has_focus_window : 1;
+
+  /* Set if window->has_focus_window and the focus isn't grabbed elsewhere.
+   */
+  guint has_focus : 1;
+
+  /* Set if the pointer is inside this window. (This is needed for
+   * for focus tracking)
+   */
+  guint has_pointer : 1;
+  
+  /* Set if the window is a descendent of the focus window and the pointer is
+   * inside it. (This is the case where the window will receive keystroke
+   * events even window->has_focus_window is FALSE)
+   */
+  guint has_pointer_focus : 1;
+
+  /* Set if we are requesting these hints */
+  guint skip_taskbar_hint : 1;
+  guint skip_pager_hint : 1;
+  guint urgency_hint : 1;
+
+  guint on_all_desktops : 1;   /* _NET_WM_STICKY == 0xFFFFFFFF */
+
+  guint have_sticky : 1;	/* _NET_WM_STATE_STICKY */
+  guint have_maxvert : 1;       /* _NET_WM_STATE_MAXIMIZED_VERT */
+  guint have_maxhorz : 1;       /* _NET_WM_STATE_MAXIMIZED_HORZ */
+  guint have_fullscreen : 1;    /* _NET_WM_STATE_FULLSCREEN */
+
+  guint is_leader : 1;
+  
+  gulong map_serial;	/* Serial of last transition from unmapped */
+  
+  cairo_surface_t *icon_pixmap;
+  cairo_surface_t *icon_mask;
+  GdkWindow *group_leader;
+
+  /* Time of most recent user interaction. */
+  gulong user_time;
+
+  /* We use an extra X window for toplevel windows that we XSetInputFocus()
+   * to in order to avoid getting keyboard events redirected to subwindows
+   * that might not even be part of this app
+   */
+  Window focus_window;
+ 
+#ifdef HAVE_XSYNC
+  XID update_counter;
+  XSyncValue pending_counter_value; /* latest _NET_WM_SYNC_REQUEST value received */
+  XSyncValue current_counter_value; /* Latest _NET_WM_SYNC_REQUEST value received
+				     * where we have also seen the corresponding
+				     * ConfigureNotify
+				     */
+#endif
+};
+
+GType gdk_window_impl_x11_get_type (void);
+
+void            gdk_x11_window_set_user_time        (GdkWindow *window,
+						     guint32    timestamp);
+
+GdkToplevelX11 *_gdk_x11_window_get_toplevel        (GdkWindow *window);
+void            _gdk_x11_window_tmp_unset_bg        (GdkWindow *window,
+						     gboolean   recurse);
+void            _gdk_x11_window_tmp_reset_bg        (GdkWindow *window,
+						     gboolean   recurse);
+void            _gdk_x11_window_tmp_unset_parent_bg (GdkWindow *window);
+void            _gdk_x11_window_tmp_reset_parent_bg (GdkWindow *window);
+
+GdkCursor      *_gdk_x11_window_get_cursor    (GdkWindow *window);
+void            _gdk_x11_window_get_offsets   (GdkWindow *window,
+                                               gint      *x_offset,
+                                               gint      *y_offset);
+
+G_END_DECLS
+
+#endif /* __GDK_WINDOW_BROADWAY_H__ */
diff --git a/gdk/broadway/gdkx.h b/gdk/broadway/gdkx.h
new file mode 100644
index 0000000..34917dd
--- /dev/null
+++ b/gdk/broadway/gdkx.h
@@ -0,0 +1,169 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_X_H__
+#define __GDK_X_H__
+
+#include <gdk/gdkprivate.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+G_BEGIN_DECLS
+
+Display *gdk_x11_drawable_get_xdisplay    (GdkDrawable *drawable);
+XID      gdk_x11_drawable_get_xid         (GdkDrawable *drawable);
+GdkDrawable *gdk_x11_window_get_drawable_impl (GdkWindow *window);
+Display *gdk_x11_cursor_get_xdisplay      (GdkCursor   *cursor);
+Cursor   gdk_x11_cursor_get_xcursor       (GdkCursor   *cursor);
+Display *gdk_x11_display_get_xdisplay     (GdkDisplay  *display);
+Visual * gdk_x11_visual_get_xvisual       (GdkVisual   *visual);
+Screen * gdk_x11_screen_get_xscreen       (GdkScreen   *screen);
+int      gdk_x11_screen_get_screen_number (GdkScreen   *screen);
+void     gdk_x11_window_set_user_time     (GdkWindow   *window,
+					   guint32      timestamp);
+void     gdk_x11_window_move_to_current_desktop (GdkWindow   *window);
+
+const char* gdk_x11_screen_get_window_manager_name (GdkScreen *screen);
+
+#ifndef GDK_MULTIHEAD_SAFE
+Window   gdk_x11_get_default_root_xwindow (void);
+Display *gdk_x11_get_default_xdisplay     (void);
+gint     gdk_x11_get_default_screen       (void);
+#endif
+
+#define GDK_CURSOR_XDISPLAY(cursor)   (gdk_x11_cursor_get_xdisplay (cursor))
+#define GDK_CURSOR_XCURSOR(cursor)    (gdk_x11_cursor_get_xcursor (cursor))
+
+#ifdef GDK_COMPILATION
+
+#include "gdkprivate-broadway.h"
+#include "gdkscreen-broadway.h"
+
+#define GDK_DISPLAY_XDISPLAY(display) (GDK_DISPLAY_X11(display)->xdisplay)
+
+#define GDK_WINDOW_XDISPLAY(win)      (GDK_SCREEN_X11 (GDK_WINDOW_SCREEN (win))->xdisplay)
+#define GDK_WINDOW_XID(win)           (GDK_DRAWABLE_IMPL_X11(((GdkWindowObject *)win)->impl)->xid)
+#define GDK_DRAWABLE_XDISPLAY(win)    (GDK_WINDOW_XDISPLAY (win))
+#define GDK_DRAWABLE_XID(win)         (GDK_WINDOW_XID (win))
+#define GDK_SCREEN_XDISPLAY(screen)   (GDK_SCREEN_X11 (screen)->xdisplay)
+#define GDK_SCREEN_XSCREEN(screen)    (GDK_SCREEN_X11 (screen)->xscreen)
+#define GDK_SCREEN_XNUMBER(screen)    (GDK_SCREEN_X11 (screen)->screen_num) 
+#define GDK_WINDOW_XWINDOW	      GDK_DRAWABLE_XID
+
+#else /* GDK_COMPILATION */
+
+#ifndef GDK_MULTIHEAD_SAFE
+#define GDK_ROOT_WINDOW()             (gdk_x11_get_default_root_xwindow ())
+#endif
+
+#define GDK_DISPLAY_XDISPLAY(display) (gdk_x11_display_get_xdisplay (display))
+
+#define GDK_WINDOW_XDISPLAY(win)      (gdk_x11_drawable_get_xdisplay (gdk_x11_window_get_drawable_impl (win)))
+#define GDK_WINDOW_XID(win)           (gdk_x11_drawable_get_xid (win))
+#define GDK_WINDOW_XWINDOW(win)       (gdk_x11_drawable_get_xid (win))
+#define GDK_DRAWABLE_XDISPLAY(win)    (gdk_x11_drawable_get_xdisplay (win))
+#define GDK_DRAWABLE_XID(win)         (gdk_x11_drawable_get_xid (win))
+#define GDK_SCREEN_XDISPLAY(screen)   (gdk_x11_display_get_xdisplay (gdk_screen_get_display (screen)))
+#define GDK_SCREEN_XSCREEN(screen)    (gdk_x11_screen_get_xscreen (screen))
+#define GDK_SCREEN_XNUMBER(screen)    (gdk_x11_screen_get_screen_number (screen))
+
+#endif /* GDK_COMPILATION */
+
+#define GDK_VISUAL_XVISUAL(visual)    (gdk_x11_visual_get_xvisual (visual))
+
+GdkVisual* gdk_x11_screen_lookup_visual (GdkScreen *screen,
+					 VisualID   xvisualid);
+#ifndef GDK_MULTIHEAD_SAFE
+GdkVisual* gdkx_visual_get            (VisualID   xvisualid);
+#endif
+
+     /* Return the Gdk* for a particular XID */
+gpointer      gdk_xid_table_lookup_for_display (GdkDisplay *display,
+						XID         xid);
+guint32       gdk_x11_get_server_time  (GdkWindow       *window);
+guint32       gdk_x11_display_get_user_time (GdkDisplay *display);
+
+G_CONST_RETURN gchar *gdk_x11_display_get_startup_notification_id (GdkDisplay *display);
+void          gdk_x11_display_set_startup_notification_id         (GdkDisplay  *display,
+                                                                   const gchar *startup_id);
+
+void          gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
+						const gchar *theme,
+						const gint   size);
+
+void gdk_x11_display_broadcast_startup_message (GdkDisplay *display,
+						const char *message_type,
+						...) G_GNUC_NULL_TERMINATED;
+
+/* returns TRUE if we support the given WM spec feature */
+gboolean gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
+					      GdkAtom    property);
+
+XID      gdk_x11_screen_get_monitor_output   (GdkScreen *screen,
+                                              gint       monitor_num);
+
+#ifndef GDK_MULTIHEAD_SAFE
+gpointer      gdk_xid_table_lookup   (XID              xid);
+gboolean      gdk_net_wm_supports    (GdkAtom    property);
+void          gdk_x11_grab_server    (void);
+void          gdk_x11_ungrab_server  (void);
+#endif
+
+GdkDisplay   *gdk_x11_lookup_xdisplay (Display *xdisplay);
+
+
+/* Functions to get the X Atom equivalent to the GdkAtom */
+Atom	              gdk_x11_atom_to_xatom_for_display (GdkDisplay  *display,
+							 GdkAtom      atom);
+GdkAtom		      gdk_x11_xatom_to_atom_for_display (GdkDisplay  *display,
+							 Atom	      xatom);
+Atom		      gdk_x11_get_xatom_by_name_for_display (GdkDisplay  *display,
+							     const gchar *atom_name);
+G_CONST_RETURN gchar *gdk_x11_get_xatom_name_for_display (GdkDisplay  *display,
+							  Atom         xatom);
+#ifndef GDK_MULTIHEAD_SAFE
+Atom                  gdk_x11_atom_to_xatom     (GdkAtom      atom);
+GdkAtom               gdk_x11_xatom_to_atom     (Atom         xatom);
+Atom                  gdk_x11_get_xatom_by_name (const gchar *atom_name);
+G_CONST_RETURN gchar *gdk_x11_get_xatom_name    (Atom         xatom);
+#endif
+
+void	    gdk_x11_display_grab	      (GdkDisplay *display);
+void	    gdk_x11_display_ungrab	      (GdkDisplay *display);
+
+void                           gdk_x11_display_error_trap_push        (GdkDisplay *display);
+/* warn unused because you could use pop_ignored otherwise */
+G_GNUC_WARN_UNUSED_RESULT gint gdk_x11_display_error_trap_pop         (GdkDisplay *display);
+void                           gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display);
+
+void        gdk_x11_register_standard_event_type (GdkDisplay *display,
+						  gint        event_base,
+						  gint        n_events);
+
+
+G_END_DECLS
+
+#endif /* __GDK_X_H__ */
diff --git a/gdk/broadway/gdkxftdefaults.c b/gdk/broadway/gdkxftdefaults.c
new file mode 100644
index 0000000..9ce1f12
--- /dev/null
+++ b/gdk/broadway/gdkxftdefaults.c
@@ -0,0 +1,268 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * 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.
+ *
+ * Based on code from xftdpy.c
+ *
+ * Copyright © 2000 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <fontconfig/fontconfig.h>
+
+#ifndef FC_HINT_STYLE
+#define FC_HINT_NONE        0
+#define FC_HINT_SLIGHT      1
+#define FC_HINT_MEDIUM      2
+#define FC_HINT_FULL        3
+#endif
+
+#include <gdkscreen-broadway.h>
+#include <gdkx.h>
+
+static gint
+parse_boolean (char *v)
+{
+  gchar c0, c1;
+  
+  c0 = *v;
+  if (g_ascii_isupper ((int)c0))
+    c0 = g_ascii_tolower (c0);
+  if (c0 == 't' || c0 == 'y' || c0 == '1')
+    return 1;
+  if (c0 == 'f' || c0 == 'n' || c0 == '0')
+    return 0;
+  if (c0 == 'o')
+    {
+      c1 = v[1];
+      if (g_ascii_isupper ((int)c1))
+	c1 = g_ascii_tolower (c1);
+      if (c1 == 'n')
+	return 1;
+      if (c1 == 'f')
+	return 0;
+    }
+  
+  return -1;
+}
+
+static gboolean
+get_boolean_default (Display *dpy,
+		     gchar   *option,
+		     gboolean *value)
+{
+  gchar *v;
+  gint i;
+  
+  v = XGetDefault (dpy, "Xft", option);
+  if (v)
+    {
+      i = parse_boolean (v);
+      if (i >= 0)
+	{
+	  *value = i;
+	  return TRUE;
+	}
+    }
+  
+  return FALSE;
+}
+
+static gboolean
+get_double_default (Display *dpy,
+		    gchar   *option,
+		    gdouble *value)
+{
+  gchar    *v, *e;
+  
+  v = XGetDefault (dpy, "Xft", option);
+  if (v)
+    {
+      /* Xft uses strtod, though localization probably wasn't
+       * desired. For compatibility, we use the conservative
+       * g_strtod() that accepts either localized or non-localized
+       * decimal separator.
+       */
+      *value = g_strtod (v, &e);
+      if (e != v)
+	return TRUE;
+    }
+  
+  return FALSE;
+}
+
+static gboolean
+get_integer_default (Display *dpy,
+		     gchar   *option,
+		     gint    *value)
+{
+  gchar *v, *e;
+  
+  v = XGetDefault (dpy, "Xft", option);
+  if (v)
+    {
+      if (FcNameConstant ((FcChar8 *) v, value))
+	return TRUE;
+      
+      *value = strtol (v, &e, 0);
+      if (e != v)
+	return TRUE;
+    }
+  
+  return FALSE;
+}
+
+static void
+init_xft_settings (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  Display *xdisplay = GDK_SCREEN_XDISPLAY (screen);
+  int xscreen = GDK_SCREEN_XNUMBER (screen);
+  double dpi_double;
+
+  if (screen_x11->xft_init)
+    return;
+
+  screen_x11->xft_init = TRUE;
+
+  if (!get_boolean_default (xdisplay, "antialias", &screen_x11->xft_antialias))
+    screen_x11->xft_antialias = TRUE;
+
+  if (!get_boolean_default (xdisplay, "hinting", &screen_x11->xft_hinting))
+    screen_x11->xft_hinting = TRUE;
+
+  if (!get_integer_default (xdisplay, "hintstyle", &screen_x11->xft_hintstyle))
+    screen_x11->xft_hintstyle = FC_HINT_FULL;
+
+  if (!get_integer_default (xdisplay, "rgba", &screen_x11->xft_rgba))
+    screen_x11->xft_rgba = FC_RGBA_UNKNOWN;
+
+  if (!get_double_default (xdisplay, "dpi", &dpi_double))
+    dpi_double = (((double) DisplayHeight (xdisplay, xscreen) * 25.4) / 
+		  (double) DisplayHeightMM (xdisplay, xscreen));
+
+  screen_x11->xft_dpi = (int)(0.5 + PANGO_SCALE * dpi_double);
+}
+
+gboolean
+_gdk_x11_get_xft_setting (GdkScreen   *screen,
+			  const gchar *name,
+			  GValue      *value)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  
+  if (strncmp (name, "gtk-xft-", 8) != 0)
+    return FALSE;
+
+  name += 8;
+
+  init_xft_settings (screen);
+
+  if (strcmp (name, "antialias") == 0)
+    {
+      g_value_set_int (value, screen_x11->xft_antialias);
+      return TRUE;
+    }
+  else if (strcmp (name, "hinting") == 0)
+    {
+      g_value_set_int (value, screen_x11->xft_hinting);
+      return TRUE;
+    }
+  else if (strcmp (name, "hintstyle") == 0)
+    {
+      const char *str;
+      
+      switch (screen_x11->xft_hintstyle)
+	{
+	case FC_HINT_NONE:
+	  str = "hintnone";
+	  break;
+	case FC_HINT_SLIGHT:
+	  str = "hintslight";
+	  break;
+	case FC_HINT_MEDIUM:
+	  str = "hintmedium";
+	  break;
+	case FC_HINT_FULL:
+	  str = "hintfull";
+	  break;
+	default:
+	  return FALSE;
+	}
+
+      g_value_set_string (value, str);
+      return TRUE;
+    }
+  else if (strcmp (name, "rgba") == 0)
+    {
+      const char *str;
+      
+      switch (screen_x11->xft_rgba)
+	{
+	case FC_RGBA_NONE:
+	  str = "none";
+	  break;
+	case FC_RGBA_RGB:
+	  str = "rgb";
+	  break;
+	case FC_RGBA_BGR:
+	  str = "bgr";
+	  break;
+	case FC_RGBA_VRGB:
+	  str = "vrgb";
+	  break;
+	case FC_RGBA_VBGR:
+	  str = "vbgr";
+	  break;
+	case FC_RGBA_UNKNOWN:
+	default:
+	  return FALSE;
+	}
+	
+      g_value_set_string (value, str);
+      return TRUE; 
+   }
+  else if (strcmp (name, "dpi") == 0)
+    {
+      g_value_set_int (value, screen_x11->xft_dpi);
+      return TRUE;
+    }
+
+  return FALSE;
+}
diff --git a/gdk/broadway/gdkxid.c b/gdk/broadway/gdkxid.c
new file mode 100644
index 0000000..ef2dc64
--- /dev/null
+++ b/gdk/broadway/gdkxid.c
@@ -0,0 +1,133 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkx.h"
+#include "gdkprivate-broadway.h"
+#include "gdkdisplay-broadway.h"
+
+#include <stdio.h>
+
+static guint     gdk_xid_hash  (XID *xid);
+static gboolean  gdk_xid_equal (XID *a,
+				XID *b);
+
+
+void
+_gdk_xid_table_insert (GdkDisplay *display,
+		       XID	  *xid,
+		       gpointer    data)
+{
+  GdkDisplayX11 *display_x11;
+
+  g_return_if_fail (xid != NULL);
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (!display_x11->xid_ht)
+    display_x11->xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash,
+					    (GEqualFunc) gdk_xid_equal);
+
+  if (g_hash_table_lookup (display_x11->xid_ht, xid))
+    g_warning ("XID collision, trouble ahead");
+
+  g_hash_table_insert (display_x11->xid_ht, xid, data);
+}
+
+void
+_gdk_xid_table_remove (GdkDisplay *display,
+		       XID	   xid)
+{
+  GdkDisplayX11 *display_x11;
+
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (display_x11->xid_ht)
+    g_hash_table_remove (display_x11->xid_ht, &xid);
+}
+
+/**
+ * gdk_xid_table_lookup_for_display:
+ * @display: the #GdkDisplay.
+ * @xid: an X id.
+ *
+ * Returns the GDK object associated with the given X id.
+ *
+ * Return value: the associated #GdkWindow or %NULL if no
+ *     object is associated with the X id.
+ *
+ * Since: 2.2
+ */
+gpointer
+gdk_xid_table_lookup_for_display (GdkDisplay  *display,
+				  XID	       xid)
+{
+  GdkDisplayX11 *display_x11;
+  gpointer data = NULL;
+  
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (display_x11->xid_ht)
+    data = g_hash_table_lookup (display_x11->xid_ht, &xid);
+  
+  return data;
+}
+
+
+/**
+ * gdk_xid_table_lookup:
+ * @xid: an X id.
+ *
+ * Returns the Gdk object associated with the given X id for the default
+ * display.
+ *
+ * Return value: the associated #GdkWindow or %NULL if no
+ *     object is associated with the X id.
+ */
+gpointer
+gdk_xid_table_lookup (XID xid)
+{
+  return gdk_xid_table_lookup_for_display (gdk_display_get_default (), xid);
+}
+
+static guint
+gdk_xid_hash (XID *xid)
+{
+  return *xid;
+}
+
+static gboolean
+gdk_xid_equal (XID *a,
+	       XID *b)
+{
+  return (*a == *b);
+}
diff --git a/gdk/broadway/xsettings-client.c b/gdk/broadway/xsettings-client.c
new file mode 100644
index 0000000..67e3b6b
--- /dev/null
+++ b/gdk/broadway/xsettings-client.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright © 2001, 2007 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Owen Taylor, Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include "xsettings-client.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xmd.h>		/* For CARD16 */
+
+struct _XSettingsClient
+{
+  Display *display;
+  int screen;
+  XSettingsNotifyFunc notify;
+  XSettingsWatchFunc watch;
+  void *cb_data;
+
+  XSettingsGrabFunc grab;
+  XSettingsGrabFunc ungrab;
+
+  Window manager_window;
+  Atom manager_atom;
+  Atom selection_atom;
+  Atom xsettings_atom;
+
+  XSettingsList *settings;
+};
+
+static void
+notify_changes (XSettingsClient *client,
+		XSettingsList   *old_list)
+{
+  XSettingsList *old_iter = old_list;
+  XSettingsList *new_iter = client->settings;
+
+  if (!client->notify)
+    return;
+
+  while (old_iter || new_iter)
+    {
+      int cmp;
+      
+      if (old_iter && new_iter)
+	cmp = strcmp (old_iter->setting->name, new_iter->setting->name);
+      else if (old_iter)
+	cmp = -1;
+      else
+	cmp = 1;
+
+      if (cmp < 0)
+	{
+	  client->notify (old_iter->setting->name,
+			  XSETTINGS_ACTION_DELETED,
+			  NULL,
+			  client->cb_data);
+	}
+      else if (cmp == 0)
+	{
+	  if (!xsettings_setting_equal (old_iter->setting,
+					new_iter->setting))
+	    client->notify (old_iter->setting->name,
+			    XSETTINGS_ACTION_CHANGED,
+			    new_iter->setting,
+			    client->cb_data);
+	}
+      else
+	{
+	  client->notify (new_iter->setting->name,
+			  XSETTINGS_ACTION_NEW,
+			  new_iter->setting,
+			  client->cb_data);
+	}
+
+      if (old_iter)
+	old_iter = old_iter->next;
+      if (new_iter)
+	new_iter = new_iter->next;
+    }
+}
+
+static int
+ignore_errors (Display *display, XErrorEvent *event)
+{
+  return True;
+}
+
+static char local_byte_order = '\0';
+
+#define BYTES_LEFT(buffer) ((buffer)->data + (buffer)->len - (buffer)->pos)
+
+static XSettingsResult
+fetch_card16 (XSettingsBuffer *buffer,
+	      CARD16          *result)
+{
+  CARD16 x;
+
+  if (BYTES_LEFT (buffer) < 2)
+    return XSETTINGS_ACCESS;
+
+  x = *(CARD16 *)buffer->pos;
+  buffer->pos += 2;
+  
+  if (buffer->byte_order == local_byte_order)
+    *result = x;
+  else
+    *result = (x << 8) | (x >> 8);
+
+  return XSETTINGS_SUCCESS;
+}
+
+static XSettingsResult
+fetch_ushort (XSettingsBuffer *buffer,
+	      unsigned short  *result) 
+{
+  CARD16 x;
+  XSettingsResult r;  
+
+  r = fetch_card16 (buffer, &x);
+  if (r == XSETTINGS_SUCCESS)
+    *result = x;
+
+  return r;
+}
+
+static XSettingsResult
+fetch_card32 (XSettingsBuffer *buffer,
+	      CARD32          *result)
+{
+  CARD32 x;
+
+  if (BYTES_LEFT (buffer) < 4)
+    return XSETTINGS_ACCESS;
+
+  x = *(CARD32 *)buffer->pos;
+  buffer->pos += 4;
+  
+  if (buffer->byte_order == local_byte_order)
+    *result = x;
+  else
+    *result = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
+  
+  return XSETTINGS_SUCCESS;
+}
+
+static XSettingsResult
+fetch_card8 (XSettingsBuffer *buffer,
+	     CARD8           *result)
+{
+  if (BYTES_LEFT (buffer) < 1)
+    return XSETTINGS_ACCESS;
+
+  *result = *(CARD8 *)buffer->pos;
+  buffer->pos += 1;
+
+  return XSETTINGS_SUCCESS;
+}
+
+#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
+
+static XSettingsList *
+parse_settings (unsigned char *data,
+		size_t         len)
+{
+  XSettingsBuffer buffer;
+  XSettingsResult result = XSETTINGS_SUCCESS;
+  XSettingsList *settings = NULL;
+  CARD32 serial;
+  CARD32 n_entries;
+  CARD32 i;
+  XSettingsSetting *setting = NULL;
+  
+  local_byte_order = xsettings_byte_order ();
+
+  buffer.pos = buffer.data = data;
+  buffer.len = len;
+  
+  result = fetch_card8 (&buffer, (unsigned char *)&buffer.byte_order);
+  if (buffer.byte_order != MSBFirst &&
+      buffer.byte_order != LSBFirst)
+    {
+      fprintf (stderr, "Invalid byte order in XSETTINGS property\n");
+      result = XSETTINGS_FAILED;
+      goto out;
+    }
+
+  buffer.pos += 3;
+
+  result = fetch_card32 (&buffer, &serial);
+  if (result != XSETTINGS_SUCCESS)
+    goto out;
+
+  result = fetch_card32 (&buffer, &n_entries);
+  if (result != XSETTINGS_SUCCESS)
+    goto out;
+
+  for (i = 0; i < n_entries; i++)
+    {
+      CARD8 type;
+      CARD16 name_len;
+      CARD32 v_int;
+      size_t pad_len;
+      
+      result = fetch_card8 (&buffer, &type);
+      if (result != XSETTINGS_SUCCESS)
+	goto out;
+
+      buffer.pos += 1;
+
+      result = fetch_card16 (&buffer, &name_len);
+      if (result != XSETTINGS_SUCCESS)
+	goto out;
+
+      pad_len = XSETTINGS_PAD(name_len, 4);
+      if (BYTES_LEFT (&buffer) < pad_len)
+	{
+	  result = XSETTINGS_ACCESS;
+	  goto out;
+	}
+
+      setting = malloc (sizeof *setting);
+      if (!setting)
+	{
+	  result = XSETTINGS_NO_MEM;
+	  goto out;
+	}
+      setting->type = XSETTINGS_TYPE_INT; /* No allocated memory */
+
+      setting->name = malloc (name_len + 1);
+      if (!setting->name)
+	{
+	  result = XSETTINGS_NO_MEM;
+	  goto out;
+	}
+
+      memcpy (setting->name, buffer.pos, name_len);
+      setting->name[name_len] = '\0';
+      buffer.pos += pad_len;
+
+      result = fetch_card32 (&buffer, &v_int);
+      if (result != XSETTINGS_SUCCESS)
+	goto out;
+      setting->last_change_serial = v_int;
+
+      switch (type)
+	{
+	case XSETTINGS_TYPE_INT:
+	  result = fetch_card32 (&buffer, &v_int);
+	  if (result != XSETTINGS_SUCCESS)
+	    goto out;
+
+	  setting->data.v_int = (INT32)v_int;
+	  break;
+	case XSETTINGS_TYPE_STRING:
+	  result = fetch_card32 (&buffer, &v_int);
+	  if (result != XSETTINGS_SUCCESS)
+	    goto out;
+
+	  pad_len = XSETTINGS_PAD (v_int, 4);
+	  if (v_int + 1 == 0 || /* Guard against wrap-around */
+	      BYTES_LEFT (&buffer) < pad_len)
+	    {
+	      result = XSETTINGS_ACCESS;
+	      goto out;
+	    }
+
+	  setting->data.v_string = malloc (v_int + 1);
+	  if (!setting->data.v_string)
+	    {
+	      result = XSETTINGS_NO_MEM;
+	      goto out;
+	    }
+	  
+	  memcpy (setting->data.v_string, buffer.pos, v_int);
+	  setting->data.v_string[v_int] = '\0';
+	  buffer.pos += pad_len;
+
+	  break;
+	case XSETTINGS_TYPE_COLOR:
+	  result = fetch_ushort (&buffer, &setting->data.v_color.red);
+	  if (result != XSETTINGS_SUCCESS)
+	    goto out;
+	  result = fetch_ushort (&buffer, &setting->data.v_color.green);
+	  if (result != XSETTINGS_SUCCESS)
+	    goto out;
+	  result = fetch_ushort (&buffer, &setting->data.v_color.blue);
+	  if (result != XSETTINGS_SUCCESS)
+	    goto out;
+	  result = fetch_ushort (&buffer, &setting->data.v_color.alpha);
+	  if (result != XSETTINGS_SUCCESS)
+	    goto out;
+
+	  break;
+	default:
+	  /* Quietly ignore unknown types */
+	  break;
+	}
+
+      setting->type = type;
+
+      result = xsettings_list_insert (&settings, setting);
+      if (result != XSETTINGS_SUCCESS)
+	goto out;
+
+      setting = NULL;
+    }
+
+ out:
+
+  if (result != XSETTINGS_SUCCESS)
+    {
+      switch (result)
+	{
+	case XSETTINGS_NO_MEM:
+	  fprintf(stderr, "Out of memory reading XSETTINGS property\n");
+	  break;
+	case XSETTINGS_ACCESS:
+	  fprintf(stderr, "Invalid XSETTINGS property (read off end)\n");
+	  break;
+	case XSETTINGS_DUPLICATE_ENTRY:
+	  fprintf (stderr, "Duplicate XSETTINGS entry for '%s'\n", setting->name);
+	case XSETTINGS_FAILED:
+	case XSETTINGS_SUCCESS:
+	case XSETTINGS_NO_ENTRY:
+	  break;
+	}
+
+      if (setting)
+	xsettings_setting_free (setting);
+
+      xsettings_list_free (settings);
+      settings = NULL;
+
+    }
+
+  return settings;
+}
+
+static void
+read_settings (XSettingsClient *client)
+{
+  Atom type;
+  int format;
+  unsigned long n_items;
+  unsigned long bytes_after;
+  unsigned char *data;
+  int result;
+
+  int (*old_handler) (Display *, XErrorEvent *);
+  
+  XSettingsList *old_list = client->settings;
+
+  client->settings = NULL;
+
+  if (client->manager_window)
+    {
+      old_handler = XSetErrorHandler (ignore_errors);
+      result = XGetWindowProperty (client->display, client->manager_window,
+				   client->xsettings_atom, 0, LONG_MAX,
+				   False, client->xsettings_atom,
+				   &type, &format, &n_items, &bytes_after, &data);
+      XSetErrorHandler (old_handler);
+      
+      if (result == Success && type != None)
+	{
+	  if (type != client->xsettings_atom)
+	    {
+	      fprintf (stderr, "Invalid type for XSETTINGS property");
+	    }
+	  else if (format != 8)
+	    {
+	      fprintf (stderr, "Invalid format for XSETTINGS property %d", format);
+	    }
+	  else
+	    client->settings = parse_settings (data, n_items);
+	  
+	  XFree (data);
+	}
+    }
+
+  notify_changes (client, old_list);
+  xsettings_list_free (old_list);
+}
+
+static void
+add_events (Display *display,
+	    Window   window,
+	    long     mask)
+{
+  XWindowAttributes attr;
+
+  XGetWindowAttributes (display, window, &attr);
+  XSelectInput (display, window, attr.your_event_mask | mask);
+}
+
+static void
+check_manager_window (XSettingsClient *client)
+{
+  if (client->manager_window && client->watch)
+    client->watch (client->manager_window, False, 0, client->cb_data);
+
+  if (client->grab)
+    client->grab (client->display);
+  else
+    XGrabServer (client->display);
+
+  client->manager_window = XGetSelectionOwner (client->display,
+					       client->selection_atom);
+  if (client->manager_window)
+    XSelectInput (client->display, client->manager_window,
+		  PropertyChangeMask | StructureNotifyMask);
+
+  if (client->ungrab)
+    client->ungrab (client->display);
+  else
+    XUngrabServer (client->display);
+  
+  XFlush (client->display);
+
+  if (client->manager_window && client->watch)
+    {
+      if (!client->watch (client->manager_window, True, 
+			  PropertyChangeMask | StructureNotifyMask,
+			  client->cb_data))
+	{
+	  /* Inability to watch the window probably means that it was destroyed
+	   * after we ungrabbed
+	   */
+	  client->manager_window = None;
+	  return;
+	}
+    }
+      
+  
+  read_settings (client);
+}
+
+XSettingsClient *
+xsettings_client_new (Display             *display,
+		      int                  screen,
+		      XSettingsNotifyFunc  notify,
+		      XSettingsWatchFunc   watch,
+		      void                *cb_data)
+{
+  return xsettings_client_new_with_grab_funcs (display, screen, notify, watch, cb_data,
+                                               NULL, NULL);
+}
+
+XSettingsClient *
+xsettings_client_new_with_grab_funcs (Display             *display,
+		                      int                  screen,
+		                      XSettingsNotifyFunc  notify,
+		                      XSettingsWatchFunc   watch,
+		                      void                *cb_data,
+		                      XSettingsGrabFunc    grab,
+		                      XSettingsGrabFunc    ungrab)
+{
+  XSettingsClient *client;
+  char buffer[256];
+  char *atom_names[3];
+  Atom atoms[3];
+  
+  client = malloc (sizeof *client);
+  if (!client)
+    return NULL;
+
+  client->display = display;
+  client->screen = screen;
+  client->notify = notify;
+  client->watch = watch;
+  client->cb_data = cb_data;
+  client->grab = grab;
+  client->ungrab = ungrab;
+  
+  client->manager_window = None;
+  client->settings = NULL;
+
+  sprintf(buffer, "_XSETTINGS_S%d", screen);
+  atom_names[0] = buffer;
+  atom_names[1] = "_XSETTINGS_SETTINGS";
+  atom_names[2] = "MANAGER";
+
+#ifdef HAVE_XINTERNATOMS
+  XInternAtoms (display, atom_names, 3, False, atoms);
+#else
+  atoms[0] = XInternAtom (display, atom_names[0], False);
+  atoms[1] = XInternAtom (display, atom_names[1], False);
+  atoms[2] = XInternAtom (display, atom_names[2], False);
+#endif
+  
+  client->selection_atom = atoms[0];
+  client->xsettings_atom = atoms[1];
+  client->manager_atom = atoms[2];
+
+  /* Select on StructureNotify so we get MANAGER events
+   */
+  add_events (display, RootWindow (display, screen), StructureNotifyMask);
+
+  if (client->watch)
+    client->watch (RootWindow (display, screen), True, StructureNotifyMask,
+		   client->cb_data);
+
+  check_manager_window (client);
+
+  return client;
+}
+
+
+void
+xsettings_client_set_grab_func   (XSettingsClient      *client,
+				  XSettingsGrabFunc     grab)
+{
+  client->grab = grab;
+}
+
+void
+xsettings_client_set_ungrab_func (XSettingsClient      *client,
+				  XSettingsGrabFunc     ungrab)
+{
+  client->ungrab = ungrab;
+}
+
+void
+xsettings_client_destroy (XSettingsClient *client)
+{
+  if (client->watch)
+    client->watch (RootWindow (client->display, client->screen),
+		   False, 0, client->cb_data);
+  if (client->manager_window && client->watch)
+    client->watch (client->manager_window, False, 0, client->cb_data);
+  
+  xsettings_list_free (client->settings);
+  free (client);
+}
+
+XSettingsResult
+xsettings_client_get_setting (XSettingsClient   *client,
+			      const char        *name,
+			      XSettingsSetting **setting)
+{
+  XSettingsSetting *search = xsettings_list_lookup (client->settings, name);
+  if (search)
+    {
+      *setting = xsettings_setting_copy (search);
+      return *setting ? XSETTINGS_SUCCESS : XSETTINGS_NO_MEM;
+    }
+  else
+    return XSETTINGS_NO_ENTRY;
+}
+
+Bool
+xsettings_client_process_event (XSettingsClient *client,
+				XEvent          *xev)
+{
+  /* The checks here will not unlikely cause us to reread
+   * the properties from the manager window a number of
+   * times when the manager changes from A->B. But manager changes
+   * are going to be pretty rare.
+   */
+  if (xev->xany.window == RootWindow (client->display, client->screen))
+    {
+      if (xev->xany.type == ClientMessage &&
+	  xev->xclient.message_type == client->manager_atom &&
+	  xev->xclient.data.l[1] == client->selection_atom)
+	{
+	  check_manager_window (client);
+	  return True;
+	}
+    }
+  else if (xev->xany.window == client->manager_window)
+    {
+      if (xev->xany.type == DestroyNotify)
+	{
+	  check_manager_window (client);
+          /* let GDK do its cleanup */
+	  return False; 
+	}
+      else if (xev->xany.type == PropertyNotify)
+	{
+	  read_settings (client);
+	  return True;
+	}
+    }
+  
+  return False;
+}
diff --git a/gdk/broadway/xsettings-client.h b/gdk/broadway/xsettings-client.h
new file mode 100644
index 0000000..710ed12
--- /dev/null
+++ b/gdk/broadway/xsettings-client.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2001, 2007 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Owen Taylor, Red Hat, Inc.
+ */
+#ifndef XSETTINGS_CLIENT_H
+#define XSETTINGS_CLIENT_H
+
+#include <X11/Xlib.h>
+#include "xsettings-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _XSettingsClient XSettingsClient;
+
+typedef enum 
+{
+  XSETTINGS_ACTION_NEW,
+  XSETTINGS_ACTION_CHANGED,
+  XSETTINGS_ACTION_DELETED
+} XSettingsAction;
+
+typedef void (*XSettingsNotifyFunc) (const char       *name,
+				     XSettingsAction   action,
+				     XSettingsSetting *setting,
+				     void             *cb_data);
+typedef Bool (*XSettingsWatchFunc)  (Window            window,
+				     Bool              is_start,
+				     long              mask,
+				     void             *cb_data);
+typedef void (*XSettingsGrabFunc)   (Display          *display);
+
+XSettingsClient *xsettings_client_new             (Display             *display,
+						   int                  screen,
+						   XSettingsNotifyFunc  notify,
+						   XSettingsWatchFunc   watch,
+						   void                *cb_data);
+XSettingsClient *xsettings_client_new_with_grab_funcs (Display             *display,
+						       int                  screen,
+						       XSettingsNotifyFunc  notify,
+						       XSettingsWatchFunc   watch,
+						       void                *cb_data,
+                                                       XSettingsGrabFunc    grab,
+                                                       XSettingsGrabFunc    ungrab);
+void             xsettings_client_set_grab_func   (XSettingsClient     *client,
+						   XSettingsGrabFunc    grab);
+void             xsettings_client_set_ungrab_func (XSettingsClient     *client,
+						   XSettingsGrabFunc    ungrab);
+void             xsettings_client_destroy         (XSettingsClient     *client);
+Bool             xsettings_client_process_event   (XSettingsClient     *client,
+						   XEvent              *xev);
+XSettingsResult  xsettings_client_get_setting     (XSettingsClient     *client,
+						   const char          *name,
+						   XSettingsSetting   **setting);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XSETTINGS_CLIENT_H */
diff --git a/gdk/broadway/xsettings-common.c b/gdk/broadway/xsettings-common.c
new file mode 100644
index 0000000..cc3a8d0
--- /dev/null
+++ b/gdk/broadway/xsettings-common.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Owen Taylor, Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include "xsettings-common.h"
+
+#include "string.h"
+#include "stdlib.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xmd.h>		/* For CARD32 */
+
+XSettingsSetting *
+xsettings_setting_copy (XSettingsSetting *setting)
+{
+  XSettingsSetting *result;
+  size_t str_len;
+  
+  result = malloc (sizeof *result);
+  if (!result)
+    return NULL;
+
+  str_len = strlen (setting->name);
+  result->name = malloc (str_len + 1);
+  if (!result->name)
+    goto err;
+
+  memcpy (result->name, setting->name, str_len + 1);
+
+  result->type = setting->type;
+
+  switch (setting->type)
+    {
+    case XSETTINGS_TYPE_INT:
+      result->data.v_int = setting->data.v_int;
+      break;
+    case XSETTINGS_TYPE_COLOR:
+      result->data.v_color = setting->data.v_color;
+      break;
+    case XSETTINGS_TYPE_STRING:
+      str_len = strlen (setting->data.v_string);
+      result->data.v_string = malloc (str_len + 1);
+      if (!result->data.v_string)
+	goto err;
+
+      memcpy (result->data.v_string, setting->data.v_string, str_len + 1);
+      break;
+    }
+
+  result->last_change_serial = setting->last_change_serial;
+
+  return result;
+
+ err:
+  if (result->name)
+    free (result->name);
+  free (result);
+  
+  return NULL;
+}
+
+XSettingsList *
+xsettings_list_copy (XSettingsList *list)
+{
+  XSettingsList *new = NULL;
+  XSettingsList *old_iter = list;
+  XSettingsList *new_iter = NULL;
+
+  while (old_iter)
+    {
+      XSettingsList *new_node;
+
+      new_node = malloc (sizeof *new_node);
+      if (!new_node)
+	goto error;
+
+      new_node->setting = xsettings_setting_copy (old_iter->setting);
+      if (!new_node->setting)
+	{
+	  free (new_node);
+	  goto error;
+	}
+
+      if (new_iter)
+	new_iter->next = new_node;
+      else
+	new = new_node;
+
+      new_iter = new_node;
+      
+      old_iter = old_iter->next;
+    }
+
+  return new;
+
+ error:
+  xsettings_list_free (new);
+  return NULL;
+}
+
+int
+xsettings_setting_equal (XSettingsSetting *setting_a,
+			 XSettingsSetting *setting_b)
+{
+  if (setting_a->type != setting_b->type)
+    return 0;
+
+  if (strcmp (setting_a->name, setting_b->name) != 0)
+    return 0;
+
+  switch (setting_a->type)
+    {
+    case XSETTINGS_TYPE_INT:
+      return setting_a->data.v_int == setting_b->data.v_int;
+    case XSETTINGS_TYPE_COLOR:
+      return (setting_a->data.v_color.red == setting_b->data.v_color.red &&
+	      setting_a->data.v_color.green == setting_b->data.v_color.green &&
+	      setting_a->data.v_color.blue == setting_b->data.v_color.blue &&
+	      setting_a->data.v_color.alpha == setting_b->data.v_color.alpha);
+    case XSETTINGS_TYPE_STRING:
+      return strcmp (setting_a->data.v_string, setting_b->data.v_string) == 0;
+    }
+
+  return 0;
+}
+
+void
+xsettings_setting_free (XSettingsSetting *setting)
+{
+  if (setting->type == XSETTINGS_TYPE_STRING)
+    free (setting->data.v_string);
+
+  if (setting->name)
+    free (setting->name);
+  
+  free (setting);
+}
+
+void
+xsettings_list_free (XSettingsList *list)
+{
+  while (list)
+    {
+      XSettingsList *next = list->next;
+
+      xsettings_setting_free (list->setting);
+      free (list);
+
+      list = next;
+    }
+}
+
+XSettingsResult
+xsettings_list_insert (XSettingsList    **list,
+		       XSettingsSetting  *setting)
+{
+  XSettingsList *node;
+  XSettingsList *iter;
+  XSettingsList *last = NULL;
+
+  node = malloc (sizeof *node);
+  if (!node)
+    return XSETTINGS_NO_MEM;
+  node->setting = setting;
+
+  iter = *list;
+  while (iter)
+    {
+      int cmp = strcmp (setting->name, iter->setting->name);
+
+      if (cmp < 0)
+	break;
+      else if (cmp == 0)
+	{
+	  free (node);
+	  return XSETTINGS_DUPLICATE_ENTRY;
+	}
+
+      last = iter;
+      iter = iter->next;
+    }
+  
+  if (last)
+    last->next = node;
+  else
+    *list = node;
+  
+  node->next = iter;
+  
+  return XSETTINGS_SUCCESS;
+}
+
+XSettingsResult
+xsettings_list_delete (XSettingsList **list,
+		       const char     *name)
+{
+  XSettingsList *iter;
+  XSettingsList *last = NULL;
+
+  iter = *list;
+  while (iter)
+    {
+      if (strcmp (name, iter->setting->name) == 0)
+	{
+	  if (last)
+	    last->next = iter->next;
+	  else
+	    *list = iter->next;
+  
+	  xsettings_setting_free (iter->setting);
+	  free (iter);
+
+	  return XSETTINGS_SUCCESS;
+	}
+
+      last = iter;
+      iter = iter->next;
+    }
+
+  return XSETTINGS_FAILED;
+}
+
+XSettingsSetting *
+xsettings_list_lookup (XSettingsList *list,
+		       const char    *name)
+{
+  XSettingsList *iter;
+
+  iter = list;
+  while (iter)
+    {
+      if (strcmp (name, iter->setting->name) == 0)
+	return iter->setting;
+
+      iter = iter->next;
+    }
+
+  return NULL;
+}
+
+char
+xsettings_byte_order (void)
+{
+  CARD32 myint = 0x01020304;
+  return (*(char *)&myint == 1) ? MSBFirst : LSBFirst;
+}
diff --git a/gdk/broadway/xsettings-common.h b/gdk/broadway/xsettings-common.h
new file mode 100644
index 0000000..de7367a
--- /dev/null
+++ b/gdk/broadway/xsettings-common.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Owen Taylor, Red Hat, Inc.
+ */
+#ifndef XSETTINGS_COMMON_H
+#define XSETTINGS_COMMON_H
+
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Renames for GDK inclusion */
+
+#define xsettings_byte_order             _gdk_xsettings_byte_order
+#define xsettings_client_destroy         _gdk_xsettings_client_destroy
+#define xsettings_client_get_setting     _gdk_xsettings_client_get_setting
+#define xsettings_client_new             _gdk_xsettings_client_new
+#define xsettings_client_new_with_grab_funcs _gdk_xsettings_client_new_with_grab_funcs
+#define xsettings_client_set_grab_func   _gdk_xsettings_client_set_grab_func
+#define xsettings_client_set_ungrab_func _gdk_xsettings_client_set_ungrab_func
+#define xsettings_client_process_event   _gdk_xsettings_client_process_event
+#define xsettings_list_copy              _gdk_xsettings_list_copy
+#define xsettings_list_delete            _gdk_xsettings_list_delete
+#define xsettings_list_free              _gdk_xsettings_list_free
+#define xsettings_list_insert            _gdk_xsettings_list_insert
+#define xsettings_list_lookup            _gdk_xsettings_list_lookup
+#define xsettings_setting_copy           _gdk_xsettings_setting_copy
+#define xsettings_setting_equal          _gdk_xsettings_setting_equal
+#define xsettings_setting_free           _gdk_xsettings_setting_free
+
+
+typedef struct _XSettingsBuffer  XSettingsBuffer;
+typedef struct _XSettingsColor   XSettingsColor;
+typedef struct _XSettingsList    XSettingsList;
+typedef struct _XSettingsSetting XSettingsSetting;
+
+/* Types of settings possible. Enum values correspond to
+ * protocol values.
+ */
+typedef enum 
+{
+  XSETTINGS_TYPE_INT     = 0,
+  XSETTINGS_TYPE_STRING  = 1,
+  XSETTINGS_TYPE_COLOR   = 2
+} XSettingsType;
+
+typedef enum
+{
+  XSETTINGS_SUCCESS,
+  XSETTINGS_NO_MEM,
+  XSETTINGS_ACCESS,
+  XSETTINGS_FAILED,
+  XSETTINGS_NO_ENTRY,
+  XSETTINGS_DUPLICATE_ENTRY
+} XSettingsResult;
+
+struct _XSettingsBuffer
+{
+  char byte_order;
+  size_t len;
+  unsigned char *data;
+  unsigned char *pos;
+};
+
+struct _XSettingsColor
+{
+  unsigned short red, green, blue, alpha;
+};
+
+struct _XSettingsList
+{
+  XSettingsSetting *setting;
+  XSettingsList *next;
+};
+
+struct _XSettingsSetting
+{
+  char *name;
+  XSettingsType type;
+  
+  union {
+    int v_int;
+    char *v_string;
+    XSettingsColor v_color;
+  } data;
+
+  unsigned long last_change_serial;
+};
+
+XSettingsSetting *xsettings_setting_copy  (XSettingsSetting *setting);
+void              xsettings_setting_free  (XSettingsSetting *setting);
+int               xsettings_setting_equal (XSettingsSetting *setting_a,
+					   XSettingsSetting *setting_b);
+
+void              xsettings_list_free   (XSettingsList     *list);
+XSettingsList    *xsettings_list_copy   (XSettingsList     *list);
+XSettingsResult   xsettings_list_insert (XSettingsList    **list,
+					 XSettingsSetting  *setting);
+XSettingsSetting *xsettings_list_lookup (XSettingsList     *list,
+					 const char        *name);
+XSettingsResult   xsettings_list_delete (XSettingsList    **list,
+					 const char        *name);
+
+char xsettings_byte_order (void);
+
+#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XSETTINGS_COMMON_H */
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index b6a92a9..edef527 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -812,18 +812,22 @@ gtkinclude_HEADERS = $(gtk_public_h_sources) $(gtk_semi_private_h_sources) $(gtk
 gtkunixprintincludedir = $(includedir)/gtk-3.0/unix-print/gtk
 gtkunixprintinclude_HEADERS = $(gtk_unix_print_public_h_sources)
 
+libgtk_broadway_3_0_la_SOURCES = $(gtk_c_sources)
 libgtk_x11_3_0_la_SOURCES = $(gtk_c_sources)
 libgtk_win32_3_0_la_SOURCES = $(gtk_c_sources)
 libgtk_quartz_3_0_la_SOURCES = $(gtk_c_sources)
 
+libgtk_broadway_3_0_la_LDFLAGS = $(libtool_opts)
 libgtk_x11_3_0_la_LDFLAGS = $(libtool_opts)
 libgtk_win32_3_0_la_LDFLAGS = $(libtool_opts) -Wl,-luuid
 libgtk_quartz_3_0_la_LDFLAGS = $(libtool_opts)
 
+libgtk_broadway_3_0_la_LIBADD = $(libadd)
 libgtk_x11_3_0_la_LIBADD = $(libadd)
 libgtk_win32_3_0_la_LIBADD = $(libadd) -lole32 -lgdi32 -lcomdlg32 -lwinspool -lcomctl32
 libgtk_quartz_3_0_la_LIBADD = $(libadd)
 
+libgtk_broadway_3_0_la_DEPENDENCIES = $(deps)
 libgtk_x11_3_0_la_DEPENDENCIES = $(deps)
 libgtk_win32_3_0_la_DEPENDENCIES = $(gtk_def) $(gtk_win32_res) $(deps)
 libgtk_quartz_3_0_la_DEPENDENCIES = $(deps)
@@ -831,7 +835,7 @@ libgtk_quartz_3_0_la_DEPENDENCIES = $(deps)
 if USE_WIN32
 libgtk_target_ldflags = $(gtk_win32_res_ldflag) $(gtk_win32_symbols)
 endif
-EXTRA_LTLIBRARIES = libgtk-x11-3.0.la libgtk-win32-3.0.la libgtk-quartz-3.0.la
+EXTRA_LTLIBRARIES = libgtk-broadway-3.0.la libgtk-x11-3.0.la libgtk-win32-3.0.la libgtk-quartz-3.0.la
 
 install-exec-hook:
 if DISABLE_EXPLICIT_DEPS
diff --git a/tests/testsocket_common.c b/tests/testsocket_common.c
index 995dbf9..6dcabb3 100644
--- a/tests/testsocket_common.c
+++ b/tests/testsocket_common.c
@@ -280,6 +280,8 @@ create_child_plug (guint32  xid,
     return GDK_WINDOW_XID (gtk_widget_get_window (window));
 #elif defined (GDK_WINDOWING_WIN32)
     return (guint32) GDK_WINDOW_HWND (gtk_widget_get_window (window));
+#elif defined (GDK_WINDOWING_BROADWAY)
+    return (guint32) 0; /* Child windows not supported */
 #endif
   else
     return 0;



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