Index: src/nautilus-application.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-application.c,v
retrieving revision 1.227
diff -p -u -r1.227 nautilus-application.c
--- src/nautilus-application.c	22 Nov 2004 15:24:37 -0000	1.227
+++ src/nautilus-application.c	14 Feb 2005 04:05:59 -0000
@@ -83,6 +83,8 @@
 #include <libnautilus-private/nautilus-desktop-link-monitor.h>
 #include <libnautilus-private/nautilus-directory-private.h>
 #include <bonobo-activation/bonobo-activation.h>
+#define SN_API_NOT_YET_FROZEN Yes_i_know_DO_IT
+#include <libsn/sn-launchee.h>
 
 /* Needed for the is_kdesktop_present check */
 #include <gdk/gdkx.h>
@@ -452,6 +454,7 @@ nautilus_application_startup (NautilusAp
 			      gboolean no_desktop,
 			      gboolean do_first_time_druid_check,
 			      gboolean browser_window,
+			      const char *startup_id,
 			      const char *geometry,
 			      const char *urls[])
 {
@@ -461,6 +464,7 @@ nautilus_application_startup (NautilusAp
 	const char *message, *detailed_message;
 	GtkDialog *dialog;
 	Nautilus_URIList *url_list;
+	const CORBA_char *corba_startup_id;
 	const CORBA_char *corba_geometry;
 	int num_failures;
 
@@ -610,15 +614,16 @@ nautilus_application_startup (NautilusAp
 
 		/* CORBA C mapping doesn't allow NULL to be passed
 		   for string parameters */
-		corba_geometry = (geometry != NULL) ? geometry : "";
+		corba_geometry   = (geometry   != NULL) ? geometry   : "";
+		corba_startup_id = (startup_id != NULL) ? startup_id : "";
 
 	  	/* Create the other windows. */
 		if (urls != NULL) {
 			url_list = nautilus_make_uri_list_from_shell_strv (urls);
-			Nautilus_Shell_open_windows (shell, url_list, corba_geometry, browser_window, &ev);
+			Nautilus_Shell_open_windows (shell, url_list, corba_startup_id, corba_geometry, browser_window, &ev);
 			CORBA_free (url_list);
 		} else if (!no_default_window) {
-			Nautilus_Shell_open_default_window (shell, corba_geometry, browser_window, &ev);
+			Nautilus_Shell_open_default_window (shell, corba_startup_id, corba_geometry, browser_window, &ev);
 		}
 		
 		/* Add ourselves to the session */
@@ -926,6 +931,7 @@ nautilus_window_delete_event_callback (G
 static NautilusWindow *
 create_window (NautilusApplication *application,
 	       GType window_type,
+	       const char *startup_id,
 	       GdkScreen *screen)
 {
 	NautilusWindow *window;
@@ -939,6 +945,9 @@ create_window (NautilusApplication *appl
 	/* Must be called after construction finished */
 	nautilus_window_constructed (window);
 
+	if (startup_id != NULL)
+		window->details->startup_id = g_strdup (startup_id);  /* FIXME: leak? */
+
 	g_signal_connect_data (window, "delete_event",
 			       G_CALLBACK (nautilus_window_delete_event_callback), NULL, NULL,
 			       G_CONNECT_AFTER);
@@ -966,21 +975,129 @@ spatial_window_destroyed_callback (void 
 NautilusWindow *
 nautilus_application_present_spatial_window (NautilusApplication *application,
 					     NautilusWindow      *requesting_window,
+					     const char          *startup_id,
 					     const char          *location,
 					     GdkScreen           *screen)
 {
 	return nautilus_application_present_spatial_window_with_selection (application,
 									   requesting_window,
+									   startup_id,
 									   location,
 									   NULL,
 									   screen);
 }
 
+static void
+sn_error_trap_push (SnDisplay *display,
+                    Display   *xdisplay)
+{
+  gdk_error_trap_push ();
+}
+
+static void
+sn_error_trap_pop (SnDisplay *display,
+                   Display   *xdisplay)
+{
+  gdk_error_trap_pop ();
+}
+
+static gboolean
+id_string_has_timestamp (const char *startup_id_string)
+{
+  char * time_str;
+
+  time_str = g_strrstr (startup_id_string, "_TIME");
+
+  return time_str != NULL;
+}
+
+static guint32
+get_timestamp_from_id_string (const char *startup_id_string)
+{
+	char   *time_str;
+	gchar  *end;
+	gulong  retval;
+
+	retval = 0;
+	time_str = g_strrstr (startup_id_string, "_TIME");
+	g_assert (time_str != NULL);
+
+	errno = 0;
+
+	/* Skip past the "_TIME" part */
+	time_str += 5;
+
+	retval = strtoul (time_str, &end, 0);
+	if (end == time_str || errno != 0)
+		g_warning ("startup_id is messed up\n");
+
+	return retval;
+}
+
+static void
+end_startup_notification (GtkWidget  *widget, 
+			  const char *startup_id_to_end,
+			  const char *startup_id_with_timestamp)
+{
+	SnDisplay *sn_display;
+	SnLauncheeContext *context;
+	GdkDisplay *display;
+	GdkScreen  *screen;
+
+	g_return_if_fail (startup_id_to_end != NULL);
+  
+	if (!GTK_WIDGET_REALIZED (widget))
+		gtk_widget_realize (widget);
+  
+	context = NULL;
+	sn_display = NULL;
+
+	/* Set up window for launch notification */
+	/* FIXME In principle all transient children of this
+	 * window should get the same startup_id
+	 */
+
+	screen = gtk_widget_get_screen (widget);
+	display = gdk_screen_get_display (screen);
+      
+	sn_display = sn_display_new (gdk_x11_display_get_xdisplay (display),
+				     sn_error_trap_push,
+				     sn_error_trap_pop);
+      
+	context = sn_launchee_context_new (sn_display,
+					   gdk_screen_get_number (screen),
+					   startup_id_to_end);
+
+	if (startup_id_with_timestamp == NULL) {
+		sn_launchee_context_setup_window (context,
+						  GDK_WINDOW_XWINDOW (widget->window));
+		startup_id_with_timestamp = startup_id_to_end;
+	}
+
+	/* Now, set the _NET_WM_USER_TIME for the new window to the timestamp
+	 * that caused the window to be launched.
+	 */
+	if (id_string_has_timestamp (startup_id_with_timestamp)) {
+		gulong startup_id_timestamp;
+		startup_id_timestamp = get_timestamp_from_id_string (startup_id_with_timestamp);
+		gdk_x11_window_set_user_time (widget->window, startup_id_timestamp);
+	} else {
+		g_warning ("Launched by a non-compliant or obsolete startup "
+			   "notification launcher.  Focus-stealing-prevention "
+			   "may fail.\n");
+	}
+  
+	sn_launchee_context_complete (context);
+	sn_launchee_context_unref (context);
+	sn_display_unref (sn_display);
+}
+
 NautilusWindow *
 nautilus_application_present_spatial_window_with_selection (NautilusApplication *application,
 							    NautilusWindow      *requesting_window,
+							    const char          *startup_id,
 							    const char          *location,
-							    GList		 *new_selection,
+							    GList		*new_selection,
 							    GdkScreen           *screen)
 {
 	NautilusWindow *window;
@@ -1001,6 +1118,9 @@ nautilus_application_present_spatial_win
 		}
 
 		if (eel_uris_match (existing_location, location)) {
+			end_startup_notification (GTK_WIDGET (existing_window),
+						  existing_window->details->startup_id,
+						  startup_id);
 			gtk_window_present (GTK_WINDOW (existing_window));
 			if (new_selection) {
 				nautilus_view_set_selection (existing_window->content_view, new_selection);
@@ -1009,7 +1129,10 @@ nautilus_application_present_spatial_win
 		}
 	}
 
-	window = create_window (application, NAUTILUS_TYPE_SPATIAL_WINDOW, screen);
+	window = create_window (application, NAUTILUS_TYPE_SPATIAL_WINDOW, startup_id, screen);
+	end_startup_notification (GTK_WIDGET (window),
+				  startup_id,
+				  NULL);
 	if (requesting_window) {
 		/* Center the window over the requesting window by default */
 		int orig_x, orig_y, orig_width, orig_height;
@@ -1044,13 +1167,17 @@ nautilus_application_present_spatial_win
 
 NautilusWindow *
 nautilus_application_create_navigation_window (NautilusApplication *application,
+					       const char          *startup_id,
 					       GdkScreen           *screen)
 {
 	NautilusWindow *window;
 
 	g_return_val_if_fail (NAUTILUS_IS_APPLICATION (application), NULL);
 	
-	window = create_window (application, NAUTILUS_TYPE_NAVIGATION_WINDOW, screen);
+	window = create_window (application, NAUTILUS_TYPE_NAVIGATION_WINDOW, startup_id, screen);
+	end_startup_notification (GTK_WIDGET (window),
+				  startup_id,
+				  NULL);
 
 	return window;
 }
Index: src/nautilus-application.h
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-application.h,v
retrieving revision 1.38
diff -p -u -r1.38 nautilus-application.h
--- src/nautilus-application.h	18 Oct 2004 21:36:11 -0000	1.38
+++ src/nautilus-application.h	14 Feb 2005 04:05:59 -0000
@@ -67,6 +67,7 @@ void                 nautilus_applicatio
 							     gboolean             no_desktop,
 							     gboolean             do_first_time_druid_check,
 							     gboolean             browser_window,
+							     const char          *startup_id,
 							     const char          *default_geometry,
 							     const char          *urls[]);
 GList *              nautilus_application_get_window_list           (void);
@@ -74,15 +75,18 @@ GList *              nautilus_applicatio
 
 NautilusWindow *     nautilus_application_present_spatial_window     (NautilusApplication *application,
 								      NautilusWindow      *requesting_window,
+								      const char          *startup_id,
 								      const char          *location,
 								      GdkScreen           *screen);
 NautilusWindow *     nautilus_application_present_spatial_window_with_selection (NautilusApplication *application,
 										 NautilusWindow      *requesting_window,
+										 const char          *startup_id,
 										 const char          *location,
 										 GList		     *new_selection,
 										 GdkScreen           *screen);
 
 NautilusWindow *     nautilus_application_create_navigation_window     (NautilusApplication *application,
+									const char          *startup_id,
 									GdkScreen           *screen);
 
 void                 nautilus_application_close_all_navigation_windows (void);
Index: src/nautilus-bookmarks-window.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-bookmarks-window.c,v
retrieving revision 1.82
diff -p -u -r1.82 nautilus-bookmarks-window.c
--- src/nautilus-bookmarks-window.c	16 Dec 2004 07:57:43 -0000	1.82
+++ src/nautilus-bookmarks-window.c	14 Feb 2005 04:05:59 -0000
@@ -555,6 +555,7 @@ get_bookmark_nautilus_navigation_window_
 	application = nautilus_application_new ();
 
 	window = nautilus_application_create_navigation_window (application, 
+								NULL,
 								screen);
 
 	return window;
Index: src/nautilus-connect-server-dialog-nonmain.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-connect-server-dialog-nonmain.c,v
retrieving revision 1.1
diff -p -u -r1.1 nautilus-connect-server-dialog-nonmain.c
--- src/nautilus-connect-server-dialog-nonmain.c	14 Jan 2005 11:11:38 -0000	1.1
+++ src/nautilus-connect-server-dialog-nonmain.c	14 Feb 2005 04:05:59 -0000
@@ -39,10 +39,12 @@ nautilus_connect_server_dialog_present_u
 	
 	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_BROWSER)) {
 		window = nautilus_application_create_navigation_window (application,
+									NULL,
 									gtk_widget_get_screen (widget));
 		nautilus_window_go_to (window, uri);
 	} else {
 		nautilus_application_present_spatial_window (application,
+							     NULL,
 							     NULL,
 							     uri,
 							     gtk_widget_get_screen (widget));
Index: src/nautilus-location-bar.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-location-bar.c,v
retrieving revision 1.101
diff -p -u -r1.101 nautilus-location-bar.c
--- src/nautilus-location-bar.c	22 Nov 2004 15:24:37 -0000	1.101
+++ src/nautilus-location-bar.c	14 Feb 2005 04:05:59 -0000
@@ -189,7 +189,7 @@ drag_data_received_callback (GtkWidget *
 		screen = gtk_window_get_screen (GTK_WINDOW (window));
 
 		for (node = names->next; node != NULL; node = node->next) {
-			new_window = nautilus_application_create_navigation_window (application, screen);
+			new_window = nautilus_application_create_navigation_window (application, NULL, screen);
 			nautilus_window_go_to (new_window, node->data);
 		}
 	}
Index: src/nautilus-main.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-main.c,v
retrieving revision 1.143
diff -p -u -r1.143 nautilus-main.c
--- src/nautilus-main.c	27 Jan 2005 19:10:45 -0000	1.143
+++ src/nautilus-main.c	14 Feb 2005 04:05:59 -0000
@@ -196,6 +196,8 @@ main (int argc, char *argv[])
 	gboolean no_default_window;
 	gboolean browser_window;
 	gboolean no_desktop;
+	const char *startup_id;
+	char *startup_id_copy;
 	char *geometry;
 	gboolean perform_self_check;
 	poptContext popt_context;
@@ -246,6 +248,17 @@ main (int argc, char *argv[])
 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 	textdomain (GETTEXT_PACKAGE);
 
+	startup_id = g_getenv ("DESKTOP_STARTUP_ID");
+	startup_id_copy = NULL;
+	if (startup_id != NULL && *startup_id != '\0') {
+		/* Clear the DESKTOP_STARTUP_ID, but make sure to copy it first */
+		startup_id_copy = g_strdup (startup_id);
+		putenv ("DESKTOP_STARTUP_ID=");
+	}
+
+	/* we'll do it ourselves due to complicated factory setup */
+	gtk_window_set_auto_startup_notification (FALSE);
+
 	/* Get parameters. */
 	geometry = NULL;
 	kill_shell = FALSE;
@@ -349,6 +362,7 @@ main (int argc, char *argv[])
 			 kill_shell, restart_shell, no_default_window, no_desktop,
 			 !(kill_shell || restart_shell),
 			 browser_window,
+			 startup_id_copy,
 			 geometry,
 			 args);
 		if (is_event_loop_needed ()) {
Index: src/nautilus-navigation-window-menus.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-navigation-window-menus.c,v
retrieving revision 1.268
diff -p -u -r1.268 nautilus-navigation-window-menus.c
--- src/nautilus-navigation-window-menus.c	11 Jan 2005 12:14:13 -0000	1.268
+++ src/nautilus-navigation-window-menus.c	14 Feb 2005 04:06:00 -0000
@@ -520,6 +520,7 @@ action_new_window_callback (GtkAction *a
 	current_window = NAUTILUS_WINDOW (user_data);
 	new_window = nautilus_application_create_navigation_window (
 				current_window->application,
+				NULL,
 				gtk_window_get_screen (GTK_WINDOW (current_window)));
 	nautilus_window_go_home (new_window);
 }
Index: src/nautilus-shell-interface.idl
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-shell-interface.idl,v
retrieving revision 1.7
diff -p -u -r1.7 nautilus-shell-interface.idl
--- src/nautilus-shell-interface.idl	22 Nov 2004 15:24:37 -0000	1.7
+++ src/nautilus-shell-interface.idl	14 Feb 2005 04:06:00 -0000
@@ -10,8 +10,8 @@ module Nautilus {
 	typedef sequence<URI> URIList;
 
 	interface Shell : ::Bonobo::Unknown {
-		void open_windows (in URIList uris, in string geometry, in boolean browser_window);
-		void open_default_window (in string geometry, in boolean browser_window);
+		void open_windows (in URIList uris, in string startup_id, in string geometry, in boolean browser_window);
+		void open_default_window (in string startup_id, in string geometry, in boolean browser_window);
 		void start_desktop ();
 		void stop_desktop ();
 		void quit ();
Index: src/nautilus-shell.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-shell.c,v
retrieving revision 1.58
diff -p -u -r1.58 nautilus-shell.c
--- src/nautilus-shell.c	22 Nov 2004 15:24:37 -0000	1.58
+++ src/nautilus-shell.c	14 Feb 2005 04:06:00 -0000
@@ -63,10 +63,12 @@ struct NautilusShellDetails {
 static void     finalize                         (GObject              *shell);
 static void     corba_open_windows              (PortableServer_Servant  servant,
 						 const Nautilus_URIList *list,
+						 const CORBA_char       *startup_id,
 						 const CORBA_char       *geometry,
 						 CORBA_boolean           browser_window,
 						 CORBA_Environment      *ev);
 static void     corba_open_default_window       (PortableServer_Servant  servant,
+						 const CORBA_char       *startup_id,
 						 const CORBA_char       *geometry,
 						 CORBA_boolean           browser_window,
 						 CORBA_Environment      *ev);
@@ -125,8 +127,8 @@ nautilus_shell_new (NautilusApplication 
 }
 
 static void
-open_window (NautilusShell *shell, const char *uri, const char *geometry,
-	     gboolean browser_window)
+open_window (NautilusShell *shell, const char *uri, const char *startup_id,
+	     const char *geometry, gboolean browser_window)
 {
 	char *home_uri;
 	NautilusWindow *window;
@@ -134,6 +136,7 @@ open_window (NautilusShell *shell, const
 	if (browser_window ||
 	    eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_BROWSER)) {
 		window = nautilus_application_create_navigation_window (shell->details->application,
+									startup_id,
 									gdk_screen_get_default ());
 		if (uri == NULL) {
 			nautilus_window_go_home (window);
@@ -149,6 +152,7 @@ open_window (NautilusShell *shell, const
 		
 		window = nautilus_application_present_spatial_window (shell->details->application,
 								      NULL,
+								      startup_id,
 								      uri,
 								      gdk_screen_get_default ());
 		g_free (home_uri);
@@ -166,6 +170,7 @@ open_window (NautilusShell *shell, const
 static void
 corba_open_windows (PortableServer_Servant servant,
 		    const Nautilus_URIList *list,
+		    const CORBA_char *startup_id,
 		    const CORBA_char *geometry,
 		    CORBA_boolean browser_window,
 		    CORBA_Environment *ev)
@@ -178,12 +183,13 @@ corba_open_windows (PortableServer_Serva
 	/* Open windows at each requested location. */
 	for (i = 0; i < list->_length; i++) {
 		g_assert (list->_buffer[i] != NULL);
-		open_window (shell, list->_buffer[i], geometry, browser_window);
+		open_window (shell, list->_buffer[i], startup_id, geometry, browser_window);
 	}
 }
 
 static void
 corba_open_default_window (PortableServer_Servant servant,
+			   const CORBA_char *startup_id,
 			   const CORBA_char *geometry,
 			   CORBA_boolean browser_window,
 			   CORBA_Environment *ev)
@@ -194,7 +200,7 @@ corba_open_default_window (PortableServe
 
 	if (!restore_window_states (shell)) {
 		/* Open a window pointing at the default location. */
-		open_window (shell, NULL, geometry, browser_window);
+		open_window (shell, NULL, startup_id, geometry, browser_window);
 	}
 }
 
@@ -345,10 +351,12 @@ restore_one_window_callback (const char 
 	if (eel_strlen (location) > 0) {
 		window = nautilus_application_present_spatial_window (shell->details->application, 
 								      NULL,
+								      NULL, /* FIXME: Need startup_id? */
 								      location,
 								      screen);
 	} else {
 		window = nautilus_application_create_navigation_window (shell->details->application,
+									NULL, /* FIXME: Need startup_id? */
 									screen);
 		nautilus_window_go_home (window);
 	}
Index: src/nautilus-window-manage-views.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-window-manage-views.c,v
retrieving revision 1.346
diff -p -u -r1.346 nautilus-window-manage-views.c
--- src/nautilus-window-manage-views.c	22 Nov 2004 15:24:37 -0000	1.346
+++ src/nautilus-window-manage-views.c	14 Feb 2005 04:06:00 -0000
@@ -451,6 +451,7 @@ nautilus_window_open_location_full (Naut
 				if (!NAUTILUS_SPATIAL_WINDOW (window)->affect_spatial_window_on_next_location_change) {
 					target_window = nautilus_application_create_navigation_window 
 						(window->application,
+						 NULL,
 						 gtk_window_get_screen (GTK_WINDOW (window)));
 				} else {
 					NAUTILUS_SPATIAL_WINDOW (window)->affect_spatial_window_on_next_location_change = FALSE;
@@ -461,6 +462,7 @@ nautilus_window_open_location_full (Naut
                                 target_window = nautilus_application_present_spatial_window_with_selection (
                                         window->application,
 					window,
+					NULL,
                                         location,
 					new_selection,
                                         gtk_window_get_screen (GTK_WINDOW (window)));
@@ -477,12 +479,14 @@ nautilus_window_open_location_full (Naut
                 target_window = nautilus_application_present_spatial_window (
                         window->application,
 			window,
+			NULL,
                         location,
                         gtk_window_get_screen (GTK_WINDOW (window)));
                 break;
         case NAUTILUS_WINDOW_OPEN_IN_NAVIGATION :
                 target_window = nautilus_application_create_navigation_window 
                         (window->application,
+			 NULL,
                          gtk_window_get_screen (GTK_WINDOW (window)));
                 break;
         default :
Index: src/nautilus-window-private.h
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-window-private.h,v
retrieving revision 1.104
diff -p -u -r1.104 nautilus-window-private.h
--- src/nautilus-window-private.h	22 Nov 2004 15:24:37 -0000	1.104
+++ src/nautilus-window-private.h	14 Feb 2005 04:06:00 -0000
@@ -56,6 +56,9 @@ struct NautilusWindowDetails
         GtkUIManager *ui_manager;
         GtkActionGroup *main_action_group; /* owned by ui_manager */
         guint help_message_cid;
+
+        /* Startup ID; for startup notification shutoff */
+        char *startup_id;
         
         /* Menus. */
         guint extensions_menu_merge_id;
Index: src/nautilus-window.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-window.c,v
retrieving revision 1.440
diff -p -u -r1.440 nautilus-window.c
--- src/nautilus-window.c	1 Feb 2005 16:44:47 -0000	1.440
+++ src/nautilus-window.c	14 Feb 2005 04:06:01 -0000
@@ -143,6 +143,8 @@ nautilus_window_init (NautilusWindow *wi
 
 	window->details->show_hidden_files_mode = NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT;
 	
+	window->details->startup_id = NULL;
+
 	/* Set initial window title */
 	gtk_window_set_title (GTK_WINDOW (window), _("Nautilus"));
 
@@ -463,7 +465,7 @@ nautilus_window_constructed (NautilusWin
 static void
 nautilus_window_set_property (GObject *object,
 			      guint arg_id,
-		      const GValue *value,
+			      const GValue *value,
 			      GParamSpec *pspec)
 {
 	NautilusWindow *window;
