From 66e5636dcaace0d9a98845490b09721c12ce3d2b Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Mon, 19 Oct 2009 17:27:45 +0000 Subject: 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. --- 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 @@ - - - - - - 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 +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 @@ + + + + + + + + + + + + + + + + + + + + + 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 #include -#ifndef G_OS_WIN32 -#include -#include -#include -#include -#endif - -#ifdef ENABLE_DBUS -#include -#include -#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 (); -- cgit v0.9.1