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