Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-application.c
Go to the documentation of this file.
1 /* this file is part of evince, a gnome document viewer
2  *
3  * Copyright (C) 2004 Martin Kretzschmar
4  * Copyright © 2010, 2012 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 "ev-application.h"
39 #include "ev-file-helpers.h"
40 #include "ev-stock-icons.h"
41 
42 #ifdef ENABLE_DBUS
43 #include "ev-gdbus-generated.h"
44 #include "ev-media-player-keys.h"
45 #endif /* ENABLE_DBUS */
46 
48  GtkApplication base_instance;
49 
50  gchar *uri;
51 
52  gchar *dot_dir;
53 
54 #ifdef ENABLE_DBUS
55  EvEvinceApplication *skeleton;
56  EvMediaPlayerKeys *keys;
57  gboolean doc_registered;
58 #endif
59 };
60 
62  GtkApplicationClass base_class;
63 };
64 
65 G_DEFINE_TYPE (EvApplication, ev_application, GTK_TYPE_APPLICATION)
66 
67 #ifdef ENABLE_DBUS
68 #define APPLICATION_DBUS_OBJECT_PATH "/org/gnome/evince/Evince"
69 #define APPLICATION_DBUS_INTERFACE "org.gnome.evince.Application"
70 
71 #define EVINCE_DAEMON_SERVICE "org.gnome.evince.Daemon"
72 #define EVINCE_DAEMON_OBJECT_PATH "/org/gnome/evince/Daemon"
73 #define EVINCE_DAEMON_INTERFACE "org.gnome.evince.Daemon"
74 #endif
75 
76 static void _ev_application_open_uri_at_dest (EvApplication *application,
77  const gchar *uri,
78  GdkScreen *screen,
79  EvLinkDest *dest,
80  EvWindowRunMode mode,
81  const gchar *search_string,
82  guint timestamp);
83 static void ev_application_open_uri_in_window (EvApplication *application,
84  const char *uri,
85  EvWindow *ev_window,
86  GdkScreen *screen,
87  EvLinkDest *dest,
88  EvWindowRunMode mode,
89  const gchar *search_string,
90  guint timestamp);
91 
101 {
102  const GApplicationFlags flags = G_APPLICATION_NON_UNIQUE;
103 
104  return g_object_new (EV_TYPE_APPLICATION,
105  "application-id", NULL,
106  "flags", flags,
107  NULL);
108 }
109 
110 #ifdef ENABLE_DBUS
111 
120 static GdkDisplay *
121 ev_display_open_if_needed (const gchar *name)
122 {
123  GSList *displays;
124  GSList *l;
125  GdkDisplay *display = NULL;
126 
127  displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
128 
129  for (l = displays; l != NULL; l = l->next) {
130  const gchar *display_name = gdk_display_get_name ((GdkDisplay *) l->data);
131 
132  /* The given name might come with the screen number, because GdkAppLaunchContext
133  * uses gdk_screen_make_display_name().
134  */
135  if (g_str_has_prefix (name, display_name)) {
136  display = l->data;
137  break;
138  }
139  }
140 
141  g_slist_free (displays);
142 
143  return display != NULL ? display : gdk_display_open (name);
144 }
145 #endif
146 
147 static void
148 ev_spawn (const char *uri,
149  GdkScreen *screen,
150  EvLinkDest *dest,
151  EvWindowRunMode mode,
152  const gchar *search_string,
153  guint timestamp)
154 {
155  GString *cmd;
156  gchar *path, *cmdline;
157  GAppInfo *app;
158  GError *error = NULL;
159 
160  cmd = g_string_new (NULL);
161 
162 #ifdef G_OS_WIN32
163 {
164  gchar *dir;
165 
166  dir = g_win32_get_package_installation_directory_of_module (NULL);
167  path = g_build_filename (dir, "bin", "evince", NULL);
168 
169  g_free (dir);
170 }
171 #else
172  path = g_build_filename (BINDIR, "evince", NULL);
173 #endif
174 
175  g_string_append_printf (cmd, " %s", path);
176  g_free (path);
177 
178  /* Page label */
179  if (dest) {
180  switch (ev_link_dest_get_dest_type (dest)) {
182  g_string_append_printf (cmd, " --page-label=%s",
184  break;
186  g_string_append_printf (cmd, " --page-index=%d",
187  ev_link_dest_get_page (dest) + 1);
188  break;
190  g_string_append_printf (cmd, " --named-dest=%s",
192  break;
193  default:
194  break;
195  }
196  }
197 
198  /* Find string */
199  if (search_string) {
200  g_string_append_printf (cmd, " --find=%s", search_string);
201  }
202 
203  /* Mode */
204  switch (mode) {
206  g_string_append (cmd, " -f");
207  break;
209  g_string_append (cmd, " -s");
210  break;
211  default:
212  break;
213  }
214 
215  cmdline = g_string_free (cmd, FALSE);
216  app = g_app_info_create_from_commandline (cmdline, NULL, G_APP_INFO_CREATE_SUPPORTS_URIS, &error);
217 
218  if (app != NULL) {
219  GList uri_list;
220  GList *uris = NULL;
221  GdkAppLaunchContext *ctx;
222 
223  ctx = gdk_display_get_app_launch_context (gdk_screen_get_display (screen));
224  gdk_app_launch_context_set_screen (ctx, screen);
225  gdk_app_launch_context_set_timestamp (ctx, timestamp);
226 
227  /* Some URIs can be changed when passed through a GFile
228  * (for instance unsupported uris with strange formats like mailto:),
229  * so if you have a textual uri you want to pass in as argument,
230  * consider using g_app_info_launch_uris() instead.
231  * See https://bugzilla.gnome.org/show_bug.cgi?id=644604
232  */
233  if (uri) {
234  uri_list.data = (gchar *)uri;
235  uri_list.prev = uri_list.next = NULL;
236  uris = &uri_list;
237  }
238  g_app_info_launch_uris (app, uris, G_APP_LAUNCH_CONTEXT (ctx), &error);
239 
240  g_object_unref (app);
241  g_object_unref (ctx);
242  }
243 
244  if (error != NULL) {
245  g_printerr ("Error launching evince %s: %s\n", uri, error->message);
246  g_error_free (error);
247  }
248 
249  g_free (cmdline);
250 }
251 
252 static EvWindow *
254  GdkScreen *screen)
255 {
256  EvWindow *empty_window = NULL;
257  GList *windows, *l;
258 
259  windows = gtk_application_get_windows (GTK_APPLICATION (application));
260  for (l = windows; l != NULL; l = l->next) {
261  EvWindow *window;
262 
263  if (!EV_IS_WINDOW (l->data))
264  continue;
265 
266  window = EV_WINDOW (l->data);
267 
268  if (ev_window_is_empty (window) &&
269  gtk_window_get_screen (GTK_WINDOW (window)) == screen) {
270  empty_window = window;
271  break;
272  }
273  }
274 
275  return empty_window;
276 }
277 
278 
279 #ifdef ENABLE_DBUS
280 typedef struct {
281  gchar *uri;
282  GdkScreen *screen;
283  EvLinkDest *dest;
284  EvWindowRunMode mode;
285  gchar *search_string;
286  guint timestamp;
287 } EvRegisterDocData;
288 
289 static void
290 ev_register_doc_data_free (EvRegisterDocData *data)
291 {
292  if (!data)
293  return;
294 
295  g_free (data->uri);
296  if (data->search_string)
297  g_free (data->search_string);
298  if (data->dest)
299  g_object_unref (data->dest);
300 
301  g_free (data);
302 }
303 
304 static void
305 on_reload_cb (GObject *source_object,
306  GAsyncResult *res,
307  gpointer user_data)
308 {
309  GDBusConnection *connection = G_DBUS_CONNECTION (source_object);
310  GVariant *value;
311  GError *error = NULL;
312 
313  g_application_release (g_application_get_default ());
314 
315  value = g_dbus_connection_call_finish (connection, res, &error);
316  if (value != NULL) {
317  g_variant_unref (value);
318  } else {
319  g_printerr ("Failed to Reload: %s\n", error->message);
320  g_error_free (error);
321  }
322 
323  /* We did not open a window, so manually clear the startup
324  * notification. */
325  gdk_notify_startup_complete ();
326 }
327 
328 static void
329 on_register_uri_cb (GObject *source_object,
330  GAsyncResult *res,
331  gpointer user_data)
332 {
333  GDBusConnection *connection = G_DBUS_CONNECTION (source_object);
334  EvRegisterDocData *data = (EvRegisterDocData *)user_data;
335  EvApplication *application = EV_APP;
336  GVariant *value;
337  const gchar *owner;
338  GVariantBuilder builder;
339  GError *error = NULL;
340 
341  g_application_release (G_APPLICATION (application));
342 
343  value = g_dbus_connection_call_finish (connection, res, &error);
344  if (!value) {
345  g_printerr ("Error registering document: %s\n", error->message);
346  g_error_free (error);
347 
349  data->uri,
350  data->screen,
351  data->dest,
352  data->mode,
353  data->search_string,
354  data->timestamp);
355  ev_register_doc_data_free (data);
356 
357  return;
358  }
359 
360  g_variant_get (value, "(&s)", &owner);
361 
362  /* This means that the document wasn't already registered; go
363  * ahead with opening it.
364  */
365  if (owner[0] == '\0') {
366  g_variant_unref (value);
367 
368  application->doc_registered = TRUE;
369 
371  data->uri,
372  data->screen,
373  data->dest,
374  data->mode,
375  data->search_string,
376  data->timestamp);
377  ev_register_doc_data_free (data);
378 
379  return;
380  }
381 
382  /* Already registered */
383  g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{sv}u)"));
384  g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
385  g_variant_builder_add (&builder, "{sv}",
386  "display",
387  g_variant_new_string (gdk_display_get_name (gdk_screen_get_display (data->screen))));
388  if (data->dest) {
389  switch (ev_link_dest_get_dest_type (data->dest)) {
391  g_variant_builder_add (&builder, "{sv}", "page-label",
392  g_variant_new_string (ev_link_dest_get_page_label (data->dest)));
393  break;
395  g_variant_builder_add (&builder, "{sv}", "page-index",
396  g_variant_new_uint32 (ev_link_dest_get_page (data->dest)));
397  break;
399  g_variant_builder_add (&builder, "{sv}", "named-dest",
400  g_variant_new_string (ev_link_dest_get_named_dest (data->dest)));
401  break;
402  default:
403  break;
404  }
405  }
406  if (data->search_string) {
407  g_variant_builder_add (&builder, "{sv}",
408  "find-string",
409  g_variant_new_string (data->search_string));
410  }
411  if (data->mode != EV_WINDOW_MODE_NORMAL) {
412  g_variant_builder_add (&builder, "{sv}",
413  "mode",
414  g_variant_new_uint32 (data->mode));
415  }
416  g_variant_builder_close (&builder);
417 
418  g_variant_builder_add (&builder, "u", data->timestamp);
419 
420  g_dbus_connection_call (connection,
421  owner,
422  APPLICATION_DBUS_OBJECT_PATH,
423  APPLICATION_DBUS_INTERFACE,
424  "Reload",
425  g_variant_builder_end (&builder),
426  NULL,
427  G_DBUS_CALL_FLAGS_NONE,
428  -1,
429  NULL,
430  on_reload_cb,
431  NULL);
432  g_application_hold (G_APPLICATION (application));
433  g_variant_unref (value);
434  ev_register_doc_data_free (data);
435 }
436 
437 /*
438  * ev_application_register_uri:
439  * @application: The instance of the application.
440  * @uri: The uri to be opened.
441  * @screen: The screen where the link will be shown.
442  * @dest: The #EvLinkDest of the document.
443  * @mode: The run mode of the window.
444  * @search_string: The word or phrase to find in the document.
445  * @timestamp: Current time value.
446  *
447  * Registers @uri with evince-daemon.
448  *
449  */
450 static void
451 ev_application_register_uri (EvApplication *application,
452  const gchar *uri,
453  GdkScreen *screen,
454  EvLinkDest *dest,
455  EvWindowRunMode mode,
456  const gchar *search_string,
457  guint timestamp)
458 {
459  EvRegisterDocData *data;
460 
461  /* If connection hasn't been made fall back to opening without D-BUS features */
462  if (!application->skeleton) {
463  _ev_application_open_uri_at_dest (application, uri, screen, dest, mode, search_string, timestamp);
464  return;
465  }
466 
467  if (application->doc_registered) {
468  /* Already registered, reload */
469  GList *windows, *l;
470 
471  windows = gtk_application_get_windows (GTK_APPLICATION (application));
472  for (l = windows; l != NULL; l = g_list_next (l)) {
473  if (!EV_IS_WINDOW (l->data))
474  continue;
475 
476  ev_application_open_uri_in_window (application, uri,
477  EV_WINDOW (l->data),
478  screen, dest, mode,
479  search_string,
480  timestamp);
481  }
482 
483  return;
484  }
485 
486  data = g_new (EvRegisterDocData, 1);
487  data->uri = g_strdup (uri);
488  data->screen = screen;
489  data->dest = dest ? g_object_ref (dest) : NULL;
490  data->mode = mode;
491  data->search_string = search_string ? g_strdup (search_string) : NULL;
492  data->timestamp = timestamp;
493 
494  g_dbus_connection_call (g_application_get_dbus_connection (G_APPLICATION (application)),
495  EVINCE_DAEMON_SERVICE,
496  EVINCE_DAEMON_OBJECT_PATH,
497  EVINCE_DAEMON_INTERFACE,
498  "RegisterDocument",
499  g_variant_new ("(s)", uri),
500  G_VARIANT_TYPE ("(s)"),
501  G_DBUS_CALL_FLAGS_NONE,
502  -1,
503  NULL,
504  on_register_uri_cb,
505  data);
506 
507  g_application_hold (G_APPLICATION (application));
508 }
509 
510 static void
511 ev_application_unregister_uri (EvApplication *application,
512  const gchar *uri)
513 {
514  GVariant *value;
515  GError *error = NULL;
516 
517  if (!application->doc_registered)
518  return;
519 
520  /* This is called from ev_application_shutdown(),
521  * so it's safe to use the sync api
522  */
523  value = g_dbus_connection_call_sync (
524  g_application_get_dbus_connection (G_APPLICATION (application)),
525  EVINCE_DAEMON_SERVICE,
526  EVINCE_DAEMON_OBJECT_PATH,
527  EVINCE_DAEMON_INTERFACE,
528  "UnregisterDocument",
529  g_variant_new ("(s)", uri),
530  NULL,
531  G_DBUS_CALL_FLAGS_NO_AUTO_START,
532  -1,
533  NULL,
534  &error);
535  if (value == NULL) {
536  g_printerr ("Error unregistering document: %s\n", error->message);
537  g_error_free (error);
538  } else {
539  g_variant_unref (value);
540  }
541 }
542 #endif /* ENABLE_DBUS */
543 
544 static void
546  const char *uri,
547  EvWindow *ev_window,
548  GdkScreen *screen,
549  EvLinkDest *dest,
550  EvWindowRunMode mode,
551  const gchar *search_string,
552  guint timestamp)
553 {
554 #ifdef GDK_WINDOWING_X11
555  GdkWindow *gdk_window;
556 #endif
557 
558  if (uri == NULL)
559  uri = application->uri;
560 
561  if (screen) {
562  ev_stock_icons_set_screen (screen);
563  gtk_window_set_screen (GTK_WINDOW (ev_window), screen);
564  }
565 
566  /* We need to load uri before showing the window, so
567  we can restore window size without flickering */
568  ev_window_open_uri (ev_window, uri, dest, mode, search_string);
569 
570  if (!gtk_widget_get_realized (GTK_WIDGET (ev_window)))
571  gtk_widget_realize (GTK_WIDGET (ev_window));
572 
573 #ifdef GDK_WINDOWING_X11
574  gdk_window = gtk_widget_get_window (GTK_WIDGET (ev_window));
575  if (GDK_IS_X11_WINDOW (gdk_window)) {
576  if (timestamp <= 0)
577  timestamp = gdk_x11_get_server_time (gdk_window);
578  gdk_x11_window_set_user_time (gdk_window, timestamp);
579 
580  gtk_window_present (GTK_WINDOW (ev_window));
581  } else
582 #endif /* GDK_WINDOWING_X11 */
583  {
584  gtk_window_present_with_time (GTK_WINDOW (ev_window), timestamp);
585  }
586 }
587 
588 static void
590  const gchar *uri,
591  GdkScreen *screen,
592  EvLinkDest *dest,
593  EvWindowRunMode mode,
594  const gchar *search_string,
595  guint timestamp)
596 {
597  EvWindow *ev_window;
598 
599  ev_window = ev_application_get_empty_window (application, screen);
600  if (!ev_window)
601  ev_window = EV_WINDOW (ev_window_new ());
602 
603  ev_application_open_uri_in_window (application, uri, ev_window,
604  screen, dest, mode,
605  search_string,
606  timestamp);
607 }
608 
619 void
621  const char *uri,
622  GdkScreen *screen,
623  EvLinkDest *dest,
624  EvWindowRunMode mode,
625  const gchar *search_string,
626  guint timestamp)
627 {
628  g_return_if_fail (uri != NULL);
629 
630  if (application->uri && strcmp (application->uri, uri) != 0) {
631  /* spawn a new evince process */
632  ev_spawn (uri, screen, dest, mode, search_string, timestamp);
633  return;
634  } else if (!application->uri) {
635  application->uri = g_strdup (uri);
636  }
637 
638 #ifdef ENABLE_DBUS
639  /* Register the uri or send Reload to
640  * remote instance if already registered
641  */
642  ev_application_register_uri (application, uri, screen, dest, mode, search_string, timestamp);
643 #else
644  _ev_application_open_uri_at_dest (application, uri, screen, dest, mode, search_string, timestamp);
645 #endif /* ENABLE_DBUS */
646 }
647 
648 static void
650  GdkScreen *screen,
651  guint32 timestamp)
652 {
653  /* spawn an empty window */
654  ev_spawn (NULL, screen, NULL, EV_WINDOW_MODE_NORMAL, NULL, timestamp);
655 }
656 
664 void
666  GdkScreen *screen,
667  guint32 timestamp)
668 {
669  GtkWidget *new_window = ev_window_new ();
670 
671  ev_window_open_recent_view (EV_WINDOW (new_window));
672 
673 #ifdef GDK_WINDOWING_X11
674  GdkWindow *gdk_window;
675 #endif
676 
677  if (screen) {
678  ev_stock_icons_set_screen (screen);
679  gtk_window_set_screen (GTK_WINDOW (new_window), screen);
680  }
681 
682  if (!gtk_widget_get_realized (new_window))
683  gtk_widget_realize (new_window);
684 
685 #ifdef GDK_WINDOWING_X11
686  gdk_window = gtk_widget_get_window (GTK_WIDGET (new_window));
687  if (GDK_IS_X11_WINDOW (gdk_window)) {
688  if (timestamp <= 0)
689  timestamp = gdk_x11_get_server_time (gdk_window);
690  gdk_x11_window_set_user_time (gdk_window, timestamp);
691 
692  gtk_window_present (GTK_WINDOW (new_window));
693  } else
694 #endif /* GDK_WINDOWING_X11 */
695  {
696  gtk_window_present_with_time (GTK_WINDOW (new_window), timestamp);
697  }
698 }
699 
700 #ifdef ENABLE_DBUS
701 static gboolean
702 handle_get_window_list_cb (EvEvinceApplication *object,
703  GDBusMethodInvocation *invocation,
704  EvApplication *application)
705 {
706  GList *windows, *l;
707  GPtrArray *paths;
708 
709  paths = g_ptr_array_new ();
710 
711  windows = gtk_application_get_windows (GTK_APPLICATION (application));
712  for (l = windows; l; l = g_list_next (l)) {
713  if (!EV_IS_WINDOW (l->data))
714  continue;
715 
716  g_ptr_array_add (paths, (gpointer) ev_window_get_dbus_object_path (EV_WINDOW (l->data)));
717  }
718 
719  g_ptr_array_add (paths, NULL);
720  ev_evince_application_complete_get_window_list (object, invocation,
721  (const char * const *) paths->pdata);
722 
723  g_ptr_array_free (paths, TRUE);
724 
725  return TRUE;
726 }
727 
728 static gboolean
729 handle_reload_cb (EvEvinceApplication *object,
730  GDBusMethodInvocation *invocation,
731  GVariant *args,
732  guint timestamp,
733  EvApplication *application)
734 {
735  GList *windows, *l;
736  GVariantIter iter;
737  const gchar *key;
738  GVariant *value;
739  GdkDisplay *display = NULL;
740  EvLinkDest *dest = NULL;
742  const gchar *search_string = NULL;
743  GdkScreen *screen = NULL;
744 
745  g_variant_iter_init (&iter, args);
746 
747  while (g_variant_iter_loop (&iter, "{&sv}", &key, &value)) {
748  if (strcmp (key, "display") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
749  display = ev_display_open_if_needed (g_variant_get_string (value, NULL));
750  } else if (strcmp (key, "mode") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_UINT32) {
751  mode = g_variant_get_uint32 (value);
752  } else if (strcmp (key, "page-label") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
753  dest = ev_link_dest_new_page_label (g_variant_get_string (value, NULL));
754  } else if (strcmp (key, "named-dest") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
755  dest = ev_link_dest_new_named (g_variant_get_string (value, NULL));
756  } else if (strcmp (key, "page-index") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_UINT32) {
757  dest = ev_link_dest_new_page (g_variant_get_uint32 (value));
758  } else if (strcmp (key, "find-string") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
759  search_string = g_variant_get_string (value, NULL);
760  }
761  }
762 
763  if (display != NULL)
764  screen = gdk_display_get_default_screen (display);
765  else
766  screen = gdk_screen_get_default ();
767 
768  windows = gtk_application_get_windows (GTK_APPLICATION ((application)));
769  for (l = windows; l != NULL; l = g_list_next (l)) {
770  if (!EV_IS_WINDOW (l->data))
771  continue;
772 
773  ev_application_open_uri_in_window (application, NULL,
774  EV_WINDOW (l->data),
775  screen, dest, mode,
776  search_string,
777  timestamp);
778  }
779 
780  if (dest)
781  g_object_unref (dest);
782 
783  ev_evince_application_complete_reload (object, invocation);
784 
785  return TRUE;
786 }
787 #endif /* ENABLE_DBUS */
788 
789 void
791  GSList *uri_list,
792  GdkScreen *screen,
793  guint timestamp)
794 {
795  GSList *l;
796 
797  for (l = uri_list; l != NULL; l = l->next) {
798  ev_application_open_uri_at_dest (application, (char *)l->data,
799  screen, NULL, 0, NULL,
800  timestamp);
801  }
802 }
803 
804 static void
806 {
807  gchar *accel_map_file;
808  gchar *tmp_filename;
809  gint fd;
810 
811  accel_map_file = g_build_filename (application->dot_dir, "accels", NULL);
812  tmp_filename = g_strdup_printf ("%s.XXXXXX", accel_map_file);
813 
814  fd = g_mkstemp (tmp_filename);
815  if (fd == -1) {
816  g_free (accel_map_file);
817  g_free (tmp_filename);
818 
819  return;
820  }
821  gtk_accel_map_save_fd (fd);
822  close (fd);
823 
824  g_mkdir_with_parents (application->dot_dir, 0700);
825  if (g_rename (tmp_filename, accel_map_file) == -1) {
826  /* FIXME: win32? */
827  g_unlink (tmp_filename);
828  }
829 
830  g_free (accel_map_file);
831  g_free (tmp_filename);
832 }
833 
834 static void
836 {
837  gchar *accel_map_file;
838 
839  accel_map_file = g_build_filename (application->dot_dir, "accels", NULL);
840  gtk_accel_map_load (accel_map_file);
841  g_free (accel_map_file);
842 }
843 
844 static void
846 {
847  const gchar *userdir;
848  gchar *old_dot_dir;
849  gchar *old_accels;
850  GError *error;
851  gint i;
852  gboolean dir_created = FALSE;
853  static const gchar *config_files[] = {
854  "evince_toolbar.xml",
855  "print-settings",
856  NULL
857  };
858 
859  userdir = g_getenv ("GNOME22_USER_DIR");
860  if (userdir) {
861  old_dot_dir = g_build_filename (userdir, "evince", NULL);
862  old_accels = g_build_filename (userdir, "accels", "evince", NULL);
863  } else {
864  old_dot_dir = g_build_filename (g_get_home_dir (),
865  ".gnome2",
866  "evince",
867  NULL);
868  old_accels = g_build_filename (g_get_home_dir (),
869  ".gnome2", "accels",
870  "evince", NULL);
871  }
872 
873  if (g_file_test (old_dot_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
874  for (i = 0; config_files[i]; i++) {
875  gchar *old_filename;
876  gchar *new_filename;
877  GFile *old_file;
878  GFile *new_file;
879 
880  old_filename = g_build_filename (old_dot_dir, config_files[i], NULL);
881  if (!g_file_test (old_filename, G_FILE_TEST_EXISTS)) {
882  g_free (old_filename);
883  continue;
884  }
885 
886  if (!dir_created) {
887  g_mkdir_with_parents (application->dot_dir, 0700);
888  dir_created = TRUE;
889  }
890 
891  new_filename = g_build_filename (application->dot_dir, config_files[i], NULL);
892  old_file = g_file_new_for_path (old_filename);
893  new_file = g_file_new_for_path (new_filename);
894 
895  error = NULL;
896  g_file_move (old_file, new_file, 0, NULL, NULL, NULL, &error);
897  if (error) {
898  g_printerr ("Error migrating config file %s: %s\n",
899  old_filename, error->message);
900  g_error_free (error);
901  }
902 
903  g_free (old_filename);
904  g_free (new_filename);
905  g_object_unref (old_file);
906  g_object_unref (new_file);
907  }
908  }
909 
910  g_free (old_dot_dir);
911 
912  if (g_file_test (old_accels, G_FILE_TEST_EXISTS)) {
913  gchar *new_accels;
914  GFile *old_accels_file;
915  GFile *new_accels_file;
916 
917  if (!dir_created)
918  g_mkdir_with_parents (application->dot_dir, 0700);
919 
920  new_accels = g_build_filename (application->dot_dir, "accels", NULL);
921  old_accels_file = g_file_new_for_path (old_accels);
922  new_accels_file = g_file_new_for_path (new_accels);
923 
924  error = NULL;
925  g_file_move (old_accels_file, new_accels_file, 0, NULL, NULL, NULL, &error);
926  if (error) {
927  g_printerr ("Error migrating accelerator specifications file %s: %s\n",
928  old_accels, error->message);
929  g_error_free (error);
930  }
931 
932  g_free (new_accels);
933  g_object_unref (old_accels_file);
934  g_object_unref (new_accels_file);
935  }
936 
937  g_free (old_accels);
938 }
939 
940 static void
941 app_new_cb (GSimpleAction *action,
942  GVariant *parameter,
943  gpointer user_data)
944 {
945  EvApplication *application = user_data;
946  GList *windows, *l;
947  GtkWindow *window = NULL;
948 
949  windows = gtk_application_get_windows (GTK_APPLICATION (application));
950  for (l = windows; l != NULL; l = l->next) {
951  if (EV_IS_WINDOW (l->data)) {
952  window = GTK_WINDOW (l->data);
953  break;
954  }
955  }
956 
957  ev_application_new_window (application,
958  window ? gtk_window_get_screen (window) : gdk_screen_get_default (),
959  gtk_get_current_event_time ());
960 }
961 
962 static void
963 app_help_cb (GSimpleAction *action,
964  GVariant *parameter,
965  gpointer user_data)
966 {
967  EvApplication *application = user_data;
968 
969  ev_application_show_help (application, NULL, NULL);
970 }
971 
972 static void
973 app_about_cb (GSimpleAction *action,
974  GVariant *parameter,
975  gpointer user_data)
976 {
977  EvApplication *application = user_data;
978 
979  const char *authors[] = {
980  "Martin Kretzschmar <m_kretzschmar@gmx.net>",
981  "Jonathan Blandford <jrb@gnome.org>",
982  "Marco Pesenti Gritti <marco@gnome.org>",
983  "Nickolay V. Shmyrev <nshmyrev@yandex.ru>",
984  "Bryan Clark <clarkbw@gnome.org>",
985  "Carlos Garcia Campos <carlosgc@gnome.org>",
986  "Wouter Bolsterlee <wbolster@gnome.org>",
987  "Christian Persch <chpe" "\100" "gnome.org>",
988  NULL
989  };
990  const char *documenters[] = {
991  "Nickolay V. Shmyrev <nshmyrev@yandex.ru>",
992  "Phil Bull <philbull@gmail.com>",
993  "Tiffany Antpolski <tiffany.antopolski@gmail.com>",
994  NULL
995  };
996  const char *license[] = {
997  N_("Evince is free software; you can redistribute it and/or modify "
998  "it under the terms of the GNU General Public License as published by "
999  "the Free Software Foundation; either version 2 of the License, or "
1000  "(at your option) any later version.\n"),
1001  N_("Evince is distributed in the hope that it will be useful, "
1002  "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1003  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1004  "GNU General Public License for more details.\n"),
1005  N_("You should have received a copy of the GNU General Public License "
1006  "along with Evince; if not, write to the Free Software Foundation, Inc., "
1007  "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n")
1008  };
1009  char *license_trans;
1010 #ifdef ENABLE_NLS
1011  const char **p;
1012 
1013  for (p = authors; *p; ++p)
1014  *p = _(*p);
1015 
1016  for (p = documenters; *p; ++p)
1017  *p = _(*p);
1018 #endif
1019 
1020  license_trans = g_strconcat (_(license[0]), "\n",
1021  _(license[1]), "\n",
1022  _(license[2]), "\n",
1023  NULL);
1024 
1025  gtk_show_about_dialog (gtk_application_get_active_window (GTK_APPLICATION (application)),
1026  "name", _("Evince"),
1027  "version", VERSION,
1028  "copyright", _("© 1996–2014 The Evince authors"),
1029  "license", license_trans,
1030  "website", "https://wiki.gnome.org/Apps/Evince",
1031  "comments", _("Document Viewer"),
1032  "authors", authors,
1033  "documenters", documenters,
1034  "translator-credits", _("translator-credits"),
1035  "logo-icon-name", "evince",
1036  "wrap-license", TRUE,
1037  NULL);
1038 
1039  g_free (license_trans);
1040 }
1041 
1042 static void
1043 ev_application_startup (GApplication *gapplication)
1044 {
1045  const GActionEntry app_menu_actions[] = {
1046  { "new", app_new_cb, NULL, NULL, NULL },
1047  { "help", app_help_cb, NULL, NULL, NULL },
1048  { "about", app_about_cb, NULL, NULL, NULL }
1049  };
1050 
1051  const gchar *action_accels[] = {
1052  "win.open", "<Ctrl>O", NULL,
1053  "win.open-copy", "<Ctrl>N", NULL,
1054  "win.save-copy", "<Ctrl>S", NULL,
1055  "win.print", "<Ctrl>P", NULL,
1056  "win.show-properties", "<alt>Return", NULL,
1057  "win.copy", "<Ctrl>C", "<Ctrl>Insert", NULL,
1058  "win.select-all", "<Ctrl>A", NULL,
1059  "win.save-settings", "<Ctrl>T", NULL,
1060  "win.add-bookmark", "<Ctrl>D", NULL,
1061  "win.close", "<Ctrl>W", NULL,
1062  "win.escape", "Escape", NULL,
1063  "win.find", "<Ctrl>F", "slash", NULL,
1064  "win.find-next", "<Ctrl>G", NULL,
1065  "win.find-previous", "<Ctrl><Shift>G", NULL,
1066  "win.select-page", "<Ctrl>L", NULL,
1067  "win.go-backwards", "<Shift>Page_Up", NULL,
1068  "win.go-forward", "<Shift>Page_Down", NULL,
1069  "win.go-next-page", "n", NULL,
1070  "win.go-previous-page", "p", NULL,
1071  "win.go-back-history", "<alt>P", NULL,
1072  "win.go-forward-history", "<alt>N", NULL,
1073  "win.sizing-mode::fit-page", "f", NULL,
1074  "win.sizing-mode::fit-width", "w", NULL,
1075  "win.open-menu", "F10", NULL,
1076  "win.caret-navigation", "F7", NULL,
1077  "win.zoom-in", "plus", "<Ctrl>plus", "KP_Add", "<Ctrl>KP_Add", "equal", "<Ctrl>equal", NULL,
1078  "win.zoom-out", "minus", "<Ctrl>minus", "KP_Subtract", "<Ctrl>KP_Subtract", NULL,
1079  "win.show-side-pane", "F9", NULL,
1080  "win.fullscreen", "F11", NULL,
1081  "win.presentation", "F5", NULL,
1082  "win.continuous", "c", NULL,
1083  "win.dual-page", "d", NULL,
1084  "win.rotate-left", "<Ctrl>Left", NULL,
1085  "win.rotate-right", "<Ctrl>Right", NULL,
1086  "win.inverted-colors", "<Ctrl>I", NULL,
1087  "win.reload", "<Ctrl>R", NULL,
1088  NULL
1089  };
1090 
1091  EvApplication *application = EV_APPLICATION (gapplication);
1092  const gchar **it;
1093 
1094  g_application_set_resource_base_path (gapplication, "/org/gnome/evince");
1095 
1096  G_APPLICATION_CLASS (ev_application_parent_class)->startup (gapplication);
1097 
1098  g_action_map_add_action_entries (G_ACTION_MAP (application),
1099  app_menu_actions, G_N_ELEMENTS (app_menu_actions),
1100  application);
1101 
1102  for (it = action_accels; it[0]; it += g_strv_length ((gchar **)it) + 1)
1103  gtk_application_set_accels_for_action (GTK_APPLICATION (application), it[0], &it[1]);
1104 }
1105 
1106 static void
1107 ev_application_shutdown (GApplication *gapplication)
1108 {
1109  EvApplication *application = EV_APPLICATION (gapplication);
1110 
1111  if (application->uri) {
1112 #ifdef ENABLE_DBUS
1113  ev_application_unregister_uri (application,
1114  application->uri);
1115 #endif
1116  g_free (application->uri);
1117  application->uri = NULL;
1118  }
1119 
1120  ev_application_accel_map_save (application);
1121 
1122  g_free (application->dot_dir);
1123  application->dot_dir = NULL;
1124 
1125  G_APPLICATION_CLASS (ev_application_parent_class)->shutdown (gapplication);
1126 }
1127 
1128 static void
1129 ev_application_activate (GApplication *gapplication)
1130 {
1131  EvApplication *application = EV_APPLICATION (gapplication);
1132  GList *windows, *l;
1133 
1134  windows = gtk_application_get_windows (GTK_APPLICATION (application));
1135  for (l = windows; l != NULL; l = l->next) {
1136  if (!EV_IS_WINDOW (l->data))
1137  continue;
1138 
1139  gtk_window_present (GTK_WINDOW (l->data));
1140  }
1141 }
1142 
1143 #ifdef ENABLE_DBUS
1144 static gboolean
1145 ev_application_dbus_register (GApplication *gapplication,
1146  GDBusConnection *connection,
1147  const gchar *object_path,
1148  GError **error)
1149 {
1150  EvApplication *application = EV_APPLICATION (gapplication);
1151  EvEvinceApplication *skeleton;
1152 
1153  if (!G_APPLICATION_CLASS (ev_application_parent_class)->dbus_register (gapplication,
1154  connection,
1155  object_path,
1156  error))
1157  return FALSE;
1158 
1159  skeleton = ev_evince_application_skeleton_new ();
1160  if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton),
1161  connection,
1162  APPLICATION_DBUS_OBJECT_PATH,
1163  error)) {
1164  g_object_unref (skeleton);
1165 
1166  return FALSE;
1167  }
1168 
1169  application->skeleton = skeleton;
1170  g_signal_connect (skeleton, "handle-get-window-list",
1171  G_CALLBACK (handle_get_window_list_cb),
1172  application);
1173  g_signal_connect (skeleton, "handle-reload",
1174  G_CALLBACK (handle_reload_cb),
1175  application);
1176  application->keys = ev_media_player_keys_new ();
1177 
1178  return TRUE;
1179 }
1180 
1181 static void
1182 ev_application_dbus_unregister (GApplication *gapplication,
1183  GDBusConnection *connection,
1184  const gchar *object_path)
1185 {
1186  EvApplication *application = EV_APPLICATION (gapplication);
1187 
1188  if (application->keys) {
1189  g_object_unref (application->keys);
1190  application->keys = NULL;
1191  }
1192  if (application->skeleton != NULL) {
1193  g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (application->skeleton));
1194  g_object_unref (application->skeleton);
1195  application->skeleton = NULL;
1196  }
1197 
1198  G_APPLICATION_CLASS (ev_application_parent_class)->dbus_unregister (gapplication,
1199  connection,
1200  object_path);
1201 }
1202 
1203 #endif /* ENABLE_DBUS */
1204 
1205 static void
1207 {
1208  GApplicationClass *g_application_class = G_APPLICATION_CLASS (ev_application_class);
1209 
1210  g_application_class->startup = ev_application_startup;
1211  g_application_class->activate = ev_application_activate;
1212  g_application_class->shutdown = ev_application_shutdown;
1213 
1214 #ifdef ENABLE_DBUS
1215  g_application_class->dbus_register = ev_application_dbus_register;
1216  g_application_class->dbus_unregister = ev_application_dbus_unregister;
1217 #endif
1218 }
1219 
1220 static void
1222 {
1223  ev_application->dot_dir = g_build_filename (g_get_user_config_dir (),
1224  "evince", NULL);
1225  if (!g_file_test (ev_application->dot_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
1226  ev_application_migrate_config_dir (ev_application);
1227 
1228  ev_application_accel_map_load (ev_application);
1229 }
1230 
1231 gboolean
1233 {
1234  GList *l, *windows;
1235 
1236  windows = gtk_application_get_windows (GTK_APPLICATION (application));
1237  for (l = windows; l != NULL; l = l->next) {
1238  if (!EV_IS_WINDOW (l->data))
1239  continue;
1240 
1241  return TRUE;
1242  }
1243 
1244  return FALSE;
1245 }
1246 
1247 guint
1249 {
1250  GList *l, *windows;
1251  guint retval = 0;
1252 
1253  windows = gtk_application_get_windows (GTK_APPLICATION (application));
1254  for (l = windows; l != NULL && !retval; l = l->next) {
1255  if (!EV_IS_WINDOW (l->data))
1256  continue;
1257 
1258  retval++;
1259  }
1260 
1261  return retval;
1262 }
1263 
1264 const gchar *
1266 {
1267  return application->uri;
1268 }
1269 
1278 GObject *
1280 {
1281 #ifdef ENABLE_DBUS
1282  return G_OBJECT (application->keys);
1283 #else
1284  return NULL;
1285 #endif /* ENABLE_DBUS */
1286 }
1287 
1288 const gchar *
1290  gboolean create)
1291 {
1292  if (create)
1293  g_mkdir_with_parents (application->dot_dir, 0700);
1294 
1295  return application->dot_dir;
1296 }
1297 
1307 void
1309  GdkScreen *screen,
1310  const char *topic)
1311 {
1312  char *escaped_topic, *uri;
1313 
1314  if (topic != NULL) {
1315  escaped_topic = g_uri_escape_string (topic, NULL, TRUE);
1316  uri = g_strdup_printf ("help:evince/%s", escaped_topic);
1317  g_free (escaped_topic);
1318  } else {
1319  uri = g_strdup ("help:evince");
1320  }
1321 
1322  gtk_show_uri (screen, uri, gtk_get_current_event_time (), NULL);
1323  g_free (uri);
1324 }