]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkevents-x11.c
Updated Azeri and Walloon files
[~andy/gtk] / gdk / x11 / gdkevents-x11.c
index 59de87bc9b6c9e1f65afec7de4822e2c29a5c9b9..a102e2b82717fa2a52c1a6295795a717870c71a1 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "gdkkeysyms.h"
 
+#include "xsettings-client.h"
+
 #if HAVE_CONFIG_H
 #  include <config.h>
 #  if STDC_HEADERS
 
 #include "gdkinputprivate.h"
 
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+#include <X11/Xatom.h>
+
 typedef struct _GdkIOClosure GdkIOClosure;
 typedef struct _GdkEventPrivate GdkEventPrivate;
 
@@ -86,21 +94,26 @@ static Bool  gdk_event_get_type     (Display   *display,
                                         XPointer   arg);
 #endif
 
-static gboolean  gdk_event_prepare      (gpointer   source_data, 
-                                        GTimeVal  *current_time,
-                                        gint      *timeout,
-                                        gpointer   user_data);
-static gboolean  gdk_event_check        (gpointer   source_data,
-                                        GTimeVal  *current_time,
-                                        gpointer   user_data);
-static gboolean  gdk_event_dispatch     (gpointer   source_data,
-                                        GTimeVal  *current_time,
-                                        gpointer   user_data);
+static gboolean gdk_event_prepare  (GSource     *source,
+                                   gint        *timeout);
+static gboolean gdk_event_check    (GSource     *source);
+static gboolean gdk_event_dispatch (GSource     *source,
+                                   GSourceFunc  callback,
+                                   gpointer     user_data);
 
 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
                                         GdkEvent  *event,
                                         gpointer   data);
 
+static void gdk_xsettings_watch_cb  (Window            window,
+                                    Bool              is_start,
+                                    long              mask,
+                                    void             *cb_data);
+static void gdk_xsettings_notify_cb (const char       *name,
+                                    XSettingsAction   action,
+                                    XSettingsSetting *setting,
+                                    void             *data);
+
 /* Private variable declarations
  */
 
@@ -116,10 +129,14 @@ static GSourceFuncs event_funcs = {
   gdk_event_prepare,
   gdk_event_check,
   gdk_event_dispatch,
-  (GDestroyNotify)g_free
+  NULL
 };
 
-GPollFD event_poll_fd;
+static GPollFD event_poll_fd;
+
+static Window wmspec_check_window = None;
+
+static XSettingsClient *xsettings_client;
 
 /*********************************************
  * Functions for maintaining the event queue *
@@ -128,19 +145,30 @@ GPollFD event_poll_fd;
 void 
 gdk_events_init (void)
 {
+  GSource *source;
+  
   connection_number = ConnectionNumber (gdk_display);
   GDK_NOTE (MISC,
            g_message ("connection number: %d", connection_number));
 
-  g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL);
 
+  source = g_source_new (&event_funcs, sizeof (GSource));
+  g_source_set_priority (source, GDK_PRIORITY_EVENTS);
+  
   event_poll_fd.fd = connection_number;
   event_poll_fd.events = G_IO_IN;
   
-  g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS);
+  g_source_add_poll (source, &event_poll_fd);
+  g_source_set_can_recurse (source, TRUE);
+  g_source_attach (source, NULL);
 
   gdk_add_client_message_filter (gdk_wm_protocols, 
                                 gdk_wm_protocols_filter, NULL);
+
+  xsettings_client = xsettings_client_new (gdk_display, DefaultScreen (gdk_display),
+                                          gdk_xsettings_notify_cb,
+                                          gdk_xsettings_watch_cb,
+                                          NULL);
 }
 
 /*
@@ -254,6 +282,145 @@ gdk_add_client_message_filter (GdkAtom       message_type,
   client_filters = g_list_prepend (client_filters, filter);
 }
 
+static GdkAtom wm_state_atom = 0;
+static GdkAtom wm_desktop_atom = 0;
+
+static void
+gdk_check_wm_state_changed (GdkWindow *window)
+{  
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  GdkAtom *atoms = NULL;
+  gulong i;
+  GdkAtom sticky_atom;
+  GdkAtom maxvert_atom;
+  GdkAtom maxhorz_atom;
+  gboolean found_sticky, found_maxvert, found_maxhorz;
+  GdkWindowState old_state;
+  
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+  
+  if (wm_state_atom == 0)
+    wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+
+  if (wm_desktop_atom == 0)
+    wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
+  
+  XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
+                     wm_state_atom, 0, G_MAXLONG,
+                     False, XA_ATOM, &type, &format, &nitems,
+                     &bytes_after, (guchar **)&atoms);
+
+  if (type != None)
+    {
+
+      sticky_atom = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
+      maxvert_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
+      maxhorz_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);    
+
+      found_sticky = FALSE;
+      found_maxvert = FALSE;
+      found_maxhorz = FALSE;
+  
+      i = 0;
+      while (i < nitems)
+        {
+          if (atoms[i] == sticky_atom)
+            found_sticky = TRUE;
+          else if (atoms[i] == maxvert_atom)
+            found_maxvert = TRUE;
+          else if (atoms[i] == maxhorz_atom)
+            found_maxhorz = TRUE;
+
+          ++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
+   */
+
+  if (found_sticky)
+    {
+      gulong *desktop;
+      
+      XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
+                          wm_desktop_atom, 0, G_MAXLONG,
+                          False, XA_CARDINAL, &type, &format, &nitems,
+                          &bytes_after, (guchar **)&desktop);
+
+      if (type != None)
+        {
+          if (*desktop != 0xFFFFFFFF)
+            found_sticky = FALSE;
+          XFree (desktop);
+        }
+    }
+          
+  old_state = gdk_window_get_state (window);
+
+  if (old_state & GDK_WINDOW_STATE_STICKY)
+    {
+      if (!found_sticky)
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_STICKY,
+                                     0);
+    }
+  else
+    {
+      if (found_sticky)
+        gdk_synthesize_window_state (window,
+                                     0,
+                                     GDK_WINDOW_STATE_STICKY);
+    }
+
+  /* Our "maximized" means both vertical and horizontal; if only one,
+   * we don't expose that via GDK
+   */
+  if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
+    {
+      if (!(found_maxvert && found_maxhorz))
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_MAXIMIZED,
+                                     0);
+    }
+  else
+    {
+      if (found_maxvert && found_maxhorz)
+        gdk_synthesize_window_state (window,
+                                     0,
+                                     GDK_WINDOW_STATE_MAXIMIZED);
+    }
+}
+
+#define HAS_FOCUS(window_impl)                           \
+  ((window_impl)->has_focus || (window_impl)->has_pointer_focus)
+
+static void
+generate_focus_event (GdkWindow *window,
+                     gboolean   in)
+{
+  GdkEvent event;
+  
+  event.type = GDK_FOCUS_CHANGE;
+  event.focus_change.window = window;
+  event.focus_change.send_event = FALSE;
+  event.focus_change.in = in;
+  
+  gdk_event_put (&event);
+}
+
 static gint
 gdk_event_translate (GdkEvent *event,
                     XEvent   *xevent,
@@ -262,15 +429,11 @@ gdk_event_translate (GdkEvent *event,
   
   GdkWindow *window;
   GdkWindowObject *window_private;
+  GdkWindowImplX11 *window_impl = NULL;
   static XComposeStatus compose;
   KeySym keysym;
   int charcount;
-#ifdef USE_XIM
-  static gchar* buf = NULL;
-  static gint buf_len= 0;
-#else
   char buf[16];
-#endif
   gint return_val;
   gint xoffset, yoffset;
   
@@ -294,13 +457,53 @@ gdk_event_translate (GdkEvent *event,
     }
   
   window = gdk_window_lookup (xevent->xany.window);
-  /* FIXME: window might be a GdkPixmap!!! */
-  
   window_private = (GdkWindowObject *) window;
+
+  if (_gdk_moveresize_window &&
+      (xevent->xany.type == MotionNotify ||
+       xevent->xany.type == ButtonRelease))
+    {
+      _gdk_moveresize_handle_event (xevent);
+      gdk_window_unref (window);
+      return FALSE;
+    }
+    
+  if (wmspec_check_window != None &&
+      xevent->xany.window == wmspec_check_window)
+    {
+      if (xevent->type == DestroyNotify)
+        wmspec_check_window = None;
+      
+      /* Eat events on this window unless someone had wrapped
+       * it as a foreign window
+       */
+      if (window == NULL)
+        return FALSE;
+    }
   
+  /* FIXME: window might be a GdkPixmap!!! */
   if (window != NULL)
-    gdk_window_ref (window);
-  
+    {
+      window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+         
+      if (xevent->xany.window != GDK_WINDOW_XID (window))
+       {
+         g_assert (xevent->xany.window == window_impl->focus_window);
+
+         switch (xevent->type)
+           {
+           case KeyPress:
+           case KeyRelease:
+             xevent->xany.window = GDK_WINDOW_XID (window);
+             break;
+           default:
+             return False;
+           }
+       }
+
+      gdk_window_ref (window);
+    }
+
   event->any.window = window;
   event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
   
@@ -326,41 +529,6 @@ gdk_event_translate (GdkEvent *event,
        }
     }
 
-#ifdef USE_XIM
-  if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
-      !GDK_WINDOW_DESTROYED (gdk_xim_window))
-    {
-      /*
-       * If user presses a key in Preedit or Status window, keypress event
-       * is sometimes sent to these windows. These windows are not managed
-       * by GDK, so we redirect KeyPress event to xim_window.
-       *
-       * If someone want to use the window whitch is not managed by GDK
-       * and want to get KeyPress event, he/she must register the filter
-       * function to gdk_default_filters to intercept the event.
-       */
-
-      GdkFilterReturn result;
-
-      window = gdk_xim_window;
-      window_private = (GdkWindowObject *) window;
-      gdk_window_ref (window);
-      event->any.window = window;
-
-      GDK_NOTE (XIM,
-       g_message ("KeyPress event is redirected to xim_window: %#lx",
-                  xevent->xany.window));
-
-      result = gdk_event_apply_filters (xevent, event,
-                                       window_private->filters);
-      if (result != GDK_FILTER_CONTINUE)
-       {
-         return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
-         goto done;
-       }
-    }
-#endif
-
   /* We do a "manual" conversion of the XEvent to a
    *  GdkEvent. The structures are mostly the same so
    *  the conversion is fairly straightforward. We also
@@ -385,51 +553,11 @@ gdk_event_translate (GdkEvent *event,
     case KeyPress:
       /* Lookup the string corresponding to the given keysym.
        */
-      
-#ifdef USE_XIM
-      if (buf_len == 0) 
-       {
-         buf_len = 128;
-         buf = g_new (gchar, buf_len);
-       }
-      keysym = GDK_VoidSymbol;
-      
-      if (gdk_xim_ic && gdk_xim_ic->xic)
-       {
-         Status status;
-         
-         /* Clear keyval. Depending on status, may not be set */
-         charcount = XmbLookupString(gdk_xim_ic->xic,
-                                     &xevent->xkey, buf, buf_len-1,
-                                     &keysym, &status);
-         if (status == XBufferOverflow)
-           {                     /* retry */
-             /* alloc adequate size of buffer */
-             GDK_NOTE (XIM,
-                       g_message("XIM: overflow (required %i)", charcount));
-             
-             while (buf_len <= charcount)
-               buf_len *= 2;
-             buf = (gchar *) g_realloc (buf, buf_len);
-             
-             charcount = XmbLookupString (gdk_xim_ic->xic,
-                                          &xevent->xkey, buf, buf_len-1,
-                                          &keysym, &status);
-           }
-         if (status == XLookupNone)
-           {
-             return_val = FALSE;
-             break;
-           }
-       }
-      else
-       charcount = XLookupString (&xevent->xkey, buf, buf_len,
-                                  &keysym, &compose);
-#else
+
       charcount = XLookupString (&xevent->xkey, buf, 16,
                                 &keysym, &compose);
-#endif
       event->key.keyval = keysym;
+      event->key.hardware_keycode = xevent->xkey.keycode;
       
       if (charcount > 0 && buf[charcount-1] == '\0')
        charcount --;
@@ -448,6 +576,10 @@ gdk_event_translate (GdkEvent *event,
                       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;
@@ -455,19 +587,32 @@ gdk_event_translate (GdkEvent *event,
       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;
       
       break;
       
     case KeyRelease:
       /* Lookup the string corresponding to the given keysym.
        */
-#ifdef USE_XIM
-      if (buf_len == 0) 
+
+      /* 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))
        {
-         buf_len = 128;
-         buf = g_new (gchar, buf_len);
+         XEvent next_event;
+
+         XPeekEvent (gdk_display, &next_event);
+
+         if (next_event.type == KeyPress &&
+             next_event.xkey.keycode == xevent->xkey.keycode &&
+             next_event.xkey.time == xevent->xkey.time)
+           break;
        }
-#endif
+      
       keysym = GDK_VoidSymbol;
       charcount = XLookupString (&xevent->xkey, buf, 16,
                                 &keysym, &compose);
@@ -505,11 +650,23 @@ gdk_event_translate (GdkEvent *event,
       
       /* If we get a ButtonPress event where the button is 4 or 5,
         it's a Scroll event */
-      if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
-       {
+      switch (xevent->xbutton.button)
+        {
+        case 4: /* up */
+        case 5: /* down */
+        case 6: /* left */
+        case 7: /* right */
          event->scroll.type = GDK_SCROLL;
-         event->scroll.direction = (xevent->xbutton.button == 4) ? 
-           GDK_SCROLL_UP : GDK_SCROLL_DOWN;
+
+          if (xevent->xbutton.button == 4)
+            event->scroll.direction = GDK_SCROLL_UP;
+          else if (xevent->xbutton.button == 5)
+            event->scroll.direction = GDK_SCROLL_DOWN;
+          else if (xevent->xbutton.button == 6)
+            event->scroll.direction = GDK_SCROLL_LEFT;
+          else
+            event->scroll.direction = GDK_SCROLL_RIGHT;
+
          event->scroll.window = window;
          event->scroll.time = xevent->xbutton.x;
          event->scroll.x = xevent->xbutton.x + xoffset;
@@ -518,9 +675,9 @@ gdk_event_translate (GdkEvent *event,
          event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
          event->scroll.state = (GdkModifierType) xevent->xbutton.state;
          event->scroll.device = gdk_core_pointer;
-       }
-      else
-       {
+          break;
+          
+        default:
          event->button.type = GDK_BUTTON_PRESS;
          event->button.window = window;
          event->button.time = xevent->xbutton.time;
@@ -534,6 +691,7 @@ gdk_event_translate (GdkEvent *event,
          event->button.device = gdk_core_pointer;
          
          gdk_event_button_generate (event);
+          break;
        }
 
       break;
@@ -554,7 +712,8 @@ gdk_event_translate (GdkEvent *event,
        }
       
       /* We treat button presses as scroll wheel events, so ignore the release */
-      if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
+      if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
+          xevent->xbutton.button == 6 || xevent->xbutton.button ==7)
        {
          return_val = FALSE;
          break;
@@ -609,7 +768,21 @@ gdk_event_translate (GdkEvent *event,
                           xevent->xcrossing.window,
                           xevent->xcrossing.detail,
                           xevent->xcrossing.subwindow));
-      
+
+      /* Handle focusing (in the case where no window manager is running */
+      if (window &&
+         GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
+         xevent->xcrossing.detail != NotifyInferior &&
+         xevent->xcrossing.focus && !window_impl->has_focus)
+       {
+         gboolean had_focus = HAS_FOCUS (window_impl);
+         
+         window_impl->has_pointer_focus = TRUE;
+
+         if (HAS_FOCUS (window_impl) != had_focus)
+           generate_focus_event (window, TRUE);
+       }
+
       /* Tell XInput stuff about it if appropriate */
       if (window_private &&
          !GDK_WINDOW_DESTROYED (window) &&
@@ -683,6 +856,20 @@ gdk_event_translate (GdkEvent *event,
                           xevent->xcrossing.window,
                           xevent->xcrossing.detail, xevent->xcrossing.subwindow));
       
+      /* Handle focusing (in the case where no window manager is running */
+      if (window &&
+         GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
+         xevent->xcrossing.detail != NotifyInferior &&
+         xevent->xcrossing.focus && !window_impl->has_focus)
+       {
+         gboolean had_focus = HAS_FOCUS (window_impl);
+         
+         window_impl->has_pointer_focus = FALSE;
+
+         if (HAS_FOCUS (window_impl) != had_focus)
+           generate_focus_event (window, FALSE);
+       }
+
       event->crossing.type = GDK_LEAVE_NOTIFY;
       event->crossing.window = window;
       
@@ -744,38 +931,77 @@ gdk_event_translate (GdkEvent *event,
       
       break;
       
-    case FocusIn:
-    case FocusOut:
       /* We only care about focus events that indicate that _this_
        * window (not a ancestor or child) got or lost the focus
        */
-      switch (xevent->xfocus.detail)
+    case FocusIn:
+      GDK_NOTE (EVENTS,
+               g_message ("focus in:\t\twindow: %ld", xevent->xfocus.window));
+      
+      if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
        {
-       case NotifyAncestor:
-       case NotifyInferior:
-       case NotifyNonlinear:
-         GDK_NOTE (EVENTS,
-                   g_message ("focus %s:\t\twindow: %ld",
-                              (xevent->xany.type == FocusIn) ? "in" : "out",
-                              xevent->xfocus.window));
+         gboolean had_focus = HAS_FOCUS (window_impl);
          
+         switch (xevent->xfocus.detail)
+           {
+           case NotifyAncestor:
+           case NotifyNonlinear:
+           case NotifyVirtual:
+           case NotifyNonlinearVirtual:
+             window_impl->has_focus = TRUE;
+             break;
+           case NotifyPointer:
+             window_impl->has_pointer_focus = TRUE;
+             break;
+           case NotifyInferior:
+           case NotifyPointerRoot:
+           case NotifyDetailNone:
+             break;
+           }
+
+         if (HAS_FOCUS (window_impl) != had_focus)
+           generate_focus_event (window, TRUE);
+       }
+      break;
+    case FocusOut:
+      GDK_NOTE (EVENTS,
+               g_message ("focus out:\t\twindow: %ld", xevent->xfocus.window));
+
+      if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
+       {
+         gboolean had_focus = HAS_FOCUS (window_impl);
+           
+         switch (xevent->xfocus.detail)
+           {
+           case NotifyAncestor:
+           case NotifyNonlinear:
+           case NotifyVirtual:
+           case NotifyNonlinearVirtual:
+             window_impl->has_focus = FALSE;
+             break;
+           case NotifyPointer:
+             window_impl->has_pointer_focus = FALSE;
+           break;
+           case NotifyInferior:
+           case NotifyPointerRoot:
+           case NotifyDetailNone:
+             break;
+           }
+
+         if (HAS_FOCUS (window_impl) != had_focus)
+           generate_focus_event (window, FALSE);
+       }
+      break;
+
+#if 0      
          /* gdk_keyboard_grab() causes following events. These events confuse
           * the XIM focus, so ignore them.
           */
          if (xevent->xfocus.mode == NotifyGrab ||
              xevent->xfocus.mode == NotifyUngrab)
            break;
-         
-         event->focus_change.type = GDK_FOCUS_CHANGE;
-         event->focus_change.window = window;
-         event->focus_change.in = (xevent->xany.type == FocusIn);
+#endif
 
-         break;
-       default:
-         return_val = FALSE;
-       }
-      break;
-      
     case KeymapNotify:
       GDK_NOTE (EVENTS,
                g_message ("keymap notify"));
@@ -803,6 +1029,7 @@ gdk_event_translate (GdkEvent *event,
          {
            event->expose.type = GDK_EXPOSE;
            event->expose.area = expose_rect;
+           event->expose.region = gdk_region_rectangle (&expose_rect);
            event->expose.window = window;
            event->expose.count = xevent->xexpose.count;
 
@@ -837,6 +1064,7 @@ gdk_event_translate (GdkEvent *event,
          {
            event->expose.type = GDK_EXPOSE;
            event->expose.area = expose_rect;
+           event->expose.region = gdk_region_rectangle (&expose_rect);
            event->expose.window = window;
            event->expose.count = xevent->xgraphicsexpose.count;
 
@@ -936,7 +1164,17 @@ gdk_event_translate (GdkEvent *event,
                           xevent->xmap.window));
       
       event->any.type = GDK_UNMAP;
-      event->any.window = window;
+      event->any.window = window;      
+
+      /* If we are shown (not withdrawn) and get an unmap, it means we
+       * were iconified in the X sense. If we are withdrawn, and get
+       * an unmap, it means we hid the window ourselves, so we
+       * will have already flipped the iconified bit off.
+       */
+      if (window && 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;
@@ -950,6 +1188,12 @@ gdk_event_translate (GdkEvent *event,
       
       event->any.type = GDK_MAP;
       event->any.window = window;
+
+      /* Unset iconified if it was set */
+      if (window && (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED))
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_ICONIFIED,
+                                     0);
       
       break;
       
@@ -1030,8 +1274,14 @@ gdk_event_translate (GdkEvent *event,
          window_private->y = event->configure.y;
          GDK_WINDOW_IMPL_X11 (window_private->impl)->width = xevent->xconfigure.width;
          GDK_WINDOW_IMPL_X11 (window_private->impl)->height = xevent->xconfigure.height;
-         if (window_private->resize_count > 1)
-           window_private->resize_count -= 1;
+         if (window_private->resize_count >= 1)
+           {
+             window_private->resize_count -= 1;
+
+             if (window_private->resize_count == 0 &&
+                 window == _gdk_moveresize_window)
+               _gdk_moveresize_configure_done ();
+           }
        }
       break;
       
@@ -1052,6 +1302,19 @@ gdk_event_translate (GdkEvent *event,
       event->property.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_atom_intern ("_NET_WM_STATE", FALSE);
+
+      if (wm_desktop_atom == 0)
+        wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
+      
+      if (event->property.atom == wm_state_atom ||
+          event->property.atom == wm_desktop_atom)
+        {
+          /* If window state changed, then synthesize those events. */
+          gdk_check_wm_state_changed (event->property.window);
+        }
       
       break;
       
@@ -1161,8 +1424,16 @@ gdk_event_translate (GdkEvent *event,
       /* Let XLib know that there is a new keyboard mapping.
        */
       XRefreshKeyboardMapping (&xevent->xmapping);
+      ++_gdk_keymap_serial;
       return_val = FALSE;
       break;
+
+#ifdef HAVE_XKB
+    case XkbMapNotify:
+      ++_gdk_keymap_serial;
+      return_val = FALSE;
+      break;
+#endif
       
     default:
       /* something else - (e.g., a Xinput event) */
@@ -1227,6 +1498,19 @@ gdk_wm_protocols_filter (GdkXEvent *xev,
     }
   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
     {
+      GdkWindow *win = event->any.window;
+      Window focus_win = GDK_WINDOW_IMPL_X11(((GdkWindowObject *)win)->impl)->focus_window;
+
+      /* There is no way of knowing reliably whether we are viewable so we need
+       * to trap errors so we don't cause a BadMatch.
+       */
+      gdk_error_trap_push ();
+      XSetInputFocus (GDK_WINDOW_XDISPLAY (win),
+                     focus_win,
+                     RevertToParent,
+                     xevent->xclient.data.l[1]);
+      XSync (GDK_WINDOW_XDISPLAY (win), False);
+      gdk_error_trap_pop ();
     }
   else if ((Atom) xevent->xclient.data.l[0] == gdk_atom_intern ("_NET_WM_PING", FALSE))
     {
@@ -1267,26 +1551,17 @@ gdk_events_queue (void)
 
   while (!gdk_event_queue_find_first() && XPending (gdk_display))
     {
-#ifdef USE_XIM
-      Window w = None;
-      
       XNextEvent (gdk_display, &xevent);
-      if (gdk_xim_window)
-       switch (xevent.type)
-         {
-         case KeyPress:
-         case KeyRelease:
-         case ButtonPress:
-         case ButtonRelease:
-           w = GDK_WINDOW_XWINDOW (gdk_xim_window);
-           break;
-         }
-      
-      if (XFilterEvent (&xevent, w))
-       continue;
-#else
-      XNextEvent (gdk_display, &xevent);
-#endif
+
+      switch (xevent.type)
+       {
+       case KeyPress:
+       case KeyRelease:
+         break;
+       default:
+         if (XFilterEvent (&xevent, None))
+           continue;
+       }
       
       event = gdk_event_new ();
       
@@ -1313,10 +1588,8 @@ gdk_events_queue (void)
 }
 
 static gboolean  
-gdk_event_prepare (gpointer  source_data, 
-                  GTimeVal *current_time,
-                  gint     *timeout,
-                  gpointer  user_data)
+gdk_event_prepare (GSource  *source,
+                  gint     *timeout)
 {
   gboolean retval;
   
@@ -1332,9 +1605,7 @@ gdk_event_prepare (gpointer  source_data,
 }
 
 static gboolean  
-gdk_event_check (gpointer  source_data,
-                GTimeVal *current_time,
-                gpointer  user_data)
+gdk_event_check (GSource  *source) 
 {
   gboolean retval;
   
@@ -1351,9 +1622,9 @@ gdk_event_check (gpointer  source_data,
 }
 
 static gboolean  
-gdk_event_dispatch (gpointer  source_data,
-                   GTimeVal *current_time,
-                   gpointer  user_data)
+gdk_event_dispatch (GSource    *source,
+                   GSourceFunc callback,
+                   gpointer    user_data)
 {
   GdkEvent *event;
  
@@ -1560,3 +1831,263 @@ gdk_x11_get_server_time (GdkWindow *window)
   return xevent.xproperty.time;
 }
 
+
+gboolean
+gdk_net_wm_supports (GdkAtom property)
+{
+  static GdkAtom wmspec_check_atom = 0;
+  static GdkAtom wmspec_supported_atom = 0;
+  static GdkAtom *atoms = NULL;
+  static gulong n_atoms = 0;
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  Window *xwindow;
+  gulong i;
+
+  if (wmspec_check_window != None)
+    {
+      if (atoms == NULL)
+        return FALSE;
+
+      i = 0;
+      while (i < n_atoms)
+        {
+          if (atoms[i] == property)
+            return TRUE;
+          
+          ++i;
+        }
+
+      return FALSE;
+    }
+
+  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_atom_intern ("_NET_SUPPORTING_WM_CHECK", FALSE);
+      
+  if (wmspec_supported_atom == 0)
+    wmspec_supported_atom = gdk_atom_intern ("_NET_SUPPORTED", FALSE);
+  
+  XGetWindowProperty (gdk_display, gdk_root_window,
+                     wmspec_check_atom, 0, G_MAXLONG,
+                     False, XA_WINDOW, &type, &format, &nitems,
+                     &bytes_after, (guchar **)&xwindow);
+
+  if (type != XA_WINDOW)
+    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 ())
+    {
+      XFree (xwindow);
+      return FALSE;
+    }
+
+  XGetWindowProperty (gdk_display, gdk_root_window,
+                     wmspec_supported_atom, 0, G_MAXLONG,
+                     False, XA_ATOM, &type, &format, &n_atoms,
+                     &bytes_after, (guchar **)&atoms);
+  
+  if (type != XA_ATOM)
+    return FALSE;
+  
+  wmspec_check_window = *xwindow;
+  XFree (xwindow);
+  
+  /* since wmspec_check_window != None this isn't infinite. ;-) */
+  return gdk_net_wm_supports (property);
+}
+
+static struct
+{
+  const char *xsettings_name;
+  const char *gdk_name;
+} settings_map[] = {
+  { "Net/DoubleClickTime", "gtk-double-click-timeout" },
+  { "Net/DragThreshold", "gtk-drag-threshold" },
+  { "Gtk/ColorPalette", "gtk-color-palette" },
+  { "Gtk/ToolbarStyle", "gtk-toolbar-style" },
+  { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
+  { "Net/CursorBlink", "gtk-cursor-blink" },
+  { "Net/CursorBlinkTime", "gtk-cursor-blink-time" }
+};
+
+static void
+gdk_xsettings_notify_cb (const char       *name,
+                        XSettingsAction   action,
+                        XSettingsSetting *setting,
+                        void             *data)
+{
+  GdkEvent new_event;
+  int i;
+
+  new_event.type = GDK_SETTING;
+  new_event.setting.window = NULL;
+  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);
+       break;
+      }
+
+  if (!new_event.setting.name)
+    return;
+  
+  switch (action)
+    {
+    case XSETTINGS_ACTION_NEW:
+      new_event.setting.action = GDK_SETTING_ACTION_NEW;
+      break;
+    case XSETTINGS_ACTION_CHANGED:
+      new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
+      break;
+    case XSETTINGS_ACTION_DELETED:
+      new_event.setting.action = GDK_SETTING_ACTION_DELETED;
+      break;
+    }
+
+  gdk_event_put (&new_event);
+}
+
+static gboolean
+check_transform (const gchar *xsettings_name,
+                GType        src_type,
+                GType        dest_type)
+{
+  if (!g_value_type_transformable (src_type, dest_type))
+    {
+      g_warning ("Cannot tranform xsetting %s of type %s to type %s\n",
+                xsettings_name,
+                g_type_name (src_type),
+                g_type_name (dest_type));
+      return FALSE;
+    }
+  else
+    return TRUE;
+}
+
+gboolean
+gdk_setting_get (const gchar *name,
+                GValue      *value)
+{
+  const char *xsettings_name = NULL;
+  XSettingsResult result;
+  XSettingsSetting *setting;
+  gboolean success = FALSE;
+  gint i;
+  GValue tmp_val = { 0, };
+
+  for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
+    if (strcmp (settings_map[i].gdk_name, name) == 0)
+      {
+       xsettings_name = settings_map[i].xsettings_name;
+       break;
+      }
+
+  if (!xsettings_name)
+    return FALSE;
+
+  result = xsettings_client_get_setting (xsettings_client, xsettings_name, &setting);
+  if (result != XSETTINGS_SUCCESS)
+    return FALSE;
+
+  switch (setting->type)
+    {
+    case XSETTINGS_TYPE_INT:
+      if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
+       {
+         g_value_init (&tmp_val, G_TYPE_INT);
+         g_value_set_int (&tmp_val, setting->data.v_int);
+         g_value_transform (&tmp_val, value);
+
+         success = TRUE;
+       }
+      break;
+    case XSETTINGS_TYPE_STRING:
+      if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
+       {
+         g_value_init (&tmp_val, G_TYPE_STRING);
+         g_value_set_string (&tmp_val, setting->data.v_string);
+         g_value_transform (&tmp_val, value);
+
+         success = TRUE;
+       }
+      break;
+    case XSETTINGS_TYPE_COLOR:
+      if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
+       {
+         GdkColor color;
+         
+         g_value_init (&tmp_val, GDK_TYPE_COLOR);
+
+         color.pixel = 0;
+         color.red = setting->data.v_color.red;
+         color.green = setting->data.v_color.green;
+         color.blue = setting->data.v_color.blue;
+         
+         g_value_set_boxed (&tmp_val, &color);
+         
+         g_value_transform (&tmp_val, value);
+         
+         success = TRUE;
+       }
+      break;
+    }
+  
+  g_value_unset (&tmp_val);
+
+  xsettings_setting_free (setting);
+
+  return success;
+}
+
+GdkFilterReturn 
+gdk_xsettings_client_event_filter (GdkXEvent *xevent,
+                                  GdkEvent  *event,
+                                  gpointer   data)
+{
+  if (xsettings_client_process_event (xsettings_client, (XEvent *)xevent))
+    return GDK_FILTER_REMOVE;
+  else
+    return GDK_FILTER_CONTINUE;
+}
+
+static void 
+gdk_xsettings_watch_cb (Window window,
+                       Bool   is_start,
+                       long   mask,
+                       void  *cb_data)
+{
+  GdkWindow *gdkwin;
+
+  gdkwin = gdk_window_lookup (window);
+  if (is_start)
+    gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
+  else
+    gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
+}