]> 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 5cabe70de24c952d5e903443685319cf46f3bdbf..e32fe2182b29e0ed00d7a3a1e77b9078ba9fc2d2 100644 (file)
@@ -51,7 +51,6 @@
 #include <X11/Xatom.h>
 
 typedef struct _GdkIOClosure GdkIOClosure;
-typedef struct _GdkEventPrivate GdkEventPrivate;
 typedef struct _GdkDisplaySource GdkDisplaySource;
 
 #define DOUBLE_CLICK_TIME      250
@@ -59,14 +58,6 @@ typedef struct _GdkDisplaySource GdkDisplaySource;
 #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;
@@ -75,12 +66,6 @@ struct _GdkIOClosure
   gpointer data;
 };
 
-struct _GdkEventPrivate
-{
-  GdkEvent event;
-  guint    flags;
-};
-
 struct _GdkDisplaySource
 {
   GSource source;
@@ -161,12 +146,25 @@ 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 
@@ -180,7 +178,7 @@ _gdk_events_init (GdkDisplay *display)
   GDK_NOTE (MISC, g_message ("connection number: %d", connection_number));
 
 
-  source = gdk_display_source_new (display);
+  source = display_x11->event_source = gdk_display_source_new (display);
   display_source = (GdkDisplaySource*) source;
   g_source_set_priority (source, GDK_PRIORITY_EVENTS);
   
@@ -198,8 +196,6 @@ _gdk_events_init (GdkDisplay *display)
        gdk_atom_intern ("WM_PROTOCOLS", FALSE), 
        gdk_wm_protocols_filter,   
        NULL);
-
-  _gdk_x11_events_init_screen (display_x11->default_screen);
 }
 
 
@@ -273,7 +269,7 @@ gdk_event_get_graphics_expose (GdkWindow *window)
   
   if (xevent.xany.type == GraphicsExpose)
     {
-      event = _gdk_event_new ();
+      event = gdk_event_new (GDK_NOTHING);
       
       if (gdk_event_translate (GDK_WINDOW_DISPLAY (window), event,
                               &xevent, TRUE))
@@ -319,6 +315,7 @@ gdk_event_apply_filters (XEvent *xevent,
  *
  * Adds a filter to be called when X ClientMessage events are received.
  *
+ * Since: 2.2
  **/ 
 void 
 gdk_display_add_client_message_filter (GdkDisplay   *display,
@@ -355,7 +352,7 @@ gdk_add_client_message_filter (GdkAtom       message_type,
                               GdkFilterFunc func,
                               gpointer      data)
 {
-  gdk_display_add_client_message_filter (gdk_get_default_display (),
+  gdk_display_add_client_message_filter (gdk_display_get_default (),
                                         message_type, func, data);
 }
 
@@ -368,16 +365,18 @@ gdk_check_wm_state_changed (GdkWindow *window)
   gulong bytes_after;
   Atom *atoms = NULL;
   gulong i;
-  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;
   
   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"),
@@ -389,7 +388,8 @@ gdk_check_wm_state_changed (GdkWindow *window)
       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)
         {
@@ -399,7 +399,9 @@ 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;
         }
 
@@ -447,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
    */
@@ -483,6 +500,185 @@ generate_focus_event (GdkWindow *window,
   gdk_event_put (&event);
 }
 
+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,
@@ -492,16 +688,14 @@ gdk_event_translate (GdkDisplay *display,
   
   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;
 
@@ -509,7 +703,7 @@ gdk_event_translate (GdkDisplay *display,
   window = NULL;
   window_private = NULL;
   event->any.window = NULL;
-  
+
   if (_gdk_default_filters)
     {
       /* Apply global filters */
@@ -540,11 +734,23 @@ gdk_event_translate (GdkDisplay *display,
        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_for_display (display, 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);
@@ -561,16 +767,18 @@ gdk_event_translate (GdkDisplay *display,
       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;
@@ -578,7 +786,7 @@ gdk_event_translate (GdkDisplay *display,
             }
         }
 
-      g_object_ref (G_OBJECT (window));
+      g_object_ref (window);
     }
 
   event->any.window = window;
@@ -592,25 +800,41 @@ gdk_event_translate (GdkDisplay *display,
          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 (screen_x11 && screen_x11->wmspec_check_window != None &&
-      xevent->xany.window == screen_x11->wmspec_check_window)
+      xwindow == screen_x11->wmspec_check_window)
     {
       if (xevent->type == DestroyNotify)
-        screen_x11->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
@@ -651,7 +875,7 @@ gdk_event_translate (GdkDisplay *display,
       xoffset = 0;
       yoffset = 0;
     }
-  
+
   switch (xevent->type)
     {
     case KeyPress:
@@ -660,48 +884,9 @@ gdk_event_translate (GdkDisplay *display,
           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 */
-
-      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;
-
-      /* 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.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
-      
+      translate_key_event (display, event, xevent);
       break;
-      
+
     case KeyRelease:
       if (window_private == NULL)
         {
@@ -709,9 +894,6 @@ gdk_event_translate (GdkDisplay *display,
           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.
@@ -726,29 +908,13 @@ gdk_event_translate (GdkDisplay *display,
          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;
-      
-      event->key.group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT;
 
+      translate_key_event (display, event, xevent);
       break;
       
     case ButtonPress:
@@ -792,7 +958,10 @@ gdk_event_translate (GdkDisplay *display,
          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:
@@ -806,8 +975,10 @@ gdk_event_translate (GdkDisplay *display,
          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);
+
          _gdk_event_button_generate (display, event);
           break;
        }
@@ -847,7 +1018,9 @@ gdk_event_translate (GdkDisplay *display,
       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;
       
@@ -876,7 +1049,9 @@ gdk_event_translate (GdkDisplay *display,
       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;
       
@@ -897,10 +1072,10 @@ gdk_event_translate (GdkDisplay *display,
       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)
@@ -930,6 +1105,8 @@ gdk_event_translate (GdkDisplay *display,
       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)
@@ -990,12 +1167,12 @@ gdk_event_translate (GdkDisplay *display,
       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);
        }
@@ -1017,6 +1194,8 @@ gdk_event_translate (GdkDisplay *display,
       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)
@@ -1066,7 +1245,10 @@ gdk_event_translate (GdkDisplay *display,
        */
     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)
        {
@@ -1078,10 +1260,21 @@ gdk_event_translate (GdkDisplay *display,
            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:
@@ -1095,8 +1288,11 @@ gdk_event_translate (GdkDisplay *display,
       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);
@@ -1107,10 +1303,13 @@ gdk_event_translate (GdkDisplay *display,
            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:
@@ -1382,13 +1581,20 @@ gdk_event_translate (GdkDisplay *display,
                           ? " (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;
@@ -1453,23 +1659,28 @@ gdk_event_translate (GdkDisplay *display,
 
       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_for_display (display, xevent->xproperty.atom);
-      event->property.time = xevent->xproperty.time;
-      event->property.state = xevent->xproperty.state;
-
       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:
@@ -1587,7 +1798,7 @@ gdk_event_translate (GdkDisplay *display,
       /* Let XLib know that there is a new keyboard mapping.
        */
       XRefreshKeyboardMapping (&xevent->xmapping);
-      ++display_x11->keymap_serial;
+      _gdk_keymap_keys_changed (display);
       return_val = FALSE;
       break;
 
@@ -1600,7 +1811,7 @@ gdk_event_translate (GdkDisplay *display,
          switch (xkb_event->any.xkb_type)
            {
            case XkbMapNotify:
-             ++display_x11->keymap_serial;
+             _gdk_keymap_keys_changed (display);
 
              return_val = FALSE;
              break;
@@ -1630,11 +1841,11 @@ gdk_event_translate (GdkDisplay *display,
   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
     {
@@ -1644,7 +1855,7 @@ gdk_event_translate (GdkDisplay *display,
     }
   
   if (window)
-    gdk_window_unref (window);
+    g_object_unref (window);
   
   return return_val;
 }
@@ -1728,9 +1939,8 @@ _gdk_events_queue (GdkDisplay *display)
            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;
 
@@ -1815,43 +2025,24 @@ gdk_event_dispatch (GSource    *source,
 }
 
 /**
- * gdk_event_send_client_message:
+ * 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.
- * @xid:  the window to send the X ClientMessage event to.
- * 
- * Sends an X ClientMessage event to a given window (which must be
- * on the default #GdkDisplay.)
- * This could be used for communicating between different applications,
- * though the amount of data is limited to 20 bytes.
- * 
- * Return value: non-zero on success.
- **/
-gboolean
-gdk_event_send_client_message (GdkEvent *event, guint32 xid)
-{
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  return gdk_event_send_client_message_for_display (gdk_get_default_display (),
-                                                   event, xid);
-}
-
-/**
- * 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.
- * @xid : the X window to send the X ClientMessage event to.
+ * @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.
+ * Returns: non-zero on success.
+ *
+ * Since: 2.2
  */
 gboolean
-gdk_event_send_client_message_for_display (GdkDisplay *display,
-                                          GdkEvent *event,
-                                          guint32 xid)
+gdk_event_send_client_message_for_display (GdkDisplay     *display,
+                                          GdkEvent       *event,
+                                          GdkNativeWindow winid)
 {
   XEvent sev;
   
@@ -1861,11 +2052,11 @@ gdk_event_send_client_message_for_display (GdkDisplay *display,
   sev.xclient.type = ClientMessage;
   sev.xclient.display = GDK_DISPLAY_XDISPLAY (display);
   sev.xclient.format = event->client.data_format;
-  sev.xclient.window = xid;
+  sev.xclient.window = winid;
   memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
   sev.xclient.message_type = gdk_x11_atom_to_xatom_for_display (display, event->client.message_type);
   
-  return _gdk_send_xevent (display, xid, False, NoEventMask, &sev);
+  return _gdk_send_xevent (display, winid, False, NoEventMask, &sev);
 }
 
 
@@ -1930,30 +2121,10 @@ gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
   return result;
 }
 
-/**
- * gdk_event_send_clientmessage_toall:
- * @event: the #GdkEvent to send, which should be a #GdkEventClient.
- *
- * Sends an X ClientMessage event to all toplevel windows on the default
- * #GdkScreen.
- *
- * 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.
- **/
-void
-gdk_event_send_clientmessage_toall (GdkEvent *event)
-{
-  g_return_if_fail (event != NULL);
-
-  gdk_screen_broadcast_client_message (gdk_get_default_screen (), event);
-}
-
 /**
  * gdk_screen_broadcast_client_message:
- * @screen : the #GdkScreen where the event will be broadcasted.
- * @event : the #GdkEvent.
+ * @screen: the #GdkScreen where the event will be broadcasted.
+ * @event: the #GdkEvent.
  *
  * Sends an X ClientMessage event to all toplevel windows on @screen.
  *
@@ -1961,6 +2132,8 @@ gdk_event_send_clientmessage_toall (GdkEvent *event)
  * 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
@@ -2074,6 +2247,120 @@ 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_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
@@ -2084,13 +2371,14 @@ struct _NetWmSupportedAtoms
 
 /**
  * gdk_x11_screen_supports_net_wm_hint:
- * @screen : the relevant #GdkScreen.
+ * @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
@@ -2098,18 +2386,17 @@ struct _NetWmSupportedAtoms
  * 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)
 {
-  Atom type;
-  gint format;
-  gulong nitems;
-  gulong bytes_after;
-  Window *xwindow;
   gulong i;
   GdkScreenX11 *screen_x11;
   NetWmSupportedAtoms *supported_atoms;
@@ -2124,75 +2411,54 @@ gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
   if (!supported_atoms)
     {
       supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
-      g_object_set_data (G_OBJECT (screen), "net-wm-supported-atoms", supported_atoms);
+      g_object_set_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms);
     }
 
-  if (screen_x11->wmspec_check_window != None)
+  fetch_net_wm_check_window (screen);
+
+  if (screen_x11->wmspec_check_window == None)
+    return FALSE;
+  
+  if (screen_x11->need_refetch_net_supported)
     {
-      if (supported_atoms->atoms == NULL)
-        return FALSE;
+      /* 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;
       
-      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;
-        }
+      if (supported_atoms->atoms)
+        XFree (supported_atoms->atoms);
       
-      return FALSE;
+      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)
-    XFree (supported_atoms->atoms);
-
-  supported_atoms->atoms = NULL;
-  supported_atoms->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.
-   */
   
-  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, 
-                     &nitems, &bytes_after, (guchar **) & xwindow);
-  
-  if (type != XA_WINDOW)
+  if (supported_atoms->atoms == NULL)
     return FALSE;
-
-  gdk_error_trap_push ();
-
-  /* Find out if this WM goes away, so we can reset everything. */
-  XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask);
-
-  gdk_display_sync (screen_x11->display);
   
-  if (gdk_error_trap_pop ())
+  i = 0;
+  while (i < supported_atoms->n_atoms)
     {
-      XFree (xwindow);
-      return FALSE;
+      if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property))
+        return TRUE;
+      
+      ++i;
     }
   
-  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;
-  
-  screen_x11->wmspec_check_window = *xwindow;
-  XFree (xwindow);
-  
-  /* since wmspec_check_window != None this isn't infinite. ;-) */
-  return gdk_x11_screen_supports_net_wm_hint (screen, property);
+  return FALSE;
 }
 
 /**
@@ -2209,7 +2475,7 @@ gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
 gboolean
 gdk_net_wm_supports (GdkAtom property)
 {
-  return gdk_x11_screen_supports_net_wm_hint (gdk_get_default_screen (), property);
+  return gdk_x11_screen_supports_net_wm_hint (gdk_screen_get_default (), property);
 }
 
 static struct
@@ -2222,9 +2488,12 @@ static struct
   { "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" }
@@ -2238,8 +2507,12 @@ gdk_xsettings_notify_cb (const char       *name,
 {
   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;
@@ -2248,10 +2521,11 @@ gdk_xsettings_notify_cb (const char       *name,
   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;
   
@@ -2288,24 +2562,6 @@ check_transform (const gchar *xsettings_name,
     return TRUE;
 }
 
-/**
- * gdk_setting_get:
- * @name: the name of the setting.
- * @value: location to store the value of the setting.
- *
- * Obtains a desktop-wide setting, such as the double-click time,
- * for the default screen. See gdk_screen_get_setting().
- *
- * Returns : %TRUE if the setting existed and a value was stored
- *   in @value, %FALSE otherwise.
- **/
-gboolean
-gdk_setting_get (const gchar *name,
-                GValue      *value)
-{
-  return gdk_screen_get_setting (gdk_get_default_screen (), name, value);
-}
-
 /**
  * gdk_screen_get_setting:
  * @screen: the #GdkScreen where the setting is located
@@ -2318,8 +2574,10 @@ gdk_setting_get (const gchar *name,
  * 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
+ * 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,
@@ -2419,17 +2677,28 @@ gdk_xsettings_client_event_filter (GdkXEvent *xevent,
 
 static void 
 gdk_xsettings_watch_cb (Window   window,
-                        Bool     is_start,
-                        long     mask,
-                        void    *cb_data)
+                       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)
-    gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+    {
+      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, screen);
+    {
+      g_assert (gdkwin);
+      gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+      g_object_unref (gdkwin);
+    }
 }