]> www.fi.muni.cz Git - evince.git/commitdiff
Run evince instances in different processes instead of single instance
authorCarlos Garcia Campos <carlosgc@gnome.org>
Mon, 19 Oct 2009 17:27:45 +0000 (19:27 +0200)
committerCarlos Garcia Campos <carlosgc@gnome.org>
Tue, 20 Oct 2009 16:26:49 +0000 (18:26 +0200)
 - 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
data/Makefile.am
data/org.gnome.evince.Daemon.service.in [new file with mode: 0644]
shell/Makefile.am
shell/ev-application-service.xml
shell/ev-application.c
shell/ev-application.h
shell/ev-daemon-service.xml [new file with mode: 0644]
shell/ev-daemon.c [new file with mode: 0644]
shell/main.c

index 6208b0c718cda84796c06681275762f8fcd8a4ad..096366d60579cd970027f3448e3d835dd69c039c 100644 (file)
@@ -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])],
index 883a3aa697f3ddc1cd6b774fc054866e46d883ed..27ba73d4ac5ae747d4dfa067dc8afbacb5f5a6c5 100644 (file)
@@ -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 (file)
index 0000000..c987f59
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.evince.Daemon
+Exec=@libexecdir@/evinced
index 3b4f6f75cd1a323b6d17278609f3e6b720503be0..8d86efe4451ec3fdd609ec82464ea9b037fdefac 100644 (file)
@@ -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
index f56bf0bac6c464806147a7eab6a56add6f80d4e8..48fc18fd266f4d20bae4f6431be559cf57cf7d36 100644 (file)
@@ -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"/>
index e31b13280667657bda47c8f6693364cbe204fc92..69a5a730e78b79a6044eb3427a7785dcbd21df35 100644 (file)
 
 #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 */
 }
index 821f9c52a2cb809518ab0c9866eabd40ae4d2be0..20a60bbe5493c5ef55a9d9422286f5c2b1cea9d9 100644 (file)
@@ -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 (file)
index 0000000..5c90b69
--- /dev/null
@@ -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 (file)
index 0000000..c5b9c6d
--- /dev/null
@@ -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;
+}
index a84c17fefa6505a3ec2e451f77774c353b6d755f..1de87f6d6be12237f121d6f8ebb65502fb29fd75 100644 (file)
 #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 ();