]> www.fi.muni.cz Git - evince.git/blob - shell/ev-application.c
shell: Use GAppInfo to launch evince instances instead of gdk_spawn
[evince.git] / shell / ev-application.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2004 Martin Kretzschmar
4  *  Copyright © 2010 Christian Persch
5  *
6  *  Author:
7  *    Martin Kretzschmar <martink@gnome.org>
8  *
9  * Evince is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Evince is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23
24
25 #include <config.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include <glib/gstdio.h>
32 #include <gtk/gtk.h>
33 #ifdef GDK_WINDOWING_X11
34 #include <gdk/gdkx.h>
35 #endif
36 #include <unistd.h>
37
38 #include "totem-scrsaver.h"
39
40 #ifdef WITH_SMCLIENT
41 #include "eggsmclient.h"
42 #endif
43
44 #include "ev-application.h"
45 #include "ev-file-helpers.h"
46 #include "ev-stock-icons.h"
47
48 #ifdef ENABLE_DBUS
49 #include "ev-media-player-keys.h"
50 #endif /* ENABLE_DBUS */
51
52 struct _EvApplication {
53         GObject base_instance;
54
55         gchar *uri;
56
57         gchar *dot_dir;
58         gchar *data_dir;
59
60 #ifdef ENABLE_DBUS
61         GDBusConnection *connection;
62         guint registration_id;
63         EvMediaPlayerKeys *keys;
64         gboolean doc_registered;
65 #endif
66
67         TotemScrsaver *scr_saver;
68
69 #ifdef WITH_SMCLIENT
70         EggSMClient *smclient;
71 #endif
72
73         gchar *filechooser_open_uri;
74         gchar *filechooser_save_uri;
75 };
76
77 struct _EvApplicationClass {
78         GObjectClass base_class;
79 };
80
81 static EvApplication *instance;
82
83 G_DEFINE_TYPE (EvApplication, ev_application, G_TYPE_OBJECT);
84
85 #ifdef ENABLE_DBUS
86 #define APPLICATION_DBUS_OBJECT_PATH "/org/gnome/evince/Evince"
87 #define APPLICATION_DBUS_INTERFACE   "org.gnome.evince.Application"
88
89 #define EVINCE_DAEMON_SERVICE        "org.gnome.evince.Daemon"
90 #define EVINCE_DAEMON_OBJECT_PATH    "/org/gnome/evince/Daemon"
91 #define EVINCE_DAEMON_INTERFACE      "org.gnome.evince.Daemon"
92 #endif
93
94 static void _ev_application_open_uri_at_dest (EvApplication  *application,
95                                               const gchar    *uri,
96                                               GdkScreen      *screen,
97                                               EvLinkDest     *dest,
98                                               EvWindowRunMode mode,
99                                               const gchar    *search_string,
100                                               guint           timestamp);
101 static void ev_application_open_uri_in_window (EvApplication  *application,
102                                                const char     *uri,
103                                                EvWindow       *ev_window,
104                                                GdkScreen      *screen,
105                                                EvLinkDest     *dest,
106                                                EvWindowRunMode mode,
107                                                const gchar    *search_string,
108                                                guint           timestamp);
109
110 /**
111  * ev_application_get_instance:
112  *
113  * Checks for #EvApplication instance, if it doesn't exist it does create it.
114  *
115  * Returns: an instance of the #EvApplication data.
116  */
117 EvApplication *
118 ev_application_get_instance (void)
119 {
120         if (!instance) {
121                 instance = EV_APPLICATION (g_object_new (EV_TYPE_APPLICATION, NULL));
122         }
123
124         return instance;
125 }
126
127 /* Session */
128 gboolean
129 ev_application_load_session (EvApplication *application)
130 {
131         GKeyFile *state_file;
132         gchar    *uri;
133
134 #ifdef WITH_SMCLIENT
135         if (egg_sm_client_is_resumed (application->smclient)) {
136                 state_file = egg_sm_client_get_state_file (application->smclient);
137                 if (!state_file)
138                         return FALSE;
139         } else
140 #endif /* WITH_SMCLIENT */
141                 return FALSE;
142
143         uri = g_key_file_get_string (state_file, "Evince", "uri", NULL);
144         if (!uri)
145                 return FALSE;
146
147         ev_application_open_uri_at_dest (application, uri,
148                                          gdk_screen_get_default (),
149                                          NULL, 0, NULL,
150                                          GDK_CURRENT_TIME);
151         g_free (uri);
152         g_key_file_free (state_file);
153
154         return TRUE;
155 }
156
157 #ifdef WITH_SMCLIENT
158
159 static void
160 smclient_save_state_cb (EggSMClient   *client,
161                         GKeyFile      *state_file,
162                         EvApplication *application)
163 {
164         if (!application->uri)
165                 return;
166
167         g_key_file_set_string (state_file, "Evince", "uri", application->uri);
168 }
169
170 static void
171 smclient_quit_cb (EggSMClient   *client,
172                   EvApplication *application)
173 {
174         ev_application_shutdown (application);
175 }
176 #endif /* WITH_SMCLIENT */
177
178 static void
179 ev_application_init_session (EvApplication *application)
180 {
181 #ifdef WITH_SMCLIENT
182         application->smclient = egg_sm_client_get ();
183         g_signal_connect (application->smclient, "save_state",
184                           G_CALLBACK (smclient_save_state_cb),
185                           application);
186         g_signal_connect (application->smclient, "quit",
187                           G_CALLBACK (smclient_quit_cb),
188                           application);
189 #endif
190 }
191
192 /**
193  * ev_display_open_if_needed:
194  * @name: the name of the display to be open if it's needed.
195  *
196  * Search among all the open displays if any of them have the same name as the
197  * passed name. If the display isn't found it tries the open it.
198  *
199  * Returns: a #GdkDisplay of the display with the passed name.
200  */
201 static GdkDisplay *
202 ev_display_open_if_needed (const gchar *name)
203 {
204         GSList     *displays;
205         GSList     *l;
206         GdkDisplay *display = NULL;
207
208         displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
209
210         for (l = displays; l != NULL; l = l->next) {
211                 const gchar *display_name = gdk_display_get_name ((GdkDisplay *) l->data);
212
213                 if (g_ascii_strcasecmp (display_name, name) == 0) {
214                         display = l->data;
215                         break;
216                 }
217         }
218
219         g_slist_free (displays);
220
221         return display != NULL ? display : gdk_display_open (name);
222 }
223
224 static void
225 ev_spawn (const char     *uri,
226           GdkScreen      *screen,
227           EvLinkDest     *dest,
228           EvWindowRunMode mode,
229           const gchar    *search_string,
230           guint           timestamp)
231 {
232         GString *cmd;
233         gchar *path, *cmdline;
234         GAppInfo *app;
235         GdkAppLaunchContext *ctx;
236         GError  *error = NULL;
237
238         cmd = g_string_new (NULL);
239
240 #ifdef G_OS_WIN32
241 {
242         gchar *dir;
243
244         dir = g_win32_get_package_installation_directory_of_module (NULL);
245         path = g_build_filename (dir, "bin", "evince", NULL);
246
247         g_free (dir);
248 }
249 #else
250         path = g_build_filename (BINDIR, "evince", NULL);
251 #endif
252
253         g_string_append_printf (cmd, " %s", path);
254         g_free (path);
255         
256         /* Page label */
257         if (dest) {
258                 const gchar *page_label;
259
260                 page_label = ev_link_dest_get_page_label (dest);
261
262                 if (page_label)
263                         g_string_append_printf (cmd, " --page-label=%s", page_label);
264                 else
265                         g_string_append_printf (cmd, " --page-label=%d",
266                                                 ev_link_dest_get_page (dest));
267         }
268
269         /* Find string */
270         if (search_string) {
271                 g_string_append_printf (cmd, " --find=%s", search_string);
272         }
273
274         /* Mode */
275         switch (mode) {
276         case EV_WINDOW_MODE_FULLSCREEN:
277                 g_string_append (cmd, " -f");
278                 break;
279         case EV_WINDOW_MODE_PRESENTATION:
280                 g_string_append (cmd, " -s");
281                 break;
282         default:
283                 break;
284         }
285
286         g_string_append_printf (cmd, " %s", uri);
287
288         cmdline = g_string_free (cmd, FALSE);
289         app = g_app_info_create_from_commandline (cmdline, NULL, 0, &error);
290
291         if (app != NULL) {
292                 ctx = gdk_display_get_app_launch_context (gdk_screen_get_display (screen));
293                 gdk_app_launch_context_set_screen (ctx, screen);
294                 gdk_app_launch_context_set_timestamp (ctx, timestamp);
295
296                 g_app_info_launch (app, NULL,
297                                    G_APP_LAUNCH_CONTEXT (ctx), &error);
298
299                 g_object_unref (app);
300                 g_object_unref (ctx);
301         }
302
303         if (error != NULL) {
304                 g_warning ("Error launching evince %s: %s\n", uri, error->message);
305                 g_error_free (error);
306         }
307
308         g_free (cmdline);
309 }
310
311 static GList *
312 ev_application_get_windows (EvApplication *application)
313 {
314         GList *l, *toplevels;
315         GList *windows = NULL;
316
317         toplevels = gtk_window_list_toplevels ();
318
319         for (l = toplevels; l != NULL; l = l->next) {
320                 if (EV_IS_WINDOW (l->data)) {
321                         windows = g_list_append (windows, l->data);
322                 }
323         }
324
325         g_list_free (toplevels);
326
327         return windows;
328 }
329
330 static EvWindow *
331 ev_application_get_empty_window (EvApplication *application,
332                                  GdkScreen     *screen)
333 {
334         EvWindow *empty_window = NULL;
335         GList    *windows = ev_application_get_windows (application);
336         GList    *l;
337
338         for (l = windows; l != NULL; l = l->next) {
339                 EvWindow *window = EV_WINDOW (l->data);
340
341                 if (ev_window_is_empty (window) &&
342                     gtk_window_get_screen (GTK_WINDOW (window)) == screen) {
343                         empty_window = window;
344                         break;
345                 }
346         }
347
348         g_list_free (windows);
349
350         return empty_window;
351 }
352
353
354 #ifdef ENABLE_DBUS
355 typedef struct {
356         gchar          *uri;
357         GdkScreen      *screen;
358         EvLinkDest     *dest;
359         EvWindowRunMode mode;
360         gchar          *search_string;
361         guint           timestamp;
362 } EvRegisterDocData;
363
364 static void
365 ev_register_doc_data_free (EvRegisterDocData *data)
366 {
367         if (!data)
368                 return;
369
370         g_free (data->uri);
371         if (data->search_string)
372                 g_free (data->search_string);
373         if (data->dest)
374                 g_object_unref (data->dest);
375
376         g_free (data);
377 }
378
379 static void
380 on_reload_cb (GObject      *source_object,
381               GAsyncResult *res,
382               gpointer      user_data)
383 {
384         GDBusConnection *connection = G_DBUS_CONNECTION (source_object);
385         GVariant        *value;
386         GError          *error = NULL;
387
388         value = g_dbus_connection_call_finish (connection, res, &error);
389         if (!value) {
390                 g_warning ("Failed to Reload: %s", error->message);
391                 g_error_free (error);
392         }
393         g_variant_unref (value);
394
395         ev_application_shutdown (EV_APP);
396 }
397
398 static void
399 on_register_uri_cb (GObject      *source_object,
400                     GAsyncResult *res,
401                     gpointer      user_data)
402 {
403         GDBusConnection   *connection = G_DBUS_CONNECTION (source_object);
404         EvRegisterDocData *data = (EvRegisterDocData *)user_data;
405         EvApplication     *application = EV_APP;
406         GVariant          *value;
407         const gchar       *owner;
408         GVariantBuilder    builder;
409         GError            *error = NULL;
410
411         value = g_dbus_connection_call_finish (connection, res, &error);
412         if (!value) {
413                 g_warning ("Error registering document: %s\n", error->message);
414                 g_error_free (error);
415
416                 _ev_application_open_uri_at_dest (application,
417                                                   data->uri,
418                                                   data->screen,
419                                                   data->dest,
420                                                   data->mode,
421                                                   data->search_string,
422                                                   data->timestamp);
423                 ev_register_doc_data_free (data);
424
425                 return;
426         }
427
428         g_variant_get (value, "(&s)", &owner);
429
430         /* This means that the document wasn't already registered; go
431          * ahead with opening it.
432          */
433         if (owner[0] == '\0') {
434                 g_variant_unref (value);
435
436                 application->doc_registered = TRUE;
437
438                 _ev_application_open_uri_at_dest (application,
439                                                   data->uri,
440                                                   data->screen,
441                                                   data->dest,
442                                                   data->mode,
443                                                   data->search_string,
444                                                   data->timestamp);
445                 ev_register_doc_data_free (data);
446
447                 return;
448         }
449
450         /* Already registered */
451         g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{sv}u)"));
452         g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
453         g_variant_builder_add (&builder, "{sv}",
454                                "display",
455                                g_variant_new_string (gdk_display_get_name (gdk_screen_get_display (data->screen))));
456         g_variant_builder_add (&builder, "{sv}",
457                                "screen",
458                                g_variant_new_int32 (gdk_screen_get_number (data->screen)));
459         if (data->dest) {
460                 g_variant_builder_add (&builder, "{sv}",
461                                        "page-label",
462                                        g_variant_new_string (ev_link_dest_get_page_label (data->dest)));
463         }
464         if (data->search_string) {
465                 g_variant_builder_add (&builder, "{sv}",
466                                        "find-string",
467                                        g_variant_new_string (data->search_string));
468         }
469         if (data->mode != EV_WINDOW_MODE_NORMAL) {
470                 g_variant_builder_add (&builder, "{sv}",
471                                        "mode",
472                                        g_variant_new_uint32 (data->mode));
473         }
474         g_variant_builder_close (&builder);
475
476         g_variant_builder_add (&builder, "u", data->timestamp);
477
478         g_dbus_connection_call (connection,
479                                 owner,
480                                 APPLICATION_DBUS_OBJECT_PATH,
481                                 APPLICATION_DBUS_INTERFACE,
482                                 "Reload",
483                                 g_variant_builder_end (&builder),
484                                 NULL,
485                                 G_DBUS_CALL_FLAGS_NONE,
486                                 -1,
487                                 NULL,
488                                 on_reload_cb,
489                                 NULL);
490         g_variant_unref (value);
491         ev_register_doc_data_free (data);
492 }
493
494 /*
495  * ev_application_register_uri:
496  * @application:
497  * @uri:
498  * @screen:
499  * @dest:
500  * @mode:
501  * @search_string:
502  * @timestamp:
503  *
504  * Registers @uri with evince-daemon.
505  *
506  */
507 static void
508 ev_application_register_uri (EvApplication  *application,
509                              const gchar    *uri,
510                              GdkScreen      *screen,
511                              EvLinkDest     *dest,
512                              EvWindowRunMode mode,
513                              const gchar    *search_string,
514                              guint           timestamp)
515 {
516         EvRegisterDocData *data;
517
518         if (!application->connection)
519                 return;
520
521         if (application->doc_registered) {
522                 /* Already registered, reload */
523                 GList *windows, *l;
524
525                 windows = ev_application_get_windows (application);
526                 for (l = windows; l != NULL; l = g_list_next (l)) {
527                         EvWindow *ev_window = EV_WINDOW (l->data);
528
529                         ev_application_open_uri_in_window (application, uri, ev_window,
530                                                            screen, dest, mode,
531                                                            search_string,
532                                                            timestamp);
533                 }
534                 g_list_free (windows);
535
536                 return;
537         }
538
539         data = g_new (EvRegisterDocData, 1);
540         data->uri = g_strdup (uri);
541         data->screen = screen;
542         data->dest = dest ? g_object_ref (dest) : NULL;
543         data->mode = mode;
544         data->search_string = search_string ? g_strdup (search_string) : NULL;
545         data->timestamp = timestamp;
546
547         g_dbus_connection_call (application->connection,
548                                 EVINCE_DAEMON_SERVICE,
549                                 EVINCE_DAEMON_OBJECT_PATH,
550                                 EVINCE_DAEMON_INTERFACE,
551                                 "RegisterDocument",
552                                 g_variant_new ("(s)", uri),
553                                 G_VARIANT_TYPE ("(s)"),
554                                 G_DBUS_CALL_FLAGS_NONE,
555                                 -1,
556                                 NULL,
557                                 on_register_uri_cb,
558                                 data);
559 }
560
561 static void
562 ev_application_unregister_uri (EvApplication *application,
563                                const gchar   *uri)
564 {
565         GVariant *value;
566         GError   *error = NULL;
567
568         if (!application->doc_registered)
569                 return;
570
571         /* This is called from ev_application_shutdown(),
572          * so it's safe to use the sync api
573          */
574         value = g_dbus_connection_call_sync (
575                 application->connection,
576                 EVINCE_DAEMON_SERVICE,
577                 EVINCE_DAEMON_OBJECT_PATH,
578                 EVINCE_DAEMON_INTERFACE,
579                 "UnregisterDocument",
580                 g_variant_new ("(s)", uri),
581                 NULL,
582                 G_DBUS_CALL_FLAGS_NO_AUTO_START,
583                 -1,
584                 NULL,
585                 &error);
586         if (value == NULL) {
587                 g_warning ("Error unregistering document: %s\n", error->message);
588                 g_error_free (error);
589         } else {
590                 g_variant_unref (value);
591         }
592 }
593 #endif /* ENABLE_DBUS */
594
595 static void
596 ev_application_open_uri_in_window (EvApplication  *application,
597                                    const char     *uri,
598                                    EvWindow       *ev_window,
599                                    GdkScreen      *screen,
600                                    EvLinkDest     *dest,
601                                    EvWindowRunMode mode,
602                                    const gchar    *search_string,
603                                    guint           timestamp)
604 {
605 #ifdef GDK_WINDOWING_X11
606         GdkWindow *gdk_window;
607 #endif
608
609         if (screen) {
610                 ev_stock_icons_set_screen (screen);
611                 gtk_window_set_screen (GTK_WINDOW (ev_window), screen);
612         }
613
614         /* We need to load uri before showing the window, so
615            we can restore window size without flickering */
616         ev_window_open_uri (ev_window, uri, dest, mode, search_string);
617
618         if (!gtk_widget_get_realized (GTK_WIDGET (ev_window)))
619                 gtk_widget_realize (GTK_WIDGET (ev_window));
620
621 #ifdef GDK_WINDOWING_X11
622         gdk_window = gtk_widget_get_window (GTK_WIDGET (ev_window));
623
624         if (timestamp <= 0)
625                 timestamp = gdk_x11_get_server_time (gdk_window);
626         gdk_x11_window_set_user_time (gdk_window, timestamp);
627
628         gtk_window_present (GTK_WINDOW (ev_window));
629 #else
630         gtk_window_present_with_time (GTK_WINDOW (ev_window), timestamp);
631 #endif /* GDK_WINDOWING_X11 */
632 }
633
634 static void
635 _ev_application_open_uri_at_dest (EvApplication  *application,
636                                   const gchar    *uri,
637                                   GdkScreen      *screen,
638                                   EvLinkDest     *dest,
639                                   EvWindowRunMode mode,
640                                   const gchar    *search_string,
641                                   guint           timestamp)
642 {
643         EvWindow *ev_window;
644
645         ev_window = ev_application_get_empty_window (application, screen);
646         if (!ev_window)
647                 ev_window = EV_WINDOW (ev_window_new ());
648
649         ev_application_open_uri_in_window (application, uri, ev_window,
650                                            screen, dest, mode,
651                                            search_string,
652                                            timestamp);
653 }
654
655 /**
656  * ev_application_open_uri_at_dest:
657  * @application: The instance of the application.
658  * @uri: The uri to be opened.
659  * @screen: Thee screen where the link will be shown.
660  * @dest: The #EvLinkDest of the document.
661  * @mode: The run mode of the window.
662  * @timestamp: Current time value.
663  */
664 void
665 ev_application_open_uri_at_dest (EvApplication  *application,
666                                  const char     *uri,
667                                  GdkScreen      *screen,
668                                  EvLinkDest     *dest,
669                                  EvWindowRunMode mode,
670                                  const gchar    *search_string,
671                                  guint           timestamp)
672 {
673         g_return_if_fail (uri != NULL);
674
675         if (application->uri && strcmp (application->uri, uri) != 0) {
676                 /* spawn a new evince process */
677                 ev_spawn (uri, screen, dest, mode, search_string, timestamp);
678                 return;
679         } else if (!application->uri) {
680                 application->uri = g_strdup (uri);
681         }
682
683 #ifdef ENABLE_DBUS
684         /* Register the uri or send Reload to
685          * remote instance if already registered
686          */
687         ev_application_register_uri (application, uri, screen, dest, mode, search_string, timestamp);
688 #else
689         _ev_application_open_uri_at_dest (application, uri, screen, dest, mode, search_string, timestamp);
690 #endif /* ENABLE_DBUS */
691 }
692
693 /**
694  * ev_application_open_window:
695  * @application: The instance of the application.
696  * @timestamp: Current time value.
697  *
698  * Creates a new window
699  */
700 void
701 ev_application_open_window (EvApplication *application,
702                             GdkScreen     *screen,
703                             guint32        timestamp)
704 {
705         GtkWidget *new_window = ev_window_new ();
706 #ifdef GDK_WINDOWING_X11
707         GdkWindow *gdk_window;
708 #endif
709
710         if (screen) {
711                 ev_stock_icons_set_screen (screen);
712                 gtk_window_set_screen (GTK_WINDOW (new_window), screen);
713         }
714
715         if (!gtk_widget_get_realized (new_window))
716                 gtk_widget_realize (new_window);
717
718 #ifdef GDK_WINDOWING_X11
719         gdk_window = gtk_widget_get_window (GTK_WIDGET (new_window));
720
721         if (timestamp <= 0)
722                 timestamp = gdk_x11_get_server_time (gdk_window);
723         gdk_x11_window_set_user_time (gdk_window, timestamp);
724
725         gtk_window_present (GTK_WINDOW (new_window));
726 #else
727         gtk_window_present_with_time (GTK_WINDOW (new_window), timestamp);
728 #endif /* GDK_WINDOWING_X11 */
729 }
730
731 #ifdef ENABLE_DBUS
732 static void
733 method_call_cb (GDBusConnection       *connection,
734                 const gchar           *sender,
735                 const gchar           *object_path,
736                 const gchar           *interface_name,
737                 const gchar           *method_name,
738                 GVariant              *parameters,
739                 GDBusMethodInvocation *invocation,
740                 gpointer               user_data)
741 {
742         EvApplication   *application = EV_APPLICATION (user_data);
743         GList           *windows, *l;
744         guint            timestamp;
745         GVariantIter    *iter;
746         const gchar     *key;
747         GVariant        *value;
748         GdkDisplay      *display = NULL;
749         int              screen_number = 0;
750         EvLinkDest      *dest = NULL;
751         EvWindowRunMode  mode = EV_WINDOW_MODE_NORMAL;
752         const gchar     *search_string = NULL;
753         GdkScreen       *screen = NULL;
754
755         if (g_strcmp0 (method_name, "Reload") == 0) {
756                 g_variant_get (parameters, "(a{sv}u)", &iter, &timestamp);
757
758                 while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) {
759                         if (strcmp (key, "display") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
760                                 display = ev_display_open_if_needed (g_variant_get_string (value, NULL));
761                         } else if (strcmp (key, "screen") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
762                                 screen_number = g_variant_get_int32 (value);
763                         } else if (strcmp (key, "mode") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_UINT32) {
764                         mode = g_variant_get_uint32 (value);
765                         } else if (strcmp (key, "page-label") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
766                                 dest = ev_link_dest_new_page_label (g_variant_get_string (value, NULL));
767                         } else if (strcmp (key, "find-string") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
768                                 search_string = g_variant_get_string (value, NULL);
769                         }
770                 }
771                 g_variant_iter_free (iter);
772
773                 if (display != NULL &&
774                     screen_number >= 0 &&
775                     screen_number < gdk_display_get_n_screens (display))
776                         screen = gdk_display_get_screen (display, screen_number);
777                 else
778                         screen = gdk_screen_get_default ();
779
780                 windows = ev_application_get_windows (application);
781                 for (l = windows; l != NULL; l = g_list_next (l)) {
782                         EvWindow *ev_window = EV_WINDOW (l->data);
783
784                         ev_application_open_uri_in_window (application, application->uri,
785                                                            ev_window,
786                                                            screen, dest, mode,
787                                                            search_string,
788                                                            timestamp);
789                 }
790                 g_list_free (windows);
791
792                 if (dest)
793                         g_object_unref (dest);
794
795                 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
796         } else if (g_strcmp0 (method_name, "GetWindowList") == 0) {
797                 GList          *windows = ev_application_get_windows (application);
798                 GVariantBuilder builder;
799                 GList          *l;
800
801                 g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ao)"));
802                 g_variant_builder_open (&builder, G_VARIANT_TYPE ("ao"));
803
804                 for (l = windows; l; l = g_list_next (l)) {
805                         EvWindow *window = (EvWindow *)l->data;
806
807                         g_variant_builder_add (&builder, "o", ev_window_get_dbus_object_path (window));
808                 }
809
810                 g_variant_builder_close (&builder);
811                 g_list_free (windows);
812
813                 g_dbus_method_invocation_return_value (invocation, g_variant_builder_end (&builder));
814         }
815 }
816
817 static const char introspection_xml[] =
818         "<node>"
819           "<interface name='org.gnome.evince.Application'>"
820             "<method name='Reload'>"
821               "<arg type='a{sv}' name='args' direction='in'/>"
822               "<arg type='u' name='timestamp' direction='in'/>"
823             "</method>"
824             "<method name='GetWindowList'>"
825               "<arg type='ao' name='window_list' direction='out'/>"
826             "</method>"
827           "</interface>"
828         "</node>";
829
830 static const GDBusInterfaceVTable interface_vtable = {
831         method_call_cb,
832         NULL,
833         NULL
834 };
835
836 static GDBusNodeInfo *introspection_data;
837 #endif /* ENABLE_DBUS */
838
839 void
840 ev_application_open_uri_list (EvApplication *application,
841                               GSList        *uri_list,
842                               GdkScreen     *screen,
843                               guint          timestamp)
844 {
845         GSList *l;
846
847         for (l = uri_list; l != NULL; l = l->next) {
848                 ev_application_open_uri_at_dest (application, (char *)l->data,
849                                                  screen, NULL, 0, NULL,
850                                                  timestamp);
851         }
852 }
853
854 static void
855 ev_application_accel_map_save (EvApplication *application)
856 {
857         gchar *accel_map_file;
858         gchar *tmp_filename;
859         gint   fd;
860
861         accel_map_file = g_build_filename (application->dot_dir, "accels", NULL);
862         tmp_filename = g_strdup_printf ("%s.XXXXXX", accel_map_file);
863
864         fd = g_mkstemp (tmp_filename);
865         if (fd == -1) {
866                 g_free (accel_map_file);
867                 g_free (tmp_filename);
868
869                 return;
870         }
871         gtk_accel_map_save_fd (fd);
872         close (fd);
873
874         g_mkdir_with_parents (application->dot_dir, 0700);
875         if (g_rename (tmp_filename, accel_map_file) == -1) {
876                 /* FIXME: win32? */
877                 g_unlink (tmp_filename);
878         }
879
880         g_free (accel_map_file);
881         g_free (tmp_filename);
882 }
883
884 static void
885 ev_application_accel_map_load (EvApplication *application)
886 {
887         gchar *accel_map_file;
888
889         accel_map_file = g_build_filename (application->dot_dir, "accels", NULL);
890         gtk_accel_map_load (accel_map_file);
891         g_free (accel_map_file);
892 }
893
894 static void
895 ev_application_migrate_config_dir (EvApplication *application)
896 {
897         const gchar        *userdir;
898         gchar              *old_dot_dir;
899         gchar              *old_accels;
900         GError             *error;
901         gint                i;
902         gboolean            dir_created = FALSE;
903         static const gchar *config_files[] = {
904                 "evince_toolbar.xml",
905                 "print-settings",
906                 NULL
907         };
908
909         userdir = g_getenv ("GNOME22_USER_DIR");
910         if (userdir) {
911                 old_dot_dir = g_build_filename (userdir, "evince", NULL);
912                 old_accels = g_build_filename (userdir, "accels", "evince", NULL);
913         } else {
914                 old_dot_dir = g_build_filename (g_get_home_dir (),
915                                                 ".gnome2",
916                                                 "evince",
917                                                 NULL);
918                 old_accels = g_build_filename (g_get_home_dir (),
919                                                ".gnome2", "accels",
920                                                "evince", NULL);
921         }
922
923         if (g_file_test (old_dot_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
924                 for (i = 0; config_files[i]; i++) {
925                         gchar   *old_filename;
926                         gchar   *new_filename;
927                         GFile   *old_file;
928                         GFile   *new_file;
929
930                         old_filename = g_build_filename (old_dot_dir, config_files[i], NULL);
931                         if (!g_file_test (old_filename, G_FILE_TEST_EXISTS)) {
932                                 g_free (old_filename);
933                                 continue;
934                         }
935
936                         if (!dir_created) {
937                                 g_mkdir_with_parents (application->dot_dir, 0700);
938                                 dir_created = TRUE;
939                         }
940
941                         new_filename = g_build_filename (application->dot_dir, config_files[i], NULL);
942                         old_file = g_file_new_for_path (old_filename);
943                         new_file = g_file_new_for_path (new_filename);
944
945                         error = NULL;
946                         g_file_move (old_file, new_file, 0, NULL, NULL, NULL, &error);
947                         if (error) {
948                                 g_warning ("Error migrating config file %s: %s\n",
949                                            old_filename, error->message);
950                                 g_error_free (error);
951                         }
952
953                         g_free (old_filename);
954                         g_free (new_filename);
955                         g_object_unref (old_file);
956                         g_object_unref (new_file);
957                 }
958         }
959
960         g_free (old_dot_dir);
961
962         if (g_file_test (old_accels, G_FILE_TEST_EXISTS)) {
963                 gchar *new_accels;
964                 GFile *old_accels_file;
965                 GFile *new_accels_file;
966
967                 if (!dir_created)
968                         g_mkdir_with_parents (application->dot_dir, 0700);
969
970                 new_accels = g_build_filename (application->dot_dir, "accels", NULL);
971                 old_accels_file = g_file_new_for_path (old_accels);
972                 new_accels_file = g_file_new_for_path (new_accels);
973
974                 error = NULL;
975                 g_file_move (old_accels_file, new_accels_file, 0, NULL, NULL, NULL, &error);
976                 if (error) {
977                         g_warning ("Error migrating accelerator specifications file %s: %s\n",
978                                    old_accels, error->message);
979                         g_error_free (error);
980                 }
981
982                 g_free (new_accels);
983                 g_object_unref (old_accels_file);
984                 g_object_unref (new_accels_file);
985         }
986
987         g_free (old_accels);
988 }
989
990 void
991 ev_application_shutdown (EvApplication *application)
992 {
993         if (application->uri) {
994 #ifdef ENABLE_DBUS
995                 ev_application_unregister_uri (application,
996                                                application->uri);
997 #endif
998                 g_free (application->uri);
999                 application->uri = NULL;
1000         }
1001
1002         ev_application_accel_map_save (application);
1003
1004         g_object_unref (application->scr_saver);
1005         application->scr_saver = NULL;
1006
1007 #ifdef ENABLE_DBUS
1008         if (application->keys) {
1009                 g_object_unref (application->keys);
1010                 application->keys = NULL;
1011         }
1012         if (application->registration_id != 0) {
1013                 g_dbus_connection_unregister_object (application->connection,
1014                                                      application->registration_id);
1015                 application->registration_id = 0;
1016         }
1017         if (application->connection != NULL) {
1018                 g_object_unref (application->connection);
1019                 application->connection = NULL;
1020         }
1021         if (introspection_data) {
1022                 g_dbus_node_info_ref (introspection_data);
1023                 introspection_data = NULL;
1024         }
1025 #endif /* ENABLE_DBUS */
1026         
1027         g_free (application->dot_dir);
1028         application->dot_dir = NULL;
1029         g_free (application->data_dir);
1030         application->data_dir = NULL;
1031         g_free (application->filechooser_open_uri);
1032         application->filechooser_open_uri = NULL;
1033         g_free (application->filechooser_save_uri);
1034         application->filechooser_save_uri = NULL;
1035
1036         g_object_unref (application);
1037         instance = NULL;
1038         
1039         gtk_main_quit ();
1040 }
1041
1042 static void
1043 ev_application_class_init (EvApplicationClass *ev_application_class)
1044 {
1045 }
1046
1047 static void
1048 ev_application_init (EvApplication *ev_application)
1049 {
1050         GError *error = NULL;
1051
1052         ev_application->dot_dir = g_build_filename (g_get_user_config_dir (),
1053                                                     "evince", NULL);
1054         if (!g_file_test (ev_application->dot_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
1055                 ev_application_migrate_config_dir (ev_application);
1056
1057 #ifdef G_OS_WIN32
1058 {
1059         gchar *dir;
1060
1061         dir = g_win32_get_package_installation_directory_of_module (NULL);
1062         ev_application->data_dir = g_build_filename (dir, "share", "evince", NULL);
1063         g_free (dir);
1064 }
1065 #else
1066         ev_application->data_dir = g_strdup (EVINCEDATADIR);
1067 #endif
1068
1069         ev_application_init_session (ev_application);
1070
1071         ev_application_accel_map_load (ev_application);
1072
1073 #ifdef ENABLE_DBUS
1074         ev_application->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1075         if (ev_application->connection != NULL) {
1076                 introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
1077                 g_assert (introspection_data != NULL);
1078
1079                 ev_application->registration_id =
1080                     g_dbus_connection_register_object (ev_application->connection,
1081                                                        APPLICATION_DBUS_OBJECT_PATH,
1082                                                        introspection_data->interfaces[0],
1083                                                        &interface_vtable,
1084                                                        ev_application, NULL,
1085                                                        &error);
1086                 if (ev_application->registration_id == 0) {
1087                         g_printerr ("Failed to register bus object: %s\n", error->message);
1088                         g_error_free (error);
1089                 }
1090         } else {
1091                 g_printerr ("Failed to get bus connection: %s\n", error->message);
1092                 g_error_free (error);
1093         }
1094
1095         ev_application->keys = ev_media_player_keys_new ();
1096 #endif /* ENABLE_DBUS */
1097
1098         ev_application->scr_saver = totem_scrsaver_new ();
1099         g_object_set (ev_application->scr_saver,
1100                       "reason", _("Running in presentation mode"),
1101                       NULL);
1102 }
1103
1104 GDBusConnection *
1105 ev_application_get_dbus_connection (EvApplication *application)
1106 {
1107 #ifdef ENABLE_DBUS
1108         return application->connection;
1109 #else
1110         return NULL;
1111 #endif
1112 }
1113
1114 gboolean
1115 ev_application_has_window (EvApplication *application)
1116 {
1117         GList    *l, *toplevels;
1118         gboolean  retval = FALSE;
1119
1120         toplevels = gtk_window_list_toplevels ();
1121
1122         for (l = toplevels; l != NULL && !retval; l = l->next) {
1123                 if (EV_IS_WINDOW (l->data))
1124                         retval = TRUE;
1125         }
1126
1127         g_list_free (toplevels);
1128
1129         return retval;
1130 }
1131
1132 guint
1133 ev_application_get_n_windows (EvApplication *application)
1134 {
1135         GList *l, *toplevels;
1136         guint  retval = 0;
1137
1138         toplevels = gtk_window_list_toplevels ();
1139
1140         for (l = toplevels; l != NULL; l = l->next) {
1141                 if (EV_IS_WINDOW (l->data))
1142                         retval++;
1143         }
1144
1145         g_list_free (toplevels);
1146
1147         return retval;
1148 }
1149
1150 const gchar *
1151 ev_application_get_uri (EvApplication *application)
1152 {
1153         return application->uri;
1154 }
1155
1156 /**
1157  * ev_application_get_media_keys:
1158  * @application: The instance of the application.
1159  *
1160  * It gives you access to the media player keys handler object.
1161  *
1162  * Returns: A #EvMediaPlayerKeys.
1163  */
1164 GObject *
1165 ev_application_get_media_keys (EvApplication *application)
1166 {
1167 #ifdef ENABLE_DBUS
1168         return G_OBJECT (application->keys);
1169 #else
1170         return NULL;
1171 #endif /* ENABLE_DBUS */
1172 }
1173
1174 void
1175 ev_application_set_filechooser_uri (EvApplication       *application,
1176                                     GtkFileChooserAction action,
1177                                     const gchar         *uri)
1178 {
1179         if (action == GTK_FILE_CHOOSER_ACTION_OPEN) {
1180                 g_free (application->filechooser_open_uri);
1181                 application->filechooser_open_uri = g_strdup (uri);
1182         } else if (action == GTK_FILE_CHOOSER_ACTION_SAVE) {
1183                 g_free (application->filechooser_save_uri);
1184                 application->filechooser_save_uri = g_strdup (uri);
1185         }
1186 }
1187
1188 const gchar *
1189 ev_application_get_filechooser_uri (EvApplication       *application,
1190                                     GtkFileChooserAction action)
1191 {
1192         if (action == GTK_FILE_CHOOSER_ACTION_OPEN) {
1193                 if (application->filechooser_open_uri)
1194                         return application->filechooser_open_uri;
1195         } else if (action == GTK_FILE_CHOOSER_ACTION_SAVE) {
1196                 if (application->filechooser_save_uri)
1197                         return application->filechooser_save_uri;
1198         }
1199
1200         return NULL;
1201 }
1202
1203 void
1204 ev_application_screensaver_enable (EvApplication *application)
1205 {
1206         totem_scrsaver_enable (application->scr_saver);
1207 }
1208
1209 void
1210 ev_application_screensaver_disable (EvApplication *application)
1211 {
1212         totem_scrsaver_disable (application->scr_saver);
1213 }
1214
1215 const gchar *
1216 ev_application_get_dot_dir (EvApplication *application,
1217                             gboolean create)
1218 {
1219         if (create)
1220                 g_mkdir_with_parents (application->dot_dir, 0700);
1221
1222         return application->dot_dir;
1223 }
1224
1225 const gchar *
1226 ev_application_get_data_dir (EvApplication   *application)
1227 {
1228         return application->data_dir;
1229 }