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