]> www.fi.muni.cz Git - evince.git/blob - shell/ev-window.c
9364c99abc353d4cf8ad0ce466d3854cb8fc457c
[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                 document = g_object_new (PS_TYPE_DOCUMENT, NULL);
487         else if (mime_type_supported_by_gdk_pixbuf (mime_type))
488                 document = g_object_new (PIXBUF_TYPE_DOCUMENT, NULL);
489
490         if (document) {
491                 start_loading_document (ev_window, document, uri);
492                 /* See the comment on start_loading_document on ref counting.
493                  * As the password dialog flow is confusing, we're very explicit
494                  * on ref counting. */
495                 g_object_unref (document);
496         } else {
497                 char *error_message;
498
499                 error_message = g_strdup_printf (_("Unhandled MIME type: '%s'"),
500                                                  mime_type?mime_type:"<Unknown MIME Type>");
501                 unable_to_load (ev_window, error_message);
502                 g_free (error_message);
503         }
504
505         g_free (mime_type);
506 }
507
508 static void
509 ev_window_cmd_file_open (GtkAction *action, EvWindow *ev_window)
510 {
511         ev_application_open (EV_APP, NULL);
512 }
513
514 /* FIXME
515 static gboolean
516 overwrite_existing_file (GtkWindow *window, const gchar *file_name)
517 {
518         GtkWidget *msgbox;
519         gchar *utf8_file_name;
520         AtkObject *obj;
521         gint ret;
522
523         utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
524         msgbox = gtk_message_dialog_new (
525                 window,
526                 (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
527                 GTK_MESSAGE_QUESTION,
528                 GTK_BUTTONS_NONE,
529                 _("A file named \"%s\" already exists."),
530                 utf8_file_name);
531         g_free (utf8_file_name);
532
533         gtk_message_dialog_format_secondary_text (
534                 GTK_MESSAGE_DIALOG (msgbox),
535                 _("Do you want to replace it with the one you are saving?"));
536
537         gtk_dialog_add_button (GTK_DIALOG (msgbox),
538                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
539
540         gtk_dialog_add_button (GTK_DIALOG (msgbox),
541                                _("_Replace"), GTK_RESPONSE_YES);
542
543         gtk_dialog_set_default_response (GTK_DIALOG (msgbox),
544                                          GTK_RESPONSE_CANCEL);
545
546         obj = gtk_widget_get_accessible (msgbox);
547
548         if (GTK_IS_ACCESSIBLE (obj))
549                 atk_object_set_name (obj, _("Question"));
550
551         ret = gtk_dialog_run (GTK_DIALOG (msgbox));
552         gtk_widget_destroy (msgbox);
553
554         return (ret == GTK_RESPONSE_YES);
555 }
556 */
557
558 static void
559 save_error_dialog (GtkWindow *window, const gchar *file_name)
560 {
561         GtkWidget *error_dialog;
562
563         error_dialog = gtk_message_dialog_new (
564                 window,
565                 (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
566                 GTK_MESSAGE_ERROR,
567                 GTK_BUTTONS_CLOSE,
568                 _("The file could not be saved as \"%s\"."),
569                 file_name);
570
571         /* Easy way to make the text bold while keeping the string
572          * above free from pango markup (FIXME ?) */
573         gtk_message_dialog_format_secondary_text (
574                 GTK_MESSAGE_DIALOG (error_dialog), " ");
575
576         gtk_dialog_run (GTK_DIALOG (error_dialog));
577         gtk_widget_destroy (error_dialog);
578 }
579
580 static void
581 ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
582 {
583         GtkWidget *fc;
584         GtkFileFilter *pdf_filter, *all_filter;
585         gchar *uri = NULL;
586
587         fc = gtk_file_chooser_dialog_new (
588                 _("Save a Copy"),
589                 NULL, GTK_FILE_CHOOSER_ACTION_SAVE,
590                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
591                 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
592                 NULL);
593         gtk_window_set_modal (GTK_WINDOW (fc), TRUE);
594
595         pdf_filter = gtk_file_filter_new ();
596         gtk_file_filter_set_name (pdf_filter, _("PDF Documents"));
597         gtk_file_filter_add_mime_type (pdf_filter, "application/pdf");
598         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fc), pdf_filter);
599
600         all_filter = gtk_file_filter_new ();
601         gtk_file_filter_set_name (all_filter, _("All Files"));
602         gtk_file_filter_add_pattern (all_filter, "*");
603         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fc), all_filter);
604         gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (fc), pdf_filter);
605
606         gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK);
607
608         gtk_widget_show (fc);
609
610         while (gtk_dialog_run (GTK_DIALOG (fc)) == GTK_RESPONSE_OK) {
611                 uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
612
613 /* FIXME
614                 if (g_file_test (uri, G_FILE_TEST_EXISTS) &&
615                     !overwrite_existing_file (GTK_WINDOW (fc), uri))
616                                 continue;
617 */
618
619                 if (ev_document_save (ev_window->priv->document, uri, NULL))
620                         break;
621                 else
622                         save_error_dialog (GTK_WINDOW (fc), uri);
623         }
624         gtk_widget_destroy (fc);
625 }
626
627 static gboolean
628 using_postscript_printer (GnomePrintConfig *config)
629 {
630         const guchar *driver;
631         const guchar *transport;
632
633         driver = gnome_print_config_get (
634                 config, (const guchar *)"Settings.Engine.Backend.Driver");
635
636         transport = gnome_print_config_get (
637                 config, (const guchar *)"Settings.Transport.Backend");
638
639         if (driver) {
640                 if (!strcmp ((const gchar *)driver, "gnome-print-ps"))
641                         return TRUE;
642                 else
643                         return FALSE;
644         } else  if (transport) {
645                 if (!strcmp ((const gchar *)transport, "CUPS"))
646                         return TRUE;
647         }
648
649         return FALSE;
650 }
651
652 static void
653 ev_window_print (EvWindow *ev_window)
654 {
655         GnomePrintConfig *config;
656         GnomePrintJob *job;
657         GtkWidget *print_dialog;
658         EvPrintJob *print_job = NULL;
659
660         g_return_if_fail (EV_IS_WINDOW (ev_window));
661         g_return_if_fail (ev_window->priv->document != NULL);
662
663         config = gnome_print_config_default ();
664         job = gnome_print_job_new (config);
665
666         print_dialog = gnome_print_dialog_new (job, _("Print"),
667                                                (GNOME_PRINT_DIALOG_RANGE |
668                                                 GNOME_PRINT_DIALOG_COPIES));
669         gtk_dialog_set_response_sensitive (GTK_DIALOG (print_dialog),
670                                            GNOME_PRINT_DIALOG_RESPONSE_PREVIEW,
671                                            FALSE);
672
673         while (TRUE) {
674                 int response;
675                 response = gtk_dialog_run (GTK_DIALOG (print_dialog));
676
677                 if (response != GNOME_PRINT_DIALOG_RESPONSE_PRINT)
678                         break;
679
680                 /* FIXME: Change this when we have the first backend
681                  * that can print more than postscript
682                  */
683                 if (!using_postscript_printer (config)) {
684                         GtkWidget *dialog;
685
686                         dialog = gtk_message_dialog_new (
687                                 GTK_WINDOW (print_dialog), GTK_DIALOG_MODAL,
688                                 GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
689                                 _("Printing is not supported on this printer."));
690                         gtk_message_dialog_format_secondary_text (
691                                 GTK_MESSAGE_DIALOG (dialog),
692                                 _("You were trying to print to a printer using the \"%s\" driver. This program requires a PostScript printer driver."),
693                                 gnome_print_config_get (
694                                         config, "Settings.Engine.Backend.Driver"));
695                         gtk_dialog_run (GTK_DIALOG (dialog));
696                         gtk_widget_destroy (dialog);
697
698                         continue;
699                 }
700
701                 print_job = g_object_new (EV_TYPE_PRINT_JOB,
702                                           "gnome_print_job", job,
703                                           "document", ev_window->priv->document,
704                                           "print_dialog", print_dialog,
705                                           NULL);
706                 break;
707         }
708
709         gtk_widget_destroy (print_dialog);
710
711         if (print_job != NULL) {
712                 ev_print_job_print (print_job, GTK_WINDOW (ev_window));
713                 g_object_unref (print_job);
714         }
715 }
716
717 static void
718 ev_window_cmd_file_print (GtkAction *action, EvWindow *ev_window)
719 {
720         ev_window_print (ev_window);
721 }
722
723 static void
724 ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
725 {
726         g_return_if_fail (EV_IS_WINDOW (ev_window));
727
728         gtk_widget_destroy (GTK_WIDGET (ev_window));
729 }
730
731 static void
732 find_not_supported_dialog (EvWindow   *ev_window)
733 {
734         GtkWidget *dialog;
735
736         /* If you change this so it isn't modal, be sure you don't
737          * allow multiple copies of the dialog...
738          */
739
740         dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
741                                          GTK_DIALOG_DESTROY_WITH_PARENT,
742                                          GTK_MESSAGE_ERROR,
743                                          GTK_BUTTONS_CLOSE,
744                                          _("The \"Find\" feature will not work with this document"));
745         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
746                                                   _("Searching for text is only supported for PDF documents."));
747         gtk_dialog_run (GTK_DIALOG (dialog));
748         gtk_widget_destroy (dialog);
749 }
750
751 static void
752 ev_window_cmd_edit_select_all (GtkAction *action, EvWindow *ev_window)
753 {
754         g_return_if_fail (EV_IS_WINDOW (ev_window));
755
756         ev_view_select_all (EV_VIEW (ev_window->priv->view));
757 }
758
759 static void
760 ev_window_cmd_edit_find (GtkAction *action, EvWindow *ev_window)
761 {
762         g_return_if_fail (EV_IS_WINDOW (ev_window));
763
764         if (ev_window->priv->document == NULL) {
765                 g_printerr ("We should have set the Find menu item insensitive since there's no document\n");
766         } else if (!EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
767                 find_not_supported_dialog (ev_window);
768         } else {
769                 gtk_widget_show (ev_window->priv->find_bar);
770
771                 if (ev_window->priv->exit_fullscreen_popup)
772                         ev_window_update_fullscreen_popup (ev_window);
773
774                 egg_find_bar_grab_focus (EGG_FIND_BAR (ev_window->priv->find_bar));
775         }
776 }
777
778 static void
779 ev_window_cmd_edit_copy (GtkAction *action, EvWindow *ev_window)
780 {
781         g_return_if_fail (EV_IS_WINDOW (ev_window));
782
783         ev_view_copy (EV_VIEW (ev_window->priv->view));
784 }
785
786 static void
787 ev_window_update_fullscreen_popup (EvWindow *window)
788 {
789         GtkWidget *popup = window->priv->exit_fullscreen_popup;
790         int popup_width, popup_height;
791         GdkRectangle screen_rect;
792
793         g_return_if_fail (popup != NULL);
794
795         if (!popup)
796                 return;
797
798         popup_width = popup->requisition.width;
799         popup_height = popup->requisition.height;
800
801         /* FIXME multihead */
802         gdk_screen_get_monitor_geometry (gdk_screen_get_default (),
803                         gdk_screen_get_monitor_at_window
804                         (gdk_screen_get_default (),
805                          GTK_WIDGET (window)->window),
806                          &screen_rect);
807
808         if (GTK_WIDGET_VISIBLE (window->priv->find_bar)) {
809                 GtkRequisition req;
810
811                 gtk_widget_size_request (window->priv->find_bar, &req);
812
813                 screen_rect.height -= req.height;
814         }
815
816         if (gtk_widget_get_direction (popup) == GTK_TEXT_DIR_RTL)
817         {
818                 gtk_window_move (GTK_WINDOW (popup),
819                                  screen_rect.x + screen_rect.width - popup_width,
820                                  screen_rect.height - popup_height);
821         }
822         else
823         {
824                 gtk_window_move (GTK_WINDOW (popup),
825                                 screen_rect.x, screen_rect.height - popup_height);
826         }
827 }
828
829 static void
830 screen_size_changed_cb (GdkScreen *screen,
831                         EvWindow *window)
832 {
833         ev_window_update_fullscreen_popup (window);
834 }
835
836 static void
837 destroy_exit_fullscreen_popup (EvWindow *window)
838 {
839         if (window->priv->exit_fullscreen_popup != NULL)
840         {
841                 /* FIXME multihead */
842                 g_signal_handlers_disconnect_by_func
843                         (gdk_screen_get_default (),
844                          G_CALLBACK (screen_size_changed_cb), window);
845
846                 gtk_widget_destroy (window->priv->exit_fullscreen_popup);
847                 window->priv->exit_fullscreen_popup = NULL;
848         }
849 }
850
851 static void
852 exit_fullscreen_button_clicked_cb (GtkWidget *button, EvWindow *window)
853 {
854         GtkAction *action;
855
856         action = gtk_action_group_get_action (window->priv->action_group, "ViewFullscreen");
857         g_return_if_fail (action != NULL);
858
859         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
860 }
861
862 static void
863 fullscreen_popup_size_request_cb (GtkWidget *popup, GtkRequisition *req, EvWindow *window)
864 {
865         ev_window_update_fullscreen_popup (window);
866 }
867
868 static void
869 ev_window_fullscreen (EvWindow *window)
870 {
871         GtkWidget *popup, *button, *icon, *label, *hbox, *main_menu;
872
873         window->priv->fullscreen_mode = TRUE;
874
875         popup = gtk_window_new (GTK_WINDOW_POPUP);
876         window->priv->exit_fullscreen_popup = popup;
877
878         button = gtk_button_new ();
879         g_signal_connect (button, "clicked",
880                           G_CALLBACK (exit_fullscreen_button_clicked_cb),
881                           window);
882         gtk_widget_show (button);
883         gtk_container_add (GTK_CONTAINER (popup), button);
884
885         hbox = gtk_hbox_new (FALSE, 2);
886         gtk_widget_show (hbox);
887         gtk_container_add (GTK_CONTAINER (button), hbox);
888
889         icon = gtk_image_new_from_stock (GTK_STOCK_QUIT, GTK_ICON_SIZE_BUTTON);
890         gtk_widget_show (icon);
891         gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
892
893         label = gtk_label_new (_("Exit Fullscreen"));
894         gtk_widget_show (label);
895         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
896
897         gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
898
899         /* FIXME multihead */
900         g_signal_connect (gdk_screen_get_default (), "size-changed",
901                           G_CALLBACK (screen_size_changed_cb), window);
902         g_signal_connect (popup, "size_request",
903                           G_CALLBACK (fullscreen_popup_size_request_cb), window);
904
905         main_menu = gtk_ui_manager_get_widget (window->priv->ui_manager, "/MainMenu");
906         gtk_widget_hide (main_menu);
907         gtk_widget_hide (window->priv->statusbar);
908
909         ev_window_update_fullscreen_popup (window);
910
911         gtk_widget_show (popup);
912 }
913
914 static void
915 ev_window_unfullscreen (EvWindow *window)
916 {
917         GtkWidget *main_menu;
918
919         window->priv->fullscreen_mode = FALSE;
920
921         main_menu = gtk_ui_manager_get_widget (window->priv->ui_manager, "/MainMenu");
922         gtk_widget_show (main_menu);
923         gtk_widget_show (window->priv->statusbar);
924
925         destroy_exit_fullscreen_popup (window);
926 }
927
928 static void
929 ev_window_cmd_view_fullscreen (GtkAction *action, EvWindow *ev_window)
930 {
931         gboolean fullscreen;
932
933         g_return_if_fail (EV_IS_WINDOW (ev_window));
934
935         fullscreen = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
936
937         if (fullscreen) {
938                 gtk_window_fullscreen (GTK_WINDOW (ev_window));
939         } else {
940                 gtk_window_unfullscreen (GTK_WINDOW (ev_window));
941         }
942 }
943
944 static gboolean
945 ev_window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event, EvWindow *window)
946 {
947         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
948         {
949                 GtkActionGroup *action_group;
950                 GtkAction *action;
951                 gboolean fullscreen;
952
953                 fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
954
955                 if (fullscreen)
956                 {
957                         ev_window_fullscreen (window);
958                 }
959                 else
960                 {
961                         ev_window_unfullscreen (window);
962                 }
963
964                 action_group = window->priv->action_group;
965
966                 action = gtk_action_group_get_action (action_group, "ViewFullscreen");
967                 g_signal_handlers_block_by_func
968                         (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
969                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fullscreen);
970                 g_signal_handlers_unblock_by_func
971                         (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
972
973         }
974
975         return FALSE;
976 }
977
978 static gboolean
979 ev_window_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *ev_window)
980 {
981         gtk_window_unfullscreen (GTK_WINDOW (ev_window));
982
983         return FALSE;
984 }
985
986 static void
987 ev_window_set_page_mode (EvWindow         *window,
988                          EvWindowPageMode  page_mode)
989 {
990         GtkWidget *child = NULL;
991         GtkWidget *real_child;
992
993         switch (page_mode) {
994         case PAGE_MODE_SINGLE_PAGE:
995                 child = window->priv->view;
996                 break;
997         case PAGE_MODE_PASSWORD:
998                 child = window->priv->password_view;
999                 break;
1000         default:
1001                 g_warning ("page_mode not implemented yet\n");
1002                 g_assert_not_reached ();
1003         }
1004         real_child = gtk_bin_get_child (GTK_BIN (window->priv->scrolled_window));
1005         if (child != real_child) {
1006                 gtk_container_remove (GTK_CONTAINER (window->priv->scrolled_window),
1007                                       real_child);
1008                 gtk_container_add (GTK_CONTAINER (window->priv->scrolled_window),
1009                                    child);
1010         }
1011 }
1012
1013 static void
1014 ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window)
1015 {
1016         g_return_if_fail (EV_IS_WINDOW (ev_window));
1017
1018         ev_view_zoom_in (EV_VIEW (ev_window->priv->view));
1019 }
1020
1021 static void
1022 ev_window_cmd_view_zoom_out (GtkAction *action, EvWindow *ev_window)
1023 {
1024         g_return_if_fail (EV_IS_WINDOW (ev_window));
1025
1026         ev_view_zoom_out (EV_VIEW (ev_window->priv->view));
1027 }
1028
1029 static void
1030 ev_window_cmd_view_normal_size (GtkAction *action, EvWindow *ev_window)
1031 {
1032         g_return_if_fail (EV_IS_WINDOW (ev_window));
1033
1034         ev_view_normal_size (EV_VIEW (ev_window->priv->view));
1035 }
1036
1037 static void
1038 ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
1039 {
1040         g_return_if_fail (EV_IS_WINDOW (ev_window));
1041
1042         ev_view_best_fit (EV_VIEW (ev_window->priv->view));
1043 }
1044
1045 static void
1046 ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
1047 {
1048         g_return_if_fail (EV_IS_WINDOW (ev_window));
1049
1050         ev_view_fit_width (EV_VIEW (ev_window->priv->view));
1051 }
1052
1053 static void
1054 ev_window_cmd_go_page_up (GtkAction *action, EvWindow *ev_window)
1055 {
1056         g_return_if_fail (EV_IS_WINDOW (ev_window));
1057
1058         ev_view_set_page (EV_VIEW (ev_window->priv->view),
1059                           ev_view_get_page (EV_VIEW (ev_window->priv->view)) - 1);
1060 }
1061
1062 static void
1063 ev_window_cmd_go_page_down (GtkAction *action, EvWindow *ev_window)
1064 {
1065         g_return_if_fail (EV_IS_WINDOW (ev_window));
1066
1067         ev_view_set_page (EV_VIEW (ev_window->priv->view),
1068                           ev_view_get_page (EV_VIEW (ev_window->priv->view)) + 1);
1069 }
1070
1071 static void
1072 ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window)
1073 {
1074         g_return_if_fail (EV_IS_WINDOW (ev_window));
1075
1076         ev_view_set_page (EV_VIEW (ev_window->priv->view), 1);
1077 }
1078
1079 static void
1080 ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window)
1081 {
1082         g_return_if_fail (EV_IS_WINDOW (ev_window));
1083
1084         ev_view_set_page (EV_VIEW (ev_window->priv->view), G_MAXINT);
1085 }
1086
1087 static void
1088 ev_window_cmd_help_contents (GtkAction *action, EvWindow *ev_window)
1089 {
1090         g_return_if_fail (EV_IS_WINDOW (ev_window));
1091
1092         /* FIXME */
1093 }
1094
1095 static void
1096 ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
1097 {
1098         const char *authors[] = {
1099                 N_("Many..."),
1100                 NULL
1101         };
1102
1103         const char *documenters[] = {
1104                 N_("Not so many..."),
1105                 NULL
1106         };
1107
1108         const char *license[] = {
1109                 N_("Evince is free software; you can redistribute it and/or modify\n"
1110                    "it under the terms of the GNU General Public License as published by\n"
1111                    "the Free Software Foundation; either version 2 of the License, or\n"
1112                    "(at your option) any later version.\n"),
1113                 N_("Evince is distributed in the hope that it will be useful,\n"
1114                    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1115                    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1116                    "GNU General Public License for more details.\n"),
1117                 N_("You should have received a copy of the GNU General Public License\n"
1118                    "along with Evince; if not, write to the Free Software Foundation, Inc.,\n"
1119                    "59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n")
1120         };
1121
1122         char *license_trans;
1123
1124 #ifdef ENABLE_NLS
1125         const char **p;
1126
1127         for (p = authors; *p; ++p)
1128                 *p = _(*p);
1129
1130         for (p = documenters; *p; ++p)
1131                 *p = _(*p);
1132 #endif
1133
1134         license_trans = g_strconcat (_(license[0]), "\n", _(license[1]), "\n",
1135                                      _(license[2]), "\n", NULL);
1136
1137         gtk_show_about_dialog (
1138                 GTK_WINDOW (ev_window),
1139                 "name", _("Evince"),
1140                 "version", VERSION,
1141                 "copyright",
1142                 _("\xc2\xa9 1996-2004 The Evince authors"),
1143                 "license", license_trans,
1144                 "website", "http://www.gnome.org/projects/evince",
1145                 "comments", _("PostScript and PDF File Viewer."),
1146                 "authors", authors,
1147                 "documenters", documenters,
1148                 "translator-credits", _("translator-credits"),
1149                 NULL);
1150
1151         g_free (license_trans);
1152 }
1153
1154 static void
1155 ev_window_view_toolbar_cb (GtkAction *action, EvWindow *ev_window)
1156 {
1157         g_object_set (
1158                 G_OBJECT (gtk_ui_manager_get_widget (
1159                                   ev_window->priv->ui_manager,
1160                                   "/ToolBar")),
1161                 "visible",
1162                 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)),
1163                 NULL);
1164 }
1165
1166 static void
1167 ev_window_view_statusbar_cb (GtkAction *action, EvWindow *ev_window)
1168 {
1169         g_object_set (
1170                 ev_window->priv->statusbar,
1171                 "visible",
1172                 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)),
1173                 NULL);
1174 }
1175
1176 static void
1177 ev_window_view_sidebar_cb (GtkAction *action, EvWindow *ev_window)
1178 {
1179         g_object_set (
1180                 ev_window->priv->sidebar,
1181                 "visible",
1182                 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)),
1183                 NULL);
1184 }
1185
1186 static void
1187 menu_item_select_cb (GtkMenuItem *proxy, EvWindow *ev_window)
1188 {
1189         GtkAction *action;
1190         char *message;
1191
1192         action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
1193         g_return_if_fail (action != NULL);
1194
1195         g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
1196         if (message) {
1197                 gtk_statusbar_push (GTK_STATUSBAR (ev_window->priv->statusbar),
1198                                     ev_window->priv->help_message_cid, message);
1199                 g_free (message);
1200         }
1201 }
1202
1203 static void
1204 menu_item_deselect_cb (GtkMenuItem *proxy, EvWindow *ev_window)
1205 {
1206         gtk_statusbar_pop (GTK_STATUSBAR (ev_window->priv->statusbar),
1207                            ev_window->priv->help_message_cid);
1208 }
1209
1210 static void
1211 connect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action,
1212                   GtkWidget *proxy, EvWindow *ev_window)
1213 {
1214         if (GTK_IS_MENU_ITEM (proxy)) {
1215                 g_signal_connect (proxy, "select",
1216                                   G_CALLBACK (menu_item_select_cb), ev_window);
1217                 g_signal_connect (proxy, "deselect",
1218                                   G_CALLBACK (menu_item_deselect_cb),
1219                                   ev_window);
1220         }
1221 }
1222
1223 static void
1224 disconnect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action,
1225                      GtkWidget *proxy, EvWindow *ev_window)
1226 {
1227         if (GTK_IS_MENU_ITEM (proxy)) {
1228                 g_signal_handlers_disconnect_by_func
1229                         (proxy, G_CALLBACK (menu_item_select_cb), ev_window);
1230                 g_signal_handlers_disconnect_by_func
1231                         (proxy, G_CALLBACK (menu_item_deselect_cb), ev_window);
1232         }
1233 }
1234
1235 static void
1236 update_current_page (EvWindow *ev_window,
1237                      EvView   *view)
1238 {
1239         int page;
1240         GtkAction *action;
1241         EvSidebarThumbnails *thumbs;
1242
1243         thumbs = EV_SIDEBAR_THUMBNAILS (ev_window->priv->thumbs_sidebar);
1244         ev_sidebar_thumbnails_select_page (thumbs, ev_view_get_page (view));
1245
1246         action = gtk_action_group_get_action
1247                 (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
1248
1249         page = ev_view_get_page (EV_VIEW (ev_window->priv->view));
1250         ev_page_action_set_current_page (EV_PAGE_ACTION (action), page);
1251 }
1252
1253 static void
1254 view_page_changed_cb (EvView   *view,
1255                       EvWindow *ev_window)
1256 {
1257         update_current_page (ev_window, view);
1258         update_action_sensitivity (ev_window);
1259 }
1260
1261 static void
1262 view_status_changed_cb (EvView     *view,
1263                         GParamSpec *pspec,
1264                         EvWindow   *ev_window)
1265 {
1266         const char *message;
1267
1268         gtk_statusbar_pop (GTK_STATUSBAR (ev_window->priv->statusbar),
1269                            ev_window->priv->view_message_cid);
1270
1271         message = ev_view_get_status (view);
1272         if (message) {
1273                 gtk_statusbar_push (GTK_STATUSBAR (ev_window->priv->statusbar),
1274                                     ev_window->priv->view_message_cid, message);
1275         }
1276 }
1277
1278 static void
1279 view_find_status_changed_cb (EvView     *view,
1280                              GParamSpec *pspec,
1281                              EvWindow   *ev_window)
1282 {
1283         const char *text;
1284
1285         text = ev_view_get_find_status (view);
1286         egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
1287                                       text);
1288 }
1289
1290 static void
1291 find_bar_previous_cb (EggFindBar *find_bar,
1292                       EvWindow   *ev_window)
1293 {
1294         ev_view_find_previous (EV_VIEW (ev_window->priv->view));
1295 }
1296
1297 static void
1298 find_bar_next_cb (EggFindBar *find_bar,
1299                   EvWindow   *ev_window)
1300 {
1301         ev_view_find_next (EV_VIEW (ev_window->priv->view));
1302 }
1303
1304 static void
1305 find_bar_close_cb (EggFindBar *find_bar,
1306                    EvWindow   *ev_window)
1307 {
1308         gtk_widget_hide (ev_window->priv->find_bar);
1309
1310         if (ev_window->priv->exit_fullscreen_popup)
1311                 ev_window_update_fullscreen_popup (ev_window);
1312 }
1313
1314 static void
1315 find_bar_search_changed_cb (EggFindBar *find_bar,
1316                             GParamSpec *param,
1317                             EvWindow   *ev_window)
1318 {
1319         gboolean case_sensitive;
1320         gboolean visible;
1321         const char *search_string;
1322
1323         g_return_if_fail (EV_IS_WINDOW (ev_window));
1324
1325         /* Either the string or case sensitivity could have changed,
1326          * we connect this callback to both. We also connect it
1327          * to ::visible so when the find bar is hidden, we should
1328          * pretend the search string is NULL/""
1329          */
1330
1331         case_sensitive = egg_find_bar_get_case_sensitive (find_bar);
1332         visible = GTK_WIDGET_VISIBLE (find_bar);
1333         search_string = egg_find_bar_get_search_string (find_bar);
1334
1335 #if 0
1336         g_printerr ("search for '%s'\n", search_string ? search_string : "(nil)");
1337 #endif
1338
1339         if (ev_window->priv->document &&
1340             EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
1341                 if (visible && search_string) {
1342                         ev_document_find_begin (EV_DOCUMENT_FIND (ev_window->priv->document), search_string, case_sensitive);
1343                 } else {
1344                         ev_document_find_cancel (EV_DOCUMENT_FIND (ev_window->priv->document));
1345                         egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
1346                                                       NULL);
1347                 }
1348         }
1349 }
1350
1351 static void
1352 ev_window_dispose (GObject *object)
1353 {
1354         EvWindowPrivate *priv;
1355
1356         g_return_if_fail (object != NULL && EV_IS_WINDOW (object));
1357
1358         priv = EV_WINDOW (object)->priv;
1359
1360         if (priv->ui_manager) {
1361                 g_object_unref (priv->ui_manager);
1362                 priv->ui_manager = NULL;
1363         }
1364
1365         if (priv->action_group) {
1366                 g_object_unref (priv->action_group);
1367                 priv->action_group = NULL;
1368         }
1369
1370         if (priv->document) {
1371                 g_object_unref (priv->document);
1372                 priv->document = NULL;
1373         }
1374         
1375         if (priv->password_document) {
1376                 g_object_unref (priv->password_document);
1377                 priv->password_document = NULL;
1378         }
1379         
1380         if (priv->password_uri) {
1381                 g_free (priv->password_uri);
1382                 priv->password_uri = NULL;
1383         }
1384         
1385         G_OBJECT_CLASS (ev_window_parent_class)->dispose (object);
1386 }
1387
1388 static void
1389 ev_window_class_init (EvWindowClass *ev_window_class)
1390 {
1391         GObjectClass *g_object_class;
1392
1393         g_object_class = G_OBJECT_CLASS (ev_window_class);
1394         g_object_class->dispose = ev_window_dispose;
1395
1396         g_type_class_add_private (g_object_class, sizeof (EvWindowPrivate));
1397
1398 }
1399
1400 /* Normal items */
1401 static GtkActionEntry entries[] = {
1402         { "File", NULL, N_("_File") },
1403         { "Edit", NULL, N_("_Edit") },
1404         { "View", NULL, N_("_View") },
1405         { "Go", NULL, N_("_Go") },
1406         { "Help", NULL, N_("_Help") },
1407
1408         /* File menu */
1409         { "FileOpen", GTK_STOCK_OPEN, N_("_Open"), "<control>O",
1410           N_("Open a file"),
1411           G_CALLBACK (ev_window_cmd_file_open) },
1412         { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy..."), NULL,
1413           N_("Save the current document with a new filename"),
1414           G_CALLBACK (ev_window_cmd_save_as) },
1415         { "FilePrint", GTK_STOCK_PRINT, N_("_Print"), "<control>P",
1416           N_("Print this document"),
1417           G_CALLBACK (ev_window_cmd_file_print) },
1418         { "FileCloseWindow", GTK_STOCK_CLOSE, N_("_Close"), "<control>W",
1419           N_("Close this window"),
1420           G_CALLBACK (ev_window_cmd_file_close_window) },
1421
1422         /* Edit menu */
1423         { "EditCopy", GTK_STOCK_COPY, N_("_Copy"), "<control>C",
1424           N_("Copy text from the document"),
1425           G_CALLBACK (ev_window_cmd_edit_copy) },
1426         { "EditSelectAll", NULL, N_("Select _All"), "<control>A",
1427           N_("Select the entire page"),
1428           G_CALLBACK (ev_window_cmd_edit_select_all) },
1429         { "EditFind", GTK_STOCK_FIND, N_("_Find"), "<control>F",
1430           N_("Find a word or phrase in the document"),
1431           G_CALLBACK (ev_window_cmd_edit_find) },
1432
1433         /* View menu */
1434         { "ViewZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), "<control>plus",
1435           N_("Enlarge the document"),
1436           G_CALLBACK (ev_window_cmd_view_zoom_in) },
1437         { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "<control>minus",
1438           N_("Shrink the document"),
1439           G_CALLBACK (ev_window_cmd_view_zoom_out) },
1440         { "ViewNormalSize", GTK_STOCK_ZOOM_100, N_("_Normal Size"), "<control>0",
1441           N_("Zoom to the normal size"),
1442           G_CALLBACK (ev_window_cmd_view_normal_size) },
1443         { "ViewBestFit", GTK_STOCK_ZOOM_FIT, N_("_Best Fit"), NULL,
1444           N_("Zoom to fit the document to the current window"),
1445           G_CALLBACK (ev_window_cmd_view_best_fit) },
1446         { "ViewPageWidth", EV_STOCK_ZOOM_FIT_WIDTH, N_("Fit Page _Width"), NULL,
1447           N_("Zoom to fit the width of the current window "),
1448           G_CALLBACK (ev_window_cmd_view_page_width) },
1449
1450         /* Go menu */
1451         { "GoPageUp", GTK_STOCK_GO_UP, N_("_Page Up"), "<control>Page_Up",
1452           N_("Go to the previous page"),
1453           G_CALLBACK (ev_window_cmd_go_page_up) },
1454         { "GoPageDown", GTK_STOCK_GO_DOWN, N_("_Page Down"), "<control>Page_Down",
1455           N_("Go to the next page"),
1456           G_CALLBACK (ev_window_cmd_go_page_down) },
1457         { "GoFirstPage", GTK_STOCK_GOTO_FIRST, N_("_First Page"), "<control>Home",
1458           N_("Go to the first page"),
1459           G_CALLBACK (ev_window_cmd_go_first_page) },
1460         { "GoLastPage", GTK_STOCK_GOTO_LAST, N_("_Last Page"), "<control>End",
1461           N_("Go to the last page"),
1462           G_CALLBACK (ev_window_cmd_go_last_page) },
1463
1464         /* Help menu */
1465         { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), NULL,
1466           N_("Display help for the viewer application"),
1467           G_CALLBACK (ev_window_cmd_help_contents) },
1468
1469         { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL,
1470           N_("Display credits for the document viewer creators"),
1471           G_CALLBACK (ev_window_cmd_help_about) },
1472 };
1473
1474 /* Toggle items */
1475 static GtkToggleActionEntry toggle_entries[] = {
1476         /* View Menu */
1477         { "ViewToolbar", NULL, N_("_Toolbar"), "<shift><control>T",
1478           N_("Show or hide toolbar"),
1479           G_CALLBACK (ev_window_view_toolbar_cb), TRUE },
1480         { "ViewStatusbar", NULL, N_("_Statusbar"), NULL,
1481           N_("Show or hide statusbar"),
1482           G_CALLBACK (ev_window_view_statusbar_cb), TRUE },
1483         { "ViewSidebar", NULL, N_("Side_bar"), "F9",
1484           N_("Show or hide sidebar"),
1485           G_CALLBACK (ev_window_view_sidebar_cb), TRUE },
1486         { "ViewFullscreen", NULL, N_("_Fullscreen"), "F11",
1487           N_("Expand the window to fill the screen"),
1488           G_CALLBACK (ev_window_cmd_view_fullscreen) },
1489 };
1490
1491 static void
1492 goto_page_cb (GtkAction *action, int page_number, EvWindow *ev_window)
1493 {
1494         EvView *view = EV_VIEW (ev_window->priv->view);
1495
1496         if (ev_view_get_page (view) != page_number) {
1497                 ev_view_set_page (view, page_number);
1498         }
1499 }
1500
1501 static void
1502 register_custom_actions (EvWindow *window, GtkActionGroup *group)
1503 {
1504         GtkAction *action;
1505
1506         action = g_object_new (EV_TYPE_PAGE_ACTION,
1507                                "name", PAGE_SELECTOR_ACTION,
1508                                "label", _("Page"),
1509                                "tooltip", _("Select Page"),
1510                                NULL);
1511         g_signal_connect (action, "goto_page",
1512                           G_CALLBACK (goto_page_cb), window);
1513         gtk_action_group_add_action (group, action);
1514         g_object_unref (action);
1515 }
1516
1517 static void
1518 set_short_labels (GtkActionGroup *action_group)
1519 {
1520         GtkAction *action;
1521
1522         action = gtk_action_group_get_action (action_group, "GoPageUp");
1523         g_object_set (action, "short_label", _("Up"), NULL);
1524         action = gtk_action_group_get_action (action_group, "GoPageDown");
1525         g_object_set (action, "short_label", _("Down"), NULL);
1526         action = gtk_action_group_get_action (action_group, "ViewPageWidth");
1527         g_object_set (action, "short_label", _("Fit Width"), NULL);
1528 }
1529
1530 static void
1531 ev_window_init (EvWindow *ev_window)
1532 {
1533         GtkActionGroup *action_group;
1534         GtkAccelGroup *accel_group;
1535         GError *error = NULL;
1536         GtkWidget *menubar;
1537         GtkWidget *toolbar;
1538         GtkWidget *sidebar_widget;
1539
1540         ev_window->priv = EV_WINDOW_GET_PRIVATE (ev_window);
1541
1542         update_window_title (NULL, NULL, ev_window);
1543
1544         ev_window->priv->main_box = gtk_vbox_new (FALSE, 0);
1545         gtk_container_add (GTK_CONTAINER (ev_window), ev_window->priv->main_box);
1546         gtk_widget_show (ev_window->priv->main_box);
1547
1548         action_group = gtk_action_group_new ("MenuActions");
1549         ev_window->priv->action_group = action_group;
1550         gtk_action_group_set_translation_domain (action_group, NULL);
1551         gtk_action_group_add_actions (action_group, entries,
1552                                       G_N_ELEMENTS (entries), ev_window);
1553         gtk_action_group_add_toggle_actions (action_group, toggle_entries,
1554                                              G_N_ELEMENTS (toggle_entries),
1555                                              ev_window);
1556         set_short_labels (action_group);
1557         register_custom_actions (ev_window, action_group);
1558
1559         ev_window->priv->ui_manager = gtk_ui_manager_new ();
1560         gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
1561                                             action_group, 0);
1562
1563         accel_group =
1564                 gtk_ui_manager_get_accel_group (ev_window->priv->ui_manager);
1565         gtk_window_add_accel_group (GTK_WINDOW (ev_window), accel_group);
1566
1567         g_signal_connect (ev_window->priv->ui_manager, "connect_proxy",
1568                           G_CALLBACK (connect_proxy_cb), ev_window);
1569         g_signal_connect (ev_window->priv->ui_manager, "disconnect_proxy",
1570                           G_CALLBACK (disconnect_proxy_cb), ev_window);
1571
1572         if (!gtk_ui_manager_add_ui_from_file (ev_window->priv->ui_manager,
1573                                               DATADIR"/evince-ui.xml",
1574                                               &error)) {
1575                 g_message ("building menus failed: %s", error->message);
1576                 g_error_free (error);
1577         }
1578
1579         menubar = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
1580                                              "/MainMenu");
1581         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), menubar,
1582                             FALSE, FALSE, 0);
1583
1584         toolbar = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
1585                                              "/ToolBar");
1586         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), toolbar,
1587                             FALSE, FALSE, 0);
1588
1589         /* Add the main area */
1590         ev_window->priv->hpaned = gtk_hpaned_new ();
1591         gtk_widget_show (ev_window->priv->hpaned);
1592         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), ev_window->priv->hpaned,
1593                             TRUE, TRUE, 0);
1594
1595         ev_window->priv->sidebar = ev_sidebar_new ();
1596         gtk_widget_show (ev_window->priv->sidebar);
1597         gtk_paned_add1 (GTK_PANED (ev_window->priv->hpaned),
1598                         ev_window->priv->sidebar);
1599
1600         /* Stub sidebar, for now */
1601         sidebar_widget = ev_sidebar_links_new ();
1602         gtk_widget_show (sidebar_widget);
1603         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
1604                              "index",
1605                              _("Index"),
1606                              sidebar_widget);
1607
1608         ev_window->priv->thumbs_sidebar = ev_sidebar_thumbnails_new ();
1609         gtk_widget_show (ev_window->priv->thumbs_sidebar);
1610         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
1611                              "thumbnails",
1612                              _("Thumbnails"),
1613                              ev_window->priv->thumbs_sidebar);
1614
1615         ev_window->priv->scrolled_window =
1616                 GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
1617                                           "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
1618                                           "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
1619                                           "shadow-type", GTK_SHADOW_IN,
1620                                           NULL));
1621         gtk_widget_show (ev_window->priv->scrolled_window);
1622
1623         gtk_paned_add2 (GTK_PANED (ev_window->priv->hpaned),
1624                         ev_window->priv->scrolled_window);
1625
1626         ev_window->priv->view = ev_view_new ();
1627         ev_window->priv->password_view = ev_password_view_new ();
1628         g_signal_connect_swapped (ev_window->priv->password_view,
1629                                   "unlock",
1630                                   G_CALLBACK (ev_window_popup_password_dialog),
1631                                   ev_window);
1632         gtk_widget_show (ev_window->priv->view);
1633         gtk_widget_show (ev_window->priv->password_view);
1634         /* We own a ref on these widgets, as we can swap them in and out */
1635         g_object_ref (ev_window->priv->view);
1636         g_object_ref (ev_window->priv->password_view);
1637
1638         gtk_container_add (GTK_CONTAINER (ev_window->priv->scrolled_window),
1639                            ev_window->priv->view);
1640         g_signal_connect (ev_window->priv->view,
1641                           "page-changed",
1642                           G_CALLBACK (view_page_changed_cb),
1643                           ev_window);
1644         g_signal_connect (ev_window->priv->view,
1645                           "notify::find-status",
1646                           G_CALLBACK (view_find_status_changed_cb),
1647                           ev_window);
1648         g_signal_connect (ev_window->priv->view,
1649                           "notify::status",
1650                           G_CALLBACK (view_status_changed_cb),
1651                           ev_window);
1652
1653         ev_window->priv->statusbar = gtk_statusbar_new ();
1654         gtk_widget_show (ev_window->priv->statusbar);
1655         gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
1656                           ev_window->priv->statusbar,
1657                           FALSE, TRUE, 0);
1658         ev_window->priv->help_message_cid = gtk_statusbar_get_context_id
1659                 (GTK_STATUSBAR (ev_window->priv->statusbar), "help_message");
1660         ev_window->priv->view_message_cid = gtk_statusbar_get_context_id
1661                 (GTK_STATUSBAR (ev_window->priv->statusbar), "view_message");
1662
1663         ev_window->priv->find_bar = egg_find_bar_new ();
1664         gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
1665                           ev_window->priv->find_bar,
1666                           FALSE, TRUE, 0);
1667
1668         /* Connect to find bar signals */
1669         g_signal_connect (ev_window->priv->find_bar,
1670                           "previous",
1671                           G_CALLBACK (find_bar_previous_cb),
1672                           ev_window);
1673         g_signal_connect (ev_window->priv->find_bar,
1674                           "next",
1675                           G_CALLBACK (find_bar_next_cb),
1676                           ev_window);
1677         g_signal_connect (ev_window->priv->find_bar,
1678                           "close",
1679                           G_CALLBACK (find_bar_close_cb),
1680                           ev_window);
1681         g_signal_connect (ev_window->priv->find_bar,
1682                           "notify::search-string",
1683                           G_CALLBACK (find_bar_search_changed_cb),
1684                           ev_window);
1685         g_signal_connect (ev_window->priv->find_bar,
1686                           "notify::case-sensitive",
1687                           G_CALLBACK (find_bar_search_changed_cb),
1688                           ev_window);
1689         g_signal_connect (ev_window->priv->find_bar,
1690                           "notify::visible",
1691                           G_CALLBACK (find_bar_search_changed_cb),
1692                           ev_window);
1693
1694         g_signal_connect (ev_window, "window-state-event",
1695                           G_CALLBACK (ev_window_state_event_cb),
1696                           ev_window);
1697         g_signal_connect (ev_window, "focus_out_event",
1698                           G_CALLBACK (ev_window_focus_out_cb),
1699                           ev_window);
1700
1701         /* Give focus to the scrolled window */
1702         gtk_widget_grab_focus (ev_window->priv->scrolled_window);
1703
1704         update_action_sensitivity (ev_window);
1705 }