From 616f5c97013f1344caa6e899de6cc99664faa5e9 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Thu, 30 Jun 2005 08:16:45 +0000 Subject: Add an optional dbus interface (--enable-dbus). Rework application code, 2005-06-24 Marco Pesenti Gritti * shell/ev-application-service.xml: * configure.ac: * shell/Makefile.am: * shell/ev-application.c: * shell/ev-application.h: * shell/ev-window.c: * shell/ev-window.h: * shell/main.c: Add an optional dbus interface (--enable-dbus). Rework application code, mainly to be easier to use "remotely". Do not open multiple windows with the same document, spatial evince! --- (limited to 'shell') diff --git a/shell/Makefile.am b/shell/Makefile.am index c916987..689199e 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -20,6 +20,10 @@ INCLUDES= \ $(EVINCE_DISABLE_DEPRECATED) \ $(NULL) +if ENABLE_DBUS +INCLUDES += $(DBUS_CFLAGS) +endif + bin_PROGRAMS=evince noinst_LTLIBRARIES = libevbackendfactory.la @@ -112,8 +116,16 @@ evince_LDADD= \ libevbackendfactory.la \ $(NULL) +if ENABLE_DBUS +evince_LDADD += $(DBUS_LIBS) +endif + BUILT_SOURCES = ev-marshal.h ev-marshal.c +if ENABLE_DBUS +BUILT_SOURCES += ev-application-service.h +endif + EXTRA_DIST = ev-marshal.list ev-marshal.h: ev-marshal.list @@ -122,3 +134,6 @@ ev-marshal.h: ev-marshal.list ev-marshal.c: ev-marshal.list echo '#include "ev-marshal.h"' > ev-marshal.c glib-genmarshal --prefix=ev_marshal ev-marshal.list --body >> ev-marshal.c + +ev-application-service.h: ev-application-service.xml + dbus-binding-tool --mode=glib-server --output=ev-application-service.h $(srcdir)/ev-application-service.xml diff --git a/shell/ev-application-service.xml b/shell/ev-application-service.xml new file mode 100644 index 0000000..68a63e2 --- /dev/null +++ b/shell/ev-application-service.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/shell/ev-application.c b/shell/ev-application.c index ef478e0..6a106fc 100644 --- a/shell/ev-application.c +++ b/shell/ev-application.c @@ -35,146 +35,181 @@ #include #include #include +#include -struct _EvApplicationPrivate { - GList *windows; -}; +#ifdef ENABLE_DBUS +#include "ev-application-service.h" +#include +#endif G_DEFINE_TYPE (EvApplication, ev_application, G_TYPE_OBJECT); #define EV_APPLICATION_GET_PRIVATE(object) \ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_APPLICATION, EvApplicationPrivate)) +#define APPLICATION_SERVICE_NAME "org.gnome.evince.ApplicationService" + +#ifdef ENABLE_DBUS +gboolean +ev_application_register_service (EvApplication *application) +{ + DBusGConnection *connection; + DBusGProxy *driver_proxy; + GError *err = NULL; + guint request_name_result; + + connection = dbus_g_bus_get (DBUS_BUS_STARTER, &err); + if (connection == NULL) { + g_warning ("Service registration failed."); + } + + 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, + 0, &request_name_result, &err)) + { + g_warning ("Service registration failed."); + } + + if (request_name_result == DBUS_REQUEST_NAME_REPLY_EXISTS) { + return FALSE; + } + + dbus_g_object_class_install_info (G_OBJECT_GET_CLASS (application), + &dbus_glib_ev_application_object_info); + dbus_g_connection_register_g_object (connection, + "/org/gnome/evince/Evince", + G_OBJECT (application)); + + return TRUE; +} +#endif + EvApplication * ev_application_get_instance (void) { static EvApplication *instance; - if (!instance) - instance = EV_APPLICATION ( - g_object_new (EV_TYPE_APPLICATION, NULL)); + if (!instance) { + instance = EV_APPLICATION (g_object_new (EV_TYPE_APPLICATION, NULL)); + } return instance; } -static void -window_destroy_cb (GtkObject *object, gpointer user_data) +void +ev_application_open_window (EvApplication *application) { - EvApplication *application; - - g_return_if_fail (EV_IS_WINDOW (object)); - g_return_if_fail (EV_IS_APPLICATION (user_data)); - - application = EV_APPLICATION (user_data); - application->priv->windows = - g_list_remove (application->priv->windows, object); - - if (application->priv->windows == NULL) - gtk_main_quit (); + gtk_widget_show (ev_window_new ()); } -EvWindow * -ev_application_new_window (EvApplication *application) +static EvWindow * +ev_application_get_empty_window (EvApplication *application) { - EvWindow *ev_window; - - ev_window = EV_WINDOW (g_object_new (EV_TYPE_WINDOW, - "type", GTK_WINDOW_TOPLEVEL, - "default-height", 600, - "default-width", 600, - NULL)); - application->priv->windows = - g_list_prepend (application->priv->windows, ev_window); - g_signal_connect (G_OBJECT (ev_window), "destroy", - G_CALLBACK (window_destroy_cb), application); - - return ev_window; + EvWindow *empty_window = NULL; + GList *windows = gtk_window_list_toplevels (); + GList *l; + + for (l = windows; l != NULL; l = l->next) { + if (EV_IS_WINDOW (l->data)) { + EvWindow *window = EV_WINDOW (l->data); + + if (ev_window_is_empty (window)) { + empty_window = window; + break; + } + } + } + + g_list_free (windows); + + return empty_window; } -static int -is_window_empty (const EvWindow *ev_window, gconstpointer dummy) +static EvWindow * +ev_application_get_uri_window (EvApplication *application, const char *uri) { - g_return_val_if_fail (EV_IS_WINDOW (ev_window), 0); + EvWindow *uri_window = NULL; + GList *windows = gtk_window_list_toplevels (); + GList *l; + + g_return_val_if_fail (uri != NULL, NULL); + + for (l = windows; l != NULL; l = l->next) { + if (EV_IS_WINDOW (l->data)) { + EvWindow *window = EV_WINDOW (l->data); + const char *window_uri = ev_window_get_uri (window); + + if (window_uri && strcmp (window_uri, uri) == 0) { + uri_window = window; + break; + } + } + } - return ev_window_is_empty (ev_window) - ? 0 - : -1; + g_list_free (windows); + + return uri_window; } -EvWindow * -ev_application_get_empty_window (EvApplication *application) +void +ev_application_open_uri (EvApplication *application, + const char *uri, + const char *page_label) { - GList *node; + EvWindow *new_window; + + g_return_if_fail (uri != NULL); - node = g_list_find_custom (application->priv->windows, NULL, - (GCompareFunc)is_window_empty); + new_window = ev_application_get_uri_window (application, uri); + if (new_window != NULL) { + gtk_window_present (GTK_WINDOW (new_window)); + return; + } - return node && node->data - ? EV_WINDOW (node->data) - : ev_application_new_window (application); + new_window = ev_application_get_empty_window (application); + + if (new_window == NULL) { + new_window = EV_WINDOW (ev_window_new ()); + } + + gtk_window_present (GTK_WINDOW (new_window)); + + ev_window_open_uri (new_window, uri); + + if (page_label != NULL) { + ev_window_open_page_label (new_window, page_label); + } } void -ev_application_open (EvApplication *application, GError *err) +ev_application_open_uri_list (EvApplication *application, GSList *uri_list) { - EvWindow *ev_window; - GtkWidget *chooser; - static char *folder = NULL; - - ev_window = ev_application_get_empty_window (application); - - chooser = gtk_file_chooser_dialog_new (_("Open document"), - GTK_WINDOW (ev_window), - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_OK, - NULL); - - if (folder) { - gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (chooser), - folder); - } - - ev_document_types_add_filters (chooser); - gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), TRUE); - gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), FALSE); - - if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) { - GSList *uris; - - uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser)); - - if (folder != NULL) - g_free (folder); - - folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (chooser)); - - ev_window_open_uri_list (ev_window, uris); - - g_slist_free (uris); - } else { - if (!GTK_WIDGET_VISIBLE (ev_window)) - gtk_widget_destroy (GTK_WIDGET (ev_window)); + GSList *l; + + for (l = uri_list; l != NULL; l = l->next) { + ev_application_open_uri (application, (char *)l->data, NULL); } +} - gtk_widget_destroy (GTK_WIDGET (chooser)); +void +ev_application_shutdown (EvApplication *application) +{ + g_object_unref (application); + gtk_main_quit (); } static void ev_application_class_init (EvApplicationClass *ev_application_class) { - GObjectClass *g_object_class; - - g_object_class = G_OBJECT_CLASS (ev_application_class); - - g_type_class_add_private (g_object_class, - sizeof (EvApplicationPrivate)); } static void ev_application_init (EvApplication *ev_application) { - ev_application->priv = EV_APPLICATION_GET_PRIVATE (ev_application); } diff --git a/shell/ev-application.h b/shell/ev-application.h index 1d70124..ddf5ede 100644 --- a/shell/ev-application.h +++ b/shell/ev-application.h @@ -44,20 +44,23 @@ typedef struct _EvApplicationPrivate EvApplicationPrivate; #define EV_APP (ev_application_get_instance ()) struct _EvApplication { - GObject base_instance; - EvApplicationPrivate *priv; + GObject base_instance; }; struct _EvApplicationClass { - GObjectClass base_class; + GObjectClass base_class; }; -GType ev_application_get_type (void); -EvApplication *ev_application_get_instance (void); -void ev_application_open (EvApplication *application, - GError *err); -EvWindow *ev_application_new_window (EvApplication *application); -EvWindow * ev_application_get_empty_window (EvApplication *application); +GType ev_application_get_type (void); +gboolean ev_application_register_service (EvApplication *application); +EvApplication *ev_application_get_instance (void); +void ev_application_open_window (EvApplication *application); +void ev_application_open_uri (EvApplication *application, + const char *uri, + const char *page_label); +void ev_application_open_uri_list (EvApplication *application, + GSList *uri_list); +void ev_application_shutdown (EvApplication *application); G_END_DECLS diff --git a/shell/ev-window.c b/shell/ev-window.c index 836bc91..11ee1ad 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -932,42 +932,49 @@ ev_window_open_uri (EvWindow *ev_window, const char *uri) TRUE); } -void -ev_window_open_uri_list (EvWindow *ev_window, GSList *uri_list) +static void +ev_window_cmd_file_open (GtkAction *action, EvWindow *window) { - GSList *list; - gchar *uri; - - g_return_if_fail (uri_list != NULL); - - list = uri_list; - while (list) { + GtkWidget *chooser; + static char *folder = NULL; - uri = (gchar *)list->data; - - if (ev_window_is_empty (EV_WINDOW (ev_window))) { - ev_window_open_uri (ev_window, uri); + chooser = gtk_file_chooser_dialog_new (_("Open document"), + GTK_WINDOW (window), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_OK, + NULL); - gtk_widget_show (GTK_WIDGET (ev_window)); - } else { - EvWindow *new_window; + if (folder) { + gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (chooser), + folder); + } - new_window = ev_application_new_window (EV_APP); - ev_window_open_uri (new_window, uri); + ev_document_types_add_filters (chooser); + gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), TRUE); + gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), FALSE); - gtk_widget_show (GTK_WIDGET (new_window)); - } + if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) { + GSList *uris; - g_free (uri); + uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser)); - list = g_slist_next (list); + if (folder != NULL) + g_free (folder); + + folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (chooser)); + + ev_application_open_uri_list (EV_APP, uris); + + g_slist_foreach (uris, (GFunc)g_free, NULL); + g_slist_free (uris); + } else { + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_destroy (GTK_WIDGET (window)); } -} -static void -ev_window_cmd_file_open (GtkAction *action, EvWindow *ev_window) -{ - ev_application_open (EV_APP, NULL); + gtk_widget_destroy (GTK_WIDGET (chooser)); } static void @@ -976,16 +983,13 @@ ev_window_cmd_recent_file_activate (GtkAction *action, { char *uri; EggRecentItem *item; - GtkWidget *window; item = egg_recent_view_uimanager_get_item (ev_window->priv->recent_view, action); uri = egg_recent_item_get_uri (item); - - window = GTK_WIDGET (ev_application_get_empty_window (EV_APP)); - gtk_widget_show (window); - ev_window_open_uri (EV_WINDOW (window), uri); + + ev_application_open_uri (EV_APP, uri, NULL); g_free (uri); } @@ -1196,6 +1200,12 @@ ev_window_print (EvWindow *window) ev_window_print_range (window, 1, -1); } +const char * +ev_window_get_uri (EvWindow *ev_window) +{ + return ev_window->priv->uri; +} + void ev_window_print_range (EvWindow *ev_window, int first_page, int last_page) { @@ -2423,6 +2433,20 @@ zoom_control_changed_cb (EphyZoomAction *action, } static void +ev_window_finalize (GObject *object) +{ + GList *windows = gtk_window_list_toplevels (); + + if (windows == NULL) { + ev_application_shutdown (EV_APP); + } else { + g_list_free (windows); + } + + G_OBJECT_CLASS (ev_window_parent_class)->finalize (object); +} + +static void ev_window_dispose (GObject *object) { EvWindow *window = EV_WINDOW (object); @@ -2522,6 +2546,7 @@ ev_window_class_init (EvWindowClass *ev_window_class) GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (ev_window_class); g_object_class->dispose = ev_window_dispose; + g_object_class->finalize = ev_window_finalize; widget_class->window_state_event = ev_window_state_event; widget_class->focus_in_event = ev_window_focus_in_event; @@ -2714,7 +2739,7 @@ drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, gnome_vfs_uri_list_free (uri_list); - ev_window_open_uri_list (EV_WINDOW (widget), uris); + ev_application_open_uri_list (EV_APP, uris); g_slist_free (uris); @@ -3213,3 +3238,18 @@ ev_window_init (EvWindow *ev_window) update_action_sensitivity (ev_window); } +GtkWidget * +ev_window_new (void) +{ + GtkWidget *ev_window; + + ev_window = GTK_WIDGET (g_object_new (EV_TYPE_WINDOW, + "type", GTK_WINDOW_TOPLEVEL, + "default-width", 600, + "default-height", 600, + NULL)); + + return ev_window; +} + + diff --git a/shell/ev-window.h b/shell/ev-window.h index 6864b71..0368f80 100644 --- a/shell/ev-window.h +++ b/shell/ev-window.h @@ -51,17 +51,17 @@ struct _EvWindowClass { GtkWindowClass base_class; }; -GType ev_window_get_type (void); -void ev_window_open_uri (EvWindow *ev_window, - const char *uri); -void ev_window_open_uri_list (EvWindow *ev_window, - GSList *uris); -void ev_window_open_page_label (EvWindow *ev_window, - const char *label); -gboolean ev_window_is_empty (const EvWindow *ev_window); -void ev_window_print_range (EvWindow *ev_window, - int first_page, - int last_page); +GType ev_window_get_type (void); +GtkWidget *ev_window_new (void); +const char *ev_window_get_uri (EvWindow *ev_window); +void ev_window_open_uri (EvWindow *ev_window, + const char *uri); +void ev_window_open_page_label (EvWindow *ev_window, + const char *label); +gboolean ev_window_is_empty (const EvWindow *ev_window); +void ev_window_print_range (EvWindow *ev_window, + int first_page, + int last_page); G_END_DECLS #endif /* !EV_WINDOW_H */ diff --git a/shell/main.c b/shell/main.c index b0cc803..d412a5e 100644 --- a/shell/main.c +++ b/shell/main.c @@ -29,48 +29,89 @@ #include #include +#ifdef ENABLE_DBUS +#include +#endif + #include "ev-stock-icons.h" #include "ev-debug.h" #include "ev-job-queue.h" #include "ev-file-helpers.h" -static char *page_label; +static char *ev_page_label; static struct poptOption popt_options[] = { - { "page-label", 'p', POPT_ARG_STRING, &page_label, 0, N_("The page of the document to display."), N_("PAGE")}, + { "page-label", 'p', POPT_ARG_STRING, &ev_page_label, 0, N_("The page of the document to display."), N_("PAGE")}, { NULL, 0, 0, NULL, 0, NULL, NULL } }; static void load_files (const char **files) { - GtkWidget *window; int i; if (!files) { - window = GTK_WIDGET (ev_application_new_window (EV_APP)); - gtk_widget_show (window); + ev_application_open_window (EV_APP); return; } for (i = 0; files[i]; i++) { char *uri; - uri = gnome_vfs_make_uri_from_shell_arg (files[i]); + uri = gnome_vfs_make_uri_from_shell_arg (files[i]); + ev_application_open_uri (EV_APP, uri, ev_page_label); + g_free (uri); + } +} - window = GTK_WIDGET (ev_application_new_window (EV_APP)); - gtk_widget_show (window); - ev_window_open_uri (EV_WINDOW (window), uri); - - if (page_label != NULL) - ev_window_open_page_label (EV_WINDOW (window), page_label); +#ifdef ENABLE_DBUS +static void +load_files_remote (const char **files) +{ + int i; + GError *error; + DBusGConnection *connection; + DBusGPendingCall *call; + DBusGProxy *remote_object; + + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (connection == NULL) { + g_warning (error->message); + return; + } + + remote_object = dbus_g_proxy_new_for_name (connection, + "org.gnome.evince.ApplicationService", + "/org/gnome/evince/Evince", + "org.gnome.evince.Application"); + if (!files) { + call = dbus_g_proxy_begin_call (remote_object, "OpenWindow", DBUS_TYPE_INVALID); + if (!dbus_g_proxy_end_call (remote_object, call, &error, DBUS_TYPE_INVALID)) { + g_warning (error->message); + } + return; + } + + for (i = 0; files[i]; i++) { + const char *page_label; + char *uri; + uri = gnome_vfs_make_uri_from_shell_arg (files[i]); + page_label = ev_page_label ? ev_page_label : ""; + + call = dbus_g_proxy_begin_call (remote_object, "OpenURI", + DBUS_TYPE_STRING, &uri, + DBUS_TYPE_STRING, &page_label, + DBUS_TYPE_INVALID); + if (!dbus_g_proxy_end_call (remote_object, call, &error, DBUS_TYPE_INVALID)) { + g_warning (error->message); + } + g_free (uri); } - - g_free (page_label); } +#endif int main (int argc, char *argv[]) @@ -92,6 +133,21 @@ main (int argc, char *argv[]) GNOME_PARAM_HUMAN_READABLE_NAME, _("Evince"), GNOME_PARAM_APP_DATADIR, GNOMEDATADIR, NULL); + g_object_get_property (G_OBJECT (program), + GNOME_PARAM_POPT_CONTEXT, + g_value_init (&context_as_value, G_TYPE_POINTER)); + context = g_value_get_pointer (&context_as_value); + + +#ifdef ENABLE_DBUS + if (!ev_application_register_service (EV_APP)) { + load_files_remote (poptGetArgs (context)); + g_warning ("Another process was running."); + return 0; + } else { + g_warning ("Starting evince process."); + } +#endif ev_job_queue_init (); g_set_application_name (_("Evince Document Viewer")); @@ -101,11 +157,6 @@ main (int argc, char *argv[]) ev_stock_icons_init (); gtk_window_set_default_icon_name ("postscript-viewer"); - g_object_get_property (G_OBJECT (program), - GNOME_PARAM_POPT_CONTEXT, - g_value_init (&context_as_value, G_TYPE_POINTER)); - context = g_value_get_pointer (&context_as_value); - load_files (poptGetArgs (context)); gtk_main (); -- cgit v0.9.1