]> www.fi.muni.cz Git - evince.git/blob - shell/ev-application.c
Add --without-libgnome, check for libgnome and libgnomeui separately, and
[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  *
5  *  Author:
6  *    Martin Kretzschmar <martink@gnome.org>
7  *
8  * Evince is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * Evince is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21  */
22
23 #include "ev-application.h"
24 #include "ev-utils.h"
25 #include "ev-file-helpers.h"
26 #include "ev-document-factory.h"
27 #include "totem-scrsaver.h"
28
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include <glib-object.h>
32 #include <gtk/gtkfilechooserdialog.h>
33 #include <gtk/gtkstock.h>
34 #include <gtk/gtkwidget.h>
35 #include <gtk/gtkmain.h>
36
37 #if WITH_GNOME
38 #include <libgnomeui/gnome-client.h>
39 #endif
40
41 #ifdef ENABLE_DBUS
42 #include "ev-application-service.h"
43 #include <dbus/dbus-glib-bindings.h>
44 #endif
45
46 #include <string.h>
47
48 struct _EvApplication {
49         GObject base_instance;
50
51         gchar *toolbars_file;
52
53         EggToolbarsModel *toolbars_model;
54
55 #ifndef HAVE_GTK_RECENT
56         EggRecentModel  *recent_model;
57 #endif
58
59         TotemScrsaver *scr_saver;
60
61         gchar *last_chooser_uri;
62 };
63
64 struct _EvApplicationClass {
65         GObjectClass base_class;
66 };
67
68 G_DEFINE_TYPE (EvApplication, ev_application, G_TYPE_OBJECT);
69
70 #define APPLICATION_SERVICE_NAME "org.gnome.evince.ApplicationService"
71
72 #ifdef ENABLE_DBUS
73 gboolean
74 ev_application_register_service (EvApplication *application)
75 {
76         static DBusGConnection *connection = NULL;
77         DBusGProxy *driver_proxy;
78         GError *err = NULL;
79         guint request_name_result;
80
81         if (connection) {
82                 g_warning ("Service already registered.");
83                 return FALSE;
84         }
85         
86         connection = dbus_g_bus_get (DBUS_BUS_STARTER, &err);
87         if (connection == NULL) {
88                 g_warning ("Service registration failed.");
89                 g_error_free (err);
90
91                 return FALSE;
92         }
93
94         driver_proxy = dbus_g_proxy_new_for_name (connection,
95                                                   DBUS_SERVICE_DBUS,
96                                                   DBUS_PATH_DBUS,
97                                                   DBUS_INTERFACE_DBUS);
98
99         if (!org_freedesktop_DBus_request_name (driver_proxy,
100                                                 APPLICATION_SERVICE_NAME,
101                                                 DBUS_NAME_FLAG_DO_NOT_QUEUE,
102                                                 &request_name_result, &err)) {
103                 g_warning ("Service registration failed.");
104                 g_clear_error (&err);
105         }
106
107         g_object_unref (driver_proxy);
108         
109         if (request_name_result == DBUS_REQUEST_NAME_REPLY_EXISTS) {
110                 return FALSE;
111         }
112
113         dbus_g_object_type_install_info (EV_TYPE_APPLICATION,
114                                          &dbus_glib_ev_application_object_info);
115         dbus_g_connection_register_g_object (connection,
116                                              "/org/gnome/evince/Evince",
117                                              G_OBJECT (application));
118         
119         application->scr_saver = totem_scrsaver_new (connection);
120         
121         return TRUE;
122 }
123 #endif /* ENABLE_DBUS */
124
125 /**
126  * ev_application_get_instance:
127  *
128  * Checks for #EvApplication instance, if it doesn't exist it does create it.
129  *
130  * Returns: an instance of the #EvApplication data.
131  */
132 EvApplication *
133 ev_application_get_instance (void)
134 {
135         static EvApplication *instance;
136
137         if (!instance) {
138                 instance = EV_APPLICATION (g_object_new (EV_TYPE_APPLICATION, NULL));
139         }
140
141         return instance;
142 }
143
144 #if WITH_GNOME
145 static void
146 removed_from_session (GnomeClient *client, EvApplication *application)
147 {
148         ev_application_shutdown (application);
149 }
150
151 static gint
152 save_session (GnomeClient *client, gint phase, GnomeSaveStyle save_style, gint shutdown,
153               GnomeInteractStyle interact_style, gint fast, EvApplication *application)
154 {
155         GList *windows, *l;
156         char **restart_argv;
157         int argc = 0, k;
158
159         windows = ev_application_get_windows (application);
160         restart_argv = g_new (char *, g_list_length (windows) + 1);
161         restart_argv[argc++] = g_strdup ("evince");
162
163         for (l = windows; l != NULL; l = l->next) {
164                 EvWindow *window = EV_WINDOW (l->data);
165                 restart_argv[argc++] = g_strdup (ev_window_get_uri (window));
166         }
167
168         gnome_client_set_restart_command (client, argc, restart_argv);
169
170         for (k = 0; k < argc; k++) {
171                 g_free (restart_argv[k]);
172         }
173
174         g_list_free (windows);
175         g_free (restart_argv);
176         
177         return TRUE;
178 }
179
180 static void
181 init_session (EvApplication *application)
182 {
183         GnomeClient *client;
184
185         client = gnome_master_client ();
186
187         g_signal_connect (client, "save_yourself",
188                           G_CALLBACK (save_session), application);      
189         g_signal_connect (client, "die",
190                           G_CALLBACK (removed_from_session), application);
191 }
192 #endif
193
194 /**
195  * ev_display_open_if_needed:
196  * @name: the name of the display to be open if it's needed.
197  *
198  * Search among all the open displays if any of them have the same name as the
199  * passed name. If the display isn't found it tries the open it.
200  *
201  * Returns: a #GdkDisplay of the display with the passed name.
202  */
203 static GdkDisplay *
204 ev_display_open_if_needed (const gchar *name)
205 {
206         GSList     *displays;
207         GSList     *l;
208         GdkDisplay *display = NULL;
209
210         displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
211
212         for (l = displays; l != NULL; l = l->next) {
213                 const gchar *display_name = gdk_display_get_name ((GdkDisplay *) l->data);
214
215                 if (g_ascii_strcasecmp (display_name, name) == 0) {
216                         display = l->data;
217                         break;
218                 }
219         }
220
221         g_slist_free (displays);
222
223         return display != NULL ? display : gdk_display_open (name);
224 }
225
226 /**
227  * get_screen_from_args:
228  * @args: a #GHashTable with data passed to the application.
229  *
230  * Looks for the screen in the display available in the hash table passed to the
231  * application. If the display isn't opened, it's opened and the #GdkScreen
232  * assigned to the screen in that display returned.
233  *
234  * Returns: the #GdkScreen assigned to the screen on the display indicated by
235  *          the data on the #GHashTable.
236  */
237 static GdkScreen *
238 get_screen_from_args (GHashTable *args)
239 {
240         GValue     *value = NULL;
241         GdkDisplay *display = NULL;
242         GdkScreen  *screen = NULL;
243
244         g_assert (args != NULL);
245         
246         value = g_hash_table_lookup (args, "display");
247         if (value) {
248                 const gchar *display_name;
249                 
250                 display_name = g_value_get_string (value);
251                 display = ev_display_open_if_needed (display_name);
252         }
253         
254         value = g_hash_table_lookup (args, "screen");
255         if (value) {
256                 gint screen_number;
257                 
258                 screen_number = g_value_get_int (value);
259                 screen = gdk_display_get_screen (display, screen_number);
260         }
261
262         return screen;
263 }
264
265 /**
266  * get_window_run_mode_from_args:
267  * @args: a #GHashTable with data passed to the application.
268  *
269  * It does look if the mode option has been passed from command line, using it
270  * as the window run mode, otherwise the run mode will be the normal mode.
271  *
272  * Returns: The window run mode passed from command line or
273  *          EV_WINDOW_MODE_NORMAL in other case.
274  */
275 static EvWindowRunMode
276 get_window_run_mode_from_args (GHashTable *args)
277 {
278         EvWindowRunMode  mode = EV_WINDOW_MODE_NORMAL;
279         GValue          *value = NULL;
280
281         g_assert (args != NULL);
282
283         value = g_hash_table_lookup (args, "mode");
284         if (value) {
285                 mode = g_value_get_uint (value);
286         }
287
288         return mode;
289 }
290
291 /**
292  * get_destination_from_args:
293  * @args: a #GHashTable with data passed to the application.
294  *
295  * It does look for the page-label argument parsed from the command line and
296  * if it does exist, it returns an #EvLinkDest.
297  *
298  * Returns: An #EvLinkDest to page-label if it has been passed from the command
299  *          line, NULL in other case.
300  */
301 static EvLinkDest *
302 get_destination_from_args (GHashTable *args)
303 {
304         EvLinkDest *dest = NULL;
305         GValue     *value = NULL;
306         
307         g_assert (args != NULL);
308         
309         value = g_hash_table_lookup (args, "page-label");
310         if (value) {
311                 const gchar *page_label;
312
313                 page_label = g_value_get_string (value);
314                 dest = ev_link_dest_new_page_label (page_label);
315         }
316
317         return dest;
318 }
319
320 /**
321  * get_unlink_temp_file_from_args:
322  * @args: a #GHashTable with data passed to the application.
323  *
324  * It does look if the unlink-temp-file option has been passed from the command
325  * line returning it's boolean representation, otherwise it does return %FALSE.
326  *
327  * Returns: the boolean representation of the unlink-temp-file value or %FALSE
328  *          in other case.
329  */
330 static gboolean
331 get_unlink_temp_file_from_args (GHashTable *args)
332 {
333         gboolean unlink_temp_file = FALSE;
334         GValue  *value = NULL;
335
336         g_assert (args != NULL);
337
338         value = g_hash_table_lookup (args, "unlink-temp-file");
339         if (value) {
340                 unlink_temp_file = g_value_get_boolean (value);
341         }
342         
343         return unlink_temp_file;
344 }
345
346 /**
347  * ev_application_open_window:
348  * @application: The instance of the application.
349  * @args: A #GHashTable with the arguments data.
350  * @timestamp: Current time value.
351  * @error: The #GError facility.
352  * 
353  * Creates a new window and if the args are available, it's not NULL, it gets
354  * the screen from them and assigns the just created window to it. At last it
355  * does show it.
356  *
357  * Returns: %TRUE.
358  */
359 gboolean
360 ev_application_open_window (EvApplication  *application,
361                             GHashTable     *args,
362                             guint32         timestamp,
363                             GError        **error)
364 {
365         GtkWidget *new_window = ev_window_new ();
366         GdkScreen *screen = NULL;
367
368         if (args) {
369                 screen = get_screen_from_args (args);
370         }
371         
372         if (screen) {
373                 gtk_window_set_screen (GTK_WINDOW (new_window), screen);
374         }
375         
376         gtk_widget_show (new_window);
377         
378         gtk_window_present_with_time (GTK_WINDOW (new_window),
379                                       timestamp);
380         return TRUE;
381 }
382
383 /**
384  * ev_application_get_empty_window:
385  * @application: The instance of the application.
386  * @screen: The screen where the empty window will be search.
387  *
388  * It does look if there is any empty window in the indicated screen.
389  *
390  * Returns: The first empty #EvWindow in the passed #GdkScreen or NULL in other
391  *          case.
392  */
393 static EvWindow *
394 ev_application_get_empty_window (EvApplication *application,
395                                  GdkScreen     *screen)
396 {
397         EvWindow *empty_window = NULL;
398         GList *windows = ev_application_get_windows (application);
399         GList *l;
400
401         for (l = windows; l != NULL; l = l->next) {
402                 EvWindow *window = EV_WINDOW (l->data);
403
404                 if (ev_window_is_empty (window) &&
405                     gtk_window_get_screen (GTK_WINDOW (window)) == screen) {
406                         empty_window = window;
407                         break;
408                 }
409         }
410
411         g_list_free (windows);
412         
413         return empty_window;
414 }
415
416 /**
417  * ev_application_get_uri_window:
418  * @application: The instance of the application.
419  * @uri: The uri to be opened.
420  *
421  * It looks in the list of the windows for the one with the document represented
422  * by the passed uri on it. If the window is empty or the document isn't present
423  * on any window, it will return NULL.
424  *
425  * Returns: The #EvWindow where the document represented by the passed uri is
426  *          shown, NULL in other case.
427  */
428 static EvWindow *
429 ev_application_get_uri_window (EvApplication *application, const char *uri)
430 {
431         EvWindow *uri_window = NULL;
432         GList *windows = gtk_window_list_toplevels ();
433         GList *l;
434
435         g_return_val_if_fail (uri != NULL, NULL);
436
437         for (l = windows; l != NULL; l = l->next) {
438                 if (EV_IS_WINDOW (l->data)) {
439                         EvWindow *window = EV_WINDOW (l->data);
440                         const char *window_uri = ev_window_get_uri (window);
441
442                         if (window_uri && strcmp (window_uri, uri) == 0 && !ev_window_is_empty (window)) {
443                                 uri_window = window;
444                                 break;
445                         }
446                 }
447         }
448
449         g_list_free (windows);
450         
451         return uri_window;
452 }
453
454 /**
455  * ev_application_open_uri_at_dest:
456  * @application: The instance of the application.
457  * @uri: The uri to be opened.
458  * @screen: Thee screen where the link will be shown.
459  * @dest: The #EvLinkDest of the document.
460  * @mode: The run mode of the window.
461  * @unlink_temp_file: The unlink_temp_file option value.
462  * @timestamp: Current time value.
463  */
464 void
465 ev_application_open_uri_at_dest (EvApplication  *application,
466                                  const char     *uri,
467                                  GdkScreen      *screen,
468                                  EvLinkDest     *dest,
469                                  EvWindowRunMode mode,
470                                  gboolean        unlink_temp_file,
471                                  guint           timestamp)
472 {
473         EvWindow     *new_window;
474         GtkIconTheme *icon_theme;
475
476         g_return_if_fail (uri != NULL);
477
478         icon_theme = gtk_icon_theme_get_for_screen (screen);
479         if (icon_theme) {
480                 gchar **path = NULL;
481                 gint    n_paths;
482                 gint    i;
483                 gchar  *ev_icons_path;
484
485                 /* GtkIconTheme will then look in Evince custom hicolor dir
486                  * for icons as well as the standard search paths
487                  */
488                 ev_icons_path = g_build_filename (DATADIR, "icons", NULL);
489                 gtk_icon_theme_get_search_path (icon_theme, &path, &n_paths);
490                 for (i = n_paths - 1; i >= 0; i--) {
491                         if (g_ascii_strcasecmp (ev_icons_path, path[i]) == 0)
492                                 break;
493                 }
494
495                 if (i < 0)
496                         gtk_icon_theme_append_search_path (icon_theme,
497                                                            ev_icons_path);
498
499                 g_free (ev_icons_path);
500                 g_strfreev (path);
501         }       
502
503         new_window = ev_application_get_uri_window (application, uri);
504         
505         if (new_window == NULL) {
506                 new_window = ev_application_get_empty_window (application, screen);
507         }
508
509         if (new_window == NULL) {
510                 new_window = EV_WINDOW (ev_window_new ());
511         }
512
513         if (screen)
514                 gtk_window_set_screen (GTK_WINDOW (new_window), screen);
515
516         /* We need to load uri before showing the window, so
517            we can restore window size without flickering */     
518         ev_window_open_uri (new_window, uri, dest, mode, unlink_temp_file);
519
520         ev_document_fc_mutex_lock ();
521         gtk_widget_show (GTK_WIDGET (new_window));
522         ev_document_fc_mutex_unlock ();
523
524         gtk_window_present_with_time (GTK_WINDOW (new_window),
525                                       timestamp);
526 }
527
528 /**
529  * ev_application_open_uri:
530  * @application: The instance of the application.
531  * @uri: The uri to be opened
532  * @args: A #GHashTable with the arguments data.
533  * @timestamp: Current time value.
534  * @error: The #GError facility.
535  */
536 gboolean
537 ev_application_open_uri (EvApplication  *application,
538                          const char     *uri,
539                          GHashTable     *args,
540                          guint           timestamp,
541                          GError        **error)
542 {
543         EvLinkDest      *dest = NULL;
544         EvWindowRunMode  mode = EV_WINDOW_MODE_NORMAL;
545         gboolean         unlink_temp_file = FALSE;
546         GdkScreen       *screen = NULL;
547
548         if (args) {
549                 screen = get_screen_from_args (args);
550                 dest = get_destination_from_args (args);
551                 mode = get_window_run_mode_from_args (args);
552                 unlink_temp_file = (mode == EV_WINDOW_MODE_PREVIEW &&
553                                     get_unlink_temp_file_from_args (args));
554         }
555         
556         ev_application_open_uri_at_dest (application, uri, screen,
557                                          dest, mode, unlink_temp_file, 
558                                          timestamp);
559
560         if (dest)
561                 g_object_unref (dest);
562
563         return TRUE;
564 }
565
566 void
567 ev_application_open_uri_list (EvApplication *application,
568                               GSList        *uri_list,
569                               GdkScreen     *screen,
570                               guint          timestamp)
571 {
572         GSList *l;
573
574         for (l = uri_list; l != NULL; l = l->next) {
575                 ev_application_open_uri_at_dest (application, (char *)l->data,
576                                                  screen, NULL, 0, FALSE, 
577                                                  timestamp);
578         }
579 }
580
581 void
582 ev_application_shutdown (EvApplication *application)
583 {
584         if (application->toolbars_model) {
585                 g_object_unref (application->toolbars_model);
586                 g_free (application->toolbars_file);
587                 application->toolbars_model = NULL;
588                 application->toolbars_file = NULL;
589         }
590
591 #ifndef HAVE_GTK_RECENT
592         if (application->recent_model) {
593                 g_object_unref (application->recent_model);
594                 application->recent_model = NULL;
595         }
596 #endif
597         
598         g_free (application->last_chooser_uri);
599         g_object_unref (application);
600         
601         gtk_main_quit ();
602 }
603
604 static void
605 ev_application_class_init (EvApplicationClass *ev_application_class)
606 {
607 }
608
609 static void
610 ev_application_init (EvApplication *ev_application)
611 {
612 #if WITH_GNOME
613         init_session (ev_application);
614 #endif
615
616         ev_application->toolbars_model = egg_toolbars_model_new ();
617
618         ev_application->toolbars_file = g_build_filename
619                         (ev_dot_dir (), "evince_toolbar.xml", NULL);
620
621         egg_toolbars_model_load_names (ev_application->toolbars_model,
622                                        DATADIR "/evince-toolbar.xml");
623
624         if (!egg_toolbars_model_load_toolbars (ev_application->toolbars_model,
625                                                ev_application->toolbars_file)) {
626                 egg_toolbars_model_load_toolbars (ev_application->toolbars_model,
627                                                   DATADIR"/evince-toolbar.xml");
628         }
629
630         egg_toolbars_model_set_flags (ev_application->toolbars_model, 0,
631                                       EGG_TB_MODEL_NOT_REMOVABLE); 
632
633 #ifndef HAVE_GTK_RECENT
634         ev_application->recent_model = egg_recent_model_new (EGG_RECENT_MODEL_SORT_MRU);
635         /* FIXME we should add a mime type filter but current eggrecent
636            has only a varargs style api which does not work well when
637            the list of mime types is dynamic */
638         egg_recent_model_set_limit (ev_application->recent_model, 5);   
639         egg_recent_model_set_filter_groups (ev_application->recent_model,
640                                             "Evince", NULL);
641 #endif /* HAVE_GTK_RECENT */
642 }
643
644 /**
645  * ev_application_get_windows:
646  * @application: The instance of the application.
647  *
648  * It creates a list of the top level windows.
649  *
650  * Returns: A #GList of the top level windows.
651  */
652 GList *
653 ev_application_get_windows (EvApplication *application)
654 {
655         GList *l, *toplevels;
656         GList *windows = NULL;
657
658         toplevels = gtk_window_list_toplevels ();
659
660         for (l = toplevels; l != NULL; l = l->next) {
661                 if (EV_IS_WINDOW (l->data)) {
662                         windows = g_list_append (windows, l->data);
663                 }
664         }
665
666         g_list_free (toplevels);
667
668         return windows;
669 }
670
671 EggToolbarsModel *
672 ev_application_get_toolbars_model (EvApplication *application)
673 {
674         return application->toolbars_model;
675 }
676
677 #ifndef HAVE_GTK_RECENT
678 EggRecentModel *
679 ev_application_get_recent_model (EvApplication *application)
680 {
681         return application->recent_model;
682 }
683 #endif
684
685 void
686 ev_application_save_toolbars_model (EvApplication *application)
687 {
688         egg_toolbars_model_save_toolbars (application->toolbars_model,
689                                           application->toolbars_file, "1.0");
690 }
691
692 void
693 ev_application_set_chooser_uri (EvApplication *application, const gchar *uri)
694 {
695         g_free (application->last_chooser_uri);
696         application->last_chooser_uri = g_strdup (uri);
697 }
698
699 const gchar *
700 ev_application_get_chooser_uri (EvApplication *application)
701 {
702         return application->last_chooser_uri;
703 }
704
705 void
706 ev_application_screensaver_enable  (EvApplication *application)
707 {
708         if (application->scr_saver)
709                 totem_scrsaver_enable (application->scr_saver); 
710 }
711
712 void
713 ev_application_screensaver_disable (EvApplication *application)
714 {
715         if (application->scr_saver)
716                 totem_scrsaver_disable (application->scr_saver);        
717 }