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