Index: gtk/gtkwindow.c
===================================================================
--- gtk/gtkwindow.c	(revision 17504)
+++ gtk/gtkwindow.c	(working copy)
@@ -26,6 +26,8 @@
 
 #include <config.h>
 #include <string.h>
+#include <stdlib.h>
+#include <errno.h>
 #include <limits.h>
 #include "gdk/gdk.h"
 #include "gdk/gdkkeysyms.h"
@@ -95,6 +97,9 @@ enum {
   PROP_IS_ACTIVE,
   PROP_HAS_TOPLEVEL_FOCUS,
   
+  /* Writeonly properties */
+  PROP_STARTUP_ID,
+  
   LAST_ARG
 };
 
@@ -177,6 +182,8 @@ struct _GtkWindowPrivate
 
   guint reset_type_hint : 1;
   GdkWindowTypeHint type_hint;
+
+  gchar *startup_id;
 };
 
 static void gtk_window_dispose            (GObject           *object);
@@ -344,6 +351,33 @@ add_arrow_bindings (GtkBindingSet    *bi
                                 GTK_TYPE_DIRECTION_TYPE, direction);
 }
 
+static guint32
+extract_time_from_startup_id (const gchar* startup_id)
+{
+  gchar* timestr = g_strrstr (startup_id, "_TIME");
+	
+  if (timestr != NULL)
+    {
+      gchar *end;
+      errno = 0;
+      guint32 timestamp; 
+    
+      /* Skip past the "_TIME" part */
+      timestr += 5;
+    
+      timestamp = strtoul (timestr, &end, 0);
+      if (end != timestr && errno == 0)
+        return timestamp;
+    }
+  
+  return GDK_CURRENT_TIME;
+}
+
+static gboolean
+startup_id_is_fake (const gchar* startup_id)
+{
+  return strncmp (startup_id, "_TIME", 5) == 0;
+}
 
 static void
 gtk_window_class_init (GtkWindowClass *klass)
@@ -429,6 +463,23 @@ gtk_window_class_init (GtkWindowClass *k
 							P_("Unique identifier for the window to be used when restoring a session"),
 							NULL,
 							GTK_PARAM_READWRITE));
+							
+  /**
+   * GtkWindow:startup-id:
+   *
+   * The :startup-id is a write-only property for setting window's
+   * startup notification identifier. See gtk_window_set_startup_id()
+   * for more details.
+   *
+   * Since: 2.12
+   */							
+  g_object_class_install_property (gobject_class,
+                                   PROP_ROLE,
+                                   g_param_spec_string ("startup-id",
+							P_("Startup ID"),
+							P_("Unique startup identifier for the window used by startup-notification"),
+							NULL,
+							GTK_PARAM_WRITABLE));
 
   g_object_class_install_property (gobject_class,
                                    PROP_ALLOW_SHRINK,
@@ -810,6 +861,7 @@ gtk_window_init (GtkWindow *window)
   priv->focus_on_map = TRUE;
   priv->deletable = TRUE;
   priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
+  priv->startup_id = NULL;
 
   colormap = _gtk_widget_peek_colormap ();
   if (colormap)
@@ -846,6 +898,9 @@ gtk_window_set_property (GObject      *o
     case PROP_ROLE:
       gtk_window_set_role (window, g_value_get_string (value));
       break;
+    case PROP_STARTUP_ID:
+      gtk_window_set_startup_id (window, g_value_get_string (value));
+      break; 
     case PROP_ALLOW_SHRINK:
       window->allow_shrink = g_value_get_boolean (value);
       gtk_widget_queue_resize (GTK_WIDGET (window));
@@ -1201,6 +1256,58 @@ gtk_window_set_role (GtkWindow   *window
 }
 
 /**
+ * gtk_window_set_startup_id:
+ * @window: a #GtkWindow
+ * @startup_id: a string with startup-notification identifier
+ *
+ * Startup notification identifiers are used by desktop environment to 
+ * track application startup, to provide user feedback and other 
+ * features. This function changes the corresponding property on the
+ * underlying GdkWindow. Normally, startup identifier is managed 
+ * automatically and you should only use this function in special cases
+ * like transferring focus from other processes.
+ *
+ * This function is only useful on X11, not with other GTK+ targets.
+ * 
+ * Since: 2.12
+ **/
+void
+gtk_window_set_startup_id (GtkWindow   *window,
+                           const gchar *startup_id)
+{
+  char *new_id;
+  
+  g_return_if_fail (GTK_IS_WINDOW (window));
+  GtkWindowPrivate *private = GTK_WINDOW_GET_PRIVATE (window);
+
+  new_id = g_strdup (startup_id);
+  g_free (private->startup_id);
+  private->startup_id = new_id;
+  
+  if (GTK_WIDGET_REALIZED (window))
+    {
+      /* Here we differentiate real and "fake" startup notification IDs,
+       * constructed on purpose just to pass interaction timestamp
+       */  
+      if (startup_id_is_fake (new_id))
+        {
+          guint32 timestamp = extract_time_from_startup_id (new_id);
+          gtk_window_present_with_time (window, timestamp);
+        }
+      else 
+        {
+          gdk_window_set_startup_id (GTK_WIDGET (window)->window, private->startup_id);
+          
+          /* If window is mapped, terminate the startup-notification too */
+          if (GTK_WIDGET_MAPPED (window) && !disable_startup_notification)
+            gdk_notify_startup_complete_with_id (private->startup_id);
+        }
+    }
+
+  g_object_notify (G_OBJECT (window), "startup-id");
+}
+
+/**
  * gtk_window_get_role:
  * @window: a #GtkWindow
  *
@@ -4149,11 +4256,22 @@ gtk_window_map (GtkWidget *widget)
   if (window->frame)
     gdk_window_show (window->frame);
 
-  if (!disable_startup_notification &&
-      !sent_startup_notification)
+  if (!disable_startup_notification)
     {
-      sent_startup_notification = TRUE;
-      gdk_notify_startup_complete ();
+      /* Do we have a custom startup-notification id? */
+      if (priv->startup_id != NULL)
+        {
+          /* Make sure we have a "real" id */
+          if (!startup_id_is_fake (priv->startup_id)) 
+            gdk_notify_startup_complete_with_id (priv->startup_id);
+            
+          priv->startup_id = NULL;
+        }
+      else if (!sent_startup_notification)
+        {
+          sent_startup_notification = TRUE;
+          gdk_notify_startup_complete ();
+        }
     }
 }
 
@@ -4223,6 +4341,7 @@ gtk_window_realize (GtkWidget *widget)
   GtkWindowPrivate *priv;
   
   window = GTK_WINDOW (widget);
+  GtkWindowPrivate *private = GTK_WINDOW_GET_PRIVATE (window);
 
   priv = GTK_WINDOW_GET_PRIVATE (window);
 
@@ -4377,6 +4496,17 @@ gtk_window_realize (GtkWidget *widget)
     gdk_window_set_modal_hint (widget->window, TRUE);
   else
     gdk_window_set_modal_hint (widget->window, FALSE);
+    
+  if (private->startup_id)
+    {
+#ifdef GDK_WINDOWING_X11
+      guint32 timestamp = extract_time_from_startup_id (private->startup_id);
+      if (timestamp != GDK_CURRENT_TIME)
+        gdk_x11_window_set_user_time (widget->window, timestamp);
+#endif
+      if (!startup_id_is_fake (private->startup_id)) 
+        gdk_window_set_startup_id (widget->window, private->startup_id);
+    }
 
   /* Icons */
   gtk_window_realize_icon (window);
Index: gtk/gtkwindow.h
===================================================================
--- gtk/gtkwindow.h	(revision 17504)
+++ gtk/gtkwindow.h	(working copy)
@@ -178,6 +178,8 @@ void       gtk_window_set_wmclass       
 						const gchar         *wmclass_class);
 void       gtk_window_set_role                 (GtkWindow           *window,
                                                 const gchar         *role);
+void       gtk_window_set_startup_id           (GtkWindow           *window,
+                                                const gchar         *startup_id);
 G_CONST_RETURN gchar *gtk_window_get_role      (GtkWindow           *window);
 void       gtk_window_add_accel_group          (GtkWindow           *window,
 						GtkAccelGroup	    *accel_group);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 17504)
+++ ChangeLog	(working copy)
@@ -1,3 +1,30 @@
+2007-03-13  Emmanuele Bassi  <ebassi@gnome.org>
+
+	Apply patch by Vytautas Liuolia for changing the startup
+	notification id on a window in the X11 backend. (#347375)
+
+	* gdk/gdk.h:
+	* gdk/gdkx.h:
+	* gdk/x11/gdkdisplay-x11.c: Add gdk_notify_startup_complete_wit_id()
+	and gdk_x11_display_get_startup_notification_id().
+
+	* gdk/gdkwindow.h:
+	* gdk/x11/gdkwindow-x11.c: Add gdk_window_set_startup_id().
+
+	* gtk/gtkwindow.h:
+	* gtk/gtkwindow.c: Add gtk_window_set_startup_id(), used to
+	change the startup notification id.
+	
+	(gtk_window_class_init), (gtk_window_init),
+	(gtk_window_set_property): Add write-only "startup-id" property
+	to GtkWindow.
+
+	(gtk_window_realize): Set the startup notification id
+	on a GtkWindow if it's valid.
+
+	(gtk_window_map): If we have another valid startup notification
+	id then finish the notification process.
+
 2007-03-12  Matthias Clasen  <mclasen@redhat.com>
 
 	* gtk/gtksizegroup.c (gtk_size_group_add_widget): Clarify
Index: gdk/gdk.h
===================================================================
--- gdk/gdk.h	(revision 17504)
+++ gdk/gdk.h	(working copy)
@@ -177,6 +177,8 @@ gboolean gdk_event_send_client_message_f
 
 void gdk_notify_startup_complete (void);
 
+void gdk_notify_startup_complete_with_id (const gchar* startup_id);
+
 /* Threading
  */
 
Index: gdk/gdkwindow.h
===================================================================
--- gdk/gdkwindow.h	(revision 17504)
+++ gdk/gdkwindow.h	(working copy)
@@ -482,6 +482,8 @@ void	      gdk_window_set_title	   (GdkW
 					    const gchar	  *title);
 void          gdk_window_set_role          (GdkWindow       *window,
 					    const gchar     *role);
+void          gdk_window_set_startup_id    (GdkWindow       *window,
+					    const gchar     *startup_id);					  
 void          gdk_window_set_transient_for (GdkWindow       *window, 
 					    GdkWindow       *parent);
 void	      gdk_window_set_background	 (GdkWindow	  *window,
Index: gdk/x11/gdkdisplay-x11.c
===================================================================
--- gdk/x11/gdkdisplay-x11.c	(revision 17504)
+++ gdk/x11/gdkdisplay-x11.c	(working copy)
@@ -1079,7 +1079,36 @@ gdk_notify_startup_complete (void)
   if (!G_LIKELY (display_x11->trusted_client))
     return;
 
-  escaped_id = escape_for_xmessage (display_x11->startup_notification_id);
+  gdk_notify_startup_complete_with_id (display_x11->startup_notification_id);
+}
+
+/**
+ * gdk_notify_startup_complete_with_id:
+ * @startup_id: a startup-notification identifier, for which notification
+ *              process should be completed
+ * 
+ * Indicates to the GUI environment that the application has finished
+ * loading, using a given identifier.
+ * 
+ * GTK+ will call this function automatically for #GtkWindow with custom
+ * startup-notification identifier unless
+ * gtk_window_set_auto_startup_notification() is called to disable
+ * that feature.
+ *
+ * Since: 2.12
+ **/
+void
+gdk_notify_startup_complete_with_id (const gchar* startup_id)
+{
+  GdkDisplay *display;
+  gchar *escaped_id;
+  gchar *message;
+
+  display = gdk_display_get_default ();
+  if (!display)
+    return;
+
+  escaped_id = escape_for_xmessage (startup_id);
   message = g_strdup_printf ("remove: ID=%s", escaped_id);
   g_free (escaped_id);
 
@@ -1091,7 +1120,6 @@ gdk_notify_startup_complete (void)
   g_free (message);
 }
 
-
 /**
  * gdk_display_supports_selection_notification:
  * @display: a #GdkDisplay
@@ -1291,5 +1319,20 @@ gdk_display_supports_input_shapes (GdkDi
 }
 
 
+/**
+ * gdk_x11_display_get_startup_notification_id:
+ * @display: a #GdkDisplay
+ *
+ * Returns: the startup notification ID for 
+ * @display.
+ *
+ * Since: 2.12
+ */
+G_CONST_RETURN gchar *
+gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
+{
+  return GDK_DISPLAY_X11 (display)->startup_notification_id;
+}
+
 #define __GDK_DISPLAY_X11_C__
 #include "gdkaliasdef.c"
Index: gdk/x11/gdkx.h
===================================================================
--- gdk/x11/gdkx.h	(revision 17504)
+++ gdk/x11/gdkx.h	(working copy)
@@ -142,6 +142,8 @@ gpointer      gdk_xid_table_lookup_for_d
 guint32       gdk_x11_get_server_time  (GdkWindow       *window);
 guint32       gdk_x11_display_get_user_time (GdkDisplay *display);
 
+G_CONST_RETURN gchar *gdk_x11_display_get_startup_notification_id (GdkDisplay *display);
+
 void          gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
 						const gchar *theme,
 						const gint   size);
Index: gdk/x11/gdkwindow-x11.c
===================================================================
--- gdk/x11/gdkwindow-x11.c	(revision 17504)
+++ gdk/x11/gdkwindow-x11.c	(working copy)
@@ -2897,6 +2897,40 @@ gdk_window_set_role (GdkWindow   *window
 }
 
 /**
+ * gdk_window_set_startup_id:
+ * @window: a toplevel #GdkWindow
+ * @startup_id: a string with startup-notification identifier
+ *
+ * When using GTK+, typically you should use gtk_window_set_startup_id()
+ * instead of this low-level function.
+ *
+ * Since: 2.12
+ *
+ **/
+void          
+gdk_window_set_startup_id (GdkWindow   *window,
+		     const gchar *startup_id)
+{
+  GdkDisplay *display;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  display = gdk_drawable_get_display (window);
+
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      if (startup_id)
+	XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+			 gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"), 
+			 gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+			 PropModeReplace, startup_id, strlen (startup_id));
+      else
+	XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+			 gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"));
+    }
+}
+
+/**
  * gdk_window_set_transient_for:
  * @window: a toplevel #GdkWindow
  * @parent: another toplevel #GdkWindow
