]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkevents-x11.c
Call the filters on the window where the event is received, not on the
[~andy/gtk] / gdk / x11 / gdkevents-x11.c
index c15fe8ce2bdb16eb6f67a992f678b3c9a3cd2f0a..e32fe2182b29e0ed00d7a3a1e77b9078ba9fc2d2 100644 (file)
@@ -2,34 +2,39 @@
  * 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 Library General Public
+ * 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
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * 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-1999.  See the AUTHORS
+ * 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 "gdk.h"
-#include "gdkprivate.h"
+#include "gdkprivate-x11.h"
+#include "gdkinternals.h"
 #include "gdkx.h"
+#include "gdkscreen-x11.h"
+#include "gdkdisplay-x11.h"
 
 #include "gdkkeysyms.h"
 
+#include "xsettings-client.h"
+
 #if HAVE_CONFIG_H
 #  include <config.h>
 #  if STDC_HEADERS
 
 #include "gdkinputprivate.h"
 
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+#include <X11/Xatom.h>
+
 typedef struct _GdkIOClosure GdkIOClosure;
-typedef struct _GdkEventPrivate GdkEventPrivate;
+typedef struct _GdkDisplaySource GdkDisplaySource;
 
 #define DOUBLE_CLICK_TIME      250
 #define TRIPLE_CLICK_TIME      500
 #define DOUBLE_CLICK_DIST      5
 #define TRIPLE_CLICK_DIST      5
 
-typedef enum
-{
-  /* Following flag is set for events on the event queue during
-   * translation and cleared afterwards.
-   */
-  GDK_EVENT_PENDING = 1 << 0
-} GdkEventFlags;
-
 struct _GdkIOClosure
 {
   GdkInputFunction function;
@@ -63,10 +66,12 @@ struct _GdkIOClosure
   gpointer data;
 };
 
-struct _GdkEventPrivate
+struct _GdkDisplaySource
 {
-  GdkEvent event;
-  guint    flags;
+  GSource source;
+  
+  GdkDisplay *display;
+  GPollFD event_poll_fd;
 };
 
 /* 
@@ -76,115 +81,163 @@ struct _GdkEventPrivate
 static gint     gdk_event_apply_filters (XEvent   *xevent,
                                          GdkEvent *event,
                                          GList    *filters);
-static gint     gdk_event_translate     (GdkEvent *event, 
-                                         XEvent   *xevent);
-#if 0
-static Bool     gdk_event_get_type     (Display   *display, 
-                                        XEvent    *xevent, 
-                                        XPointer   arg);
-#endif
-
-static gboolean  gdk_event_prepare      (gpointer   source_data, 
-                                        GTimeVal  *current_time,
-                                        gint      *timeout,
-                                        gpointer   user_data);
-static gboolean  gdk_event_check        (gpointer   source_data,
-                                        GTimeVal  *current_time,
-                                        gpointer   user_data);
-static gboolean  gdk_event_dispatch     (gpointer   source_data,
-                                        GTimeVal  *current_time,
-                                        gpointer   user_data);
-
-GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
-                                        GdkEvent  *event,
-                                        gpointer   data);
+static gboolean         gdk_event_translate     (GdkDisplay *display,
+                                         GdkEvent   *event, 
+                                         XEvent     *xevent,
+                                         gboolean    return_exposes);
+
+static gboolean gdk_event_prepare  (GSource     *source,
+                                   gint        *timeout);
+static gboolean gdk_event_check    (GSource     *source);
+static gboolean gdk_event_dispatch (GSource     *source,
+                                   GSourceFunc  callback,
+                                   gpointer     user_data);
+
+static GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
+                                               GdkEvent  *event,
+                                               gpointer   data);
+
+static GSource *gdk_display_source_new (GdkDisplay *display);
+static gboolean gdk_check_xpending     (GdkDisplay *display);
+
+static void gdk_xsettings_watch_cb  (Window            window,
+                                    Bool              is_start,
+                                    long              mask,
+                                    void             *cb_data);
+static void gdk_xsettings_notify_cb (const char       *name,
+                                    XSettingsAction   action,
+                                    XSettingsSetting *setting,
+                                    void             *data);
 
 /* Private variable declarations
  */
 
-static int connection_number = 0;          /* The file descriptor number of our
-                                            *  connection to the X server. This
-                                            *  is used so that we may determine
-                                            *  when events are pending by using
-                                            *  the "select" system call.
-                                            */
-static GList *client_filters;              /* Filters for client messages */
+static GList *display_sources;
 
 static GSourceFuncs event_funcs = {
   gdk_event_prepare,
   gdk_event_check,
   gdk_event_dispatch,
-  (GDestroyNotify)g_free
+  NULL
 };
 
-GPollFD event_poll_fd;
+static GSource *
+gdk_display_source_new (GdkDisplay *display)
+{
+  GSource *source = g_source_new (&event_funcs, sizeof (GdkDisplaySource));
+  GdkDisplaySource *display_source = (GdkDisplaySource *)source;
+  
+  display_source->display = display;
+  
+  return source;
+}
+
+static gboolean
+gdk_check_xpending (GdkDisplay *display)
+{
+  return XPending (GDK_DISPLAY_XDISPLAY (display));
+}
 
 /*********************************************
  * Functions for maintaining the event queue *
  *********************************************/
 
+void
+_gdk_x11_events_init_screen (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 (screen_x11->xdisplay,
+                                                      screen_x11->screen_num,
+                                                      gdk_xsettings_notify_cb,
+                                                      gdk_xsettings_watch_cb,
+                                                      screen);
+  screen_x11->xsettings_in_init = FALSE;
+}
+
+void
+_gdk_x11_events_uninit_screen (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+  xsettings_client_destroy (screen_x11->xsettings_client);
+  screen_x11->xsettings_client = NULL;
+}
+
 void 
-gdk_events_init (void)
+_gdk_events_init (GdkDisplay *display)
 {
-  connection_number = ConnectionNumber (gdk_display);
-  GDK_NOTE (MISC,
-           g_message ("connection number: %d", connection_number));
+  GSource *source;
+  GdkDisplaySource *display_source;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  
+  int connection_number = ConnectionNumber (display_x11->xdisplay);
+  GDK_NOTE (MISC, g_message ("connection number: %d", connection_number));
 
-  g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL);
 
-  event_poll_fd.fd = connection_number;
-  event_poll_fd.events = G_IO_IN;
+  source = display_x11->event_source = gdk_display_source_new (display);
+  display_source = (GdkDisplaySource*) source;
+  g_source_set_priority (source, GDK_PRIORITY_EVENTS);
+  
+  display_source->event_poll_fd.fd = connection_number;
+  display_source->event_poll_fd.events = G_IO_IN;
   
-  g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS);
+  g_source_add_poll (source, &display_source->event_poll_fd);
+  g_source_set_can_recurse (source, TRUE);
+  g_source_attach (source, NULL);
 
-  gdk_add_client_message_filter (gdk_wm_protocols, 
-                                gdk_wm_protocols_filter, NULL);
+  display_sources = g_list_prepend (display_sources,display_source);
+
+  gdk_display_add_client_message_filter (
+       display,
+       gdk_atom_intern ("WM_PROTOCOLS", FALSE), 
+       gdk_wm_protocols_filter,   
+       NULL);
 }
 
-/*
- *--------------------------------------------------------------
- * gdk_events_pending
- *
- *   Returns if events are pending on the queue.
- *
- * Arguments:
- *
- * Results:
- *   Returns TRUE if events are pending
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
 
+/**
+ * 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)
 {
-  return (gdk_event_queue_find_first() || XPending (gdk_display));
-}
+  GList *tmp_list;
 
-/*
- *--------------------------------------------------------------
- * gdk_event_get_graphics_expose
- *
- *   Waits for a GraphicsExpose or NoExpose event
- *
- * Arguments:
- *
- * Results: 
- *   For GraphicsExpose events, returns a pointer to the event
- *   converted into a GdkEvent Otherwise, returns NULL.
- *
- * Side effects:
- *
- *-------------------------------------------------------------- */
+  for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next)
+    {
+      GdkDisplaySource *tmp_source = tmp_list->data;
+      GdkDisplay *display = tmp_source->display;
+      
+      if (_gdk_event_queue_find_first (display))
+       return TRUE;
+    }
+
+  for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next)
+    {
+      GdkDisplaySource *tmp_source = tmp_list->data;
+      GdkDisplay *display = tmp_source->display;
+      
+      if (gdk_check_xpending (display))
+       return TRUE;
+    }
+  
+  return FALSE;
+}
 
 static Bool
 graphics_expose_predicate (Display  *display,
                           XEvent   *xevent,
                           XPointer  arg)
 {
-  if (xevent->xany.window == GDK_DRAWABLE_XID (arg) &&
+  if (xevent->xany.window == GDK_DRAWABLE_XID ((GdkDrawable *)arg) &&
       (xevent->xany.type == GraphicsExpose ||
        xevent->xany.type == NoExpose))
     return True;
@@ -192,6 +245,17 @@ graphics_expose_predicate (Display  *display,
     return False;
 }
 
+/**
+ * gdk_event_get_graphics_expose:
+ * @window: the #GdkWindow to wait for the events for.
+ * 
+ * Waits for a GraphicsExpose or NoExpose event from the X server.
+ * This is used in the #GtkText and #GtkCList widgets in GTK+ to make sure any
+ * GraphicsExpose events are handled before the widget is scrolled.
+ *
+ * Return value:  a #GdkEventExpose if a GraphicsExpose was received, or %NULL if a
+ * NoExpose event was received.
+ **/
 GdkEvent*
 gdk_event_get_graphics_expose (GdkWindow *window)
 {
@@ -200,13 +264,15 @@ gdk_event_get_graphics_expose (GdkWindow *window)
   
   g_return_val_if_fail (window != NULL, NULL);
   
-  XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer) window);
+  XIfEvent (GDK_WINDOW_XDISPLAY (window), &xevent, 
+           graphics_expose_predicate, (XPointer) window);
   
   if (xevent.xany.type == GraphicsExpose)
     {
-      event = gdk_event_new ();
+      event = gdk_event_new (GDK_NOTHING);
       
-      if (gdk_event_translate (event, &xevent))
+      if (gdk_event_translate (GDK_WINDOW_DISPLAY (window), event,
+                              &xevent, TRUE))
        return event;
       else
        gdk_event_free (event);
@@ -215,353 +281,582 @@ gdk_event_get_graphics_expose (GdkWindow *window)
   return NULL; 
 }
 
-/************************
- * Exposure compression *
- ************************/
+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;
+}
 
-/*
- * The following implements simple exposure compression. It is
- * modelled after the way Xt does exposure compression - in
- * particular compress_expose = XtExposeCompressMultiple.
- * It compress consecutive sequences of exposure events,
- * but not sequences that cross other events. (This is because
- * if it crosses a ConfigureNotify, we could screw up and
- * mistakenly compress the exposures generated for the new
- * size - could we just check for ConfigureNotify?)
+/**
+ * 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.
  *
- * Xt compresses to a region / bounding rectangle, we compress
- * to two rectangles, and try find the two rectangles of minimal
- * area for this - this is supposed to handle the typical
- * L-shaped regions generated by OpaqueMove.
- */
+ * Adds a filter to be called when X ClientMessage events are received.
+ *
+ * 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);
 
-/* Given three rectangles, find the two rectangles that cover
- * them with the smallest area.
- */
-static void
-gdk_add_rect_to_rects (GdkRectangle *rect1,
-                      GdkRectangle *rect2, 
-                      GdkRectangle *new_rect)
+  filter->type = message_type;
+  filter->function = func;
+  filter->data = data;
+  
+  GDK_DISPLAY_X11(display)->client_filters = 
+    g_list_prepend (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)
 {
-  GdkRectangle t1, t2, t3;
-  gint size1, size2, size3;
+  gdk_display_add_client_message_filter (gdk_display_get_default (),
+                                        message_type, func, data);
+}
 
-  gdk_rectangle_union (rect1, rect2, &t1);
-  gdk_rectangle_union (rect1, new_rect, &t2);
-  gdk_rectangle_union (rect2, new_rect, &t3);
+static void
+gdk_check_wm_state_changed (GdkWindow *window)
+{  
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  Atom *atoms = NULL;
+  gulong i;
+  gboolean found_sticky, found_maxvert, found_maxhorz, found_fullscreen;
+  GdkWindowState old_state;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+  
+  if (GDK_WINDOW_DESTROYED (window) ||
+      gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL)
+    return;
+  
+  found_sticky = FALSE;
+  found_maxvert = FALSE;
+  found_maxhorz = FALSE;
+  found_fullscreen = FALSE;
+  
+  XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), 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, (guchar **)&atoms);
+
+  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");
+      
+      i = 0;
+      while (i < nitems)
+        {
+          if (atoms[i] == sticky_atom)
+            found_sticky = TRUE;
+          else if (atoms[i] == maxvert_atom)
+            found_maxvert = TRUE;
+          else if (atoms[i] == maxhorz_atom)
+            found_maxhorz = TRUE;
+          else if (atoms[i] == fullscreen_atom)
+            found_fullscreen = TRUE;
+          
+          ++i;
+        }
+
+      XFree (atoms);
+    }
 
-  size1 = t1.width * t1.height + new_rect->width * new_rect->height;
-  size2 = t2.width * t2.height + rect2->width * rect2->height;
-  size3 = t1.width * t1.height + rect1->width * rect1->height;
+  /* For found_sticky to remain TRUE, we have to also be on desktop
+   * 0xFFFFFFFF
+   */
 
-  if (size1 < size2)
+  if (found_sticky)
     {
-      if (size1 < size3)
-       {
-         *rect1 = t1;
-         *rect2 = *new_rect;
-       }
-      else
-       *rect2 = t3;
+      gulong *desktop;
+      
+      XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), 
+                         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, (guchar **)&desktop);
+
+      if (type != None)
+        {
+          if (*desktop != 0xFFFFFFFF)
+            found_sticky = FALSE;
+          XFree (desktop);
+        }
+    }
+          
+  old_state = gdk_window_get_state (window);
+
+  if (old_state & GDK_WINDOW_STATE_STICKY)
+    {
+      if (!found_sticky)
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_STICKY,
+                                     0);
     }
   else
     {
-      if (size2 < size3)
-       *rect1 = t2;
-      else
-       *rect2 = t3;
+      if (found_sticky)
+        gdk_synthesize_window_state (window,
+                                     0,
+                                     GDK_WINDOW_STATE_STICKY);
     }
-}
-
-typedef struct _GdkExposeInfo GdkExposeInfo;
-
-struct _GdkExposeInfo
-{
-  Window window;
-  gboolean seen_nonmatching;
-};
 
-static Bool
-expose_predicate (Display *display,
-                 XEvent  *xevent,
-                 XPointer arg)
-{
-  GdkExposeInfo *info = (GdkExposeInfo*) arg;
-
-  /* Compressing across GravityNotify events is safe, because
-   * we completely ignore them, so they can't change what
-   * we are going to draw. Compressing across GravityNotify
-   * events is necessay because during window-unshading animation
-   * we'll get a whole bunch of them interspersed with
-   * expose events.
+  if (old_state & GDK_WINDOW_STATE_FULLSCREEN)
+    {
+      if (!found_fullscreen)
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_FULLSCREEN,
+                                     0);
+    }
+  else
+    {
+      if (found_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 (xevent->xany.type != Expose && 
-      xevent->xany.type != GravityNotify)
+  if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
     {
-      info->seen_nonmatching = TRUE;
+      if (!(found_maxvert && found_maxhorz))
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_MAXIMIZED,
+                                     0);
     }
-
-  if (info->seen_nonmatching ||
-      xevent->xany.type != Expose ||
-      xevent->xany.window != info->window)
-    return FALSE;
   else
-    return TRUE;
+    {
+      if (found_maxvert && found_maxhorz)
+        gdk_synthesize_window_state (window,
+                                     0,
+                                     GDK_WINDOW_STATE_MAXIMIZED);
+    }
 }
 
-void
-gdk_compress_exposures (XEvent    *xevent,
-                       GdkWindow *window)
+#define HAS_FOCUS(window_impl)                           \
+  ((window_impl)->has_focus || (window_impl)->has_pointer_focus)
+
+static void
+generate_focus_event (GdkWindow *window,
+                     gboolean   in)
 {
-  gint nrects = 1;
-  gint count = 0;
-  GdkRectangle rect1;
-  GdkRectangle rect2;
-  GdkRectangle tmp_rect;
-  XEvent tmp_event;
-  GdkFilterReturn result;
-  GdkExposeInfo info;
   GdkEvent event;
-
-  info.window = xevent->xany.window;
-  info.seen_nonmatching = FALSE;
   
-  rect1.x = xevent->xexpose.x;
-  rect1.y = xevent->xexpose.y;
-  rect1.width = xevent->xexpose.width;
-  rect1.height = xevent->xexpose.height;
-
-  event.any.type = GDK_EXPOSE;
-  event.any.window = None;
-  event.any.send_event = FALSE;
+  event.type = GDK_FOCUS_CHANGE;
+  event.focus_change.window = window;
+  event.focus_change.send_event = FALSE;
+  event.focus_change.in = in;
   
-  while (1)
-    {
-      if (count == 0)
-       {
-         if (!XCheckIfEvent (gdk_display, 
-                             &tmp_event, 
-                             expose_predicate, 
-                             (XPointer)&info))
-           break;
-       }
-      else
-       XIfEvent (gdk_display, 
-                 &tmp_event, 
-                 expose_predicate, 
-                 (XPointer)&info);
+  gdk_event_put (&event);
+}
 
-      event.any.window = window;
-      
-      /* We apply filters here, and if it was filtered, completely
-       * ignore the return
-       */
-      result = gdk_event_apply_filters (xevent, &event,
-                                       window ? 
-                                         ((GdkWindowPrivate *)window)->filters
-                                         : gdk_default_filters);
-      
-      if (result != GDK_FILTER_CONTINUE)
-       {
-         if (result == GDK_FILTER_TRANSLATE)
-           gdk_event_put (&event);
-         continue;
-       }
+static void
+set_screen_from_root (GdkDisplay *display,
+                     GdkEvent   *event,
+                     Window      xrootwin)
+{
+  GdkScreen *screen;
 
-      if (nrects == 1)
-       {
-         rect2.x = tmp_event.xexpose.x;
-         rect2.y = tmp_event.xexpose.y;
-         rect2.width = tmp_event.xexpose.width;
-         rect2.height = tmp_event.xexpose.height;
+  screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
+  g_assert (screen);
 
-         nrects++;
-       }
-      else
-       {
-         tmp_rect.x = tmp_event.xexpose.x;
-         tmp_rect.y = tmp_event.xexpose.y;
-         tmp_rect.width = tmp_event.xexpose.width;
-         tmp_rect.height = tmp_event.xexpose.height;
+  gdk_event_set_screen (event, screen);
+}
 
-         gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect);
-       }
+static void
+translate_key_event (GdkDisplay *display,
+                    GdkEvent   *event,
+                    XEvent     *xevent)
+{
+  GdkKeymap *keymap = gdk_keymap_get_for_display (display);
+  gunichar c = 0;
+  guchar buf[7];
 
-      count = tmp_event.xexpose.count;
-    }
+  event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
+  event->key.time = xevent->xkey.time;
+
+  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_VoidSymbol;
+
+  gdk_keymap_translate_keyboard_state (keymap,
+                                      event->key.hardware_keycode,
+                                      event->key.state,
+                                      event->key.group,
+                                      &event->key.keyval,
+                                      NULL, NULL, NULL);
+
+  /* Fill in event->string crudely, since various programs
+   * depend on it.
+   */
+  event->key.string = NULL;
+  
+  if (event->key.keyval != GDK_VoidSymbol)
+    c = gdk_keyval_to_unicode (event->key.keyval);
 
-  if (nrects == 2)
+  if (c)
     {
-      gdk_rectangle_union (&rect1, &rect2, &tmp_rect);
+      gsize bytes_written;
+      gint len;
 
-      if ((tmp_rect.width * tmp_rect.height) <
-         2 * (rect1.height * rect1.width +
-              rect2.height * rect2.width))
+      /* Apply the control key - Taken from Xlib
+       */
+      if (event->key.state & GDK_CONTROL_MASK)
        {
-         rect1 = tmp_rect;
-         nrects = 1;
+         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;
     }
-
-  if (nrects == 2)
+  else if (event->key.keyval == GDK_Escape)
     {
-      event.expose.type = GDK_EXPOSE;
-      event.expose.window = window;
-      event.expose.area.x = rect2.x;
-      event.expose.area.y = rect2.y;
-      event.expose.area.width = rect2.width;
-      event.expose.area.height = rect2.height;
-      event.expose.count = 0;
-
-      gdk_event_put (&event);
+      event->key.length = 1;
+      event->key.string = g_strdup ("\033");
+    }
+  else if (event->key.keyval == GDK_Return ||
+         event->key.keyval == GDK_KP_Enter)
+    {
+      event->key.length = 1;
+      event->key.string = g_strdup ("\r");
     }
 
-  xevent->xexpose.count = nrects - 1;
-  xevent->xexpose.x = rect1.x;
-  xevent->xexpose.y = rect1.y;
-  xevent->xexpose.width = rect1.width;
-  xevent->xexpose.height = rect1.height;
-}
-
-static gint
-gdk_event_apply_filters (XEvent *xevent,
-                        GdkEvent *event,
-                        GList *filters)
-{
-  GList *tmp_list;
-  GdkFilterReturn result;
-  
-  tmp_list = filters;
-  
-  while (tmp_list)
+  if (!event->key.string)
     {
-      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;
+      event->key.length = 0;
+      event->key.string = g_strdup ("");
     }
   
-  return GDK_FILTER_CONTINUE;
+ 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 */  
 }
 
-void 
-gdk_add_client_message_filter (GdkAtom       message_type,
-                              GdkFilterFunc func,
-                              gpointer      data)
+/* Return the window this has to do with, if any, rather
+ * than the frame or root window that was selecting
+ * for substructure
+ */
+static Window
+get_real_window (XEvent *event)
 {
-  GdkClientFilter *filter = g_new (GdkClientFilter, 1);
+  switch (event->type)
+    {      
+    case CreateNotify:
+      return event->xcreatewindow.window;
+      
+    case DestroyNotify:
+      return event->xdestroywindow.window;
 
-  filter->type = message_type;
-  filter->function = func;
-  filter->data = data;
-  
-  client_filters = g_list_prepend (client_filters, filter);
+    case UnmapNotify:
+      return event->xunmap.window;
+
+    case MapNotify:
+      return event->xmap.window;
+
+    case MapRequest:
+      return event->xmaprequest.window;
+
+    case ReparentNotify:
+     return event->xreparent.window;
+      
+    case ConfigureNotify:
+      return event->xconfigure.window;
+      
+    case ConfigureRequest:
+      return event->xconfigurerequest.window;
+
+    case GravityNotify:
+      return event->xgravity.window;
+
+    case CirculateNotify:
+      return event->xcirculate.window;
+
+    case CirculateRequest:
+      return event->xcirculaterequest.window;
+
+    default:
+      return event->xany.window;
+    }
 }
 
-static gint
-gdk_event_translate (GdkEvent *event,
-                    XEvent   *xevent)
+#ifdef G_ENABLE_DEBUG
+static const char notify_modes[][18] = {
+  "NotifyNormal",
+  "NotifyGrab",
+  "NotifyUngrab",
+  "NotifyWhileGrabbed"
+};
+
+static const char notify_details[][22] = {
+  "NotifyAncestor",
+  "NotifyVirtual",
+  "NotifyInferior",
+  "NotifyNonlinear",
+  "NotifyNonlinearVirtual",
+  "NotifyPointer",
+  "NotifyPointerRoot",
+  "NotifyDetailNone"
+};
+#endif
+
+static gboolean
+gdk_event_translate (GdkDisplay *display,
+                    GdkEvent   *event,
+                    XEvent     *xevent,
+                    gboolean    return_exposes)
 {
   
   GdkWindow *window;
-  GdkWindowPrivate *window_private;
-  static XComposeStatus compose;
-  KeySym keysym;
-  int charcount;
-#ifdef USE_XIM
-  static gchar* buf = NULL;
-  static gint buf_len= 0;
-#else
-  char buf[16];
-#endif
+  GdkWindowObject *window_private;
+  GdkWindow *filter_window;
+  GdkWindowImplX11 *window_impl = NULL;
   gint return_val;
+  gint xoffset, yoffset;
+  GdkScreen *screen = NULL;
+  GdkScreenX11 *screen_x11 = NULL;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  Window xwindow;
   
   return_val = FALSE;
+
+  /* init these, since the done: block uses them */
+  window = NULL;
+  window_private = NULL;
+  event->any.window = NULL;
+
+  if (_gdk_default_filters)
+    {
+      /* Apply global filters */
+      GdkFilterReturn result;
+      result = gdk_event_apply_filters (xevent, event,
+                                        _gdk_default_filters);
+      
+      if (result != GDK_FILTER_CONTINUE)
+        {
+          return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+          goto done;
+        }
+    }  
+
+   /* We handle events with window=None
+    *  specially - they are generated by XFree86's XInput under
+    *  some circumstances. This handling for obvious reasons
+    * goes before we bother to lookup the event window.
+    */
   
-  /* Find the GdkWindow that this event occurred in.
-   * 
-   * We handle events with window=None
-   *  specially - they are generated by XFree86's XInput under
-   *  some circumstances.
-   */
-  
-  if ((xevent->xany.window == None) &&
-      gdk_input_vtable.window_none_event)
+  if (xevent->xany.window == None)
     {
-      return_val = gdk_input_vtable.window_none_event (event,xevent);
+      return_val = _gdk_input_window_none_event (event, xevent);
       
       if (return_val >= 0)     /* was handled */
        return return_val;
       else
        return_val = FALSE;
     }
+
+  /* Find the GdkWindow that this event relates to.
+   * Basically this means substructure events
+   * are reported same as structure events
+   */
+  xwindow = get_real_window (xevent);
   
-  window = gdk_window_lookup (xevent->xany.window);
-  /* FIXME: window might be a GdkPixmap!!! */
-  
-  window_private = (GdkWindowPrivate *) window;
-  
+  window = gdk_window_lookup_for_display (display, xwindow);
+  window_private = (GdkWindowObject *) window;
+
+  /* We always run the filters for the window where the event
+   * is delivered, not the window that it relates to
+   */
+  if (xevent->xany.window == xwindow)
+    filter_window = window;
+  else
+    filter_window = gdk_window_lookup_for_display (display, xevent->xany.window);
+
+  if (window)
+    {
+      screen = GDK_WINDOW_SCREEN (window);
+      screen_x11 = GDK_SCREEN_X11 (screen);
+    }
+    
   if (window != NULL)
-    gdk_window_ref (window);
-  
+    {
+      /* Window may be a pixmap, so check its type.
+       * (This check is probably too expensive unless
+       *  GLib short-circuits an exact type match,
+       *  which has been proposed)
+       */
+      if (GDK_IS_WINDOW (window))
+        {
+          window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+
+          /* Move key events on focus window to the real toplevel, and
+           * filter out all other events on focus window
+           */          
+          if (xwindow == window_impl->focus_window)
+            {
+              switch (xevent->type)
+                {
+                case KeyPress:
+                case KeyRelease:
+                  xwindow = GDK_WINDOW_XID (window);
+                  xevent->xany.window = xwindow;
+                  break;
+                default:
+                  return FALSE;
+                }
+            }
+        }
+
+      g_object_ref (window);
+    }
+
   event->any.window = window;
   event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
   
-  if (window_private && GDK_DRAWABLE_DESTROYED (window))
+  if (window_private && GDK_WINDOW_DESTROYED (window))
     {
       if (xevent->type != DestroyNotify)
-       return FALSE;
+       {
+         return_val = FALSE;
+         goto done;
+       }
     }
-  else
+  else if (filter_window)
     {
-      /* Check for filters for this window
-       */
+      /* Apply per-window filters */
+      GdkWindowObject *filter_private = (GdkWindowObject *) filter_window;
       GdkFilterReturn result;
-      result = gdk_event_apply_filters (xevent, event,
-                                       window_private
-                                       ?window_private->filters
-                                       :gdk_default_filters);
-      
-      if (result != GDK_FILTER_CONTINUE)
+
+      if (filter_private->filters)
        {
-         return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+         g_object_ref (filter_window);
+         
+         result = gdk_event_apply_filters (xevent, event,
+                                           filter_private->filters);
+         
+         g_object_unref (filter_window);
+      
+         if (result != GDK_FILTER_CONTINUE)
+           {
+             return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+             goto done;
+           }
        }
     }
-
-#ifdef USE_XIM
-  if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
-      !GDK_DRAWABLE_DESTROYED (gdk_xim_window))
+      
+  if (screen_x11 && screen_x11->wmspec_check_window != None &&
+      xwindow == screen_x11->wmspec_check_window)
     {
-      /*
-       * If user presses a key in Preedit or Status window, keypress event
-       * is sometimes sent to these windows. These windows are not managed
-       * by GDK, so we redirect KeyPress event to xim_window.
-       *
-       * If someone want to use the window whitch is not managed by GDK
-       * and want to get KeyPress event, he/she must register the filter
-       * function to gdk_default_filters to intercept the event.
+      if (xevent->type == DestroyNotify)
+        {
+          screen_x11->wmspec_check_window = None;
+          g_free (screen_x11->window_manager_name);
+          screen_x11->window_manager_name = g_strdup ("unknown");
+
+          /* careful, reentrancy */
+          _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
+        }
+      
+      /* Eat events on this window unless someone had wrapped
+       * it as a foreign window
        */
-
-      GdkFilterReturn result;
-
-      window = gdk_xim_window;
-      window_private = (GdkWindowPrivate *) window;
-      gdk_window_ref (window);
-      event->any.window = window;
-
-      GDK_NOTE (XIM,
-       g_message ("KeyPress event is redirected to xim_window: %#lx",
-                  xevent->xany.window));
-
-      result = gdk_event_apply_filters (xevent, event,
-                                       window_private->filters);
-      if (result != GDK_FILTER_CONTINUE)
-       return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+      if (window == NULL)
+       {
+         return_val = FALSE;
+         goto done;
+       }
     }
-#endif
 
+  if (window &&
+      (xevent->xany.type == MotionNotify ||
+       xevent->xany.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
@@ -571,200 +866,174 @@ gdk_event_translate (GdkEvent *event,
 
   return_val = TRUE;
 
+  if (window)
+    {
+      _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
+    }
+  else
+    {
+      xoffset = 0;
+      yoffset = 0;
+    }
+
   switch (xevent->type)
     {
     case KeyPress:
-      /* Lookup the string corresponding to the given keysym.
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+      translate_key_event (display, event, xevent);
+      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.
        */
-      
-#ifdef USE_XIM
-      if (buf_len == 0) 
-       {
-         buf_len = 128;
-         buf = g_new (gchar, buf_len);
-       }
-      keysym = GDK_VoidSymbol;
-      
-      if (gdk_xim_ic && gdk_xim_ic->xic)
+
+      if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
        {
-         Status status;
-         
-         /* Clear keyval. Depending on status, may not be set */
-         charcount = XmbLookupString(gdk_xim_ic->xic,
-                                     &xevent->xkey, buf, buf_len-1,
-                                     &keysym, &status);
-         if (status == XBufferOverflow)
-           {                     /* retry */
-             /* alloc adequate size of buffer */
-             GDK_NOTE (XIM,
-                       g_message("XIM: overflow (required %i)", charcount));
-             
-             while (buf_len <= charcount)
-               buf_len *= 2;
-             buf = (gchar *) g_realloc (buf, buf_len);
-             
-             charcount = XmbLookupString (gdk_xim_ic->xic,
-                                          &xevent->xkey, buf, buf_len-1,
-                                          &keysym, &status);
-           }
-         if (status == XLookupNone)
+         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;
            }
        }
-      else
-       charcount = XLookupString (&xevent->xkey, buf, buf_len,
-                                  &keysym, &compose);
-#else
-      charcount = XLookupString (&xevent->xkey, buf, 16,
-                                &keysym, &compose);
-#endif
-      event->key.keyval = keysym;
-      
-      if (charcount > 0 && buf[charcount-1] == '\0')
-       charcount --;
-      else
-       buf[charcount] = '\0';
-      
-      /* Print debugging info. */
-      
-#ifdef G_ENABLE_DEBUG
-      if (gdk_debug_flags & GDK_DEBUG_EVENTS)
-       {
-         g_message ("key press:\twindow: %ld  key: %12s  %d",
-                    xevent->xkey.window,
-                    event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
-                    event->key.keyval);
-         if (charcount > 0)
-           g_message ("\t\tlength: %4d string: \"%s\"",
-                      charcount, buf);
-       }
-#endif /* G_ENABLE_DEBUG */
-      
-      event->key.type = GDK_KEY_PRESS;
-      event->key.window = window;
-      event->key.time = xevent->xkey.time;
-      event->key.state = (GdkModifierType) xevent->xkey.state;
-      event->key.string = g_strdup (buf);
-      event->key.length = charcount;
-      
-      break;
-      
-    case KeyRelease:
-      /* Lookup the string corresponding to the given keysym.
-       */
-#ifdef USE_XIM
-      if (buf_len == 0) 
-       {
-         buf_len = 128;
-         buf = g_new (gchar, buf_len);
-       }
-#endif
-      keysym = GDK_VoidSymbol;
-      charcount = XLookupString (&xevent->xkey, buf, 16,
-                                &keysym, &compose);
-      event->key.keyval = keysym;      
-      
-      /* Print debugging info.
-       */
-      GDK_NOTE (EVENTS, 
-               g_message ("key release:\t\twindow: %ld  key: %12s  %d",
-                          xevent->xkey.window,
-                          XKeysymToString (event->key.keyval),
-                          event->key.keyval));
-      
-      event->key.type = GDK_KEY_RELEASE;
-      event->key.window = window;
-      event->key.time = xevent->xkey.time;
-      event->key.state = (GdkModifierType) xevent->xkey.state;
-      event->key.length = 0;
-      event->key.string = NULL;
-      
+
+      translate_key_event (display, event, xevent);
       break;
       
     case ButtonPress:
-      /* Print debugging info.
-       */
       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 &&
-         (window_private->extension_events != 0) &&
-         gdk_input_ignore_core)
+      if (window_private == NULL || 
+         ((window_private->extension_events != 0) &&
+           display_x11->input_ignore_core))
        {
          return_val = FALSE;
          break;
        }
       
-      event->button.type = GDK_BUTTON_PRESS;
-      event->button.window = window;
-      event->button.time = xevent->xbutton.time;
-      event->button.x = xevent->xbutton.x;
-      event->button.y = xevent->xbutton.y;
-      event->button.x_root = (gfloat)xevent->xbutton.x_root;
-      event->button.y_root = (gfloat)xevent->xbutton.y_root;
-      event->button.pressure = 0.5;
-      event->button.xtilt = 0;
-      event->button.ytilt = 0;
-      event->button.state = (GdkModifierType) xevent->xbutton.state;
-      event->button.button = xevent->xbutton.button;
-      event->button.source = GDK_SOURCE_MOUSE;
-      event->button.deviceid = GDK_CORE_POINTER;
+      /* 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 = xevent->xbutton.x + xoffset;
+         event->scroll.y = xevent->xbutton.y + yoffset;
+         event->scroll.x_root = (gfloat)xevent->xbutton.x_root;
+         event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
+         event->scroll.state = (GdkModifierType) xevent->xbutton.state;
+         event->scroll.device = display->core_pointer;
+
+         set_screen_from_root (display, event, xevent->xbutton.root);
+         
+          break;
+          
+        default:
+         event->button.type = GDK_BUTTON_PRESS;
+         event->button.window = window;
+         event->button.time = xevent->xbutton.time;
+         event->button.x = xevent->xbutton.x + xoffset;
+         event->button.y = xevent->xbutton.y + yoffset;
+         event->button.x_root = (gfloat)xevent->xbutton.x_root;
+         event->button.y_root = (gfloat)xevent->xbutton.y_root;
+         event->button.axes = NULL;
+         event->button.state = (GdkModifierType) xevent->xbutton.state;
+         event->button.button = xevent->xbutton.button;
+         event->button.device = display->core_pointer;
+         
+         set_screen_from_root (display, event, xevent->xbutton.root);
+
+         _gdk_event_button_generate (display, event);
+          break;
+       }
 
-      gdk_event_button_generate (event);
-      
       break;
       
     case ButtonRelease:
-      /* Print debugging info.
-       */
       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 &&
-         (window_private->extension_events != 0) &&
-         gdk_input_ignore_core)
+      if (window_private == NULL ||
+         ((window_private->extension_events != 0) &&
+           display_x11->input_ignore_core))
        {
          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 = xevent->xbutton.x;
-      event->button.y = xevent->xbutton.y;
+      event->button.x = xevent->xbutton.x + xoffset;
+      event->button.y = xevent->xbutton.y + yoffset;
       event->button.x_root = (gfloat)xevent->xbutton.x_root;
       event->button.y_root = (gfloat)xevent->xbutton.y_root;
-      event->button.pressure = 0.5;
-      event->button.xtilt = 0;
-      event->button.ytilt = 0;
+      event->button.axes = NULL;
       event->button.state = (GdkModifierType) xevent->xbutton.state;
       event->button.button = xevent->xbutton.button;
-      event->button.source = GDK_SOURCE_MOUSE;
-      event->button.deviceid = GDK_CORE_POINTER;
+      event->button.device = display->core_pointer;
+
+      set_screen_from_root (display, event, xevent->xbutton.root);
       
       break;
       
     case MotionNotify:
-      /* Print debugging info.
-       */
       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 &&
-         (window_private->extension_events != 0) &&
-         gdk_input_ignore_core)
+      if (window_private == NULL ||
+         ((window_private->extension_events != 0) &&
+           display_x11->input_ignore_core))
        {
          return_val = FALSE;
          break;
@@ -773,35 +1042,51 @@ gdk_event_translate (GdkEvent *event,
       event->motion.type = GDK_MOTION_NOTIFY;
       event->motion.window = window;
       event->motion.time = xevent->xmotion.time;
-      event->motion.x = xevent->xmotion.x;
-      event->motion.y = xevent->xmotion.y;
+      event->motion.x = xevent->xmotion.x + xoffset;
+      event->motion.y = xevent->xmotion.y + yoffset;
       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
-      event->motion.pressure = 0.5;
-      event->motion.xtilt = 0;
-      event->motion.ytilt = 0;
+      event->motion.axes = NULL;
       event->motion.state = (GdkModifierType) xevent->xmotion.state;
       event->motion.is_hint = xevent->xmotion.is_hint;
-      event->motion.source = GDK_SOURCE_MOUSE;
-      event->motion.deviceid = GDK_CORE_POINTER;
+      event->motion.device = display->core_pointer;
+      
+      set_screen_from_root (display, event, xevent->xmotion.root);
       
       break;
       
     case EnterNotify:
-      /* Print debugging info.
-       */
       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;
+        }
       
+      /* Handle focusing (in the case where no window manager is running */
+      if (window &&
+         GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
+         xevent->xcrossing.detail != NotifyInferior &&
+         xevent->xcrossing.focus && !window_impl->has_focus_window)
+       {
+         gboolean had_focus = HAS_FOCUS (window_impl);
+
+         window_impl->has_pointer_focus = TRUE;
+
+         if (HAS_FOCUS (window_impl) != had_focus)
+           generate_focus_event (window, TRUE);
+       }
+
       /* Tell XInput stuff about it if appropriate */
       if (window_private &&
-         !GDK_DRAWABLE_DESTROYED (window) &&
-         (window_private->extension_events != 0) &&
-         gdk_input_vtable.enter_event)
-       gdk_input_vtable.enter_event (&xevent->xcrossing, window);
+         !GDK_WINDOW_DESTROYED (window) &&
+         window_private->extension_events != 0)
+       _gdk_input_enter_event (&xevent->xcrossing, window);
       
       event->crossing.type = GDK_ENTER_NOTIFY;
       event->crossing.window = window;
@@ -810,16 +1095,18 @@ gdk_event_translate (GdkEvent *event,
        *  lookup the corresponding GdkWindow.
        */
       if (xevent->xcrossing.subwindow != None)
-       event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
+       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 = xevent->xcrossing.x;
-      event->crossing.y = xevent->xcrossing.y;
+      event->crossing.x = xevent->xcrossing.x + xoffset;
+      event->crossing.y = xevent->xcrossing.y + yoffset;
       event->crossing.x_root = xevent->xcrossing.x_root;
       event->crossing.y_root = xevent->xcrossing.y_root;
       
+      set_screen_from_root (display, event, xevent->xcrossing.root);
+      
       /* Translate the crossing mode into Gdk terms.
        */
       switch (xevent->xcrossing.mode)
@@ -865,13 +1152,31 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case LeaveNotify:
-      /* Print debugging info.
-       */
       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;
+        }
       
+      /* Handle focusing (in the case where no window manager is running */
+      if (window &&
+         GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
+         xevent->xcrossing.detail != NotifyInferior &&
+         xevent->xcrossing.focus && !window_impl->has_focus_window)
+       {
+         gboolean had_focus = HAS_FOCUS (window_impl);
+         
+         window_impl->has_pointer_focus = FALSE;
+         
+         if (HAS_FOCUS (window_impl) != had_focus)
+           generate_focus_event (window, FALSE);
+       }
+
       event->crossing.type = GDK_LEAVE_NOTIFY;
       event->crossing.window = window;
       
@@ -879,16 +1184,18 @@ gdk_event_translate (GdkEvent *event,
        *  lookup the corresponding GdkWindow.
        */
       if (xevent->xcrossing.subwindow != None)
-       event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
+       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 = xevent->xcrossing.x;
-      event->crossing.y = xevent->xcrossing.y;
+      event->crossing.x = xevent->xcrossing.x + xoffset;
+      event->crossing.y = xevent->xcrossing.y + yoffset;
       event->crossing.x_root = xevent->xcrossing.x_root;
       event->crossing.y_root = xevent->xcrossing.y_root;
       
+      set_screen_from_root (display, event, xevent->xcrossing.root);
+      
       /* Translate the crossing mode into Gdk terms.
        */
       switch (xevent->xcrossing.mode)
@@ -933,43 +1240,98 @@ gdk_event_translate (GdkEvent *event,
       
       break;
       
-    case FocusIn:
-    case FocusOut:
       /* We only care about focus events that indicate that _this_
        * window (not a ancestor or child) got or lost the focus
        */
-      switch (xevent->xfocus.detail)
+    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 (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
        {
-       case NotifyAncestor:
-       case NotifyInferior:
-       case NotifyNonlinear:
-         /* Print debugging info.
-          */
-         GDK_NOTE (EVENTS,
-                   g_message ("focus %s:\t\twindow: %ld",
-                              (xevent->xany.type == FocusIn) ? "in" : "out",
-                              xevent->xfocus.window));
+         gboolean had_focus = HAS_FOCUS (window_impl);
          
+         switch (xevent->xfocus.detail)
+           {
+           case NotifyAncestor:
+           case NotifyNonlinear:
+           case NotifyVirtual:
+           case NotifyNonlinearVirtual:
+             window_impl->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)
+               window_impl->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)
+               window_impl->has_pointer_focus = TRUE;
+             break;
+           case NotifyInferior:
+           case NotifyPointerRoot:
+           case NotifyDetailNone:
+             break;
+           }
+
+         if (HAS_FOCUS (window_impl) != had_focus)
+           generate_focus_event (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 (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
+       {
+         gboolean had_focus = HAS_FOCUS (window_impl);
+           
+         switch (xevent->xfocus.detail)
+           {
+           case NotifyAncestor:
+           case NotifyNonlinear:
+           case NotifyVirtual:
+           case NotifyNonlinearVirtual:
+             window_impl->has_focus_window = FALSE;
+             if (xevent->xfocus.mode != NotifyWhileGrabbed)
+               window_impl->has_focus = FALSE;
+             break;
+           case NotifyPointer:
+             if (xevent->xfocus.mode != NotifyUngrab)
+               window_impl->has_pointer_focus = FALSE;
+           break;
+           case NotifyInferior:
+           case NotifyPointerRoot:
+           case NotifyDetailNone:
+             break;
+           }
+
+         if (HAS_FOCUS (window_impl) != had_focus)
+           generate_focus_event (window, FALSE);
+       }
+      break;
+
+#if 0      
          /* gdk_keyboard_grab() causes following events. These events confuse
           * the XIM focus, so ignore them.
           */
          if (xevent->xfocus.mode == NotifyGrab ||
              xevent->xfocus.mode == NotifyUngrab)
            break;
-         
-         event->focus_change.type = GDK_FOCUS_CHANGE;
-         event->focus_change.window = window;
-         event->focus_change.in = (xevent->xany.type == FocusIn);
+#endif
 
-         break;
-       default:
-         return_val = FALSE;
-       }
-      break;
-      
     case KeymapNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("keymap notify"));
 
@@ -978,46 +1340,88 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case Expose:
-      /* Print debugging info.
-       */
       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)" : ""));
-      gdk_compress_exposures (xevent, window);
       
-      event->expose.type = GDK_EXPOSE;
-      event->expose.window = window;
-      event->expose.area.x = xevent->xexpose.x;
-      event->expose.area.y = xevent->xexpose.y;
-      event->expose.area.width = xevent->xexpose.width;
-      event->expose.area.height = xevent->xexpose.height;
-      event->expose.count = xevent->xexpose.count;
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
       
+      {
+       GdkRectangle expose_rect;
+
+       expose_rect.x = xevent->xexpose.x + xoffset;
+       expose_rect.y = xevent->xexpose.y + yoffset;
+       expose_rect.width = xevent->xexpose.width;
+       expose_rect.height = xevent->xexpose.height;
+
+       if (return_exposes)
+         {
+           event->expose.type = GDK_EXPOSE;
+           event->expose.area = expose_rect;
+           event->expose.region = gdk_region_rectangle (&expose_rect);
+           event->expose.window = window;
+           event->expose.count = xevent->xexpose.count;
+
+           return_val = TRUE;
+         }
+       else
+         {
+           _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
+           return_val = FALSE;
+         }
+       
+       return_val = FALSE;
+      }
+       
       break;
       
     case GraphicsExpose:
-      /* Print debugging info.
-       */
-      GDK_NOTE (EVENTS,
-               g_message ("graphics expose:\tdrawable: %ld",
-                          xevent->xgraphicsexpose.drawable));
-      
-      event->expose.type = GDK_EXPOSE;
-      event->expose.window = window;
-      event->expose.area.x = xevent->xgraphicsexpose.x;
-      event->expose.area.y = xevent->xgraphicsexpose.y;
-      event->expose.area.width = xevent->xgraphicsexpose.width;
-      event->expose.area.height = xevent->xgraphicsexpose.height;
-      event->expose.count = xevent->xexpose.count;
-      
+      {
+       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 + xoffset;
+       expose_rect.y = xevent->xgraphicsexpose.y + yoffset;
+       expose_rect.width = xevent->xgraphicsexpose.width;
+       expose_rect.height = xevent->xgraphicsexpose.height;
+           
+       if (return_exposes)
+         {
+           event->expose.type = GDK_EXPOSE;
+           event->expose.area = expose_rect;
+           event->expose.region = gdk_region_rectangle (&expose_rect);
+           event->expose.window = window;
+           event->expose.count = xevent->xgraphicsexpose.count;
+
+           return_val = TRUE;
+         }
+       else
+         {
+           _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
+           
+           return_val = FALSE;
+         }
+       
+      }
       break;
       
     case NoExpose:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("no expose:\t\tdrawable: %ld",
                           xevent->xnoexpose.drawable));
@@ -1028,10 +1432,8 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case VisibilityNotify:
-      /* Print debugging info.
-       */
 #ifdef G_ENABLE_DEBUG
-      if (gdk_debug_flags & GDK_DEBUG_EVENTS)
+      if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
        switch (xevent->xvisibility.state)
          {
          case VisibilityFullyObscured:
@@ -1049,6 +1451,12 @@ gdk_event_translate (GdkEvent *event,
          }
 #endif /* G_ENABLE_DEBUG */
       
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+      
       event->visibility.type = GDK_VISIBILITY_NOTIFY;
       event->visibility.window = window;
       
@@ -1084,51 +1492,68 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case DestroyNotify:
-      /* Print debugging info.
-       */
       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;
       
-      event->any.type = GDK_DESTROY;
-      event->any.window = window;
-      
-      return_val = window_private && !GDK_DRAWABLE_DESTROYED (window);
-      
-      if (window && GDK_DRAWABLE_XID (window) != GDK_ROOT_WINDOW())
-       gdk_window_destroy_notify (window);
       break;
       
     case UnmapNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("unmap notify:\t\twindow: %ld",
                           xevent->xmap.window));
       
       event->any.type = GDK_UNMAP;
-      event->any.window = window;
-      
-      if (gdk_xgrab_window == window_private)
-       gdk_xgrab_window = NULL;
+      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:
-      /* Print debugging info.
-       */
       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:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld      ovr: %d",
                           xevent->xreparent.window,
@@ -1142,8 +1567,6 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case ConfigureNotify:
-      /* Print debugging info.
-       */
       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,
@@ -1156,16 +1579,24 @@ gdk_event_translate (GdkEvent *event,
                           xevent->xconfigure.override_redirect,
                           !window
                           ? " (discarding)"
-                          : GDK_DRAWABLE_TYPE (window) == GDK_WINDOW_CHILD
+                          : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
                           ? " (discarding child)"
+                          : xevent->xconfigure.event != xevent->xconfigure.window
+                          ? " (discarding substructure)"
                           : ""));
-      if (window &&
-         !GDK_DRAWABLE_DESTROYED (window) &&
-         (window_private->extension_events != 0) &&
-         gdk_input_vtable.configure_event)
-       gdk_input_vtable.configure_event (&xevent->xconfigure, window);
+      if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
+       _gdk_x11_screen_size_changed (screen, xevent);
 
-      if (!window || GDK_DRAWABLE_TYPE (window) == GDK_WINDOW_CHILD)
+      if (window &&
+         xevent->xconfigure.event == xevent->xconfigure.window &&
+         !GDK_WINDOW_DESTROYED (window) &&
+         (window_private->extension_events != 0))
+       _gdk_input_configure_event (&xevent->xconfigure, window);
+
+      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
        {
@@ -1174,9 +1605,8 @@ gdk_event_translate (GdkEvent *event,
          event->configure.width = xevent->xconfigure.width;
          event->configure.height = xevent->xconfigure.height;
          
-         if (!xevent->xconfigure.x &&
-             !xevent->xconfigure.y &&
-             !GDK_DRAWABLE_DESTROYED (window))
+         if (!xevent->xconfigure.send_event && 
+             !GDK_WINDOW_DESTROYED (window))
            {
              gint tx = 0;
              gint ty = 0;
@@ -1185,7 +1615,7 @@ gdk_event_translate (GdkEvent *event,
              gdk_error_trap_push ();
              if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
                                         GDK_DRAWABLE_XID (window),
-                                        gdk_root_window,
+                                        screen_x11->xroot_window,
                                         0, 0,
                                         &tx, &ty,
                                         &child_window))
@@ -1206,45 +1636,68 @@ gdk_event_translate (GdkEvent *event,
            }
          window_private->x = event->configure.x;
          window_private->y = event->configure.y;
-         window_private->drawable.width = xevent->xconfigure.width;
-         window_private->drawable.height = xevent->xconfigure.height;
-         if (window_private->resize_count > 1)
-           window_private->resize_count -= 1;
+         GDK_WINDOW_IMPL_X11 (window_private->impl)->width = xevent->xconfigure.width;
+         GDK_WINDOW_IMPL_X11 (window_private->impl)->height = xevent->xconfigure.height;
+         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:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
-               gchar *atom = gdk_atom_name (xevent->xproperty.atom);
                g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
                           xevent->xproperty.window,
                           xevent->xproperty.atom,
-                          atom ? "\"" : "",
-                          atom ? atom : "unknown",
-                          atom ? "\"" : "");
-               g_free (atom);
-               );
-      
-      event->property.type = GDK_PROPERTY_NOTIFY;
-      event->property.window = window;
-      event->property.atom = xevent->xproperty.atom;
-      event->property.time = xevent->xproperty.time;
-      event->property.state = xevent->xproperty.state;
+                          "\"",
+                          gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom),
+                          "\""));
+
+      if (window_private == NULL)
+        {
+         return_val = FALSE;
+          break;
+        }
+      
+      if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE") ||
+         xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
+        {
+          /* If window state changed, then synthesize those events. */
+          gdk_check_wm_state_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));
-      
-      event->selection.type = GDK_SELECTION_CLEAR;
-      event->selection.window = window;
-      event->selection.selection = xevent->xselectionclear.selection;
-      event->selection.time = xevent->xselectionclear.time;
-      
+
+      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:
@@ -1254,9 +1707,9 @@ gdk_event_translate (GdkEvent *event,
       
       event->selection.type = GDK_SELECTION_REQUEST;
       event->selection.window = window;
-      event->selection.selection = xevent->xselectionrequest.selection;
-      event->selection.target = xevent->xselectionrequest.target;
-      event->selection.property = xevent->xselectionrequest.property;
+      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;
       
@@ -1270,16 +1723,14 @@ gdk_event_translate (GdkEvent *event,
       
       event->selection.type = GDK_SELECTION_NOTIFY;
       event->selection.window = window;
-      event->selection.selection = xevent->xselection.selection;
-      event->selection.target = xevent->xselection.target;
-      event->selection.property = xevent->xselection.property;
+      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);
+      event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
       event->selection.time = xevent->xselection.time;
       
       break;
       
     case ColormapNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("colormap notify:\twindow: %ld",
                           xevent->xcolormap.window));
@@ -1292,18 +1743,17 @@ gdk_event_translate (GdkEvent *event,
       {
        GList *tmp_list;
        GdkFilterReturn result = GDK_FILTER_CONTINUE;
+       GdkAtom message_type = gdk_x11_xatom_to_atom_for_display (display, xevent->xclient.message_type);
 
-       /* Print debugging info.
-        */
        GDK_NOTE (EVENTS,
                  g_message ("client message:\twindow: %ld",
                             xevent->xclient.window));
        
-       tmp_list = client_filters;
+       tmp_list = display_x11->client_filters;
        while (tmp_list)
          {
            GdkClientFilter *filter = tmp_list->data;
-           if (filter->type == xevent->xclient.message_type)
+           if (filter->type == message_type)
              {
                result = (*filter->function) (xevent, event, filter->data);
                break;
@@ -1322,51 +1772,80 @@ gdk_event_translate (GdkEvent *event,
            break;
          case GDK_FILTER_CONTINUE:
            /* Send unknown ClientMessage's on to Gtk for it to use */
-           event->client.type = GDK_CLIENT_EVENT;
-           event->client.window = window;
-           event->client.message_type = xevent->xclient.message_type;
-           event->client.data_format = xevent->xclient.format;
-           memcpy(&event->client.data, &xevent->xclient.data,
-                  sizeof(event->client.data));
-         }
+            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:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("mapping notify"));
       
       /* Let XLib know that there is a new keyboard mapping.
        */
       XRefreshKeyboardMapping (&xevent->xmapping);
-      return_val = FALSE;
-      break;
-      
-    default:
-      /* something else - (e.g., a Xinput event) */
-      
-      if (window_private &&
-         !window_private->drawable.destroyed &&
-         (window_private->extension_events != 0) &&
-         gdk_input_vtable.other_event)
-       return_val = gdk_input_vtable.other_event(event, xevent, window);
-      else
-       return_val = FALSE;
-      
+      _gdk_keymap_keys_changed (display);
+      return_val = FALSE;
       break;
+
+    default:
+#ifdef HAVE_XKB
+      if (xevent->type == display_x11->xkb_event_type)
+       {
+         XkbEvent *xkb_event = (XkbEvent *)xevent;
+
+         switch (xkb_event->any.xkb_type)
+           {
+           case XkbMapNotify:
+             _gdk_keymap_keys_changed (display);
+
+             return_val = FALSE;
+             break;
+             
+           case XkbStateNotify:
+             _gdk_keymap_state_changed (display);
+             break;
+           }
+       }
+      else
+#endif
+       {
+         /* something else - (e.g., a Xinput event) */
+         
+         if (window_private &&
+             !GDK_WINDOW_DESTROYED (window_private) &&
+             (window_private->extension_events != 0))
+           return_val = _gdk_input_other_event(event, xevent, window);
+         else
+           return_val = FALSE;
+         
+         break;
+       }
     }
-  
+
+ done:
   if (return_val)
     {
       if (event->any.window)
-       gdk_window_ref (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))
-       gdk_window_ref (event->crossing.subwindow);
+       g_object_ref (event->crossing.subwindow);
     }
   else
     {
@@ -1376,19 +1855,21 @@ gdk_event_translate (GdkEvent *event,
     }
   
   if (window)
-    gdk_window_unref (window);
+    g_object_unref (window);
   
   return return_val;
 }
 
-GdkFilterReturn
+static GdkFilterReturn
 gdk_wm_protocols_filter (GdkXEvent *xev,
                         GdkEvent  *event,
                         gpointer data)
 {
   XEvent *xevent = (XEvent *)xev;
+  GdkWindow *win = event->any.window;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (win);
 
-  if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
+  if ((Atom) xevent->xclient.data.l[0] == 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
@@ -1406,80 +1887,74 @@ gdk_wm_protocols_filter (GdkXEvent *xev,
 
       return GDK_FILTER_TRANSLATE;
     }
-  else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
+  else if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
     {
-    }
-
-  return GDK_FILTER_REMOVE;
-}
+      GdkWindow *win = event->any.window;
+      Window focus_win = GDK_WINDOW_IMPL_X11(((GdkWindowObject *)win)->impl)->focus_window;
 
-#if 0
-static Bool
-gdk_event_get_type (Display  *display,
-                   XEvent   *xevent,
-                   XPointer  arg)
-{
-  GdkEvent event;
-  GdkPredicate *pred;
-  
-  if (gdk_event_translate (&event, xevent))
+      /* There is no way of knowing reliably whether we are viewable so we need
+       * to trap errors so we don't cause a BadMatch.
+       */
+      gdk_error_trap_push ();
+      XSetInputFocus (GDK_WINDOW_XDISPLAY (win),
+                     focus_win,
+                     RevertToParent,
+                     xevent->xclient.data.l[1]);
+      XSync (GDK_WINDOW_XDISPLAY (win), False);
+      gdk_error_trap_pop ();
+    }
+  else if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING"))
     {
-      pred = (GdkPredicate*) arg;
-      return (* pred->func) (&event, pred->data);
+      XEvent xev = *xevent;
+      
+      xev.xclient.window = GDK_WINDOW_XROOTWIN (win);
+      XSendEvent (GDK_WINDOW_XDISPLAY (win), 
+                 xev.xclient.window,
+                 False, 
+                 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
     }
-  
-  return FALSE;
+
+  return GDK_FILTER_REMOVE;
 }
-#endif
 
 void
-gdk_events_queue (void)
+_gdk_events_queue (GdkDisplay *display)
 {
   GList *node;
   GdkEvent *event;
   XEvent xevent;
+  Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
 
-  while (!gdk_event_queue_find_first() && XPending (gdk_display))
+  while (!_gdk_event_queue_find_first(display) && XPending (xdisplay))
     {
-#ifdef USE_XIM
-      Window w = None;
-      
-      XNextEvent (gdk_display, &xevent);
-      if (gdk_xim_window)
-       switch (xevent.type)
-         {
-         case KeyPress:
-         case KeyRelease:
-         case ButtonPress:
-         case ButtonRelease:
-           w = GDK_WINDOW_XWINDOW (gdk_xim_window);
-           break;
-         }
-      
-      if (XFilterEvent (&xevent, w))
-       continue;
-#else
-      XNextEvent (gdk_display, &xevent);
-#endif
+      XNextEvent (xdisplay, &xevent);
+
+      switch (xevent.type)
+       {
+       case KeyPress:
+       case KeyRelease:
+         break;
+       default:
+         if (XFilterEvent (&xevent, None))
+           continue;
+       }
       
-      event = gdk_event_new ();
+      event = gdk_event_new (GDK_NOTHING);
       
-      event->any.type = GDK_NOTHING;
       event->any.window = NULL;
       event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
 
       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
 
-      gdk_event_queue_append (event);
-      node = gdk_queued_tail;
+      node = _gdk_event_queue_append (display, event);
 
-      if (gdk_event_translate (event, &xevent))
+      if (gdk_event_translate (display, event, &xevent, FALSE))
        {
          ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
        }
       else
        {
-         gdk_event_queue_remove_link (node);
+         _gdk_event_queue_remove_link (display, node);
          g_list_free_1 (node);
          gdk_event_free (event);
        }
@@ -1487,35 +1962,34 @@ gdk_events_queue (void)
 }
 
 static gboolean  
-gdk_event_prepare (gpointer  source_data, 
-                  GTimeVal *current_time,
-                  gint     *timeout,
-                  gpointer  user_data)
+gdk_event_prepare (GSource  *source,
+                  gint     *timeout)
 {
+  GdkDisplay *display = ((GdkDisplaySource*)source)->display;
   gboolean retval;
   
   GDK_THREADS_ENTER ();
 
   *timeout = -1;
-
-  retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
-
+  retval = (_gdk_event_queue_find_first (display) != NULL || 
+           gdk_check_xpending (display));
+  
   GDK_THREADS_LEAVE ();
 
   return retval;
 }
 
 static gboolean  
-gdk_event_check (gpointer  source_data,
-                GTimeVal *current_time,
-                gpointer  user_data)
+gdk_event_check (GSource *source) 
 {
+  GdkDisplaySource *display_source = (GdkDisplaySource*)source;
   gboolean retval;
-  
+
   GDK_THREADS_ENTER ();
 
-  if (event_poll_fd.revents & G_IO_IN)
-    retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
+  if (display_source->event_poll_fd.revents & G_IO_IN)
+    retval = (_gdk_event_queue_find_first (display_source->display) != NULL || 
+             gdk_check_xpending (display_source->display));
   else
     retval = FALSE;
 
@@ -1525,21 +1999,22 @@ gdk_event_check (gpointer  source_data,
 }
 
 static gboolean  
-gdk_event_dispatch (gpointer  source_data,
-                   GTimeVal *current_time,
-                   gpointer  user_data)
+gdk_event_dispatch (GSource    *source,
+                   GSourceFunc callback,
+                   gpointer    user_data)
 {
+  GdkDisplay *display = ((GdkDisplaySource*)source)->display;
   GdkEvent *event;
  
   GDK_THREADS_ENTER ();
 
-  gdk_events_queue();
-  event = gdk_event_unqueue();
+  _gdk_events_queue (display);
+  event = _gdk_event_unqueue (display);
 
   if (event)
     {
-      if (gdk_event_func)
-       (*gdk_event_func) (event, gdk_event_data);
+      if (_gdk_event_func)
+       (*_gdk_event_func) (event, _gdk_event_data);
       
       gdk_event_free (event);
     }
@@ -1549,58 +2024,69 @@ gdk_event_dispatch (gpointer  source_data,
   return TRUE;
 }
 
-/* Sends a ClientMessage to all toplevel client windows */
+/**
+ * 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 X ClientMessage event to.
+ *
+ * Sends an X ClientMessage event to a given window.
+ *
+ * This could be used for communicating between different applications,
+ * though the amount of data is limited to 20 bytes.
+ *
+ * Returns: non-zero on success.
+ *
+ * Since: 2.2
+ */
 gboolean
-gdk_event_send_client_message (GdkEvent *event, guint32 xid)
+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;
+  sev.xclient.display = GDK_DISPLAY_XDISPLAY (display);
   sev.xclient.format = event->client.data_format;
-  sev.xclient.window = xid;
-  memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
-  sev.xclient.message_type = event->client.message_type;
+  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 (xid, False, NoEventMask, &sev);
+  return _gdk_send_xevent (display, winid, False, NoEventMask, &sev);
 }
 
+
+
 /* Sends a ClientMessage to all toplevel client windows */
 gboolean
-gdk_event_send_client_message_to_all_recurse (XEvent  *xev, 
-                                             guint32  xid,
-                                             guint    level)
+gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
+                                             XEvent     *xev, 
+                                             guint32     xid,
+                                             guint       level)
 {
-  static GdkAtom wm_state_atom = GDK_NONE;
   Atom type = None;
   int format;
   unsigned long nitems, after;
   unsigned char *data;
   Window *ret_children, ret_root, ret_parent;
   unsigned int ret_nchildren;
-  gint old_warnings = gdk_error_warnings;
   gboolean send = FALSE;
   gboolean found = FALSE;
+  gboolean result = FALSE;
   int i;
-
-  if (!wm_state_atom)
-    wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
-
-  gdk_error_warnings = FALSE;
-  gdk_error_code = 0;
-  XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
-                     &type, &format, &nitems, &after, &data);
-
-  if (gdk_error_code)
-    {
-      gdk_error_warnings = old_warnings;
-
-      return FALSE;
-    }
-
+  
+  gdk_error_trap_push ();
+  
+  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid, 
+                         gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
+                         0, 0, False, AnyPropertyType,
+                         &type, &format, &nitems, &after, &data) != Success)
+    goto out;
+  
   if (type)
     {
       send = TRUE;
@@ -1609,17 +2095,13 @@ gdk_event_send_client_message_to_all_recurse (XEvent  *xev,
   else
     {
       /* OK, we're all set, now let's find some windows to send this to */
-      if (XQueryTree (gdk_display, xid, &ret_root, &ret_parent,
-                     &ret_children, &ret_nchildren) != True ||
-         gdk_error_code)
-       {
-         gdk_error_warnings = old_warnings;
-
-         return FALSE;
-       }
+      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 (xev, ret_children[i], level + 1))
+       if (gdk_event_send_client_message_to_all_recurse (display, xev, ret_children[i], level + 1))
          found = TRUE;
 
       XFree (ret_children);
@@ -1628,32 +2110,56 @@ gdk_event_send_client_message_to_all_recurse (XEvent  *xev,
   if (send || (!found && (level == 1)))
     {
       xev->xclient.window = xid;
-      gdk_send_xevent (xid, False, NoEventMask, xev);
+      _gdk_send_xevent (display, xid, False, NoEventMask, xev);
     }
 
-  gdk_error_warnings = old_warnings;
+  result = send || found;
 
-  return (send || found);
+ out:
+  gdk_error_trap_pop ();
+
+  return result;
 }
 
+/**
+ * gdk_screen_broadcast_client_message:
+ * @screen: the #GdkScreen where the event will be broadcasted.
+ * @event: the #GdkEvent.
+ *
+ * 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.
+ *
+ * Since: 2.2
+ */
+
 void
-gdk_event_send_clientmessage_toall (GdkEvent *event)
+gdk_screen_broadcast_client_message (GdkScreen *screen, 
+                                    GdkEvent  *event)
 {
   XEvent sev;
-  gint old_warnings = gdk_error_warnings;
+  GdkWindow *root_window;
 
-  g_return_if_fail(event != NULL);
+  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_display;
+  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 = event->client.message_type;
-
-  gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
-
-  gdk_error_warnings = old_warnings;
+  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);
 }
 
 /*
@@ -1677,7 +2183,522 @@ gdk_event_send_clientmessage_toall (GdkEvent *event)
 void
 gdk_flush (void)
 {
-  XSync (gdk_display, False);
+  GSList *tmp_list = _gdk_displays;
+  
+  while (tmp_list)
+    {
+      XSync (GDK_DISPLAY_XDISPLAY (tmp_list->data), False);
+      tmp_list = tmp_list->next;
+    }
+}
+
+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;
+}
+
+static void
+fetch_net_wm_check_window (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11;
+  GdkDisplay *display;
+  Atom type;
+  gint format;
+  gulong n_items;
+  gulong bytes_after;
+  Window *xwindow;
+  
+  /* This function is very slow on every call if you are not running a
+   * spec-supporting WM. For now not optimized, because it isn't in
+   * any critical code paths, but if you used it somewhere that had to
+   * be fast you want to avoid "GTK is slow with old WMs" complaints.
+   * Probably at that point the function should be changed to query
+   * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something.
+   */
+  
+  screen_x11 = GDK_SCREEN_X11 (screen);
+  display = screen_x11->display;
+  
+  if (screen_x11->wmspec_check_window != None)
+    return; /* already have it */
+  
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), 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, (guchar **) & xwindow);
+  
+  if (type != XA_WINDOW)
+    return;
+
+  gdk_error_trap_push ();
+  
+  /* Find out if this WM goes away, so we can reset everything. */
+  XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask);
+
+  screen_x11->wmspec_check_window = *xwindow;
+  XFree (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));
+}
+
+/**
+ * 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);
+  
+  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;
+          guchar *name;
+          
+          name = NULL;
+          
+          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_display_sync (screen_x11->display);
+          
+          gdk_error_trap_pop ();
+          
+          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;
+}
+
+typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
+
+struct _NetWmSupportedAtoms
+{
+  Atom *atoms;
+  gulong n_atoms;
+};
+
+/**
+ * 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;
+
+  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 (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_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 struct
+{
+  const char *xsettings_name;
+  const char *gdk_name;
+} settings_map[] = {
+  { "Net/DoubleClickTime", "gtk-double-click-time" },
+  { "Net/DndDragThreshold", "gtk-dnd-drag-threshold" },
+  { "Gtk/CanChangeAccels", "gtk-can-change-accels" },
+  { "Gtk/ColorPalette", "gtk-color-palette" },
+  { "Gtk/FontName", "gtk-font-name" },
+  { "Gtk/IconSizes", "gtk-icon-sizes" },
+  { "Gtk/KeyThemeName", "gtk-key-theme-name" },
+  { "Gtk/ToolbarStyle", "gtk-toolbar-style" },
+  { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
+  { "Gtk/IMPreeditStyle", "gtk-im-preedit-style" },
+  { "Gtk/IMStatusStyle", "gtk-im-status-style" },
+  { "Net/CursorBlink", "gtk-cursor-blink" },
+  { "Net/CursorBlinkTime", "gtk-cursor-blink-time" },
+  { "Net/ThemeName", "gtk-theme-name" }
+};
+
+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 < G_N_ELEMENTS (settings_map) ; i++)
+    if (strcmp (settings_map[i].xsettings_name, name) == 0)
+      {
+       new_event.setting.name = (char *)settings_map[i].gdk_name;
+       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);
+}
+
+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 tranform 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;
+  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 < G_N_ELEMENTS (settings_map) ; i++)
+    if (strcmp (settings_map[i].gdk_name, name) == 0)
+      {
+       xsettings_name = settings_map[i].xsettings_name;
+       break;
+      }
+
+  if (!xsettings_name)
+    return FALSE;
+
+  result = xsettings_client_get_setting (screen_x11->xsettings_client, 
+                                        xsettings_name, &setting);
+  if (result != XSETTINGS_SUCCESS)
+    return FALSE;
+
+  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);
+
+  xsettings_setting_free (setting);
+
+  return success;
+}
+
+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 void 
+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)
+       gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
+      else
+       g_object_ref (gdkwin);
+      
+      gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+    }
+  else
+    {
+      g_assert (gdkwin);
+      gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+      g_object_unref (gdkwin);
+    }
+}