[evince] Run evince instances in different processes instead of single instance



commit 66e5636dcaace0d9a98845490b09721c12ce3d2b
Author: Carlos Garcia Campos <carlosgc gnome org>
Date:   Mon Oct 19 19:27:45 2009 +0200

    Run evince instances in different processes instead of single instance
    
     - When built with DBus support a daemon is used to keep track of opened
       documents and reload them when reopened.
    
     - Crash recovery code has been removed.
    
     - Metadata migration code has been moved from main.c to ev-daemon.c, so
       that it's only run once on daemon startup.
    
    Fixes bgo#583680, bgo#434966, bgo#497388, bgo#524633 and bgo#586087.

 configure.ac                            |    8 +
 data/Makefile.am                        |   27 +-
 data/org.gnome.evince.Daemon.service.in |    3 +
 shell/Makefile.am                       |   31 ++-
 shell/ev-application-service.xml        |    6 -
 shell/ev-application.c                  |  613 +++++++++++++++----------------
 shell/ev-application.h                  |   14 +-
 shell/ev-daemon-service.xml             |   21 +
 shell/ev-daemon.c                       |  442 ++++++++++++++++++++++
 shell/main.c                            |  351 ++----------------
 10 files changed, 862 insertions(+), 654 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 6208b0c..096366d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -269,6 +269,10 @@ AC_SUBST([DBUS_LIBS])
 
 AM_CONDITIONAL([ENABLE_DBUS], [test "$enable_dbus" = "yes"])
 
+if test "$enable_dbus" = "yes"; then
+   PKG_CHECK_MODULES([EV_DAEMON], [gthread-2.0 gio-2.0 >= $GLIB_REQUIRED dbus-glib-1 >= $DBUS_GLIB_REQUIRED])
+fi
+
 dnl ========= Check for GConf
 
 AC_MSG_CHECKING([whether GConf support is requested])
@@ -339,6 +343,10 @@ FRONTEND_LIBS="$FRONTEND_CORE_LIBS -lz"
 AC_SUBST(FRONTEND_CFLAGS)
 AC_SUBST(FRONTEND_LIBS)
 
+EV_DAEMON_CFLAGS="$EV_DAEMON_CFLAGS $DEBUG_FLAGS"
+AC_SUBST([EV_DAEMON_CFLAGS])
+AC_SUBST([EV_DAEMON_LIBS])
+
 # Check for Nautilus property page build
 AC_ARG_ENABLE([nautilus],
   [AS_HELP_STRING([--disable-nautilus],[Build the nautilus extensions])],
diff --git a/data/Makefile.am b/data/Makefile.am
index 883a3aa..27ba73d 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -36,6 +36,17 @@ DESKTOP_FILES= $(DESKTOP_IN_FILES:.desktop.in.in=.desktop)
 desktopdir = $(datadir)/applications
 desktop_DATA = $(DESKTOP_FILES)
 
+#
+# DBus servide file
+#
+if ENABLE_DBUS
+servicedir = $(datadir)/dbus-1/services
+service_in_files = org.gnome.evince.Daemon.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+
+$(service_DATA): $(service_in_files) Makefile
+	@sed -e "s|\ libexecdir\@|$(libexecdir)|" $< > $@
+endif
 
 #
 # GConf schema
@@ -102,12 +113,13 @@ update-icon-cache:
 # Extra files to be included in the tarball
 #
 
-EXTRA_DIST =				\
-	$(ui_DATA)			\
-	$(DESKTOP_IN_FILES)		\
-	$(schema_in_files)		\
-	$(man_MANS)			\
-	$(NULL)				
+EXTRA_DIST =					\
+	$(ui_DATA)				\
+	$(DESKTOP_IN_FILES)			\
+	$(schema_in_files)			\
+	org.gnome.evince.Daemon.service.in	\
+	$(man_MANS)				\
+	$(NULL)
 
 #
 # Clean up properly
@@ -115,4 +127,5 @@ EXTRA_DIST =				\
 
 DISTCLEANFILES = \
 	$(DESKTOP_FILES)	\
-	$(schema_DATA)
+	$(schema_DATA)		\
+	$(service_DATA)
diff --git a/data/org.gnome.evince.Daemon.service.in b/data/org.gnome.evince.Daemon.service.in
new file mode 100644
index 0000000..c987f59
--- /dev/null
+++ b/data/org.gnome.evince.Daemon.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.evince.Daemon
+Exec= libexecdir@/evinced
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 3b4f6f7..8d86efe 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -26,6 +26,9 @@ INCLUDES=							\
 bin_PROGRAMS=evince
 
 libexec_PROGRAMS=evince-convert-metadata
+if ENABLE_DBUS
+libexec_PROGRAMS += evinced
+endif
 
 EV_MEDIA_PLAYER_KEYS_SOURCES = ev-media-player-keys.c ev-media-player-keys.h
 if ENABLE_DBUS
@@ -119,10 +122,30 @@ evince_convert_metadata_SOURCES=	\
 evince_convert_metadata_LDADD=		\
 	$(SHELL_LIBS)
 
+if ENABLE_DBUS
+BUILT_SOURCES += ev-daemon-service.h
 
+evinced_SOURCES=			\
+	ev-daemon.c
+
+evinced_CFLAGS=				\
+	-DDATADIR=\"$(pkgdatadir)\"				\
+	-DGNOMEDATADIR=\"$(datadir)\"				\
+	-I$(top_srcdir)						\
+	-I$(top_builddir)					\
+	-DLIBEXECDIR=\""$(libexecdir)"\"			\
+	-DEVINCE_COMPILATION					\
+	$(EV_DAEMON_CFLAGS)					\
+	$(WARN_CFLAGS)						\
+	$(DISABLE_DEPRECATED)
+
+evinced_LDADD=				\
+	$(EV_DAEMON_LIBS)
+endif
 
 EXTRA_DIST = ev-marshal.list		\
 	ev-application-service.xml	\
+	ev-daemon-service.xml		\
 	$(EV_MEDIA_PLAYER_KEYS_SOURCES)
 
 
@@ -133,8 +156,12 @@ ev-marshal.c: $(srcdir)/ev-marshal.list
 	echo '#include "ev-marshal.h"' > ev-marshal.c
 	$(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=ev_marshal $(srcdir)/ev-marshal.list --body >> ev-marshal.c
 
-DISTCLEANFILES= \
-	ev-application-service.h
+DISTCLEANFILES= 			\
+	ev-application-service.h	\
+	ev-daemon-service.h
 
 ev-application-service.h: $(srcdir)/ev-application-service.xml
 	$(AM_V_GEN)dbus-binding-tool --prefix=ev_application --mode=glib-server --output=ev-application-service.h $(srcdir)/ev-application-service.xml
+
+ev-daemon-service.h: $(srcdir)/ev-daemon-service.xml
+	$(AM_V_GEN)dbus-binding-tool --prefix=ev_daemon --mode=glib-server --output=ev-daemon-service.h $(srcdir)/ev-daemon-service.xml
diff --git a/shell/ev-application-service.xml b/shell/ev-application-service.xml
index f56bf0b..48fc18f 100644
--- a/shell/ev-application-service.xml
+++ b/shell/ev-application-service.xml
@@ -5,12 +5,6 @@
   <interface name="org.gnome.evince.Application">
     <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="ev_application"/>
 
-    <method name="OpenWindow">
-       <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="ev_application_open_window"/>
-       <arg type="a{sv}" name="args" direction="in"/>
-      <arg type="u" name="timestamp" direction="in"/>
-    </method>
-
     <method name="OpenURI">
       <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="ev_application_open_uri"/>
       <arg type="s" name="uri" direction="in"/>
diff --git a/shell/ev-application.c b/shell/ev-application.c
index e31b132..69a5a73 100644
--- a/shell/ev-application.c
+++ b/shell/ev-application.c
@@ -50,6 +50,11 @@
 
 #ifdef ENABLE_DBUS
 #include <dbus/dbus-glib-bindings.h>
+static gboolean ev_application_open_uri (EvApplication  *application,
+					 const char     *uri,
+					 GHashTable     *args,
+					 guint           timestamp,
+					 GError        **error);
 #include "ev-application-service.h"
 #endif
 
@@ -64,8 +69,9 @@ struct _EvApplication {
 	gchar *toolbars_file;
 
 #ifdef ENABLE_DBUS
-	gchar *crashed_file;
-	guint  crashed_idle;
+	DBusGConnection *connection;
+	GHashTable *windows;
+	guint doc_counter;
 #endif
 
 	EggToolbarsModel *toolbars_model;
@@ -96,65 +102,15 @@ static EvApplication *instance;
 
 G_DEFINE_TYPE (EvApplication, ev_application, G_TYPE_OBJECT);
 
-#define APPLICATION_SERVICE_NAME "org.gnome.evince.ApplicationService"
+#ifdef ENABLE_DBUS
+#define APPLICATION_DBUS_OBJECT_PATH "/org/gnome/evince/Evince"
+#define APPLICATION_DBUS_INTERFACE   "org.gnome.evince.Application"
+#endif
 
 #define EV_PRINT_SETTINGS_FILE "print-settings"
 #define EV_PRINT_SETTINGS_GROUP "Print Settings"
 #define EV_PAGE_SETUP_GROUP "Page Setup"
 
-#ifdef ENABLE_DBUS
-gboolean
-ev_application_register_service (EvApplication *application)
-{
-	static DBusGConnection *connection = NULL;
-	DBusGProxy *driver_proxy;
-	GError *err = NULL;
-	guint request_name_result;
-
-	if (connection) {
-		g_warning ("Service already registered.");
-		return FALSE;
-	}
-	
-	connection = dbus_g_bus_get (DBUS_BUS_STARTER, &err);
-	if (connection == NULL) {
-		g_warning ("Service registration failed.");
-		g_error_free (err);
-
-		return FALSE;
-	}
-
-	driver_proxy = dbus_g_proxy_new_for_name (connection,
-						  DBUS_SERVICE_DBUS,
-						  DBUS_PATH_DBUS,
-						  DBUS_INTERFACE_DBUS);
-
-	if (!org_freedesktop_DBus_request_name (driver_proxy,
-                                        	APPLICATION_SERVICE_NAME,
-						DBUS_NAME_FLAG_DO_NOT_QUEUE,
-						&request_name_result, &err)) {
-		g_warning ("Service registration failed.");
-		g_clear_error (&err);
-	}
-
-	g_object_unref (driver_proxy);
-	
-	if (request_name_result == DBUS_REQUEST_NAME_REPLY_EXISTS) {
-		return FALSE;
-	}
-
-	dbus_g_object_type_install_info (EV_TYPE_APPLICATION,
-					 &dbus_glib_ev_application_object_info);
-	dbus_g_connection_register_g_object (connection,
-					     "/org/gnome/evince/Evince",
-                                             G_OBJECT (application));
-	
-	application->scr_saver = totem_scrsaver_new (connection);
-
-	return TRUE;
-}
-#endif /* ENABLE_DBUS */
-
 /**
  * ev_application_get_instance:
  *
@@ -172,8 +128,7 @@ ev_application_get_instance (void)
 	return instance;
 }
 
-#if defined (WITH_SMCLIENT) || defined (ENABLE_DBUS)
-
+#if defined (WITH_SMCLIENT)
 /* Session */
 static void
 save_session (EvApplication *application,
@@ -202,173 +157,7 @@ save_session (EvApplication *application,
 	g_free (uri_list);
 }
 
-#endif /* WITH_SMCLIENT || ENABLE_DBUS */
-
-#ifdef ENABLE_DBUS
-static void
-ev_application_save_session_crashed (EvApplication *application)
-{
-	GList *windows;
-
-	windows = ev_application_get_windows (application);
-	if (windows) {
-		GKeyFile *crashed_file;
-		gchar    *data;
-		gssize    data_length;
-		GError   *error = NULL;
-
-		crashed_file = g_key_file_new ();
-		save_session (application, windows, crashed_file);
-
-		data = g_key_file_to_data (crashed_file, (gsize *)&data_length, NULL);
-		g_file_set_contents (application->crashed_file, data, data_length, &error);
-		if (error) {
-			g_warning ("%s", error->message);
-			g_error_free (error);
-		}
-		g_free (data);
-		g_key_file_free (crashed_file);
-	} else if (g_file_test (application->crashed_file, G_FILE_TEST_IS_REGULAR)) {
-		GFile *file;
-
-		file = g_file_new_for_path (application->crashed_file);
-		g_file_delete (file, NULL, NULL);
-		g_object_unref (file);
-	}
-}
-
-static gboolean
-save_session_crashed_in_idle_cb (EvApplication *application)
-{
-	ev_application_save_session_crashed (application);
-	application->crashed_idle = 0;
-
-	return FALSE;
-}
-
-static void
-save_session_crashed_in_idle (EvApplication *application)
-{
-	if (application->crashed_idle > 0)
-		g_source_remove (application->crashed_idle);
-	application->crashed_idle =
-		g_idle_add ((GSourceFunc)save_session_crashed_in_idle_cb,
-			    application);
-}
-
-static gboolean
-ev_application_run_crash_recovery_dialog (EvApplication *application)
-{
-	GtkWidget *dialog;
-	gint       response;
-
-	dialog = gtk_message_dialog_new	(NULL,
-					 GTK_DIALOG_MODAL,
-					 GTK_MESSAGE_WARNING,
-					 GTK_BUTTONS_NONE,
-					 _("Recover previous documents?"));
-	gtk_message_dialog_format_secondary_text (
-		GTK_MESSAGE_DIALOG (dialog),
-		_("Evince appears to have exited unexpectedly the last time "
-		  "it was run. You can recover the opened documents."));
-
-	gtk_dialog_add_button (GTK_DIALOG (dialog),
-			       _("_Don't Recover"),
-			       GTK_RESPONSE_CANCEL);
-	gtk_dialog_add_button (GTK_DIALOG (dialog),
-			       _("_Recover"),
-			       GTK_RESPONSE_ACCEPT);
-
-	gtk_window_set_title (GTK_WINDOW (dialog), _("Crash Recovery"));
-	gtk_window_set_icon_name (GTK_WINDOW (dialog), "evince");
-	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
-	gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE);
-	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
-
-	response = gtk_dialog_run (GTK_DIALOG (dialog));
-	gtk_widget_destroy (dialog);
-
-	return response == GTK_RESPONSE_ACCEPT;
-}
-
-static gboolean
-is_in_command_line (GFile         *file,
-		    const gchar  **files)
-{
-	gint i;
-
-	if (!files)
-		return FALSE;
-
-	for (i = 0; files[i]; i++) {
-		GFile *cfile;
-
-		cfile = g_file_new_for_commandline_arg (files[i]);
-		if (g_file_equal (cfile, file)) {
-			g_object_unref (cfile);
-			return TRUE;
-		}
-		g_object_unref (cfile);
-	}
-
-	return FALSE;
-}
-
-static GKeyFile *
-ev_application_get_files_to_recover (EvApplication *application,
-				     const gchar  **files)
-{
-	GKeyFile *state_file;
-	gchar   **uri_list;
-	gchar   **dest_list = NULL;
-	gint      i, j;
-
-	state_file = g_key_file_new ();
-	g_key_file_load_from_file (state_file,
-				   application->crashed_file,
-				   G_KEY_FILE_NONE,
-				   NULL);
-
-	uri_list = g_key_file_get_string_list (state_file,
-					       "Evince",
-					       "documents",
-					       NULL, NULL);
-	if (!uri_list) {
-		g_key_file_free (state_file);
-		return NULL;
-	}
-
-	for (i = 0, j = 0; uri_list[i]; i++) {
-		GFile *file = g_file_new_for_uri (uri_list[i]);
-
-		if (!g_file_query_exists (file, NULL) ||
-		    is_in_command_line (file, files)) {
-			g_object_unref (file);
-			continue;
-		}
-
-		if (!dest_list)
-			dest_list = g_new (gchar *, g_strv_length (uri_list) - i);
-		dest_list[j++] = uri_list[i];
-	}
-
-	if (j > 0) {
-		g_key_file_set_string_list (state_file,
-					    "Evince",
-					    "documents",
-					    (const gchar **)dest_list,
-					    j);
-	} else {
-		g_key_file_free (state_file);
-		state_file = NULL;
-	}
-
-	g_free (dest_list);
-	g_strfreev (uri_list);
-
-	return state_file;
-}
-#endif /* ENABLE_DBUS */
+#endif /* WITH_SMCLIENT */
 
 gboolean
 ev_application_load_session (EvApplication *application,
@@ -384,18 +173,6 @@ ev_application_load_session (EvApplication *application,
 			return FALSE;
 	} else
 #endif /* WITH_SMCLIENT */
-#ifdef ENABLE_DBUS
-        if (g_file_test (application->crashed_file, G_FILE_TEST_IS_REGULAR)) {
-		state_file = ev_application_get_files_to_recover (application, files);
-		if (!state_file)
-			return FALSE;
-
-		if (!ev_application_run_crash_recovery_dialog (application)) {
-			g_key_file_free (state_file);
-			return FALSE;
-		}
-	} else
-#endif /* ENABLE_DBUS */
 		return FALSE;
 
 	uri_list = g_key_file_get_string_list (state_file,
@@ -404,12 +181,14 @@ ev_application_load_session (EvApplication *application,
 					       NULL, NULL);
 	if (uri_list) {
 		gint i;
+		GdkScreen *screen = gdk_screen_get_default ();
 
 		for (i = 0; uri_list[i]; i++) {
 			if (g_ascii_strcasecmp (uri_list[i], "empty-window") == 0)
-				ev_application_open_window (application, NULL, GDK_CURRENT_TIME, NULL);
+				ev_application_open_window (application, screen, GDK_CURRENT_TIME);
 			else
-				ev_application_open_uri (application, uri_list[i], NULL, GDK_CURRENT_TIME, NULL);
+				ev_application_open_uri_at_dest (application, uri_list[i], screen,
+								 NULL, 0, NULL, GDK_CURRENT_TIME);
 		}
 		g_strfreev (uri_list);
 	}
@@ -446,11 +225,6 @@ smclient_quit_cb (EggSMClient   *client,
 static void
 ev_application_init_session (EvApplication *application)
 {
-#ifdef ENABLE_DBUS
-	application->crashed_file = g_build_filename (application->dot_dir,
-						      "evince-crashed", NULL);
-#endif
-
 #ifdef WITH_SMCLIENT
 	application->smclient = egg_sm_client_get ();
 	g_signal_connect (application->smclient, "save_state",
@@ -600,58 +374,106 @@ get_find_string_from_args (GHashTable *args)
 	return value ? g_value_get_string (value) : NULL;
 }
 
+static void
+value_free (GValue *value)
+{
+	g_value_unset (value);
+	g_free (value);
+}
+
+static GHashTable *
+build_args (GdkScreen      *screen,
+	    EvLinkDest     *dest,
+	    EvWindowRunMode mode,
+	    const gchar    *search_string)
+{
+	GHashTable  *args;
+	GValue      *value;
+	GdkDisplay  *display;
+	const gchar *display_name;
+	gint         screen_number;
+
+	args = g_hash_table_new_full (g_str_hash,
+				      g_str_equal,
+				      (GDestroyNotify)g_free,
+				      (GDestroyNotify)value_free);
+
+	/* Display */
+	display = gdk_screen_get_display (screen);
+	display_name = gdk_display_get_name (display);
+	value = g_new0 (GValue, 1);
+	g_value_init (value, G_TYPE_STRING);
+	g_value_set_string (value, display_name);
+	g_hash_table_insert (args, g_strdup ("display"), value);
+
+	/* Screen */
+	screen_number = gdk_screen_get_number (screen);
+	value = g_new0 (GValue, 1);
+	g_value_init (value, G_TYPE_INT);
+	g_value_set_int (value, screen_number);
+	g_hash_table_insert (args, g_strdup ("screen"), value);
+
+	/* Page label */
+	if (dest) {
+		value = g_new0 (GValue, 1);
+		g_value_init (value, G_TYPE_STRING);
+		g_value_set_string (value, ev_link_dest_get_page_label (dest));
+
+		g_hash_table_insert (args, g_strdup ("page-label"), value);
+	}
+
+	/* Find string */
+	if (search_string) {
+		value = g_new0 (GValue, 1);
+		g_value_init (value, G_TYPE_STRING);
+		g_value_set_string (value, search_string);
+
+		g_hash_table_insert (args, g_strdup ("find-string"), value);
+	}
+
+	/* Mode */
+	if (mode != EV_WINDOW_MODE_NORMAL) {
+		value = g_new0 (GValue, 1);
+		g_value_init (value, G_TYPE_UINT);
+		g_value_set_uint (value, mode);
+
+		g_hash_table_insert (args, g_strdup ("mode"), value);
+	}
+
+	return args;
+}
+
 /**
  * ev_application_open_window:
  * @application: The instance of the application.
- * @args: A #GHashTable with the arguments data.
  * @timestamp: Current time value.
- * @error: The #GError facility.
- * 
- * Creates a new window and if the args are available, it's not NULL, it gets
- * the screen from them and assigns the just created window to it. At last it
- * does show it.
  *
- * Returns: %TRUE.
+ * Creates a new window
  */
-gboolean
-ev_application_open_window (EvApplication  *application,
-			    GHashTable     *args,
-			    guint32         timestamp,
-			    GError        **error)
+void
+ev_application_open_window (EvApplication *application,
+			    GdkScreen     *screen,
+			    guint32        timestamp)
 {
 	GtkWidget *new_window = ev_window_new ();
-	GdkScreen *screen = NULL;
 
-	if (args) {
-		screen = get_screen_from_args (args);
-	}
-	
 	if (screen) {
 		ev_stock_icons_set_screen (screen);
 		gtk_window_set_screen (GTK_WINDOW (new_window), screen);
 	}
 
-#ifdef ENABLE_DBUS
-	ev_application_save_session_crashed (application);
-	g_signal_connect_swapped (new_window, "destroy",
-				  G_CALLBACK (save_session_crashed_in_idle),
-				  application);
-#endif
-
 	if (!GTK_WIDGET_REALIZED (new_window))
 		gtk_widget_realize (new_window);
-	
+
 #ifdef GDK_WINDOWING_X11
 	if (timestamp <= 0)
 		timestamp = gdk_x11_get_server_time (GTK_WIDGET (new_window)->window);
 	gdk_x11_window_set_user_time (GTK_WIDGET (new_window)->window, timestamp);
-	
+
 	gtk_window_present (GTK_WINDOW (new_window));
 #else
 	gtk_window_present_with_time (GTK_WINDOW (new_window), timestamp);
 #endif /* GDK_WINDOWING_X11 */
-
-	return TRUE;
 }
 
 /**
@@ -725,6 +547,152 @@ ev_application_get_uri_window (EvApplication *application, const char *uri)
 	return uri_window;
 }
 
+#ifdef ENABLE_DBUS
+static gboolean
+ev_application_register_uri (EvApplication *application,
+			     const gchar   *uri,
+			     GHashTable    *args,
+			     guint          timestamp)
+{
+	DBusGProxy *proxy;
+	gchar      *owner;
+	gboolean    retval = TRUE;
+	GError     *error = NULL;
+
+	if (!application->connection)
+		return TRUE;
+
+	proxy = dbus_g_proxy_new_for_name (application->connection,
+					   "org.gnome.evince.Daemon",
+					   "/org/gnome/evince/Daemon",
+					   "org.gnome.evince.Daemon");
+	if (!dbus_g_proxy_call (proxy, "RegisterDocument", &error,
+				G_TYPE_STRING, uri,
+				G_TYPE_INVALID,
+				G_TYPE_STRING, &owner,
+				G_TYPE_INVALID)) {
+		g_warning ("Error registering document: %s\n", error->message);
+		g_error_free (error);
+		g_object_unref (proxy);
+
+		return TRUE;
+	}
+	g_object_unref (proxy);
+
+	if (*owner == ':') {
+		/* Already registered */
+		proxy = dbus_g_proxy_new_for_name_owner (application->connection,
+							 owner,
+							 APPLICATION_DBUS_OBJECT_PATH,
+							 APPLICATION_DBUS_INTERFACE,
+							 &error);
+		if (proxy) {
+			if (!dbus_g_proxy_call (proxy, "OpenURI", &error,
+						G_TYPE_STRING, uri,
+						dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), args,
+						G_TYPE_UINT, timestamp,
+						G_TYPE_INVALID,
+						G_TYPE_INVALID)) {
+				g_warning ("%s", error->message);
+				g_error_free (error);
+			}
+			g_object_unref (proxy);
+		} else {
+			g_warning ("Error creating proxy: %s\n", error->message);
+			g_error_free (error);
+		}
+
+		/* Do not continue opening this document */
+		retval = FALSE;
+	}
+
+	g_free (owner);
+
+	return retval;
+}
+
+static void
+ev_application_unregister_uri (EvApplication *application,
+			       const gchar   *uri)
+{
+	DBusGProxy *proxy;
+	GError     *error = NULL;
+
+	if (!application->connection)
+		return;
+
+	proxy = dbus_g_proxy_new_for_name (application->connection,
+					   "org.gnome.evince.Daemon",
+					   "/org/gnome/evince/Daemon",
+					   "org.gnome.evince.Daemon");
+	if (!dbus_g_proxy_call (proxy, "UnregisterDocument", &error,
+				G_TYPE_STRING, uri,
+				G_TYPE_INVALID,
+				G_TYPE_INVALID)) {
+		g_warning ("Error unregistering document: %s\n", error->message);
+		g_error_free (error);
+	}
+
+	g_object_unref (proxy);
+}
+
+static void
+ev_application_window_destroyed (EvApplication *application,
+				 EvWindow      *ev_window)
+{
+	gchar *uri = g_hash_table_lookup (application->windows, ev_window);
+
+	ev_application_unregister_uri (application, uri);
+	g_hash_table_remove (application->windows, ev_window);
+}
+#endif /* ENABLE_DBUS */
+
+static void
+ev_application_open_uri_in_window (EvApplication  *application,
+				   const char     *uri,
+				   EvWindow       *ev_window,
+				   GdkScreen      *screen,
+				   EvLinkDest     *dest,
+				   EvWindowRunMode mode,
+				   const gchar    *search_string,
+				   guint           timestamp)
+{
+	if (screen) {
+		ev_stock_icons_set_screen (screen);
+		gtk_window_set_screen (GTK_WINDOW (ev_window), screen);
+	}
+
+	/* We need to load uri before showing the window, so
+	   we can restore window size without flickering */
+	ev_window_open_uri (ev_window, uri, dest, mode, search_string);
+
+#ifdef ENABLE_DBUS
+	if (!g_hash_table_lookup (application->windows, ev_window)) {
+		g_hash_table_insert (application->windows, ev_window, g_strdup (uri));
+		g_signal_connect_swapped (ev_window, "destroy",
+					  G_CALLBACK (ev_application_window_destroyed),
+					  application);
+	}
+#endif
+
+	if (!GTK_WIDGET_REALIZED (GTK_WIDGET (ev_window)))
+		gtk_widget_realize (GTK_WIDGET (ev_window));
+
+#ifdef GDK_WINDOWING_X11
+	if (timestamp <= 0)
+		timestamp = gdk_x11_get_server_time (GTK_WIDGET (ev_window)->window);
+	gdk_x11_window_set_user_time (GTK_WIDGET (ev_window)->window, timestamp);
+
+	ev_document_fc_mutex_lock ();
+	gtk_window_present (GTK_WINDOW (ev_window));
+	ev_document_fc_mutex_unlock ();
+#else
+	ev_document_fc_mutex_lock ();
+	gtk_window_present_with_time (GTK_WINDOW (ev_window), timestamp);
+	ev_document_fc_mutex_unlock ();
+#endif /* GDK_WINDOWING_X11 */
+}
+
 /**
  * ev_application_open_uri_at_dest:
  * @application: The instance of the application.
@@ -743,52 +711,37 @@ ev_application_open_uri_at_dest (EvApplication  *application,
 				 const gchar    *search_string,
 				 guint           timestamp)
 {
-	EvWindow *new_window;
+	EvWindow *ev_window;
 
 	g_return_if_fail (uri != NULL);
-	
-	new_window = ev_application_get_uri_window (application, uri);
-	
-	if (new_window == NULL) {
-		new_window = ev_application_get_empty_window (application, screen);
-	}
 
-	if (new_window == NULL) {
-		new_window = EV_WINDOW (ev_window_new ());
+	ev_window = ev_application_get_uri_window (application, uri);
+#ifdef ENABLE_DBUS
+	if (!ev_window) {
+		GHashTable *args = build_args (screen, dest, mode, search_string);
+		gboolean    ret;
+
+		/* Register the uri or send OpenURI to
+		 * remote instance if already registered
+		 */
+		ret = ev_application_register_uri (application, uri, args, timestamp);
+		g_hash_table_destroy (args);
+		if (!ret)
+			return;
 	}
+#endif /* ENABLE_DBUS */
 
-	if (screen) {
-		ev_stock_icons_set_screen (screen);
-		gtk_window_set_screen (GTK_WINDOW (new_window), screen);
+	if (ev_window == NULL) {
+		ev_window = ev_application_get_empty_window (application, screen);
 	}
 
-	/* We need to load uri before showing the window, so
-	   we can restore window size without flickering */	
-	ev_window_open_uri (new_window, uri, dest, mode, search_string);
-
-#ifdef ENABLE_DBUS
-	ev_application_save_session_crashed (application);
-	g_signal_connect_swapped (new_window, "destroy",
-				  G_CALLBACK (save_session_crashed_in_idle),
-				  application);
-#endif
-
-	if (!GTK_WIDGET_REALIZED (GTK_WIDGET (new_window)))
-		gtk_widget_realize (GTK_WIDGET (new_window));
-
-#ifdef GDK_WINDOWING_X11
-	if (timestamp <= 0)
-		timestamp = gdk_x11_get_server_time (GTK_WIDGET (new_window)->window);
-	gdk_x11_window_set_user_time (GTK_WIDGET (new_window)->window, timestamp);
+	if (ev_window == NULL) {
+		ev_window = EV_WINDOW (ev_window_new ());
+	}
 
-	ev_document_fc_mutex_lock ();
-	gtk_window_present (GTK_WINDOW (new_window));
-	ev_document_fc_mutex_unlock ();
-#else
-	ev_document_fc_mutex_lock ();
-	gtk_window_present_with_time (GTK_WINDOW (new_window), timestamp);
-	ev_document_fc_mutex_unlock ();
-#endif /* GDK_WINDOWING_X11 */
+	ev_application_open_uri_in_window (application, uri, ev_window,
+					   screen, dest, mode, search_string,
+					   timestamp);
 }
 
 /**
@@ -799,28 +752,32 @@ ev_application_open_uri_at_dest (EvApplication  *application,
  * @timestamp: Current time value.
  * @error: The #GError facility.
  */
-gboolean
+static gboolean
 ev_application_open_uri (EvApplication  *application,
 			 const char     *uri,
 			 GHashTable     *args,
 			 guint           timestamp,
 			 GError        **error)
 {
+	EvWindow        *ev_window;
 	EvLinkDest      *dest = NULL;
 	EvWindowRunMode  mode = EV_WINDOW_MODE_NORMAL;
 	const gchar     *search_string = NULL;
 	GdkScreen       *screen = NULL;
 
+	ev_window = ev_application_get_uri_window (application, uri);
+	g_assert (ev_window != NULL);
+
 	if (args) {
 		screen = get_screen_from_args (args);
 		dest = get_destination_from_args (args);
 		mode = get_window_run_mode_from_args (args);
 		search_string = get_find_string_from_args (args);
 	}
-	
-	ev_application_open_uri_at_dest (application, uri, screen,
-					 dest, mode, search_string,
-					 timestamp);
+
+	ev_application_open_uri_in_window (application, uri, ev_window,
+					   screen, dest, mode, search_string,
+					   timestamp);
 
 	if (dest)
 		g_object_unref (dest);
@@ -847,10 +804,9 @@ void
 ev_application_shutdown (EvApplication *application)
 {
 #ifdef ENABLE_DBUS
-	if (application->crashed_file) {
-		ev_application_save_session_crashed (application);
-		g_free (application->crashed_file);
-		application->crashed_file = NULL;
+	if (application->windows) {
+		g_hash_table_destroy (application->windows);
+		application->windows = NULL;
 	}
 #endif
 
@@ -909,6 +865,10 @@ ev_application_shutdown (EvApplication *application)
 static void
 ev_application_class_init (EvApplicationClass *ev_application_class)
 {
+#ifdef ENABLE_DBUS
+	dbus_g_object_type_install_info (EV_TYPE_APPLICATION,
+					 &dbus_glib_ev_application_object_info);
+#endif
 }
 
 static void
@@ -917,6 +877,7 @@ ev_application_init (EvApplication *ev_application)
 	gint i;
 	const gchar *home_dir;
 	gchar *toolbar_path;
+	GError *error = NULL;
 
         ev_application->dot_dir = g_build_filename (g_get_home_dir (),
                                                     ".gnome2",
@@ -988,6 +949,20 @@ ev_application_init (EvApplication *ev_application)
 				      EGG_TB_MODEL_NOT_REMOVABLE);
 
 #ifdef ENABLE_DBUS
+	ev_application->connection = dbus_g_bus_get (DBUS_BUS_STARTER, &error);
+	if (ev_application->connection) {
+		dbus_g_connection_register_g_object (ev_application->connection,
+						     APPLICATION_DBUS_OBJECT_PATH,
+						     G_OBJECT (ev_application));
+		ev_application->windows = g_hash_table_new_full (g_direct_hash,
+								 g_direct_equal,
+								 NULL,
+								 (GDestroyNotify)g_free);
+		ev_application->scr_saver = totem_scrsaver_new (ev_application->connection);
+	} else {
+		g_warning ("Error connection to DBus: %s\n", error->message);
+		g_error_free (error);
+	}
 	ev_application->keys = ev_media_player_keys_new ();
 #endif /* ENABLE_DBUS */
 }
diff --git a/shell/ev-application.h b/shell/ev-application.h
index 821f9c5..20a60bb 100644
--- a/shell/ev-application.h
+++ b/shell/ev-application.h
@@ -55,15 +55,9 @@ void	          ev_application_shutdown	     (EvApplication   *application);
 
 gboolean          ev_application_load_session        (EvApplication   *application,
 						      const gchar    **files);
-gboolean          ev_application_open_window         (EvApplication   *application,
-						      GHashTable      *args,
-						      guint32          timestamp,
-						      GError         **error);
-gboolean          ev_application_open_uri            (EvApplication   *application,
-						      const char      *uri,
-						      GHashTable      *args,
-						      guint            timestamp,
-						      GError         **error);
+void              ev_application_open_window         (EvApplication   *application,
+						      GdkScreen       *screen,
+						      guint32          timestamp);
 void              ev_application_open_uri_at_dest    (EvApplication   *application,
 						      const char      *uri,
 						      GdkScreen       *screen,
@@ -94,7 +88,7 @@ GtkPageSetup     *ev_application_get_page_setup      (EvApplication   *applicati
 void              ev_application_set_page_setup      (EvApplication   *application,
 						      GtkPageSetup    *page_setup);
 const gchar      *ev_application_get_dot_dir         (EvApplication   *application);
-const gchar      *ev_application_get_data_dir         (EvApplication   *application);
+const gchar      *ev_application_get_data_dir        (EvApplication   *application);
 
 G_END_DECLS
 
diff --git a/shell/ev-daemon-service.xml b/shell/ev-daemon-service.xml
new file mode 100644
index 0000000..5c90b69
--- /dev/null
+++ b/shell/ev-daemon-service.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/org/gnome/evince/Daemon">
+
+  <interface name="org.gnome.evince.Daemon">
+    <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="ev_daemon"/>
+
+    <method name="RegisterDocument">
+       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+       <arg type="s" name="uri" direction="in"/>
+       <arg type="s" name="owner" direction="out"/>
+    </method>
+
+    <method name="UnregisterDocument">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg type="s" name="uri" direction="in"/>
+    </method>
+
+  </interface>
+
+</node>
diff --git a/shell/ev-daemon.c b/shell/ev-daemon.c
new file mode 100644
index 0000000..c5b9c6d
--- /dev/null
+++ b/shell/ev-daemon.c
@@ -0,0 +1,442 @@
+/* ev-metadata.c
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2009 Carlos Garcia Campos  <carlosgc gnome org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dbus/dbus-glib-bindings.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#define EV_DBUS_DAEMON_NAME        "org.gnome.evince.Daemon"
+#define EV_DBUS_DAEMON_OBJECT_PATH "/org/gnome/evince/Daemon"
+
+#define EV_TYPE_DAEMON                     (ev_daemon_get_type ())
+#define EV_DAEMON(object)                  (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_DAEMON, EvDaemon))
+#define EV_DAEMON_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_DAEMON, EvDaemonClass))
+#define EV_IS_DAEMON(object)               (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_DAEMON))
+
+typedef struct _EvDaemon      EvDaemon;
+typedef struct _EvDaemonClass EvDaemonClass;
+
+struct _EvDaemon {
+	GObject base;
+
+	DBusGProxy *bus_proxy;
+
+	GList      *docs;
+	guint       n_docs;
+
+	guint       timer_id;
+};
+
+struct _EvDaemonClass {
+	GObjectClass base_class;
+};
+
+static GType    ev_daemon_get_type            (void) G_GNUC_CONST;
+static gboolean ev_daemon_register_document   (EvDaemon              *ev_daemon,
+					       const gchar           *uri,
+					       DBusGMethodInvocation *context);
+static gboolean ev_daemon_unregister_document (EvDaemon              *ev_daemon,
+					       const gchar           *uri,
+					       DBusGMethodInvocation *context);
+#include "ev-daemon-service.h"
+
+static EvDaemon *ev_daemon = NULL;
+
+G_DEFINE_TYPE(EvDaemon, ev_daemon, G_TYPE_OBJECT)
+
+typedef struct {
+	gchar *dbus_name;
+	gchar *uri;
+} EvDoc;
+
+static void
+ev_doc_free (EvDoc *doc)
+{
+	if (!doc)
+		return;
+
+	g_free (doc->dbus_name);
+	g_free (doc->uri);
+
+	g_free (doc);
+}
+
+static EvDoc *
+ev_daemon_find_doc (EvDaemon    *ev_daemon,
+		    const gchar *uri)
+{
+	GList *l;
+
+	for (l = ev_daemon->docs; l; l = g_list_next (l)) {
+		EvDoc *doc = (EvDoc *)l->data;
+
+		if (strcmp (doc->uri, uri) == 0)
+			return doc;
+	}
+
+	return NULL;
+}
+
+static void
+ev_daemon_finalize (GObject *object)
+{
+	EvDaemon *ev_daemon = EV_DAEMON (object);
+
+	if (ev_daemon->docs) {
+		g_list_foreach (ev_daemon->docs, (GFunc)ev_doc_free, NULL);
+		g_list_free (ev_daemon->docs);
+		ev_daemon->docs = NULL;
+	}
+
+	if (ev_daemon->bus_proxy) {
+		g_object_unref (ev_daemon->bus_proxy);
+		ev_daemon->bus_proxy = NULL;
+	}
+
+	G_OBJECT_CLASS (ev_daemon_parent_class)->finalize (object);
+}
+
+static void
+ev_daemon_init (EvDaemon *ev_daemon)
+{
+}
+
+static void
+ev_daemon_class_init (EvDaemonClass *klass)
+{
+	GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+
+	g_object_class->finalize = ev_daemon_finalize;
+
+	dbus_g_object_type_install_info (EV_TYPE_DAEMON,
+					 &dbus_glib_ev_daemon_object_info);
+}
+
+static gboolean
+ev_daemon_shutdown (EvDaemon *ev_daemon)
+{
+	g_object_unref (ev_daemon);
+
+	return FALSE;
+}
+
+static void
+ev_daemon_stop_killtimer (EvDaemon *ev_daemon)
+{
+	if (ev_daemon->timer_id > 0)
+		g_source_remove (ev_daemon->timer_id);
+	ev_daemon->timer_id = 0;
+}
+
+static void
+ev_daemon_start_killtimer (EvDaemon *ev_daemon)
+{
+	ev_daemon_stop_killtimer (ev_daemon);
+	ev_daemon->timer_id =
+		g_timeout_add_seconds (30,
+				       (GSourceFunc) ev_daemon_shutdown,
+				       ev_daemon);
+}
+
+static void
+ev_daemon_name_owner_changed (DBusGProxy  *proxy,
+			      const gchar *name,
+			      const gchar *old_owner,
+			      const gchar *new_owner,
+			      EvDaemon    *ev_daemon)
+{
+	GList *l, *next = NULL;
+
+	if (*name == ':' && *new_owner == '\0') {
+		for (l = ev_daemon->docs; l; l = next) {
+			EvDoc *doc = (EvDoc *)l->data;
+
+			next = l->next;
+			if (strcmp (doc->dbus_name, name) == 0) {
+				ev_doc_free (doc);
+				ev_daemon->docs = g_list_delete_link (ev_daemon->docs, l);
+				if (--ev_daemon->n_docs == 0)
+					ev_daemon_start_killtimer (ev_daemon);
+			}
+		}
+	}
+}
+
+static EvDaemon *
+ev_daemon_get (void)
+{
+	DBusGConnection *connection;
+	guint            request_name_result;
+	GError          *error = NULL;
+
+	if (ev_daemon)
+		return ev_daemon;
+
+	connection = dbus_g_bus_get (DBUS_BUS_STARTER, &error);
+	if (!connection) {
+		g_printerr ("Failed to connect to the D-BUS daemon: %s\n", error->message);
+		g_error_free (error);
+
+		return NULL;
+	}
+
+	ev_daemon = g_object_new (EV_TYPE_DAEMON, NULL);
+
+	ev_daemon->bus_proxy = dbus_g_proxy_new_for_name (connection,
+						       DBUS_SERVICE_DBUS,
+						       DBUS_PATH_DBUS,
+						       DBUS_INTERFACE_DBUS);
+	if (!org_freedesktop_DBus_request_name (ev_daemon->bus_proxy,
+						EV_DBUS_DAEMON_NAME,
+						DBUS_NAME_FLAG_DO_NOT_QUEUE,
+						&request_name_result, &error)) {
+		g_printerr ("Failed to acquire daemon name: %s", error->message);
+		g_error_free (error);
+		g_object_unref (ev_daemon);
+
+		return NULL;
+	}
+
+	switch (request_name_result) {
+	case DBUS_REQUEST_NAME_REPLY_EXISTS:
+		g_printerr ("Evince daemon already running, exiting.\n");
+		g_object_unref (ev_daemon);
+
+		return NULL;
+	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+		dbus_g_connection_register_g_object (connection,
+						     EV_DBUS_DAEMON_OBJECT_PATH,
+						     G_OBJECT (ev_daemon));
+		break;
+	default:
+		g_printerr ("Not primary owner of the service, exiting.\n");
+		g_object_unref (ev_daemon);
+
+		return NULL;
+	}
+
+
+	dbus_g_proxy_add_signal (ev_daemon->bus_proxy,
+				 "NameOwnerChanged",
+				 G_TYPE_STRING,
+				 G_TYPE_STRING,
+				 G_TYPE_STRING,
+				 G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (ev_daemon->bus_proxy, "NameOwnerChanged",
+				     G_CALLBACK (ev_daemon_name_owner_changed),
+				     ev_daemon, NULL);
+	ev_daemon_start_killtimer (ev_daemon);
+
+	return ev_daemon;
+}
+
+
+
+static gboolean
+ev_daemon_register_document (EvDaemon              *ev_daemon,
+			     const gchar           *uri,
+			     DBusGMethodInvocation *method)
+{
+	EvDoc       *doc;
+	const gchar *owner = NULL;
+
+	doc = ev_daemon_find_doc (ev_daemon, uri);
+	if (doc) {
+		/* Already registered */
+		owner = doc->dbus_name;
+	} else {
+		doc = g_new (EvDoc, 1);
+		doc->dbus_name = dbus_g_method_get_sender (method);
+		doc->uri = g_strdup (uri);
+		ev_daemon->docs = g_list_prepend (ev_daemon->docs, doc);
+		if (ev_daemon->n_docs++ == 0)
+			ev_daemon_stop_killtimer (ev_daemon);
+	}
+
+	dbus_g_method_return (method, owner);
+
+	return TRUE;
+}
+
+static gboolean
+ev_daemon_unregister_document (EvDaemon              *ev_daemon,
+			       const gchar           *uri,
+			       DBusGMethodInvocation *method)
+{
+	EvDoc *doc;
+	gchar *sender;
+
+	doc = ev_daemon_find_doc (ev_daemon, uri);
+	if (!doc) {
+		g_warning ("Document %s is not registered\n", uri);
+		dbus_g_method_return (method);
+
+		return TRUE;
+	}
+
+	sender = dbus_g_method_get_sender (method);
+	if (strcmp (doc->dbus_name, sender) != 0) {
+		g_warning ("Failed to unregister document %s: invalid owner %s, expected %s\n",
+			   uri, sender, doc->dbus_name);
+		g_free (sender);
+		dbus_g_method_return (method);
+
+		return TRUE;
+	}
+	g_free (sender);
+
+	ev_daemon->docs = g_list_remove (ev_daemon->docs, doc);
+	ev_doc_free (doc);
+	if (--ev_daemon->n_docs == 0)
+		ev_daemon_start_killtimer (ev_daemon);
+
+	dbus_g_method_return (method);
+
+	return TRUE;
+}
+
+static void
+do_exit (GMainLoop *loop,
+	 GObject   *object)
+{
+	if (g_main_loop_is_running (loop))
+		g_main_loop_quit (loop);
+}
+
+static gboolean
+convert_metadata (const gchar *metadata)
+{
+	GFile   *file;
+	gchar   *cmd;
+	gint     exit_status;
+	GFileAttributeInfoList *namespaces;
+	gboolean supported = FALSE;
+	GError  *error = NULL;
+	gboolean retval;
+
+	/* If metadata is not supported for a local file
+	 * is likely because and old gvfs version is running.
+	 */
+	file = g_file_new_for_path (metadata);
+	namespaces = g_file_query_writable_namespaces (file, NULL, NULL);
+	if (namespaces) {
+		gint i;
+
+		for (i = 0; i < namespaces->n_infos; i++) {
+			if (strcmp (namespaces->infos[i].name, "metadata") == 0) {
+				supported = TRUE;
+				break;
+			}
+		}
+		g_file_attribute_info_list_unref (namespaces);
+	}
+	if (!supported) {
+		g_warning ("%s\n",
+			   "GVFS metadata not supported, "
+			   "Evince will run without metadata support");
+		g_object_unref (file);
+		return FALSE;
+	}
+	g_object_unref (file);
+
+	cmd = g_strdup_printf ("%s %s", LIBEXECDIR"/evince-convert-metadata", metadata);
+
+	retval = g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error);
+	g_free (cmd);
+
+	if (!retval) {
+		g_printerr ("Error migrating metadata: %s\n", error->message);
+		g_error_free (error);
+	}
+
+	return retval && exit_status == 0;
+}
+
+static void
+ev_migrate_metadata (void)
+{
+	gchar *updated;
+	gchar *metadata;
+	gchar *dot_dir;
+
+	dot_dir = g_build_filename (g_get_home_dir (),
+				    ".gnome2",
+				    "evince",
+				    NULL);
+
+	updated = g_build_filename (dot_dir, "migrated-to-gvfs", NULL);
+	if (g_file_test (updated, G_FILE_TEST_EXISTS)) {
+		/* Already migrated */
+		g_free (updated);
+		g_free (dot_dir);
+		return;
+	}
+
+	metadata = g_build_filename (dot_dir, "ev-metadata.xml", NULL);
+	if (g_file_test (metadata, G_FILE_TEST_EXISTS)) {
+		if (convert_metadata (metadata)) {
+			gint fd;
+
+			fd = g_creat (updated, 0600);
+			if (fd != -1) {
+				close (fd);
+			}
+		}
+	}
+
+	g_free (dot_dir);
+	g_free (updated);
+	g_free (metadata);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	GMainLoop *loop;
+
+	/* Init glib threads asap */
+	if (!g_thread_supported ())
+		g_thread_init (NULL);
+
+	g_type_init ();
+
+	if (!ev_daemon_get ())
+		return 1;
+
+	ev_migrate_metadata ();
+
+	loop = g_main_loop_new (NULL, FALSE);
+	g_object_weak_ref (G_OBJECT (ev_daemon),
+			   (GWeakNotify) do_exit,
+			   loop);
+	g_main_loop_run (loop);
+	g_main_loop_unref (loop);
+
+	return 0;
+}
diff --git a/shell/main.c b/shell/main.c
index a84c17f..1de87f6 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -26,20 +26,7 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
-#ifndef G_OS_WIN32
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#endif
-
-#ifdef ENABLE_DBUS
-#include <gdk/gdkx.h>
-#include <dbus/dbus-glib-bindings.h>
-#endif
-
 #include "ev-application.h"
-#include "ev-backends-manager.h"
 #include "ev-debug.h"
 #include "ev-init.h"
 #include "ev-file-helpers.h"
@@ -154,167 +141,6 @@ launch_previewer (void)
 	return retval;
 }
 
-#ifndef G_OS_WIN32
-static gboolean
-convert_metadata (const gchar *metadata)
-{
-	GFile   *file;
-	gchar   *cmd;
-	gint     exit_status;
-	GError  *error = NULL;
-	gboolean retval;
-
-	/* If metadata is not supported for a local file
-	 * is likely because and old gvfs version is running.
-	 */
-	file = g_file_new_for_path (metadata);
-	if (!ev_is_metadata_supported_for_file (file)) {
-		g_warning ("%s\n",
-			   "GVFS metadata not supported, "
-			   "Evince will run without metadata support");
-		g_object_unref (file);
-		return FALSE;
-	}
-	g_object_unref (file);
-
-	cmd = g_strdup_printf ("%s %s", LIBEXECDIR"/evince-convert-metadata", metadata);
-
-	retval = g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error);
-	g_free (cmd);
-
-	if (!retval) {
-		g_printerr ("Error migrating metadata: %s\n", error->message);
-		g_error_free (error);
-	}
-
-	return retval && exit_status == 0;
-}
-
-static void
-ev_migrate_metadata (void)
-{
-	gchar *updated;
-	gchar *metadata;
-
-	updated = g_build_filename (ev_application_get_dot_dir (EV_APP),
-				    "migrated-to-gvfs", NULL);
-	if (g_file_test (updated, G_FILE_TEST_EXISTS)) {
-		/* Already migrated */
-		g_free (updated);
-		return;
-	}
-
-	metadata = g_build_filename (ev_application_get_dot_dir (EV_APP),
-				     "ev-metadata.xml", NULL);
-	if (g_file_test (metadata, G_FILE_TEST_EXISTS)) {
-		if (convert_metadata (metadata)) {
-			gint fd;
-
-			fd = g_creat (updated, 0600);
-			if (fd != -1) {
-				close (fd);
-			}
-		}
-	}
-
-	g_free (updated);
-	g_free (metadata);
-}
-#endif /* !G_OS_WIN32 */
-
-static void
-value_free (GValue *value)
-{
-	g_value_unset (value);
-	g_free (value);
-}
-
-/**
- * arguments_parse:
- *
- * Parses the arguments and creates a #GHashTable with this data.
- *
- *  key                 ->  value
- *
- *  dislay              ->  display at the default screen.
- *  screen              ->  screen number.
- *  page-label          ->  only if the page label argument has been passed,
- *                          the page of the document to display.
- *  mode                ->  only if the view mode is one of the availables,
- *                          the view mode.
- *
- * Returns: a pointer into #GHashTable with data from the arguments.
- */
-static GHashTable *
-arguments_parse (void)
-{
-	GHashTable      *args;
-	GValue          *value;
-	EvWindowRunMode  mode;
-	GdkScreen       *screen;
-	GdkDisplay      *display;
-	const gchar     *display_name;
-	gint             screen_number;
-
-	args = g_hash_table_new_full (g_str_hash,
-				      g_str_equal,
-				      (GDestroyNotify)g_free,
-				      (GDestroyNotify)value_free);
-	
-	screen = gdk_screen_get_default ();
-	display = gdk_screen_get_display (screen);
-
-	display_name = gdk_display_get_name (display);
-	screen_number = gdk_screen_get_number (screen);
-
-	value = g_new0 (GValue, 1);
-	g_value_init (value, G_TYPE_STRING);
-	g_value_set_string (value, display_name);
-	g_hash_table_insert (args, g_strdup ("display"), value);
-
-	value = g_new0 (GValue, 1);
-	g_value_init (value, G_TYPE_INT);
-	g_value_set_int (value, screen_number);
-	g_hash_table_insert (args, g_strdup ("screen"), value);
-
-	if (ev_page_label) {
-		value = g_new0 (GValue, 1);
-		g_value_init (value, G_TYPE_STRING);
-		g_value_set_string (value, ev_page_label);
-
-		g_hash_table_insert (args, g_strdup ("page-label"), value);
-
-		g_free (ev_page_label);
-		ev_page_label = NULL;
-	}
-
-	if (ev_find_string) {
-		value = g_new0 (GValue, 1);
-		g_value_init (value, G_TYPE_STRING);
-		g_value_set_string (value, ev_find_string);
-
-		g_hash_table_insert (args, g_strdup ("find-string"), value);
-
-		g_free (ev_find_string);
-		ev_page_label = NULL;
-	}
-
-	if (fullscreen_mode)
-		mode = EV_WINDOW_MODE_FULLSCREEN;
-	else if (presentation_mode)
-		mode = EV_WINDOW_MODE_PRESENTATION;
-	else
-		return args;
-
-	value = g_new0 (GValue, 1);
-	g_value_init (value, G_TYPE_UINT);
-	g_value_set_uint (value, mode);
-
-	g_hash_table_insert (args, g_strdup ("mode"), value);
-
-	return args;
-}
-
 static gint
 find_window_list (EvWindow    *window,
 		  const gchar *uri)
@@ -323,27 +149,37 @@ find_window_list (EvWindow    *window,
 }
 
 static void
-load_files (const char **files,
-	    GHashTable  *args)
+load_files (const char **files)
 {
-	int    i;
-	GList *windows;
+	GdkScreen       *screen = gdk_screen_get_default ();
+	EvWindowRunMode  mode = EV_WINDOW_MODE_NORMAL;
+	GList           *windows;
+	gint             i;
+	EvLinkDest      *global_dest = NULL;
 
 	windows = ev_application_get_windows (EV_APP);
 
 	if (!files) {
 		if (!windows)
-			ev_application_open_window (EV_APP, args, GDK_CURRENT_TIME, NULL);
+			ev_application_open_window (EV_APP, screen, GDK_CURRENT_TIME);
 		else
 			g_list_free (windows);
 		return;
 	}
 
+	if (ev_page_label)
+		global_dest = ev_link_dest_new_page_label (ev_page_label);
+
+	if (fullscreen_mode)
+		mode = EV_WINDOW_MODE_FULLSCREEN;
+	else if (presentation_mode)
+		mode = EV_WINDOW_MODE_PRESENTATION;
+
 	for (i = 0; files[i]; i++) {
-		char   *uri;
-		char   *label;
-		GValue *old = NULL;
-		GFile  *file;
+		gchar      *uri;
+		gchar      *label;
+		GFile      *file;
+		EvLinkDest *dest = NULL;
 
 		file = g_file_new_for_commandline_arg (files[i]);
 		uri = g_file_get_uri (file);
@@ -355,122 +191,31 @@ load_files (const char **files,
 		}
 
 		label = strchr (uri, '#');
-
 		if (label) {
-			GValue *new;
-
-			*label = 0; label++;
-			
-			old = g_hash_table_lookup (args, "page-label");
-			
-			new = g_new0 (GValue, 1);
-			g_value_init (new, G_TYPE_STRING);
-			g_value_set_string (new, label);
-
-			g_hash_table_insert (args, g_strdup ("page-label"), new);
-
+			*label = 0;
+			label++;
+			dest = ev_link_dest_new_page_label (label);
+		} else if (global_dest) {
+			dest = g_object_ref (global_dest);
 		}
 
-		ev_application_open_uri (EV_APP, uri, args,
-					 GDK_CURRENT_TIME, NULL);
+		ev_application_open_uri_at_dest (EV_APP, uri, screen, dest,
+						 mode, ev_find_string,
+						 GDK_CURRENT_TIME);
 
-		if (old)
-			g_hash_table_insert (args, g_strdup ("page-label"), old);
-		
+		if (dest)
+			g_object_unref (dest);
 		g_free (uri);
         }
 
 	g_list_free (windows);
 }
 
-#ifdef ENABLE_DBUS
-static gboolean
-load_files_remote (const char **files,
-		   GHashTable  *args)
-{
-	int i;
-	GError *error = NULL;
-	DBusGConnection *connection;
-	gboolean result = FALSE;
-	DBusGProxy *remote_object;
-	GdkDisplay *display;
-	guint32 timestamp;
-
-	display = gdk_display_get_default ();
-	timestamp = gdk_x11_display_get_user_time (display);
-	connection = dbus_g_bus_get (DBUS_BUS_STARTER, &error);
-
-	if (connection == NULL) {
-		g_warning ("%s", error->message);
-		g_error_free (error);	
-
-		return FALSE;
-	}
-
-	remote_object = dbus_g_proxy_new_for_name (connection,
-						   "org.gnome.evince.ApplicationService",
-                                                   "/org/gnome/evince/Evince",
-                                                   "org.gnome.evince.Application");
-	if (!files) {
-		if (!dbus_g_proxy_call (remote_object, "OpenWindow", &error,
-					dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), args,
-					G_TYPE_UINT, timestamp,
-					G_TYPE_INVALID,
-					G_TYPE_INVALID)) {
-			g_warning ("%s", error->message);
-			g_clear_error (&error);
-			g_object_unref (remote_object);
-			dbus_g_connection_unref (connection);
-			return FALSE;
-		}
-
-		g_object_unref (remote_object);
-		dbus_g_connection_unref (connection);
-		
-		return TRUE;
-	}
-
-	for (i = 0; files[i]; i++) {
-		const char *page_label;
-		GFile *file;
-		char *uri;
-
-		file = g_file_new_for_commandline_arg (files[i]);
-		uri = g_file_get_uri (file);
-		g_object_unref (file);
-
-		page_label = ev_page_label ? ev_page_label : "";
-
-		if (!dbus_g_proxy_call (remote_object, "OpenURI", &error,
-					G_TYPE_STRING, uri,
-					dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), args,
-					G_TYPE_UINT, timestamp,
-					G_TYPE_INVALID,
-					G_TYPE_INVALID)) {
-			g_warning ("%s", error->message);
-			g_clear_error (&error);
-			g_free (uri);
-			continue;
-		}
-
-		g_free (uri);
-		result = TRUE;
-        }
-
-	g_object_unref (remote_object);
-	dbus_g_connection_unref (connection);
-
-	gdk_notify_startup_complete ();
-
-	return result;
-}
-#endif /* ENABLE_DBUS */
-
 int
 main (int argc, char *argv[])
 {
 	GOptionContext *context;
-	GHashTable *args;
+	GList *toplevels;
 	GError *error = NULL;
 
 #ifdef G_OS_WIN32
@@ -536,25 +281,9 @@ main (int argc, char *argv[])
 		return retval ? 0 : 1;
 	}
 
-	args = arguments_parse ();
-
-#ifdef ENABLE_DBUS
-	if (!ev_application_register_service (EV_APP)) {
-		if (load_files_remote (file_arguments, args)) {
-			g_hash_table_destroy (args);
-
-			return 0;
-		}
-	}
-#endif /* ENABLE_DBUS */
-	
         if (!ev_init ())
                 return 1;
 
-#ifndef G_OS_WIN32
-	ev_migrate_metadata ();
-#endif
-
 	ev_stock_icons_init ();
 
 #if defined(WITH_SMCLIENT) && defined(GDK_WINDOWING_X11)
@@ -566,15 +295,17 @@ main (int argc, char *argv[])
 #endif /* WITH_SMCLIENT && GDK_WINDOWING_X11 */
 
 	ev_application_load_session (EV_APP, file_arguments);
-	load_files (file_arguments, args);
-	g_hash_table_destroy (args);
-
-	/* Change directory so we don't prevent unmounting in case the initial cwd
-	 * is on an external device (see bug #575436)
-	 */
-	g_chdir (g_get_home_dir ());	
-
-	gtk_main ();
+	load_files (file_arguments);
+	toplevels = gtk_window_list_toplevels ();
+	if (toplevels) {
+		g_list_free (toplevels);
+		/* Change directory so we don't prevent unmounting in case the initial cwd
+		 * is on an external device (see bug #575436)
+		 */
+		g_chdir (g_get_home_dir ());
+
+		gtk_main ();
+	}
 
 	ev_shutdown ();
 	ev_stock_icons_shutdown ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]