2 * this file is part of evince, a gnome document viewer
4 * Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
5 * Copyright © 2010 Christian Persch
7 * Evince is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * Evince is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <glib/gstdio.h>
28 #include <sys/types.h>
34 #define EV_DBUS_DAEMON_NAME "org.gnome.evince.Daemon"
35 #define EV_DBUS_DAEMON_INTERFACE_NAME "org.gnome.evince.Daemon"
36 #define EV_DBUS_DAEMON_OBJECT_PATH "/org/gnome/evince/Daemon"
38 #define DAEMON_TIMEOUT (30) /* seconds */
40 static GList *ev_daemon_docs = NULL;
41 static guint kill_timer_id;
50 ev_doc_free (EvDoc *doc)
55 g_free (doc->dbus_name);
58 g_bus_unwatch_name (doc->watch_id);
64 ev_daemon_find_doc (const gchar *uri)
68 for (l = ev_daemon_docs; l != NULL; l = l->next) {
69 EvDoc *doc = (EvDoc *)l->data;
71 if (strcmp (doc->uri, uri) == 0)
79 ev_daemon_stop_killtimer (void)
81 if (kill_timer_id != 0)
82 g_source_remove (kill_timer_id);
87 ev_daemon_shutdown (gpointer user_data)
89 GMainLoop *loop = (GMainLoop *) user_data;
91 if (g_main_loop_is_running (loop))
92 g_main_loop_quit (loop);
98 ev_daemon_maybe_start_killtimer (gpointer data)
100 ev_daemon_stop_killtimer ();
101 if (ev_daemon_docs != NULL)
104 kill_timer_id = g_timeout_add_seconds (DAEMON_TIMEOUT,
105 (GSourceFunc) ev_daemon_shutdown,
110 convert_metadata (const gchar *metadata)
115 GFileAttributeInfoList *namespaces;
116 gboolean supported = FALSE;
117 GError *error = NULL;
120 /* If metadata is not supported for a local file
121 * is likely because and old gvfs version is running.
123 file = g_file_new_for_path (metadata);
124 namespaces = g_file_query_writable_namespaces (file, NULL, NULL);
128 for (i = 0; i < namespaces->n_infos; i++) {
129 if (strcmp (namespaces->infos[i].name, "metadata") == 0) {
134 g_file_attribute_info_list_unref (namespaces);
137 g_warning ("GVFS metadata not supported. "
138 "Evince will run without metadata support.\n");
139 g_object_unref (file);
142 g_object_unref (file);
144 argv[0] = g_build_filename (LIBEXECDIR, "evince-convert-metadata", NULL);
145 argv[1] = (char *) metadata;
148 retval = g_spawn_sync (NULL /* wd */, argv, NULL /* env */,
149 0, NULL, NULL, NULL, NULL,
150 &exit_status, &error);
154 g_printerr ("Error migrating metadata: %s\n", error->message);
155 g_error_free (error);
158 return retval && WIFEXITED (exit_status) && WEXITSTATUS (exit_status) == 0;
162 ev_migrate_metadata (void)
167 const gchar *userdir;
169 userdir = g_getenv ("GNOME22_USER_DIR");
171 dot_dir = g_build_filename (userdir, "evince", NULL);
173 dot_dir = g_build_filename (g_get_home_dir (),
179 updated = g_build_filename (dot_dir, "migrated-to-gvfs", NULL);
180 if (g_file_test (updated, G_FILE_TEST_EXISTS)) {
181 /* Already migrated */
187 metadata = g_build_filename (dot_dir, "ev-metadata.xml", NULL);
188 if (g_file_test (metadata, G_FILE_TEST_EXISTS)) {
189 if (convert_metadata (metadata)) {
192 fd = g_creat (updated, 0600);
205 name_appeared_cb (GDBusConnection *connection,
207 const gchar *name_owner,
213 name_vanished_cb (GDBusConnection *connection,
219 for (l = ev_daemon_docs; l != NULL; l = l->next) {
220 EvDoc *doc = (EvDoc *) l->data;
222 if (strcmp (doc->dbus_name, name) != 0)
225 ev_daemon_docs = g_list_delete_link (ev_daemon_docs, l);
228 ev_daemon_maybe_start_killtimer (user_data);
234 method_call_cb (GDBusConnection *connection,
236 const gchar *object_path,
237 const gchar *interface_name,
238 const gchar *method_name,
239 GVariant *parameters,
240 GDBusMethodInvocation *invocation,
243 if (g_strcmp0 (interface_name, EV_DBUS_DAEMON_INTERFACE_NAME) != 0)
246 if (g_strcmp0 (method_name, "RegisterDocument") == 0) {
249 const gchar *owner = NULL;
251 g_variant_get (parameters, "(&s)", &uri);
253 doc = ev_daemon_find_doc (uri);
255 /* Already registered */
256 owner = doc->dbus_name;
258 ev_daemon_stop_killtimer ();
260 doc = g_new (EvDoc, 1);
261 doc->dbus_name = g_strdup (sender);
262 doc->uri = g_strdup (uri);
264 doc->watch_id = g_bus_watch_name (G_BUS_TYPE_STARTER,
266 G_BUS_NAME_WATCHER_FLAGS_NONE,
271 ev_daemon_docs = g_list_prepend (ev_daemon_docs, doc);
274 g_dbus_method_invocation_return_value (invocation,
275 g_variant_new_string (owner));
278 } else if (g_strcmp0 (method_name, "UnregisterDocument") == 0) {
282 g_variant_get (parameters, "(&s)", &uri);
284 doc = ev_daemon_find_doc (uri);
286 g_dbus_method_invocation_return_error_literal (invocation,
288 G_DBUS_ERROR_INVALID_ARGS,
289 "URI not registered");
293 if (strcmp (doc->dbus_name, sender) != 0) {
294 g_dbus_method_invocation_return_error_literal (invocation,
296 G_DBUS_ERROR_BAD_ADDRESS,
297 "Only owner can call this method");
301 ev_daemon_docs = g_list_remove (ev_daemon_docs, doc);
303 ev_daemon_maybe_start_killtimer (user_data);
305 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
311 name_acquired_cb (GDBusConnection *connection,
315 ev_migrate_metadata ();
317 ev_daemon_maybe_start_killtimer (user_data);
321 name_lost_cb (GDBusConnection *connection,
325 GMainLoop *loop = (GMainLoop *) user_data;
327 /* Failed to acquire the name; exit daemon */
328 if (g_main_loop_is_running (loop))
329 g_main_loop_quit (loop);
332 static const char introspection_xml[] =
334 "<interface name='org.gnome.evince.Daemon'>"
335 "<method name='RegisterDocument'>"
336 "<arg type='s' name='uri' direction='in'/>"
337 "<arg type='s' name='owner' direction='out'/>"
339 "<method name='UnregisterDocument'>"
340 "<arg type='s' name='uri' direction='in'/>"
345 static const GDBusInterfaceVTable interface_vtable = {
352 main (gint argc, gchar **argv)
354 GDBusConnection *connection;
356 GError *error = NULL;
357 guint registration_id, owner_id;
358 GDBusNodeInfo *introspection_data;
362 connection = g_bus_get_sync (G_BUS_TYPE_STARTER, NULL, &error);
363 if (connection == NULL) {
364 g_printerr ("Failed to get bus connection: %s\n", error->message);
365 g_error_free (error);
369 introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
370 g_assert (introspection_data != NULL);
372 loop = g_main_loop_new (NULL, FALSE);
374 registration_id = g_dbus_connection_register_object (connection,
375 EV_DBUS_DAEMON_OBJECT_PATH,
377 introspection_data->interfaces[0],
379 g_main_loop_ref (loop),
380 (GDestroyNotify) g_main_loop_unref,
382 if (registration_id == 0) {
383 g_printerr ("Failed to register object: %s\n", error->message);
384 g_error_free (error);
385 g_object_unref (connection);
389 owner_id = g_bus_own_name_on_connection (connection,
391 G_BUS_NAME_OWNER_FLAGS_NONE,
394 g_main_loop_ref (loop),
395 (GDestroyNotify) g_main_loop_unref);
397 g_main_loop_run (loop);
399 g_bus_unown_name (owner_id);
401 g_main_loop_unref (loop);
402 g_dbus_node_info_unref (introspection_data);
403 g_list_foreach (ev_daemon_docs, (GFunc)ev_doc_free, NULL);
404 g_list_free (ev_daemon_docs);