Index: src/display.c
===================================================================
--- src/display.c	(revision 3127)
+++ src/display.c	(working copy)
@@ -333,7 +333,8 @@ meta_display_open (void)
     "_NET_DESKTOP_VIEWPORT",
     "_METACITY_VERSION",
     "_NET_WM_VISIBLE_NAME",
-    "_NET_WM_VISIBLE_ICON_NAME"
+    "_NET_WM_VISIBLE_ICON_NAME",
+    "_NET_WM_USER_TIME_WINDOW"
   };
   Atom atoms[G_N_ELEMENTS(atom_names)];
   
@@ -492,6 +493,7 @@ meta_display_open (void)
   display->atom_metacity_version = atoms[91];
   display->atom_net_wm_visible_name = atoms[92];
   display->atom_net_wm_visible_icon_name = atoms[93];
+  display->atom_net_wm_user_time_window = atoms[94];
 
   display->prop_hooks = NULL;
   meta_display_init_window_prop_hooks (display);
@@ -502,6 +504,7 @@ meta_display_open (void)
    * created in screen_new
    */
   display->leader_window = None;
+  display->timestamp_pinging_window = None;
 
   display->xinerama_cache_invalidated = TRUE;
 
@@ -685,6 +688,13 @@ meta_display_open (void)
     timestamp = event.xproperty.time;
   }
 
+  /* Make a little window used only for pinging the server for timestamps; note
+   * that meta_create_offscreen_window already selects for PropertyChangeMask.
+   */
+  display->timestamp_pinging_window =
+    meta_create_offscreen_window (display->xdisplay,
+                                  DefaultRootWindow (display->xdisplay));
+
   display->last_focus_time = timestamp;
   display->last_user_time = timestamp;
   display->compositor = NULL;
@@ -1192,14 +1202,13 @@ meta_display_get_current_time_roundtrip 
        * would use it as a property. The type doesn't matter.
        */
       XChangeProperty (display->xdisplay,
-                       display->leader_window,
+                       display->timestamp_pinging_window,
                        XA_PRIMARY, XA_STRING, 8,
                        PropModeAppend, NULL, 0);
       XWindowEvent (display->xdisplay,
-                    display->leader_window,
+                    display->timestamp_pinging_window,
                     PropertyChangeMask,
                     &property_event);
-
       timestamp = property_event.xproperty.time;
     }
 
@@ -1457,6 +1466,7 @@ event_callback (XEvent   *event,
                 gpointer  data)
 {
   MetaWindow *window;
+  MetaWindow *property_for_window;
   MetaDisplay *display;
   Window modified;
   gboolean frame_was_receiver;
@@ -1510,6 +1520,18 @@ event_callback (XEvent   *event,
   else
     window = NULL;
 
+  /* We only want to respond to _NET_WM_USER_TIME property notify
+   * events on _NET_WM_USER_TIME_WINDOW windows; in particular,
+   * responding to UnmapNotify events is kind of bad.
+   */
+  property_for_window = NULL;
+  if (window && modified == window->user_time_window)
+    {
+      property_for_window = window;
+      window = NULL;
+    }
+    
+
   frame_was_receiver = FALSE;
   if (window &&
       window->frame &&
@@ -2173,6 +2195,8 @@ event_callback (XEvent   *event,
         
         if (window && !frame_was_receiver)
           meta_window_property_notify (window, event);
+        else if (property_for_window && !frame_was_receiver)
+          meta_window_property_notify (property_for_window, event);
 
         group = meta_display_lookup_group (display,
                                            event->xproperty.window);
Index: src/display.h
===================================================================
--- src/display.h	(revision 3127)
+++ src/display.h	(working copy)
@@ -85,6 +85,7 @@ struct _MetaDisplay
   Display *xdisplay;
 
   Window leader_window;
+  Window timestamp_pinging_window;
   
   Atom atom_net_wm_name;
   Atom atom_wm_protocols;
@@ -180,6 +181,7 @@ struct _MetaDisplay
   Atom atom_metacity_version;
   Atom atom_net_wm_visible_name;
   Atom atom_net_wm_visible_icon_name;
+  Atom atom_net_wm_user_time_window;
 
   /* This is the actual window from focus events,
    * not the one we last set
Index: src/window-props.c
===================================================================
--- src/window-props.c	(revision 3127)
+++ src/window-props.c	(working copy)
@@ -70,6 +70,26 @@ meta_window_reload_properties (MetaWindo
                                const Atom *properties,
                                int         n_properties)
 {
+  meta_window_reload_properties_from_xwindow (window,
+                                              window->xwindow,
+                                              properties,
+                                              n_properties);
+}
+
+void
+meta_window_reload_property_from_xwindow (MetaWindow *window,
+                                          Window      xwindow,
+                                          Atom        property)
+{
+  meta_window_reload_properties_from_xwindow (window, xwindow, &property, 1);
+}
+
+void
+meta_window_reload_properties_from_xwindow (MetaWindow *window,
+                                            Window      xwindow,
+                                            const Atom *properties,
+                                            int         n_properties)
+{
   int i;
   MetaPropValue *values;
 
@@ -85,7 +105,7 @@ meta_window_reload_properties (MetaWindo
       ++i;
     }
   
-  meta_prop_get_values (window->display, window->xwindow,
+  meta_prop_get_values (window->display, xwindow,
                         values, n_properties);
 
   i = 0;
@@ -200,6 +220,70 @@ reload_net_wm_user_time (MetaWindow    *
     }
 }
 
+static void
+init_net_wm_user_time_window (MetaDisplay   *display,
+                              Atom           property,
+                              MetaPropValue *value)
+{
+  value->type = META_PROP_VALUE_WINDOW;
+  value->atom = display->atom_net_wm_user_time_window;
+}
+
+static void
+reload_net_wm_user_time_window (MetaWindow    *window,
+                                MetaPropValue *value)
+{
+  if (value->type != META_PROP_VALUE_INVALID)
+    {
+      /* Unregister old NET_WM_USER_TIME_WINDOW */
+      if (window->user_time_window != None)
+        {
+          /* See the comment to the meta_display_register_x_window call below. */
+          meta_display_unregister_x_window (window->display,
+                                            window->user_time_window);
+          /* Don't get events on not-managed windows */
+          XSelectInput (window->display->xdisplay,
+                        window->user_time_window,
+                        NoEventMask);
+        }
+
+
+      /* Obtain the new NET_WM_USER_TIME_WINDOW and register it */
+      window->user_time_window = value->v.xwindow;
+      if (window->user_time_window != None)
+        {
+          /* Kind of a hack; display.c:event_callback() ignores events
+           * for unknown windows.  We make window->user_time_window
+           * known by registering it with window (despite the fact
+           * that window->xwindow is already registered with window).
+           * This basically means that property notifies to either the
+           * window->user_time_window or window->xwindow will be
+           * treated identically and will result in functions for
+           * window being called to update it.  Maybe we should ignore
+           * any property notifies to window->user_time_window other
+           * than atom_net_wm_user_time ones, but I just don't care
+           * and it's not specified in the spec anyway.
+           */
+          meta_display_register_x_window (window->display,
+                                          &window->user_time_window,
+                                          window);
+          /* Just listen for property notify events */
+          XSelectInput (window->display->xdisplay,
+                        window->user_time_window,
+                        PropertyChangeMask);
+
+          /* Manually load the _NET_WM_USER_TIME field from the given window
+           * at this time as well.  If the user_time_window ever broadens in
+           * scope, we'll probably want to load all relevant properties here.
+           */
+          meta_window_reload_property_from_xwindow (
+            window,
+            window->display->atom_net_wm_user_time,
+            window->user_time_window);
+        }
+    }
+}
+
 #define MAX_TITLE_LENGTH 512
 
 /**
@@ -1217,7 +1301,7 @@ reload_transient_for (MetaWindow    *win
     meta_window_queue_move_resize (window);
 }
 
-#define N_HOOKS 25
+#define N_HOOKS 26
 
 void
 meta_display_init_window_prop_hooks (MetaDisplay *display)
@@ -1357,6 +1441,11 @@ meta_display_init_window_prop_hooks (Met
   hooks[i].reload_func = reload_transient_for;
   ++i;
 
+  hooks[i].property = display->atom_net_wm_user_time_window;
+  hooks[i].init_func = init_net_wm_user_time_window;
+  hooks[i].reload_func = reload_net_wm_user_time_window;
+  ++i;
+
   if (i != N_HOOKS)
     g_error ("Initialized %d hooks should have been %d\n", i, N_HOOKS);
 }
Index: src/window-props.h
===================================================================
--- src/window-props.h	(revision 3127)
+++ src/window-props.h	(working copy)
@@ -31,6 +31,15 @@ void meta_window_reload_property   (Meta
 void meta_window_reload_properties (MetaWindow *window,
                                     const Atom *properties,
                                     int         n_properties);
+void meta_window_reload_property_from_xwindow
+                                   (MetaWindow *window,
+                                    Window      xwindow,
+                                    Atom        property);
+void meta_window_reload_properties_from_xwindow
+                                   (MetaWindow *window,
+                                    Window      xwindow,
+                                    const Atom *properties,
+                                    int         n_properties);
 
 void meta_display_init_window_prop_hooks (MetaDisplay *display);
 void meta_display_free_window_prop_hooks (MetaDisplay *display);
Index: src/screen.c
===================================================================
--- src/screen.c	(revision 3127)
+++ src/screen.c	(working copy)
@@ -89,7 +89,7 @@ set_wm_check_hint (MetaScreen *screen)
 static int
 set_supported_hint (MetaScreen *screen)
 {
-#define N_SUPPORTED 58
+#define N_SUPPORTED 59
   Atom atoms[N_SUPPORTED];
   
   atoms[0] = screen->display->atom_net_wm_name;
@@ -150,6 +150,7 @@ set_supported_hint (MetaScreen *screen)
   atoms[55] = screen->display->atom_net_wm_state_demands_attention;
   atoms[56] = screen->display->atom_net_desktop_geometry;
   atoms[57] = screen->display->atom_net_desktop_viewport;
+  atoms[58] = screen->display->atom_net_wm_user_time_window;
   //atoms[58] = screen->display->atom_net_restack_window;
   //atoms[59] = screen->display->atom_net_moveresize_window;
   
Index: src/window.c
===================================================================
--- src/window.c	(revision 3127)
+++ src/window.c	(working copy)
@@ -234,7 +234,7 @@ meta_window_new_with_attrs (MetaDisplay 
   gulong existing_wm_state;
   gulong event_mask;
   MetaMoveResizeFlags flags;
-#define N_INITIAL_PROPS 17
+#define N_INITIAL_PROPS 18
   Atom initial_props[N_INITIAL_PROPS];
   int i;
   gboolean has_shape;
@@ -478,6 +478,7 @@ meta_window_new_with_attrs (MetaDisplay 
   window->initial_workspace_set = FALSE;
   window->initial_timestamp_set = FALSE;
   window->net_wm_user_time_set = FALSE;
+  window->user_time_window = None;
   window->calc_placement = FALSE;
   window->shaken_loose = FALSE;
   window->have_focus_click_grab = FALSE;
@@ -577,6 +578,7 @@ meta_window_new_with_attrs (MetaDisplay 
   initial_props[i++] = display->atom_net_wm_state;
   initial_props[i++] = display->atom_motif_wm_hints;
   initial_props[i++] = XA_WM_TRANSIENT_FOR;
+  initial_props[i++] = display->atom_net_wm_user_time_window;
   g_assert (N_INITIAL_PROPS == i);
   
   meta_window_reload_properties (window, initial_props, N_INITIAL_PROPS);
@@ -1103,6 +1105,17 @@ meta_window_free (MetaWindow  *window,
                 window->xwindow,
                 NoEventMask);
 
+  /* Stop getting events for the window's _NET_WM_USER_TIME_WINDOW too */
+  if (window->user_time_window != None)
+    {
+      meta_display_unregister_x_window (window->display,
+                                        window->user_time_window);
+      XSelectInput (window->display->xdisplay,
+                    window->user_time_window,
+                    NoEventMask);
+      window->user_time_window = None;
+    }
+
 #ifdef HAVE_SHAPE
   if (META_DISPLAY_HAS_SHAPE (window->display))
     XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
@@ -5229,10 +5242,19 @@ process_property_notify (MetaWindow     
     }
   else if (event->atom == window->display->atom_net_wm_user_time)
     {
+      Window xid;
+      Atom atom_net_wm_user_time;
+
       meta_verbose ("Property notify on %s for _NET_WM_USER_TIME\n", window->desc);
-      
-      meta_window_reload_property (window,
-                                   window->display->atom_net_wm_user_time);
+
+      atom_net_wm_user_time = window->display->atom_net_wm_user_time;
+      if (window->user_time_window)
+        xid = window->user_time_window;
+      else
+        xid = window->xwindow;
+      meta_window_reload_property_from_xwindow (window,
+                                                xid,
+                                                atom_net_wm_user_time);
     }
 
   return TRUE;
Index: src/window.h
===================================================================
--- src/window.h	(revision 3127)
+++ src/window.h	(working copy)
@@ -318,6 +318,9 @@ struct _MetaWindow
   /* set to the most recent user-interaction event timestamp that we
      know about for this window */
   guint32 net_wm_user_time;
+
+  /* window that gets updated net_wm_user_time values */
+  Window user_time_window;
   
   /* The size we set the window to last (i.e. what we believe
    * to be its actual size on the server). The x, y are
