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