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