]> www.fi.muni.cz Git - evince.git/blob - shell/ev-daemon.c
Update FSF address everywhere.
[evince.git] / shell / ev-daemon.c
1 /* ev-metadata.c
2  *  this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2009 Carlos Garcia Campos  <carlosgc@gnome.org>
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #include <glib.h>
24 #include <glib/gstdio.h>
25 #include <gio/gio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <dbus/dbus-glib-bindings.h>
33 #include <dbus/dbus-glib-lowlevel.h>
34
35 #define EV_DBUS_DAEMON_NAME        "org.gnome.evince.Daemon"
36 #define EV_DBUS_DAEMON_OBJECT_PATH "/org/gnome/evince/Daemon"
37
38 #define EV_TYPE_DAEMON                     (ev_daemon_get_type ())
39 #define EV_DAEMON(object)                  (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_DAEMON, EvDaemon))
40 #define EV_DAEMON_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_DAEMON, EvDaemonClass))
41 #define EV_IS_DAEMON(object)               (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_DAEMON))
42
43 typedef struct _EvDaemon      EvDaemon;
44 typedef struct _EvDaemonClass EvDaemonClass;
45
46 struct _EvDaemon {
47         GObject base;
48
49         DBusGProxy *bus_proxy;
50
51         GList      *docs;
52         guint       n_docs;
53
54         guint       timer_id;
55 };
56
57 struct _EvDaemonClass {
58         GObjectClass base_class;
59 };
60
61 static GType    ev_daemon_get_type            (void) G_GNUC_CONST;
62 static gboolean ev_daemon_register_document   (EvDaemon              *ev_daemon,
63                                                const gchar           *uri,
64                                                DBusGMethodInvocation *context);
65 static gboolean ev_daemon_unregister_document (EvDaemon              *ev_daemon,
66                                                const gchar           *uri,
67                                                DBusGMethodInvocation *context);
68 #include "ev-daemon-service.h"
69
70 static EvDaemon *ev_daemon = NULL;
71
72 G_DEFINE_TYPE(EvDaemon, ev_daemon, G_TYPE_OBJECT)
73
74 typedef struct {
75         gchar *dbus_name;
76         gchar *uri;
77 } EvDoc;
78
79 static void
80 ev_doc_free (EvDoc *doc)
81 {
82         if (!doc)
83                 return;
84
85         g_free (doc->dbus_name);
86         g_free (doc->uri);
87
88         g_free (doc);
89 }
90
91 static EvDoc *
92 ev_daemon_find_doc (EvDaemon    *ev_daemon,
93                     const gchar *uri)
94 {
95         GList *l;
96
97         for (l = ev_daemon->docs; l; l = g_list_next (l)) {
98                 EvDoc *doc = (EvDoc *)l->data;
99
100                 if (strcmp (doc->uri, uri) == 0)
101                         return doc;
102         }
103
104         return NULL;
105 }
106
107 static void
108 ev_daemon_finalize (GObject *object)
109 {
110         EvDaemon *ev_daemon = EV_DAEMON (object);
111
112         if (ev_daemon->docs) {
113                 g_list_foreach (ev_daemon->docs, (GFunc)ev_doc_free, NULL);
114                 g_list_free (ev_daemon->docs);
115                 ev_daemon->docs = NULL;
116         }
117
118         if (ev_daemon->bus_proxy) {
119                 g_object_unref (ev_daemon->bus_proxy);
120                 ev_daemon->bus_proxy = NULL;
121         }
122
123         G_OBJECT_CLASS (ev_daemon_parent_class)->finalize (object);
124 }
125
126 static void
127 ev_daemon_init (EvDaemon *ev_daemon)
128 {
129 }
130
131 static void
132 ev_daemon_class_init (EvDaemonClass *klass)
133 {
134         GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
135
136         g_object_class->finalize = ev_daemon_finalize;
137
138         dbus_g_object_type_install_info (EV_TYPE_DAEMON,
139                                          &dbus_glib_ev_daemon_object_info);
140 }
141
142 static gboolean
143 ev_daemon_shutdown (EvDaemon *ev_daemon)
144 {
145         g_object_unref (ev_daemon);
146
147         return FALSE;
148 }
149
150 static void
151 ev_daemon_stop_killtimer (EvDaemon *ev_daemon)
152 {
153         if (ev_daemon->timer_id != 0)
154                 g_source_remove (ev_daemon->timer_id);
155         ev_daemon->timer_id = 0;
156 }
157
158 static void
159 ev_daemon_start_killtimer (EvDaemon *ev_daemon)
160 {
161         ev_daemon_stop_killtimer (ev_daemon);
162         ev_daemon->timer_id =
163                 g_timeout_add_seconds (30,
164                                        (GSourceFunc) ev_daemon_shutdown,
165                                        ev_daemon);
166 }
167
168 static void
169 ev_daemon_name_owner_changed (DBusGProxy  *proxy,
170                               const gchar *name,
171                               const gchar *old_owner,
172                               const gchar *new_owner,
173                               EvDaemon    *ev_daemon)
174 {
175         GList *l, *next = NULL;
176
177         if (*name == ':' && *new_owner == '\0') {
178                 for (l = ev_daemon->docs; l; l = next) {
179                         EvDoc *doc = (EvDoc *)l->data;
180
181                         next = l->next;
182                         if (strcmp (doc->dbus_name, name) == 0) {
183                                 ev_doc_free (doc);
184                                 ev_daemon->docs = g_list_delete_link (ev_daemon->docs, l);
185                                 if (--ev_daemon->n_docs == 0)
186                                         ev_daemon_start_killtimer (ev_daemon);
187                         }
188                 }
189         }
190 }
191
192 static EvDaemon *
193 ev_daemon_get (void)
194 {
195         DBusGConnection *connection;
196         guint            request_name_result;
197         GError          *error = NULL;
198
199         if (ev_daemon)
200                 return ev_daemon;
201
202         connection = dbus_g_bus_get (DBUS_BUS_STARTER, &error);
203         if (!connection) {
204                 g_printerr ("Failed to connect to the D-BUS daemon: %s\n", error->message);
205                 g_error_free (error);
206
207                 return NULL;
208         }
209
210         ev_daemon = g_object_new (EV_TYPE_DAEMON, NULL);
211
212         ev_daemon->bus_proxy = dbus_g_proxy_new_for_name (connection,
213                                                        DBUS_SERVICE_DBUS,
214                                                        DBUS_PATH_DBUS,
215                                                        DBUS_INTERFACE_DBUS);
216         if (!org_freedesktop_DBus_request_name (ev_daemon->bus_proxy,
217                                                 EV_DBUS_DAEMON_NAME,
218                                                 DBUS_NAME_FLAG_DO_NOT_QUEUE,
219                                                 &request_name_result, &error)) {
220                 g_printerr ("Failed to acquire daemon name: %s", error->message);
221                 g_error_free (error);
222                 g_object_unref (ev_daemon);
223
224                 return NULL;
225         }
226
227         switch (request_name_result) {
228         case DBUS_REQUEST_NAME_REPLY_EXISTS:
229                 g_printerr ("Evince daemon already running, exiting.\n");
230                 g_object_unref (ev_daemon);
231
232                 return NULL;
233         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
234                 dbus_g_connection_register_g_object (connection,
235                                                      EV_DBUS_DAEMON_OBJECT_PATH,
236                                                      G_OBJECT (ev_daemon));
237                 break;
238         default:
239                 g_printerr ("Not primary owner of the service, exiting.\n");
240                 g_object_unref (ev_daemon);
241
242                 return NULL;
243         }
244
245
246         dbus_g_proxy_add_signal (ev_daemon->bus_proxy,
247                                  "NameOwnerChanged",
248                                  G_TYPE_STRING,
249                                  G_TYPE_STRING,
250                                  G_TYPE_STRING,
251                                  G_TYPE_INVALID);
252         dbus_g_proxy_connect_signal (ev_daemon->bus_proxy, "NameOwnerChanged",
253                                      G_CALLBACK (ev_daemon_name_owner_changed),
254                                      ev_daemon, NULL);
255         ev_daemon_start_killtimer (ev_daemon);
256
257         return ev_daemon;
258 }
259
260
261
262 static gboolean
263 ev_daemon_register_document (EvDaemon              *ev_daemon,
264                              const gchar           *uri,
265                              DBusGMethodInvocation *method)
266 {
267         EvDoc       *doc;
268         const gchar *owner = NULL;
269
270         doc = ev_daemon_find_doc (ev_daemon, uri);
271         if (doc) {
272                 /* Already registered */
273                 owner = doc->dbus_name;
274         } else {
275                 doc = g_new (EvDoc, 1);
276                 doc->dbus_name = dbus_g_method_get_sender (method);
277                 doc->uri = g_strdup (uri);
278                 ev_daemon->docs = g_list_prepend (ev_daemon->docs, doc);
279                 if (ev_daemon->n_docs++ == 0)
280                         ev_daemon_stop_killtimer (ev_daemon);
281         }
282
283         dbus_g_method_return (method, owner);
284
285         return TRUE;
286 }
287
288 static gboolean
289 ev_daemon_unregister_document (EvDaemon              *ev_daemon,
290                                const gchar           *uri,
291                                DBusGMethodInvocation *method)
292 {
293         EvDoc *doc;
294         gchar *sender;
295
296         doc = ev_daemon_find_doc (ev_daemon, uri);
297         if (!doc) {
298                 g_warning ("Document %s is not registered\n", uri);
299                 dbus_g_method_return (method);
300
301                 return TRUE;
302         }
303
304         sender = dbus_g_method_get_sender (method);
305         if (strcmp (doc->dbus_name, sender) != 0) {
306                 g_warning ("Failed to unregister document %s: invalid owner %s, expected %s\n",
307                            uri, sender, doc->dbus_name);
308                 g_free (sender);
309                 dbus_g_method_return (method);
310
311                 return TRUE;
312         }
313         g_free (sender);
314
315         ev_daemon->docs = g_list_remove (ev_daemon->docs, doc);
316         ev_doc_free (doc);
317         if (--ev_daemon->n_docs == 0)
318                 ev_daemon_start_killtimer (ev_daemon);
319
320         dbus_g_method_return (method);
321
322         return TRUE;
323 }
324
325 static void
326 do_exit (GMainLoop *loop,
327          GObject   *object)
328 {
329         if (g_main_loop_is_running (loop))
330                 g_main_loop_quit (loop);
331 }
332
333 static gboolean
334 convert_metadata (const gchar *metadata)
335 {
336         GFile   *file;
337         char    *argv[3];
338         gint     exit_status;
339         GFileAttributeInfoList *namespaces;
340         gboolean supported = FALSE;
341         GError  *error = NULL;
342         gboolean retval;
343
344         /* If metadata is not supported for a local file
345          * is likely because and old gvfs version is running.
346          */
347         file = g_file_new_for_path (metadata);
348         namespaces = g_file_query_writable_namespaces (file, NULL, NULL);
349         if (namespaces) {
350                 gint i;
351
352                 for (i = 0; i < namespaces->n_infos; i++) {
353                         if (strcmp (namespaces->infos[i].name, "metadata") == 0) {
354                                 supported = TRUE;
355                                 break;
356                         }
357                 }
358                 g_file_attribute_info_list_unref (namespaces);
359         }
360         if (!supported) {
361                 g_warning ("GVFS metadata not supported. "
362                            "Evince will run without metadata support.\n");
363                 g_object_unref (file);
364                 return FALSE;
365         }
366         g_object_unref (file);
367
368         argv[0] = g_build_filename (LIBEXECDIR, "evince-convert-metadata", NULL);
369         argv[1] = (char *) metadata;
370         argv[2] = NULL;
371
372         retval = g_spawn_sync (NULL /* wd */, argv, NULL /* env */,
373                                0, NULL, NULL, NULL, NULL,
374                                &exit_status, &error);
375         g_free (argv[0]);
376
377         if (!retval) {
378                 g_printerr ("Error migrating metadata: %s\n", error->message);
379                 g_error_free (error);
380         }
381
382         return retval && WIFEXITED (exit_status) && WEXITSTATUS (exit_status) == 0;
383 }
384
385 static void
386 ev_migrate_metadata (void)
387 {
388         gchar *updated;
389         gchar *metadata;
390         gchar *dot_dir;
391
392         dot_dir = g_build_filename (g_get_home_dir (),
393                                     ".gnome2",
394                                     "evince",
395                                     NULL);
396
397         updated = g_build_filename (dot_dir, "migrated-to-gvfs", NULL);
398         if (g_file_test (updated, G_FILE_TEST_EXISTS)) {
399                 /* Already migrated */
400                 g_free (updated);
401                 g_free (dot_dir);
402                 return;
403         }
404
405         metadata = g_build_filename (dot_dir, "ev-metadata.xml", NULL);
406         if (g_file_test (metadata, G_FILE_TEST_EXISTS)) {
407                 if (convert_metadata (metadata)) {
408                         gint fd;
409
410                         fd = g_creat (updated, 0600);
411                         if (fd != -1) {
412                                 close (fd);
413                         }
414                 }
415         }
416
417         g_free (dot_dir);
418         g_free (updated);
419         g_free (metadata);
420 }
421
422 gint
423 main (gint argc, gchar **argv)
424 {
425         GMainLoop *loop;
426
427         /* Init glib threads asap */
428         if (!g_thread_supported ())
429                 g_thread_init (NULL);
430
431         g_type_init ();
432
433         if (!ev_daemon_get ())
434                 return 1;
435
436         ev_migrate_metadata ();
437
438         loop = g_main_loop_new (NULL, FALSE);
439         g_object_weak_ref (G_OBJECT (ev_daemon),
440                            (GWeakNotify) do_exit,
441                            loop);
442         g_main_loop_run (loop);
443         g_main_loop_unref (loop);
444
445         return 0;
446 }