X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;ds=inline;f=shell%2Fev-daemon.c;h=fa9d506db83ee6b3e32ca7451583952a8df17908;hb=b03015826c22cb2c28a0d0507963c23b9c9ddcb3;hp=315636a3124543f1f09d179e95317550cc4de731;hpb=f480eea33f494d7e28ab82cb2cf6105861886c6a;p=evince.git diff --git a/shell/ev-daemon.c b/shell/ev-daemon.c index 315636a3..fa9d506d 100644 --- a/shell/ev-daemon.c +++ b/shell/ev-daemon.c @@ -1,4 +1,4 @@ -/* ev-metadata.c +/* ev-daemon.c * this file is part of evince, a gnome document viewer * * Copyright (C) 2009 Carlos Garcia Campos @@ -35,15 +35,21 @@ #define EV_DBUS_DAEMON_INTERFACE_NAME "org.gnome.evince.Daemon" #define EV_DBUS_DAEMON_OBJECT_PATH "/org/gnome/evince/Daemon" +#define EV_DBUS_WINDOW_INTERFACE_NAME "org.gnome.evince.Window" + #define DAEMON_TIMEOUT (30) /* seconds */ +#define LOG g_printerr + static GList *ev_daemon_docs = NULL; static guint kill_timer_id; +static GHashTable *pending_invocations = NULL; typedef struct { gchar *dbus_name; gchar *uri; - guint watch_id; + guint watch_id; + guint loaded_id; } EvDoc; static void @@ -88,6 +94,8 @@ ev_daemon_shutdown (gpointer user_data) { GMainLoop *loop = (GMainLoop *) user_data; + LOG ("Timeout; exiting daemon.\n"); + if (g_main_loop_is_running (loop)) g_main_loop_quit (loop); @@ -107,98 +115,26 @@ ev_daemon_maybe_start_killtimer (gpointer data) } static gboolean -convert_metadata (const gchar *metadata) +spawn_evince (const gchar *uri) { - GFile *file; - char *argv[3]; - gint exit_status; - GFileAttributeInfoList *namespaces; - gboolean supported = FALSE; - GError *error = NULL; + gchar *argv[3]; gboolean retval; + GError *error = NULL; - /* 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 ("GVFS metadata not supported. " - "Evince will run without metadata support.\n"); - g_object_unref (file); - return FALSE; - } - g_object_unref (file); - - argv[0] = g_build_filename (LIBEXECDIR, "evince-convert-metadata", NULL); - argv[1] = (char *) metadata; + /* TODO Check that the uri exists */ + argv[0] = g_build_filename (BINDIR, "evince", NULL); + argv[1] = (gchar *) uri; argv[2] = NULL; - retval = g_spawn_sync (NULL /* wd */, argv, NULL /* env */, - 0, NULL, NULL, NULL, NULL, - &exit_status, &error); - g_free (argv[0]); - + retval = g_spawn_async (NULL /* wd */, argv, NULL /* env */, + 0, NULL, NULL, NULL, &error); if (!retval) { - g_printerr ("Error migrating metadata: %s\n", error->message); + g_printerr ("Error spawning evince for uri %s: %s\n", uri, error->message); g_error_free (error); } + g_free (argv[0]); - return retval && WIFEXITED (exit_status) && WEXITSTATUS (exit_status) == 0; -} - -static void -ev_migrate_metadata (void) -{ - gchar *updated; - gchar *metadata; - gchar *dot_dir; - const gchar *userdir; - - userdir = g_getenv ("GNOME22_USER_DIR"); - if (userdir) { - dot_dir = g_build_filename (userdir, "evince", NULL); - } else { - 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); + return retval; } static void @@ -207,6 +143,7 @@ name_appeared_cb (GDBusConnection *connection, const gchar *name_owner, gpointer user_data) { + LOG ("Watch name'%s' appeared with owner '%s'\n", name, name_owner); } static void @@ -216,12 +153,16 @@ name_vanished_cb (GDBusConnection *connection, { GList *l; + LOG ("Watch name'%s' disappeared\n", name); + for (l = ev_daemon_docs; l != NULL; l = l->next) { EvDoc *doc = (EvDoc *) l->data; if (strcmp (doc->dbus_name, name) != 0) continue; + LOG ("Watch found URI '%s' for name; removing\n", doc->uri); + ev_daemon_docs = g_list_delete_link (ev_daemon_docs, l); ev_doc_free (doc); @@ -230,6 +171,45 @@ name_vanished_cb (GDBusConnection *connection, } } +static void +process_pending_invocations (const gchar *uri, + const gchar *dbus_name) +{ + GList *l; + GList *uri_invocations; + + LOG ("RegisterDocument process pending invocations for URI %s\n", uri); + uri_invocations = g_hash_table_lookup (pending_invocations, uri); + + for (l = uri_invocations; l != NULL; l = l->next) { + GDBusMethodInvocation *invocation; + + invocation = (GDBusMethodInvocation *)l->data; + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(s)", dbus_name)); + } + + g_list_free (uri_invocations); + g_hash_table_remove (pending_invocations, uri); +} + +static void +document_loaded_cb (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + EvDoc *doc) +{ + const gchar *uri; + + g_variant_get (parameters, "(&s)", &uri); + if (strcmp (uri, doc->uri) == 0) + process_pending_invocations (uri, sender_name); + g_dbus_connection_signal_unsubscribe (connection, doc->loaded_id); +} + static void method_call_cb (GDBusConnection *connection, const gchar *sender, @@ -246,43 +226,55 @@ method_call_cb (GDBusConnection *connection, if (g_strcmp0 (method_name, "RegisterDocument") == 0) { EvDoc *doc; const gchar *uri; - const gchar *owner = NULL; g_variant_get (parameters, "(&s)", &uri); doc = ev_daemon_find_doc (uri); - if (doc) { - /* Already registered */ - owner = doc->dbus_name; - } else { - ev_daemon_stop_killtimer (); - - doc = g_new (EvDoc, 1); - doc->dbus_name = g_strdup (sender); - doc->uri = g_strdup (uri); - - doc->watch_id = g_bus_watch_name (G_BUS_TYPE_STARTER, - sender, - G_BUS_NAME_WATCHER_FLAGS_NONE, - name_appeared_cb, - name_vanished_cb, - user_data, NULL); - - ev_daemon_docs = g_list_prepend (ev_daemon_docs, doc); + if (doc != NULL) { + LOG ("RegisterDocument found owner '%s' for URI '%s'\n", doc->dbus_name, uri); + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(s)", doc->dbus_name)); + return; } - g_dbus_method_invocation_return_value (invocation, - g_variant_new_string (owner)); - return; - + ev_daemon_stop_killtimer (); + + doc = g_new (EvDoc, 1); + doc->dbus_name = g_strdup (sender); + doc->uri = g_strdup (uri); + + doc->loaded_id = g_dbus_connection_signal_subscribe (connection, + doc->dbus_name, + EV_DBUS_WINDOW_INTERFACE_NAME, + "DocumentLoaded", + NULL, + NULL, + 0, + (GDBusSignalCallback) document_loaded_cb, + doc, + NULL); + doc->watch_id = g_bus_watch_name_on_connection (connection, + sender, + G_BUS_NAME_WATCHER_FLAGS_NONE, + name_appeared_cb, + name_vanished_cb, + user_data, NULL); + + LOG ("RegisterDocument registered owner '%s' for URI '%s'\n", doc->dbus_name, uri); + ev_daemon_docs = g_list_prepend (ev_daemon_docs, doc); + + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "")); } else if (g_strcmp0 (method_name, "UnregisterDocument") == 0) { EvDoc *doc; const gchar *uri; g_variant_get (parameters, "(&s)", &uri); + LOG ("UnregisterDocument URI '%s'\n", uri); + doc = ev_daemon_find_doc (uri); if (doc == NULL) { + LOG ("UnregisterDocument URI was not registered!\n"); g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, @@ -291,6 +283,9 @@ method_call_cb (GDBusConnection *connection, } if (strcmp (doc->dbus_name, sender) != 0) { + LOG ("UnregisterDocument called by non-owner (owner '%s' sender '%s')\n", + doc->dbus_name, sender); + g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_BAD_ADDRESS, @@ -303,30 +298,47 @@ method_call_cb (GDBusConnection *connection, ev_daemon_maybe_start_killtimer (user_data); g_dbus_method_invocation_return_value (invocation, g_variant_new ("()")); - return; - } -} + } else if (g_strcmp0 (method_name, "FindDocument") == 0) { + EvDoc *doc; + const gchar *uri; + gboolean spawn; -static void -name_acquired_cb (GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - ev_migrate_metadata (); + g_variant_get (parameters, "(&sb)", &uri, &spawn); - ev_daemon_maybe_start_killtimer (user_data); -} + LOG ("FindDocument URI '%s' \n", uri); -static void -name_lost_cb (GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - GMainLoop *loop = (GMainLoop *) user_data; + doc = ev_daemon_find_doc (uri); + if (doc != NULL) { + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(s)", doc->dbus_name)); + return; + } - /* Failed to acquire the name; exit daemon */ - if (g_main_loop_is_running (loop)) - g_main_loop_quit (loop); + if (spawn) { + GList *uri_invocations; + gboolean ret_val = TRUE; + + uri_invocations = g_hash_table_lookup (pending_invocations, uri); + + if (uri_invocations == NULL) { + /* Only spawn once. */ + ret_val = spawn_evince (uri); + } + + if (ret_val) { + /* Only defer DBUS answer if evince was succesfully spawned */ + uri_invocations = g_list_prepend (uri_invocations, invocation); + g_hash_table_insert (pending_invocations, + g_strdup (uri), + uri_invocations); + return; + } + } + + LOG ("FindDocument URI '%s' was not registered!\n", uri); + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(s)","")); + } } static const char introspection_xml[] = @@ -339,6 +351,11 @@ static const char introspection_xml[] = "" "" "" + "" + "" + "" + "" + "" "" ""; @@ -348,61 +365,92 @@ static const GDBusInterfaceVTable interface_vtable = { NULL }; +static GDBusNodeInfo *introspection_data; + +static void +bus_acquired_cb (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + GMainLoop *loop = (GMainLoop *) user_data; + guint registration_id; + GError *error = NULL; + + if (!introspection_data) + introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); + + registration_id = g_dbus_connection_register_object (connection, + EV_DBUS_DAEMON_OBJECT_PATH, + introspection_data->interfaces[0], + &interface_vtable, + g_main_loop_ref (loop), + (GDestroyNotify) g_main_loop_unref, + &error); + if (registration_id == 0) { + g_printerr ("Failed to register object: %s\n", error->message); + g_error_free (error); + + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + } +} + +static void +name_acquired_cb (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + ev_daemon_maybe_start_killtimer (user_data); +} + +static void +name_lost_cb (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + GMainLoop *loop = (GMainLoop *) user_data; + + /* Failed to acquire the name; exit daemon */ + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); +} + gint main (gint argc, gchar **argv) { - GDBusConnection *connection; GMainLoop *loop; - GError *error = NULL; - guint registration_id, owner_id; - GDBusNodeInfo *introspection_data; + guint owner_id; - g_type_init (); + g_set_prgname ("evince-daemon"); - connection = g_bus_get_sync (G_BUS_TYPE_STARTER, NULL, &error); - if (connection == NULL) { - g_printerr ("Failed to get bus connection: %s\n", error->message); - g_error_free (error); - return 1; - } - - introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); - g_assert (introspection_data != NULL); + g_type_init (); loop = g_main_loop_new (NULL, FALSE); - registration_id = g_dbus_connection_register_object (connection, - EV_DBUS_DAEMON_OBJECT_PATH, - EV_DBUS_DAEMON_NAME, - introspection_data->interfaces[0], - &interface_vtable, - g_main_loop_ref (loop), - (GDestroyNotify) g_main_loop_unref, - &error); - if (registration_id == 0) { - g_printerr ("Failed to register object: %s\n", error->message); - g_error_free (error); - g_object_unref (connection); - return 1; - } + pending_invocations = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify)g_free, + NULL); - owner_id = g_bus_own_name_on_connection (connection, - EV_DBUS_DAEMON_NAME, - G_BUS_NAME_OWNER_FLAGS_NONE, - name_acquired_cb, - name_lost_cb, - g_main_loop_ref (loop), - (GDestroyNotify) g_main_loop_unref); + owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, + EV_DBUS_DAEMON_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + bus_acquired_cb, + name_acquired_cb, + name_lost_cb, + g_main_loop_ref (loop), + (GDestroyNotify) g_main_loop_unref); g_main_loop_run (loop); g_bus_unown_name (owner_id); g_main_loop_unref (loop); - g_dbus_node_info_unref (introspection_data); + if (introspection_data) + g_dbus_node_info_unref (introspection_data); g_list_foreach (ev_daemon_docs, (GFunc)ev_doc_free, NULL); g_list_free (ev_daemon_docs); - g_object_unref (connection); + g_hash_table_destroy (pending_invocations); return 0; }