]> 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 bb62f04ad9e7af1244f8bc3bea391398102b1e61..e32fe2182b29e0ed00d7a3a1e77b9078ba9fc2d2 100644 (file)
@@ -28,6 +28,8 @@
 #include "gdkprivate-x11.h"
 #include "gdkinternals.h"
 #include "gdkx.h"
+#include "gdkscreen-x11.h"
+#include "gdkdisplay-x11.h"
 
 #include "gdkkeysyms.h"
 
 #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;
@@ -72,10 +66,12 @@ struct _GdkIOClosure
   gpointer data;
 };
 
-struct _GdkEventPrivate
+struct _GdkDisplaySource
 {
-  GdkEvent event;
-  guint    flags;
+  GSource source;
+  
+  GdkDisplay *display;
+  GPollFD event_poll_fd;
 };
 
 /* 
@@ -85,14 +81,10 @@ struct _GdkEventPrivate
 static gint     gdk_event_apply_filters (XEvent   *xevent,
                                          GdkEvent *event,
                                          GList    *filters);
-static gint     gdk_event_translate     (GdkEvent *event, 
-                                         XEvent   *xevent,
-                                         gboolean  return_exposes);
-#if 0
-static Bool     gdk_event_get_type     (Display   *display, 
-                                        XEvent    *xevent, 
-                                        XPointer   arg);
-#endif
+static gboolean         gdk_event_translate     (GdkDisplay *display,
+                                         GdkEvent   *event, 
+                                         XEvent     *xevent,
+                                         gboolean    return_exposes);
 
 static gboolean gdk_event_prepare  (GSource     *source,
                                    gint        *timeout);
@@ -105,6 +97,9 @@ 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,
@@ -117,13 +112,7 @@ static void gdk_xsettings_notify_cb (const char       *name,
 /* 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,
@@ -132,86 +121,116 @@ static GSourceFuncs event_funcs = {
   NULL
 };
 
-static GPollFD event_poll_fd;
-
-static Window wmspec_check_window = None;
+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 XSettingsClient *xsettings_client;
+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)
 {
   GSource *source;
+  GdkDisplaySource *display_source;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
   
-  connection_number = ConnectionNumber (gdk_display);
-  GDK_NOTE (MISC,
-           g_message ("connection number: %d", connection_number));
+  int connection_number = ConnectionNumber (display_x11->xdisplay);
+  GDK_NOTE (MISC, g_message ("connection number: %d", connection_number));
 
 
-  source = g_source_new (&event_funcs, sizeof (GSource));
+  source = display_x11->event_source = gdk_display_source_new (display);
+  display_source = (GdkDisplaySource*) source;
   g_source_set_priority (source, GDK_PRIORITY_EVENTS);
   
-  event_poll_fd.fd = connection_number;
-  event_poll_fd.events = G_IO_IN;
+  display_source->event_poll_fd.fd = connection_number;
+  display_source->event_poll_fd.events = G_IO_IN;
   
-  g_source_add_poll (source, &event_poll_fd);
+  g_source_add_poll (source, &display_source->event_poll_fd);
   g_source_set_can_recurse (source, TRUE);
   g_source_attach (source, NULL);
 
-  _gdk_wm_window_protocols[0] = gdk_x11_get_xatom_by_name ("WM_DELETE_WINDOW");
-  _gdk_wm_window_protocols[1] = gdk_x11_get_xatom_by_name ("WM_TAKE_FOCUS");
-  _gdk_wm_window_protocols[2] = gdk_x11_get_xatom_by_name ("_NET_WM_PING");
-  
-  gdk_add_client_message_filter (gdk_atom_intern ("WM_PROTOCOLS", FALSE),
-                                gdk_wm_protocols_filter, NULL);
+  display_sources = g_list_prepend (display_sources,display_source);
 
-  xsettings_client = xsettings_client_new (gdk_display, DefaultScreen (gdk_display),
-                                          gdk_xsettings_notify_cb,
-                                          gdk_xsettings_watch_cb,
-                                          NULL);
+  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,
@@ -226,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)
 {
@@ -234,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, TRUE))
+      if (gdk_event_translate (GDK_WINDOW_DISPLAY (window), event,
+                              &xevent, TRUE))
        return event;
       else
        gdk_event_free (event);
@@ -272,22 +304,57 @@ gdk_event_apply_filters (XEvent *xevent,
   return GDK_FILTER_CONTINUE;
 }
 
+/**
+ * gdk_display_add_client_message_filter:
+ * @display: a #GdkDisplay for which this message filter applies
+ * @message_type: the type of ClientMessage events to receive.
+ *   This will be checked against the @message_type field 
+ *   of the XClientMessage event struct.
+ * @func: the function to call to process the event.
+ * @data: user data to pass to @func.
+ *
+ * Adds a filter to be called when X ClientMessage events are received.
+ *
+ * Since: 2.2
+ **/ 
 void 
-gdk_add_client_message_filter (GdkAtom       message_type,
-                              GdkFilterFunc func,
-                              gpointer      data)
+gdk_display_add_client_message_filter (GdkDisplay   *display,
+                                      GdkAtom       message_type,
+                                      GdkFilterFunc func,
+                                      gpointer      data)
 {
-  GdkClientFilter *filter = g_new (GdkClientFilter, 1);
+  GdkClientFilter *filter;
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+  filter = g_new (GdkClientFilter, 1);
 
   filter->type = message_type;
   filter->function = func;
   filter->data = data;
   
-  client_filters = g_list_prepend (client_filters, filter);
+  GDK_DISPLAY_X11(display)->client_filters = 
+    g_list_prepend (GDK_DISPLAY_X11 (display)->client_filters,
+                   filter);
 }
 
-static Atom wm_state_atom = 0;
-static Atom wm_desktop_atom = 0;
+/**
+ * gdk_add_client_message_filter:
+ * @message_type: the type of ClientMessage events to receive. This will be
+ *     checked against the <structfield>message_type</structfield> field of the
+ *     XClientMessage event struct.
+ * @func: the function to call to process the event.
+ * @data: user data to pass to @func. 
+ * 
+ * Adds a filter to the default display to be called when X ClientMessage events
+ * are received. See gdk_display_add_client_message_filter().
+ **/
+void 
+gdk_add_client_message_filter (GdkAtom       message_type,
+                              GdkFilterFunc func,
+                              gpointer      data)
+{
+  gdk_display_add_client_message_filter (gdk_display_get_default (),
+                                        message_type, func, data);
+}
 
 static void
 gdk_check_wm_state_changed (GdkWindow *window)
@@ -298,37 +365,31 @@ gdk_check_wm_state_changed (GdkWindow *window)
   gulong bytes_after;
   Atom *atoms = NULL;
   gulong i;
-  Atom sticky_atom;
-  Atom maxvert_atom;
-  Atom maxhorz_atom;
-  gboolean found_sticky, found_maxvert, found_maxhorz;
+  gboolean found_sticky, found_maxvert, found_maxhorz, found_fullscreen;
   GdkWindowState old_state;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) ||
+      gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL)
     return;
   
-  if (wm_state_atom == 0)
-    wm_state_atom = gdk_x11_get_xatom_by_name ("_NET_WM_STATE");
-
-  if (wm_desktop_atom == 0)
-    wm_desktop_atom = gdk_x11_get_xatom_by_name ("_NET_WM_DESKTOP");
+  found_sticky = FALSE;
+  found_maxvert = FALSE;
+  found_maxhorz = FALSE;
+  found_fullscreen = FALSE;
   
   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
-                     wm_state_atom, 0, G_MAXLONG,
-                     False, XA_ATOM, &type, &format, &nitems,
+                     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)
     {
-
-      sticky_atom = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_STICKY");
-      maxvert_atom = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_MAXIMIZED_VERT");
-      maxhorz_atom = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_MAXIMIZED_HORZ");    
-
-      found_sticky = FALSE;
-      found_maxvert = FALSE;
-      found_maxhorz = FALSE;
-  
+      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)
         {
@@ -338,18 +399,14 @@ gdk_check_wm_state_changed (GdkWindow *window)
             found_maxvert = TRUE;
           else if (atoms[i] == maxhorz_atom)
             found_maxhorz = TRUE;
-
+          else if (atoms[i] == fullscreen_atom)
+            found_fullscreen = TRUE;
+          
           ++i;
         }
 
       XFree (atoms);
     }
-  else
-    {
-      found_sticky = FALSE;
-      found_maxvert = FALSE;
-      found_maxhorz = FALSE;
-    }
 
   /* For found_sticky to remain TRUE, we have to also be on desktop
    * 0xFFFFFFFF
@@ -359,9 +416,12 @@ gdk_check_wm_state_changed (GdkWindow *window)
     {
       gulong *desktop;
       
-      XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
-                          wm_desktop_atom, 0, G_MAXLONG,
-                          False, XA_CARDINAL, &type, &format, &nitems,
+      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)
@@ -389,6 +449,21 @@ gdk_check_wm_state_changed (GdkWindow *window)
                                      GDK_WINDOW_STATE_STICKY);
     }
 
+  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
    */
@@ -425,21 +500,202 @@ generate_focus_event (GdkWindow *window,
   gdk_event_put (&event);
 }
 
-static gint
-gdk_event_translate (GdkEvent *event,
-                    XEvent   *xevent,
-                    gboolean  return_exposes)
+static void
+set_screen_from_root (GdkDisplay *display,
+                     GdkEvent   *event,
+                     Window      xrootwin)
+{
+  GdkScreen *screen;
+
+  screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
+  g_assert (screen);
+
+  gdk_event_set_screen (event, screen);
+}
+
+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];
+
+  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 (c)
+    {
+      gsize bytes_written;
+      gint len;
+
+      /* Apply the control key - Taken from Xlib
+       */
+      if (event->key.state & GDK_CONTROL_MASK)
+       {
+         if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
+         else if (c == '2')
+           {
+             event->key.string = g_memdup ("\0\0", 2);
+             event->key.length = 1;
+             buf[0] = '\0';
+             goto out;
+           }
+         else if (c >= '3' && c <= '7') c -= ('3' - '\033');
+         else if (c == '8') c = '\177';
+         else if (c == '/') c = '_' & 0x1F;
+       }
+      
+      len = g_unichar_to_utf8 (c, buf);
+      buf[len] = '\0';
+      
+      event->key.string = g_locale_from_utf8 (buf, len,
+                                             NULL, &bytes_written,
+                                             NULL);
+      if (event->key.string)
+       event->key.length = bytes_written;
+    }
+  else if (event->key.keyval == GDK_Escape)
+    {
+      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");
+    }
+
+  if (!event->key.string)
+    {
+      event->key.length = 0;
+      event->key.string = g_strdup ("");
+    }
+  
+ out:
+#ifdef G_ENABLE_DEBUG
+  if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
+    {
+      g_message ("%s:\t\twindow: %ld    key: %12s  %d",
+                event->type == GDK_KEY_PRESS ? "key press  " : "key release",
+                xevent->xkey.window,
+                event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
+                event->key.keyval);
+  
+      if (event->key.length > 0)
+       g_message ("\t\tlength: %4d string: \"%s\"",
+                  event->key.length, buf);
+    }
+#endif /* G_ENABLE_DEBUG */  
+}
+
+/* Return 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)
+{
+  switch (event->type)
+    {      
+    case CreateNotify:
+      return event->xcreatewindow.window;
+      
+    case DestroyNotify:
+      return event->xdestroywindow.window;
+
+    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;
+    }
+}
+
+#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;
   GdkWindowObject *window_private;
+  GdkWindow *filter_window;
   GdkWindowImplX11 *window_impl = NULL;
-  static XComposeStatus compose;
-  KeySym keysym;
-  int charcount;
-  char buf[16];
   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;
 
@@ -447,7 +703,7 @@ gdk_event_translate (GdkEvent *event,
   window = NULL;
   window_private = NULL;
   event->any.window = NULL;
-  
+
   if (_gdk_default_filters)
     {
       /* Apply global filters */
@@ -478,11 +734,29 @@ gdk_event_translate (GdkEvent *event,
        return_val = FALSE;
     }
 
-  /* Find the GdkWindow that this event occurred in. */
+  /* 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);
+  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)
     {
       /* Window may be a pixmap, so check its type.
@@ -493,24 +767,26 @@ gdk_event_translate (GdkEvent *event,
       if (GDK_IS_WINDOW (window))
         {
           window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
-         
-          if (xevent->xany.window != GDK_WINDOW_XID (window))
+
+          /* 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)
             {
-              g_assert (xevent->xany.window == window_impl->focus_window);
-              
               switch (xevent->type)
                 {
                 case KeyPress:
                 case KeyRelease:
-                  xevent->xany.window = GDK_WINDOW_XID (window);
+                  xwindow = GDK_WINDOW_XID (window);
+                  xevent->xany.window = xwindow;
                   break;
                 default:
-                  return False;
+                  return FALSE;
                 }
             }
         }
 
-      g_object_ref (G_OBJECT (window));
+      g_object_ref (window);
     }
 
   event->any.window = window;
@@ -524,25 +800,41 @@ gdk_event_translate (GdkEvent *event,
          goto done;
        }
     }
-  else if (window_private)
+  else if (filter_window)
     {
       /* Apply per-window filters */
+      GdkWindowObject *filter_private = (GdkWindowObject *) filter_window;
       GdkFilterReturn result;
-      result = gdk_event_apply_filters (xevent, event,
-                                       window_private->filters);
-      
-      if (result != GDK_FILTER_CONTINUE)
+
+      if (filter_private->filters)
        {
-         return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
-         goto done;
+         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;
+           }
        }
     }
       
-  if (wmspec_check_window != None &&
-      xevent->xany.window == wmspec_check_window)
+  if (screen_x11 && screen_x11->wmspec_check_window != None &&
+      xwindow == screen_x11->wmspec_check_window)
     {
       if (xevent->type == DestroyNotify)
-        wmspec_check_window = None;
+        {
+          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
@@ -555,14 +847,14 @@ gdk_event_translate (GdkEvent *event,
     }
 
   if (window &&
-      _gdk_moveresize_window &&
       (xevent->xany.type == MotionNotify ||
        xevent->xany.type == ButtonRelease))
     {
-      _gdk_moveresize_handle_event (xevent);
-      
-      return_val = FALSE;
-      goto done;
+      if (_gdk_moveresize_handle_event (xevent))
+       {
+          return_val = FALSE;
+          goto done;
+        }
     }
   
   /* We do a "manual" conversion of the XEvent to a
@@ -583,7 +875,7 @@ gdk_event_translate (GdkEvent *event,
       xoffset = 0;
       yoffset = 0;
     }
-  
+
   switch (xevent->type)
     {
     case KeyPress:
@@ -592,48 +884,9 @@ gdk_event_translate (GdkEvent *event,
           return_val = FALSE;
           break;
         }
-      
-      /* Lookup the string corresponding to the given keysym.
-       */
-
-      charcount = XLookupString (&xevent->xkey, buf, 16,
-                                &keysym, &compose);
-      event->key.keyval = keysym;
-      event->key.hardware_keycode = xevent->xkey.keycode;
-      
-      if (charcount > 0 && buf[charcount-1] == '\0')
-       charcount --;
-      else
-       buf[charcount] = '\0';
-      
-#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 */
-
-      /* bits 13 and 14 in the "state" field are the keyboard group */
-#define KEYBOARD_GROUP_SHIFT 13
-#define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14))
-      
-      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;
-
-      event->key.group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT;
-      
+      translate_key_event (display, event, xevent);
       break;
-      
+
     case KeyRelease:
       if (window_private == NULL)
         {
@@ -641,44 +894,27 @@ gdk_event_translate (GdkEvent *event,
           break;
         }
       
-      /* Lookup the string corresponding to the given keysym.
-       */
-
       /* Emulate detectable auto-repeat by checking to see
        * if the next event is a key press with the same
        * keycode and timestamp, and if so, ignoring the event.
        */
 
-      if (!_gdk_have_xkb_autorepeat && XPending (gdk_display))
+      if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
        {
          XEvent next_event;
 
-         XPeekEvent (gdk_display, &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)
-           break;
+           {
+             return_val = FALSE;
+             break;
+           }
        }
-      
-      keysym = GDK_VoidSymbol;
-      charcount = XLookupString (&xevent->xkey, buf, 16,
-                                &keysym, &compose);
-      event->key.keyval = keysym;      
-      
-      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:
@@ -690,7 +926,7 @@ gdk_event_translate (GdkEvent *event,
       
       if (window_private == NULL || 
          ((window_private->extension_events != 0) &&
-           _gdk_input_ignore_core))
+           display_x11->input_ignore_core))
        {
          return_val = FALSE;
          break;
@@ -716,13 +952,16 @@ gdk_event_translate (GdkEvent *event,
             event->scroll.direction = GDK_SCROLL_RIGHT;
 
          event->scroll.window = window;
-         event->scroll.time = xevent->xbutton.x;
+         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 = _gdk_core_pointer;
+         event->scroll.device = display->core_pointer;
+
+         set_screen_from_root (display, event, xevent->xbutton.root);
+         
           break;
           
         default:
@@ -736,9 +975,11 @@ gdk_event_translate (GdkEvent *event,
          event->button.axes = NULL;
          event->button.state = (GdkModifierType) xevent->xbutton.state;
          event->button.button = xevent->xbutton.button;
-         event->button.device = _gdk_core_pointer;
+         event->button.device = display->core_pointer;
          
-         _gdk_event_button_generate (event);
+         set_screen_from_root (display, event, xevent->xbutton.root);
+
+         _gdk_event_button_generate (display, event);
           break;
        }
 
@@ -753,7 +994,7 @@ gdk_event_translate (GdkEvent *event,
       
       if (window_private == NULL ||
          ((window_private->extension_events != 0) &&
-           _gdk_input_ignore_core))
+           display_x11->input_ignore_core))
        {
          return_val = FALSE;
          break;
@@ -777,7 +1018,9 @@ gdk_event_translate (GdkEvent *event,
       event->button.axes = NULL;
       event->button.state = (GdkModifierType) xevent->xbutton.state;
       event->button.button = xevent->xbutton.button;
-      event->button.device = _gdk_core_pointer;
+      event->button.device = display->core_pointer;
+
+      set_screen_from_root (display, event, xevent->xbutton.root);
       
       break;
       
@@ -790,7 +1033,7 @@ gdk_event_translate (GdkEvent *event,
       
       if (window_private == NULL ||
          ((window_private->extension_events != 0) &&
-           _gdk_input_ignore_core))
+           display_x11->input_ignore_core))
        {
          return_val = FALSE;
          break;
@@ -806,7 +1049,9 @@ gdk_event_translate (GdkEvent *event,
       event->motion.axes = NULL;
       event->motion.state = (GdkModifierType) xevent->xmotion.state;
       event->motion.is_hint = xevent->xmotion.is_hint;
-      event->motion.device = _gdk_core_pointer;
+      event->motion.device = display->core_pointer;
+      
+      set_screen_from_root (display, event, xevent->xmotion.root);
       
       break;
       
@@ -827,10 +1072,10 @@ gdk_event_translate (GdkEvent *event,
       if (window &&
          GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
          xevent->xcrossing.detail != NotifyInferior &&
-         xevent->xcrossing.focus && !window_impl->has_focus)
+         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)
@@ -850,7 +1095,7 @@ 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;
       
@@ -860,6 +1105,8 @@ gdk_event_translate (GdkEvent *event,
       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)
@@ -920,12 +1167,12 @@ gdk_event_translate (GdkEvent *event,
       if (window &&
          GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
          xevent->xcrossing.detail != NotifyInferior &&
-         xevent->xcrossing.focus && !window_impl->has_focus)
+         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);
        }
@@ -937,7 +1184,7 @@ 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;
       
@@ -947,6 +1194,8 @@ gdk_event_translate (GdkEvent *event,
       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)
@@ -996,7 +1245,10 @@ gdk_event_translate (GdkEvent *event,
        */
     case FocusIn:
       GDK_NOTE (EVENTS,
-               g_message ("focus in:\t\twindow: %ld", xevent->xfocus.window));
+               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)
        {
@@ -1008,10 +1260,21 @@ gdk_event_translate (GdkEvent *event,
            case NotifyNonlinear:
            case NotifyVirtual:
            case NotifyNonlinearVirtual:
-             window_impl->has_focus = TRUE;
+             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:
-             window_impl->has_pointer_focus = TRUE;
+             /* 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:
@@ -1025,8 +1288,11 @@ gdk_event_translate (GdkEvent *event,
       break;
     case FocusOut:
       GDK_NOTE (EVENTS,
-               g_message ("focus out:\t\twindow: %ld", xevent->xfocus.window));
-
+               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);
@@ -1037,10 +1303,13 @@ gdk_event_translate (GdkEvent *event,
            case NotifyNonlinear:
            case NotifyVirtual:
            case NotifyNonlinearVirtual:
-             window_impl->has_focus = FALSE;
+             window_impl->has_focus_window = FALSE;
+             if (xevent->xfocus.mode != NotifyWhileGrabbed)
+               window_impl->has_focus = FALSE;
              break;
            case NotifyPointer:
-             window_impl->has_pointer_focus = FALSE;
+             if (xevent->xfocus.mode != NotifyUngrab)
+               window_impl->has_pointer_focus = FALSE;
            break;
            case NotifyInferior:
            case NotifyPointerRoot:
@@ -1105,7 +1374,6 @@ gdk_event_translate (GdkEvent *event,
        else
          {
            _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
-
            return_val = FALSE;
          }
        
@@ -1236,11 +1504,12 @@ gdk_event_translate (GdkEvent *event,
          
          return_val = window_private && !GDK_WINDOW_DESTROYED (window);
          
-         if (window && GDK_WINDOW_XID (window) != GDK_ROOT_WINDOW())
+         if (window && GDK_WINDOW_XID (window) != screen_x11->xroot_window)
            gdk_window_destroy_notify (window);
        }
       else
        return_val = FALSE;
+      
       break;
       
     case UnmapNotify:
@@ -1256,13 +1525,15 @@ gdk_event_translate (GdkEvent *event,
        * an unmap, it means we hid the window ourselves, so we
        * will have already flipped the iconified bit off.
        */
-      if (window && GDK_WINDOW_IS_MAPPED (window))
-        gdk_synthesize_window_state (window,
-                                     0,
-                                     GDK_WINDOW_STATE_ICONIFIED);
-      
-      if (_gdk_xgrab_window == window_private)
-       _gdk_xgrab_window = NULL;
+      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;
       
@@ -1310,13 +1581,20 @@ gdk_event_translate (GdkEvent *event,
                           ? " (discarding)"
                           : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
                           ? " (discarding child)"
+                          : xevent->xconfigure.event != xevent->xconfigure.window
+                          ? " (discarding substructure)"
                           : ""));
+      if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
+       _gdk_x11_screen_size_changed (screen, xevent);
+
       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;
@@ -1337,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))
@@ -1364,9 +1642,8 @@ gdk_event_translate (GdkEvent *event,
            {
              window_private->resize_count -= 1;
 
-             if (window_private->resize_count == 0 &&
-                 window == _gdk_moveresize_window)
-               _gdk_moveresize_configure_done ();
+             if (window_private->resize_count == 0)
+               _gdk_moveresize_configure_done (display, window);
            }
        }
       break;
@@ -1377,34 +1654,33 @@ gdk_event_translate (GdkEvent *event,
                           xevent->xproperty.window,
                           xevent->xproperty.atom,
                           "\"",
-                          gdk_x11_get_xatom_name (xevent->xproperty.atom),
+                          gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom),
                           "\""));
 
       if (window_private == NULL)
         {
-          return_val = FALSE;
+         return_val = FALSE;
           break;
         }
       
-      event->property.type = GDK_PROPERTY_NOTIFY;
-      event->property.window = window;
-      event->property.atom = gdk_x11_xatom_to_atom (xevent->xproperty.atom);
-      event->property.time = xevent->xproperty.time;
-      event->property.state = xevent->xproperty.state;
-
-      if (wm_state_atom == 0)
-        wm_state_atom = gdk_x11_get_xatom_by_name ("_NET_WM_STATE");
-
-      if (wm_desktop_atom == 0)
-        wm_desktop_atom = gdk_x11_get_xatom_by_name ("_NET_WM_DESKTOP");
-      
-      if (xevent->xproperty.atom == wm_state_atom || 
-         xevent->xproperty.atom == wm_desktop_atom)
+      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 (event->property.window);
+          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:
@@ -1416,7 +1692,7 @@ gdk_event_translate (GdkEvent *event,
        {
          event->selection.type = GDK_SELECTION_CLEAR;
          event->selection.window = window;
-         event->selection.selection = gdk_x11_xatom_to_atom (xevent->xselectionclear.selection);
+         event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionclear.selection);
          event->selection.time = xevent->xselectionclear.time;
        }
       else
@@ -1431,9 +1707,9 @@ gdk_event_translate (GdkEvent *event,
       
       event->selection.type = GDK_SELECTION_REQUEST;
       event->selection.window = window;
-      event->selection.selection = gdk_x11_xatom_to_atom (xevent->xselectionrequest.selection);
-      event->selection.target = gdk_x11_xatom_to_atom (xevent->xselectionrequest.target);
-      event->selection.property = gdk_x11_xatom_to_atom (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;
       
@@ -1447,9 +1723,9 @@ gdk_event_translate (GdkEvent *event,
       
       event->selection.type = GDK_SELECTION_NOTIFY;
       event->selection.window = window;
-      event->selection.selection = gdk_x11_xatom_to_atom (xevent->xselection.selection);
-      event->selection.target = gdk_x11_xatom_to_atom (xevent->xselection.target);
-      event->selection.property = gdk_x11_xatom_to_atom (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;
@@ -1467,13 +1743,13 @@ gdk_event_translate (GdkEvent *event,
       {
        GList *tmp_list;
        GdkFilterReturn result = GDK_FILTER_CONTINUE;
-       GdkAtom message_type = gdk_x11_xatom_to_atom (xevent->xclient.message_type);
+       GdkAtom message_type = gdk_x11_xatom_to_atom_for_display (display, xevent->xclient.message_type);
 
        GDK_NOTE (EVENTS,
                  g_message ("client message:\twindow: %ld",
                             xevent->xclient.window));
        
-       tmp_list = client_filters;
+       tmp_list = display_x11->client_filters;
        while (tmp_list)
          {
            GdkClientFilter *filter = tmp_list->data;
@@ -1522,25 +1798,26 @@ gdk_event_translate (GdkEvent *event,
       /* Let XLib know that there is a new keyboard mapping.
        */
       XRefreshKeyboardMapping (&xevent->xmapping);
-      ++_gdk_keymap_serial;
+      _gdk_keymap_keys_changed (display);
       return_val = FALSE;
       break;
 
     default:
 #ifdef HAVE_XKB
-      if (xevent->type == _gdk_xkb_event_type)
+      if (xevent->type == display_x11->xkb_event_type)
        {
          XkbEvent *xkb_event = (XkbEvent *)xevent;
 
          switch (xkb_event->any.xkb_type)
            {
            case XkbMapNotify:
-             ++_gdk_keymap_serial;
+             _gdk_keymap_keys_changed (display);
+
              return_val = FALSE;
              break;
              
            case XkbStateNotify:
-             _gdk_keymap_state_changed ();
+             _gdk_keymap_state_changed (display);
              break;
            }
        }
@@ -1564,11 +1841,11 @@ gdk_event_translate (GdkEvent *event,
   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
     {
@@ -1578,7 +1855,7 @@ gdk_event_translate (GdkEvent *event,
     }
   
   if (window)
-    gdk_window_unref (window);
+    g_object_unref (window);
   
   return return_val;
 }
@@ -1589,8 +1866,10 @@ gdk_wm_protocols_filter (GdkXEvent *xev,
                         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_x11_get_xatom_by_name ("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
@@ -1608,7 +1887,7 @@ gdk_wm_protocols_filter (GdkXEvent *xev,
 
       return GDK_FILTER_TRANSLATE;
     }
-  else if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name ("WM_TAKE_FOCUS"))
+  else if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
     {
       GdkWindow *win = event->any.window;
       Window focus_win = GDK_WINDOW_IMPL_X11(((GdkWindowObject *)win)->impl)->focus_window;
@@ -1624,46 +1903,31 @@ gdk_wm_protocols_filter (GdkXEvent *xev,
       XSync (GDK_WINDOW_XDISPLAY (win), False);
       gdk_error_trap_pop ();
     }
-  else if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name ("_NET_WM_PING"))
+  else if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING"))
     {
       XEvent xev = *xevent;
       
-      xev.xclient.window = _gdk_root_window;
-      XSendEvent (gdk_display, _gdk_root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+      xev.xclient.window = GDK_WINDOW_XROOTWIN (win);
+      XSendEvent (GDK_WINDOW_XDISPLAY (win), 
+                 xev.xclient.window,
+                 False, 
+                 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
     }
 
   return GDK_FILTER_REMOVE;
 }
 
-#if 0
-static Bool
-gdk_event_get_type (Display  *display,
-                   XEvent   *xevent,
-                   XPointer  arg)
-{
-  GdkEvent event;
-  GdkPredicate *pred;
-  
-  if (gdk_event_translate (&event, xevent, FALSE))
-    {
-      pred = (GdkPredicate*) arg;
-      return (* pred->func) (&event, pred->data);
-    }
-  
-  return FALSE;
-}
-#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))
     {
-      XNextEvent (gdk_display, &xevent);
+      XNextEvent (xdisplay, &xevent);
 
       switch (xevent.type)
        {
@@ -1675,24 +1939,22 @@ _gdk_events_queue (void)
            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, FALSE))
+      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);
        }
@@ -1703,28 +1965,31 @@ static gboolean
 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 (GSource  *source) 
+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;
 
@@ -1738,12 +2003,13 @@ 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)
     {
@@ -1758,58 +2024,69 @@ gdk_event_dispatch (GSource    *source,
   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 = gdk_x11_atom_to_xatom (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 Atom wm_state_atom = 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_x11_get_xatom_by_name ("WM_STATE");
-
-  _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;
@@ -1818,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);
@@ -1837,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;
+
+ out:
+  gdk_error_trap_pop ();
 
-  return (send || found);
+  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 = gdk_x11_atom_to_xatom (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);
 }
 
 /*
@@ -1886,21 +2183,27 @@ 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 Atom timestamp_prop_atom = 0;
-
 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 == timestamp_prop_atom)
+      xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display 
+      (gdk_display, "GDK_TIMESTAMP_PROP"))
     return True;
 
   return False;
@@ -1923,18 +2226,19 @@ gdk_x11_get_server_time (GdkWindow *window)
   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);
 
-  if (!timestamp_prop_atom)
-    timestamp_prop_atom = gdk_x11_get_xatom_by_name ("GDK_TIMESTAMP_PROP");
-
   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,
+  XChangeProperty (xdisplay, xwindow, timestamp_prop_atom,
+                  timestamp_prop_atom,
                   8, PropModeReplace, &c, 1);
 
   XIfEvent (xdisplay, &xevent,
@@ -1943,112 +2247,235 @@ gdk_x11_get_server_time (GdkWindow *window)
   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_net_wm_supports:
- * @property: a property atom
+ * 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 http://www.freedesktop.org.
+ * 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_net_wm_supports() will return %FALSE for every property.
+ * 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_net_wm_supports (GdkAtom property)
+gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
+                                    GdkAtom    property)
 {
-  static Atom wmspec_check_atom = 0;
-  static Atom wmspec_supported_atom = 0;
-  static Atom *atoms = NULL;
-  static gulong n_atoms = 0;
-  Atom xproperty = gdk_x11_atom_to_xatom (property);
-  Atom type;
-  gint format;
-  gulong nitems;
-  gulong bytes_after;
-  Window *xwindow;
   gulong i;
+  GdkScreenX11 *screen_x11;
+  NetWmSupportedAtoms *supported_atoms;
+  GdkDisplay *display;
 
-  if (wmspec_check_window != None)
-    {
-      if (atoms == NULL)
-        return FALSE;
-
-      i = 0;
-      while (i < n_atoms)
-        {
-          if (atoms[i] == xproperty)
-            return TRUE;
-          
-          ++i;
-        }
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+  
+  screen_x11 = GDK_SCREEN_X11 (screen);
+  display = screen_x11->display;
 
-      return FALSE;
+  supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
+  if (!supported_atoms)
+    {
+      supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
+      g_object_set_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms);
     }
 
-  if (atoms)
-    XFree (atoms);
-
-  atoms = NULL;
-  n_atoms = 0;
-  
-  /* 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.
-   */
-  
-  if (wmspec_check_atom == 0)
-    wmspec_check_atom = gdk_x11_get_xatom_by_name ("_NET_SUPPORTING_WM_CHECK");
-      
-  if (wmspec_supported_atom == 0)
-    wmspec_supported_atom = gdk_x11_get_xatom_by_name ("_NET_SUPPORTED");
-  
-  XGetWindowProperty (gdk_display, _gdk_root_window,
-                     wmspec_check_atom, 0, G_MAXLONG,
-                     False, XA_WINDOW, &type, &format, &nitems,
-                     &bytes_after, (guchar **)&xwindow);
+  fetch_net_wm_check_window (screen);
 
-  if (type != XA_WINDOW)
+  if (screen_x11->wmspec_check_window == None)
     return FALSE;
-
-  gdk_error_trap_push ();
-
-  /* Find out if this WM goes away, so we can reset everything. */
-  XSelectInput (gdk_display, *xwindow,
-                StructureNotifyMask);
-  
-  gdk_flush ();
   
-  if (gdk_error_trap_pop ())
+  if (screen_x11->need_refetch_net_supported)
     {
-      XFree (xwindow);
-      return FALSE;
-    }
+      /* WM has changed since we last got the supported list,
+       * refetch it.
+       */
+      Atom type;
+      gint format;
+      gulong bytes_after;
 
-  XGetWindowProperty (gdk_display, _gdk_root_window,
-                     wmspec_supported_atom, 0, G_MAXLONG,
-                     False, XA_ATOM, &type, &format, &n_atoms,
-                     &bytes_after, (guchar **)&atoms);
+      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 (type != XA_ATOM)
+  if (supported_atoms->atoms == NULL)
     return FALSE;
   
-  wmspec_check_window = *xwindow;
-  XFree (xwindow);
+  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;
+    }
   
-  /* since wmspec_check_window != None this isn't infinite. ;-) */
-  return gdk_net_wm_supports (property);
+  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
@@ -2056,15 +2483,20 @@ static struct
   const char *xsettings_name;
   const char *gdk_name;
 } settings_map[] = {
-  { "Net/DoubleClickTime", "gtk-double-click-timeout" },
+  { "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" },
-  { "Gtk/KeyThemeName", "gtk-key-theme-name" }
+  { "Net/ThemeName", "gtk-theme-name" }
 };
 
 static void
@@ -2074,20 +2506,26 @@ gdk_xsettings_notify_cb (const char       *name,
                         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 = NULL;
+  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 = g_strdup (settings_map[i].gdk_name);
+       new_event.setting.name = (char *)settings_map[i].gdk_name;
        break;
       }
 
+  
   if (!new_event.setting.name)
     return;
   
@@ -2124,16 +2562,40 @@ check_transform (const gchar *xsettings_name,
     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_setting_get (const gchar *name,
-                GValue      *value)
+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)
@@ -2145,7 +2607,8 @@ gdk_setting_get (const gchar *name,
   if (!xsettings_name)
     return FALSE;
 
-  result = xsettings_client_get_setting (xsettings_client, xsettings_name, &setting);
+  result = xsettings_client_get_setting (screen_x11->xsettings_client, 
+                                        xsettings_name, &setting);
   if (result != XSETTINGS_SUCCESS)
     return FALSE;
 
@@ -2204,23 +2667,38 @@ gdk_xsettings_client_event_filter (GdkXEvent *xevent,
                                   GdkEvent  *event,
                                   gpointer   data)
 {
-  if (xsettings_client_process_event (xsettings_client, (XEvent *)xevent))
+  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)
+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);
 
-  gdkwin = gdk_window_lookup (window);
   if (is_start)
-    gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
+    {
+      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
-    gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
+    {
+      g_assert (gdkwin);
+      gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+      g_object_unref (gdkwin);
+    }
 }