]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkevents-x11.c
Remove old XIM code.
[~andy/gtk] / gdk / x11 / gdkevents-x11.c
index e83b05086fa0b3c0258b849f42fff68976b26b57..90cbb60223e7d24a1419e1d0eae4f1e491dede9e 100644 (file)
@@ -2,25 +2,33 @@
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
 #include "gdk.h"
+#include "gdkprivate-x11.h"
+#include "gdkinternals.h"
 #include "gdkx.h"
-#include "gdkprivate.h"
-#include "gdkinput.h"
+
 #include "gdkkeysyms.h"
 
 #if HAVE_CONFIG_H
 #  endif
 #endif
 
+#include "gdkinputprivate.h"
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+#include <X11/Xatom.h>
 
 typedef struct _GdkIOClosure GdkIOClosure;
 typedef struct _GdkEventPrivate GdkEventPrivate;
@@ -39,21 +54,24 @@ typedef struct _GdkEventPrivate GdkEventPrivate;
 #define DOUBLE_CLICK_DIST      5
 #define TRIPLE_CLICK_DIST      5
 
-typedef enum {
+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 {
+struct _GdkIOClosure
+{
   GdkInputFunction function;
   GdkInputCondition condition;
   GdkDestroyNotify notify;
   gpointer data;
 };
 
-struct _GdkEventPrivate {
+struct _GdkEventPrivate
+{
   GdkEvent event;
   guint    flags;
 };
@@ -62,31 +80,24 @@ struct _GdkEventPrivate {
  * Private function declarations
  */
 
-static GdkEvent *gdk_event_new         (void);
-static gint     gdk_event_apply_filters (XEvent *xevent,
+static gint     gdk_event_apply_filters (XEvent   *xevent,
                                          GdkEvent *event,
-                                         GList *filters);
+                                         GList    *filters);
 static gint     gdk_event_translate     (GdkEvent *event, 
-                                         XEvent   *xevent);
+                                         XEvent   *xevent,
+                                         gboolean  return_exposes);
 #if 0
-static Bool     gdk_event_get_type     (Display      *display, 
-                                        XEvent       *xevent, 
-                                        XPointer      arg);
+static Bool     gdk_event_get_type     (Display   *display, 
+                                        XEvent    *xevent, 
+                                        XPointer   arg);
 #endif
-static void      gdk_events_queue       (void);
-static GdkEvent *gdk_event_unqueue      (void);
-
-static gboolean  gdk_event_prepare      (gpointer  source_data, 
-                                        GTimeVal *current_time,
-                                        gint     *timeout);
-static gboolean  gdk_event_check        (gpointer  source_data,
-                                        GTimeVal *current_time);
-static gboolean  gdk_event_dispatch     (gpointer  source_data,
-                                        GTimeVal *current_time,
-                                        gpointer  user_data);
 
-static void     gdk_synthesize_click   (GdkEvent     *event, 
-                                        gint          nclicks);
+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,
@@ -101,130 +112,42 @@ static int connection_number = 0;            /* The file descriptor number of our
                                             *  when events are pending by using
                                             *  the "select" system call.
                                             */
-static guint32 button_click_time[2];       /* The last 2 button click times. Used
-                                            *  to determine if the latest button click
-                                            *  is part of a double or triple click.
-                                            */
-static GdkWindow *button_window[2];        /* The last 2 windows to receive button presses.
-                                            *  Also used to determine if the latest button
-                                            *  click is part of a double or triple click.
-                                            */
-static guint button_number[2];             /* The last 2 buttons to be pressed.
-                                            */
-static GdkEventFunc   event_func;          /* Callback for events */
-static gpointer       event_data;
-static GDestroyNotify event_notify;
-
-static GList *client_filters;                      /* Filters for client messages */
-
-/* FIFO's for event queue, and for events put back using
- * gdk_event_put().
- */
-static GList *queued_events = NULL;
-static GList *queued_tail = NULL;
+static GList *client_filters;              /* Filters for client messages */
 
 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;
 
 /*********************************************
  * Functions for maintaining the event queue *
  *********************************************/
 
-/*************************************************************
- * gdk_event_queue_find_first:
- *     Find the first event on the queue that is not still
- *     being filled in.
- *   arguments:
- *     
- *   results:
- *     Pointer to the list node for that event, or NULL
- *************************************************************/
-
-static GList *
-gdk_event_queue_find_first (void)
-{
-  GList *tmp_list = queued_events;
-
-  while (tmp_list)
-    {
-      GdkEventPrivate *event = tmp_list->data;
-      if (!(event->flags & GDK_EVENT_PENDING))
-       return tmp_list;
-
-      tmp_list = g_list_next (tmp_list);
-    }
-
-  return NULL;
-}
-
-/*************************************************************
- * gdk_event_queue_remove_link:
- *     Remove a specified list node from the event queue.
- *   arguments:
- *     node: Node to remove.
- *   results:
- *************************************************************/
-
-static void
-gdk_event_queue_remove_link (GList *node)
-{
-  if (node->prev)
-    node->prev->next = node->next;
-  else
-    queued_events = node->next;
-  
-  if (node->next)
-    node->next->prev = node->prev;
-  else
-    queued_tail = node->prev;
-  
-}
-
-/*************************************************************
- * gdk_event_queue_append:
- *     Append an event onto the tail of the event queue.
- *   arguments:
- *     event: Event to append.
- *   results:
- *************************************************************/
-
-static void
-gdk_event_queue_append (GdkEvent *event)
-{
-  queued_tail = g_list_append(queued_tail, event);
-  
-  if (!queued_events)
-    queued_events = queued_tail;
-  else
-    queued_tail = queued_tail->next;
-}
-
 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);
-
-  button_click_time[0] = 0;
-  button_click_time[1] = 0;
-  button_window[0] = NULL;
-  button_window[1] = NULL;
-  button_number[0] = -1;
-  button_number[1] = -1;
+  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);
@@ -269,23 +192,19 @@ gdk_events_pending (void)
  *-------------------------------------------------------------- */
 
 static Bool
-graphics_expose_predicate  (Display  *display,
-                           XEvent   *xevent,
-                           XPointer  arg)
+graphics_expose_predicate (Display  *display,
+                          XEvent   *xevent,
+                          XPointer  arg)
 {
-  GdkWindowPrivate *private = (GdkWindowPrivate *)arg;
-  
-  g_return_val_if_fail (private != NULL, False);
-  
-  if ((xevent->xany.window == private->xwindow) &&
-      ((xevent->xany.type == GraphicsExpose) ||
-       (xevent->xany.type == NoExpose)))
+  if (xevent->xany.window == GDK_DRAWABLE_XID (arg) &&
+      (xevent->xany.type == GraphicsExpose ||
+       xevent->xany.type == NoExpose))
     return True;
   else
     return False;
 }
 
-GdkEvent *
+GdkEvent*
 gdk_event_get_graphics_expose (GdkWindow *window)
 {
   XEvent xevent;
@@ -293,13 +212,13 @@ 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_display, &xevent, graphics_expose_predicate, (XPointer) window);
   
   if (xevent.xany.type == GraphicsExpose)
     {
       event = gdk_event_new ();
       
-      if (gdk_event_translate (event, &xevent))
+      if (gdk_event_translate (event, &xevent, TRUE))
        return event;
       else
        gdk_event_free (event);
@@ -308,609 +227,11 @@ gdk_event_get_graphics_expose (GdkWindow *window)
   return NULL; 
 }
 
-/************************
- * Exposure compression *
- ************************/
-
-/*
- * The following implements simple exposure compression. It is
- * modelled after the way Xt does exposure compression - in
- * particular compress_expose = XtExposeCompressMultiple.
- * It compress consecutive sequences of exposure events,
- * but not sequences that cross other events. (This is because
- * if it crosses a ConfigureNotify, we could screw up and
- * mistakenly compress the exposures generated for the new
- * size - could we just check for ConfigureNotify?)
- *
- * Xt compresses to a region / bounding rectangle, we compress
- * to two rectangles, and try find the two rectangles of minimal
- * area for this - this is supposed to handle the typical
- * L-shaped regions generated by OpaqueMove.
- */
-
-/* Given three rectangles, find the two rectangles that cover
- * them with the smallest area.
- */
-static void
-gdk_add_rect_to_rects (GdkRectangle *rect1,
-                      GdkRectangle *rect2, 
-                      GdkRectangle *new_rect)
-{
-  GdkRectangle t1, t2, t3;
-  gint size1, size2, size3;
-
-  gdk_rectangle_union (rect1, rect2, &t1);
-  gdk_rectangle_union (rect1, new_rect, &t2);
-  gdk_rectangle_union (rect2, new_rect, &t3);
-
-  size1 = t1.width * t1.height + new_rect->width * new_rect->height;
-  size2 = t2.width * t2.height + rect2->width * rect2->height;
-  size3 = t1.width * t1.height + rect1->width * rect1->height;
-
-  if (size1 < size2)
-    {
-      if (size1 < size3)
-       {
-         *rect1 = t1;
-         *rect2 = *new_rect;
-       }
-      else
-       *rect2 = t3;
-    }
-  else
-    {
-      if (size2 < size3)
-       *rect1 = t2;
-      else
-       *rect2 = t3;
-    }
-}
-
-typedef struct _GdkExposeInfo GdkExposeInfo;
-
-struct _GdkExposeInfo {
-  Window window;
-  gboolean seen_nonmatching;
-};
-
-Bool
-expose_predicate (Display *display, XEvent *xevent, XPointer arg)
-{
-  GdkExposeInfo *info = (GdkExposeInfo *)arg;
-
-  /* Compressing across GravityNotify events is safe, because
-   * we completely ignore them, so they can't change what
-   * we are going to draw. Compressing across GravityNotify
-   * events is necessay because during window-unshading animation
-   * we'll get a whole bunch of them interspersed with
-   * expose events.
-   */
-  if ((xevent->xany.type != Expose) && 
-      (xevent->xany.type != GravityNotify))
-    {
-      info->seen_nonmatching = TRUE;
-    }
-
-  if (info->seen_nonmatching ||
-      (xevent->xany.type != Expose) ||
-      (xevent->xany.window != info->window))
-    return FALSE;
-  else
-    return TRUE;
-}
-
-void
-gdk_compress_exposures (XEvent *xevent, GdkWindow *window)
-{
-  gint nrects = 1;
-  gint count = 0;
-  GdkRectangle rect1;
-  GdkRectangle rect2;
-  GdkRectangle tmp_rect;
-  XEvent tmp_event;
-  GdkFilterReturn result;
-  GdkExposeInfo info;
-  GdkEvent event;
-
-  info.window = xevent->xany.window;
-  info.seen_nonmatching = FALSE;
-  
-  rect1.x = xevent->xexpose.x;
-  rect1.y = xevent->xexpose.y;
-  rect1.width = xevent->xexpose.width;
-  rect1.height = xevent->xexpose.height;
-
-  while (1)
-    {
-      if (count == 0)
-       {
-         if (!XCheckIfEvent (gdk_display, 
-                             &tmp_event, 
-                             expose_predicate, 
-                             (XPointer)&info))
-           break;
-       }
-      else
-       XIfEvent (gdk_display, 
-                 &tmp_event, 
-                 expose_predicate, 
-                 (XPointer)&info);
-      
-      /* We apply filters here, and if it was filtered, completely
-       * ignore the return
-       */
-      result = gdk_event_apply_filters (xevent, &event,
-                                       window ? 
-                                         ((GdkWindowPrivate *)window)->filters
-                                         : gdk_default_filters);
-      
-      if (result != GDK_FILTER_CONTINUE)
-       {
-         if (result == GDK_FILTER_TRANSLATE)
-           gdk_event_put (&event);
-         continue;
-       }
-
-      if (nrects == 1)
-       {
-         rect2.x = tmp_event.xexpose.x;
-         rect2.y = tmp_event.xexpose.y;
-         rect2.width = tmp_event.xexpose.width;
-         rect2.height = tmp_event.xexpose.height;
-
-         nrects++;
-       }
-      else
-       {
-         tmp_rect.x = tmp_event.xexpose.x;
-         tmp_rect.y = tmp_event.xexpose.y;
-         tmp_rect.width = tmp_event.xexpose.width;
-         tmp_rect.height = tmp_event.xexpose.height;
-
-         gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect);
-       }
-
-      count = tmp_event.xexpose.count;
-    }
-
-  if (nrects == 2)
-    {
-      gdk_rectangle_union (&rect1, &rect2, &tmp_rect);
-
-      if ((tmp_rect.width * tmp_rect.height) <
-         2 * (rect1.height * rect1.width +
-              rect2.height * rect2.width))
-       {
-         rect1 = tmp_rect;
-         nrects = 1;
-       }
-    }
-
-  if (nrects == 2)
-    {
-      event.expose.type = GDK_EXPOSE;
-      event.expose.window = window;
-      event.expose.area.x = rect2.x;
-      event.expose.area.y = rect2.y;
-      event.expose.area.width = rect2.width;
-      event.expose.area.height = rect2.height;
-      event.expose.count = 0;
-
-      gdk_event_put (&event);
-    }
-
-  xevent->xexpose.count = nrects - 1;
-  xevent->xexpose.x = rect1.x;
-  xevent->xexpose.y = rect1.y;
-  xevent->xexpose.width = rect1.width;
-  xevent->xexpose.height = rect1.height;
-}
-
-/*************************************************************
- * gdk_event_handler_set:
- *     
- *   arguments:
- *     func: Callback function to be called for each event.
- *     data: Data supplied to the function
- *     notify: function called when function is no longer needed
- * 
- *   results:
- *************************************************************/
-
-void 
-gdk_event_handler_set (GdkEventFunc   func,
-                      gpointer       data,
-                      GDestroyNotify notify)
-{
-  if (event_func && event_notify)
-    (*event_notify) (event_data);
-
-  event_func = func;
-  event_data = data;
-  event_notify = notify;
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_event_get
- *
- *   Gets the next event.
- *
- * Arguments:
- *
- * Results:
- *   If an event is waiting that we care about, returns 
- *   a pointer to that event, to be freed with gdk_event_free.
- *   Otherwise, returns NULL.
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
-
-GdkEvent *
-gdk_event_get (void)
-{
-  gdk_events_queue();
-
-  return gdk_event_unqueue();
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_event_peek
- *
- *   Gets the next event.
- *
- * Arguments:
- *
- * Results:
- *   If an event is waiting that we care about, returns 
- *   a copy of that event, but does not remove it from
- *   the queue. The pointer is to be freed with gdk_event_free.
- *   Otherwise, returns NULL.
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
-
-GdkEvent *
-gdk_event_peek (void)
-{
-  GList *tmp_list;
-
-  tmp_list = gdk_event_queue_find_first ();
-  
-  if (tmp_list)
-    return gdk_event_copy (tmp_list->data);
-  else
-    return NULL;
-}
-
-void
-gdk_event_put (GdkEvent *event)
-{
-  GdkEvent *new_event;
-  
-  g_return_if_fail (event != NULL);
-  
-  new_event = gdk_event_copy (event);
-
-  gdk_event_queue_append (new_event);
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_event_copy
- *
- *   Copy a event structure into new storage.
- *
- * Arguments:
- *   "event" is the event struct to copy.
- *
- * Results:
- *   A new event structure.  Free it with gdk_event_free.
- *
- * Side effects:
- *   The reference count of the window in the event is increased.
- *
- *--------------------------------------------------------------
- */
-
-static GMemChunk *event_chunk;
-
-static GdkEvent*
-gdk_event_new (void)
-{
-  GdkEventPrivate *new_event;
-  
-  if (event_chunk == NULL)
-    event_chunk = g_mem_chunk_new ("events",
-                                  sizeof (GdkEventPrivate),
-                                  4096,
-                                  G_ALLOC_AND_FREE);
-  
-  new_event = g_chunk_new (GdkEventPrivate, event_chunk);
-  new_event->flags = 0;
-  
-  return (GdkEvent *)new_event;
-}
-
-GdkEvent*
-gdk_event_copy (GdkEvent *event)
-{
-  GdkEvent *new_event;
-  
-  g_return_val_if_fail (event != NULL, NULL);
-  
-  new_event = gdk_event_new ();
-  
-  *new_event = *event;
-  gdk_window_ref (new_event->any.window);
-  
-  switch (event->any.type)
-    {
-    case GDK_KEY_PRESS:
-    case GDK_KEY_RELEASE:
-      new_event->key.string = g_strdup (event->key.string);
-      break;
-      
-    case GDK_ENTER_NOTIFY:
-    case GDK_LEAVE_NOTIFY:
-      if (event->crossing.subwindow != NULL)
-       gdk_window_ref (event->crossing.subwindow);
-      break;
-      
-    case GDK_DRAG_ENTER:
-    case GDK_DRAG_LEAVE:
-    case GDK_DRAG_MOTION:
-    case GDK_DRAG_STATUS:
-    case GDK_DROP_START:
-    case GDK_DROP_FINISHED:
-      gdk_drag_context_ref (event->dnd.context);
-      break;
-
-      
-    default:
-      break;
-    }
-  
-  return new_event;
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_event_free
- *
- *   Free a event structure obtained from gdk_event_copy.  Do not use
- *   with other event structures.
- *
- * Arguments:
- *   "event" is the event struct to free.
- *
- * Results:
- *
- * Side effects:
- *   The reference count of the window in the event is decreased and
- *   might be freed, too.
- *
- *-------------------------------------------------------------- */
-
-void
-gdk_event_free (GdkEvent *event)
-{
-  g_assert (event_chunk != NULL);
-  g_return_if_fail (event != NULL);
-  
-  if (event->any.window)
-    gdk_window_unref (event->any.window);
-  
-  switch (event->any.type)
-    {
-    case GDK_KEY_PRESS:
-    case GDK_KEY_RELEASE:
-      g_free (event->key.string);
-      break;
-      
-    case GDK_ENTER_NOTIFY:
-    case GDK_LEAVE_NOTIFY:
-      if (event->crossing.subwindow != NULL)
-       gdk_window_unref (event->crossing.subwindow);
-      break;
-      
-    case GDK_DRAG_ENTER:
-    case GDK_DRAG_LEAVE:
-    case GDK_DRAG_MOTION:
-    case GDK_DRAG_STATUS:
-    case GDK_DROP_START:
-    case GDK_DROP_FINISHED:
-      gdk_drag_context_unref (event->dnd.context);
-      break;
-
-      
-    default:
-      break;
-    }
-  
-  g_mem_chunk_free (event_chunk, event);
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_event_get_time:
- *    Get the timestamp from an event.
- *   arguments:
- *     event:
- *   results:
- *    The event's time stamp, if it has one, otherwise
- *    GDK_CURRENT_TIME.
- *--------------------------------------------------------------
- */
-
-guint32
-gdk_event_get_time (GdkEvent *event)
-{
-  if (event)
-    switch (event->type)
-      {
-      case GDK_MOTION_NOTIFY:
-       return event->motion.time;
-      case GDK_BUTTON_PRESS:
-      case GDK_2BUTTON_PRESS:
-      case GDK_3BUTTON_PRESS:
-      case GDK_BUTTON_RELEASE:
-       return event->button.time;
-      case GDK_KEY_PRESS:
-      case GDK_KEY_RELEASE:
-       return event->key.time;
-      case GDK_ENTER_NOTIFY:
-      case GDK_LEAVE_NOTIFY:
-       return event->crossing.time;
-      case GDK_PROPERTY_NOTIFY:
-       return event->property.time;
-      case GDK_SELECTION_CLEAR:
-      case GDK_SELECTION_REQUEST:
-      case GDK_SELECTION_NOTIFY:
-       return event->selection.time;
-      case GDK_PROXIMITY_IN:
-      case GDK_PROXIMITY_OUT:
-       return event->proximity.time;
-      case GDK_DRAG_ENTER:
-      case GDK_DRAG_LEAVE:
-      case GDK_DRAG_MOTION:
-      case GDK_DRAG_STATUS:
-      case GDK_DROP_START:
-      case GDK_DROP_FINISHED:
-       return event->dnd.time;
-      default:                 /* use current time */
-       break;
-      }
-  
-  return GDK_CURRENT_TIME;
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_set_show_events
- *
- *   Turns on/off the showing of events.
- *
- * Arguments:
- *   "show_events" is a boolean describing whether or
- *   not to show the events gdk receives.
- *
- * Results:
- *
- * Side effects:
- *   When "show_events" is TRUE, calls to "gdk_event_get"
- *   will output debugging informatin regarding the event
- *   received to stdout.
- *
- *--------------------------------------------------------------
- */
-
-void
-gdk_set_show_events (int show_events)
-{
-  if (show_events)
-    gdk_debug_flags |= GDK_DEBUG_EVENTS;
-  else
-    gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
-}
-
-gint
-gdk_get_show_events (void)
-{
-  return gdk_debug_flags & GDK_DEBUG_EVENTS;
-}
-
-static void
-gdk_io_destroy (gpointer data)
-{
-  GdkIOClosure *closure = data;
-
-  if (closure->notify)
-    closure->notify (closure->data);
-
-  g_free (closure);
-}
-
-static gboolean  
-gdk_io_invoke (GIOChannel   *source,
-              GIOCondition  condition,
-              gpointer      data)
-{
-  GdkIOClosure *closure = data;
-  GdkInputCondition gdk_cond = 0;
-
-  if (condition & (G_IO_IN | G_IO_PRI))
-    gdk_cond |= GDK_INPUT_READ;
-  if (condition & G_IO_OUT)
-    gdk_cond |= GDK_INPUT_WRITE;
-  if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
-    gdk_cond |= GDK_INPUT_EXCEPTION;
-
-  if (closure->condition & gdk_cond)
-    closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
-
-  return TRUE;
-}
-
-gint
-gdk_input_add_full (gint             source,
-                   GdkInputCondition condition,
-                   GdkInputFunction  function,
-                   gpointer          data,
-                   GdkDestroyNotify  destroy)
-{
-  guint result;
-  GdkIOClosure *closure = g_new (GdkIOClosure, 1);
-  GIOChannel *channel;
-  GIOCondition cond = 0;
-
-  closure->function = function;
-  closure->condition = condition;
-  closure->notify = destroy;
-  closure->data = data;
-
-  if (condition & GDK_INPUT_READ)
-    cond |= (G_IO_IN | G_IO_PRI);
-  if (condition & GDK_INPUT_WRITE)
-    cond |= G_IO_OUT;
-  if (condition & GDK_INPUT_EXCEPTION)
-    cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL;
-
-  channel = g_io_channel_unix_new (source);
-  result = g_io_add_watch_full   (channel, G_PRIORITY_DEFAULT, cond, 
-                                 gdk_io_invoke,
-                                 closure, gdk_io_destroy);
-  g_io_channel_unref (channel);
-
-  return result;
-}
-
-gint
-gdk_input_add (gint             source,
-              GdkInputCondition condition,
-              GdkInputFunction  function,
-              gpointer          data)
-{
-  return gdk_input_add_full (source, condition, function, data, NULL);
-}
-
-void
-gdk_input_remove (gint tag)
-{
-  g_source_remove (tag);
-}
-
 static gint
 gdk_event_apply_filters (XEvent *xevent,
                         GdkEvent *event,
                         GList *filters)
 {
-  GdkEventFilter *filter;
   GList *tmp_list;
   GdkFilterReturn result;
   
@@ -918,13 +239,12 @@ gdk_event_apply_filters (XEvent *xevent,
   
   while (tmp_list)
     {
-      filter = (GdkEventFilter *)tmp_list->data;
+      GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
       
-      result = (*filter->function)(xevent, event, filter->data);
+      tmp_list = tmp_list->next;
+      result = filter->function (xevent, event, filter->data);
       if (result !=  GDK_FILTER_CONTINUE)
        return result;
-      
-      tmp_list = tmp_list->next;
     }
   
   return GDK_FILTER_CONTINUE;
@@ -944,23 +264,142 @@ 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);
+    }
+}
+
 static gint
 gdk_event_translate (GdkEvent *event,
-                    XEvent   *xevent)
+                    XEvent   *xevent,
+                    gboolean  return_exposes)
 {
   
   GdkWindow *window;
-  GdkWindowPrivate *window_private;
+  GdkWindowObject *window_private;
   static XComposeStatus compose;
   KeySym keysym;
   int charcount;
-#ifdef USE_XIM
-  static gchar* buf = NULL;
-  static gint buf_len= 0;
-#else
   char buf[16];
-#endif
   gint return_val;
+  gint xoffset, yoffset;
   
   return_val = FALSE;
   
@@ -971,10 +410,9 @@ gdk_event_translate (GdkEvent *event,
    *  some circumstances.
    */
   
-  if ((xevent->xany.window == None) &&
-      gdk_input_vtable.window_none_event)
+  if (xevent->xany.window == None)
     {
-      return_val = gdk_input_vtable.window_none_event (event,xevent);
+      return_val = _gdk_input_window_none_event (event, xevent);
       
       if (return_val >= 0)     /* was handled */
        return return_val;
@@ -983,18 +421,33 @@ gdk_event_translate (GdkEvent *event,
     }
   
   window = gdk_window_lookup (xevent->xany.window);
-  window_private = (GdkWindowPrivate *) window;
+  /* FIXME: window might be a GdkPixmap!!! */
+  
+  window_private = (GdkWindowObject *) window;
   
   if (window != NULL)
     gdk_window_ref (window);
+
+  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;
+    }
   
   event->any.window = window;
-  event->any.send_event = xevent->xany.send_event;
+  event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
   
-  if (window_private && window_private->destroyed)
+  if (window_private && GDK_WINDOW_DESTROYED (window))
     {
       if (xevent->type != DestroyNotify)
-       return FALSE;
+        return FALSE;
     }
   else
     {
@@ -1008,45 +461,11 @@ gdk_event_translate (GdkEvent *event,
       
       if (result != GDK_FILTER_CONTINUE)
        {
-         return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+         return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+         goto done;
        }
     }
 
-#ifdef USE_XIM
-  if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
-      !((GdkWindowPrivate *) gdk_xim_window)->destroyed)
-    {
-      /*
-       * 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 = (GdkWindowPrivate *) window;
-      gdk_window_ref (window);
-      event->any.window = window;
-
-      GDK_NOTE (XIM,
-       g_message ("KeyPress event is redirected to xim_window: %#lx",
-                  xevent->xany.window));
-
-      result = gdk_event_apply_filters (xevent, event,
-                                       window_private->filters);
-      if (result != GDK_FILTER_CONTINUE)
-       return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
-    }
-#endif
-
-  if (window == NULL)
-    g_message ("Got event for unknown window: %#lx\n", xevent->xany.window);
-
   /* 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
@@ -1056,64 +475,32 @@ gdk_event_translate (GdkEvent *event,
 
   return_val = TRUE;
 
+  if (window)
+    {
+      _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
+    }
+  else
+    {
+      xoffset = 0;
+      yoffset = 0;
+    }
+
   switch (xevent->type)
     {
     case KeyPress:
       /* Lookup the string corresponding to the given keysym.
        */
-      
-#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 --;
       else
        buf[charcount] = '\0';
       
-      /* Print debugging info. */
-      
 #ifdef G_ENABLE_DEBUG
       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
        {
@@ -1126,6 +513,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;
@@ -1133,26 +524,37 @@ 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);
       event->key.keyval = keysym;      
       
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS, 
                g_message ("key release:\t\twindow: %ld  key: %12s  %d",
                           xevent->xkey.window,
@@ -1169,8 +571,6 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case ButtonPress:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS, 
                g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
                           xevent->xbutton.window,
@@ -1185,62 +585,42 @@ gdk_event_translate (GdkEvent *event,
          break;
        }
       
-      event->button.type = GDK_BUTTON_PRESS;
-      event->button.window = window;
-      event->button.time = xevent->xbutton.time;
-      event->button.x = xevent->xbutton.x;
-      event->button.y = xevent->xbutton.y;
-      event->button.x_root = (gfloat)xevent->xbutton.x_root;
-      event->button.y_root = (gfloat)xevent->xbutton.y_root;
-      event->button.pressure = 0.5;
-      event->button.xtilt = 0;
-      event->button.ytilt = 0;
-      event->button.state = (GdkModifierType) xevent->xbutton.state;
-      event->button.button = xevent->xbutton.button;
-      event->button.source = GDK_SOURCE_MOUSE;
-      event->button.deviceid = GDK_CORE_POINTER;
-      
-      if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
-         (event->button.window == button_window[1]) &&
-         (event->button.button == button_number[1]))
-       {
-         gdk_synthesize_click (event, 3);
-         
-         button_click_time[1] = 0;
-         button_click_time[0] = 0;
-         button_window[1] = NULL;
-         button_window[0] = 0;
-         button_number[1] = -1;
-         button_number[0] = -1;
-       }
-      else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
-              (event->button.window == button_window[0]) &&
-              (event->button.button == button_number[0]))
+      /* 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)
        {
-         gdk_synthesize_click (event, 2);
-         
-         button_click_time[1] = button_click_time[0];
-         button_click_time[0] = event->button.time;
-         button_window[1] = button_window[0];
-         button_window[0] = event->button.window;
-         button_number[1] = button_number[0];
-         button_number[0] = event->button.button;
+         event->scroll.type = GDK_SCROLL;
+         event->scroll.direction = (xevent->xbutton.button == 4) ? 
+           GDK_SCROLL_UP : GDK_SCROLL_DOWN;
+         event->scroll.window = window;
+         event->scroll.time = xevent->xbutton.x;
+         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;
        }
       else
        {
-         button_click_time[1] = 0;
-         button_click_time[0] = event->button.time;
-         button_window[1] = NULL;
-         button_window[0] = event->button.window;
-         button_number[1] = -1;
-         button_number[0] = event->button.button;
+         event->button.type = GDK_BUTTON_PRESS;
+         event->button.window = window;
+         event->button.time = xevent->xbutton.time;
+         event->button.x = xevent->xbutton.x + xoffset;
+         event->button.y = xevent->xbutton.y + yoffset;
+         event->button.x_root = (gfloat)xevent->xbutton.x_root;
+         event->button.y_root = (gfloat)xevent->xbutton.y_root;
+         event->button.axes = NULL;
+         event->button.state = (GdkModifierType) xevent->xbutton.state;
+         event->button.button = xevent->xbutton.button;
+         event->button.device = gdk_core_pointer;
+         
+         gdk_event_button_generate (event);
        }
 
       break;
       
     case ButtonRelease:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS, 
                g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
                           xevent->xbutton.window,
@@ -1255,26 +635,28 @@ gdk_event_translate (GdkEvent *event,
          break;
        }
       
+      /* We treat button presses as scroll wheel events, so ignore the release */
+      if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
+       {
+         return_val = FALSE;
+         break;
+       }
+
       event->button.type = GDK_BUTTON_RELEASE;
       event->button.window = window;
       event->button.time = xevent->xbutton.time;
-      event->button.x = xevent->xbutton.x;
-      event->button.y = xevent->xbutton.y;
+      event->button.x = xevent->xbutton.x + xoffset;
+      event->button.y = xevent->xbutton.y + yoffset;
       event->button.x_root = (gfloat)xevent->xbutton.x_root;
       event->button.y_root = (gfloat)xevent->xbutton.y_root;
-      event->button.pressure = 0.5;
-      event->button.xtilt = 0;
-      event->button.ytilt = 0;
+      event->button.axes = NULL;
       event->button.state = (GdkModifierType) xevent->xbutton.state;
       event->button.button = xevent->xbutton.button;
-      event->button.source = GDK_SOURCE_MOUSE;
-      event->button.deviceid = GDK_CORE_POINTER;
+      event->button.device = gdk_core_pointer;
       
       break;
       
     case MotionNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
                           xevent->xmotion.window,
@@ -1292,23 +674,18 @@ gdk_event_translate (GdkEvent *event,
       event->motion.type = GDK_MOTION_NOTIFY;
       event->motion.window = window;
       event->motion.time = xevent->xmotion.time;
-      event->motion.x = xevent->xmotion.x;
-      event->motion.y = xevent->xmotion.y;
+      event->motion.x = xevent->xmotion.x + xoffset;
+      event->motion.y = xevent->xmotion.y + yoffset;
       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
-      event->motion.pressure = 0.5;
-      event->motion.xtilt = 0;
-      event->motion.ytilt = 0;
+      event->motion.axes = NULL;
       event->motion.state = (GdkModifierType) xevent->xmotion.state;
       event->motion.is_hint = xevent->xmotion.is_hint;
-      event->motion.source = GDK_SOURCE_MOUSE;
-      event->motion.deviceid = GDK_CORE_POINTER;
+      event->motion.device = gdk_core_pointer;
       
       break;
       
     case EnterNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
                           xevent->xcrossing.window,
@@ -1317,10 +694,9 @@ gdk_event_translate (GdkEvent *event,
       
       /* Tell XInput stuff about it if appropriate */
       if (window_private &&
-         !window_private->destroyed &&
-         (window_private->extension_events != 0) &&
-         gdk_input_vtable.enter_event)
-       gdk_input_vtable.enter_event (&xevent->xcrossing, window);
+         !GDK_WINDOW_DESTROYED (window) &&
+         window_private->extension_events != 0)
+       _gdk_input_enter_event (&xevent->xcrossing, window);
       
       event->crossing.type = GDK_ENTER_NOTIFY;
       event->crossing.window = window;
@@ -1334,8 +710,8 @@ gdk_event_translate (GdkEvent *event,
        event->crossing.subwindow = NULL;
       
       event->crossing.time = xevent->xcrossing.time;
-      event->crossing.x = xevent->xcrossing.x;
-      event->crossing.y = xevent->xcrossing.y;
+      event->crossing.x = xevent->xcrossing.x + xoffset;
+      event->crossing.y = xevent->xcrossing.y + yoffset;
       event->crossing.x_root = xevent->xcrossing.x_root;
       event->crossing.y_root = xevent->xcrossing.y_root;
       
@@ -1384,8 +760,6 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case LeaveNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS, 
                g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
                           xevent->xcrossing.window,
@@ -1403,8 +777,8 @@ gdk_event_translate (GdkEvent *event,
        event->crossing.subwindow = NULL;
       
       event->crossing.time = xevent->xcrossing.time;
-      event->crossing.x = xevent->xcrossing.x;
-      event->crossing.y = xevent->xcrossing.y;
+      event->crossing.x = xevent->xcrossing.x + xoffset;
+      event->crossing.y = xevent->xcrossing.y + yoffset;
       event->crossing.x_root = xevent->xcrossing.x_root;
       event->crossing.y_root = xevent->xcrossing.y_root;
       
@@ -1462,8 +836,6 @@ gdk_event_translate (GdkEvent *event,
        case NotifyAncestor:
        case NotifyInferior:
        case NotifyNonlinear:
-         /* Print debugging info.
-          */
          GDK_NOTE (EVENTS,
                    g_message ("focus %s:\t\twindow: %ld",
                               (xevent->xany.type == FocusIn) ? "in" : "out",
@@ -1487,8 +859,6 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case KeymapNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("keymap notify"));
 
@@ -1497,45 +867,76 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case Expose:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
-               g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d",
+               g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d%s",
                           xevent->xexpose.window, xevent->xexpose.count,
                           xevent->xexpose.x, xevent->xexpose.y,
-                          xevent->xexpose.width, xevent->xexpose.height));
-      gdk_compress_exposures (xevent, window);
-      
-      event->expose.type = GDK_EXPOSE;
-      event->expose.window = window;
-      event->expose.area.x = xevent->xexpose.x;
-      event->expose.area.y = xevent->xexpose.y;
-      event->expose.area.width = xevent->xexpose.width;
-      event->expose.area.height = xevent->xexpose.height;
-      event->expose.count = xevent->xexpose.count;
-      
+                          xevent->xexpose.width, xevent->xexpose.height,
+                          event->any.send_event ? " (send)" : ""));
+      {
+       GdkRectangle expose_rect;
+
+       expose_rect.x = xevent->xexpose.x + xoffset;
+       expose_rect.y = xevent->xexpose.y + yoffset;
+       expose_rect.width = xevent->xexpose.width;
+       expose_rect.height = xevent->xexpose.height;
+
+       if (return_exposes)
+         {
+           event->expose.type = GDK_EXPOSE;
+           event->expose.area = expose_rect;
+           event->expose.region = gdk_region_rectangle (&expose_rect);
+           event->expose.window = window;
+           event->expose.count = xevent->xexpose.count;
+
+           return_val = TRUE;
+         }
+       else
+         {
+           _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
+
+           return_val = FALSE;
+         }
+       
+       return_val = FALSE;
+      }
+       
       break;
       
     case GraphicsExpose:
-      /* Print debugging info.
-       */
-      GDK_NOTE (EVENTS,
-               g_message ("graphics expose:\tdrawable: %ld",
-                          xevent->xgraphicsexpose.drawable));
-      
-      event->expose.type = GDK_EXPOSE;
-      event->expose.window = window;
-      event->expose.area.x = xevent->xgraphicsexpose.x;
-      event->expose.area.y = xevent->xgraphicsexpose.y;
-      event->expose.area.width = xevent->xgraphicsexpose.width;
-      event->expose.area.height = xevent->xgraphicsexpose.height;
-      event->expose.count = xevent->xexpose.count;
-      
+      {
+       GdkRectangle expose_rect;
+
+        GDK_NOTE (EVENTS,
+                 g_message ("graphics expose:\tdrawable: %ld",
+                            xevent->xgraphicsexpose.drawable));
+
+       expose_rect.x = xevent->xgraphicsexpose.x + xoffset;
+       expose_rect.y = xevent->xgraphicsexpose.y + yoffset;
+       expose_rect.width = xevent->xgraphicsexpose.width;
+       expose_rect.height = xevent->xgraphicsexpose.height;
+           
+       if (return_exposes)
+         {
+           event->expose.type = GDK_EXPOSE;
+           event->expose.area = expose_rect;
+           event->expose.region = gdk_region_rectangle (&expose_rect);
+           event->expose.window = window;
+           event->expose.count = xevent->xgraphicsexpose.count;
+
+           return_val = TRUE;
+         }
+       else
+         {
+           _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
+           
+           return_val = FALSE;
+         }
+       
+      }
       break;
       
     case NoExpose:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("no expose:\t\tdrawable: %ld",
                           xevent->xnoexpose.drawable));
@@ -1546,8 +947,6 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case VisibilityNotify:
-      /* Print debugging info.
-       */
 #ifdef G_ENABLE_DEBUG
       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
        switch (xevent->xvisibility.state)
@@ -1588,12 +987,20 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case CreateNotify:
-      /* Not currently handled */
+      GDK_NOTE (EVENTS,
+               g_message ("create notify:\twindow: %ld  x,y: %d %d     w,h: %d %d  b-w: %d  parent: %ld         ovr: %d",
+                          xevent->xcreatewindow.window,
+                          xevent->xcreatewindow.x,
+                          xevent->xcreatewindow.y,
+                          xevent->xcreatewindow.width,
+                          xevent->xcreatewindow.height,
+                          xevent->xcreatewindow.border_width,
+                          xevent->xcreatewindow.parent,
+                          xevent->xcreatewindow.override_redirect));
+      /* not really handled */
       break;
       
     case DestroyNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("destroy notify:\twindow: %ld",
                           xevent->xdestroywindow.window));
@@ -1601,21 +1008,29 @@ gdk_event_translate (GdkEvent *event,
       event->any.type = GDK_DESTROY;
       event->any.window = window;
       
-      return_val = window_private && !window_private->destroyed;
+      return_val = window_private && !GDK_WINDOW_DESTROYED (window);
       
-      if(window && window_private->xwindow != GDK_ROOT_WINDOW())
+      if (window && GDK_WINDOW_XID (window) != GDK_ROOT_WINDOW())
        gdk_window_destroy_notify (window);
       break;
       
     case UnmapNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("unmap notify:\t\twindow: %ld",
                           xevent->xmap.window));
       
       event->any.type = GDK_UNMAP;
-      event->any.window = window;
+      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 (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;
@@ -1623,61 +1038,37 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case MapNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("map notify:\t\twindow: %ld",
                           xevent->xmap.window));
       
       event->any.type = GDK_MAP;
       event->any.window = window;
+
+      /* Unset iconified if it was set */
+      if (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED)
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_ICONIFIED,
+                                     0);
       
       break;
       
     case ReparentNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
-               g_message ("reparent notify:\twindow: %ld",
-                          xevent->xreparent.window));
+               g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld      ovr: %d",
+                          xevent->xreparent.window,
+                          xevent->xreparent.x,
+                          xevent->xreparent.y,
+                          xevent->xreparent.parent,
+                          xevent->xreparent.override_redirect));
 
       /* Not currently handled */
       return_val = FALSE;
       break;
       
     case ConfigureNotify:
-      /* Print debugging info.
-       */
-      while ((XPending (gdk_display) > 0) &&
-            XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
-                                   ConfigureNotify, xevent))
-       {
-         GdkFilterReturn result;
-         
-         GDK_NOTE (EVENTS, 
-                   g_message ("configure notify discarded:\twindow: %ld",
-                              xevent->xconfigure.window));
-         
-         result = gdk_event_apply_filters (xevent, event,
-                                           window_private
-                                           ?window_private->filters
-                                           :gdk_default_filters);
-         
-         /* If the result is GDK_FILTER_REMOVE, there will be
-          * trouble, but anybody who filtering the Configure events
-          * better know what they are doing
-          */
-         if (result != GDK_FILTER_CONTINUE)
-           {
-             return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
-           }
-         
-         /*XSync (gdk_display, 0);*/
-       }
-      
-      
       GDK_NOTE (EVENTS,
-               g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d",
+               g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d%s",
                           xevent->xconfigure.window,
                           xevent->xconfigure.x,
                           xevent->xconfigure.y,
@@ -1685,14 +1076,18 @@ gdk_event_translate (GdkEvent *event,
                           xevent->xconfigure.height,
                           xevent->xconfigure.border_width,
                           xevent->xconfigure.above,
-                          xevent->xconfigure.override_redirect));
-      
-      if (!window_private->destroyed &&
-         (window_private->extension_events != 0) &&
-         gdk_input_vtable.configure_event)
-       gdk_input_vtable.configure_event (&xevent->xconfigure, window);
-
-      if (window_private->window_type == GDK_WINDOW_CHILD)
+                          xevent->xconfigure.override_redirect,
+                          !window
+                          ? " (discarding)"
+                          : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
+                          ? " (discarding child)"
+                          : ""));
+      if (window &&
+         !GDK_WINDOW_DESTROYED (window) &&
+         (window_private->extension_events != 0))
+       _gdk_input_configure_event (&xevent->xconfigure, window);
+
+      if (!window || GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
        return_val = FALSE;
       else
        {
@@ -1703,22 +1098,28 @@ gdk_event_translate (GdkEvent *event,
          
          if (!xevent->xconfigure.x &&
              !xevent->xconfigure.y &&
-             !window_private->destroyed)
+             !GDK_WINDOW_DESTROYED (window))
            {
              gint tx = 0;
              gint ty = 0;
              Window child_window = 0;
-             
-             if (!XTranslateCoordinates (window_private->xdisplay,
-                                         window_private->xwindow,
-                                         gdk_root_window,
-                                         0, 0,
-                                         &tx, &ty,
-                                         &child_window))
-               g_warning ("GdkWindow %ld doesn't share root windows display?",
-                          window_private->xwindow);
-             event->configure.x = tx;
-             event->configure.y = ty;
+
+             gdk_error_trap_push ();
+             if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
+                                        GDK_DRAWABLE_XID (window),
+                                        gdk_root_window,
+                                        0, 0,
+                                        &tx, &ty,
+                                        &child_window))
+               {
+                 if (!gdk_error_trap_pop ())
+                   {
+                     event->configure.x = tx;
+                     event->configure.y = ty;
+                   }
+               }
+             else
+               gdk_error_trap_pop ();
            }
          else
            {
@@ -1727,25 +1128,43 @@ gdk_event_translate (GdkEvent *event,
            }
          window_private->x = event->configure.x;
          window_private->y = event->configure.y;
-         window_private->width = xevent->xconfigure.width;
-         window_private->height = xevent->xconfigure.height;
+         GDK_WINDOW_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;
        }
       break;
       
     case PropertyNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
-               g_message ("property notify:\twindow: %ld",
-                          xevent->xproperty.window));
+               gchar *atom = gdk_atom_name (xevent->xproperty.atom);
+               g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
+                          xevent->xproperty.window,
+                          xevent->xproperty.atom,
+                          atom ? "\"" : "",
+                          atom ? atom : "unknown",
+                          atom ? "\"" : "");
+               g_free (atom);
+               );
       
       event->property.type = GDK_PROPERTY_NOTIFY;
       event->property.window = window;
       event->property.atom = xevent->xproperty.atom;
       event->property.time = xevent->xproperty.time;
       event->property.state = xevent->xproperty.state;
+
+      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;
       
@@ -1753,12 +1172,17 @@ gdk_event_translate (GdkEvent *event,
       GDK_NOTE (EVENTS,
                g_message ("selection clear:\twindow: %ld",
                           xevent->xproperty.window));
-      
-      event->selection.type = GDK_SELECTION_CLEAR;
-      event->selection.window = window;
-      event->selection.selection = xevent->xselectionclear.selection;
-      event->selection.time = xevent->xselectionclear.time;
-      
+
+      if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
+       {
+         event->selection.type = GDK_SELECTION_CLEAR;
+         event->selection.window = window;
+         event->selection.selection = xevent->xselectionclear.selection;
+         event->selection.time = xevent->xselectionclear.time;
+       }
+      else
+       return_val = FALSE;
+         
       break;
       
     case SelectionRequest:
@@ -1792,8 +1216,6 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case ColormapNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("colormap notify:\twindow: %ld",
                           xevent->xcolormap.window));
@@ -1807,8 +1229,6 @@ gdk_event_translate (GdkEvent *event,
        GList *tmp_list;
        GdkFilterReturn result = GDK_FILTER_CONTINUE;
 
-       /* Print debugging info.
-        */
        GDK_NOTE (EVENTS,
                  g_message ("client message:\twindow: %ld",
                             xevent->xclient.window));
@@ -1848,31 +1268,37 @@ gdk_event_translate (GdkEvent *event,
       break;
       
     case MappingNotify:
-      /* Print debugging info.
-       */
       GDK_NOTE (EVENTS,
                g_message ("mapping notify"));
       
       /* Let XLib know that there is a new keyboard mapping.
        */
       XRefreshKeyboardMapping (&xevent->xmapping);
+      ++_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) */
       
       if (window_private &&
-         !window_private->destroyed &&
-         (window_private->extension_events != 0) &&
-         gdk_input_vtable.other_event)
-       return_val = gdk_input_vtable.other_event(event, xevent, window);
+         !GDK_WINDOW_DESTROYED (window_private) &&
+         (window_private->extension_events != 0))
+       return_val = _gdk_input_other_event(event, xevent, window);
       else
        return_val = FALSE;
       
       break;
     }
-  
+
+ done:
   if (return_val)
     {
       if (event->any.window)
@@ -1897,8 +1323,8 @@ gdk_event_translate (GdkEvent *event,
 
 GdkFilterReturn
 gdk_wm_protocols_filter (GdkXEvent *xev,
-                    GdkEvent  *event,
-                    gpointer data)
+                        GdkEvent  *event,
+                        gpointer data)
 {
   XEvent *xevent = (XEvent *)xev;
 
@@ -1923,6 +1349,13 @@ gdk_wm_protocols_filter (GdkXEvent *xev,
   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
     {
     }
+  else if ((Atom) xevent->xclient.data.l[0] == gdk_atom_intern ("_NET_WM_PING", FALSE))
+    {
+      XEvent xev = *xevent;
+      
+      xev.xclient.window = gdk_root_window;
+      XSendEvent (gdk_display, gdk_root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+    }
 
   return GDK_FILTER_REMOVE;
 }
@@ -1936,7 +1369,7 @@ gdk_event_get_type (Display  *display,
   GdkEvent event;
   GdkPredicate *pred;
   
-  if (gdk_event_translate (&event, xevent))
+  if (gdk_event_translate (&event, xevent, FALSE))
     {
       pred = (GdkPredicate*) arg;
       return (* pred->func) (&event, pred->data);
@@ -1946,7 +1379,7 @@ gdk_event_get_type (Display  *display,
 }
 #endif
 
-static void
+void
 gdk_events_queue (void)
 {
   GList *node;
@@ -1955,40 +1388,30 @@ 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 ();
       
       event->any.type = GDK_NOTHING;
       event->any.window = NULL;
-      event->any.send_event = FALSE;
-      event->any.send_event = xevent.xany.send_event;
+      event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
 
       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
 
       gdk_event_queue_append (event);
-      node = queued_tail;
+      node = gdk_queued_tail;
 
-      if (gdk_event_translate (event, &xevent))
+      if (gdk_event_translate (event, &xevent, FALSE))
        {
          ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
        }
@@ -2002,8 +1425,7 @@ gdk_events_queue (void)
 }
 
 static gboolean  
-gdk_event_prepare (gpointer  source_data, 
-                  GTimeVal *current_time,
+gdk_event_prepare (GSource  *source,
                   gint     *timeout)
 {
   gboolean retval;
@@ -2020,8 +1442,7 @@ gdk_event_prepare (gpointer  source_data,
 }
 
 static gboolean  
-gdk_event_check   (gpointer  source_data,
-                  GTimeVal *current_time)
+gdk_event_check (GSource  *source) 
 {
   gboolean retval;
   
@@ -2037,28 +1458,10 @@ gdk_event_check   (gpointer  source_data,
   return retval;
 }
 
-static GdkEvent *
-gdk_event_unqueue (void)
-{
-  GdkEvent *event = NULL;
-  GList *tmp_list;
-
-  tmp_list = gdk_event_queue_find_first ();
-
-  if (tmp_list)
-    {
-      event = tmp_list->data;
-      gdk_event_queue_remove_link (tmp_list);
-      g_list_free_1 (tmp_list);
-    }
-
-  return event;
-}
-
 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;
  
@@ -2069,8 +1472,8 @@ gdk_event_dispatch (gpointer  source_data,
 
   if (event)
     {
-      if (event_func)
-       (*event_func) (event, event_data);
+      if (gdk_event_func)
+       (*gdk_event_func) (event, gdk_event_data);
       
       gdk_event_free (event);
     }
@@ -2080,20 +1483,6 @@ gdk_event_dispatch (gpointer  source_data,
   return TRUE;
 }
 
-static void
-gdk_synthesize_click (GdkEvent *event,
-                     gint      nclicks)
-{
-  GdkEvent temp_event;
-  
-  g_return_if_fail (event != NULL);
-  
-  temp_event = *event;
-  temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
-  
-  gdk_event_put (&temp_event);
-}
-
 /* Sends a ClientMessage to all toplevel client windows */
 gboolean
 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
@@ -2120,29 +1509,29 @@ gdk_event_send_client_message_to_all_recurse (XEvent  *xev,
                                              guint    level)
 {
   static GdkAtom wm_state_atom = GDK_NONE;
-
   Atom type = None;
   int format;
   unsigned long nitems, after;
   unsigned char *data;
-  
   Window *ret_children, ret_root, ret_parent;
   unsigned int ret_nchildren;
-  int i;
-  
+  gint old_warnings = gdk_error_warnings;
   gboolean send = FALSE;
   gboolean found = FALSE;
+  int i;
 
   if (!wm_state_atom)
     wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
 
+  gdk_error_warnings = FALSE;
   gdk_error_code = 0;
   XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
                      &type, &format, &nitems, &after, &data);
 
   if (gdk_error_code)
     {
-      gdk_error_code = 0;
+      gdk_error_warnings = old_warnings;
+
       return FALSE;
     }
 
@@ -2154,18 +1543,20 @@ 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)
-       return FALSE;
-      
-      if (gdk_error_code)
-       return FALSE;
+      if (XQueryTree (gdk_display, xid, &ret_root, &ret_parent,
+                     &ret_children, &ret_nchildren) != True ||
+         gdk_error_code)
+       {
+         gdk_error_warnings = old_warnings;
+
+         return FALSE;
+       }
 
       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 (xev, ret_children[i], level + 1))
          found = TRUE;
 
-      XFree(ret_children);
+      XFree (ret_children);
     }
 
   if (send || (!found && (level == 1)))
@@ -2174,6 +1565,8 @@ gdk_event_send_client_message_to_all_recurse (XEvent  *xev,
       gdk_send_xevent (xid, False, NoEventMask, xev);
     }
 
+  gdk_error_warnings = old_warnings;
+
   return (send || found);
 }
 
@@ -2215,9 +1608,154 @@ gdk_event_send_clientmessage_toall (GdkEvent *event)
  *--------------------------------------------------------------
  */
 
-void gdk_flush (void)
+void
+gdk_flush (void)
 {
   XSync (gdk_display, False);
 }
 
+static GdkAtom timestamp_prop_atom = 0;
+
+static Bool
+timestamp_predicate (Display *display,
+                    XEvent  *xevent,
+                    XPointer arg)
+{
+  Window xwindow = GPOINTER_TO_UINT (arg);
+
+  if (xevent->type == PropertyNotify &&
+      xevent->xproperty.window == xwindow &&
+      xevent->xproperty.atom == timestamp_prop_atom)
+    return True;
+
+  return False;
+}
+
+/**
+ * gdk_x11_get_server_time:
+ * @window: a #GdkWindow, used for communication with the server.
+ *          The window must have GDK_PROPERTY_CHANGE_MASK in its
+ *          events mask or a hang will result.
+ * 
+ * Routine to get the current X server time stamp. 
+ * 
+ * Return value: the time stamp.
+ **/
+guint32
+gdk_x11_get_server_time (GdkWindow *window)
+{
+  Display *xdisplay;
+  Window   xwindow;
+  guchar c = 'a';
+  XEvent xevent;
+
+  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_atom_intern ("GDK_TIMESTAMP_PROP", FALSE);
+
+  xdisplay = GDK_WINDOW_XDISPLAY (window);
+  xwindow = GDK_WINDOW_XWINDOW (window);
+  
+  XChangeProperty (xdisplay, xwindow,
+                  timestamp_prop_atom, timestamp_prop_atom,
+                  8, PropModeReplace, &c, 1);
+
+  XIfEvent (xdisplay, &xevent,
+           timestamp_predicate, GUINT_TO_POINTER(xwindow));
+
+  return xevent.xproperty.time;
+}
+
+
+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);
+}
+
+