]> www.fi.muni.cz Git - evince.git/blob - shell/ev-window.c
d114f4123746ee1de7a74304391dcdab246340b1
[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, 2005 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 <libgnomevfs/gnome-vfs-uri.h>
54 #include <libgnomeprintui/gnome-print-dialog.h>
55
56 #include <gconf/gconf-client.h>
57
58 #include <string.h>
59
60 #include "ev-application.h"
61 #include "ev-stock-icons.h"
62
63 typedef enum {
64         PAGE_MODE_SINGLE_PAGE,
65         PAGE_MODE_CONTINUOUS_PAGE,
66         PAGE_MODE_PASSWORD,
67 } EvWindowPageMode;
68
69 typedef enum {
70         EV_CHROME_MENUBAR       = 1 << 0,
71         EV_CHROME_TOOLBAR       = 1 << 1,
72         EV_CHROME_SIDEBAR       = 1 << 2,
73         EV_CHROME_FINDBAR       = 1 << 3,
74         EV_CHROME_STATUSBAR     = 1 << 4,
75         EV_CHROME_NORMAL        = EV_CHROME_MENUBAR | EV_CHROME_TOOLBAR | EV_CHROME_SIDEBAR | EV_CHROME_STATUSBAR
76 } EvChrome;
77
78 struct _EvWindowPrivate {
79         GtkWidget *main_box;
80         GtkWidget *menubar;
81         GtkWidget *toolbar_dock;
82         GtkWidget *toolbar;
83         GtkWidget *hpaned;
84         GtkWidget *sidebar;
85         GtkWidget *thumbs_sidebar;
86         GtkWidget *find_bar;
87         GtkWidget *scrolled_window;
88         GtkWidget *view;
89         GtkWidget *page_view;
90         GtkWidget *password_view;
91         GtkActionGroup *action_group;
92         GtkUIManager *ui_manager;
93         GtkWidget *statusbar;
94         guint help_message_cid;
95         guint view_message_cid;
96         GtkWidget *fullscreen_toolbar;
97         GtkWidget *fullscreen_popup;
98         char *uri;
99
100         EvDocument *document;
101
102         EvWindowPageMode page_mode;
103         /* These members are used temporarily when in PAGE_MODE_PASSWORD */
104         EvDocument *password_document;
105         GtkWidget *password_dialog;
106         char *password_uri;
107
108         EvChrome chrome;
109         gboolean fullscreen_mode;
110         EvSizingMode sizing_mode;
111         GSource *fullscreen_timeout_source;
112 };
113
114 static GtkTargetEntry ev_drop_types[] = {
115         { "text/uri-list", 0, 0 }
116 };
117
118
119 #define EV_WINDOW_GET_PRIVATE(object) \
120         (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_WINDOW, EvWindowPrivate))
121
122 #define PAGE_SELECTOR_ACTION    "PageSelector"
123
124 #define GCONF_CHROME_TOOLBAR    "/apps/evince/show_toolbar"
125 #define GCONF_CHROME_SIDEBAR    "/apps/evince/show_sidebar"
126 #define GCONF_CHROME_STATUSBAR  "/apps/evince/show_statusbar"
127
128 static void     ev_window_update_fullscreen_popup (EvWindow         *window);
129 static void     ev_window_set_page_mode           (EvWindow         *window,
130                                                    EvWindowPageMode  page_mode);
131 static gboolean start_loading_document            (EvWindow         *ev_window,
132                                                    EvDocument       *document,
133                                                    const char       *uri);
134 static void     ev_window_set_sizing_mode         (EvWindow         *ev_window,
135                                                    EvSizingMode      sizing_mode);
136
137 G_DEFINE_TYPE (EvWindow, ev_window, GTK_TYPE_WINDOW)
138
139 static void
140 set_action_sensitive (EvWindow   *ev_window,
141                       const char *name,
142                       gboolean    sensitive)
143 {
144         GtkAction *action = gtk_action_group_get_action (ev_window->priv->action_group,
145                                                          name);
146         gtk_action_set_sensitive (action, sensitive);
147 }
148
149 static void
150 update_action_sensitivity (EvWindow *ev_window)
151 {
152         EvDocument *document;
153         EvWindowPageMode page_mode;
154         EvView *view;
155
156         document = ev_window->priv->document;
157         page_mode = ev_window->priv->page_mode;
158
159         view = EV_VIEW (ev_window->priv->view);
160
161         /* File menu */
162         /* "FileOpen": always sensitive */
163         set_action_sensitive (ev_window, "FileSaveAs", document!=NULL);
164         set_action_sensitive (ev_window, "FilePrint", document!=NULL);
165         /* "FileCloseWindow": always sensitive */
166
167         /* Edit menu */
168         set_action_sensitive (ev_window, "EditCopy", document!=NULL);
169         set_action_sensitive (ev_window, "EditSelectAll", document!=NULL);
170
171         if (document)
172                 set_action_sensitive (ev_window, "EditFind", EV_IS_DOCUMENT_FIND (document));
173         else
174                 set_action_sensitive (ev_window, "EditFind", FALSE);
175
176         /* View menu */
177         set_action_sensitive (ev_window, "ViewZoomIn", document!=NULL);
178         set_action_sensitive (ev_window, "ViewZoomOut", document!=NULL);
179         set_action_sensitive (ev_window, "ViewNormalSize", document!=NULL);
180         set_action_sensitive (ev_window, "ViewBestFit", document!=NULL);
181         set_action_sensitive (ev_window, "ViewPageWidth", document!=NULL);
182
183         /* Go menu */
184         if (document) {
185                 int n_pages;
186                 int page;
187
188                 page = ev_view_get_page (EV_VIEW (ev_window->priv->view));
189                 n_pages = ev_document_get_n_pages (document);
190
191                 set_action_sensitive (ev_window, "GoPreviousPage", page > 1);
192                 set_action_sensitive (ev_window, "GoNextPage", page < n_pages);
193                 set_action_sensitive (ev_window, "GoFirstPage", page > 1);
194                 set_action_sensitive (ev_window, "GoLastPage", page < n_pages);
195         } else {
196                 set_action_sensitive (ev_window, "GoFirstPage", FALSE);
197                 set_action_sensitive (ev_window, "GoPreviousPage", FALSE);
198                 set_action_sensitive (ev_window, "GoNextPage", FALSE);
199                 set_action_sensitive (ev_window, "GoLastPage", FALSE);
200         }
201
202         /* Page View radio group */
203         if (document) {
204                 set_action_sensitive (ev_window, "SinglePage", page_mode != PAGE_MODE_PASSWORD);
205                 set_action_sensitive (ev_window, "ContinuousPage", page_mode != PAGE_MODE_PASSWORD);
206         } else {
207                 set_action_sensitive (ev_window, "SinglePage", FALSE);
208                 set_action_sensitive (ev_window, "ContinuousPage", FALSE);
209         }
210         /* Help menu */
211         /* "HelpContents": always sensitive */
212         /* "HelpAbout": always sensitive */
213
214         /* Toolbar-specific actions: */
215         set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, document!=NULL);
216 }
217
218 static void
219 update_chrome_visibility (EvWindow *window)
220 {
221         EvWindowPrivate *priv = window->priv;
222         gboolean menubar, toolbar, sidebar, findbar, statusbar, fullscreen_toolbar;
223
224         menubar = (priv->chrome & EV_CHROME_MENUBAR) != 0 && !priv->fullscreen_mode;
225         toolbar = (priv->chrome & EV_CHROME_TOOLBAR) != 0 && !priv->fullscreen_mode;
226         sidebar = (priv->chrome & EV_CHROME_SIDEBAR) != 0 && !priv->fullscreen_mode;
227         fullscreen_toolbar = (priv->chrome & EV_CHROME_TOOLBAR) != 0;
228         statusbar = (priv->chrome & EV_CHROME_STATUSBAR) != 0 && !priv->fullscreen_mode;
229         findbar = (priv->chrome & EV_CHROME_FINDBAR) != 0;
230
231         g_object_set (priv->menubar, "visible", menubar, NULL);
232         g_object_set (priv->toolbar_dock, "visible", toolbar, NULL);
233         g_object_set (priv->sidebar, "visible", sidebar, NULL);
234         g_object_set (priv->find_bar, "visible", findbar, NULL);
235         g_object_set (priv->statusbar, "visible", statusbar, NULL);
236         g_object_set (priv->fullscreen_toolbar, "visible", fullscreen_toolbar, NULL);
237
238         if (priv->fullscreen_popup) {
239                 g_object_set (priv->fullscreen_popup, "visible", priv->fullscreen_mode, NULL);
240         } 
241 }
242
243 static void
244 update_chrome_flag (EvWindow *window, EvChrome flag, const char *pref, gboolean active)
245 {
246         EvWindowPrivate *priv = window->priv;
247         GConfClient *client;
248         
249         if (active) {
250                 priv->chrome |= flag;
251         }
252         else {
253                 priv->chrome &= ~flag;
254         }
255
256         if (pref != NULL) {
257                 client = gconf_client_get_default ();
258                 gconf_client_set_bool (client, pref, active, NULL);
259                 g_object_unref (client);
260         }
261
262         update_chrome_visibility (window);
263 }
264
265 static void
266 update_sizing_buttons (EvWindow *ev_window)
267 {
268         GtkWidget *best_fit;
269         GtkWidget *fit_width;
270
271         best_fit = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
272                                               "/ToolBar/ViewBestFit");
273         fit_width = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
274                                               "/ToolBar/ViewPageWidth");
275
276         switch (ev_window->priv->sizing_mode) {
277         case EV_SIZING_BEST_FIT:
278                 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (best_fit), TRUE);
279                 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (fit_width), FALSE);
280                 break;
281         case EV_SIZING_FIT_WIDTH:
282                 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (best_fit), FALSE);
283                 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (fit_width), TRUE);
284                 break;
285         case EV_SIZING_FREE:
286                 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (best_fit), FALSE);
287                 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (fit_width), FALSE);
288                 break;
289         }
290 }
291
292 void
293 ev_window_open_page (EvWindow *ev_window, int page)
294 {
295         ev_view_set_page (EV_VIEW (ev_window->priv->view), page);
296 }
297
298 void
299 ev_window_open_link (EvWindow *ev_window, EvLink *link)
300 {
301         ev_view_go_to_link (EV_VIEW (ev_window->priv->view), link);
302 }
303
304 gboolean
305 ev_window_is_empty (const EvWindow *ev_window)
306 {
307         g_return_val_if_fail (EV_IS_WINDOW (ev_window), FALSE);
308
309         return ev_window->priv->document == NULL;
310 }
311
312 static void
313 unable_to_load (EvWindow   *ev_window,
314                 const char *error_message)
315 {
316         GtkWidget *dialog;
317
318         dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
319                                          GTK_DIALOG_DESTROY_WITH_PARENT,
320                                          GTK_MESSAGE_ERROR,
321                                          GTK_BUTTONS_CLOSE,
322                                          _("Unable to open document"));
323         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
324                                                   "%s", error_message);
325         gtk_dialog_run (GTK_DIALOG (dialog));
326         gtk_widget_destroy (dialog);
327 }
328
329 /* Would be nice to have this in gdk-pixbuf */
330 static gboolean
331 mime_type_supported_by_gdk_pixbuf (const gchar *mime_type)
332 {
333         GSList *formats, *list;
334         gboolean retval = FALSE;
335
336         formats = gdk_pixbuf_get_formats ();
337
338         list = formats;
339         while (list) {
340                 GdkPixbufFormat *format = list->data;
341                 int i;
342                 gchar **mime_types;
343
344                 if (gdk_pixbuf_format_is_disabled (format))
345                         continue;
346
347                 mime_types = gdk_pixbuf_format_get_mime_types (format);
348
349                 for (i = 0; mime_types[i] != NULL; i++) {
350                         if (strcmp (mime_types[i], mime_type) == 0) {
351                                 retval = TRUE;
352                                 break;
353                         }
354                 }
355
356                 if (retval)
357                         break;
358
359                 list = list->next;
360         }
361
362         g_slist_free (formats);
363
364         return retval;
365 }
366
367 static void
368 update_window_title (EvDocument *document, GParamSpec *pspec, EvWindow *ev_window)
369 {
370         char *title = NULL;
371         char *doc_title = NULL;
372         gboolean password_needed;
373
374         password_needed = (ev_window->priv->password_document != NULL);
375
376         if (document) {
377                 doc_title = ev_document_get_title (document);
378
379                 /* Make sure we get a valid title back */
380                 if (doc_title) {
381                         if (doc_title[0] == '\000' ||
382                             !g_utf8_validate (doc_title, -1, NULL)) {
383                                 g_free (doc_title);
384                                 doc_title = NULL;
385                         }
386                 }
387         }
388
389         if (doc_title) {
390                 char *p;
391
392                 for (p = doc_title; *p; ++p) {
393                         /* an '\n' byte is always ASCII, no need for UTF-8 special casing */
394                         if (*p == '\n')
395                                 *p = ' ';
396                 }
397         }
398
399         if (doc_title == NULL && ev_window->priv->uri) {
400                 doc_title = g_path_get_basename (ev_window->priv->uri);
401         }
402
403         if (password_needed) {
404                 if (doc_title == NULL) {
405                         title = g_strdup (_("Document Viewer - Password Required"));
406                 } else {
407                         title = g_strdup_printf (_("%s - Password Required"), doc_title);
408                 }
409         } else {
410                 if (doc_title == NULL) {
411                         title = g_strdup (_("Document Viewer"));
412                 } else {
413                         title = g_strdup (doc_title);
414                 }
415         }
416
417         gtk_window_set_title (GTK_WINDOW (ev_window), title);
418
419         g_free (doc_title);
420         g_free (title);
421 }
422
423 static void
424 update_total_pages (EvWindow *ev_window)
425 {
426         GtkAction *action;
427         int pages;
428
429         pages = ev_document_get_n_pages (ev_window->priv->document);
430         action = gtk_action_group_get_action
431                 (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
432         ev_page_action_set_total_pages (EV_PAGE_ACTION (action), pages);
433 }
434
435 /* This function assumes that ev_window just had ev_window->document set.
436  */
437 static void
438 ev_window_setup_document (EvWindow *ev_window)
439 {
440         EvDocument *document;
441         EvView *view = EV_VIEW (ev_window->priv->view);
442         EvSidebar *sidebar = EV_SIDEBAR (ev_window->priv->sidebar);
443
444         document = ev_window->priv->document;
445
446         g_signal_connect_object (G_OBJECT (document),
447                                  "notify::title",
448                                  G_CALLBACK (update_window_title),
449                                  ev_window, 0);
450
451         ev_window_set_page_mode (ev_window, PAGE_MODE_SINGLE_PAGE);
452
453         ev_sidebar_set_document (sidebar, document);
454         ev_view_set_document (view, document);
455
456         update_window_title (document, NULL, ev_window);
457         update_total_pages (ev_window);
458         update_action_sensitivity (ev_window);
459 }
460
461 static void
462 password_dialog_response (GtkWidget *password_dialog,
463                           gint       response_id,
464                           EvWindow  *ev_window)
465 {
466         char *password;
467         
468         if (response_id == GTK_RESPONSE_OK) {
469                 EvDocument *document;
470                 gchar *uri;
471
472                 password = ev_password_dialog_get_password (password_dialog);
473                 if (password)
474                         ev_document_security_set_password (EV_DOCUMENT_SECURITY (ev_window->priv->password_document),
475                                                            password);
476                 g_free (password);
477
478                 document = ev_window->priv->password_document;
479                 uri = ev_window->priv->password_uri;
480
481                 ev_window->priv->password_document = NULL;
482                 ev_window->priv->password_uri = NULL;
483
484                 if (start_loading_document (ev_window, document, uri)) {
485                         gtk_widget_destroy (password_dialog);
486                 }
487
488                 g_object_unref (document);
489                 g_free (uri);
490
491                 return;
492         }
493
494         gtk_widget_set_sensitive (ev_window->priv->password_view, TRUE);
495         gtk_widget_destroy (password_dialog);
496 }
497
498 /* Called either by start_loading_document or by the "unlock" callback on the
499  * password_view page.  It assumes that ev_window->priv->password_* has been set
500  * correctly.  These are cleared by password_dialog_response() */
501
502 static void
503 ev_window_popup_password_dialog (EvWindow *ev_window)
504 {
505         g_assert (ev_window->priv->password_document);
506         g_assert (ev_window->priv->password_uri);
507
508         gtk_widget_set_sensitive (ev_window->priv->password_view, FALSE);
509
510         update_window_title (ev_window->priv->password_document, NULL, ev_window);
511         if (ev_window->priv->password_dialog == NULL) {
512                 gchar *file_name;
513
514                 file_name = g_path_get_basename (ev_window->priv->password_uri);
515                 ev_window->priv->password_dialog =
516                         ev_password_dialog_new (GTK_WIDGET (ev_window), file_name);
517                 g_object_add_weak_pointer (G_OBJECT (ev_window->priv->password_dialog),
518                                            (gpointer *) &(ev_window->priv->password_dialog));
519                 g_signal_connect (ev_window->priv->password_dialog,
520                                   "response",
521                                   G_CALLBACK (password_dialog_response),
522                                   ev_window);
523                 g_free (file_name);
524                 gtk_widget_show (ev_window->priv->password_dialog);
525         } else {
526                 ev_password_dialog_set_bad_pass (ev_window->priv->password_dialog);
527         }
528 }
529
530 /* This wil try to load the document.  It might be called multiple times on the
531  * same document by the password dialog.
532  *
533  * Since the flow of the error dialog is very confusing, we assume that both
534  * document and uri will go away after this function is called, and thus we need
535  * to ref/dup them.  Additionally, it needs to clear
536  * ev_window->priv->password_{uri,document}, and thus people who call this
537  * function should _not_ necessarily expect those to exist after being
538  * called. */
539 static gboolean
540 start_loading_document (EvWindow   *ev_window,
541                         EvDocument *document,
542                         const char *uri)
543 {
544         gboolean result;
545         GError *error = NULL;
546
547         g_assert (document);
548         g_assert (document != ev_window->priv->document);
549         g_assert (uri);
550         if (ev_window->priv->password_document) {
551                 g_object_unref (ev_window->priv->password_document);
552                 ev_window->priv->password_document = NULL;
553         }
554         if (ev_window->priv->password_uri) {
555                 g_free (ev_window->priv->password_uri);
556                 ev_window->priv->password_uri = NULL;
557         }
558
559         result = ev_document_load (document, uri, &error);
560
561         /* Success! */
562         if (result) {
563                 if (ev_window->priv->document)
564                         g_object_unref (ev_window->priv->document);
565                 ev_window->priv->document = g_object_ref (document);
566                 ev_window_setup_document (ev_window);
567
568                 return TRUE;
569         }
570
571         /* unable to load the document */
572         g_assert (error != NULL);
573
574         if (error->domain == EV_DOCUMENT_ERROR &&
575             error->code == EV_DOCUMENT_ERROR_ENCRYPTED) {
576                 char *file_name;
577
578                 ev_window->priv->password_document = g_object_ref (document);
579                 ev_window->priv->password_uri = g_strdup (uri);
580
581                 file_name = g_path_get_basename (uri);
582                 ev_password_view_set_file_name (EV_PASSWORD_VIEW (ev_window->priv->password_view),
583                                                 file_name);
584                 g_free (file_name);
585                 ev_window_set_page_mode (ev_window, PAGE_MODE_PASSWORD);
586
587                 ev_window_popup_password_dialog (ev_window);
588         } else {
589                 unable_to_load (ev_window, error->message);
590         }
591         g_error_free (error);
592
593         return FALSE;
594 }
595
596 static gboolean
597 is_file_supported (const gchar *mime_type)
598 {
599         static char *supported_types [] = {
600                 "application/pdf",
601                 "application/postscript",
602                 "application/x-gzpostscript",
603                 "image/x-eps",
604                 NULL
605         };
606         gint   i;
607         
608         g_return_val_if_fail (mime_type != NULL, FALSE);
609
610         if (mime_type_supported_by_gdk_pixbuf (mime_type))
611                 return TRUE;
612         
613         for (i = 0; supported_types[i] != NULL; i++) {
614                 if (g_ascii_strcasecmp (mime_type, supported_types[i]) == 0)
615                         return TRUE;
616         }
617         
618         return FALSE;
619 }
620
621 void
622 ev_window_open (EvWindow *ev_window, const char *uri)
623 {
624         EvDocument *document = NULL;
625         char *mime_type;
626
627         g_free (ev_window->priv->uri);
628         ev_window->priv->uri = g_strdup (uri);
629
630         mime_type = gnome_vfs_get_mime_type (uri);
631
632         if (mime_type == NULL)
633                 document = NULL;
634         else if (!strcmp (mime_type, "application/pdf"))
635                 document = g_object_new (PDF_TYPE_DOCUMENT, NULL);
636         else if (!strcmp (mime_type, "application/postscript") ||
637                  !strcmp (mime_type, "application/x-gzpostscript") ||
638                  !strcmp (mime_type, "image/x-eps"))
639                 document = g_object_new (PS_TYPE_DOCUMENT, NULL);
640         else if (mime_type_supported_by_gdk_pixbuf (mime_type))
641                 document = g_object_new (PIXBUF_TYPE_DOCUMENT, NULL);
642
643         if (document) {
644                 start_loading_document (ev_window, document, uri);
645                 /* See the comment on start_loading_document on ref counting.
646                  * As the password dialog flow is confusing, we're very explicit
647                  * on ref counting. */
648                 g_object_unref (document);
649         } else {
650                 char *error_message;
651
652                 error_message = g_strdup_printf (_("Unhandled MIME type: '%s'"),
653                                                  mime_type?mime_type:"<Unknown MIME Type>");
654                 unable_to_load (ev_window, error_message);
655                 g_free (error_message);
656         }
657
658         g_free (mime_type);
659 }
660
661 static void
662 ev_window_open_uri_list (EvWindow *ev_window, GList *uri_list)
663 {
664         GList *list;
665         gchar *uri, *mime_type;
666         
667         g_return_if_fail (uri_list != NULL);
668         
669         list = uri_list;
670         while (list) {
671                 uri = gnome_vfs_uri_to_string (list->data, GNOME_VFS_URI_HIDE_NONE);
672                 mime_type = gnome_vfs_get_mime_type (uri);
673                 
674                 if (is_file_supported (mime_type)) {
675                         if (ev_window_is_empty (EV_WINDOW (ev_window))) {
676                                 ev_window_open (ev_window, uri);
677                                 
678                                 gtk_widget_show (GTK_WIDGET (ev_window));
679                         } else {
680                                 EvWindow *new_window;
681                                 
682                                 new_window = ev_application_new_window (EV_APP);
683                                 ev_window_open (new_window, uri);
684                                 
685                                 gtk_widget_show (GTK_WIDGET (new_window));
686                         }
687                 }
688
689                 g_free (mime_type);
690                 g_free (uri);
691
692                 list = g_list_next (list);
693         }
694 }
695
696 static void
697 ev_window_cmd_file_open (GtkAction *action, EvWindow *ev_window)
698 {
699         ev_application_open (EV_APP, NULL);
700 }
701
702 /* FIXME
703 static gboolean
704 overwrite_existing_file (GtkWindow *window, const gchar *file_name)
705 {
706         GtkWidget *msgbox;
707         gchar *utf8_file_name;
708         AtkObject *obj;
709         gint ret;
710
711         utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
712         msgbox = gtk_message_dialog_new (
713                 window,
714                 (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
715                 GTK_MESSAGE_QUESTION,
716                 GTK_BUTTONS_NONE,
717                 _("A file named \"%s\" already exists."),
718                 utf8_file_name);
719         g_free (utf8_file_name);
720
721         gtk_message_dialog_format_secondary_text (
722                 GTK_MESSAGE_DIALOG (msgbox),
723                 _("Do you want to replace it with the one you are saving?"));
724
725         gtk_dialog_add_button (GTK_DIALOG (msgbox),
726                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
727
728         gtk_dialog_add_button (GTK_DIALOG (msgbox),
729                                _("_Replace"), GTK_RESPONSE_YES);
730
731         gtk_dialog_set_default_response (GTK_DIALOG (msgbox),
732                                          GTK_RESPONSE_CANCEL);
733
734         obj = gtk_widget_get_accessible (msgbox);
735
736         if (GTK_IS_ACCESSIBLE (obj))
737                 atk_object_set_name (obj, _("Question"));
738
739         ret = gtk_dialog_run (GTK_DIALOG (msgbox));
740         gtk_widget_destroy (msgbox);
741
742         return (ret == GTK_RESPONSE_YES);
743 }
744 */
745
746 static void
747 save_error_dialog (GtkWindow *window, const gchar *file_name)
748 {
749         GtkWidget *error_dialog;
750
751         error_dialog = gtk_message_dialog_new (
752                 window,
753                 (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
754                 GTK_MESSAGE_ERROR,
755                 GTK_BUTTONS_CLOSE,
756                 _("The file could not be saved as \"%s\"."),
757                 file_name);
758
759         /* Easy way to make the text bold while keeping the string
760          * above free from pango markup (FIXME ?) */
761         gtk_message_dialog_format_secondary_text (
762                 GTK_MESSAGE_DIALOG (error_dialog), " ");
763
764         gtk_dialog_run (GTK_DIALOG (error_dialog));
765         gtk_widget_destroy (error_dialog);
766 }
767
768 static void
769 ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
770 {
771         GtkWidget *fc;
772         GtkFileFilter *pdf_filter, *all_filter;
773         gchar *uri = NULL;
774
775         fc = gtk_file_chooser_dialog_new (
776                 _("Save a Copy"),
777                 NULL, GTK_FILE_CHOOSER_ACTION_SAVE,
778                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
779                 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
780                 NULL);
781         gtk_window_set_modal (GTK_WINDOW (fc), TRUE);
782
783         pdf_filter = gtk_file_filter_new ();
784         gtk_file_filter_set_name (pdf_filter, _("PDF Documents"));
785         gtk_file_filter_add_mime_type (pdf_filter, "application/pdf");
786         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fc), pdf_filter);
787
788         all_filter = gtk_file_filter_new ();
789         gtk_file_filter_set_name (all_filter, _("All Files"));
790         gtk_file_filter_add_pattern (all_filter, "*");
791         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fc), all_filter);
792         gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (fc), pdf_filter);
793
794         gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK);
795
796         gtk_widget_show (fc);
797
798         while (gtk_dialog_run (GTK_DIALOG (fc)) == GTK_RESPONSE_OK) {
799                 uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
800
801 /* FIXME
802                 if (g_file_test (uri, G_FILE_TEST_EXISTS) &&
803                     !overwrite_existing_file (GTK_WINDOW (fc), uri))
804                                 continue;
805 */
806
807                 if (ev_document_save (ev_window->priv->document, uri, NULL))
808                         break;
809                 else
810                         save_error_dialog (GTK_WINDOW (fc), uri);
811         }
812         gtk_widget_destroy (fc);
813 }
814
815 static gboolean
816 using_postscript_printer (GnomePrintConfig *config)
817 {
818         const guchar *driver;
819         const guchar *transport;
820
821         driver = gnome_print_config_get (
822                 config, (const guchar *)"Settings.Engine.Backend.Driver");
823
824         transport = gnome_print_config_get (
825                 config, (const guchar *)"Settings.Transport.Backend");
826
827         if (driver) {
828                 if (!strcmp ((const gchar *)driver, "gnome-print-ps"))
829                         return TRUE;
830                 else
831                         return FALSE;
832         } else  if (transport) {
833                 if (!strcmp ((const gchar *)transport, "CUPS"))
834                         return TRUE;
835         }
836
837         return FALSE;
838 }
839
840 static void
841 ev_window_print (EvWindow *ev_window)
842 {
843         GnomePrintConfig *config;
844         GnomePrintJob *job;
845         GtkWidget *print_dialog;
846         EvPrintJob *print_job = NULL;
847
848         g_return_if_fail (EV_IS_WINDOW (ev_window));
849         g_return_if_fail (ev_window->priv->document != NULL);
850
851         config = gnome_print_config_default ();
852         job = gnome_print_job_new (config);
853
854         print_dialog = gnome_print_dialog_new (job, _("Print"),
855                                                (GNOME_PRINT_DIALOG_RANGE |
856                                                 GNOME_PRINT_DIALOG_COPIES));
857         gtk_dialog_set_response_sensitive (GTK_DIALOG (print_dialog),
858                                            GNOME_PRINT_DIALOG_RESPONSE_PREVIEW,
859                                            FALSE);
860
861         while (TRUE) {
862                 int response;
863                 response = gtk_dialog_run (GTK_DIALOG (print_dialog));
864
865                 if (response != GNOME_PRINT_DIALOG_RESPONSE_PRINT)
866                         break;
867
868                 /* FIXME: Change this when we have the first backend
869                  * that can print more than postscript
870                  */
871                 if (!using_postscript_printer (config)) {
872                         GtkWidget *dialog;
873
874                         dialog = gtk_message_dialog_new (
875                                 GTK_WINDOW (print_dialog), GTK_DIALOG_MODAL,
876                                 GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
877                                 _("Printing is not supported on this printer."));
878                         gtk_message_dialog_format_secondary_text (
879                                 GTK_MESSAGE_DIALOG (dialog),
880                                 _("You were trying to print to a printer using the \"%s\" driver. This program requires a PostScript printer driver."),
881                                 gnome_print_config_get (
882                                         config, "Settings.Engine.Backend.Driver"));
883                         gtk_dialog_run (GTK_DIALOG (dialog));
884                         gtk_widget_destroy (dialog);
885
886                         continue;
887                 }
888
889                 print_job = g_object_new (EV_TYPE_PRINT_JOB,
890                                           "gnome_print_job", job,
891                                           "document", ev_window->priv->document,
892                                           "print_dialog", print_dialog,
893                                           NULL);
894                 break;
895         }
896
897         gtk_widget_destroy (print_dialog);
898
899         if (print_job != NULL) {
900                 ev_print_job_print (print_job, GTK_WINDOW (ev_window));
901                 g_object_unref (print_job);
902         }
903 }
904
905 static void
906 ev_window_cmd_file_print (GtkAction *action, EvWindow *ev_window)
907 {
908         ev_window_print (ev_window);
909 }
910
911 static void
912 ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
913 {
914         g_return_if_fail (EV_IS_WINDOW (ev_window));
915
916         gtk_widget_destroy (GTK_WIDGET (ev_window));
917 }
918
919 static void
920 find_not_supported_dialog (EvWindow   *ev_window)
921 {
922         GtkWidget *dialog;
923
924         /* If you change this so it isn't modal, be sure you don't
925          * allow multiple copies of the dialog...
926          */
927
928         dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
929                                          GTK_DIALOG_DESTROY_WITH_PARENT,
930                                          GTK_MESSAGE_ERROR,
931                                          GTK_BUTTONS_CLOSE,
932                                          _("The \"Find\" feature will not work with this document"));
933         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
934                                                   _("Searching for text is only supported for PDF documents."));
935         gtk_dialog_run (GTK_DIALOG (dialog));
936         gtk_widget_destroy (dialog);
937 }
938
939 static void
940 ev_window_cmd_edit_select_all (GtkAction *action, EvWindow *ev_window)
941 {
942         g_return_if_fail (EV_IS_WINDOW (ev_window));
943
944         ev_view_select_all (EV_VIEW (ev_window->priv->view));
945 }
946
947 static void
948 ev_window_cmd_edit_find (GtkAction *action, EvWindow *ev_window)
949 {
950         g_return_if_fail (EV_IS_WINDOW (ev_window));
951
952         if (ev_window->priv->document == NULL) {
953                 g_printerr ("We should have set the Find menu item insensitive since there's no document\n");
954         } else if (!EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
955                 find_not_supported_dialog (ev_window);
956         } else {
957                 update_chrome_flag (ev_window, EV_CHROME_FINDBAR, NULL, TRUE);
958
959                 egg_find_bar_grab_focus (EGG_FIND_BAR (ev_window->priv->find_bar));
960         }
961 }
962
963 static void
964 ev_window_cmd_edit_copy (GtkAction *action, EvWindow *ev_window)
965 {
966         g_return_if_fail (EV_IS_WINDOW (ev_window));
967
968         ev_view_copy (EV_VIEW (ev_window->priv->view));
969 }
970
971 static void
972 ev_window_update_fullscreen_popup (EvWindow *window)
973 {
974         GtkWidget *popup = window->priv->fullscreen_popup;
975         int popup_width, popup_height;
976         GdkRectangle screen_rect;
977         gboolean toolbar;
978
979         g_return_if_fail (popup != NULL);
980
981         toolbar = (window->priv->chrome & EV_CHROME_TOOLBAR) != 0;
982         popup_width = popup->requisition.width;
983         popup_height = popup->requisition.height;
984
985         /* FIXME multihead */
986         gdk_screen_get_monitor_geometry (gdk_screen_get_default (),
987                         gdk_screen_get_monitor_at_window
988                         (gdk_screen_get_default (),
989                          GTK_WIDGET (window)->window),
990                          &screen_rect);
991         if (toolbar) {
992                 gtk_widget_set_size_request (popup,
993                                              screen_rect.width,
994                                              -1);
995                 gtk_window_move (GTK_WINDOW (popup),
996                                  screen_rect.x,
997                                  screen_rect.y);
998
999         } else {
1000                 if (gtk_widget_get_direction (popup) == GTK_TEXT_DIR_RTL)
1001                 {
1002                         gtk_window_move (GTK_WINDOW (popup),
1003                                          screen_rect.x,
1004                                          screen_rect.y);
1005                 } else {
1006                         gtk_window_move (GTK_WINDOW (popup),
1007                                          screen_rect.x + screen_rect.width - popup_width,
1008                                          screen_rect.y);
1009                 }
1010         }
1011 }
1012
1013 static void
1014 screen_size_changed_cb (GdkScreen *screen,
1015                         EvWindow *window)
1016 {
1017         ev_window_update_fullscreen_popup (window);
1018 }
1019
1020 static void
1021 destroy_fullscreen_popup (EvWindow *window)
1022 {
1023         if (window->priv->fullscreen_popup != NULL)
1024         {
1025                 /* FIXME multihead */
1026                 g_signal_handlers_disconnect_by_func
1027                         (gdk_screen_get_default (),
1028                          G_CALLBACK (screen_size_changed_cb), window);
1029
1030                 gtk_widget_destroy (window->priv->fullscreen_popup);
1031                 window->priv->fullscreen_popup = NULL;
1032         }
1033 }
1034
1035 static void
1036 exit_fullscreen_button_clicked_cb (GtkWidget *button, EvWindow *window)
1037 {
1038         GtkAction *action;
1039
1040         action = gtk_action_group_get_action (window->priv->action_group, "ViewFullscreen");
1041         g_return_if_fail (action != NULL);
1042
1043         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
1044 }
1045
1046 static void
1047 fullscreen_popup_size_request_cb (GtkWidget *popup, GtkRequisition *req, EvWindow *window)
1048 {
1049         ev_window_update_fullscreen_popup (window);
1050 }
1051
1052 static gboolean
1053 fullscreen_timeout_cb (gpointer data)
1054 {
1055         EvWindow *window = EV_WINDOW (data);
1056
1057         g_object_set (window->priv->fullscreen_popup, "visible", FALSE, NULL);
1058         ev_view_hide_cursor (EV_VIEW (window->priv->view));
1059         window->priv->fullscreen_timeout_source = NULL;
1060
1061         return FALSE;
1062 }
1063
1064 static void
1065 fullscreen_set_timeout (EvWindow *window)
1066 {
1067         GSource *source;
1068
1069         if (window->priv->fullscreen_timeout_source != NULL)
1070                 g_source_destroy (window->priv->fullscreen_timeout_source);
1071
1072         source = g_timeout_source_new (1000);
1073         g_source_set_callback (source, fullscreen_timeout_cb, window, NULL);
1074         g_source_attach (source, NULL);
1075         window->priv->fullscreen_timeout_source = source;
1076 }
1077
1078 static void
1079 fullscreen_clear_timeout (EvWindow *window)
1080 {
1081         if (window->priv->fullscreen_timeout_source != NULL)
1082                 g_source_destroy (window->priv->fullscreen_timeout_source);
1083
1084         window->priv->fullscreen_timeout_source = NULL;
1085         ev_view_show_cursor (EV_VIEW (window->priv->view));
1086 }
1087
1088 static gboolean
1089 fullscreen_motion_notify_cb (GtkWidget *widget,
1090                              GdkEventMotion *event,
1091                              gpointer user_data)
1092 {
1093         EvWindow *window = EV_WINDOW (user_data);
1094
1095         if (!GTK_WIDGET_VISIBLE (window->priv->fullscreen_popup)) {
1096                 g_object_set (window->priv->fullscreen_popup, "visible", TRUE, NULL);
1097                 ev_view_show_cursor (EV_VIEW (window->priv->view));
1098         }
1099
1100         fullscreen_set_timeout (window);
1101
1102         return FALSE;
1103 }
1104
1105 static gboolean
1106 fullscreen_leave_notify_cb (GtkWidget *widget,
1107                             GdkEventCrossing *event,
1108                             gpointer user_data)
1109 {
1110         EvWindow *window = EV_WINDOW (user_data);
1111
1112         fullscreen_clear_timeout (window);
1113
1114         return FALSE;
1115 }
1116
1117 static GtkWidget *
1118 ev_window_get_exit_fullscreen_button (EvWindow *window)
1119 {
1120         GtkWidget *button, *icon, *label, *hbox;
1121
1122         button = gtk_button_new ();
1123         g_signal_connect (button, "clicked",
1124                           G_CALLBACK (exit_fullscreen_button_clicked_cb),
1125                           window);
1126         gtk_widget_show (button);
1127
1128         hbox = gtk_hbox_new (FALSE, 2);
1129         gtk_widget_show (hbox);
1130         gtk_container_add (GTK_CONTAINER (button), hbox);
1131
1132         icon = gtk_image_new_from_stock (EV_STOCK_LEAVE_FULLSCREEN, GTK_ICON_SIZE_BUTTON);
1133         gtk_widget_show (icon);
1134         gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
1135
1136         label = gtk_label_new (_("Leave Fullscreen"));
1137         gtk_widget_show (label);
1138         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1139
1140         return button;
1141 }
1142
1143 static GtkWidget *
1144 ev_window_create_fullscreen_popup (EvWindow *window)
1145 {
1146         GtkWidget *popup;
1147         GtkWidget *hbox;
1148         GtkWidget *button;
1149
1150         popup = gtk_window_new (GTK_WINDOW_POPUP);
1151         hbox = gtk_hbox_new (FALSE, 0);
1152         button = ev_window_get_exit_fullscreen_button (window);
1153
1154         gtk_container_add (GTK_CONTAINER (popup), hbox);
1155         gtk_box_pack_start (GTK_BOX (hbox), window->priv->fullscreen_toolbar,
1156                             TRUE, TRUE, 0);
1157         gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1158
1159         gtk_widget_show (button);
1160         gtk_widget_show (hbox);
1161
1162         gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
1163
1164         /* FIXME multihead */
1165         g_signal_connect (gdk_screen_get_default (), "size-changed",
1166                           G_CALLBACK (screen_size_changed_cb), window);
1167         g_signal_connect (popup, "size_request",
1168                           G_CALLBACK (fullscreen_popup_size_request_cb), window);
1169
1170         return popup;
1171 }
1172
1173 static void
1174 ev_window_fullscreen (EvWindow *window)
1175 {
1176         window->priv->fullscreen_mode = TRUE;
1177
1178         if (window->priv->fullscreen_popup == NULL)
1179                 window->priv->fullscreen_popup
1180                         = ev_window_create_fullscreen_popup (window);
1181         update_chrome_visibility (window);
1182
1183         g_object_set (G_OBJECT (window->priv->scrolled_window),
1184                       "shadow-type", GTK_SHADOW_NONE,
1185                       NULL);
1186
1187         g_signal_connect (window->priv->view,
1188                           "motion-notify-event",
1189                           G_CALLBACK (fullscreen_motion_notify_cb),
1190                           window);
1191         g_signal_connect (window->priv->view,
1192                           "leave-notify-event",
1193                           G_CALLBACK (fullscreen_leave_notify_cb),
1194                           window);
1195         fullscreen_set_timeout (window);
1196
1197         gtk_widget_grab_focus (window->priv->view);
1198
1199         ev_window_update_fullscreen_popup (window);
1200 }
1201
1202 static void
1203 ev_window_unfullscreen (EvWindow *window)
1204 {
1205         window->priv->fullscreen_mode = FALSE;
1206
1207         g_object_set (G_OBJECT (window->priv->scrolled_window),
1208                       "shadow-type", GTK_SHADOW_IN,
1209                       NULL);
1210
1211         fullscreen_clear_timeout (window);
1212
1213         g_signal_handlers_disconnect_by_func (window->priv->view,
1214                                               (gpointer) fullscreen_motion_notify_cb,
1215                                               window);
1216
1217 //      destroy_fullscreen_popup (window);
1218
1219         update_chrome_visibility (window);
1220 }
1221
1222 static void
1223 ev_window_cmd_view_fullscreen (GtkAction *action, EvWindow *ev_window)
1224 {
1225         gboolean fullscreen;
1226
1227         g_return_if_fail (EV_IS_WINDOW (ev_window));
1228
1229         fullscreen = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1230
1231         if (fullscreen) {
1232                 gtk_window_fullscreen (GTK_WINDOW (ev_window));
1233         } else {
1234                 gtk_window_unfullscreen (GTK_WINDOW (ev_window));
1235         }
1236 }
1237
1238 static gboolean
1239 ev_window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event, EvWindow *window)
1240 {
1241         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
1242         {
1243                 GtkActionGroup *action_group;
1244                 GtkAction *action;
1245                 gboolean fullscreen;
1246
1247                 fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
1248
1249                 if (fullscreen)
1250                 {
1251                         ev_window_fullscreen (window);
1252                 }
1253                 else
1254                 {
1255                         ev_window_unfullscreen (window);
1256                 }
1257
1258                 action_group = window->priv->action_group;
1259
1260                 action = gtk_action_group_get_action (action_group, "ViewFullscreen");
1261                 g_signal_handlers_block_by_func
1262                         (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
1263                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fullscreen);
1264                 g_signal_handlers_unblock_by_func
1265                         (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
1266
1267         }
1268
1269         return FALSE;
1270 }
1271
1272 static gboolean
1273 ev_window_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
1274 {
1275         EvWindow *window = EV_WINDOW (widget);
1276         EvWindowPrivate *priv = window->priv;
1277
1278         if (priv->fullscreen_mode)
1279         {
1280                 gtk_widget_show (priv->fullscreen_popup);
1281         }
1282
1283         return GTK_WIDGET_CLASS (ev_window_parent_class)->focus_in_event (widget, event);
1284 }
1285
1286 static gboolean
1287 ev_window_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
1288 {
1289         EvWindow *window = EV_WINDOW (widget);
1290         EvWindowPrivate *priv = window->priv;
1291
1292         if (priv->fullscreen_mode)
1293         {
1294                 gtk_widget_hide (priv->fullscreen_popup);
1295         }
1296
1297         return GTK_WIDGET_CLASS (ev_window_parent_class)->focus_out_event (widget, event);
1298 }
1299
1300 static void
1301 ev_window_set_page_mode (EvWindow         *window,
1302                          EvWindowPageMode  page_mode)
1303 {
1304         GtkWidget *child = NULL;
1305         GtkWidget *real_child;
1306
1307         if (window->priv->page_mode == page_mode)
1308                 return;
1309
1310         window->priv->page_mode = page_mode;
1311
1312         switch (page_mode) {
1313         case PAGE_MODE_SINGLE_PAGE:
1314                 child = window->priv->view;
1315                 break;
1316         case PAGE_MODE_PASSWORD:
1317                 child = window->priv->password_view;
1318                 break;
1319         case PAGE_MODE_CONTINUOUS_PAGE:
1320                 child = window->priv->page_view;
1321                 break;
1322         default:
1323                 g_assert_not_reached ();
1324         }
1325
1326         real_child = gtk_bin_get_child (GTK_BIN (window->priv->scrolled_window));
1327         if (child != real_child) {
1328                 gtk_container_remove (GTK_CONTAINER (window->priv->scrolled_window),
1329                                       real_child);
1330                 gtk_container_add (GTK_CONTAINER (window->priv->scrolled_window),
1331                                    child);
1332         }
1333         update_action_sensitivity (window);
1334 }
1335
1336 static void
1337 ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window)
1338 {
1339         g_return_if_fail (EV_IS_WINDOW (ev_window));
1340
1341         ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE);
1342
1343         ev_view_zoom_in (EV_VIEW (ev_window->priv->view));
1344 }
1345
1346 static void
1347 ev_window_cmd_view_zoom_out (GtkAction *action, EvWindow *ev_window)
1348 {
1349         g_return_if_fail (EV_IS_WINDOW (ev_window));
1350
1351         ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE);
1352
1353         ev_view_zoom_out (EV_VIEW (ev_window->priv->view));
1354 }
1355
1356 static void
1357 ev_window_cmd_view_normal_size (GtkAction *action, EvWindow *ev_window)
1358 {
1359         g_return_if_fail (EV_IS_WINDOW (ev_window));
1360
1361         ev_view_normal_size (EV_VIEW (ev_window->priv->view));
1362 }
1363
1364 static void
1365 ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
1366 {
1367         EvWindowPrivate *priv = ev_window->priv;
1368         GtkWidget *button;
1369
1370         g_return_if_fail (EV_IS_WINDOW (ev_window));
1371
1372         button = gtk_ui_manager_get_widget (priv->ui_manager, "/ToolBar/ViewBestFit");
1373         if (! gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button)))
1374                 return;
1375
1376         ev_window_set_sizing_mode (ev_window, EV_SIZING_BEST_FIT);
1377 }
1378
1379 static void
1380 ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
1381 {
1382         EvWindowPrivate *priv = ev_window->priv;
1383         GtkWidget *button;
1384         int width, height;
1385         GtkRequisition vsb_requisition;
1386         int scrollbar_spacing;
1387
1388         g_return_if_fail (EV_IS_WINDOW (ev_window));
1389
1390         button = gtk_ui_manager_get_widget (priv->ui_manager, "/ToolBar/ViewPageWidth");
1391         if (! gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button)))
1392                 return;
1393
1394
1395         width = priv->scrolled_window->allocation.width;
1396         height = priv->scrolled_window->allocation.height;
1397
1398         /* the scrolled window has a GTK_SHADOW_IN */
1399         width -= 2 * priv->view->style->xthickness;
1400         height -= 2 * priv->view->style->ythickness;
1401
1402         gtk_widget_size_request (
1403                 GTK_SCROLLED_WINDOW (priv->scrolled_window)->vscrollbar,
1404                 &vsb_requisition);
1405         gtk_widget_style_get (priv->scrolled_window,
1406                               "scrollbar_spacing", &scrollbar_spacing,
1407                               NULL);
1408
1409         ev_window_set_sizing_mode (ev_window, EV_SIZING_FIT_WIDTH);
1410
1411         ev_view_fit_width (EV_VIEW (ev_window->priv->view),
1412                            width, height,
1413                            vsb_requisition.width + scrollbar_spacing);
1414 }
1415
1416 static void
1417 ev_window_cmd_go_previous_page (GtkAction *action, EvWindow *ev_window)
1418 {
1419         g_return_if_fail (EV_IS_WINDOW (ev_window));
1420
1421         ev_view_set_page (EV_VIEW (ev_window->priv->view),
1422                           ev_view_get_page (EV_VIEW (ev_window->priv->view)) - 1);
1423 }
1424
1425 static void
1426 ev_window_cmd_go_next_page (GtkAction *action, EvWindow *ev_window)
1427 {
1428         g_return_if_fail (EV_IS_WINDOW (ev_window));
1429
1430         ev_view_set_page (EV_VIEW (ev_window->priv->view),
1431                           ev_view_get_page (EV_VIEW (ev_window->priv->view)) + 1);
1432 }
1433
1434 static void
1435 ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window)
1436 {
1437         g_return_if_fail (EV_IS_WINDOW (ev_window));
1438
1439         ev_view_set_page (EV_VIEW (ev_window->priv->view), 1);
1440 }
1441
1442 static void
1443 ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window)
1444 {
1445         g_return_if_fail (EV_IS_WINDOW (ev_window));
1446
1447         ev_view_set_page (EV_VIEW (ev_window->priv->view), G_MAXINT);
1448 }
1449
1450 static void
1451 ev_window_cmd_help_contents (GtkAction *action, EvWindow *ev_window)
1452 {
1453         g_return_if_fail (EV_IS_WINDOW (ev_window));
1454
1455         /* FIXME */
1456 }
1457
1458 static void
1459 ev_window_cmd_leave_fullscreen (GtkAction *action, EvWindow *window)
1460 {
1461         gtk_window_unfullscreen (GTK_WINDOW (window));
1462 }
1463
1464 static void
1465 size_allocate_cb (GtkWidget     *scrolled_window,
1466                   GtkAllocation *allocation,
1467                   EvWindow      *ev_window)
1468 {
1469         int width, height;
1470         GtkRequisition vsb_requisition;
1471         int scrollbar_spacing;
1472
1473         width = ev_window->priv->scrolled_window->allocation.width;
1474         height = ev_window->priv->scrolled_window->allocation.height;
1475
1476         /* the scrolled window has a GTK_SHADOW_IN */
1477         width -= 2 * ev_window->priv->view->style->xthickness;
1478         height -= 2 * ev_window->priv->view->style->ythickness;
1479
1480         if (ev_window->priv->sizing_mode == EV_SIZING_BEST_FIT) {
1481                 ev_view_best_fit (EV_VIEW (ev_window->priv->view),
1482                                   MAX (1, width), MAX (1, height));
1483         } else if (ev_window->priv->sizing_mode == EV_SIZING_FIT_WIDTH) {
1484                 gtk_widget_size_request (GTK_SCROLLED_WINDOW (ev_window->priv->scrolled_window)->vscrollbar,
1485                                          &vsb_requisition);
1486                 gtk_widget_style_get (ev_window->priv->scrolled_window,
1487                                       "scrollbar_spacing", &scrollbar_spacing,
1488                                       NULL);
1489                 ev_view_fit_width (EV_VIEW (ev_window->priv->view),
1490                                    width, height,
1491                                    vsb_requisition.width + scrollbar_spacing);
1492         }
1493 }
1494
1495 static void
1496 ev_window_set_sizing_mode (EvWindow     *ev_window,
1497                            EvSizingMode  sizing_mode)
1498 {
1499         GtkWidget *scrolled_window;
1500
1501         if (ev_window->priv->sizing_mode == sizing_mode)
1502                 return;
1503
1504         scrolled_window = ev_window->priv->scrolled_window;
1505         ev_window->priv->sizing_mode = sizing_mode;
1506
1507         g_signal_handlers_disconnect_by_func (scrolled_window, size_allocate_cb, ev_window);
1508
1509         switch (sizing_mode) {
1510         case EV_SIZING_BEST_FIT:
1511                 g_object_set (G_OBJECT (scrolled_window),
1512                               "hscrollbar-policy", GTK_POLICY_NEVER,
1513                               "vscrollbar-policy", GTK_POLICY_NEVER,
1514                               NULL);
1515                 g_signal_connect (scrolled_window, "size-allocate",
1516                                   G_CALLBACK (size_allocate_cb),
1517                                   ev_window);
1518                 break;
1519         case EV_SIZING_FIT_WIDTH:
1520                 g_object_set (G_OBJECT (scrolled_window),
1521                               "hscrollbar-policy", GTK_POLICY_NEVER,
1522                               "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
1523                               NULL);
1524                 g_signal_connect (scrolled_window, "size-allocate",
1525                                   G_CALLBACK (size_allocate_cb),
1526                                   ev_window);
1527                 break;
1528         case EV_SIZING_FREE:
1529                 g_object_set (G_OBJECT (scrolled_window),
1530                               "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
1531                               "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
1532                               NULL);
1533                 break;
1534         }
1535
1536         ev_view_set_mode (EV_VIEW (ev_window->priv->view), sizing_mode);
1537         update_sizing_buttons (ev_window);
1538 }
1539
1540 static void
1541 ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
1542 {
1543         const char *authors[] = {
1544                 N_("Many..."),
1545                 NULL
1546         };
1547
1548         const char *documenters[] = {
1549                 N_("Not so many..."),
1550                 NULL
1551         };
1552
1553         const char *license[] = {
1554                 N_("Evince is free software; you can redistribute it and/or modify\n"
1555                    "it under the terms of the GNU General Public License as published by\n"
1556                    "the Free Software Foundation; either version 2 of the License, or\n"
1557                    "(at your option) any later version.\n"),
1558                 N_("Evince is distributed in the hope that it will be useful,\n"
1559                    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1560                    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1561                    "GNU General Public License for more details.\n"),
1562                 N_("You should have received a copy of the GNU General Public License\n"
1563                    "along with Evince; if not, write to the Free Software Foundation, Inc.,\n"
1564                    "59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n")
1565         };
1566
1567         char *license_trans;
1568
1569 #ifdef ENABLE_NLS
1570         const char **p;
1571
1572         for (p = authors; *p; ++p)
1573                 *p = _(*p);
1574
1575         for (p = documenters; *p; ++p)
1576                 *p = _(*p);
1577 #endif
1578
1579         license_trans = g_strconcat (_(license[0]), "\n", _(license[1]), "\n",
1580                                      _(license[2]), "\n", NULL);
1581
1582         gtk_show_about_dialog (
1583                 GTK_WINDOW (ev_window),
1584                 "name", _("Evince"),
1585                 "version", VERSION,
1586                 "copyright",
1587                 _("\xc2\xa9 1996-2004 The Evince authors"),
1588                 "license", license_trans,
1589                 "website", "http://www.gnome.org/projects/evince",
1590                 "comments", _("PostScript and PDF File Viewer."),
1591                 "authors", authors,
1592                 "documenters", documenters,
1593                 "translator-credits", _("translator-credits"),
1594                 NULL);
1595
1596         g_free (license_trans);
1597 }
1598
1599 static void
1600 ev_window_view_toolbar_cb (GtkAction *action, EvWindow *ev_window)
1601 {
1602         update_chrome_flag (ev_window, EV_CHROME_TOOLBAR,
1603                             GCONF_CHROME_TOOLBAR,
1604                             gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
1605 }
1606
1607 static void
1608 ev_window_view_statusbar_cb (GtkAction *action, EvWindow *ev_window)
1609 {
1610         update_chrome_flag (ev_window, EV_CHROME_STATUSBAR,
1611                             GCONF_CHROME_STATUSBAR,
1612                             gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
1613 }
1614
1615 static void
1616 ev_window_view_sidebar_cb (GtkAction *action, EvWindow *ev_window)
1617 {
1618         update_chrome_flag (ev_window, EV_CHROME_SIDEBAR,
1619                             GCONF_CHROME_SIDEBAR,
1620                             gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
1621 }
1622
1623 static void
1624 menu_item_select_cb (GtkMenuItem *proxy, EvWindow *ev_window)
1625 {
1626         GtkAction *action;
1627         char *message;
1628
1629         action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
1630         g_return_if_fail (action != NULL);
1631
1632         g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
1633         if (message) {
1634                 gtk_statusbar_push (GTK_STATUSBAR (ev_window->priv->statusbar),
1635                                     ev_window->priv->help_message_cid, message);
1636                 g_free (message);
1637         }
1638 }
1639
1640 static void
1641 menu_item_deselect_cb (GtkMenuItem *proxy, EvWindow *ev_window)
1642 {
1643         gtk_statusbar_pop (GTK_STATUSBAR (ev_window->priv->statusbar),
1644                            ev_window->priv->help_message_cid);
1645 }
1646
1647 static void
1648 connect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action,
1649                   GtkWidget *proxy, EvWindow *ev_window)
1650 {
1651         if (GTK_IS_MENU_ITEM (proxy)) {
1652                 g_signal_connect (proxy, "select",
1653                                   G_CALLBACK (menu_item_select_cb), ev_window);
1654                 g_signal_connect (proxy, "deselect",
1655                                   G_CALLBACK (menu_item_deselect_cb),
1656                                   ev_window);
1657         }
1658 }
1659
1660 static void
1661 disconnect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action,
1662                      GtkWidget *proxy, EvWindow *ev_window)
1663 {
1664         if (GTK_IS_MENU_ITEM (proxy)) {
1665                 g_signal_handlers_disconnect_by_func
1666                         (proxy, G_CALLBACK (menu_item_select_cb), ev_window);
1667                 g_signal_handlers_disconnect_by_func
1668                         (proxy, G_CALLBACK (menu_item_deselect_cb), ev_window);
1669         }
1670 }
1671
1672 static void
1673 update_current_page (EvWindow *ev_window,
1674                      EvView   *view)
1675 {
1676         int page;
1677         GtkAction *action;
1678         EvSidebarThumbnails *thumbs;
1679
1680         thumbs = EV_SIDEBAR_THUMBNAILS (ev_window->priv->thumbs_sidebar);
1681         ev_sidebar_thumbnails_select_page (thumbs, ev_view_get_page (view));
1682
1683         action = gtk_action_group_get_action
1684                 (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
1685
1686         page = ev_view_get_page (EV_VIEW (ev_window->priv->view));
1687         ev_page_action_set_current_page (EV_PAGE_ACTION (action), page);
1688 }
1689
1690 static void
1691 view_page_changed_cb (EvView   *view,
1692                       EvWindow *ev_window)
1693 {
1694         update_current_page (ev_window, view);
1695         update_action_sensitivity (ev_window);
1696 }
1697
1698 static void
1699 view_status_changed_cb (EvView     *view,
1700                         GParamSpec *pspec,
1701                         EvWindow   *ev_window)
1702 {
1703         const char *message;
1704
1705         gtk_statusbar_pop (GTK_STATUSBAR (ev_window->priv->statusbar),
1706                            ev_window->priv->view_message_cid);
1707
1708         message = ev_view_get_status (view);
1709         if (message) {
1710                 gtk_statusbar_push (GTK_STATUSBAR (ev_window->priv->statusbar),
1711                                     ev_window->priv->view_message_cid, message);
1712         }
1713 }
1714
1715 static void
1716 view_find_status_changed_cb (EvView     *view,
1717                              GParamSpec *pspec,
1718                              EvWindow   *ev_window)
1719 {
1720         const char *text;
1721
1722         text = ev_view_get_find_status (view);
1723         egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
1724                                       text);
1725 }
1726
1727 static void
1728 find_bar_previous_cb (EggFindBar *find_bar,
1729                       EvWindow   *ev_window)
1730 {
1731         ev_view_find_previous (EV_VIEW (ev_window->priv->view));
1732 }
1733
1734 static void
1735 find_bar_next_cb (EggFindBar *find_bar,
1736                   EvWindow   *ev_window)
1737 {
1738         ev_view_find_next (EV_VIEW (ev_window->priv->view));
1739 }
1740
1741 static void
1742 find_bar_close_cb (EggFindBar *find_bar,
1743                    EvWindow   *ev_window)
1744 {
1745         update_chrome_flag (ev_window, EV_CHROME_FINDBAR, NULL, FALSE);
1746 }
1747
1748 static void
1749 ev_window_page_mode_cb (GtkRadioAction *action,
1750                         GtkRadioAction *activated_action,
1751                         EvWindow       *window)
1752 {
1753         int mode;
1754
1755         mode = gtk_radio_action_get_current_value (action);
1756
1757         g_assert (mode == PAGE_MODE_CONTINUOUS_PAGE ||
1758                   mode == PAGE_MODE_SINGLE_PAGE);
1759
1760         ev_window_set_page_mode (window, (EvWindowPageMode) mode);
1761 }
1762
1763 static void
1764 find_bar_search_changed_cb (EggFindBar *find_bar,
1765                             GParamSpec *param,
1766                             EvWindow   *ev_window)
1767 {
1768         gboolean case_sensitive;
1769         gboolean visible;
1770         const char *search_string;
1771
1772         g_return_if_fail (EV_IS_WINDOW (ev_window));
1773
1774         /* Either the string or case sensitivity could have changed,
1775          * we connect this callback to both. We also connect it
1776          * to ::visible so when the find bar is hidden, we should
1777          * pretend the search string is NULL/""
1778          */
1779
1780         case_sensitive = egg_find_bar_get_case_sensitive (find_bar);
1781         visible = GTK_WIDGET_VISIBLE (find_bar);
1782         search_string = egg_find_bar_get_search_string (find_bar);
1783
1784 #if 0
1785         g_printerr ("search for '%s'\n", search_string ? search_string : "(nil)");
1786 #endif
1787
1788         if (ev_window->priv->document &&
1789             EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
1790                 if (visible && search_string) {
1791                         ev_document_find_begin (EV_DOCUMENT_FIND (ev_window->priv->document), search_string, case_sensitive);
1792                 } else {
1793                         ev_document_find_cancel (EV_DOCUMENT_FIND (ev_window->priv->document));
1794                         egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
1795                                                       NULL);
1796                         gtk_widget_queue_draw (GTK_WIDGET (ev_window->priv->view));
1797                 }
1798         }
1799 }
1800
1801 static void
1802 ev_window_dispose (GObject *object)
1803 {
1804         EvWindow *window = EV_WINDOW (object);
1805         EvWindowPrivate *priv = window->priv;
1806
1807         if (priv->ui_manager) {
1808                 g_object_unref (priv->ui_manager);
1809                 priv->ui_manager = NULL;
1810         }
1811
1812         if (priv->action_group) {
1813                 g_object_unref (priv->action_group);
1814                 priv->action_group = NULL;
1815         }
1816
1817         if (priv->document) {
1818                 g_object_unref (priv->document);
1819                 priv->document = NULL;
1820         }
1821
1822         if (priv->view) {
1823                 g_object_unref (priv->view);
1824                 priv->view = NULL;
1825         }
1826
1827         if (priv->page_view) {
1828                 g_object_unref (priv->page_view);
1829                 priv->page_view = NULL;
1830         }
1831
1832         if (priv->password_document) {
1833                 g_object_unref (priv->password_document);
1834                 priv->password_document = NULL;
1835         }
1836         
1837         if (priv->password_uri) {
1838                 g_free (priv->password_uri);
1839                 priv->password_uri = NULL;
1840         }
1841
1842         destroy_fullscreen_popup (window);
1843
1844         G_OBJECT_CLASS (ev_window_parent_class)->dispose (object);
1845 }
1846
1847 static void
1848 ev_window_class_init (EvWindowClass *ev_window_class)
1849 {
1850         GObjectClass *g_object_class = G_OBJECT_CLASS (ev_window_class);
1851         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (ev_window_class);
1852
1853         g_object_class->dispose = ev_window_dispose;
1854
1855         widget_class->focus_in_event = ev_window_focus_in_event;
1856         widget_class->focus_out_event = ev_window_focus_out_event;
1857
1858         g_type_class_add_private (g_object_class, sizeof (EvWindowPrivate));
1859 }
1860
1861 /* Normal items */
1862 static GtkActionEntry entries[] = {
1863         { "File", NULL, N_("_File") },
1864         { "Edit", NULL, N_("_Edit") },
1865         { "View", NULL, N_("_View") },
1866         { "Go", NULL, N_("_Go") },
1867         { "Help", NULL, N_("_Help") },
1868
1869         /* File menu */
1870         { "FileOpen", GTK_STOCK_OPEN, NULL, "<control>O",
1871           N_("Open an existing document"),
1872           G_CALLBACK (ev_window_cmd_file_open) },
1873         { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy..."), NULL,
1874           N_("Save the current document with a new filename"),
1875           G_CALLBACK (ev_window_cmd_save_as) },
1876         { "FilePrint", GTK_STOCK_PRINT, N_("Print..."), "<control>P",
1877           N_("Print this document"),
1878           G_CALLBACK (ev_window_cmd_file_print) },
1879         { "FileCloseWindow", GTK_STOCK_CLOSE, NULL, "<control>W",
1880           N_("Close this window"),
1881           G_CALLBACK (ev_window_cmd_file_close_window) },
1882
1883         /* Edit menu */
1884         { "EditCopy", GTK_STOCK_COPY, NULL, "<control>C",
1885           N_("Copy text from the document"),
1886           G_CALLBACK (ev_window_cmd_edit_copy) },
1887         { "EditSelectAll", NULL, N_("Select _All"), "<control>A",
1888           N_("Select the entire page"),
1889           G_CALLBACK (ev_window_cmd_edit_select_all) },
1890         { "EditFind", GTK_STOCK_FIND, NULL, "<control>F",
1891           N_("Find a word or phrase in the document"),
1892           G_CALLBACK (ev_window_cmd_edit_find) },
1893
1894         /* View menu */
1895         { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus",
1896           N_("Enlarge the document"),
1897           G_CALLBACK (ev_window_cmd_view_zoom_in) },
1898         { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus",
1899           N_("Shrink the document"),
1900           G_CALLBACK (ev_window_cmd_view_zoom_out) },
1901         { "ViewNormalSize", GTK_STOCK_ZOOM_100, NULL, "<control>0",
1902           N_("Reset the zoom level to the default value"),
1903           G_CALLBACK (ev_window_cmd_view_normal_size) },
1904
1905         /* Go menu */
1906         { "GoPreviousPage", GTK_STOCK_GO_BACK, N_("_Previous Page"), "Page_Up",
1907           N_("Go to the previous page"),
1908           G_CALLBACK (ev_window_cmd_go_previous_page) },
1909         { "GoNextPage", GTK_STOCK_GO_FORWARD, N_("_Next Page"), "Page_Down",
1910           N_("Go to the next page"),
1911           G_CALLBACK (ev_window_cmd_go_next_page) },
1912         { "GoFirstPage", GTK_STOCK_GOTO_FIRST, N_("_First Page"), "<control>Home",
1913           N_("Go to the first page"),
1914           G_CALLBACK (ev_window_cmd_go_first_page) },
1915         { "GoLastPage", GTK_STOCK_GOTO_LAST, N_("_Last Page"), "<control>End",
1916           N_("Go to the last page"),
1917           G_CALLBACK (ev_window_cmd_go_last_page) },
1918
1919         /* Help menu */
1920         { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), NULL,
1921           N_("Display help for the viewer application"),
1922           G_CALLBACK (ev_window_cmd_help_contents) },
1923
1924         { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL,
1925           N_("Display credits for the document viewer creators"),
1926           G_CALLBACK (ev_window_cmd_help_about) },
1927
1928         /* Toolbar-only */
1929         { "LeaveFullscreen", EV_STOCK_LEAVE_FULLSCREEN, N_("Leave Fullscreen"), "Escape",
1930           N_("Leave fullscreen mode"),
1931           G_CALLBACK (ev_window_cmd_leave_fullscreen) }
1932 };
1933
1934 /* Toggle items */
1935 static GtkToggleActionEntry toggle_entries[] = {
1936         /* View Menu */
1937         { "ViewToolbar", NULL, N_("_Toolbar"), "<shift><control>T",
1938           N_("Show or hide the toolbar"),
1939           G_CALLBACK (ev_window_view_toolbar_cb), TRUE },
1940         { "ViewStatusbar", NULL, N_("_Statusbar"), NULL,
1941           N_("Show or hide the statusbar"),
1942           G_CALLBACK (ev_window_view_statusbar_cb), TRUE },
1943         { "ViewSidebar", NULL, N_("Side _pane"), "F9",
1944           N_("Show or hide the side pane"),
1945           G_CALLBACK (ev_window_view_sidebar_cb), TRUE },
1946         { "ViewFullscreen", NULL, N_("_Fullscreen"), "F11",
1947           N_("Expand the window to fill the screen"),
1948           G_CALLBACK (ev_window_cmd_view_fullscreen) },
1949         { "ViewBestFit", EV_STOCK_ZOOM_PAGE, N_("_Best Fit"), NULL,
1950           N_("Make the current document fill the window"),
1951           G_CALLBACK (ev_window_cmd_view_best_fit) },
1952         { "ViewPageWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit Page _Width"), NULL,
1953           N_("Make the current document fill the window width"),
1954           G_CALLBACK (ev_window_cmd_view_page_width) },
1955 };
1956
1957 static GtkRadioActionEntry page_view_entries[] = {
1958         { "SinglePage", GTK_STOCK_DND, N_("Single"), NULL,
1959           N_("Show the document one page at a time"),
1960           PAGE_MODE_SINGLE_PAGE },
1961         { "ContinuousPage", GTK_STOCK_DND_MULTIPLE, N_("Multi"), NULL,
1962           N_("Show the full document at once"),
1963           PAGE_MODE_CONTINUOUS_PAGE }
1964 };
1965
1966 static void
1967 goto_page_cb (GtkAction *action, int page_number, EvWindow *ev_window)
1968 {
1969         EvView *view = EV_VIEW (ev_window->priv->view);
1970
1971         if (ev_view_get_page (view) != page_number) {
1972                 ev_view_set_page (view, page_number);
1973         }
1974 }
1975
1976 static void
1977 drag_data_received_cb (GtkWidget *widget, GdkDragContext *context,
1978                        gint x, gint y, GtkSelectionData *selection_data,
1979                        guint info, guint time, gpointer gdata)
1980 {
1981         GList    *uri_list = NULL;
1982
1983         uri_list = gnome_vfs_uri_list_parse ((gchar *) selection_data->data);
1984
1985         if (uri_list) {
1986                 ev_window_open_uri_list (EV_WINDOW (widget), uri_list);
1987                 
1988                 gnome_vfs_uri_list_free (uri_list);
1989
1990                 gtk_drag_finish (context, TRUE, FALSE, time);
1991         }
1992 }
1993
1994 static void
1995 register_custom_actions (EvWindow *window, GtkActionGroup *group)
1996 {
1997         GtkAction *action;
1998
1999         action = g_object_new (EV_TYPE_PAGE_ACTION,
2000                                "name", PAGE_SELECTOR_ACTION,
2001                                "label", _("Page"),
2002                                "tooltip", _("Select Page"),
2003                                NULL);
2004         g_signal_connect (action, "goto_page",
2005                           G_CALLBACK (goto_page_cb), window);
2006         gtk_action_group_add_action (group, action);
2007         g_object_unref (action);
2008 }
2009
2010 static void
2011 set_action_properties (GtkActionGroup *action_group)
2012 {
2013         GtkAction *action;
2014
2015         action = gtk_action_group_get_action (action_group, "GoPreviousPage");
2016         /*translators: this is the label for toolbar button*/
2017         g_object_set (action, "short_label", _("Previous"), NULL);
2018         g_object_set (action, "is-important", TRUE, NULL);
2019         action = gtk_action_group_get_action (action_group, "GoNextPage");
2020         /*translators: this is the label for toolbar button*/
2021         g_object_set (action, "is-important", TRUE, NULL);
2022         g_object_set (action, "short_label", _("Next"), NULL);
2023         action = gtk_action_group_get_action (action_group, "ViewPageWidth");
2024         /*translators: this is the label for toolbar button*/
2025         g_object_set (action, "short_label", _("Fit Width"), NULL);
2026         action = gtk_action_group_get_action (action_group, "ViewZoomIn");
2027
2028         action = gtk_action_group_get_action (action_group, "LeaveFullscreen");
2029         g_object_set (action, "is-important", TRUE, NULL);
2030 }
2031
2032 static void
2033 set_chrome_actions (EvWindow *window)
2034 {
2035         EvWindowPrivate *priv = window->priv;
2036         GtkActionGroup *action_group = priv->action_group;
2037         GtkAction *action;
2038
2039         action= gtk_action_group_get_action (action_group, "ViewToolbar");
2040         g_signal_handlers_block_by_func
2041                 (action, G_CALLBACK (ev_window_view_toolbar_cb), window);
2042         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
2043                                       (priv->chrome & EV_CHROME_TOOLBAR) != 0);
2044         g_signal_handlers_unblock_by_func
2045                 (action, G_CALLBACK (ev_window_view_toolbar_cb), window);
2046
2047         action= gtk_action_group_get_action (action_group, "ViewSidebar");
2048         g_signal_handlers_block_by_func
2049                 (action, G_CALLBACK (ev_window_view_sidebar_cb), window);
2050         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
2051                                       (priv->chrome & EV_CHROME_SIDEBAR) != 0);
2052         g_signal_handlers_unblock_by_func
2053                 (action, G_CALLBACK (ev_window_view_sidebar_cb), window);
2054
2055         action= gtk_action_group_get_action (action_group, "ViewStatusbar");
2056         g_signal_handlers_block_by_func
2057                 (action, G_CALLBACK (ev_window_view_statusbar_cb), window);
2058         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
2059                                       (priv->chrome & EV_CHROME_STATUSBAR) != 0);
2060         g_signal_handlers_unblock_by_func
2061                 (action, G_CALLBACK (ev_window_view_statusbar_cb), window);
2062 }
2063
2064 static EvChrome
2065 load_chrome (void)
2066 {
2067         GConfClient *client;
2068         GConfValue *value;      
2069         EvChrome chrome = EV_CHROME_NORMAL;
2070
2071         client = gconf_client_get_default ();
2072
2073         value = gconf_client_get (client, GCONF_CHROME_TOOLBAR, NULL);
2074         if (value != NULL) {
2075                 if (value->type == GCONF_VALUE_BOOL && !gconf_value_get_bool (value)) {
2076                         chrome &= ~EV_CHROME_TOOLBAR;
2077                 }
2078                 gconf_value_free (value);
2079         }
2080
2081         value = gconf_client_get (client, GCONF_CHROME_SIDEBAR, NULL);
2082         if (value != NULL) {
2083                 if (value->type == GCONF_VALUE_BOOL && !gconf_value_get_bool (value)) {
2084                         chrome &= ~EV_CHROME_SIDEBAR;
2085                 }
2086                 gconf_value_free (value);
2087         }
2088
2089         value = gconf_client_get (client, GCONF_CHROME_STATUSBAR, NULL);
2090         if (value != NULL) {
2091                 if (value->type == GCONF_VALUE_BOOL && !gconf_value_get_bool (value)) {
2092                         chrome &= ~EV_CHROME_STATUSBAR;
2093                 }
2094                 gconf_value_free (value);
2095         }
2096
2097         g_object_unref (client);
2098
2099         return chrome;
2100 }
2101
2102 static void
2103 ev_window_init (EvWindow *ev_window)
2104 {
2105         GtkActionGroup *action_group;
2106         GtkAccelGroup *accel_group;
2107         GError *error = NULL;
2108         GtkWidget *sidebar_widget, *toolbar_dock;
2109
2110         ev_window->priv = EV_WINDOW_GET_PRIVATE (ev_window);
2111
2112         ev_window->priv->page_mode = PAGE_MODE_SINGLE_PAGE;
2113         update_window_title (NULL, NULL, ev_window);
2114
2115         ev_window->priv->main_box = gtk_vbox_new (FALSE, 0);
2116         gtk_container_add (GTK_CONTAINER (ev_window), ev_window->priv->main_box);
2117         gtk_widget_show (ev_window->priv->main_box);
2118
2119         action_group = gtk_action_group_new ("MenuActions");
2120         ev_window->priv->action_group = action_group;
2121         gtk_action_group_set_translation_domain (action_group, NULL);
2122         gtk_action_group_add_actions (action_group, entries,
2123                                       G_N_ELEMENTS (entries), ev_window);
2124         gtk_action_group_add_toggle_actions (action_group, toggle_entries,
2125                                              G_N_ELEMENTS (toggle_entries),
2126                                              ev_window);
2127         gtk_action_group_add_radio_actions (action_group, page_view_entries,
2128                                             G_N_ELEMENTS (page_view_entries),
2129                                             ev_window->priv->page_mode,
2130                                             G_CALLBACK (ev_window_page_mode_cb),
2131                                             ev_window);
2132         set_action_properties (action_group);
2133         register_custom_actions (ev_window, action_group);
2134
2135         ev_window->priv->ui_manager = gtk_ui_manager_new ();
2136         gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
2137                                             action_group, 0);
2138
2139         accel_group =
2140                 gtk_ui_manager_get_accel_group (ev_window->priv->ui_manager);
2141         gtk_window_add_accel_group (GTK_WINDOW (ev_window), accel_group);
2142
2143         g_signal_connect (ev_window->priv->ui_manager, "connect_proxy",
2144                           G_CALLBACK (connect_proxy_cb), ev_window);
2145         g_signal_connect (ev_window->priv->ui_manager, "disconnect_proxy",
2146                           G_CALLBACK (disconnect_proxy_cb), ev_window);
2147
2148         if (!gtk_ui_manager_add_ui_from_file (ev_window->priv->ui_manager,
2149                                               DATADIR"/evince-ui.xml",
2150                                               &error)) {
2151                 g_message ("building menus failed: %s", error->message);
2152                 g_error_free (error);
2153         }
2154
2155         ev_window->priv->menubar =
2156                  gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
2157                                             "/MainMenu");
2158         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box),
2159                             ev_window->priv->menubar,
2160                             FALSE, FALSE, 0);
2161
2162         /* This sucks, but there is no way to have a draw=no, expand=true separator
2163          * in a GtkUIManager-built toolbar. So, just add another toolbar.
2164          * See gtk+ bug 166489.
2165          */
2166         toolbar_dock = ev_window->priv->toolbar_dock = gtk_hbox_new (FALSE, 0);
2167         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), toolbar_dock,
2168                             FALSE, FALSE, 0);
2169         gtk_widget_show (toolbar_dock);
2170
2171         ev_window->priv->toolbar =
2172                 gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
2173                                            "/ToolBar");
2174         gtk_box_pack_start (GTK_BOX (toolbar_dock), ev_window->priv->toolbar,
2175                             TRUE, TRUE, 0);
2176         gtk_widget_show (ev_window->priv->toolbar);
2177
2178         ev_window->priv->fullscreen_toolbar =
2179                 gtk_ui_manager_get_widget (ev_window->priv->ui_manager, "/LeaveFullscreenToolbar");
2180         gtk_toolbar_set_show_arrow (GTK_TOOLBAR (ev_window->priv->fullscreen_toolbar), TRUE);
2181         gtk_toolbar_set_style (GTK_TOOLBAR (ev_window->priv->fullscreen_toolbar), GTK_TOOLBAR_BOTH_HORIZ);
2182
2183         /* Add the main area */
2184         ev_window->priv->hpaned = gtk_hpaned_new ();
2185         gtk_widget_show (ev_window->priv->hpaned);
2186         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), ev_window->priv->hpaned,
2187                             TRUE, TRUE, 0);
2188
2189         ev_window->priv->sidebar = ev_sidebar_new ();
2190         gtk_paned_add1 (GTK_PANED (ev_window->priv->hpaned),
2191                         ev_window->priv->sidebar);
2192
2193         /* Stub sidebar, for now */
2194         sidebar_widget = ev_sidebar_links_new ();
2195         gtk_widget_show (sidebar_widget);
2196         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
2197                              "index",
2198                              _("Index"),
2199                              sidebar_widget);
2200
2201         ev_window->priv->thumbs_sidebar = ev_sidebar_thumbnails_new ();
2202         gtk_widget_show (ev_window->priv->thumbs_sidebar);
2203         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
2204                              "thumbnails",
2205                              _("Thumbnails"),
2206                              ev_window->priv->thumbs_sidebar);
2207
2208         ev_window->priv->scrolled_window =
2209                 GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
2210                                           "shadow-type", GTK_SHADOW_IN,
2211                                           NULL));
2212         gtk_widget_show (ev_window->priv->scrolled_window);
2213
2214         gtk_paned_add2 (GTK_PANED (ev_window->priv->hpaned),
2215                         ev_window->priv->scrolled_window);
2216
2217         ev_window->priv->view = ev_view_new ();
2218         //ev_window->priv->page_view = ev_page_view_new ();
2219         ev_window->priv->password_view = ev_password_view_new ();
2220         g_signal_connect_swapped (ev_window->priv->password_view,
2221                                   "unlock",
2222                                   G_CALLBACK (ev_window_popup_password_dialog),
2223                                   ev_window);
2224         gtk_widget_show (ev_window->priv->view);
2225         //gtk_widget_show (ev_window->priv->page_view);
2226         gtk_widget_show (ev_window->priv->password_view);
2227
2228         /* We own a ref on these widgets, as we can swap them in and out */
2229         g_object_ref (ev_window->priv->view);
2230         //g_object_ref (ev_window->priv->page_view);
2231         g_object_ref (ev_window->priv->password_view);
2232
2233         gtk_container_add (GTK_CONTAINER (ev_window->priv->scrolled_window),
2234                            ev_window->priv->view);
2235         g_signal_connect (ev_window->priv->view,
2236                           "page-changed",
2237                           G_CALLBACK (view_page_changed_cb),
2238                           ev_window);
2239         g_signal_connect (ev_window->priv->view,
2240                           "notify::find-status",
2241                           G_CALLBACK (view_find_status_changed_cb),
2242                           ev_window);
2243         g_signal_connect (ev_window->priv->view,
2244                           "notify::status",
2245                           G_CALLBACK (view_status_changed_cb),
2246                           ev_window);
2247
2248         ev_window->priv->statusbar = gtk_statusbar_new ();
2249         gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
2250                           ev_window->priv->statusbar,
2251                           FALSE, TRUE, 0);
2252         ev_window->priv->help_message_cid = gtk_statusbar_get_context_id
2253                 (GTK_STATUSBAR (ev_window->priv->statusbar), "help_message");
2254         ev_window->priv->view_message_cid = gtk_statusbar_get_context_id
2255                 (GTK_STATUSBAR (ev_window->priv->statusbar), "view_message");
2256
2257         ev_window->priv->find_bar = egg_find_bar_new ();
2258         gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
2259                           ev_window->priv->find_bar,
2260                           FALSE, TRUE, 0);
2261
2262         ev_window->priv->chrome = load_chrome ();
2263         set_chrome_actions (ev_window);
2264         update_chrome_visibility (ev_window);
2265
2266         /* Connect to find bar signals */
2267         g_signal_connect (ev_window->priv->find_bar,
2268                           "previous",
2269                           G_CALLBACK (find_bar_previous_cb),
2270                           ev_window);
2271         g_signal_connect (ev_window->priv->find_bar,
2272                           "next",
2273                           G_CALLBACK (find_bar_next_cb),
2274                           ev_window);
2275         g_signal_connect (ev_window->priv->find_bar,
2276                           "close",
2277                           G_CALLBACK (find_bar_close_cb),
2278                           ev_window);
2279         g_signal_connect (ev_window->priv->find_bar,
2280                           "notify::search-string",
2281                           G_CALLBACK (find_bar_search_changed_cb),
2282                           ev_window);
2283         g_signal_connect (ev_window->priv->find_bar,
2284                           "notify::case-sensitive",
2285                           G_CALLBACK (find_bar_search_changed_cb),
2286                           ev_window);
2287         g_signal_connect (ev_window->priv->find_bar,
2288                           "notify::visible",
2289                           G_CALLBACK (find_bar_search_changed_cb),
2290                           ev_window);
2291
2292         g_signal_connect (ev_window, "window-state-event",
2293                           G_CALLBACK (ev_window_state_event_cb),
2294                           ev_window);
2295
2296         /* Give focus to the scrolled window */
2297         gtk_widget_grab_focus (ev_window->priv->scrolled_window);
2298
2299         /* Drag and Drop */
2300         gtk_drag_dest_unset (GTK_WIDGET (ev_window));
2301         gtk_drag_dest_set (GTK_WIDGET (ev_window), GTK_DEST_DEFAULT_ALL, ev_drop_types,
2302                            sizeof (ev_drop_types) / sizeof (ev_drop_types[0]),
2303                            GDK_ACTION_COPY);
2304         g_signal_connect (G_OBJECT (ev_window), "drag_data_received",
2305                           G_CALLBACK (drag_data_received_cb), NULL);
2306
2307         /* Set it to something random to force a change */
2308         ev_window->priv->sizing_mode = EV_SIZING_FREE;
2309         ev_window_set_sizing_mode (ev_window, EV_SIZING_BEST_FIT);
2310         update_action_sensitivity (ev_window);
2311 }