]> www.fi.muni.cz Git - evince.git/blob - shell/ev-window.c
532efae1fd6c13dc3223cf807fba0ea6907e9f95
[evince.git] / shell / ev-window.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* this file is part of evince, a gnome document viewer
3  *
4  *  Copyright (C) 2004 Martin Kretzschmar
5  *  Copyright (C) 2004 Red Hat, Inc.
6  *  Copyright (C) 2000, 2001, 2002, 2003, 2004 Marco Pesenti Gritti
7  *  Copyright (C) 2003, 2004 Christian Persch
8  *
9  *  Author:
10  *    Martin Kretzschmar <martink@gnome.org>
11  *
12  * Evince is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * Evince is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "ev-window.h"
32 #include "ev-navigation-action.h"
33 #include "ev-page-action.h"
34 #include "ev-sidebar.h"
35 #include "ev-sidebar-links.h"
36 #include "ev-sidebar-thumbnails.h"
37 #include "ev-view.h"
38 #include "ev-password.h"
39 #include "ev-print-job.h"
40 #include "ev-document-find.h"
41 #include "ev-document-security.h"
42 #include "eggfindbar.h"
43
44 #include "pdf-document.h"
45 #include "pixbuf-document.h"
46 #include "ps-document.h"
47
48 #include <glib/gi18n.h>
49 #include <gtk/gtk.h>
50
51 #include <libgnomevfs/gnome-vfs-mime-utils.h>
52 #include <libgnomeprintui/gnome-print-dialog.h>
53
54 #include <string.h>
55
56 #include "ev-application.h"
57 #include "ev-stock-icons.h"
58
59 enum {
60         PROP_0,
61         PROP_ATTRIBUTE
62 };
63
64 enum {
65         SIGNAL,
66         N_SIGNALS
67 };
68
69 struct _EvWindowPrivate {
70         GtkWidget *main_box;
71         GtkWidget *hpaned;
72         GtkWidget *sidebar;
73         GtkWidget *find_bar;
74         GtkWidget *view;
75         GtkActionGroup *action_group;
76         GtkUIManager *ui_manager;
77         GtkWidget *statusbar;
78         guint help_message_cid;
79         guint view_message_cid;
80         GtkWidget *exit_fullscreen_popup;
81         char *uri;
82
83         EvDocument *document;
84
85         gboolean fullscreen_mode;
86 };
87
88 #define NAVIGATION_BACK_ACTION "NavigationBack"
89 #define NAVIGATION_FORWARD_ACTION "NavigationForward"
90 #define PAGE_SELECTOR_ACTION "PageSelector"
91
92 #if 0
93 /* enable these to add support for signals */
94 static guint ev_window_signals [N_SIGNALS] = { 0 };
95 #endif
96
97 static void update_fullscreen_popup (EvWindow *window);
98
99 static GObjectClass *parent_class = NULL;
100
101 G_DEFINE_TYPE (EvWindow, ev_window, GTK_TYPE_WINDOW)
102
103 #define EV_WINDOW_GET_PRIVATE(object) \
104         (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_WINDOW, EvWindowPrivate))
105
106 #if 0
107 const char *
108 ev_window_get_attribute (EvWindow *self)
109 {
110         g_return_val_if_fail (self != NULL && EV_IS_WINDOW (self), NULL);
111
112         return self->priv->attribute;
113 }
114
115 void
116 ev_window_set_attribute (EvWindow* self, const char *attribute)
117 {
118         g_assert (self != NULL && EV_IS_WINDOW (self));
119         g_assert (attribute != NULL);
120
121         if (self->priv->attribute != NULL) {
122                 g_free (self->priv->attribute);
123         }
124
125         self->priv->attribute = g_strdup (attribute);
126
127         g_object_notify (G_OBJECT (self), "attribute");
128 }
129
130 static void
131 ev_window_get_property (GObject *object, guint prop_id, GValue *value,
132                         GParamSpec *param_spec)
133 {
134         EvWindow *self;
135
136         self = EV_WINDOW (object);
137
138         switch (prop_id) {
139         case PROP_ATTRIBUTE:
140                 g_value_set_string (value, self->priv->attribute);
141                 break;
142         default:
143                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
144                                                    prop_id,
145                                                    param_spec);
146                 break;
147         }
148 }
149
150 static void
151 ev_window_set_property (GObject *object, guint prop_id, const GValue *value,
152                         GParamSpec *param_spec)
153 {
154         EvWindow *self;
155
156         self = EV_WINDOW (object);
157
158         switch (prop_id) {
159         case PROP_ATTRIBUTE:
160                 ev_window_set_attribute (self, g_value_get_string (value));
161                 break;
162         default:
163                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
164                                                    prop_id,
165                                                    param_spec);
166                 break;
167         }
168 }
169 #endif
170
171 static void
172 set_action_sensitive (EvWindow   *ev_window,
173                       const char *name,
174                       gboolean    sensitive)
175 {
176         GtkAction *action = gtk_action_group_get_action (ev_window->priv->action_group,
177                                                          name);
178         gtk_action_set_sensitive (action, sensitive);
179 }
180
181 static void
182 update_action_sensitivity (EvWindow *ev_window)
183 {
184         EvDocument *document;
185         EvView *view;
186
187         gboolean can_go_back = FALSE;
188         gboolean can_go_forward = FALSE;
189
190         document = ev_window->priv->document;
191
192         view = EV_VIEW (ev_window->priv->view);
193
194         if (document) {
195                 can_go_back = ev_view_can_go_back (view);
196                 can_go_forward = ev_view_can_go_forward (view);
197         }
198
199         /* File menu */
200         /* "FileOpen": always sensitive */
201         set_action_sensitive (ev_window, "FileSaveAs", document!=NULL);
202         set_action_sensitive (ev_window, "FilePrint", document!=NULL);
203         /* "FileCloseWindow": always sensitive */
204
205         /* Edit menu */
206         set_action_sensitive (ev_window, "EditCopy", document!=NULL);
207         set_action_sensitive (ev_window, "EditSelectAll", document!=NULL);
208
209         if (document)
210                 set_action_sensitive (ev_window, "EditFind", EV_IS_DOCUMENT_FIND (document));
211         else
212                 set_action_sensitive (ev_window, "EditFind", FALSE);
213
214         /* View menu */
215         set_action_sensitive (ev_window, "ViewZoomIn", document!=NULL);
216         set_action_sensitive (ev_window, "ViewZoomOut", document!=NULL);
217         set_action_sensitive (ev_window, "ViewNormalSize", document!=NULL);
218         set_action_sensitive (ev_window, "ViewBestFit", document!=NULL);
219         set_action_sensitive (ev_window, "ViewPageWidth", document!=NULL);
220
221         /* Go menu */
222         set_action_sensitive (ev_window, "GoBack", can_go_back);
223         set_action_sensitive (ev_window, "GoForward", can_go_forward);
224         if (document) {
225                 int n_pages;
226                 int page;
227
228                 page = ev_view_get_page (EV_VIEW (ev_window->priv->view));
229                 n_pages = ev_document_get_n_pages (document);
230
231                 set_action_sensitive (ev_window, "GoPageDown", page > 1);
232                 set_action_sensitive (ev_window, "GoPageUp", page < n_pages);
233                 set_action_sensitive (ev_window, "GoFirstPage", page > 1);
234                 set_action_sensitive (ev_window, "GoLastPage", page < n_pages);
235         } else {
236                 set_action_sensitive (ev_window, "GoFirstPage", FALSE);
237                 set_action_sensitive (ev_window, "GoPageDown", FALSE);
238                 set_action_sensitive (ev_window, "GoPageUp", FALSE);
239                 set_action_sensitive (ev_window, "GoLastPage", FALSE);
240         }
241
242         /* Help menu */
243         /* "HelpContents": always sensitive */
244         /* "HelpAbout": always sensitive */
245
246         /* Toolbar-specific actions: */
247         set_action_sensitive (ev_window, NAVIGATION_BACK_ACTION, can_go_back);
248         set_action_sensitive (ev_window, NAVIGATION_FORWARD_ACTION, can_go_forward);
249         set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, document!=NULL);
250 }
251
252 void
253 ev_window_open_link (EvWindow *ev_window, EvLink *link)
254 {
255         ev_view_go_to_link (EV_VIEW (ev_window->priv->view), link);
256 }
257
258 gboolean
259 ev_window_is_empty (const EvWindow *ev_window)
260 {
261         g_return_val_if_fail (EV_IS_WINDOW (ev_window), FALSE);
262
263         return ev_window->priv->document == NULL;
264 }
265
266 static void
267 unable_to_load (EvWindow   *ev_window,
268                 const char *error_message)
269 {
270         GtkWidget *dialog;
271
272         dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
273                                          GTK_DIALOG_DESTROY_WITH_PARENT,
274                                          GTK_MESSAGE_ERROR,
275                                          GTK_BUTTONS_CLOSE,
276                                          _("Unable to open document"));
277         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
278                                                   "%s", error_message);
279         gtk_dialog_run (GTK_DIALOG (dialog));
280         gtk_widget_destroy (dialog);
281 }
282
283 /* Would be nice to have this in gdk-pixbuf */
284 static gboolean
285 mime_type_supported_by_gdk_pixbuf (const gchar *mime_type)
286 {
287         GSList *formats, *list;
288         gboolean retval = FALSE;
289
290         formats = gdk_pixbuf_get_formats ();
291
292         list = formats;
293         while (list) {
294                 GdkPixbufFormat *format = list->data;
295                 int i;
296                 gchar **mime_types;
297
298                 if (gdk_pixbuf_format_is_disabled (format))
299                         continue;
300
301                 mime_types = gdk_pixbuf_format_get_mime_types (format);
302
303                 for (i = 0; mime_types[i] != NULL; i++) {
304                         if (strcmp (mime_types[i], mime_type) == 0) {
305                                 retval = TRUE;
306                                 break;
307                         }
308                 }
309
310                 if (retval)
311                         break;
312
313                 list = list->next;
314         }
315
316         g_slist_free (formats);
317
318         return retval;
319 }
320
321 static void
322 update_window_title (EvDocument *document, GParamSpec *pspec, EvWindow *ev_window)
323 {
324         char *title = NULL;
325
326         if (document == NULL) {
327                 title = g_strdup (_("Document Viewer"));
328         } else {
329                 title = ev_document_get_title (document);
330
331                 if (title == NULL) {
332                         title = g_path_get_basename (ev_window->priv->uri);
333                 }
334         }
335
336         gtk_window_set_title (GTK_WINDOW (ev_window), title);
337
338         g_free (title);
339 }
340
341 static void
342 update_total_pages (EvWindow *ev_window)
343 {
344         GtkAction *action;
345         int pages;
346
347         pages = ev_document_get_n_pages (ev_window->priv->document);
348         action = gtk_action_group_get_action
349                 (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
350         ev_page_action_set_total_pages (EV_PAGE_ACTION (action), pages);
351 }
352
353 /* This function assumes that ev_window just had ev_window->document set.
354  */
355 static void
356 ev_window_setup_document (EvWindow *ev_window)
357 {
358         EvDocument *document;
359         EvHistory *history;
360         EvView *view = EV_VIEW (ev_window->priv->view);
361         EvSidebar *sidebar = EV_SIDEBAR (ev_window->priv->sidebar);
362         GtkAction *action;
363
364         document = ev_window->priv->document;
365
366         ev_view_set_document (view, document);
367         ev_sidebar_set_document (sidebar, document);
368
369         history = ev_history_new ();
370         ev_view_set_history (view, history);
371         g_object_unref (history);
372
373         action = gtk_action_group_get_action
374                 (ev_window->priv->action_group, NAVIGATION_BACK_ACTION);
375         ev_navigation_action_set_history
376                 (EV_NAVIGATION_ACTION (action), history);
377
378         action = gtk_action_group_get_action
379                 (ev_window->priv->action_group, NAVIGATION_FORWARD_ACTION);
380         ev_navigation_action_set_history
381                 (EV_NAVIGATION_ACTION (action), history);
382
383         update_total_pages (ev_window);
384         update_action_sensitivity (ev_window);
385 }
386
387
388 static gchar *
389 ev_window_get_password (GtkWidget *password_dialog)
390 {
391         gchar *password = NULL;
392
393         if (gtk_dialog_run (GTK_DIALOG (password_dialog)) == GTK_RESPONSE_OK)
394                 password = ev_password_dialog_get_password (password_dialog);
395
396         return password;
397 }
398
399 void
400 ev_window_open (EvWindow *ev_window, const char *uri)
401 {
402         EvDocument *document = NULL;
403         char *mime_type;
404
405         g_free (ev_window->priv->uri);
406         ev_window->priv->uri = g_strdup (uri);
407
408         mime_type = gnome_vfs_get_mime_type (uri);
409
410         if (mime_type == NULL)
411                 document = NULL;
412         else if (!strcmp (mime_type, "application/pdf"))
413                 document = g_object_new (PDF_TYPE_DOCUMENT, NULL);
414         else if (!strcmp (mime_type, "application/postscript"))
415                 document = g_object_new (PS_TYPE_DOCUMENT, NULL);
416         else if (mime_type_supported_by_gdk_pixbuf (mime_type))
417                 document = g_object_new (PIXBUF_TYPE_DOCUMENT, NULL);
418
419         if (document) {
420                 GError *error = NULL;
421                 GtkWidget *password_dialog = NULL;
422
423                 g_signal_connect_object (G_OBJECT (document),
424                                          "notify::title",
425                                          G_CALLBACK (update_window_title),
426                                          ev_window, 0);
427
428                 /* If we get an error while loading the document, we try to fix
429                  * it and try again. This is an ugly loop that could do with
430                  * some refactoring.*/
431                 while (TRUE) {
432                         gboolean result;
433
434                         result = ev_document_load (document, uri, &error);
435
436                         if (result) {
437                                 if (ev_window->priv->document)
438                                         g_object_unref (ev_window->priv->document);
439                                 ev_window->priv->document = document;
440                                 ev_window_setup_document (ev_window);
441
442                                 if (password_dialog)
443                                         gtk_widget_destroy (password_dialog);
444                                 break;
445                         }
446
447                         g_assert (error != NULL);
448
449                         if (error->domain == EV_DOCUMENT_ERROR &&
450                             error->code == EV_DOCUMENT_ERROR_ENCRYPTED) {
451                                 char *password;
452
453                                 if (password_dialog == NULL)
454                                         password_dialog = ev_password_dialog_new (GTK_WIDGET (ev_window), uri);
455                                 else
456                                         ev_password_dialog_set_bad_pass (password_dialog);
457                                 password = ev_window_get_password (password_dialog);
458                                 if (password) {
459                                         ev_document_security_set_password (EV_DOCUMENT_SECURITY (document),
460                                                                            password);
461                                         g_free (password);
462                                         g_error_free (error);
463                                         error = NULL;
464                                         continue;
465                                 } else {
466                                         gtk_widget_destroy (password_dialog);
467                                 }
468                         } else {
469                                 unable_to_load (ev_window, error->message);
470                         }
471                         g_object_unref (document);
472                         g_error_free (error);
473                         break;
474                 }
475         } else {
476                 char *error_message;
477
478                 error_message = g_strdup_printf (_("Unhandled MIME type: '%s'"),
479                                                  mime_type?mime_type:"<Unknown MIME Type>");
480                 unable_to_load (ev_window, error_message);
481                 g_free (error_message);
482         }
483
484         g_free (mime_type);
485 }
486
487 static void
488 ev_window_cmd_file_open (GtkAction *action, EvWindow *ev_window)
489 {
490         ev_application_open (EV_APP, NULL);
491 }
492
493 /* FIXME
494 static gboolean
495 overwrite_existing_file (GtkWindow *window, const gchar *file_name)
496 {
497         GtkWidget *msgbox;
498         gchar *utf8_file_name;
499         AtkObject *obj;
500         gint ret;
501
502         utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
503         msgbox = gtk_message_dialog_new (
504                 window,
505                 (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
506                 GTK_MESSAGE_QUESTION,
507                 GTK_BUTTONS_NONE,
508                 _("A file named \"%s\" already exists."),
509                 utf8_file_name);
510         g_free (utf8_file_name);
511
512         gtk_message_dialog_format_secondary_text (
513                 GTK_MESSAGE_DIALOG (msgbox),
514                 _("Do you want to replace it with the one you are saving?"));
515
516         gtk_dialog_add_button (GTK_DIALOG (msgbox),
517                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
518
519         gtk_dialog_add_button (GTK_DIALOG (msgbox),
520                                _("_Replace"), GTK_RESPONSE_YES);
521
522         gtk_dialog_set_default_response (GTK_DIALOG (msgbox),
523                                          GTK_RESPONSE_CANCEL);
524
525         obj = gtk_widget_get_accessible (msgbox);
526
527         if (GTK_IS_ACCESSIBLE (obj))
528                 atk_object_set_name (obj, _("Question"));
529
530         ret = gtk_dialog_run (GTK_DIALOG (msgbox));
531         gtk_widget_destroy (msgbox);
532
533         return (ret == GTK_RESPONSE_YES);
534 }
535 */
536
537 static void
538 save_error_dialog (GtkWindow *window, const gchar *file_name)
539 {
540         GtkWidget *error_dialog;
541
542         error_dialog = gtk_message_dialog_new (
543                 window,
544                 (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
545                 GTK_MESSAGE_ERROR,
546                 GTK_BUTTONS_CLOSE,
547                 _("The file could not be saved as \"%s\"."),
548                 file_name);
549
550         /* Easy way to make the text bold while keeping the string
551          * above free from pango markup (FIXME ?) */
552         gtk_message_dialog_format_secondary_text (
553                 GTK_MESSAGE_DIALOG (error_dialog), " ");
554
555         gtk_dialog_run (GTK_DIALOG (error_dialog));
556         gtk_widget_destroy (error_dialog);
557 }
558
559 static void
560 ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
561 {
562         GtkWidget *fc;
563         GtkFileFilter *pdf_filter, *all_filter;
564         gchar *uri = NULL;
565
566         fc = gtk_file_chooser_dialog_new (
567                 _("Save a Copy"),
568                 NULL, GTK_FILE_CHOOSER_ACTION_SAVE,
569                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
570                 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
571                 NULL);
572         gtk_window_set_modal (GTK_WINDOW (fc), TRUE);
573
574         pdf_filter = gtk_file_filter_new ();
575         gtk_file_filter_set_name (pdf_filter, _("PDF Documents"));
576         gtk_file_filter_add_mime_type (pdf_filter, "application/pdf");
577         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fc), pdf_filter);
578
579         all_filter = gtk_file_filter_new ();
580         gtk_file_filter_set_name (all_filter, _("All Files"));
581         gtk_file_filter_add_pattern (all_filter, "*");
582         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fc), all_filter);
583         gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (fc), pdf_filter);
584
585         gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK);
586
587         gtk_widget_show (fc);
588
589         while (gtk_dialog_run (GTK_DIALOG (fc)) == GTK_RESPONSE_OK) {
590                 uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
591
592 /* FIXME
593                 if (g_file_test (uri, G_FILE_TEST_EXISTS) &&
594                     !overwrite_existing_file (GTK_WINDOW (fc), uri))
595                                 continue;
596 */
597
598                 if (ev_document_save (ev_window->priv->document, uri, NULL))
599                         break;
600                 else
601                         save_error_dialog (GTK_WINDOW (fc), uri);
602         }
603         gtk_widget_destroy (fc);
604 }
605
606 static gboolean
607 using_postscript_printer (GnomePrintConfig *config)
608 {
609         const guchar *driver;
610         const guchar *transport;
611
612         driver = gnome_print_config_get (
613                 config, (const guchar *)"Settings.Engine.Backend.Driver");
614
615         transport = gnome_print_config_get (
616                 config, (const guchar *)"Settings.Transport.Backend");
617
618         if (driver) {
619                 if (!strcmp ((const gchar *)driver, "gnome-print-ps"))
620                         return TRUE;
621                 else
622                         return FALSE;
623         } else  if (transport) {
624                 if (!strcmp ((const gchar *)transport, "CUPS"))
625                         return TRUE;
626         }
627
628         return FALSE;
629 }
630
631 static void
632 ev_window_print (EvWindow *ev_window)
633 {
634         GnomePrintConfig *config;
635         GnomePrintJob *job;
636         GtkWidget *print_dialog;
637         EvPrintJob *print_job = NULL;
638
639         g_return_if_fail (EV_IS_WINDOW (ev_window));
640         g_return_if_fail (ev_window->priv->document != NULL);
641
642         config = gnome_print_config_default ();
643         job = gnome_print_job_new (config);
644
645         print_dialog = gnome_print_dialog_new (job, _("Print"),
646                                                (GNOME_PRINT_DIALOG_RANGE |
647                                                 GNOME_PRINT_DIALOG_COPIES));
648         gtk_dialog_set_response_sensitive (GTK_DIALOG (print_dialog),
649                                            GNOME_PRINT_DIALOG_RESPONSE_PREVIEW,
650                                            FALSE);
651
652         while (TRUE) {
653                 int response;
654                 response = gtk_dialog_run (GTK_DIALOG (print_dialog));
655
656                 if (response != GNOME_PRINT_DIALOG_RESPONSE_PRINT)
657                         break;
658
659                 /* FIXME: Change this when we have the first backend
660                  * that can print more than postscript
661                  */
662                 if (!using_postscript_printer (config)) {
663                         GtkWidget *dialog;
664
665                         dialog = gtk_message_dialog_new (
666                                 GTK_WINDOW (print_dialog), GTK_DIALOG_MODAL,
667                                 GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
668                                 _("Printing is not supported on this printer."));
669                         gtk_message_dialog_format_secondary_text (
670                                 GTK_MESSAGE_DIALOG (dialog),
671                                 _("You were trying to print to a printer using the \"%s\" driver. This program requires a PostScript printer driver."),
672                                 gnome_print_config_get (
673                                         config, "Settings.Engine.Backend.Driver"));
674                         gtk_dialog_run (GTK_DIALOG (dialog));
675                         gtk_widget_destroy (dialog);
676
677                         continue;
678                 }
679
680                 print_job = g_object_new (EV_TYPE_PRINT_JOB,
681                                           "gnome_print_job", job,
682                                           "document", ev_window->priv->document,
683                                           "print_dialog", print_dialog,
684                                           NULL);
685                 break;
686         }
687
688         gtk_widget_destroy (print_dialog);
689
690         if (print_job != NULL) {
691                 ev_print_job_print (print_job, GTK_WINDOW (ev_window));
692                 g_object_unref (print_job);
693         }
694 }
695
696 static void
697 ev_window_cmd_file_print (GtkAction *action, EvWindow *ev_window)
698 {
699         ev_window_print (ev_window);
700 }
701
702 static void
703 ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
704 {
705         g_return_if_fail (EV_IS_WINDOW (ev_window));
706
707         gtk_widget_destroy (GTK_WIDGET (ev_window));
708 }
709
710 static void
711 find_not_supported_dialog (EvWindow   *ev_window)
712 {
713         GtkWidget *dialog;
714
715         /* If you change this so it isn't modal, be sure you don't
716          * allow multiple copies of the dialog...
717          */
718
719         dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
720                                          GTK_DIALOG_DESTROY_WITH_PARENT,
721                                          GTK_MESSAGE_ERROR,
722                                          GTK_BUTTONS_CLOSE,
723                                          _("The \"Find\" feature will not work with this document"));
724         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
725                                                   _("Searching for text is only supported for PDF documents."));
726         gtk_dialog_run (GTK_DIALOG (dialog));
727         gtk_widget_destroy (dialog);
728 }
729
730 static void
731 ev_window_cmd_edit_select_all (GtkAction *action, EvWindow *ev_window)
732 {
733         g_return_if_fail (EV_IS_WINDOW (ev_window));
734
735         ev_view_select_all (EV_VIEW (ev_window->priv->view));
736 }
737
738 static void
739 ev_window_cmd_edit_find (GtkAction *action, EvWindow *ev_window)
740 {
741         g_return_if_fail (EV_IS_WINDOW (ev_window));
742
743         if (ev_window->priv->document == NULL) {
744                 g_printerr ("We should have set the Find menu item insensitive since there's no document\n");
745         } else if (!EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
746                 find_not_supported_dialog (ev_window);
747         } else {
748                 gtk_widget_show (ev_window->priv->find_bar);
749
750                 if (ev_window->priv->exit_fullscreen_popup)
751                         update_fullscreen_popup (ev_window);
752
753                 egg_find_bar_grab_focus (EGG_FIND_BAR (ev_window->priv->find_bar));
754         }
755 }
756
757 static void
758 ev_window_cmd_edit_copy (GtkAction *action, EvWindow *ev_window)
759 {
760         g_return_if_fail (EV_IS_WINDOW (ev_window));
761
762         ev_view_copy (EV_VIEW (ev_window->priv->view));
763 }
764
765 static void
766 update_fullscreen_popup (EvWindow *window)
767 {
768         GtkWidget *popup = window->priv->exit_fullscreen_popup;
769         int popup_width, popup_height;
770         GdkRectangle screen_rect;
771
772         g_return_if_fail (popup != NULL);
773
774         if (!popup)
775                 return;
776
777         popup_width = popup->requisition.width;
778         popup_height = popup->requisition.height;
779
780         /* FIXME multihead */
781         gdk_screen_get_monitor_geometry (gdk_screen_get_default (),
782                         gdk_screen_get_monitor_at_window
783                         (gdk_screen_get_default (),
784                          GTK_WIDGET (window)->window),
785                          &screen_rect);
786
787         if (GTK_WIDGET_VISIBLE (window->priv->find_bar)) {
788                 GtkRequisition req;
789
790                 gtk_widget_size_request (window->priv->find_bar, &req);
791
792                 screen_rect.height -= req.height;
793         }
794
795         if (gtk_widget_get_direction (popup) == GTK_TEXT_DIR_RTL)
796         {
797                 gtk_window_move (GTK_WINDOW (popup),
798                                  screen_rect.x + screen_rect.width - popup_width,
799                                  screen_rect.height - popup_height);
800         }
801         else
802         {
803                 gtk_window_move (GTK_WINDOW (popup),
804                                 screen_rect.x, screen_rect.height - popup_height);
805         }
806 }
807
808 static void
809 screen_size_changed_cb (GdkScreen *screen,
810                         EvWindow *window)
811 {
812         update_fullscreen_popup (window);
813 }
814
815 static void
816 destroy_exit_fullscreen_popup (EvWindow *window)
817 {
818         if (window->priv->exit_fullscreen_popup != NULL)
819         {
820                 /* FIXME multihead */
821                 g_signal_handlers_disconnect_by_func
822                         (gdk_screen_get_default (),
823                          G_CALLBACK (screen_size_changed_cb), window);
824
825                 gtk_widget_destroy (window->priv->exit_fullscreen_popup);
826                 window->priv->exit_fullscreen_popup = NULL;
827         }
828 }
829
830 static void
831 exit_fullscreen_button_clicked_cb (GtkWidget *button, EvWindow *window)
832 {
833         GtkAction *action;
834
835         action = gtk_action_group_get_action (window->priv->action_group, "ViewFullscreen");
836         g_return_if_fail (action != NULL);
837
838         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
839 }
840
841 static void
842 fullscreen_popup_size_request_cb (GtkWidget *popup, GtkRequisition *req, EvWindow *window)
843 {
844         update_fullscreen_popup (window);
845 }
846
847 static void
848 ev_window_fullscreen (EvWindow *window)
849 {
850         GtkWidget *popup, *button, *icon, *label, *hbox, *main_menu;
851
852         window->priv->fullscreen_mode = TRUE;
853
854         popup = gtk_window_new (GTK_WINDOW_POPUP);
855         window->priv->exit_fullscreen_popup = popup;
856
857         button = gtk_button_new ();
858         g_signal_connect (button, "clicked",
859                           G_CALLBACK (exit_fullscreen_button_clicked_cb),
860                           window);
861         gtk_widget_show (button);
862         gtk_container_add (GTK_CONTAINER (popup), button);
863
864         hbox = gtk_hbox_new (FALSE, 2);
865         gtk_widget_show (hbox);
866         gtk_container_add (GTK_CONTAINER (button), hbox);
867
868         icon = gtk_image_new_from_stock (GTK_STOCK_QUIT, GTK_ICON_SIZE_BUTTON);
869         gtk_widget_show (icon);
870         gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
871
872         label = gtk_label_new (_("Exit Fullscreen"));
873         gtk_widget_show (label);
874         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
875
876         gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
877
878         /* FIXME multihead */
879         g_signal_connect (gdk_screen_get_default (), "size-changed",
880                           G_CALLBACK (screen_size_changed_cb), window);
881         g_signal_connect (popup, "size_request",
882                           G_CALLBACK (fullscreen_popup_size_request_cb), window);
883
884         main_menu = gtk_ui_manager_get_widget (window->priv->ui_manager, "/MainMenu");
885         gtk_widget_hide (main_menu);
886         gtk_widget_hide (window->priv->statusbar);
887
888         update_fullscreen_popup (window);
889
890         gtk_widget_show (popup);
891 }
892
893 static void
894 ev_window_unfullscreen (EvWindow *window)
895 {
896         GtkWidget *main_menu;
897
898         window->priv->fullscreen_mode = FALSE;
899
900         main_menu = gtk_ui_manager_get_widget (window->priv->ui_manager, "/MainMenu");
901         gtk_widget_show (main_menu);
902         gtk_widget_show (window->priv->statusbar);
903
904         destroy_exit_fullscreen_popup (window);
905 }
906
907 static void
908 ev_window_cmd_view_fullscreen (GtkAction *action, EvWindow *ev_window)
909 {
910         gboolean fullscreen;
911
912         g_return_if_fail (EV_IS_WINDOW (ev_window));
913
914         fullscreen = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
915
916         if (fullscreen) {
917                 gtk_window_fullscreen (GTK_WINDOW (ev_window));
918         } else {
919                 gtk_window_unfullscreen (GTK_WINDOW (ev_window));
920         }
921 }
922
923 static gboolean
924 ev_window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event, EvWindow *window)
925 {
926         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
927         {
928                 GtkActionGroup *action_group;
929                 GtkAction *action;
930                 gboolean fullscreen;
931
932                 fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
933
934                 if (fullscreen)
935                 {
936                         ev_window_fullscreen (window);
937                 }
938                 else
939                 {
940                         ev_window_unfullscreen (window);
941                 }
942
943                 action_group = window->priv->action_group;
944
945                 action = gtk_action_group_get_action (action_group, "ViewFullscreen");
946                 g_signal_handlers_block_by_func
947                         (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
948                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fullscreen);
949                 g_signal_handlers_unblock_by_func
950                         (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
951
952         }
953
954         return FALSE;
955 }
956
957 static gboolean
958 ev_window_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *ev_window)
959 {
960         gtk_window_unfullscreen (GTK_WINDOW (ev_window));
961
962         return FALSE;
963 }
964
965
966 static void
967 ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window)
968 {
969         g_return_if_fail (EV_IS_WINDOW (ev_window));
970
971         ev_view_zoom_in (EV_VIEW (ev_window->priv->view));
972 }
973
974 static void
975 ev_window_cmd_view_zoom_out (GtkAction *action, EvWindow *ev_window)
976 {
977         g_return_if_fail (EV_IS_WINDOW (ev_window));
978
979         ev_view_zoom_out (EV_VIEW (ev_window->priv->view));
980 }
981
982 static void
983 ev_window_cmd_view_normal_size (GtkAction *action, EvWindow *ev_window)
984 {
985         g_return_if_fail (EV_IS_WINDOW (ev_window));
986
987         ev_view_normal_size (EV_VIEW (ev_window->priv->view));
988 }
989
990 static void
991 ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
992 {
993         g_return_if_fail (EV_IS_WINDOW (ev_window));
994
995         ev_view_best_fit (EV_VIEW (ev_window->priv->view));
996 }
997
998 static void
999 ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
1000 {
1001         g_return_if_fail (EV_IS_WINDOW (ev_window));
1002
1003         ev_view_fit_width (EV_VIEW (ev_window->priv->view));
1004 }
1005
1006 static void
1007 ev_window_cmd_go_back (GtkAction *action, EvWindow *ev_window)
1008 {
1009         g_return_if_fail (EV_IS_WINDOW (ev_window));
1010
1011         ev_view_go_back (EV_VIEW (ev_window->priv->view));
1012 }
1013
1014 static void
1015 ev_window_cmd_go_forward (GtkAction *action, EvWindow *ev_window)
1016 {
1017         g_return_if_fail (EV_IS_WINDOW (ev_window));
1018
1019         ev_view_go_forward (EV_VIEW (ev_window->priv->view));
1020 }
1021
1022 static void
1023 ev_window_cmd_go_page_up (GtkAction *action, EvWindow *ev_window)
1024 {
1025         g_return_if_fail (EV_IS_WINDOW (ev_window));
1026
1027         ev_view_set_page (EV_VIEW (ev_window->priv->view),
1028                           ev_view_get_page (EV_VIEW (ev_window->priv->view)) - 1);
1029 }
1030
1031 static void
1032 ev_window_cmd_go_page_down (GtkAction *action, EvWindow *ev_window)
1033 {
1034         g_return_if_fail (EV_IS_WINDOW (ev_window));
1035
1036         ev_view_set_page (EV_VIEW (ev_window->priv->view),
1037                           ev_view_get_page (EV_VIEW (ev_window->priv->view)) + 1);
1038 }
1039
1040 static void
1041 ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window)
1042 {
1043         g_return_if_fail (EV_IS_WINDOW (ev_window));
1044
1045         ev_view_set_page (EV_VIEW (ev_window->priv->view), 1);
1046 }
1047
1048 static void
1049 ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window)
1050 {
1051         g_return_if_fail (EV_IS_WINDOW (ev_window));
1052
1053         ev_view_set_page (EV_VIEW (ev_window->priv->view), G_MAXINT);
1054 }
1055
1056 static void
1057 ev_window_cmd_help_contents (GtkAction *action, EvWindow *ev_window)
1058 {
1059         g_return_if_fail (EV_IS_WINDOW (ev_window));
1060
1061         /* FIXME */
1062 }
1063
1064 static void
1065 ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
1066 {
1067         const char *authors[] = {
1068                 N_("Many..."),
1069                 NULL
1070         };
1071
1072         const char *documenters[] = {
1073                 N_("Not so many..."),
1074                 NULL
1075         };
1076
1077         const char *license[] = {
1078                 N_("Evince is free software; you can redistribute it and/or modify\n"
1079                    "it under the terms of the GNU General Public License as published by\n"
1080                    "the Free Software Foundation; either version 2 of the License, or\n"
1081                    "(at your option) any later version.\n"),
1082                 N_("Evince is distributed in the hope that it will be useful,\n"
1083                    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1084                    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1085                    "GNU General Public License for more details.\n"),
1086                 N_("You should have received a copy of the GNU General Public License\n"
1087                    "along with Evince; if not, write to the Free Software Foundation, Inc.,\n"
1088                    "59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n")
1089         };
1090
1091         char *license_trans;
1092
1093 #ifdef ENABLE_NLS
1094         const char **p;
1095
1096         for (p = authors; *p; ++p)
1097                 *p = _(*p);
1098
1099         for (p = documenters; *p; ++p)
1100                 *p = _(*p);
1101 #endif
1102
1103         license_trans = g_strconcat (_(license[0]), "\n", _(license[1]), "\n",
1104                                      _(license[2]), "\n", NULL);
1105
1106         gtk_show_about_dialog (
1107                 GTK_WINDOW (ev_window),
1108                 "name", _("Evince"),
1109                 "version", VERSION,
1110                 "copyright",
1111                 _("\xc2\xa9 1996-2004 The Evince authors"),
1112                 "license", license_trans,
1113                 "website", "http://www.gnome.org/projects/evince",
1114                 "comments", _("PostScript and PDF File Viewer."),
1115                 "authors", authors,
1116                 "documenters", documenters,
1117                 "translator-credits", _("translator-credits"),
1118                 NULL);
1119
1120         g_free (license_trans);
1121 }
1122
1123 static void
1124 ev_window_view_toolbar_cb (GtkAction *action, EvWindow *ev_window)
1125 {
1126         g_object_set (
1127                 G_OBJECT (gtk_ui_manager_get_widget (
1128                                   ev_window->priv->ui_manager,
1129                                   "/ToolBar")),
1130                 "visible",
1131                 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)),
1132                 NULL);
1133 }
1134
1135 static void
1136 ev_window_view_statusbar_cb (GtkAction *action, EvWindow *ev_window)
1137 {
1138         g_object_set (
1139                 ev_window->priv->statusbar,
1140                 "visible",
1141                 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)),
1142                 NULL);
1143 }
1144
1145 static void
1146 ev_window_view_sidebar_cb (GtkAction *action, EvWindow *ev_window)
1147 {
1148         g_object_set (
1149                 ev_window->priv->sidebar,
1150                 "visible",
1151                 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)),
1152                 NULL);
1153 }
1154
1155 static void
1156 menu_item_select_cb (GtkMenuItem *proxy, EvWindow *ev_window)
1157 {
1158         GtkAction *action;
1159         char *message;
1160
1161         action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
1162         g_return_if_fail (action != NULL);
1163
1164         g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
1165         if (message) {
1166                 gtk_statusbar_push (GTK_STATUSBAR (ev_window->priv->statusbar),
1167                                     ev_window->priv->help_message_cid, message);
1168                 g_free (message);
1169         }
1170 }
1171
1172 static void
1173 menu_item_deselect_cb (GtkMenuItem *proxy, EvWindow *ev_window)
1174 {
1175         gtk_statusbar_pop (GTK_STATUSBAR (ev_window->priv->statusbar),
1176                            ev_window->priv->help_message_cid);
1177 }
1178
1179 static void
1180 connect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action,
1181                   GtkWidget *proxy, EvWindow *ev_window)
1182 {
1183         if (GTK_IS_MENU_ITEM (proxy)) {
1184                 g_signal_connect (proxy, "select",
1185                                   G_CALLBACK (menu_item_select_cb), ev_window);
1186                 g_signal_connect (proxy, "deselect",
1187                                   G_CALLBACK (menu_item_deselect_cb),
1188                                   ev_window);
1189         }
1190 }
1191
1192 static void
1193 disconnect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action,
1194                      GtkWidget *proxy, EvWindow *ev_window)
1195 {
1196         if (GTK_IS_MENU_ITEM (proxy)) {
1197                 g_signal_handlers_disconnect_by_func
1198                         (proxy, G_CALLBACK (menu_item_select_cb), ev_window);
1199                 g_signal_handlers_disconnect_by_func
1200                         (proxy, G_CALLBACK (menu_item_deselect_cb), ev_window);
1201         }
1202 }
1203
1204 static void
1205 update_current_page (EvWindow *ev_window)
1206 {
1207         int page;
1208         GtkAction *action;
1209
1210         action = gtk_action_group_get_action
1211                 (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
1212
1213         page = ev_view_get_page (EV_VIEW (ev_window->priv->view));
1214         ev_page_action_set_current_page (EV_PAGE_ACTION (action), page);
1215 }
1216
1217 static void
1218 view_page_changed_cb (EvView   *view,
1219                       EvWindow *ev_window)
1220 {
1221         update_current_page (ev_window);
1222         update_action_sensitivity (ev_window);
1223 }
1224
1225 static void
1226 view_status_changed_cb (EvView     *view,
1227                         GParamSpec *pspec,
1228                         EvWindow   *ev_window)
1229 {
1230         const char *message;
1231
1232         gtk_statusbar_pop (GTK_STATUSBAR (ev_window->priv->statusbar),
1233                            ev_window->priv->view_message_cid);
1234
1235         message = ev_view_get_status (view);
1236         if (message) {
1237                 gtk_statusbar_push (GTK_STATUSBAR (ev_window->priv->statusbar),
1238                                     ev_window->priv->view_message_cid, message);
1239         }
1240 }
1241
1242 static void
1243 view_find_status_changed_cb (EvView     *view,
1244                              GParamSpec *pspec,
1245                              EvWindow   *ev_window)
1246 {
1247         const char *text;
1248
1249         text = ev_view_get_find_status (view);
1250         egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
1251                                       text);
1252 }
1253
1254 static void
1255 find_bar_previous_cb (EggFindBar *find_bar,
1256                       EvWindow   *ev_window)
1257 {
1258         /* FIXME - highlight previous result */
1259         g_printerr ("Find Previous\n");
1260
1261 }
1262
1263 static void
1264 find_bar_next_cb (EggFindBar *find_bar,
1265                   EvWindow   *ev_window)
1266 {
1267         /* FIXME - highlight next result */
1268         g_printerr ("Find Next\n");
1269 }
1270
1271 static void
1272 find_bar_close_cb (EggFindBar *find_bar,
1273                    EvWindow   *ev_window)
1274 {
1275         gtk_widget_hide (ev_window->priv->find_bar);
1276
1277         if (ev_window->priv->exit_fullscreen_popup)
1278                 update_fullscreen_popup (ev_window);
1279 }
1280
1281 static void
1282 find_bar_search_changed_cb (EggFindBar *find_bar,
1283                             GParamSpec *param,
1284                             EvWindow   *ev_window)
1285 {
1286         gboolean case_sensitive;
1287         gboolean visible;
1288         const char *search_string;
1289
1290         g_return_if_fail (EV_IS_WINDOW (ev_window));
1291
1292         /* Either the string or case sensitivity could have changed,
1293          * we connect this callback to both. We also connect it
1294          * to ::visible so when the find bar is hidden, we should
1295          * pretend the search string is NULL/""
1296          */
1297
1298         case_sensitive = egg_find_bar_get_case_sensitive (find_bar);
1299         visible = GTK_WIDGET_VISIBLE (find_bar);
1300         search_string = egg_find_bar_get_search_string (find_bar);
1301
1302 #if 0
1303         g_printerr ("search for '%s'\n", search_string ? search_string : "(nil)");
1304 #endif
1305
1306         if (ev_window->priv->document &&
1307             EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
1308                 if (visible && search_string) {
1309                         ev_document_find_begin (EV_DOCUMENT_FIND (ev_window->priv->document), search_string, case_sensitive);
1310                 } else {
1311                         ev_document_find_cancel (EV_DOCUMENT_FIND (ev_window->priv->document));
1312                         egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
1313                                                       NULL);
1314                 }
1315         }
1316 }
1317
1318 static void
1319 ev_window_dispose (GObject *object)
1320 {
1321         EvWindowPrivate *priv;
1322
1323         g_return_if_fail (object != NULL && EV_IS_WINDOW (object));
1324
1325         priv = EV_WINDOW (object)->priv;
1326
1327         if (priv->ui_manager) {
1328                 g_object_unref (priv->ui_manager);
1329                 priv->ui_manager = NULL;
1330         }
1331
1332         if (priv->action_group) {
1333                 g_object_unref (priv->action_group);
1334                 priv->action_group = NULL;
1335         }
1336
1337         G_OBJECT_CLASS (parent_class)->dispose (object);
1338 }
1339
1340 static void
1341 ev_window_class_init (EvWindowClass *ev_window_class)
1342 {
1343         GObjectClass *g_object_class;
1344
1345         parent_class = g_type_class_peek_parent (ev_window_class);
1346
1347         g_object_class = G_OBJECT_CLASS (ev_window_class);
1348         g_object_class->dispose = ev_window_dispose;
1349
1350         g_type_class_add_private (g_object_class, sizeof (EvWindowPrivate));
1351
1352 #if 0
1353         /* setting up signal system */
1354         ev_window_class->signal = ev_window_signal;
1355
1356         ev_window_signals [SIGNAL] = g_signal_new (
1357                 "signal",
1358                 EV_TYPE_WINDOW,
1359                 G_SIGNAL_RUN_LAST,
1360                 G_STRUCT_OFFSET (EvWindowClass,
1361                                  signal),
1362                 NULL,
1363                 NULL,
1364                 g_cclosure_marshal_VOID__STRING,
1365                 G_TYPE_NONE,
1366                 0);
1367         /* setting up property system */
1368         g_object_class->set_property = ev_window_set_property;
1369         g_object_class->get_property = ev_window_get_property;
1370
1371         g_object_class_install_property (
1372                 g_object_class,
1373                 PROP_ATTRIBUTE,
1374                 g_param_spec_string ("attribute",
1375                                      "Attribute",
1376                                      "A simple unneccessary attribute that "
1377                                      "does nothing special except being a "
1378                                      "demonstration for the correct implem"
1379                                      "entation of a GObject property",
1380                                      "default_value",
1381                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
1382 #endif
1383 }
1384
1385 /* Normal items */
1386 static GtkActionEntry entries[] = {
1387         { "File", NULL, N_("_File") },
1388         { "Edit", NULL, N_("_Edit") },
1389         { "View", NULL, N_("_View") },
1390         { "Go", NULL, N_("_Go") },
1391         { "Help", NULL, N_("_Help") },
1392
1393         /* File menu */
1394         { "FileOpen", GTK_STOCK_OPEN, N_("_Open"), "<control>O",
1395           N_("Open a file"),
1396           G_CALLBACK (ev_window_cmd_file_open) },
1397         { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy..."), NULL,
1398           N_("Save the current document with a new filename"),
1399           G_CALLBACK (ev_window_cmd_save_as) },
1400         { "FilePrint", GTK_STOCK_PRINT, N_("_Print"), "<control>P",
1401           N_("Print this document"),
1402           G_CALLBACK (ev_window_cmd_file_print) },
1403         { "FileCloseWindow", GTK_STOCK_CLOSE, N_("_Close"), "<control>W",
1404           N_("Close this window"),
1405           G_CALLBACK (ev_window_cmd_file_close_window) },
1406
1407         /* Edit menu */
1408         { "EditCopy", GTK_STOCK_COPY, N_("_Copy"), "<control>C",
1409           N_("Copy text from the document"),
1410           G_CALLBACK (ev_window_cmd_edit_copy) },
1411         { "EditSelectAll", NULL, N_("Select _All"), "<control>A",
1412           N_("Select the entire page"),
1413           G_CALLBACK (ev_window_cmd_edit_select_all) },
1414         { "EditFind", GTK_STOCK_FIND, N_("_Find"), "<control>F",
1415           N_("Find a word or phrase in the document"),
1416           G_CALLBACK (ev_window_cmd_edit_find) },
1417
1418         /* View menu */
1419         { "ViewZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), "<control>plus",
1420           N_("Enlarge the document"),
1421           G_CALLBACK (ev_window_cmd_view_zoom_in) },
1422         { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "<control>minus",
1423           N_("Shrink the document"),
1424           G_CALLBACK (ev_window_cmd_view_zoom_out) },
1425         { "ViewNormalSize", GTK_STOCK_ZOOM_100, N_("_Normal Size"), "<control>0",
1426           N_("Zoom to the normal size"),
1427           G_CALLBACK (ev_window_cmd_view_normal_size) },
1428         { "ViewBestFit", GTK_STOCK_ZOOM_FIT, N_("_Best Fit"), NULL,
1429           N_("Zoom to fit the document to the current window"),
1430           G_CALLBACK (ev_window_cmd_view_best_fit) },
1431         { "ViewPageWidth", EV_STOCK_ZOOM_FIT_WIDTH, N_("Fit Page _Width"), NULL,
1432           N_("Zoom to fit the width of the current window "),
1433           G_CALLBACK (ev_window_cmd_view_page_width) },
1434
1435         /* Go menu */
1436         { "GoBack", GTK_STOCK_GO_BACK, N_("_Back"), "<mod1>Left",
1437           N_("Go to the page viewed before this one"),
1438           G_CALLBACK (ev_window_cmd_go_back) },
1439         { "GoForward", GTK_STOCK_GO_FORWARD, N_("Fo_rward"), "<mod1>Right",
1440           N_("Go to the page viewed before this one"),
1441           G_CALLBACK (ev_window_cmd_go_forward) },
1442         { "GoPageDown", GTK_STOCK_GO_UP, N_("_Page Up"), "<control>Page_Up",
1443           N_("Go to the previous page"),
1444           G_CALLBACK (ev_window_cmd_go_page_up) },
1445         { "GoPageUp", GTK_STOCK_GO_DOWN, N_("_Page Down"), "<control>Page_Down",
1446           N_("Go to the next page"),
1447           G_CALLBACK (ev_window_cmd_go_page_down) },
1448         { "GoFirstPage", GTK_STOCK_GOTO_FIRST, N_("_First Page"), "<control>Home",
1449           N_("Go to the first page"),
1450           G_CALLBACK (ev_window_cmd_go_first_page) },
1451         { "GoLastPage", GTK_STOCK_GOTO_LAST, N_("_Last Page"), "<control>End",
1452           N_("Go to the last page"),
1453           G_CALLBACK (ev_window_cmd_go_last_page) },
1454
1455         /* Help menu */
1456         { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), NULL,
1457           N_("Display help for the viewer application"),
1458           G_CALLBACK (ev_window_cmd_help_contents) },
1459
1460         { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL,
1461           N_("Display credits for the document viewer creators"),
1462           G_CALLBACK (ev_window_cmd_help_about) },
1463 };
1464
1465 /* Toggle items */
1466 static GtkToggleActionEntry toggle_entries[] = {
1467         /* View Menu */
1468         { "ViewToolbar", NULL, N_("_Toolbar"), "<shift><control>T",
1469           N_("Show or hide toolbar"),
1470           G_CALLBACK (ev_window_view_toolbar_cb), TRUE },
1471         { "ViewStatusbar", NULL, N_("_Statusbar"), NULL,
1472           N_("Show or hide statusbar"),
1473           G_CALLBACK (ev_window_view_statusbar_cb), TRUE },
1474         { "ViewSidebar", NULL, N_("Side_bar"), "F9",
1475           N_("Show or hide sidebar"),
1476           G_CALLBACK (ev_window_view_sidebar_cb), TRUE },
1477         { "ViewFullscreen", NULL, N_("_Fullscreen"), "F11",
1478           N_("Expand the window to fill the screen"),
1479           G_CALLBACK (ev_window_cmd_view_fullscreen) },
1480 };
1481
1482 static void
1483 goto_page_cb (GtkAction *action, int page_number, EvWindow *ev_window)
1484 {
1485         EvView *view = EV_VIEW (ev_window->priv->view);
1486
1487         if (ev_view_get_page (view) != page_number) {
1488                 ev_view_set_page (view, page_number);
1489         }
1490 }
1491
1492 static void
1493 register_custom_actions (EvWindow *window, GtkActionGroup *group)
1494 {
1495         GtkAction *action;
1496
1497         action = g_object_new (EV_TYPE_NAVIGATION_ACTION,
1498                                "name", NAVIGATION_BACK_ACTION,
1499                                "label", _("Back"),
1500                                "stock_id", GTK_STOCK_GO_BACK,
1501                                "tooltip", _("Go back"),
1502                                "arrow-tooltip", _("Back history"),
1503                                "direction", EV_NAVIGATION_DIRECTION_BACK,
1504                                "is_important", TRUE,
1505                                NULL);
1506         g_signal_connect (action, "activate",
1507                           G_CALLBACK (ev_window_cmd_go_back), window);
1508         gtk_action_group_add_action (group, action);
1509         g_object_unref (action);
1510
1511         action = g_object_new (EV_TYPE_NAVIGATION_ACTION,
1512                                "name", NAVIGATION_FORWARD_ACTION,
1513                                "label", _("Forward"),
1514                                "stock_id", GTK_STOCK_GO_FORWARD,
1515                                "tooltip", _("Go forward"),
1516                                "arrow-tooltip", _("Forward history"),
1517                                "direction", EV_NAVIGATION_DIRECTION_FORWARD,
1518                                NULL);
1519         g_signal_connect (action, "activate",
1520                           G_CALLBACK (ev_window_cmd_go_forward), window);
1521         gtk_action_group_add_action (group, action);
1522         g_object_unref (action);
1523
1524         action = g_object_new (EV_TYPE_PAGE_ACTION,
1525                                "name", PAGE_SELECTOR_ACTION,
1526                                "label", _("Page"),
1527                                "tooltip", _("Select Page"),
1528                                NULL);
1529         g_signal_connect (action, "goto_page",
1530                           G_CALLBACK (goto_page_cb), window);
1531         gtk_action_group_add_action (group, action);
1532         g_object_unref (action);
1533 }
1534
1535 static void
1536 ev_window_init (EvWindow *ev_window)
1537 {
1538         GtkActionGroup *action_group;
1539         GtkAccelGroup *accel_group;
1540         GError *error = NULL;
1541         GtkWidget *scrolled_window;
1542         GtkWidget *menubar;
1543         GtkWidget *toolbar;
1544         GtkWidget *sidebar_widget;
1545
1546         ev_window->priv = EV_WINDOW_GET_PRIVATE (ev_window);
1547
1548         update_window_title (NULL, NULL, ev_window);
1549
1550         ev_window->priv->main_box = gtk_vbox_new (FALSE, 0);
1551         gtk_container_add (GTK_CONTAINER (ev_window), ev_window->priv->main_box);
1552         gtk_widget_show (ev_window->priv->main_box);
1553
1554         action_group = gtk_action_group_new ("MenuActions");
1555         ev_window->priv->action_group = action_group;
1556         gtk_action_group_set_translation_domain (action_group, NULL);
1557         gtk_action_group_add_actions (action_group, entries,
1558                                       G_N_ELEMENTS (entries), ev_window);
1559         gtk_action_group_add_toggle_actions (action_group, toggle_entries,
1560                                              G_N_ELEMENTS (toggle_entries),
1561                                              ev_window);
1562
1563         register_custom_actions (ev_window, action_group);
1564
1565         ev_window->priv->ui_manager = gtk_ui_manager_new ();
1566         gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
1567                                             action_group, 0);
1568
1569         accel_group =
1570                 gtk_ui_manager_get_accel_group (ev_window->priv->ui_manager);
1571         gtk_window_add_accel_group (GTK_WINDOW (ev_window), accel_group);
1572
1573         g_signal_connect (ev_window->priv->ui_manager, "connect_proxy",
1574                           G_CALLBACK (connect_proxy_cb), ev_window);
1575         g_signal_connect (ev_window->priv->ui_manager, "disconnect_proxy",
1576                           G_CALLBACK (disconnect_proxy_cb), ev_window);
1577
1578         if (!gtk_ui_manager_add_ui_from_file (ev_window->priv->ui_manager,
1579                                               DATADIR"/evince-ui.xml",
1580                                               &error)) {
1581                 g_message ("building menus failed: %s", error->message);
1582                 g_error_free (error);
1583         }
1584
1585         menubar = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
1586                                              "/MainMenu");
1587         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), menubar,
1588                             FALSE, FALSE, 0);
1589
1590         toolbar = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
1591                                              "/ToolBar");
1592         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), toolbar,
1593                             FALSE, FALSE, 0);
1594
1595         /* Add the main area */
1596         ev_window->priv->hpaned = gtk_hpaned_new ();
1597         gtk_widget_show (ev_window->priv->hpaned);
1598         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), ev_window->priv->hpaned,
1599                             TRUE, TRUE, 0);
1600
1601         ev_window->priv->sidebar = ev_sidebar_new ();
1602         gtk_widget_show (ev_window->priv->sidebar);
1603         gtk_paned_add1 (GTK_PANED (ev_window->priv->hpaned),
1604                         ev_window->priv->sidebar);
1605
1606         /* Stub sidebar, for now */
1607         sidebar_widget = ev_sidebar_links_new ();
1608         gtk_widget_show (sidebar_widget);
1609         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
1610                              "index",
1611                              _("Index"),
1612                              sidebar_widget);
1613
1614         sidebar_widget = ev_sidebar_thumbnails_new ();
1615         gtk_widget_show (sidebar_widget);
1616         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
1617                              "thumbnails",
1618                              _("Thumbnails"),
1619                              sidebar_widget);
1620
1621         scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1622         gtk_widget_show (scrolled_window);
1623         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1624                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1625
1626         gtk_paned_add2 (GTK_PANED (ev_window->priv->hpaned),
1627                         scrolled_window);
1628
1629         ev_window->priv->view = ev_view_new ();
1630         gtk_widget_show (ev_window->priv->view);
1631         gtk_container_add (GTK_CONTAINER (scrolled_window),
1632                            ev_window->priv->view);
1633         g_signal_connect (ev_window->priv->view,
1634                           "page-changed",
1635                           G_CALLBACK (view_page_changed_cb),
1636                           ev_window);
1637         g_signal_connect (ev_window->priv->view,
1638                           "notify::find-status",
1639                           G_CALLBACK (view_find_status_changed_cb),
1640                           ev_window);
1641         g_signal_connect (ev_window->priv->view,
1642                           "notify::status",
1643                           G_CALLBACK (view_status_changed_cb),
1644                           ev_window);
1645
1646         ev_window->priv->statusbar = gtk_statusbar_new ();
1647         gtk_widget_show (ev_window->priv->statusbar);
1648         gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
1649                           ev_window->priv->statusbar,
1650                           FALSE, TRUE, 0);
1651         ev_window->priv->help_message_cid = gtk_statusbar_get_context_id
1652                 (GTK_STATUSBAR (ev_window->priv->statusbar), "help_message");
1653         ev_window->priv->view_message_cid = gtk_statusbar_get_context_id
1654                 (GTK_STATUSBAR (ev_window->priv->statusbar), "view_message");
1655
1656         ev_window->priv->find_bar = egg_find_bar_new ();
1657         gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
1658                           ev_window->priv->find_bar,
1659                           FALSE, TRUE, 0);
1660
1661         /* Connect to find bar signals */
1662         g_signal_connect (ev_window->priv->find_bar,
1663                           "previous",
1664                           G_CALLBACK (find_bar_previous_cb),
1665                           ev_window);
1666         g_signal_connect (ev_window->priv->find_bar,
1667                           "next",
1668                           G_CALLBACK (find_bar_next_cb),
1669                           ev_window);
1670         g_signal_connect (ev_window->priv->find_bar,
1671                           "close",
1672                           G_CALLBACK (find_bar_close_cb),
1673                           ev_window);
1674         g_signal_connect (ev_window->priv->find_bar,
1675                           "notify::search-string",
1676                           G_CALLBACK (find_bar_search_changed_cb),
1677                           ev_window);
1678         g_signal_connect (ev_window->priv->find_bar,
1679                           "notify::case-sensitive",
1680                           G_CALLBACK (find_bar_search_changed_cb),
1681                           ev_window);
1682         g_signal_connect (ev_window->priv->find_bar,
1683                           "notify::visible",
1684                           G_CALLBACK (find_bar_search_changed_cb),
1685                           ev_window);
1686
1687         g_signal_connect (ev_window, "window-state-event",
1688                           G_CALLBACK (ev_window_state_event_cb),
1689                           ev_window);
1690         g_signal_connect (ev_window, "focus_out_event",
1691                           G_CALLBACK (ev_window_focus_out_cb),
1692                           ev_window);
1693
1694         /* Give focus to the scrolled window */
1695         gtk_widget_grab_focus (scrolled_window);
1696
1697         update_action_sensitivity (ev_window);
1698 }