]> www.fi.muni.cz Git - evince.git/blob - shell/ev-window.c
65d05fd4fe12c3c947452dd246de5eef41d97ae0
[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-window-title.h"
33 #include "ev-page-action.h"
34 #include "ev-sidebar.h"
35 #include "ev-sidebar-links.h"
36 #include "ev-sidebar-attachments.h"
37 #include "ev-sidebar-thumbnails.h"
38 #include "ev-view.h"
39 #include "ev-password.h"
40 #include "ev-password-view.h"
41 #include "ev-properties-dialog.h"
42 #include "ev-ps-exporter.h"
43 #include "ev-document-thumbnails.h"
44 #include "ev-document-links.h"
45 #include "ev-document-fonts.h"
46 #include "ev-document-find.h"
47 #include "ev-document-security.h"
48 #include "ev-document-factory.h"
49 #include "ev-job-queue.h"
50 #include "ev-jobs.h"
51 #include "ev-sidebar-page.h"
52 #include "eggfindbar.h"
53 #include "egg-recent-view-uimanager.h"
54 #include "egg-recent-view.h"
55 #include "egg-toolbar-editor.h"
56 #include "egg-editable-toolbar.h"
57 #include "egg-recent-model.h"
58 #include "egg-toolbars-model.h"
59 #include "ephy-zoom.h"
60 #include "ephy-zoom-action.h"
61 #include "ev-application.h"
62 #include "ev-stock-icons.h"
63 #include "ev-metadata-manager.h"
64 #include "ev-file-helpers.h"
65 #include "ev-utils.h"
66 #include "ev-debug.h"
67
68 #ifdef WITH_GNOME_PRINT
69 #include "ev-print-job.h"
70 #include <libgnomeprintui/gnome-print-dialog.h>
71 #endif
72
73 #ifdef WITH_GTK_PRINT
74 #include <gtk/gtkprintunixdialog.h>
75 #endif
76
77 #include <poppler.h>
78
79 #include <glib/gi18n.h>
80 #include <gtk/gtk.h>
81 #include <gnome.h>
82 #include <libgnomevfs/gnome-vfs-utils.h>
83 #include <gconf/gconf-client.h>
84
85 #include <string.h>
86
87 typedef enum {
88         PAGE_MODE_DOCUMENT,
89         PAGE_MODE_PASSWORD
90 } EvWindowPageMode;
91
92 typedef enum {
93         EV_CHROME_MENUBAR       = 1 << 0,
94         EV_CHROME_TOOLBAR       = 1 << 1,
95         EV_CHROME_FINDBAR       = 1 << 2,
96         EV_CHROME_RAISE_TOOLBAR = 1 << 3,
97         EV_CHROME_FULLSCREEN_TOOLBAR    = 1 << 4,
98         EV_CHROME_SIDEBAR       = 1 << 5,
99         EV_CHROME_NORMAL        = EV_CHROME_MENUBAR | EV_CHROME_TOOLBAR | EV_CHROME_SIDEBAR
100 } EvChrome;
101
102 struct _EvWindowPrivate {
103         /* UI */
104         EvChrome chrome;
105
106         GtkWidget *main_box;
107         GtkWidget *menubar;
108         GtkWidget *toolbar_dock;
109         GtkWidget *toolbar;
110         GtkWidget *hpaned;
111         GtkWidget *sidebar;
112         GtkWidget *find_bar;
113         GtkWidget *scrolled_window;
114         GtkWidget *view;
115         GtkWidget *password_view;
116         GtkWidget *sidebar_thumbs;
117         GtkWidget *sidebar_links;
118         GtkWidget *sidebar_attachments;
119
120         /* Dialogs */
121         GtkWidget *properties;
122 #ifdef WITH_PRINT
123         GtkWidget *print_dialog;
124 #endif
125         GtkWidget *password_dialog;
126
127         /* UI Builders */
128         GtkActionGroup *action_group;
129         GtkActionGroup *view_popup_action_group;
130         GtkActionGroup *attachment_popup_action_group;
131         GtkUIManager   *ui_manager;
132
133         /* Fullscreen mode */
134         GtkWidget *fullscreen_toolbar;
135         GtkWidget *fullscreen_popup;
136         guint      fullscreen_timeout_id;
137         
138         /* Popup link */
139         GtkWidget *view_popup;
140         EvLink    *link;
141
142         /* Popup attachment */
143         GtkWidget    *attachment_popup;
144         GList        *attach_list;
145
146         /* Document */
147         char *uri;
148         char *local_uri;
149         EvLinkDest *dest;
150         
151         EvDocument *document;
152
153         EvPageCache *page_cache;
154         EvWindowPageMode page_mode;
155         EvWindowTitle *title;
156         EggRecentViewUIManager *recent_view;
157
158         EvJob *xfer_job;
159 #ifdef WITH_GNOME_PRINT
160         GnomePrintJob *print_job;
161 #endif
162
163 #ifdef WITH_GTK_PRINT
164         EvJob            *print_job;
165         GtkPrintJob      *gtk_print_job;
166         GtkPrinter       *printer;
167         GtkPrintSettings *print_settings;
168         GtkPageSetup     *print_page_setup;
169 #endif
170 };
171
172 static const GtkTargetEntry ev_drop_types[] = {
173         { "text/uri-list", 0, 0 }
174 };
175
176
177 #define EV_WINDOW_GET_PRIVATE(object) \
178         (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_WINDOW, EvWindowPrivate))
179
180 #define PAGE_SELECTOR_ACTION    "PageSelector"
181 #define ZOOM_CONTROL_ACTION     "ViewZoom"
182
183 #define GCONF_OVERRIDE_RESTRICTIONS "/apps/evince/override_restrictions"
184 #define GCONF_LOCKDOWN_SAVE         "/desktop/gnome/lockdown/disable_save_to_disk"
185 #define GCONF_LOCKDOWN_PRINT        "/desktop/gnome/lockdown/disable_printing"
186
187 #define FULLSCREEN_TIMEOUT 5 * 1000
188
189 #define SIDEBAR_DEFAULT_SIZE    132
190 #define LINKS_SIDEBAR_ID "links"
191 #define THUMBNAILS_SIDEBAR_ID "thumbnails"
192 #define ATTACHMENTS_SIDEBAR_ID "attachments"
193
194 static void     ev_window_update_actions                (EvWindow *ev_window);
195 static void     ev_window_update_fullscreen_popup       (EvWindow         *window);
196 static void     ev_window_sidebar_visibility_changed_cb (EvSidebar        *ev_sidebar,
197                                                          GParamSpec       *pspec,
198                                                          EvWindow         *ev_window);
199 static void     ev_window_set_page_mode                 (EvWindow         *window,
200                                                          EvWindowPageMode  page_mode);
201 static void     ev_window_xfer_job_cb                   (EvJobXfer        *job,
202                                                          gpointer          data);
203 static void     ev_window_print_job_cb                  (EvJobPrint       *job,
204                                                          EvWindow         *window);
205 static void     ev_window_sizing_mode_changed_cb        (EvView           *view,
206                                                          GParamSpec       *pspec,
207                                                          EvWindow         *ev_window);
208 static void     ev_window_zoom_changed_cb               (EvView           *view,
209                                                          GParamSpec       *pspec,
210                                                          EvWindow         *ev_window);
211 static void     ev_window_add_recent                    (EvWindow         *window,
212                                                          const char       *filename);
213 static void     ev_window_run_fullscreen                (EvWindow         *window);
214 static void     ev_window_stop_fullscreen               (EvWindow         *window);
215 static void     ev_window_cmd_view_fullscreen           (GtkAction        *action,
216                                                          EvWindow         *window);
217 static void     ev_window_run_presentation              (EvWindow         *window);
218 static void     ev_window_stop_presentation             (EvWindow         *window);
219 static void     ev_window_cmd_view_presentation         (GtkAction        *action,
220                                                          EvWindow         *window);
221 static void     ev_window_run_preview                   (EvWindow         *window);
222 static void     ev_view_popup_cmd_open_link             (GtkAction        *action,
223                                                          EvWindow         *window);
224 static void     ev_view_popup_cmd_copy_link_address     (GtkAction        *action,
225                                                          EvWindow         *window);
226 static void     ev_attachment_popup_cmd_open_attachment (GtkAction        *action,
227                                                          EvWindow *window);
228 static void     ev_attachment_popup_cmd_save_attachment_as (GtkAction *action, 
229                                                          EvWindow *window);
230 static void     ev_window_cmd_view_best_fit             (GtkAction        *action, 
231                                                          EvWindow         *ev_window);
232 static void     ev_window_cmd_view_page_width           (GtkAction        *action, 
233                                                          EvWindow         *ev_window);
234 static void     fullscreen_set_timeout                  (EvWindow *window);
235 static gboolean fullscreen_motion_notify_cb             (GtkWidget *widget,
236                                                          GdkEventMotion *event,
237                                                          gpointer user_data);
238 static gboolean fullscreen_leave_notify_cb              (GtkWidget *widget,
239                                                          GdkEventCrossing *event,
240                                                          gpointer user_data);
241
242 G_DEFINE_TYPE (EvWindow, ev_window, GTK_TYPE_WINDOW)
243
244 static void
245 ev_window_set_action_sensitive (EvWindow   *ev_window,
246                                 const char *name,
247                                 gboolean    sensitive)
248 {
249         GtkAction *action = gtk_action_group_get_action (ev_window->priv->action_group,
250                                                          name);
251         gtk_action_set_sensitive (action, sensitive);
252 }
253
254
255 static void
256 ev_window_setup_action_sensitivity (EvWindow *ev_window)
257 {
258         EvDocument *document = ev_window->priv->document;
259         const EvDocumentInfo *info = NULL;
260
261         gboolean has_document = FALSE;
262         gboolean ok_to_print = TRUE;
263         gboolean ok_to_copy = TRUE;
264         gboolean has_properties = TRUE;
265         gboolean override_restrictions = FALSE;
266         gboolean can_get_text = FALSE;
267         gboolean has_pages = FALSE;
268         gboolean can_find = FALSE;
269
270         GConfClient *client;
271
272         if (document) {
273                 has_document = TRUE;
274                 info = ev_page_cache_get_info (ev_window->priv->page_cache);
275         }
276
277         if (has_document && ev_window->priv->page_cache) {
278                 has_pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache) > 0;
279         }
280
281         if (!info || info->fields_mask == 0) {
282                 has_properties = FALSE;
283         }
284
285         if (has_document && ev_document_can_get_text (document)) {
286                 can_get_text = TRUE;
287         }
288         
289         if (has_document && EV_IS_DOCUMENT_FIND (document)) {
290                 can_find = TRUE;
291         }
292
293         client = gconf_client_get_default ();
294         override_restrictions = gconf_client_get_bool (client, 
295                                                        GCONF_OVERRIDE_RESTRICTIONS, 
296                                                        NULL);
297         if (!override_restrictions && info && info->fields_mask & EV_DOCUMENT_INFO_PERMISSIONS) {
298                 ok_to_print = (info->permissions & EV_DOCUMENT_PERMISSIONS_OK_TO_PRINT);
299                 ok_to_copy = (info->permissions & EV_DOCUMENT_PERMISSIONS_OK_TO_COPY);
300         }
301
302         if (has_document && !EV_IS_PS_EXPORTER(document))
303                 ok_to_print = FALSE;
304
305         
306         if (gconf_client_get_bool (client, GCONF_LOCKDOWN_SAVE, NULL)) {
307                 ok_to_copy = FALSE;
308         }
309
310         if (gconf_client_get_bool (client, GCONF_LOCKDOWN_PRINT, NULL)) {
311                 ok_to_print = FALSE;
312         }
313 #ifndef WITH_PRINT
314         ok_to_print = FALSE;
315 #endif
316         g_object_unref (client);
317
318
319         /* File menu */
320         ev_window_set_action_sensitive (ev_window, "FileSaveAs", has_document && ok_to_copy);
321         ev_window_set_action_sensitive (ev_window, "FilePrint", has_pages && ok_to_print);
322         ev_window_set_action_sensitive (ev_window, "FileProperties", has_document && has_properties);
323
324         /* Edit menu */
325         ev_window_set_action_sensitive (ev_window, "EditSelectAll", has_pages && can_get_text);
326         ev_window_set_action_sensitive (ev_window, "EditFind",
327                               has_pages && EV_IS_DOCUMENT_FIND (document));
328         ev_window_set_action_sensitive (ev_window, "Slash",
329                               has_pages && EV_IS_DOCUMENT_FIND (document));
330         ev_window_set_action_sensitive (ev_window, "EditRotateLeft", has_pages);
331         ev_window_set_action_sensitive (ev_window, "EditRotateRight", has_pages);
332
333         /* View menu */
334         ev_window_set_action_sensitive (ev_window, "ViewContinuous", has_pages);
335         ev_window_set_action_sensitive (ev_window, "ViewDual", has_pages);
336         ev_window_set_action_sensitive (ev_window, "ViewBestFit", has_pages);
337         ev_window_set_action_sensitive (ev_window, "ViewPageWidth", has_pages);
338         ev_window_set_action_sensitive (ev_window, "ViewReload", has_pages);
339
340         /* Toolbar-specific actions: */
341         ev_window_set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, has_pages);
342         ev_window_set_action_sensitive (ev_window, ZOOM_CONTROL_ACTION,  has_pages);
343
344         ev_window_update_actions (ev_window);
345 }
346
347 static void
348 ev_window_update_actions (EvWindow *ev_window)
349 {
350         EvView *view = EV_VIEW (ev_window->priv->view);
351         int n_pages = 0, page = -1;
352         gboolean has_pages = FALSE;
353
354         if (ev_window->priv->document && ev_window->priv->page_cache) {
355                 page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
356                 n_pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache);
357                 has_pages = n_pages > 0;
358         }
359
360         ev_window_set_action_sensitive (ev_window, "EditCopy", has_pages && ev_view_get_has_selection (view));
361         ev_window_set_action_sensitive (ev_window, "EditFindNext",
362                               ev_view_can_find_next (view));
363         ev_window_set_action_sensitive (ev_window, "EditFindPrevious",
364                               ev_view_can_find_previous (view));
365
366         ev_window_set_action_sensitive (ev_window, "ViewZoomIn",
367                               has_pages && ev_view_can_zoom_in (view));
368         ev_window_set_action_sensitive (ev_window, "ViewZoomOut",
369                               has_pages && ev_view_can_zoom_out (view));
370
371         /* Go menu */
372         if (has_pages) {
373                 ev_window_set_action_sensitive (ev_window, "GoPreviousPage", page > 0);
374                 ev_window_set_action_sensitive (ev_window, "GoNextPage", page < n_pages - 1);
375                 ev_window_set_action_sensitive (ev_window, "GoFirstPage", page > 0);
376                 ev_window_set_action_sensitive (ev_window, "GoLastPage", page < n_pages - 1);
377         } else {
378                 ev_window_set_action_sensitive (ev_window, "GoFirstPage", FALSE);
379                 ev_window_set_action_sensitive (ev_window, "GoPreviousPage", FALSE);
380                 ev_window_set_action_sensitive (ev_window, "GoNextPage", FALSE);
381                 ev_window_set_action_sensitive (ev_window, "GoLastPage", FALSE);
382         }
383
384         if (has_pages &&
385             ev_view_get_sizing_mode (view) != EV_SIZING_FIT_WIDTH &&
386             ev_view_get_sizing_mode (view) != EV_SIZING_BEST_FIT) {
387                 GtkAction *action;
388                 float      zoom;
389                 float      real_zoom;
390
391                 action = gtk_action_group_get_action (ev_window->priv->action_group, 
392                                                       ZOOM_CONTROL_ACTION);
393
394                 real_zoom = ev_view_get_zoom (EV_VIEW (ev_window->priv->view));
395                 zoom = ephy_zoom_get_nearest_zoom_level (real_zoom);
396
397                 ephy_zoom_action_set_zoom_level (EPHY_ZOOM_ACTION (action), zoom);
398         }
399 }
400
401 static void
402 ev_window_set_view_accels_sensitivity (EvWindow *window, gboolean sensitive)
403 {
404         if (window->priv->action_group) {
405                 ev_window_set_action_sensitive (window, "PageDown", sensitive);
406                 ev_window_set_action_sensitive (window, "PageUp", sensitive);
407                 ev_window_set_action_sensitive (window, "Space", sensitive);
408                 ev_window_set_action_sensitive (window, "ShiftSpace", sensitive);
409                 ev_window_set_action_sensitive (window, "BackSpace", sensitive);
410                 ev_window_set_action_sensitive (window, "ShiftBackSpace", sensitive);
411                 ev_window_set_action_sensitive (window, "Return", sensitive);
412                 ev_window_set_action_sensitive (window, "ShiftReturn", sensitive);
413                 ev_window_set_action_sensitive (window, "Slash", sensitive);
414                 ev_window_set_action_sensitive (window, "Plus", sensitive);
415                 ev_window_set_action_sensitive (window, "Minus", sensitive);
416                 ev_window_set_action_sensitive (window, "KpPlus", sensitive);
417                 ev_window_set_action_sensitive (window, "KpMinus", sensitive);
418                 ev_window_set_action_sensitive (window, "Equal", sensitive);
419         }
420 }
421
422 static void
423 set_widget_visibility (GtkWidget *widget, gboolean visible)
424 {
425         g_assert (GTK_IS_WIDGET (widget));
426         
427         if (visible)
428                 gtk_widget_show (widget);
429         else
430                 gtk_widget_hide (widget);
431 }
432
433 static void
434 update_chrome_visibility (EvWindow *window)
435 {
436         EvWindowPrivate *priv = window->priv;
437         gboolean menubar, toolbar, findbar, fullscreen_toolbar, sidebar;
438         gboolean fullscreen_mode, presentation, fullscreen;
439
440         presentation = ev_view_get_presentation (EV_VIEW (priv->view));
441         fullscreen = ev_view_get_fullscreen (EV_VIEW (priv->view));
442         fullscreen_mode = fullscreen || presentation;
443
444         menubar = (priv->chrome & EV_CHROME_MENUBAR) != 0 && !fullscreen_mode;
445         toolbar = ((priv->chrome & EV_CHROME_TOOLBAR) != 0  || 
446                    (priv->chrome & EV_CHROME_RAISE_TOOLBAR) != 0) && !fullscreen_mode;
447         fullscreen_toolbar = ((priv->chrome & EV_CHROME_FULLSCREEN_TOOLBAR) != 0 || 
448                               (priv->chrome & EV_CHROME_RAISE_TOOLBAR) != 0) && fullscreen;
449         findbar = (priv->chrome & EV_CHROME_FINDBAR) != 0;
450         sidebar = (priv->chrome & EV_CHROME_SIDEBAR) != 0 && !fullscreen_mode;
451
452         set_widget_visibility (priv->menubar, menubar); 
453         set_widget_visibility (priv->toolbar_dock, toolbar);
454         set_widget_visibility (priv->find_bar, findbar);
455         set_widget_visibility (priv->sidebar, sidebar);
456
457         ev_window_set_action_sensitive (window, "EditToolbar", toolbar);
458         gtk_widget_set_sensitive (priv->menubar, menubar);
459
460         if (priv->fullscreen_popup != NULL) {
461                 set_widget_visibility (priv->fullscreen_toolbar, fullscreen_toolbar);
462                 set_widget_visibility (priv->fullscreen_popup, fullscreen_toolbar);
463         }
464 }
465
466 static void
467 update_chrome_flag (EvWindow *window, EvChrome flag, gboolean active)
468 {
469         EvWindowPrivate *priv = window->priv;
470         
471         if (active) {
472                 priv->chrome |= flag;
473         } else {
474                 priv->chrome &= ~flag;
475         }
476
477         update_chrome_visibility (window);
478 }
479
480 static void
481 update_sizing_buttons (EvWindow *window)
482 {
483         GtkActionGroup *action_group = window->priv->action_group;
484         GtkAction *action;
485         gboolean best_fit, page_width;
486         EvSizingMode sizing_mode;
487
488         if (window->priv->view == NULL)
489                 return;
490
491         g_object_get (window->priv->view,
492                       "sizing_mode", &sizing_mode,
493                       NULL);
494
495         switch (sizing_mode) {
496                 case EV_SIZING_BEST_FIT:
497                         best_fit = TRUE;
498                         page_width = FALSE;
499                         break;
500                 case EV_SIZING_FIT_WIDTH:
501                         best_fit = FALSE;
502                         page_width = TRUE;
503                         break;
504                 default:
505                         best_fit = page_width = FALSE;
506                         break;
507         }
508
509         action = gtk_action_group_get_action (action_group, "ViewBestFit");
510         g_signal_handlers_block_by_func
511                 (action, G_CALLBACK (ev_window_cmd_view_best_fit), window);
512         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), best_fit);
513         g_signal_handlers_unblock_by_func
514                 (action, G_CALLBACK (ev_window_cmd_view_best_fit), window);
515
516         action = gtk_action_group_get_action (action_group, "ViewPageWidth");   
517         g_signal_handlers_block_by_func
518                 (action, G_CALLBACK (ev_window_cmd_view_page_width), window);
519         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), page_width);
520         g_signal_handlers_unblock_by_func
521                 (action, G_CALLBACK (ev_window_cmd_view_page_width), window);
522
523         action = gtk_action_group_get_action (window->priv->action_group, 
524                                               ZOOM_CONTROL_ACTION);     
525         if (best_fit) {
526                 ephy_zoom_action_set_zoom_level (EPHY_ZOOM_ACTION (action), 
527                                                  EPHY_ZOOM_BEST_FIT);
528         } else if (page_width) {
529                 ephy_zoom_action_set_zoom_level (EPHY_ZOOM_ACTION (action), 
530                                                  EPHY_ZOOM_FIT_WIDTH);
531         }
532 }
533
534 gboolean
535 ev_window_is_empty (const EvWindow *ev_window)
536 {
537         g_return_val_if_fail (EV_IS_WINDOW (ev_window), FALSE);
538
539         return (ev_window->priv->document == NULL) && 
540                 (ev_window->priv->xfer_job == NULL);
541 }
542
543 static void
544 ev_window_error_dialog_response_cb (GtkWidget *dialog,
545                                    gint       response_id,
546                                    EvWindow  *ev_window)
547 {
548         gtk_widget_destroy (dialog);
549 }
550
551 static void
552 ev_window_error_dialog (GtkWindow *window, const gchar *msg, GError *error)
553 {
554         GtkWidget *dialog;
555
556         dialog = gtk_message_dialog_new (GTK_WINDOW (window),
557                                          GTK_DIALOG_DESTROY_WITH_PARENT,
558                                          GTK_MESSAGE_ERROR,
559                                          GTK_BUTTONS_CLOSE,
560                                          msg);
561         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
562                                                   "%s", error->message);
563         g_signal_connect (dialog, "response",
564                           G_CALLBACK (ev_window_error_dialog_response_cb),
565                            window);
566         gtk_widget_show (dialog);
567 }
568
569 static void
570 find_changed_cb (EvDocument *document, int page, EvWindow *ev_window)
571 {
572         ev_window_update_actions (ev_window);
573 }
574
575 static void
576 page_changed_cb (EvPageCache *page_cache,
577                  gint         page,
578                  EvWindow    *ev_window)
579 {
580         ev_window_update_actions (ev_window);
581
582         if (!ev_window_is_empty (ev_window))
583                 ev_metadata_manager_set_int (ev_window->priv->uri, "page", page);
584 }
585
586 static void
587 update_document_mode (EvWindow *window, EvDocumentMode mode)
588 {
589         if (mode == EV_DOCUMENT_MODE_PRESENTATION) {
590                 ev_window_run_presentation (window);
591         }
592         else if (mode == EV_DOCUMENT_MODE_FULL_SCREEN) {
593                 ev_window_run_fullscreen (window);
594         }
595 }
596
597 static void
598 setup_document_from_metadata (EvWindow *window)
599 {
600         char *uri = window->priv->uri;
601         GValue page = { 0, };
602         gint new_page;
603
604         if (uri && ev_metadata_manager_get (uri, "page", &page, TRUE)) {
605                 new_page = CLAMP (g_value_get_int (&page), 0, ev_page_cache_get_n_pages (window->priv->page_cache) - 1);
606                 ev_page_cache_set_current_page (window->priv->page_cache,
607                                                 new_page);
608         }
609 }
610
611 static void
612 setup_chrome_from_metadata (EvWindow *window)
613 {
614         EvChrome chrome = EV_CHROME_NORMAL;
615         GValue show_toolbar = { 0, };
616
617         if (ev_metadata_manager_get (NULL, "show_toolbar", &show_toolbar, FALSE)) {
618                 if (!g_value_get_boolean (&show_toolbar))
619                         chrome &= ~EV_CHROME_TOOLBAR;
620         }
621         window->priv->chrome = chrome;
622 }
623
624 static void
625 setup_sidebar_from_metadata (EvWindow *window, EvDocument *document)
626 {
627         char *uri = window->priv->uri;
628         GtkWidget *sidebar = window->priv->sidebar;
629         GtkWidget *links = window->priv->sidebar_links;
630         GtkWidget *thumbs = window->priv->sidebar_thumbs;
631         GtkWidget *attachments = window->priv->sidebar_attachments;
632         GValue sidebar_size = { 0, };
633         GValue sidebar_page = { 0, };
634         GValue sidebar_visibility = { 0, };
635
636         if (ev_metadata_manager_get (uri, "sidebar_size", &sidebar_size, FALSE)) {
637                 gtk_paned_set_position (GTK_PANED (window->priv->hpaned),
638                                         g_value_get_int (&sidebar_size));
639         }
640         
641         if (document && ev_metadata_manager_get (uri, "sidebar_page", &sidebar_page, FALSE)) {
642                 const char *page_id = g_value_get_string (&sidebar_page);
643
644                 if (strcmp (page_id, LINKS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) {
645                         ev_sidebar_set_page (EV_SIDEBAR (sidebar), links);
646                 } else if (strcmp (page_id, THUMBNAILS_SIDEBAR_ID) && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) {
647                         ev_sidebar_set_page (EV_SIDEBAR (sidebar), thumbs);
648                 } else if (strcmp (page_id, ATTACHMENTS_SIDEBAR_ID) && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) {
649                         ev_sidebar_set_page (EV_SIDEBAR (sidebar), thumbs);
650                 }
651         } else if (document && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) {
652                 ev_sidebar_set_page (EV_SIDEBAR (sidebar), links);
653         }
654
655         if (ev_metadata_manager_get (uri, "sidebar_visibility", &sidebar_visibility, FALSE)) {
656                 update_chrome_flag (window, EV_CHROME_SIDEBAR, g_value_get_boolean (&sidebar_visibility));
657         }
658 }
659
660 static void
661 setup_view_from_metadata (EvWindow *window)
662 {
663         EvView *view = EV_VIEW (window->priv->view);
664         char *uri = window->priv->uri;
665         GEnumValue *enum_value;
666         GValue width = { 0, };
667         GValue height = { 0, };
668         GValue maximized = { 0, };
669         GValue x = { 0, };
670         GValue y = { 0, };
671         GValue sizing_mode = { 0, };
672         GValue zoom = { 0, };
673         GValue continuous = { 0, };
674         GValue dual_page = { 0, };
675         GValue presentation = { 0, };
676         GValue fullscreen = { 0, };
677         GValue rotation = { 0, };
678         gboolean restore_size = TRUE;
679
680         /* Window size */
681
682         if (ev_metadata_manager_get (uri, "window_maximized", &maximized, FALSE)) {
683                 if (g_value_get_boolean (&maximized)) {
684                         gtk_window_maximize (GTK_WINDOW (window));
685                         restore_size = FALSE;
686                 } else {
687                         gtk_window_unmaximize (GTK_WINDOW (window));
688                 }
689         }
690
691         if (restore_size &&
692             ev_metadata_manager_get (uri, "window_width", &width, TRUE) &&
693             ev_metadata_manager_get (uri, "window_height", &height, TRUE)) {
694                 gtk_window_resize (GTK_WINDOW (window),
695                                    g_value_get_int (&width),
696                                    g_value_get_int (&height));
697         }
698         if (restore_size &&
699             ev_metadata_manager_get (uri, "window_x", &x, TRUE) &&
700             ev_metadata_manager_get (uri, "window_y", &y, TRUE)) {
701                 gtk_window_move (GTK_WINDOW (window), g_value_get_int (&x),
702                                  g_value_get_int (&y));
703         }
704
705         /* Sizing mode */
706         if (ev_metadata_manager_get (uri, "sizing_mode", &sizing_mode, FALSE)) {
707                 enum_value = g_enum_get_value_by_nick
708                         (EV_SIZING_MODE_CLASS, g_value_get_string (&sizing_mode));
709                 g_value_unset (&sizing_mode);
710                 ev_view_set_sizing_mode (view, enum_value->value);
711         }
712
713         /* Zoom */
714         if (ev_metadata_manager_get (uri, "zoom", &zoom, FALSE) &&
715             ev_view_get_sizing_mode (view) == EV_SIZING_FREE) {
716                 ev_view_set_zoom (view, g_value_get_double (&zoom), FALSE);
717         }
718
719         /* Continuous */
720         if (ev_metadata_manager_get (uri, "continuous", &continuous, FALSE)) {
721                 ev_view_set_continuous (view, g_value_get_boolean (&continuous));
722         }
723
724         /* Dual page */
725         if (ev_metadata_manager_get (uri, "dual-page", &dual_page, FALSE)) {
726                 ev_view_set_dual_page (view, g_value_get_boolean (&dual_page));
727         }
728
729         /* Presentation */
730         if (ev_metadata_manager_get (uri, "presentation", &presentation, FALSE)) {
731                 if (g_value_get_boolean (&presentation) && uri) {
732                         ev_window_run_presentation (window);
733                 }
734         }
735
736         /* Fullscreen */
737         if (ev_metadata_manager_get (uri, "fullscreen", &fullscreen, FALSE)) {
738                 if (g_value_get_boolean (&fullscreen) && uri) {
739                         ev_window_run_fullscreen (window);
740                 }
741         }
742
743         /* Rotation */
744         if (ev_metadata_manager_get (uri, "rotation", &rotation, TRUE)) {
745                 if (g_value_get_int (&rotation)) {
746                         switch (g_value_get_int (&rotation)) {
747                                 case 90:
748                                         ev_view_set_rotation (view, 90);
749                                         break;
750                                 case 180:
751                                         ev_view_set_rotation (view, 180);
752                                         break;
753                                 case 270:
754                                         ev_view_set_rotation (view, 270);
755                                         break;
756                                 default:
757                                         break;
758                         }
759                 }
760         }
761 }
762
763 static void
764 ev_window_setup_document (EvWindow *ev_window)
765 {
766         const EvDocumentInfo *info;
767         EvDocument *document;
768         EvView *view = EV_VIEW (ev_window->priv->view);
769         EvSidebar *sidebar = EV_SIDEBAR (ev_window->priv->sidebar);
770         GtkAction *action;
771
772         document = ev_window->priv->document;
773         ev_window->priv->page_cache = ev_page_cache_get (ev_window->priv->document);
774         g_signal_connect (ev_window->priv->page_cache, "page-changed", G_CALLBACK (page_changed_cb), ev_window);
775
776         if (EV_IS_DOCUMENT_FIND (document)) {
777                 g_signal_connect_object (G_OBJECT (document),
778                                          "find_changed",
779                                          G_CALLBACK (find_changed_cb),  
780                                          ev_window, 0);
781         }
782
783         ev_sidebar_set_document (sidebar, document);
784
785         if (ev_page_cache_get_n_pages (ev_window->priv->page_cache) > 0) {
786                 ev_view_set_document (view, document);
787         }
788         ev_window_set_page_mode (ev_window, PAGE_MODE_DOCUMENT);
789
790         ev_window_title_set_document (ev_window->priv->title, document);
791         ev_window_title_set_uri (ev_window->priv->title, ev_window->priv->uri);
792
793         action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
794         ev_page_action_set_document (EV_PAGE_ACTION (action), document);
795         ev_window_setup_action_sensitivity (ev_window);
796
797         if (ev_window->priv->properties) {
798                 ev_properties_dialog_set_document (EV_PROPERTIES_DIALOG (ev_window->priv->properties),
799                                                    ev_window->priv->document);
800         }
801         
802         setup_document_from_metadata (ev_window);
803         setup_sidebar_from_metadata (ev_window, document);
804
805         info = ev_page_cache_get_info (ev_window->priv->page_cache);
806         update_document_mode (ev_window, info->mode);
807 }
808
809 static void
810 password_dialog_response (GtkWidget *password_dialog,
811                           gint       response_id,
812                           EvWindow  *ev_window)
813 {
814         char *password;
815         
816         if (response_id == GTK_RESPONSE_OK) {
817
818                 password = ev_password_dialog_get_password (EV_PASSWORD_DIALOG (password_dialog));
819                 if (password) {
820                         ev_document_doc_mutex_lock ();
821                         ev_document_security_set_password (EV_DOCUMENT_SECURITY (ev_window->priv->xfer_job->document),
822                                                            password);
823                         ev_document_doc_mutex_unlock ();
824                 }
825                 g_free (password);
826
827                 ev_password_dialog_save_password (EV_PASSWORD_DIALOG (password_dialog));
828
829                 ev_window_title_set_type (ev_window->priv->title, EV_WINDOW_TITLE_DOCUMENT);
830                 ev_job_queue_add_job (ev_window->priv->xfer_job, EV_JOB_PRIORITY_HIGH);
831                 
832                 gtk_widget_destroy (password_dialog);
833                         
834                 return;
835         }
836
837         gtk_widget_set_sensitive (ev_window->priv->password_view, TRUE);
838         gtk_widget_destroy (password_dialog);
839 }
840
841 /* Called either by ev_window_xfer_job_cb or by the "unlock" callback on the
842  * password_view page.  It assumes that ev_window->priv->password_* has been set
843  * correctly.  These are cleared by password_dialog_response() */
844
845 static void
846 ev_window_popup_password_dialog (EvWindow *ev_window)
847 {
848         g_assert (ev_window->priv->xfer_job);
849
850         gtk_widget_set_sensitive (ev_window->priv->password_view, FALSE);
851
852         ev_window_title_set_uri (ev_window->priv->title, ev_window->priv->uri);
853         ev_window_title_set_type (ev_window->priv->title, EV_WINDOW_TITLE_PASSWORD);
854
855         if (ev_window->priv->password_dialog == NULL) {
856                 ev_window->priv->password_dialog =
857                         g_object_new (EV_TYPE_PASSWORD_DIALOG, "uri", ev_window->priv->uri, NULL);
858                 gtk_window_set_transient_for (GTK_WINDOW (ev_window->priv->password_dialog), GTK_WINDOW (ev_window));
859
860                 g_object_add_weak_pointer (G_OBJECT (ev_window->priv->password_dialog),
861                                            (gpointer *) &(ev_window->priv->password_dialog));
862                 g_signal_connect (ev_window->priv->password_dialog,
863                                   "response",
864                                   G_CALLBACK (password_dialog_response),
865                                   ev_window);
866                 gtk_widget_show (ev_window->priv->password_dialog);
867         } else {
868                 ev_password_dialog_set_bad_pass (EV_PASSWORD_DIALOG (ev_window->priv->password_dialog));
869         }
870 }
871
872 static void
873 ev_window_clear_xfer_job (EvWindow *ev_window)
874 {
875     if (ev_window->priv->xfer_job != NULL) {
876
877         if (!ev_window->priv->xfer_job->finished)
878                 ev_job_queue_remove_job (ev_window->priv->xfer_job);
879
880         g_signal_handlers_disconnect_by_func (ev_window->priv->xfer_job, ev_window_xfer_job_cb, ev_window);
881         g_object_unref (ev_window->priv->xfer_job);
882         ev_window->priv->xfer_job = NULL;
883     }
884 }
885
886 static void
887 ev_window_clear_local_uri (EvWindow *ev_window)
888 {
889     char *filename;
890     
891     if (ev_window->priv->local_uri) {
892             filename = g_filename_from_uri (ev_window->priv->local_uri, NULL, NULL);
893             if (filename != NULL) {
894                     unlink (filename);
895                     g_free (filename);
896             }
897             g_free (ev_window->priv->local_uri);
898             ev_window->priv->local_uri = NULL;
899     }
900 }
901
902 /* This callback will executed when load job will be finished.
903  *
904  * Since the flow of the error dialog is very confusing, we assume that both
905  * document and uri will go away after this function is called, and thus we need
906  * to ref/dup them.  Additionally, it needs to clear
907  * ev_window->priv->password_{uri,document}, and thus people who call this
908  * function should _not_ necessarily expect those to exist after being
909  * called. */
910 static void
911 ev_window_xfer_job_cb  (EvJobXfer *job,
912                         gpointer data)
913 {
914         EvWindow *ev_window = EV_WINDOW (data);
915         EvDocument *document = EV_JOB (job)->document;
916
917         g_assert (job->uri);
918         
919         ev_view_set_loading (EV_VIEW (ev_window->priv->view), FALSE);
920
921         /* Success! */
922         if (job->error == NULL) {
923
924                 g_free (ev_window->priv->uri);
925                 ev_window->priv->uri = g_strdup (job->uri);
926                 setup_view_from_metadata (ev_window);
927
928                 if (job->local_uri) {
929                         ev_window->priv->local_uri = g_strdup (job->local_uri);
930                 } else {
931                         ev_window->priv->local_uri = NULL;
932                 }
933                 
934                 if (ev_window->priv->document)
935                         g_object_unref (ev_window->priv->document);
936                 ev_window->priv->document = g_object_ref (document);
937                 
938                 ev_window_setup_document (ev_window);
939                 ev_window_add_recent (ev_window, ev_window->priv->uri);         
940
941                 if (job->dest)
942                         ev_window_goto_dest (ev_window, job->dest);
943
944                 switch (job->mode) {
945                         case EV_WINDOW_MODE_FULLSCREEN:
946                                 ev_window_run_fullscreen (ev_window);
947                                 break;
948                         case EV_WINDOW_MODE_PRESENTATION:
949                                 ev_window_run_presentation (ev_window);
950                                 break;
951                         case EV_WINDOW_MODE_PREVIEW:
952                                 ev_window_run_preview (ev_window);
953                                 break;
954                         default:
955                                 break;
956                 }
957
958                 ev_window_clear_xfer_job (ev_window);           
959                 return;
960         }
961
962         if (job->error->domain == EV_DOCUMENT_ERROR &&
963             job->error->code == EV_DOCUMENT_ERROR_ENCRYPTED) {
964                 gchar *base_name, *file_name;
965
966                 g_free (ev_window->priv->uri);
967                 ev_window->priv->uri = g_strdup (job->uri);
968                 setup_view_from_metadata (ev_window);
969
970
971                 file_name = gnome_vfs_format_uri_for_display (job->uri);
972                 base_name = g_path_get_basename (file_name);
973                 ev_password_view_set_file_name (EV_PASSWORD_VIEW (ev_window->priv->password_view),
974                                                 base_name);
975                 g_free (file_name);
976                 g_free (base_name);
977                 ev_window_set_page_mode (ev_window, PAGE_MODE_PASSWORD);
978
979                 ev_window_popup_password_dialog (ev_window);
980         } else {
981                 ev_window_error_dialog (GTK_WINDOW (ev_window), 
982                                         _("Unable to open document"),
983                                         job->error);
984                 ev_window_clear_xfer_job (ev_window);
985         }       
986
987         return;
988 }
989
990 const char *
991 ev_window_get_uri (EvWindow *ev_window)
992 {
993         return ev_window->priv->uri;
994 }
995
996 static void
997 ev_window_close_dialogs (EvWindow *ev_window)
998 {
999         if (ev_window->priv->password_dialog)
1000                 gtk_widget_destroy (ev_window->priv->password_dialog);
1001         ev_window->priv->password_dialog = NULL;
1002         
1003 #ifdef WITH_PRINT
1004         if (ev_window->priv->print_dialog)
1005                 gtk_widget_destroy (ev_window->priv->print_dialog);
1006         ev_window->priv->print_dialog = NULL;
1007 #endif
1008
1009 #ifdef WITH_GNOME_PRINT
1010         if (ev_window->priv->print_job)
1011                 g_object_unref (ev_window->priv->print_job);
1012         ev_window->priv->print_job = NULL;
1013 #endif
1014         
1015         if (ev_window->priv->properties)
1016                 gtk_widget_destroy (ev_window->priv->properties);
1017         ev_window->priv->properties = NULL;
1018 }
1019
1020 void
1021 ev_window_open_uri (EvWindow       *ev_window,
1022                     const char     *uri,
1023                     EvLinkDest     *dest,
1024                     EvWindowRunMode mode)
1025 {
1026         ev_window_close_dialogs (ev_window);
1027         ev_window_clear_xfer_job (ev_window);
1028         ev_window_clear_local_uri (ev_window);
1029         ev_view_set_loading (EV_VIEW (ev_window->priv->view), TRUE);
1030         
1031         ev_window->priv->xfer_job = ev_job_xfer_new (uri, dest, mode);
1032         g_signal_connect (ev_window->priv->xfer_job,
1033                           "finished",
1034                           G_CALLBACK (ev_window_xfer_job_cb),
1035                           ev_window);
1036         ev_job_queue_add_job (ev_window->priv->xfer_job, EV_JOB_PRIORITY_HIGH);
1037 }
1038
1039 void
1040 ev_window_goto_dest (EvWindow *ev_window, EvLinkDest *dest)
1041 {
1042         ev_view_goto_dest (EV_VIEW (ev_window->priv->view), dest);
1043 }
1044
1045 static void
1046 file_open_dialog_response_cb (GtkWidget *chooser,
1047                               gint       response_id,
1048                               EvWindow  *ev_window)
1049 {
1050         if (response_id == GTK_RESPONSE_OK) {
1051                 GSList *uris;
1052
1053                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser));
1054
1055                 ev_application_open_uri_list (EV_APP, uris, GDK_CURRENT_TIME);
1056         
1057                 g_slist_foreach (uris, (GFunc)g_free, NULL);    
1058                 g_slist_free (uris);
1059         }
1060         ev_application_set_chooser_uri (EV_APP, 
1061                                         gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (chooser)));
1062
1063         gtk_widget_destroy (chooser);
1064 }
1065
1066 static void
1067 ev_window_cmd_file_open (GtkAction *action, EvWindow *window)
1068 {
1069         GtkWidget *chooser;
1070
1071         chooser = gtk_file_chooser_dialog_new (_("Open Document"),
1072                                                GTK_WINDOW (window),
1073                                                GTK_FILE_CHOOSER_ACTION_OPEN,
1074                                                GTK_STOCK_CANCEL,
1075                                                GTK_RESPONSE_CANCEL,
1076                                                GTK_STOCK_OPEN, GTK_RESPONSE_OK,
1077                                                NULL);
1078
1079         ev_document_factory_add_filters (chooser, NULL);
1080         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), TRUE);
1081         gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), FALSE);
1082         if (ev_application_get_chooser_uri (EV_APP) != NULL)
1083                 gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (chooser),
1084                                           ev_application_get_chooser_uri (EV_APP));
1085         
1086         g_signal_connect (chooser, "response",
1087                           G_CALLBACK (file_open_dialog_response_cb),
1088                           window);
1089
1090         gtk_widget_show (chooser);
1091 }
1092
1093 static void
1094 ev_window_cmd_recent_file_activate (GtkAction *action,
1095                                     EvWindow *ev_window)
1096 {
1097         char *uri;
1098         EggRecentItem *item;
1099
1100         item = egg_recent_view_uimanager_get_item (ev_window->priv->recent_view,
1101                                                    action);
1102
1103         uri = egg_recent_item_get_uri (item);
1104
1105         ev_application_open_uri (EV_APP, uri, NULL, GDK_CURRENT_TIME, NULL);
1106         
1107         g_free (uri);
1108 }
1109
1110 static void
1111 ev_window_add_recent (EvWindow *window, const char *filename)
1112 {
1113         EggRecentItem *item;
1114
1115         item = egg_recent_item_new_from_uri (filename);
1116         egg_recent_item_add_group (item, "Evince");
1117         egg_recent_model_add_full (ev_application_get_recent_model (EV_APP), item);
1118 }
1119
1120 static void
1121 ev_window_setup_recent (EvWindow *ev_window)
1122 {
1123
1124         ev_window->priv->recent_view = egg_recent_view_uimanager_new (ev_window->priv->ui_manager,
1125                                                                       "/MainMenu/FileMenu/RecentFilesMenu",
1126                                                                       G_CALLBACK (ev_window_cmd_recent_file_activate), 
1127                                                                       ev_window);       
1128
1129         egg_recent_view_uimanager_show_icons (EGG_RECENT_VIEW_UIMANAGER (ev_window->priv->recent_view), FALSE);
1130
1131         egg_recent_view_set_model (EGG_RECENT_VIEW (ev_window->priv->recent_view),
1132                                    ev_application_get_recent_model (EV_APP));
1133
1134         egg_recent_view_uimanager_set_trailing_sep (ev_window->priv->recent_view, TRUE);
1135         
1136         g_signal_connect (ev_window->priv->recent_view, "activate",
1137                         G_CALLBACK (ev_window_cmd_recent_file_activate), ev_window);
1138 }
1139
1140 static void
1141 file_save_dialog_response_cb (GtkWidget *fc,
1142                               gint       response_id,
1143                               EvWindow  *ev_window)
1144 {
1145         gboolean success;
1146
1147         if (response_id == GTK_RESPONSE_OK) {
1148                 gchar *uri;
1149                 GError *err = NULL;
1150
1151                 uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
1152
1153                 ev_document_doc_mutex_lock ();
1154                 success = ev_document_save (ev_window->priv->document, uri, &err);
1155                 ev_document_doc_mutex_unlock ();
1156
1157                 if (err) {
1158                         gchar *msg;
1159                         msg = g_strdup_printf (_("The file could not be saved as “%s”."), uri);
1160                         ev_window_error_dialog (GTK_WINDOW (fc), msg, err);
1161                         g_free (msg);
1162                 }
1163
1164                 g_free (uri);
1165         }
1166
1167         gtk_widget_destroy (fc);
1168 }
1169
1170 static void
1171 ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
1172 {
1173         GtkWidget *fc;
1174         gchar *base_name;
1175         gchar *file_name;
1176
1177         fc = gtk_file_chooser_dialog_new (
1178                 _("Save a Copy"),
1179                 GTK_WINDOW (ev_window), GTK_FILE_CHOOSER_ACTION_SAVE,
1180                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1181                 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
1182                 NULL);
1183
1184         ev_document_factory_add_filters (fc, ev_window->priv->document);
1185         gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK);
1186
1187         gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (fc), TRUE);    
1188         file_name = gnome_vfs_format_uri_for_display (ev_window->priv->uri);
1189         base_name = g_path_get_basename (file_name);
1190         gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (fc), base_name);
1191         g_free (file_name);
1192         g_free (base_name);
1193
1194         g_signal_connect (fc, "response",
1195                           G_CALLBACK (file_save_dialog_response_cb),
1196                           ev_window);
1197
1198         gtk_widget_show (fc);
1199 }
1200
1201 #ifdef WITH_GTK_PRINT
1202 static void
1203 ev_window_clear_print_job (EvWindow *window)
1204 {
1205         if (window->priv->print_job) {
1206                 if (!window->priv->print_job->finished)
1207                         ev_job_queue_remove_job (window->priv->print_job);
1208
1209                 g_signal_handlers_disconnect_by_func (window->priv->print_job,
1210                                                       ev_window_print_job_cb,
1211                                                       window);
1212                 g_object_unref (window->priv->print_job);
1213                 window->priv->print_job = NULL;
1214         }
1215 }
1216
1217 static void
1218 ev_window_print_finished (GtkPrintJob *print_job,
1219                           EvWindow    *window,
1220                           GError      *error)
1221 {
1222         ev_window_clear_print_job (window);
1223         
1224         if (error) {
1225                 GtkWidget *dialog;
1226                 
1227                 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1228                                                  GTK_DIALOG_MODAL,
1229                                                  GTK_MESSAGE_ERROR,
1230                                                  GTK_BUTTONS_OK,
1231                                                  _("Failed to print document"));
1232                 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1233                                                           error->message);
1234
1235                 gtk_dialog_run (GTK_DIALOG (dialog));
1236                 gtk_widget_destroy (dialog);
1237         }
1238 }
1239
1240 static void
1241 ev_window_print_send (EvWindow    *window,
1242                       const gchar *filename)
1243 {
1244         GtkPrintJob *job;
1245         GError      *error = NULL;
1246         
1247         if (window->priv->gtk_print_job)
1248                 g_object_unref (window->priv->gtk_print_job);
1249         
1250         job = gtk_print_job_new ("evince-print",
1251                                  window->priv->printer,
1252                                  window->priv->print_settings,
1253                                  window->priv->print_page_setup);
1254         
1255         window->priv->gtk_print_job = job;
1256
1257         if (gtk_print_job_set_source_file (job, filename, &error)) {
1258                 gtk_print_job_send (job,
1259                                     (GtkPrintJobCompleteFunc)ev_window_print_finished,
1260                                     window, NULL);
1261         } else {
1262                 ev_window_clear_print_job (window);
1263                 g_warning (error->message);
1264                 g_error_free (error);
1265         }
1266 }
1267
1268 static void
1269 ev_window_print_job_cb (EvJobPrint *job,
1270                         EvWindow   *window)
1271 {
1272         if (job->error) {
1273                 g_warning (job->error->message);
1274                 ev_window_clear_print_job (window);
1275                 return;
1276         }
1277
1278         g_assert (job->temp_file != NULL);
1279
1280         ev_window_print_send (window, job->temp_file);
1281 }
1282
1283 static gboolean
1284 ev_window_print_dialog_response_cb (GtkDialog *dialog,
1285                                     gint       response,
1286                                     EvWindow  *window)
1287 {
1288         EvBackend document_type;
1289         gboolean  export_to_ps = TRUE;
1290         
1291         if (response != GTK_RESPONSE_OK) {
1292                 gtk_widget_destroy (GTK_WIDGET (dialog));
1293                 window->priv->print_dialog = NULL;
1294
1295                 return FALSE;
1296         }
1297
1298         if (window->priv->printer)
1299                 g_object_unref (window->priv->printer);
1300         if (window->priv->print_settings)
1301                 g_object_unref (window->priv->print_settings);
1302         if (window->priv->print_page_setup)
1303                 g_object_unref (window->priv->print_page_setup);
1304         
1305         window->priv->printer = g_object_ref (
1306                 gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (dialog)));
1307         window->priv->print_settings = g_object_ref (
1308                 gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (dialog)));
1309         window->priv->print_page_setup = g_object_ref (
1310                 gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (dialog)));
1311
1312         document_type = ev_document_factory_get_backend (window->priv->document);
1313         switch (document_type) {
1314                 case EV_BACKEND_PDF:
1315                         export_to_ps = !gtk_printer_accepts_pdf (window->priv->printer);
1316                         break;
1317                 case EV_BACKEND_PS:
1318                         export_to_ps = FALSE;
1319                         break;
1320                 default:
1321                         export_to_ps = TRUE;
1322                         break;
1323         }
1324
1325         if ((export_to_ps || document_type == EV_BACKEND_PS) &&
1326             !gtk_printer_accepts_ps (window->priv->printer)) {
1327                 GtkWidget *msgdialog;
1328
1329                 msgdialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
1330                                                     GTK_DIALOG_MODAL,
1331                                                     GTK_MESSAGE_ERROR,
1332                                                     GTK_BUTTONS_OK,
1333                                                     _("Printing is not supported on this printer."));
1334                 
1335                 gtk_dialog_run (GTK_DIALOG (msgdialog));
1336                 gtk_widget_destroy (msgdialog);
1337
1338                 return FALSE;
1339         }
1340
1341         if (export_to_ps) {
1342                 EvPageCache *page_cache;
1343                 gint         width;
1344                 gint         height;
1345
1346                 ev_window_clear_print_job (window);
1347
1348                 page_cache = ev_page_cache_get (window->priv->document);
1349                 ev_page_cache_get_size (page_cache,
1350                                         ev_page_cache_get_current_page (page_cache),
1351                                         0, 1.0, &width, &height);
1352         
1353                 window->priv->print_job =
1354                         ev_job_print_new (window->priv->document,
1355                                           (gdouble)width,
1356                                           (gdouble)height);
1357                 g_signal_connect (window->priv->print_job, "finished",
1358                                   G_CALLBACK (ev_window_print_job_cb),
1359                                   window);
1360                 /* The priority doesn't matter for this job */
1361                 ev_job_queue_add_job (window->priv->print_job, EV_JOB_PRIORITY_LOW);
1362         } else {
1363                 gchar *filename;
1364
1365                 filename = g_filename_from_uri (window->priv->uri, NULL, NULL);
1366                 ev_window_print_send (window, filename);
1367                 g_free (filename);
1368         }
1369         
1370         gtk_widget_destroy (GTK_WIDGET (dialog));
1371         window->priv->print_dialog = NULL;
1372
1373         return TRUE;
1374 }
1375
1376 void
1377 ev_window_print_range (EvWindow *ev_window, int first_page, int last_page)
1378 {
1379         GtkWidget   *dialog;
1380         EvPageCache *page_cache;
1381         gint         current_page;
1382         gint         document_last_page;
1383
1384         g_return_if_fail (EV_IS_WINDOW (ev_window));
1385         g_return_if_fail (ev_window->priv->document != NULL);
1386
1387         if (ev_window->priv->print_dialog) {
1388                 gtk_window_present (GTK_WINDOW (ev_window->priv->print_dialog));
1389                 return;
1390         }
1391         
1392         page_cache = ev_page_cache_get (ev_window->priv->document);
1393         current_page = ev_page_cache_get_current_page (page_cache);
1394         document_last_page = ev_page_cache_get_n_pages (page_cache);
1395
1396         
1397         if (!ev_window->priv->print_settings)
1398                 ev_window->priv->print_settings = gtk_print_settings_new ();
1399
1400         if (first_page != 1 && last_page != document_last_page) {
1401                 GtkPageRange range;
1402
1403                 range.start = first_page;
1404                 range.end = last_page;
1405                 
1406                 gtk_print_settings_set_print_pages (ev_window->priv->print_settings,
1407                                                     GTK_PRINT_PAGES_RANGES);
1408                 gtk_print_settings_set_page_ranges (ev_window->priv->print_settings,
1409                                                     &range, 1);
1410         }
1411
1412         dialog = gtk_print_unix_dialog_new (_("Print"), GTK_WINDOW (ev_window));
1413         ev_window->priv->print_dialog = dialog;
1414         gtk_print_unix_dialog_set_current_page (GTK_PRINT_UNIX_DIALOG (dialog),
1415                                                 current_page);
1416         
1417         gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (dialog),
1418                                             ev_window->priv->print_settings);
1419         
1420         if (ev_window->priv->print_page_setup)
1421                 gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (dialog),
1422                                                       ev_window->priv->print_page_setup);
1423         
1424         g_signal_connect (G_OBJECT (dialog), "response",
1425                           G_CALLBACK (ev_window_print_dialog_response_cb),
1426                           ev_window);
1427
1428         gtk_widget_show (dialog);
1429 }
1430 #endif /* WITH_GTK_PRINT */
1431
1432 #ifdef WITH_GNOME_PRINT
1433 static gboolean
1434 ev_window_print_dialog_response_cb (GtkDialog *print_dialog,
1435                                     gint       response,
1436                                     EvWindow  *ev_window)
1437 {
1438         EvPrintJob *print_job;
1439         GnomePrintConfig *config;
1440     
1441         if (response != GNOME_PRINT_DIALOG_RESPONSE_PRINT) {
1442                 gtk_widget_destroy (GTK_WIDGET (print_dialog));
1443                 ev_window->priv->print_dialog = NULL;
1444                 g_object_unref (ev_window->priv->print_job);
1445                 ev_window->priv->print_job = NULL;
1446                 
1447                 return FALSE;
1448         }
1449
1450         config = gnome_print_dialog_get_config (GNOME_PRINT_DIALOG (print_dialog));
1451
1452         /* FIXME: Change this when we have the first backend
1453          * that can print more than postscript
1454          */
1455         if (using_pdf_printer (config)) {
1456                 GtkWidget *dialog;
1457                 
1458                 dialog = gtk_message_dialog_new (GTK_WINDOW (print_dialog), GTK_DIALOG_MODAL,
1459                                                  GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1460                                                  _("Generating PDF is not supported"));
1461                 gtk_dialog_run (GTK_DIALOG (dialog));
1462                 gtk_widget_destroy (dialog);
1463                 
1464                 return FALSE;
1465         } else if (!using_postscript_printer (config)) {
1466                 GtkWidget *dialog;
1467
1468                 dialog = gtk_message_dialog_new (GTK_WINDOW (print_dialog), GTK_DIALOG_MODAL,
1469                                                  GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1470                                                  _("Printing is not supported on this printer."));
1471                 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1472                                                           _("You were trying to print to a printer using the “%s” driver. "
1473                                                             "This program requires a PostScript printer driver."),
1474                                                           gnome_print_config_get (config, (guchar *)"Settings.Engine.Backend.Driver"));
1475                 gtk_dialog_run (GTK_DIALOG (dialog));
1476                 gtk_widget_destroy (dialog);
1477                 
1478                 return FALSE;
1479         }
1480
1481         save_print_config_to_file (config);
1482     
1483         print_job = g_object_new (EV_TYPE_PRINT_JOB,
1484                                   "gnome_print_job", ev_window->priv->print_job,
1485                                   "document", ev_window->priv->document,
1486                                   "print_dialog", print_dialog,
1487                                   NULL);
1488
1489         if (print_job != NULL) {
1490                 ev_print_job_print (print_job, GTK_WINDOW (ev_window));
1491                 g_object_unref (print_job);
1492         }
1493
1494         g_object_unref (config);
1495
1496         gtk_widget_destroy (GTK_WIDGET (print_dialog));
1497         ev_window->priv->print_dialog = NULL;
1498         g_object_unref (ev_window->priv->print_job);
1499         ev_window->priv->print_job = NULL;
1500
1501         return FALSE;
1502 }
1503
1504 void
1505 ev_window_print_range (EvWindow *ev_window, int first_page, int last_page)
1506 {
1507         GnomePrintConfig *config;
1508         gchar *pages_label;
1509
1510         g_return_if_fail (EV_IS_WINDOW (ev_window));
1511         g_return_if_fail (ev_window->priv->document != NULL);
1512
1513         config = load_print_config_from_file ();
1514
1515         if (ev_window->priv->print_job == NULL)
1516                 ev_window->priv->print_job = gnome_print_job_new (config);
1517         
1518         if (ev_window->priv->print_dialog == NULL) {
1519                 ev_window->priv->print_dialog =
1520                         gnome_print_dialog_new (ev_window->priv->print_job,
1521                                                 (guchar *) _("Print"),
1522                                                 (GNOME_PRINT_DIALOG_RANGE |
1523                                                  GNOME_PRINT_DIALOG_COPIES));
1524         }
1525         
1526         gtk_window_set_transient_for (GTK_WINDOW (ev_window->priv->print_dialog),
1527                                       GTK_WINDOW (ev_window));                                                          
1528         g_object_unref (config);                                                                
1529
1530         pages_label = g_strconcat (_("Pages"), " ", NULL);
1531         gnome_print_dialog_construct_range_page (GNOME_PRINT_DIALOG (ev_window->priv->print_dialog),
1532                                                  GNOME_PRINT_RANGE_ALL |
1533                                                  GNOME_PRINT_RANGE_RANGE,
1534                                                  first_page, last_page,
1535                                                  NULL, (const guchar *)pages_label);
1536         g_free (pages_label);
1537                                                  
1538         gtk_dialog_set_response_sensitive (GTK_DIALOG (ev_window->priv->print_dialog),
1539                                            GNOME_PRINT_DIALOG_RESPONSE_PREVIEW,
1540                                            FALSE);
1541
1542         g_signal_connect (G_OBJECT (ev_window->priv->print_dialog), "response",
1543                           G_CALLBACK (ev_window_print_dialog_response_cb),
1544                           ev_window);
1545         gtk_widget_show (ev_window->priv->print_dialog);
1546 }
1547 #endif /* WITH_GNOME_PRINT */
1548
1549 static void
1550 ev_window_print (EvWindow *window)
1551 {
1552         EvPageCache *page_cache;
1553         gint         last_page;
1554
1555         page_cache = ev_page_cache_get (window->priv->document);
1556         last_page = ev_page_cache_get_n_pages (page_cache);
1557
1558 #ifdef WITH_PRINT
1559         ev_window_print_range (window, 1, last_page);
1560 #endif
1561 }
1562
1563 static void
1564 ev_window_cmd_file_print (GtkAction *action, EvWindow *ev_window)
1565 {
1566         ev_window_print (ev_window);
1567 }
1568
1569 static void
1570 ev_window_cmd_file_properties (GtkAction *action, EvWindow *ev_window)
1571 {
1572         if (ev_window->priv->properties == NULL) {
1573                 ev_window->priv->properties = ev_properties_dialog_new ();
1574                 ev_properties_dialog_set_document (EV_PROPERTIES_DIALOG (ev_window->priv->properties),
1575                                                    ev_window->priv->document);
1576                 g_object_add_weak_pointer (G_OBJECT (ev_window->priv->properties),
1577                                            (gpointer *) &(ev_window->priv->properties));
1578                 gtk_window_set_transient_for (GTK_WINDOW (ev_window->priv->properties),
1579                                               GTK_WINDOW (ev_window));
1580         }
1581
1582         gtk_widget_show (ev_window->priv->properties);
1583 }
1584                                         
1585 static void
1586 ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
1587 {
1588         g_return_if_fail (EV_IS_WINDOW (ev_window));
1589
1590         gtk_widget_destroy (GTK_WIDGET (ev_window));
1591 }
1592
1593 static void
1594 ev_window_cmd_focus_page_selector (GtkAction *act, EvWindow *window)
1595 {
1596         GtkAction *action;
1597         
1598         update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, TRUE);
1599         ev_window_set_action_sensitive (window, "ViewToolbar", FALSE);
1600         
1601         action = gtk_action_group_get_action (window->priv->action_group,
1602                                               PAGE_SELECTOR_ACTION);
1603         ev_page_action_grab_focus (EV_PAGE_ACTION (action));
1604 }
1605
1606 static void
1607 ev_window_cmd_scroll_forward (GtkAction *action, EvWindow *window)
1608 {
1609         ev_view_scroll (EV_VIEW (window->priv->view), EV_SCROLL_PAGE_FORWARD, FALSE);
1610 }
1611
1612 static void
1613 ev_window_cmd_scroll_backward (GtkAction *action, EvWindow *window)
1614 {
1615         ev_view_scroll (EV_VIEW (window->priv->view), EV_SCROLL_PAGE_BACKWARD, FALSE);
1616 }
1617
1618 static void
1619 ev_window_cmd_continuous (GtkAction *action, EvWindow *ev_window)
1620 {
1621         gboolean continuous;
1622
1623         ev_window_stop_presentation (ev_window);
1624         continuous = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1625         g_object_set (G_OBJECT (ev_window->priv->view),
1626                       "continuous", continuous,
1627                       NULL);
1628         ev_window_update_actions (ev_window);
1629 }
1630
1631 static void
1632 ev_window_cmd_dual (GtkAction *action, EvWindow *ev_window)
1633 {
1634         gboolean dual_page;
1635
1636         ev_window_stop_presentation (ev_window);
1637         dual_page = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1638         g_object_set (G_OBJECT (ev_window->priv->view),
1639                       "dual-page", dual_page,
1640                       NULL);
1641         ev_window_update_actions (ev_window);
1642 }
1643
1644 static void
1645 ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
1646 {
1647         ev_window_stop_presentation (ev_window);
1648
1649         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
1650                 ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_BEST_FIT);
1651         } else {
1652                 ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FREE);
1653         }
1654         ev_window_update_actions (ev_window);
1655 }
1656
1657 static void
1658 ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
1659 {
1660         ev_window_stop_presentation (ev_window);
1661
1662         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
1663                 ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FIT_WIDTH);
1664         } else {
1665                 ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FREE);
1666         }
1667         ev_window_update_actions (ev_window);
1668 }
1669
1670
1671 static void
1672 ev_window_cmd_edit_select_all (GtkAction *action, EvWindow *ev_window)
1673 {
1674         g_return_if_fail (EV_IS_WINDOW (ev_window));
1675
1676         ev_view_select_all (EV_VIEW (ev_window->priv->view));
1677 }
1678
1679 static void
1680 ev_window_cmd_edit_find (GtkAction *action, EvWindow *ev_window)
1681 {
1682         g_return_if_fail (EV_IS_WINDOW (ev_window));
1683
1684         if (ev_window->priv->document == NULL || !EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
1685                 g_error ("Find action should be insensitive since document doesn't support find");
1686                 return;
1687         } 
1688
1689         update_chrome_flag (ev_window, EV_CHROME_FINDBAR, TRUE);
1690         gtk_widget_grab_focus (ev_window->priv->find_bar);
1691 }
1692
1693 static void
1694 ev_window_cmd_edit_find_next (GtkAction *action, EvWindow *ev_window)
1695 {
1696         g_return_if_fail (EV_IS_WINDOW (ev_window));
1697
1698         ev_view_find_next (EV_VIEW (ev_window->priv->view));
1699 }
1700
1701 static void
1702 ev_window_cmd_edit_find_previous (GtkAction *action, EvWindow *ev_window)
1703 {
1704         g_return_if_fail (EV_IS_WINDOW (ev_window));
1705
1706         ev_view_find_previous (EV_VIEW (ev_window->priv->view));
1707 }
1708
1709 static void
1710 ev_window_cmd_edit_copy (GtkAction *action, EvWindow *ev_window)
1711 {
1712         g_return_if_fail (EV_IS_WINDOW (ev_window));
1713
1714         ev_view_copy (EV_VIEW (ev_window->priv->view));
1715 }
1716
1717 static void
1718 ev_window_update_fullscreen_popup (EvWindow *window)
1719 {
1720         GtkWidget *popup = window->priv->fullscreen_popup;
1721         int popup_width, popup_height;
1722         GdkScreen *screen;
1723         GdkRectangle screen_rect;
1724         gboolean toolbar;
1725
1726         g_return_if_fail (popup != NULL);
1727
1728         if (GTK_WIDGET (window)->window == NULL)
1729                 return;
1730
1731         toolbar = (window->priv->chrome & EV_CHROME_FULLSCREEN_TOOLBAR) != 0 || 
1732                   (window->priv->chrome & EV_CHROME_RAISE_TOOLBAR) != 0;
1733         popup_width = popup->requisition.width;
1734         popup_height = popup->requisition.height;
1735
1736         screen = gtk_widget_get_screen (GTK_WIDGET (window));
1737         gdk_screen_get_monitor_geometry (screen,
1738                         gdk_screen_get_monitor_at_window
1739                         (screen,
1740                          GTK_WIDGET (window)->window),
1741                          &screen_rect);
1742         if (toolbar) {
1743                 gtk_widget_set_size_request (popup,
1744                                              screen_rect.width,
1745                                              -1);
1746                 gtk_window_move (GTK_WINDOW (popup),
1747                                  screen_rect.x,
1748                                  screen_rect.y);
1749
1750         } else {
1751                 if (gtk_widget_get_direction (popup) == GTK_TEXT_DIR_RTL)
1752                 {
1753                         gtk_window_move (GTK_WINDOW (popup),
1754                                          screen_rect.x,
1755                                          screen_rect.y);
1756                 } else {
1757                         gtk_window_move (GTK_WINDOW (popup),
1758                                          screen_rect.x + screen_rect.width - popup_width,
1759                                          screen_rect.y);
1760                 }
1761         }
1762 }
1763
1764 static void
1765 screen_size_changed_cb (GdkScreen *screen,
1766                         EvWindow *window)
1767 {
1768         ev_window_update_fullscreen_popup (window);
1769 }
1770
1771 static void
1772 ev_window_sidebar_position_change_cb (GObject *object, GParamSpec *pspec,
1773                                       EvWindow *ev_window)
1774 {
1775         if (!ev_window_is_empty (ev_window))
1776                 ev_metadata_manager_set_int (ev_window->priv->uri, "sidebar_size",
1777                                              gtk_paned_get_position (GTK_PANED (object)));
1778 }
1779
1780 static void
1781 destroy_fullscreen_popup (EvWindow *window)
1782 {
1783         if (window->priv->fullscreen_popup != NULL)
1784         {
1785                 gtk_widget_destroy (window->priv->fullscreen_popup);
1786                 window->priv->fullscreen_popup = NULL;
1787         }
1788 }
1789
1790 static void
1791 exit_fullscreen_button_clicked_cb (GtkWidget *button, EvWindow *window)
1792 {
1793         GtkAction *action;
1794
1795         action = gtk_action_group_get_action (window->priv->action_group, "ViewFullscreen");
1796         g_return_if_fail (action != NULL);
1797
1798         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
1799 }
1800
1801 static void
1802 fullscreen_popup_size_request_cb (GtkWidget *popup, GtkRequisition *req, EvWindow *window)
1803 {
1804         ev_window_update_fullscreen_popup (window);
1805 }
1806
1807 static gboolean
1808 fullscreen_timeout_cb (gpointer data)
1809 {
1810         EvWindow *window = EV_WINDOW (data);
1811         
1812         update_chrome_flag (window, EV_CHROME_FULLSCREEN_TOOLBAR, FALSE);
1813         ev_view_hide_cursor (EV_VIEW (window->priv->view));
1814         window->priv->fullscreen_timeout_id = 0;
1815
1816         return FALSE;
1817 }
1818
1819 static void
1820 fullscreen_set_timeout (EvWindow *window)
1821 {
1822         if (window->priv->fullscreen_timeout_id != 0) {
1823                 g_source_remove (window->priv->fullscreen_timeout_id);
1824         }
1825         
1826         window->priv->fullscreen_timeout_id = 
1827             g_timeout_add (FULLSCREEN_TIMEOUT, fullscreen_timeout_cb, window);
1828
1829         update_chrome_flag (window, EV_CHROME_FULLSCREEN_TOOLBAR, TRUE);
1830         update_chrome_visibility (window);
1831         ev_view_show_cursor (EV_VIEW (window->priv->view));
1832 }
1833
1834 static void
1835 fullscreen_clear_timeout (EvWindow *window)
1836 {
1837         if (window->priv->fullscreen_timeout_id != 0) {
1838                 g_source_remove (window->priv->fullscreen_timeout_id);
1839         }
1840         
1841         window->priv->fullscreen_timeout_id = 0;
1842         update_chrome_visibility (window);
1843         ev_view_show_cursor (EV_VIEW (window->priv->view));
1844 }
1845
1846
1847 static gboolean
1848 fullscreen_motion_notify_cb (GtkWidget *widget,
1849                              GdkEventMotion *event,
1850                              gpointer user_data)
1851 {
1852         EvWindow *window = EV_WINDOW (user_data);
1853
1854         fullscreen_set_timeout (window);
1855
1856         return FALSE;
1857 }
1858
1859 static gboolean
1860 fullscreen_leave_notify_cb (GtkWidget *widget,
1861                             GdkEventCrossing *event,
1862                             gpointer user_data)
1863 {
1864         EvWindow *window = EV_WINDOW (user_data);
1865
1866         fullscreen_clear_timeout (window);
1867
1868         return FALSE;
1869 }
1870
1871 static GtkWidget *
1872 ev_window_get_exit_fullscreen_button (EvWindow *window)
1873 {
1874         GtkWidget *button, *icon, *label, *hbox;
1875
1876         button = gtk_button_new ();
1877         g_signal_connect (button, "clicked",
1878                           G_CALLBACK (exit_fullscreen_button_clicked_cb),
1879                           window);
1880         gtk_widget_show (button);
1881
1882         hbox = gtk_hbox_new (FALSE, 2);
1883         gtk_widget_show (hbox);
1884         gtk_container_add (GTK_CONTAINER (button), hbox);
1885
1886         icon = gtk_image_new_from_stock (EV_STOCK_LEAVE_FULLSCREEN, GTK_ICON_SIZE_BUTTON);
1887         gtk_widget_show (icon);
1888         gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
1889
1890         label = gtk_label_new (_("Leave Fullscreen"));
1891         gtk_widget_show (label);
1892         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1893
1894         return button;
1895 }
1896
1897 static GtkWidget *
1898 ev_window_create_fullscreen_popup (EvWindow *window)
1899 {
1900         GtkWidget *popup;
1901         GtkWidget *hbox;
1902         GtkWidget *button;
1903         GdkScreen *screen;
1904
1905         window->priv->fullscreen_toolbar = egg_editable_toolbar_new_with_model
1906                         (window->priv->ui_manager, ev_application_get_toolbars_model (EV_APP), NULL);
1907
1908         popup = gtk_window_new (GTK_WINDOW_POPUP);
1909         hbox = gtk_hbox_new (FALSE, 0);
1910         button = ev_window_get_exit_fullscreen_button (window);
1911
1912         gtk_container_add (GTK_CONTAINER (popup), hbox);
1913         gtk_box_pack_start (GTK_BOX (hbox), window->priv->fullscreen_toolbar,
1914                             TRUE, TRUE, 0);
1915         gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1916
1917         gtk_widget_show (button);
1918         gtk_widget_show (hbox);
1919
1920         gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
1921
1922         screen = gtk_widget_get_screen (GTK_WIDGET (window));
1923         g_signal_connect_object (screen, "size-changed",
1924                                  G_CALLBACK (screen_size_changed_cb),
1925                                  window, 0);
1926         g_signal_connect_object (popup, "size_request",
1927                                  G_CALLBACK (fullscreen_popup_size_request_cb),
1928                                  window, 0);
1929
1930         gtk_window_set_screen (GTK_WINDOW (popup),
1931                                gtk_widget_get_screen (GTK_WIDGET (window)));
1932
1933         return popup;
1934 }
1935
1936
1937 static void
1938 ev_window_update_fullscreen_action (EvWindow *window)
1939 {
1940         GtkAction *action;
1941
1942         action = gtk_action_group_get_action (window->priv->action_group, "ViewFullscreen");
1943         g_signal_handlers_block_by_func
1944                 (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
1945         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1946                                       ev_view_get_fullscreen (EV_VIEW (window->priv->view)));
1947         g_signal_handlers_unblock_by_func
1948                 (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
1949 }
1950
1951 static void
1952 ev_window_run_fullscreen (EvWindow *window)
1953 {
1954         if (window->priv->fullscreen_popup == NULL)
1955                 window->priv->fullscreen_popup
1956                         = ev_window_create_fullscreen_popup (window);
1957
1958         g_object_set (G_OBJECT (window->priv->scrolled_window),
1959                       "shadow-type", GTK_SHADOW_NONE,
1960                       NULL);
1961
1962         ev_view_set_fullscreen (EV_VIEW (window->priv->view), TRUE);
1963         ev_window_update_fullscreen_action (window);
1964         
1965         gtk_window_fullscreen (GTK_WINDOW (window));
1966         gtk_widget_grab_focus (window->priv->view);
1967         ev_window_update_fullscreen_popup (window);
1968
1969         g_signal_connect (window->priv->view,
1970                           "motion-notify-event",
1971                           G_CALLBACK (fullscreen_motion_notify_cb),
1972                           window);
1973         g_signal_connect (window->priv->view,
1974                           "leave-notify-event",
1975                           G_CALLBACK (fullscreen_leave_notify_cb),
1976                           window);
1977         fullscreen_set_timeout (window);
1978
1979         if (!ev_window_is_empty (window))
1980                 ev_metadata_manager_set_boolean (window->priv->uri, "fullscreen", TRUE);
1981 }
1982
1983 static void
1984 ev_window_stop_fullscreen (EvWindow *window)
1985 {
1986         EvView *view = EV_VIEW (window->priv->view);
1987
1988         if (!ev_view_get_fullscreen (EV_VIEW (view)))
1989                 return;
1990
1991         g_object_set (G_OBJECT (window->priv->scrolled_window),
1992                       "shadow-type", GTK_SHADOW_IN,
1993                       NULL);
1994
1995         ev_view_set_fullscreen (view, FALSE);
1996         ev_window_update_fullscreen_action (window);
1997         gtk_window_unfullscreen (GTK_WINDOW (window));
1998
1999         g_signal_handlers_disconnect_by_func (window->priv->view,
2000                                               (gpointer) fullscreen_motion_notify_cb,
2001                                               window);
2002         g_signal_handlers_disconnect_by_func (window->priv->view,
2003                                               (gpointer) fullscreen_leave_notify_cb,
2004                                               window);
2005         fullscreen_clear_timeout (window);
2006
2007         if (!ev_window_is_empty (window))
2008                 ev_metadata_manager_set_boolean (window->priv->uri, "fullscreen", FALSE);
2009 }
2010
2011 static void
2012 ev_window_cmd_view_fullscreen (GtkAction *action, EvWindow *window)
2013 {
2014         gboolean fullscreen;
2015
2016         g_return_if_fail (EV_IS_WINDOW (window));
2017         ev_window_stop_presentation (window);
2018
2019         fullscreen = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
2020         if (fullscreen) {
2021                 ev_window_run_fullscreen (window);
2022         } else {
2023                 ev_window_stop_fullscreen (window);
2024         }
2025 }
2026
2027 static void
2028 ev_window_update_presentation_action (EvWindow *window)
2029 {
2030         GtkAction *action;
2031
2032         action = gtk_action_group_get_action (window->priv->action_group, "ViewPresentation");
2033         g_signal_handlers_block_by_func
2034                 (action, G_CALLBACK (ev_window_cmd_view_presentation), window);
2035         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
2036                                       ev_view_get_presentation (EV_VIEW (window->priv->view)));
2037         g_signal_handlers_unblock_by_func
2038                 (action, G_CALLBACK (ev_window_cmd_view_presentation), window);
2039 }
2040
2041 static void
2042 ev_window_run_presentation (EvWindow *window)
2043 {
2044         g_object_set (G_OBJECT (window->priv->scrolled_window),
2045                       "shadow-type", GTK_SHADOW_NONE,
2046                       NULL);
2047
2048         ev_view_set_presentation (EV_VIEW (window->priv->view), TRUE);
2049         ev_window_update_presentation_action (window);
2050
2051         gtk_widget_grab_focus (window->priv->view);
2052         gtk_window_fullscreen (GTK_WINDOW (window));
2053
2054         g_signal_connect (window->priv->view,
2055                           "motion-notify-event",
2056                           G_CALLBACK (fullscreen_motion_notify_cb),
2057                           window);
2058         g_signal_connect (window->priv->view,
2059                           "leave-notify-event",
2060                           G_CALLBACK (fullscreen_leave_notify_cb),
2061                           window);
2062         fullscreen_set_timeout (window);
2063
2064         if (!ev_window_is_empty (window))
2065                 ev_metadata_manager_set_boolean (window->priv->uri, "presentation", TRUE);
2066 }
2067
2068 static void
2069 ev_window_stop_presentation (EvWindow *window)
2070 {
2071         if (!ev_view_get_presentation (EV_VIEW (window->priv->view)))
2072                 return;
2073
2074         g_object_set (G_OBJECT (window->priv->scrolled_window),
2075                       "shadow-type", GTK_SHADOW_IN,
2076                       NULL);
2077
2078         ev_view_set_presentation (EV_VIEW (window->priv->view), FALSE);
2079         ev_window_update_presentation_action (window);
2080         gtk_window_unfullscreen (GTK_WINDOW (window));
2081
2082         g_signal_handlers_disconnect_by_func (window->priv->view,
2083                                               (gpointer) fullscreen_motion_notify_cb,
2084                                               window);
2085         g_signal_handlers_disconnect_by_func (window->priv->view,
2086                                               (gpointer) fullscreen_leave_notify_cb,
2087                                               window);
2088         fullscreen_clear_timeout (window);
2089
2090         if (!ev_window_is_empty (window))
2091                 ev_metadata_manager_set_boolean (window->priv->uri, "presentation", FALSE);
2092 }
2093
2094 static void
2095 ev_window_cmd_view_presentation (GtkAction *action, EvWindow *window)
2096 {
2097         gboolean presentation;
2098
2099         g_return_if_fail (EV_IS_WINDOW (window));
2100         ev_window_stop_fullscreen (window);
2101
2102         presentation = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
2103         if (presentation) {
2104                 ev_window_run_presentation (window);
2105         } else {
2106                 ev_window_stop_presentation (window);
2107         }
2108 }
2109
2110 static void
2111 ev_window_run_preview (EvWindow *window)
2112 {
2113         EggToolbarsModel *model;
2114         EggTbModelFlags   flags;
2115
2116         model = egg_toolbars_model_new ();
2117
2118         egg_toolbars_model_load_toolbars (model,
2119                                           DATADIR"/evince-toolbar.xml");
2120         
2121         flags = egg_toolbars_model_get_flags (model, 1);
2122         egg_toolbars_model_set_flags (model, 1, flags &= ~(EGG_TB_MODEL_HIDDEN));
2123
2124         egg_editable_toolbar_set_model (EGG_EDITABLE_TOOLBAR (window->priv->toolbar),
2125                                         model);
2126         
2127         egg_editable_toolbar_hide (EGG_EDITABLE_TOOLBAR (window->priv->toolbar),
2128                                    "DefaultToolBar");
2129         egg_editable_toolbar_show (EGG_EDITABLE_TOOLBAR (window->priv->toolbar),
2130                                    "PreviewToolBar");
2131
2132         ev_view_set_continuous (EV_VIEW (window->priv->view), FALSE); 
2133         
2134         update_chrome_flag (window, EV_CHROME_MENUBAR, FALSE);
2135         update_chrome_flag (window, EV_CHROME_SIDEBAR, FALSE);
2136         update_chrome_visibility (window);
2137 }
2138
2139 static gboolean
2140 ev_window_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
2141 {
2142         EvWindow *window = EV_WINDOW (widget);
2143         EvWindowPrivate *priv = window->priv;
2144
2145         if (ev_view_get_fullscreen (EV_VIEW (priv->view)))
2146                 fullscreen_set_timeout (window);
2147
2148         return GTK_WIDGET_CLASS (ev_window_parent_class)->focus_in_event (widget, event);
2149 }
2150
2151 static gboolean
2152 ev_window_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
2153 {
2154         EvWindow *window = EV_WINDOW (widget);
2155         EvWindowPrivate *priv = window->priv;
2156
2157         if (ev_view_get_fullscreen (EV_VIEW (priv->view))) {
2158                 fullscreen_set_timeout (window);
2159                 gtk_widget_hide (priv->fullscreen_popup);
2160         }
2161
2162         return GTK_WIDGET_CLASS (ev_window_parent_class)->focus_out_event (widget, event);
2163 }
2164
2165 static void
2166 ev_window_screen_changed (GtkWidget *widget,
2167                           GdkScreen *old_screen)
2168 {
2169         EvWindow *window = EV_WINDOW (widget);
2170         EvWindowPrivate *priv = window->priv;
2171         GdkScreen *screen;
2172
2173         if (GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed) {
2174                 GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed (widget, old_screen);
2175         }
2176
2177         if (priv->fullscreen_popup != NULL) {
2178                 g_signal_handlers_disconnect_by_func
2179                         (old_screen, G_CALLBACK (screen_size_changed_cb), window);
2180
2181                 screen = gtk_widget_get_screen (widget);
2182                 g_signal_connect_object (screen, "size-changed",
2183                                          G_CALLBACK (screen_size_changed_cb),
2184                                          window, 0);
2185                 gtk_window_set_screen (GTK_WINDOW (priv->fullscreen_popup), screen);
2186
2187                 ev_window_update_fullscreen_popup (window);
2188         }
2189 }
2190
2191 static void
2192 ev_window_set_page_mode (EvWindow         *window,
2193                          EvWindowPageMode  page_mode)
2194 {
2195         GtkWidget *child = NULL;
2196         GtkWidget *real_child;
2197
2198         if (window->priv->page_mode == page_mode)
2199                 return;
2200
2201         window->priv->page_mode = page_mode;
2202
2203         switch (page_mode) {
2204                 case PAGE_MODE_DOCUMENT:
2205                         child = window->priv->view;
2206                         break;
2207                 case PAGE_MODE_PASSWORD:
2208                         child = window->priv->password_view;
2209                         break;
2210                 default:
2211                         g_assert_not_reached ();
2212         }
2213
2214         real_child = gtk_bin_get_child (GTK_BIN (window->priv->scrolled_window));
2215         if (child != real_child) {
2216                 gtk_container_remove (GTK_CONTAINER (window->priv->scrolled_window),
2217                                       real_child);
2218                 gtk_container_add (GTK_CONTAINER (window->priv->scrolled_window),
2219                                    child);
2220         }
2221         ev_window_update_actions (window);
2222 }
2223
2224
2225 static void
2226 ev_window_cmd_edit_rotate_left (GtkAction *action, EvWindow *ev_window)
2227 {
2228         ev_view_rotate_left (EV_VIEW (ev_window->priv->view));
2229 }
2230
2231 static void
2232 ev_window_cmd_edit_rotate_right (GtkAction *action, EvWindow *ev_window)
2233 {
2234         ev_view_rotate_right (EV_VIEW (ev_window->priv->view));
2235 }
2236
2237 static void
2238 ev_window_cmd_edit_toolbar_cb (GtkDialog *dialog, gint response, gpointer data)
2239 {
2240         EvWindow *ev_window = EV_WINDOW (data);
2241         egg_editable_toolbar_set_edit_mode
2242                         (EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar), FALSE);
2243         ev_application_save_toolbars_model (EV_APP);
2244         gtk_widget_destroy (GTK_WIDGET (dialog));
2245 }
2246
2247 static void
2248 ev_window_cmd_edit_toolbar (GtkAction *action, EvWindow *ev_window)
2249 {
2250         GtkWidget *dialog;
2251         GtkWidget *editor;
2252
2253         dialog = gtk_dialog_new_with_buttons (_("Toolbar Editor"),
2254                                               GTK_WINDOW (ev_window), 
2255                                               GTK_DIALOG_DESTROY_WITH_PARENT, 
2256                                               GTK_STOCK_CLOSE,
2257                                               GTK_RESPONSE_CLOSE, 
2258                                               NULL);
2259         gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
2260         gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)), 5);
2261         gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
2262         gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
2263         gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 400);
2264           
2265         editor = egg_toolbar_editor_new (ev_window->priv->ui_manager,
2266                                          ev_application_get_toolbars_model (EV_APP));
2267         gtk_container_set_border_width (GTK_CONTAINER (editor), 5);
2268         gtk_box_set_spacing (GTK_BOX (EGG_TOOLBAR_EDITOR (editor)), 5);
2269              
2270         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), editor);
2271
2272         egg_editable_toolbar_set_edit_mode
2273                 (EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar), TRUE);
2274
2275         g_signal_connect (dialog, "response",
2276                           G_CALLBACK (ev_window_cmd_edit_toolbar_cb),
2277                           ev_window);
2278         gtk_widget_show_all (dialog);
2279 }
2280
2281 static void
2282 ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window)
2283 {
2284         g_return_if_fail (EV_IS_WINDOW (ev_window));
2285
2286         ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FREE);
2287         ev_view_zoom_in (EV_VIEW (ev_window->priv->view));
2288 }
2289
2290 static void
2291 ev_window_cmd_view_zoom_out (GtkAction *action, EvWindow *ev_window)
2292 {
2293         g_return_if_fail (EV_IS_WINDOW (ev_window));
2294
2295         ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FREE);
2296         ev_view_zoom_out (EV_VIEW (ev_window->priv->view));
2297 }
2298
2299 static void
2300 ev_window_cmd_go_previous_page (GtkAction *action, EvWindow *ev_window)
2301 {
2302         g_return_if_fail (EV_IS_WINDOW (ev_window));
2303
2304         ev_view_previous_page (EV_VIEW (ev_window->priv->view));
2305 }
2306
2307 static void
2308 ev_window_cmd_go_next_page (GtkAction *action, EvWindow *ev_window)
2309 {
2310         g_return_if_fail (EV_IS_WINDOW (ev_window));
2311
2312         ev_view_next_page (EV_VIEW (ev_window->priv->view));
2313 }
2314
2315 static void
2316 ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window)
2317 {
2318         g_return_if_fail (EV_IS_WINDOW (ev_window));
2319
2320         ev_page_cache_set_current_page (ev_window->priv->page_cache, 0);
2321 }
2322
2323 static void
2324 ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window)
2325 {
2326         int n_pages;
2327
2328         g_return_if_fail (EV_IS_WINDOW (ev_window));
2329
2330         n_pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache);
2331         ev_page_cache_set_current_page (ev_window->priv->page_cache, n_pages - 1);
2332 }
2333
2334 static void
2335 ev_window_cmd_go_forward (GtkAction *action, EvWindow *ev_window)
2336 {
2337         int n_pages, current_page;
2338         
2339         g_return_if_fail (EV_IS_WINDOW (ev_window));
2340
2341         n_pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache);
2342         current_page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
2343         
2344         if (current_page + 10 < n_pages)
2345                 ev_page_cache_set_current_page (ev_window->priv->page_cache, current_page + 10);
2346 }
2347
2348 static void
2349 ev_window_cmd_go_backward (GtkAction *action, EvWindow *ev_window)
2350 {
2351         int current_page;
2352         
2353         g_return_if_fail (EV_IS_WINDOW (ev_window));
2354
2355         current_page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
2356         
2357         if (current_page - 10 >= 0)
2358                 ev_page_cache_set_current_page (ev_window->priv->page_cache, current_page - 10);
2359 }
2360
2361 static void
2362 ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window)
2363 {
2364         char *uri;
2365
2366         g_return_if_fail (EV_IS_WINDOW (ev_window));
2367
2368         uri = g_strdup (ev_window->priv->uri);
2369
2370         ev_window_open_uri (ev_window, uri, NULL, 0);
2371
2372         g_free (uri);
2373 }
2374
2375 static void
2376 ev_window_cmd_help_contents (GtkAction *action, EvWindow *ev_window)
2377 {
2378         GError *error = NULL;
2379
2380         g_return_if_fail (EV_IS_WINDOW (ev_window));
2381
2382         gnome_help_display ("evince.xml", NULL, &error);
2383
2384         if(error != NULL) {
2385                 g_warning (error->message);
2386                 g_error_free (error);
2387         }
2388 }
2389
2390 static void
2391 ev_window_cmd_leave_fullscreen (GtkAction *action, EvWindow *window)
2392 {
2393         gtk_window_unfullscreen (GTK_WINDOW (window));
2394 }
2395
2396 static void
2397 ev_window_cmd_escape (GtkAction *action, EvWindow *window)
2398 {
2399         GtkWidget *widget;
2400
2401         widget = gtk_window_get_focus (GTK_WINDOW (window));
2402         if (widget && gtk_widget_get_ancestor (widget, EGG_TYPE_FIND_BAR)) {
2403                 update_chrome_flag (window, EV_CHROME_FINDBAR, FALSE);
2404                 gtk_widget_grab_focus (window->priv->view);
2405         } else {
2406                 gboolean fullscreen;
2407                 gboolean presentation;
2408
2409                 g_object_get (window->priv->view,
2410                               "fullscreen", &fullscreen,
2411                               "presentation", &presentation,
2412                               NULL);
2413
2414                 if (fullscreen)
2415                         ev_window_stop_fullscreen (window);
2416                 if (presentation)
2417                         ev_window_stop_presentation (window);
2418
2419                 if (fullscreen && presentation)
2420                         g_warning ("Both fullscreen and presentation set somehow");
2421         }
2422 }
2423
2424 static void
2425 update_view_size (EvView *view, EvWindow *window)
2426 {
2427         int width, height;
2428         GtkRequisition vsb_requisition;
2429         GtkRequisition hsb_requisition;
2430         int scrollbar_spacing;
2431
2432         /* Calculate the width available for the */
2433         width = window->priv->scrolled_window->allocation.width;
2434         height = window->priv->scrolled_window->allocation.height;
2435
2436         if (gtk_scrolled_window_get_shadow_type (GTK_SCROLLED_WINDOW (window->priv->scrolled_window)) == GTK_SHADOW_IN) {
2437                 width -= 2 * window->priv->view->style->xthickness;
2438                 height -= 2 * window->priv->view->style->ythickness;
2439         }
2440
2441         gtk_widget_size_request (GTK_SCROLLED_WINDOW (window->priv->scrolled_window)->vscrollbar,
2442                                  &vsb_requisition);
2443         gtk_widget_size_request (GTK_SCROLLED_WINDOW (window->priv->scrolled_window)->hscrollbar,
2444                                  &hsb_requisition);
2445         gtk_widget_style_get (window->priv->scrolled_window,
2446                               "scrollbar_spacing", &scrollbar_spacing,
2447                               NULL);
2448
2449         ev_view_set_zoom_for_size (EV_VIEW (window->priv->view),
2450                                    MAX (1, width),
2451                                    MAX (1, height),
2452                                    vsb_requisition.width + scrollbar_spacing,
2453                                    hsb_requisition.height + scrollbar_spacing);
2454 }
2455
2456 static void
2457 save_sizing_mode (EvWindow *window)
2458 {
2459         EvSizingMode mode;
2460         GEnumValue *enum_value;
2461
2462         mode = ev_view_get_sizing_mode (EV_VIEW (window->priv->view));
2463         enum_value = g_enum_get_value (EV_SIZING_MODE_CLASS, mode);
2464
2465         if (!ev_window_is_empty (window))
2466                 ev_metadata_manager_set_string (window->priv->uri, "sizing_mode",
2467                                                 enum_value->value_nick);
2468 }
2469
2470 static void     
2471 ev_window_sizing_mode_changed_cb (EvView *view, GParamSpec *pspec,
2472                                   EvWindow   *ev_window)
2473 {
2474         GtkWidget *scrolled_window;
2475         EvSizingMode sizing_mode;
2476
2477         g_object_get (ev_window->priv->view,
2478                       "sizing-mode", &sizing_mode,
2479                       NULL);
2480
2481         scrolled_window = ev_window->priv->scrolled_window;
2482
2483         g_signal_handlers_disconnect_by_func (ev_window->priv->view, update_view_size, ev_window);
2484
2485         if (sizing_mode != EV_SIZING_FREE)
2486                 update_view_size (NULL, ev_window);
2487
2488         switch (sizing_mode) {
2489                 case EV_SIZING_BEST_FIT:
2490                         g_object_set (G_OBJECT (scrolled_window),
2491                                       "hscrollbar-policy", GTK_POLICY_NEVER,
2492                                       "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
2493                                       NULL);
2494                         g_signal_connect (ev_window->priv->view, "zoom_invalid",
2495                                           G_CALLBACK (update_view_size),
2496                                           ev_window);
2497                         break;
2498                 case EV_SIZING_FIT_WIDTH:
2499                         g_object_set (G_OBJECT (scrolled_window),
2500                                       "hscrollbar-policy", GTK_POLICY_NEVER,
2501                                       "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
2502                                       NULL);
2503                         g_signal_connect (ev_window->priv->view, "zoom_invalid",
2504                                           G_CALLBACK (update_view_size),
2505                                           ev_window);
2506                         break;
2507                 case EV_SIZING_FREE:
2508                         g_object_set (G_OBJECT (scrolled_window),
2509                                       "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
2510                                       "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
2511                                       NULL);
2512                         break;
2513         }
2514
2515         update_sizing_buttons (ev_window);
2516         save_sizing_mode (ev_window);
2517 }
2518
2519 static void     
2520 ev_window_zoom_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *ev_window)
2521 {
2522         ev_window_update_actions (ev_window);
2523
2524         if (ev_view_get_sizing_mode (view) == EV_SIZING_FREE && !ev_window_is_empty (ev_window)) {
2525                 ev_metadata_manager_set_double (ev_window->priv->uri, "zoom",
2526                                                 ev_view_get_zoom (view));
2527         }
2528 }
2529
2530 static void
2531 ev_window_update_continuous_action (EvWindow *window)
2532 {
2533         GtkAction *action;
2534
2535         action = gtk_action_group_get_action (window->priv->action_group, "ViewContinuous");
2536         g_signal_handlers_block_by_func
2537                 (action, G_CALLBACK (ev_window_cmd_continuous), window);
2538         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
2539                                       ev_view_get_continuous (EV_VIEW (window->priv->view)));
2540         g_signal_handlers_unblock_by_func
2541                 (action, G_CALLBACK (ev_window_cmd_continuous), window);
2542 }
2543
2544 static void
2545 ev_window_update_dual_page_action (EvWindow *window)
2546 {
2547         GtkAction *action;
2548
2549         action = gtk_action_group_get_action (window->priv->action_group, "ViewDual");
2550         g_signal_handlers_block_by_func
2551                 (action, G_CALLBACK (ev_window_cmd_dual), window);
2552         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
2553                                       ev_view_get_dual_page (EV_VIEW (window->priv->view)));
2554         g_signal_handlers_unblock_by_func
2555                 (action, G_CALLBACK (ev_window_cmd_dual), window);
2556 }
2557
2558 static void     
2559 ev_window_continuous_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *ev_window)
2560 {
2561         ev_window_update_continuous_action (ev_window);
2562
2563         if (!ev_window_is_empty (ev_window))
2564                 ev_metadata_manager_set_boolean (ev_window->priv->uri, "continuous",
2565                                                  ev_view_get_continuous (EV_VIEW (ev_window->priv->view)));
2566 }
2567
2568 static void     
2569 ev_window_rotation_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *window)
2570 {
2571         int rotation;
2572
2573         rotation = ev_view_get_rotation (EV_VIEW (window->priv->view));
2574
2575         if (!ev_window_is_empty (window))
2576                 ev_metadata_manager_set_int (window->priv->uri, "rotation",
2577                                              rotation);
2578
2579         ev_sidebar_thumbnails_refresh (EV_SIDEBAR_THUMBNAILS (window->priv->sidebar_thumbs),
2580                                        rotation);
2581 }
2582
2583 static void
2584 ev_window_has_selection_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *window)
2585 {
2586         ev_window_update_actions (window);
2587 }
2588
2589 static void     
2590 ev_window_dual_mode_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *ev_window)
2591 {
2592         ev_window_update_dual_page_action (ev_window);
2593
2594         if (!ev_window_is_empty (ev_window))
2595                 ev_metadata_manager_set_boolean (ev_window->priv->uri, "dual-page",
2596                                                  ev_view_get_dual_page (EV_VIEW (ev_window->priv->view)));
2597 }
2598
2599 static char *
2600 build_comments_string (void)
2601 {
2602         PopplerBackend backend;
2603         const char *backend_name;
2604         const char *version;
2605
2606         backend = poppler_get_backend ();
2607         version = poppler_get_version ();
2608         switch (backend) {
2609                 case POPPLER_BACKEND_CAIRO:
2610                         backend_name = "cairo";
2611                         break;
2612                 case POPPLER_BACKEND_SPLASH:
2613                         backend_name = "splash";
2614                         break;
2615                 default:
2616                         backend_name = "unknown";
2617                         break;
2618         }
2619
2620         return g_strdup_printf (_("PostScript and PDF File Viewer.\n"
2621                                   "Using poppler %s (%s)"),
2622                                 version, backend_name);
2623 }
2624
2625 static void
2626 ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
2627 {
2628         const char *authors[] = {
2629                 "Martin Kretzschmar <m_kretzschmar@gmx.net>",
2630                 "Jonathan Blandford <jrb@gnome.org>",
2631                 "Marco Pesenti Gritti <marco@gnome.org>",
2632                 "Nickolay V. Shmyrev <nshmyrev@yandex.ru>",
2633                 "Bryan Clark <clarkbw@gnome.org>",
2634                 "Carlos Garcia Campos  <carlosgc@gnome.org>",
2635                 NULL
2636         };
2637
2638         const char *documenters[] = {
2639                 "Nickolay V. Shmyrev <nshmyrev@yandex.ru>",
2640                 NULL
2641         };
2642
2643         const char *license[] = {
2644                 N_("Evince is free software; you can redistribute it and/or modify "
2645                    "it under the terms of the GNU General Public License as published by "
2646                    "the Free Software Foundation; either version 2 of the License, or "
2647                    "(at your option) any later version.\n"),
2648                 N_("Evince is distributed in the hope that it will be useful, "
2649                    "but WITHOUT ANY WARRANTY; without even the implied warranty of "
2650                    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the "
2651                    "GNU General Public License for more details.\n"),
2652                 N_("You should have received a copy of the GNU General Public License "
2653                    "along with Evince; if not, write to the Free Software Foundation, Inc., "
2654                    "59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n")
2655         };
2656
2657         char *license_trans;
2658         char *comments;
2659
2660 #ifdef ENABLE_NLS
2661         const char **p;
2662
2663         for (p = authors; *p; ++p)
2664                 *p = _(*p);
2665
2666         for (p = documenters; *p; ++p)
2667                 *p = _(*p);
2668 #endif
2669
2670         license_trans = g_strconcat (_(license[0]), "\n", _(license[1]), "\n",
2671                                      _(license[2]), "\n", NULL);
2672         comments = build_comments_string ();
2673
2674         gtk_show_about_dialog (
2675                 GTK_WINDOW (ev_window),
2676                 "name", _("Evince"),
2677                 "version", VERSION,
2678                 "copyright",
2679                 _("\xc2\xa9 1996-2005 The Evince authors"),
2680                 "license", license_trans,
2681                 "website", "http://www.gnome.org/projects/evince",
2682                 "comments", comments,
2683                 "authors", authors,
2684                 "documenters", documenters,
2685                 "translator-credits", _("translator-credits"),
2686                 "logo-icon-name", "evince",
2687                 "wrap-license", TRUE,
2688                 NULL);
2689
2690         g_free (comments);
2691         g_free (license_trans);
2692 }
2693
2694 static void
2695 ev_window_view_toolbar_cb (GtkAction *action, EvWindow *ev_window)
2696 {
2697         gboolean active;
2698         
2699         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
2700         update_chrome_flag (ev_window, EV_CHROME_TOOLBAR, active);
2701         ev_metadata_manager_set_boolean (NULL, "show_toolbar", active);
2702 }
2703
2704 static void
2705 ev_window_view_sidebar_cb (GtkAction *action, EvWindow *ev_window)
2706 {
2707         update_chrome_flag (ev_window, EV_CHROME_SIDEBAR,
2708                             gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
2709 }
2710
2711 static void
2712 ev_window_sidebar_current_page_changed_cb (EvSidebar  *ev_sidebar,
2713                                            GParamSpec *pspec,
2714                                            EvWindow   *ev_window)
2715 {
2716         GtkWidget *current_page;
2717         const char *id;
2718
2719         g_object_get (G_OBJECT (ev_sidebar), "current_page", &current_page, NULL);
2720
2721         if (current_page == ev_window->priv->sidebar_links) {
2722                 id = LINKS_SIDEBAR_ID;
2723         } else if (current_page == ev_window->priv->sidebar_thumbs) {
2724                 id = THUMBNAILS_SIDEBAR_ID;
2725         } else if (current_page == ev_window->priv->sidebar_attachments) {
2726                 id = ATTACHMENTS_SIDEBAR_ID;
2727         } else {
2728                 g_assert_not_reached();
2729         }
2730
2731         g_object_unref (current_page);
2732
2733         if (!ev_window_is_empty (ev_window))
2734                 ev_metadata_manager_set_string (ev_window->priv->uri, "sidebar_page", id);
2735 }
2736
2737 static void
2738 ev_window_sidebar_visibility_changed_cb (EvSidebar  *ev_sidebar,
2739                                          GParamSpec *pspec,
2740                                          EvWindow   *ev_window)
2741 {
2742         EvView *view = EV_VIEW (ev_window->priv->view);
2743         GtkAction *action;
2744
2745         action = gtk_action_group_get_action (ev_window->priv->action_group, "ViewSidebar");
2746         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
2747                                       GTK_WIDGET_VISIBLE (ev_sidebar));
2748
2749         if (!ev_view_get_presentation (view) && 
2750             !ev_view_get_fullscreen (view)) {
2751                 ev_metadata_manager_set_boolean (ev_window->priv->uri, "sidebar_visibility",
2752                                                  GTK_WIDGET_VISIBLE (ev_sidebar));
2753         }
2754 }
2755
2756 static gboolean
2757 view_menu_popup_cb (EvView   *view,
2758                     EvLink   *link,
2759                     EvWindow *ev_window)
2760 {
2761         GtkWidget *popup;
2762         gboolean   show_external = FALSE;
2763         gboolean   show_internal = FALSE;
2764         GtkAction *action;
2765
2766         if (ev_view_get_presentation (EV_VIEW (ev_window->priv->view)))
2767                 return FALSE;
2768         
2769         if (ev_window->priv->link)
2770                 g_object_unref (ev_window->priv->link);
2771         
2772         if (link)
2773                 ev_window->priv->link = g_object_ref (link);
2774         else    
2775                 ev_window->priv->link = NULL;
2776
2777         popup = ev_window->priv->view_popup;
2778
2779         if (ev_window->priv->link) {
2780                 EvLinkAction *ev_action;
2781
2782                 ev_action = ev_link_get_action (link);
2783                 if (!ev_action)
2784                         return FALSE;
2785                 
2786                 switch (ev_link_action_get_action_type (ev_action)) {
2787                         case EV_LINK_ACTION_TYPE_GOTO_DEST:
2788                         case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
2789                                 show_internal = TRUE;
2790                                 break;
2791                         case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
2792                         case EV_LINK_ACTION_TYPE_LAUNCH:
2793                                 show_external = TRUE;
2794                                 break;
2795                         default:
2796                                 break;
2797                 }
2798         }
2799         
2800         action = gtk_action_group_get_action (ev_window->priv->view_popup_action_group,
2801                                               "OpenLink");
2802         gtk_action_set_visible (action, show_external);
2803
2804         action = gtk_action_group_get_action (ev_window->priv->view_popup_action_group,
2805                                               "CopyLinkAddress");
2806         gtk_action_set_visible (action, show_external);
2807
2808         action = gtk_action_group_get_action (ev_window->priv->view_popup_action_group,
2809                                               "GoLink");
2810         gtk_action_set_visible (action, show_internal);
2811
2812         gtk_menu_popup (GTK_MENU (popup), NULL, NULL,
2813                         NULL, NULL,
2814                         3, gtk_get_current_event_time ());
2815         return TRUE;
2816 }
2817
2818 static gboolean
2819 attachment_bar_menu_popup_cb (EvSidebarAttachments *attachbar,
2820                               GList           *attach_list,
2821                               EvWindow        *ev_window)
2822 {
2823         GtkWidget *popup;
2824
2825         g_assert (attach_list != NULL);
2826
2827         if (ev_window->priv->attach_list) {
2828                 g_list_foreach (ev_window->priv->attach_list,
2829                                 (GFunc) g_object_unref, NULL);
2830                 g_list_free (ev_window->priv->attach_list);
2831         }
2832         
2833         ev_window->priv->attach_list = attach_list;
2834         
2835         popup = ev_window->priv->attachment_popup;
2836
2837         gtk_menu_popup (GTK_MENU (popup), NULL, NULL,
2838                         NULL, NULL,
2839                         3, gtk_get_current_event_time ());
2840
2841         return TRUE;
2842 }
2843
2844 static void
2845 view_find_status_changed_cb (EvView     *view,
2846                              GParamSpec *pspec,
2847                              EvWindow   *ev_window)
2848 {
2849         const char *text;
2850
2851         text = ev_view_get_find_status (view);
2852         egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
2853                                       text);
2854 }
2855
2856 static void
2857 find_bar_previous_cb (EggFindBar *find_bar,
2858                       EvWindow   *ev_window)
2859 {
2860         ev_view_find_previous (EV_VIEW (ev_window->priv->view));
2861 }
2862
2863 static void
2864 find_bar_next_cb (EggFindBar *find_bar,
2865                   EvWindow   *ev_window)
2866 {
2867         ev_view_find_next (EV_VIEW (ev_window->priv->view));
2868 }
2869
2870 static void
2871 find_bar_close_cb (EggFindBar *find_bar,
2872                    EvWindow   *ev_window)
2873 {
2874         update_chrome_flag (ev_window, EV_CHROME_FINDBAR, FALSE);
2875 }
2876
2877 static void
2878 find_bar_search_changed_cb (EggFindBar *find_bar,
2879                             GParamSpec *param,
2880                             EvWindow   *ev_window)
2881 {
2882         gboolean case_sensitive;
2883         gboolean visible;
2884         const char *search_string;
2885
2886         g_return_if_fail (EV_IS_WINDOW (ev_window));
2887
2888         /* Either the string or case sensitivity could have changed,
2889          * we connect this callback to both. We also connect it
2890          * to ::visible so when the find bar is hidden, we should
2891          * pretend the search string is NULL/""
2892          */
2893
2894         case_sensitive = egg_find_bar_get_case_sensitive (find_bar);
2895         visible = GTK_WIDGET_VISIBLE (find_bar);
2896         search_string = egg_find_bar_get_search_string (find_bar);
2897
2898         ev_view_search_changed (EV_VIEW(ev_window->priv->view));
2899
2900         if (ev_window->priv->document &&
2901             EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
2902                 if (visible && search_string && search_string[0]) {
2903                         ev_document_doc_mutex_lock ();
2904                         ev_document_find_begin (EV_DOCUMENT_FIND (ev_window->priv->document), 
2905                                                 ev_page_cache_get_current_page (ev_window->priv->page_cache),
2906                                                 search_string,
2907                                                 case_sensitive);
2908                         ev_document_doc_mutex_unlock ();
2909                 } else {
2910                         ev_document_doc_mutex_lock ();
2911                         ev_document_find_cancel (EV_DOCUMENT_FIND (ev_window->priv->document));
2912                         ev_document_doc_mutex_unlock ();
2913
2914                         ev_window_update_actions (ev_window);
2915                         egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
2916                                                       NULL);
2917                         gtk_widget_queue_draw (GTK_WIDGET (ev_window->priv->view));
2918                 }
2919         }
2920 }
2921
2922 static void
2923 find_bar_scroll(EggFindBar *find_bar, GtkScrollType scroll, EvWindow* ev_window)
2924 {
2925         ev_view_scroll(EV_VIEW(ev_window->priv->view), scroll, FALSE);
2926 }
2927
2928 static void
2929 zoom_control_changed_cb (EphyZoomAction *action,
2930                          float           zoom,
2931                          EvWindow       *ev_window)
2932 {
2933         EvSizingMode mode;
2934         
2935         g_return_if_fail (EV_IS_WINDOW (ev_window));
2936
2937         if (zoom == EPHY_ZOOM_BEST_FIT) {
2938                 mode = EV_SIZING_BEST_FIT;
2939         } else if (zoom == EPHY_ZOOM_FIT_WIDTH) {
2940                 mode = EV_SIZING_FIT_WIDTH;
2941         } else {
2942                 mode = EV_SIZING_FREE;
2943         }
2944         
2945         ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), mode);
2946         
2947         if (mode == EV_SIZING_FREE) {
2948                 ev_view_set_zoom (EV_VIEW (ev_window->priv->view), zoom, FALSE);
2949         }
2950 }
2951
2952 static void
2953 ev_window_finalize (GObject *object)
2954 {
2955         GList *windows = ev_application_get_windows (EV_APP);
2956
2957         if (windows == NULL) {
2958                 ev_application_shutdown (EV_APP);
2959         } else {
2960                 g_list_free (windows);
2961         }
2962         
2963         G_OBJECT_CLASS (ev_window_parent_class)->finalize (object);
2964 }
2965
2966 static void
2967 ev_window_dispose (GObject *object)
2968 {
2969         EvWindow *window = EV_WINDOW (object);
2970         EvWindowPrivate *priv = window->priv;
2971
2972         if (priv->title) {
2973                 ev_window_title_free (priv->title);
2974                 priv->title = NULL;
2975         }
2976
2977         if (priv->recent_view) {
2978                 g_object_unref (priv->recent_view);
2979                 priv->recent_view = NULL;
2980         }
2981
2982         if (priv->ui_manager) {
2983                 g_object_unref (priv->ui_manager);
2984                 priv->ui_manager = NULL;
2985         }
2986
2987         if (priv->action_group) {
2988                 g_object_unref (priv->action_group);
2989                 priv->action_group = NULL;
2990         }
2991
2992         if (priv->view_popup_action_group) {
2993                 g_object_unref (priv->view_popup_action_group);
2994                 priv->view_popup_action_group = NULL;
2995         }
2996
2997         if (priv->attachment_popup_action_group) {
2998                 g_object_unref (priv->attachment_popup_action_group);
2999                 priv->attachment_popup_action_group = NULL;
3000         }
3001
3002         if (priv->page_cache) {
3003                 g_signal_handlers_disconnect_by_func (priv->page_cache, page_changed_cb, window);
3004                 priv->page_cache = NULL;
3005         }
3006
3007         if (priv->document) {
3008                 g_object_unref (priv->document);
3009                 priv->document = NULL;
3010         }
3011         
3012         if (priv->view) {
3013                 g_object_unref (priv->view);
3014                 priv->view = NULL;
3015         }
3016
3017         if (priv->xfer_job) {
3018                 ev_window_clear_xfer_job (window);
3019         }
3020         
3021         if (priv->local_uri) {
3022                 ev_window_clear_local_uri (window);
3023         }
3024         
3025         ev_window_close_dialogs (window);
3026
3027 #ifdef WITH_GTK_PRINT
3028         ev_window_clear_print_job (window);
3029
3030         if (window->priv->gtk_print_job) {
3031                 g_object_unref (window->priv->gtk_print_job);
3032                 window->priv->gtk_print_job = NULL;
3033         }
3034         
3035         if (window->priv->printer) {
3036                 g_object_unref (window->priv->printer);
3037                 window->priv->printer = NULL;
3038         }
3039
3040         if (window->priv->print_settings) {
3041                 g_object_unref (window->priv->print_settings);
3042                 window->priv->print_settings = NULL;
3043         }
3044
3045         if (window->priv->print_page_setup) {
3046                 g_object_unref (window->priv->print_page_setup);
3047                 window->priv->print_page_setup = NULL;
3048         }
3049 #endif
3050
3051         if (priv->link) {
3052                 g_object_unref (priv->link);
3053                 priv->link = NULL;
3054         }
3055
3056         if (priv->attach_list) {
3057                 g_list_foreach (priv->attach_list,
3058                                 (GFunc) g_object_unref,
3059                                 NULL);
3060                 g_list_free (priv->attach_list);
3061                 priv->attach_list = NULL;
3062         }
3063
3064         if (priv->find_bar) {
3065                 g_signal_handlers_disconnect_by_func
3066                         (window->priv->find_bar,
3067                          G_CALLBACK (find_bar_close_cb),
3068                          window);
3069                 priv->find_bar = NULL;
3070         }
3071
3072         if (priv->uri) {
3073                 g_free (priv->uri);
3074                 priv->uri = NULL;
3075         }
3076
3077         if (priv->dest) {
3078                 g_object_unref (priv->dest);
3079                 priv->dest = NULL;
3080         }
3081
3082         if (priv->fullscreen_timeout_id) {
3083                 g_source_remove (priv->fullscreen_timeout_id);
3084                 priv->fullscreen_timeout_id = 0;
3085         }
3086         destroy_fullscreen_popup (window);
3087
3088         G_OBJECT_CLASS (ev_window_parent_class)->dispose (object);
3089 }
3090
3091 static void
3092 ev_window_class_init (EvWindowClass *ev_window_class)
3093 {
3094         GObjectClass *g_object_class = G_OBJECT_CLASS (ev_window_class);
3095         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (ev_window_class);
3096
3097         g_object_class->dispose = ev_window_dispose;
3098         g_object_class->finalize = ev_window_finalize;
3099
3100         widget_class->focus_in_event = ev_window_focus_in_event;
3101         widget_class->focus_out_event = ev_window_focus_out_event;
3102         widget_class->screen_changed = ev_window_screen_changed;
3103
3104         g_type_class_add_private (g_object_class, sizeof (EvWindowPrivate));
3105 }
3106
3107 /* Normal items */
3108 static const GtkActionEntry entries[] = {
3109         { "File", NULL, N_("_File") },
3110         { "Edit", NULL, N_("_Edit") },
3111         { "View", NULL, N_("_View") },
3112         { "Go", NULL, N_("_Go") },
3113         { "Help", NULL, N_("_Help") },
3114
3115         /* File menu */
3116         { "FileOpen", GTK_STOCK_OPEN, N_("_Open..."), "<control>O",
3117           N_("Open an existing document"),
3118           G_CALLBACK (ev_window_cmd_file_open) },
3119         { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy..."), "<control>S",
3120           N_("Save a copy of the current document"),
3121           G_CALLBACK (ev_window_cmd_save_as) },
3122         { "FilePrint", GTK_STOCK_PRINT, N_("_Print..."), "<control>P",
3123           N_("Print this document"),
3124           G_CALLBACK (ev_window_cmd_file_print) },
3125         { "FileProperties", GTK_STOCK_PROPERTIES, N_("P_roperties"), "<alt>Return", NULL,
3126           G_CALLBACK (ev_window_cmd_file_properties) },                       
3127         { "FileCloseWindow", GTK_STOCK_CLOSE, NULL, "<control>W", NULL,
3128           G_CALLBACK (ev_window_cmd_file_close_window) },
3129
3130         /* Edit menu */
3131         { "EditCopy", GTK_STOCK_COPY, NULL, "<control>C", NULL,
3132           G_CALLBACK (ev_window_cmd_edit_copy) },
3133         { "EditSelectAll", NULL, N_("Select _All"), "<control>A", NULL,
3134           G_CALLBACK (ev_window_cmd_edit_select_all) },
3135         { "EditFind", GTK_STOCK_FIND, N_("_Find..."), "<control>F",
3136           N_("Find a word or phrase in the document"),
3137           G_CALLBACK (ev_window_cmd_edit_find) },
3138         { "EditFindNext", NULL, N_("Find Ne_xt"), "<control>G", NULL,
3139           G_CALLBACK (ev_window_cmd_edit_find_next) },
3140         { "EditFindPrevious", NULL, N_("Find Pre_vious"), "<shift><control>G", NULL,
3141           G_CALLBACK (ev_window_cmd_edit_find_previous) },
3142         { "EditToolbar", NULL, N_("T_oolbar"), NULL, NULL,
3143           G_CALLBACK (ev_window_cmd_edit_toolbar) },
3144         { "EditRotateLeft", NULL, N_("Rotate _Left"), NULL, NULL,
3145           G_CALLBACK (ev_window_cmd_edit_rotate_left) },
3146         { "EditRotateRight", NULL, N_("Rotate _Right"), NULL, NULL,
3147           G_CALLBACK (ev_window_cmd_edit_rotate_right) },
3148
3149         /* View menu */
3150         { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus",
3151           N_("Enlarge the document"),
3152           G_CALLBACK (ev_window_cmd_view_zoom_in) },
3153         { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus",
3154           N_("Shrink the document"),
3155           G_CALLBACK (ev_window_cmd_view_zoom_out) },
3156         { "ViewReload", GTK_STOCK_REFRESH, N_("_Reload"), "<control>R",
3157           N_("Reload the document"),
3158           G_CALLBACK (ev_window_cmd_view_reload) },
3159
3160         /* Go menu */
3161         { "GoPreviousPage", GTK_STOCK_GO_BACK, N_("_Previous Page"), "<control>Page_Up",
3162           N_("Go to the previous page"),
3163           G_CALLBACK (ev_window_cmd_go_previous_page) },
3164         { "GoNextPage", GTK_STOCK_GO_FORWARD, N_("_Next Page"), "<control>Page_Down",
3165           N_("Go to the next page"),
3166           G_CALLBACK (ev_window_cmd_go_next_page) },
3167         { "GoFirstPage", GTK_STOCK_GOTO_FIRST, N_("_First Page"), "<control>Home",
3168           N_("Go to the first page"),
3169           G_CALLBACK (ev_window_cmd_go_first_page) },
3170         { "GoLastPage", GTK_STOCK_GOTO_LAST, N_("_Last Page"), "<control>End",
3171           N_("Go to the last page"),
3172           G_CALLBACK (ev_window_cmd_go_last_page) },
3173
3174         /* Help menu */
3175         { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", NULL,
3176           G_CALLBACK (ev_window_cmd_help_contents) },
3177
3178         { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL,
3179           G_CALLBACK (ev_window_cmd_help_about) },
3180
3181         /* Toolbar-only */
3182         { "LeaveFullscreen", EV_STOCK_LEAVE_FULLSCREEN, N_("Leave Fullscreen"), NULL,
3183           N_("Leave fullscreen mode"),
3184           G_CALLBACK (ev_window_cmd_leave_fullscreen) },
3185
3186         /* Accellerators */
3187         { "Escape", NULL, "", "Escape", "",
3188           G_CALLBACK (ev_window_cmd_escape) },
3189         { "Slash", GTK_STOCK_FIND, NULL, "slash", NULL,
3190           G_CALLBACK (ev_window_cmd_edit_find) },
3191         { "PageDown", NULL, "", "Page_Down", NULL,
3192           G_CALLBACK (ev_window_cmd_scroll_forward) },
3193         { "PageUp", NULL, "", "Page_Up", NULL,
3194           G_CALLBACK (ev_window_cmd_scroll_backward) },
3195         { "Space", NULL, "", "space", NULL,
3196           G_CALLBACK (ev_window_cmd_scroll_forward) },
3197         { "ShiftSpace", NULL, "", "<shift>space", NULL,
3198           G_CALLBACK (ev_window_cmd_scroll_backward) },
3199         { "BackSpace", NULL, "", "BackSpace", NULL,
3200           G_CALLBACK (ev_window_cmd_scroll_backward) },
3201         { "ShiftBackSpace", NULL, "", "<shift>BackSpace", NULL,
3202           G_CALLBACK (ev_window_cmd_scroll_forward) },
3203         { "Return", NULL, "", "Return", NULL,
3204           G_CALLBACK (ev_window_cmd_scroll_forward) },
3205         { "ShiftReturn", NULL, "", "<shift>Return", NULL,
3206           G_CALLBACK (ev_window_cmd_scroll_backward) },
3207         { "Plus", GTK_STOCK_ZOOM_IN, NULL, "plus", NULL,
3208           G_CALLBACK (ev_window_cmd_view_zoom_in) },
3209         { "CtrlEqual", GTK_STOCK_ZOOM_IN, NULL, "<control>equal", NULL,
3210           G_CALLBACK (ev_window_cmd_view_zoom_in) },
3211         { "Equal", GTK_STOCK_ZOOM_IN, NULL, "equal", NULL,
3212           G_CALLBACK (ev_window_cmd_view_zoom_in) },
3213         { "Minus", GTK_STOCK_ZOOM_OUT, NULL, "minus", NULL,
3214           G_CALLBACK (ev_window_cmd_view_zoom_out) },
3215         { "FocusPageSelector", NULL, "", "<control>l", NULL,
3216           G_CALLBACK (ev_window_cmd_focus_page_selector) },
3217         { "GoBackwardFast", NULL, "", "<shift>Page_Up", NULL,
3218           G_CALLBACK (ev_window_cmd_go_backward) },
3219         { "GoForwardFast", NULL, "", "<shift>Page_Down", NULL,
3220           G_CALLBACK (ev_window_cmd_go_forward) },
3221         { "KpPlus", GTK_STOCK_ZOOM_IN, NULL, "KP_Add", NULL,
3222           G_CALLBACK (ev_window_cmd_view_zoom_in) },
3223         { "KpMinus", GTK_STOCK_ZOOM_OUT, NULL, "KP_Subtract", NULL,
3224           G_CALLBACK (ev_window_cmd_view_zoom_out) },
3225         { "CtrlKpPlus", GTK_STOCK_ZOOM_IN, NULL, "<control>KP_Add", NULL,
3226           G_CALLBACK (ev_window_cmd_view_zoom_in) },
3227         { "CtrlKpMinus", GTK_STOCK_ZOOM_OUT, NULL, "<control>KP_Subtract", NULL,
3228           G_CALLBACK (ev_window_cmd_view_zoom_out) },
3229 };
3230
3231 /* Toggle items */
3232 static const GtkToggleActionEntry toggle_entries[] = {
3233         /* View Menu */
3234         { "ViewToolbar", NULL, N_("_Toolbar"), "<shift><control>T",
3235           N_("Show or hide the toolbar"),
3236           G_CALLBACK (ev_window_view_toolbar_cb), TRUE },
3237         { "ViewSidebar", GTK_STOCK_INDEX, N_("Side _Pane"), "F9",
3238           N_("Show or hide the side pane"),
3239           G_CALLBACK (ev_window_view_sidebar_cb), TRUE },
3240         { "ViewContinuous", EV_STOCK_VIEW_CONTINUOUS, N_("_Continuous"), NULL,
3241           N_("Show the entire document"),
3242           G_CALLBACK (ev_window_cmd_continuous), TRUE },
3243         { "ViewDual", EV_STOCK_VIEW_DUAL, N_("_Dual"), NULL,
3244           N_("Show two pages at once"),
3245           G_CALLBACK (ev_window_cmd_dual), FALSE },
3246         { "ViewFullscreen", NULL, N_("_Fullscreen"), "F11",
3247           N_("Expand the window to fill the screen"),
3248           G_CALLBACK (ev_window_cmd_view_fullscreen) },
3249         { "ViewPresentation", NULL, N_("_Presentation"), "F5",
3250           N_("Run document as a presentation"),
3251           G_CALLBACK (ev_window_cmd_view_presentation) },
3252         { "ViewBestFit", EV_STOCK_ZOOM_PAGE, N_("_Best Fit"), NULL,
3253           N_("Make the current document fill the window"),
3254           G_CALLBACK (ev_window_cmd_view_best_fit) },
3255         { "ViewPageWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit Page _Width"), NULL,
3256           N_("Make the current document fill the window width"),
3257           G_CALLBACK (ev_window_cmd_view_page_width) },
3258 };
3259
3260 /* Popups specific items */
3261 static const GtkActionEntry view_popup_entries [] = {
3262         /* Links */
3263         { "OpenLink", GTK_STOCK_OPEN, N_("_Open Link"), NULL,
3264           NULL, G_CALLBACK (ev_view_popup_cmd_open_link) },
3265         { "GoLink", GTK_STOCK_GO_FORWARD, N_("_Go To"), NULL,
3266           NULL, G_CALLBACK (ev_view_popup_cmd_open_link) },
3267         { "CopyLinkAddress", NULL, N_("_Copy Link Address"), NULL,
3268           NULL,
3269           G_CALLBACK (ev_view_popup_cmd_copy_link_address) },
3270 };
3271
3272 static const GtkActionEntry attachment_popup_entries [] = {
3273         { "OpenAttachment", GTK_STOCK_OPEN, N_("_Open..."), NULL,
3274           NULL, G_CALLBACK (ev_attachment_popup_cmd_open_attachment) },
3275         { "SaveAttachmentAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy..."), NULL,
3276           NULL, G_CALLBACK (ev_attachment_popup_cmd_save_attachment_as) },
3277 };
3278
3279 static void
3280 drag_data_received_cb (GtkWidget *widget, GdkDragContext *context,
3281                        gint x, gint y, GtkSelectionData *selection_data,
3282                        guint info, guint time, gpointer gdata)
3283 {
3284         GList  *uri_list = NULL;
3285         GSList *uris = NULL;
3286         gchar  *uri;
3287
3288         uri_list = gnome_vfs_uri_list_parse ((gchar *) selection_data->data);
3289
3290         if (uri_list) {
3291                 while (uri_list) {
3292                         uri = gnome_vfs_uri_to_string (uri_list->data, GNOME_VFS_URI_HIDE_NONE);
3293                         uris = g_slist_append (uris, (gpointer) uri);
3294                         
3295                         uri_list = g_list_next (uri_list);
3296                 }
3297
3298                 gnome_vfs_uri_list_free (uri_list);
3299                 
3300                 ev_application_open_uri_list (EV_APP, uris, 0);
3301                 
3302                 g_slist_free (uris);
3303         }
3304 }
3305
3306 static void
3307 activate_link_cb (EvPageAction *page_action, EvLink *link, EvWindow *window)
3308 {
3309         ev_view_handle_link (EV_VIEW (window->priv->view), link);
3310         gtk_widget_grab_focus (window->priv->view);
3311 }
3312
3313 static gboolean
3314 activate_label_cb (EvPageAction *page_action, char *label, EvWindow *window)
3315 {
3316         g_return_val_if_fail (EV_IS_WINDOW (window), FALSE);
3317
3318         gtk_widget_grab_focus (window->priv->view);
3319
3320         return ev_page_cache_set_page_label (window->priv->page_cache, label);
3321 }
3322
3323 static void
3324 register_custom_actions (EvWindow *window, GtkActionGroup *group)
3325 {
3326         GtkAction *action;
3327
3328         action = g_object_new (EV_TYPE_PAGE_ACTION,
3329                                "name", PAGE_SELECTOR_ACTION,
3330                                "label", _("Page"),
3331                                "tooltip", _("Select Page"),
3332                                "visible_overflown", FALSE,
3333                                NULL);
3334         g_signal_connect (action, "activate_link",
3335                           G_CALLBACK (activate_link_cb), window);
3336         g_signal_connect (action, "activate_label",
3337                           G_CALLBACK (activate_label_cb), window);
3338         gtk_action_group_add_action (group, action);
3339         g_object_unref (action);
3340
3341         action = g_object_new (EPHY_TYPE_ZOOM_ACTION,
3342                                "name", ZOOM_CONTROL_ACTION,
3343                                "label", _("Zoom"),
3344                                "stock_id", GTK_STOCK_ZOOM_IN,
3345                                "tooltip", _("Adjust the zoom level"),
3346                                "zoom", 1.0,
3347                                NULL);
3348         g_signal_connect (action, "zoom_to_level",
3349                           G_CALLBACK (zoom_control_changed_cb), window);
3350         gtk_action_group_add_action (group, action);
3351         g_object_unref (action);
3352 }
3353
3354 static void
3355 set_action_properties (GtkActionGroup *action_group)
3356 {
3357         GtkAction *action;
3358
3359         action = gtk_action_group_get_action (action_group, "GoPreviousPage");
3360         /*translators: this is the label for toolbar button*/
3361         g_object_set (action, "short_label", _("Previous"), NULL);
3362         g_object_set (action, "is-important", TRUE, NULL);
3363
3364         action = gtk_action_group_get_action (action_group, "GoNextPage");
3365         g_object_set (action, "is-important", TRUE, NULL);
3366         /*translators: this is the label for toolbar button*/
3367         g_object_set (action, "short_label", _("Next"), NULL);
3368
3369         action = gtk_action_group_get_action (action_group, "ViewZoomIn");
3370         /*translators: this is the label for toolbar button*/
3371         g_object_set (action, "short_label", _("Zoom In"), NULL);
3372         action = gtk_action_group_get_action (action_group, "ViewZoomIn");
3373
3374         action = gtk_action_group_get_action (action_group, "ViewZoomOut");
3375         /*translators: this is the label for toolbar button*/
3376         g_object_set (action, "short_label", _("Zoom Out"), NULL);
3377         action = gtk_action_group_get_action (action_group, "ViewZoomIn");
3378
3379         action = gtk_action_group_get_action (action_group, "ViewBestFit");
3380         /*translators: this is the label for toolbar button*/
3381         g_object_set (action, "short_label", _("Best Fit"), NULL);
3382         action = gtk_action_group_get_action (action_group, "ViewZoomIn");
3383
3384         action = gtk_action_group_get_action (action_group, "ViewPageWidth");
3385         /*translators: this is the label for toolbar button*/
3386         g_object_set (action, "short_label", _("Fit Width"), NULL);
3387         action = gtk_action_group_get_action (action_group, "ViewZoomIn");
3388
3389         action = gtk_action_group_get_action (action_group, "LeaveFullscreen");
3390         g_object_set (action, "is-important", TRUE, NULL);
3391 }
3392
3393 static void
3394 set_chrome_actions (EvWindow *window)
3395 {
3396         EvWindowPrivate *priv = window->priv;
3397         GtkActionGroup *action_group = priv->action_group;
3398         GtkAction *action;
3399
3400         action= gtk_action_group_get_action (action_group, "ViewToolbar");
3401         g_signal_handlers_block_by_func
3402                 (action, G_CALLBACK (ev_window_view_toolbar_cb), window);
3403         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
3404                                       (priv->chrome & EV_CHROME_TOOLBAR) != 0);
3405         g_signal_handlers_unblock_by_func
3406                 (action, G_CALLBACK (ev_window_view_toolbar_cb), window);
3407 }
3408
3409 static void
3410 sidebar_widget_model_set (EvSidebarLinks *ev_sidebar_links,
3411                           GParamSpec     *pspec,
3412                           EvWindow       *ev_window)
3413 {
3414         GtkTreeModel *model;
3415         GtkAction *action;
3416
3417         g_object_get (G_OBJECT (ev_sidebar_links),
3418                       "model", &model,
3419                       NULL);
3420
3421         action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
3422         ev_page_action_set_model (EV_PAGE_ACTION (action), model);
3423         g_object_unref (model);
3424 }
3425
3426 static gboolean
3427 view_actions_focus_in_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *window)
3428 {
3429         update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, FALSE);
3430         ev_window_set_action_sensitive (window, "ViewToolbar", TRUE);
3431
3432         ev_window_set_view_accels_sensitivity (window, TRUE);
3433
3434         return FALSE;
3435 }
3436
3437 static gboolean
3438 view_actions_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *window)
3439 {
3440         ev_window_set_view_accels_sensitivity (window, FALSE);
3441
3442         return FALSE;
3443 }
3444
3445 static void
3446 sidebar_page_main_widget_update_cb (GObject *ev_sidebar_page,
3447                                     GParamSpec         *pspec,
3448                                     EvWindow           *ev_window)
3449 {
3450         GtkWidget *widget;
3451         
3452         g_object_get (ev_sidebar_page, "main_widget", &widget, NULL);
3453
3454         if (widget != NULL) {           
3455                 g_signal_connect_object (widget, "focus_in_event",
3456                                          G_CALLBACK (view_actions_focus_in_cb),
3457                                          ev_window, 0);
3458                 g_signal_connect_object (widget, "focus_out_event",
3459                                          G_CALLBACK (view_actions_focus_out_cb),
3460                                          ev_window, 0);
3461                 g_object_unref (widget);
3462         }
3463 }
3464
3465 static gboolean
3466 window_state_event_cb (EvWindow *window, GdkEventWindowState *event, gpointer dummy)
3467 {
3468         if (!(event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
3469                 gboolean maximized;
3470
3471                 maximized = event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED;
3472                 if (!ev_window_is_empty (window))
3473                         ev_metadata_manager_set_boolean (window->priv->uri, "window_maximized", maximized);
3474         }
3475
3476         return FALSE;
3477 }
3478
3479 static gboolean
3480 window_configure_event_cb (EvWindow *window, GdkEventConfigure *event, gpointer dummy)
3481 {
3482         char *uri = window->priv->uri;
3483         GdkWindowState state;
3484         int x, y, width, height;
3485
3486         state = gdk_window_get_state (GTK_WIDGET (window)->window);
3487
3488         if (!(state & GDK_WINDOW_STATE_FULLSCREEN)) {
3489                 gtk_window_get_position (GTK_WINDOW (window), &x, &y);
3490                 gtk_window_get_size (GTK_WINDOW (window), &width, &height);
3491
3492                 if (!ev_window_is_empty (window)) {
3493                         ev_metadata_manager_set_int (uri, "window_x", x);
3494                         ev_metadata_manager_set_int (uri, "window_y", y);
3495                         ev_metadata_manager_set_int (uri, "window_width", width);
3496                         ev_metadata_manager_set_int (uri, "window_height", height);
3497                 }
3498         }
3499
3500         return FALSE;
3501 }
3502
3503 static void
3504 sidebar_links_link_activated_cb (EvSidebarLinks *sidebar_links, EvLink *link, EvWindow *window)
3505 {
3506         ev_view_handle_link (EV_VIEW (window->priv->view), link);
3507 }
3508
3509 static void
3510 launch_action (EvWindow *window, EvLinkAction *action)
3511 {
3512         const char *filename = ev_link_action_get_filename (action);
3513         char *uri = NULL;
3514
3515         if (filename  && g_path_is_absolute (filename)) {
3516                 uri = gnome_vfs_get_uri_from_local_path (filename);
3517         } else {
3518                 GnomeVFSURI *base_uri, *resolved_uri;
3519
3520                 base_uri = gnome_vfs_uri_new (window->priv->uri);
3521                 if (base_uri && filename) {
3522                         resolved_uri = gnome_vfs_uri_resolve_relative (base_uri, filename);     
3523                         if (resolved_uri) {
3524                                 uri = gnome_vfs_uri_to_string (resolved_uri, GNOME_VFS_URI_HIDE_NONE);
3525                                 gnome_vfs_uri_unref (resolved_uri);
3526                         }
3527                         gnome_vfs_uri_unref (base_uri);
3528                 }
3529         }
3530
3531         if (uri) {
3532                 gnome_vfs_url_show (uri);
3533         } else {
3534                 gnome_vfs_url_show (filename);
3535         }
3536
3537         g_free (uri);
3538
3539         /* According to the PDF spec filename can be an executable. I'm not sure
3540            allowing to launch executables is a good idea though. -- marco */
3541 }
3542
3543 static void
3544 launch_external_uri (EvWindow *window, EvLinkAction *action)
3545 {
3546         const char *uri;
3547         char *escaped;
3548
3549         uri = ev_link_action_get_uri (action);
3550         escaped = gnome_vfs_escape_host_and_path_string (uri);
3551
3552         gnome_vfs_url_show (escaped);
3553         g_free (escaped);
3554 }
3555
3556 static void
3557 open_remote_link (EvWindow *window, EvLinkAction *action)
3558 {
3559         gchar *uri;
3560         gchar *dir;
3561
3562         dir = g_path_get_dirname (window->priv->uri);
3563         
3564         uri = g_build_filename (dir, ev_link_action_get_filename (action),
3565                                 NULL);
3566         g_free (dir);
3567         
3568         ev_application_open_uri_at_dest (EV_APP, uri,
3569                                          ev_link_action_get_dest (action),
3570                                          0,
3571                                          GDK_CURRENT_TIME);
3572
3573         g_free (uri);
3574 }
3575
3576 static void
3577 do_action_named (EvWindow *window, EvLinkAction *action)
3578 {
3579         const gchar *name = ev_link_action_get_name (action);
3580
3581         if (g_ascii_strcasecmp (name, "FirstPage") == 0) {
3582                 ev_window_cmd_go_first_page (NULL, window);
3583         } else if (g_ascii_strcasecmp (name, "PrevPage") == 0) {
3584                 ev_window_cmd_go_previous_page (NULL, window);
3585         } else if (g_ascii_strcasecmp (name, "NextPage") == 0) {
3586                 ev_window_cmd_go_next_page (NULL, window);
3587         } else if (g_ascii_strcasecmp (name, "LastPage") == 0) {
3588                 ev_window_cmd_go_last_page (NULL, window);
3589         } else if (g_ascii_strcasecmp (name, "GoToPage") == 0) {
3590                 ev_window_cmd_focus_page_selector (NULL, window);
3591         } else if (g_ascii_strcasecmp (name, "Find") == 0) {
3592                 ev_window_cmd_edit_find (NULL, window);
3593         } else {
3594                 g_warning ("Unimplemented named action: %s, please post a "
3595                            "bug report in Evince bugzilla "
3596                            "(http://bugzilla.gnome.org) with a testcase.",
3597                            name);
3598         }
3599 }
3600
3601 static void
3602 view_external_link_cb (EvView *view, EvLinkAction *action, EvWindow *window)
3603 {
3604         switch (ev_link_action_get_action_type (action)) {
3605                 case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
3606                         launch_external_uri (window, action);
3607                         break;
3608                 case EV_LINK_ACTION_TYPE_LAUNCH:
3609                         launch_action (window, action);
3610                         break;
3611                 case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
3612                         open_remote_link (window, action);
3613                         break;
3614                 case EV_LINK_ACTION_TYPE_NAMED:
3615                         do_action_named (window, action);
3616                         break;
3617                 default:
3618                         g_assert_not_reached ();
3619         }
3620 }
3621
3622 static void
3623 ev_view_popup_cmd_open_link (GtkAction *action, EvWindow *window)
3624 {
3625         ev_view_handle_link (EV_VIEW (window->priv->view), window->priv->link);
3626 }
3627
3628 static void
3629 ev_view_popup_cmd_copy_link_address (GtkAction *action, EvWindow *window)
3630 {
3631         GtkClipboard *clipboard;
3632         EvLinkAction *ev_action;
3633         const gchar *uri;
3634
3635         ev_action = ev_link_get_action (window->priv->link);
3636         if (!ev_action)
3637                 return;
3638
3639         uri = ev_link_action_get_uri (ev_action);
3640
3641         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window),
3642                                               GDK_SELECTION_CLIPBOARD);
3643         gtk_clipboard_set_text (clipboard, uri, -1);
3644 }
3645
3646 static void
3647 ev_attachment_popup_cmd_open_attachment (GtkAction *action, EvWindow *window)
3648 {
3649         GList *l;
3650         
3651         if (!window->priv->attach_list)
3652                 return;
3653
3654         for (l = window->priv->attach_list; l && l->data; l = g_list_next (l)) {
3655                 EvAttachment *attachment;
3656                 GError       *error = NULL;
3657                 
3658                 attachment = (EvAttachment *) l->data;
3659                 
3660                 ev_attachment_open (attachment, &error);
3661
3662                 if (error) {
3663                         ev_window_error_dialog (GTK_WINDOW (window),
3664                                                 _("Unable to open attachment"),
3665                                                 error);
3666                         g_error_free (error);
3667                 }
3668         }
3669 }
3670
3671 static void
3672 attachment_save_dialog_response_cb (GtkWidget *fc,
3673                                     gint       response_id,
3674                                     EvWindow  *ev_window)
3675 {
3676         gchar                *uri;
3677         GList                *l;
3678         GtkFileChooserAction  fc_action;
3679         gboolean              is_dir;
3680         
3681         if (response_id != GTK_RESPONSE_OK) {
3682                 gtk_widget_destroy (fc);
3683                 return;
3684         }
3685
3686         uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
3687         
3688         g_object_get (G_OBJECT (fc), "action", &fc_action, NULL);
3689         is_dir = (fc_action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
3690         
3691         for (l = ev_window->priv->attach_list; l && l->data; l = g_list_next (l)) {
3692                 EvAttachment *attachment;
3693                 gchar        *filename;
3694                 GError       *error = NULL;
3695                 
3696                 attachment = (EvAttachment *) l->data;
3697
3698                 if (is_dir) {
3699                         filename = g_strjoin ("/", uri,
3700                                               ev_attachment_get_name (attachment),
3701                                               NULL);
3702                 } else {
3703                         filename = g_strdup (uri);
3704                 }
3705                 
3706                 ev_attachment_save (attachment, filename, &error);
3707                 g_free (filename);
3708                 
3709                 if (error) {
3710                         ev_window_error_dialog (GTK_WINDOW (fc),
3711                                                 _("The attachment could not be saved."),
3712                                                 error);
3713                         g_error_free (error);
3714                 }
3715         }
3716
3717         g_free (uri);
3718
3719         gtk_widget_destroy (fc);
3720 }
3721
3722 static void
3723 ev_attachment_popup_cmd_save_attachment_as (GtkAction *action, EvWindow *window)
3724 {
3725         GtkWidget    *fc;
3726         EvAttachment *attachment = NULL;
3727
3728         if (!window->priv->attach_list)
3729                 return;
3730
3731         if (g_list_length (window->priv->attach_list) == 1)
3732                 attachment = (EvAttachment *) window->priv->attach_list->data;
3733         
3734         fc = gtk_file_chooser_dialog_new (
3735                 _("Save a Copy"),
3736                 GTK_WINDOW (window),
3737                 attachment ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
3738                 GTK_STOCK_CANCEL,
3739                 GTK_RESPONSE_CANCEL,
3740                 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
3741                 NULL);
3742
3743         gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK);
3744         gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (fc), TRUE);
3745
3746         if (attachment)
3747                 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (fc),
3748                                                    ev_attachment_get_name (attachment));
3749
3750         g_signal_connect (fc, "response",
3751                           G_CALLBACK (attachment_save_dialog_response_cb),
3752                           window);
3753
3754         gtk_widget_show (fc);
3755 }
3756
3757 static void
3758 ev_window_init (EvWindow *ev_window)
3759 {
3760         GtkActionGroup *action_group;
3761         GtkAccelGroup *accel_group;
3762         GError *error = NULL;
3763         GtkWidget *sidebar_widget, *toolbar_dock;
3764
3765         g_signal_connect (ev_window, "configure_event",
3766                           G_CALLBACK (window_configure_event_cb), NULL);
3767         g_signal_connect (ev_window, "window_state_event",
3768                           G_CALLBACK (window_state_event_cb), NULL);
3769
3770         ev_window->priv = EV_WINDOW_GET_PRIVATE (ev_window);
3771
3772         ev_window->priv->page_mode = PAGE_MODE_DOCUMENT;
3773         ev_window->priv->title = ev_window_title_new (ev_window);
3774
3775         ev_window->priv->main_box = gtk_vbox_new (FALSE, 0);
3776         gtk_container_add (GTK_CONTAINER (ev_window), ev_window->priv->main_box);
3777         gtk_widget_show (ev_window->priv->main_box);
3778
3779         action_group = gtk_action_group_new ("MenuActions");
3780         ev_window->priv->action_group = action_group;
3781         gtk_action_group_set_translation_domain (action_group, NULL);
3782         gtk_action_group_add_actions (action_group, entries,
3783                                       G_N_ELEMENTS (entries), ev_window);
3784         gtk_action_group_add_toggle_actions (action_group, toggle_entries,
3785                                              G_N_ELEMENTS (toggle_entries),
3786                                              ev_window);
3787         set_action_properties (action_group);
3788         register_custom_actions (ev_window, action_group);
3789
3790         ev_window->priv->ui_manager = gtk_ui_manager_new ();
3791         gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
3792                                             action_group, 0);
3793
3794         accel_group =
3795                 gtk_ui_manager_get_accel_group (ev_window->priv->ui_manager);
3796         gtk_window_add_accel_group (GTK_WINDOW (ev_window), accel_group);
3797
3798         ev_window_set_view_accels_sensitivity (ev_window, FALSE);
3799
3800         action_group = gtk_action_group_new ("ViewPopupActions");
3801         ev_window->priv->view_popup_action_group = action_group;
3802         gtk_action_group_set_translation_domain (action_group, NULL);
3803         gtk_action_group_add_actions (action_group, view_popup_entries,
3804                                       G_N_ELEMENTS (view_popup_entries),
3805                                       ev_window);
3806         gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
3807                                             action_group, 0);
3808
3809         action_group = gtk_action_group_new ("AttachmentPopupActions");
3810         ev_window->priv->attachment_popup_action_group = action_group;
3811         gtk_action_group_set_translation_domain (action_group, NULL);
3812         gtk_action_group_add_actions (action_group, attachment_popup_entries,
3813                                       G_N_ELEMENTS (attachment_popup_entries),
3814                                       ev_window);
3815         gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
3816                                             action_group, 0);
3817
3818         if (!gtk_ui_manager_add_ui_from_file (ev_window->priv->ui_manager,
3819                                               DATADIR"/evince-ui.xml",
3820                                               &error)) {
3821                 g_warning ("building menus failed: %s", error->message);
3822                 g_error_free (error);
3823         }
3824
3825         ev_window->priv->menubar =
3826                  gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
3827                                             "/MainMenu");
3828         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box),
3829                             ev_window->priv->menubar,
3830                             FALSE, FALSE, 0);
3831
3832         /* This sucks, but there is no way to have a draw=no, expand=true separator
3833          * in a GtkUIManager-built toolbar. So, just add another toolbar.
3834          * See gtk+ bug 166489.
3835          */
3836         toolbar_dock = ev_window->priv->toolbar_dock = gtk_hbox_new (FALSE, 0);
3837         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), toolbar_dock,
3838                             FALSE, FALSE, 0);
3839         gtk_widget_show (toolbar_dock);
3840
3841         ev_window->priv->toolbar = egg_editable_toolbar_new_with_model
3842                                 (ev_window->priv->ui_manager, ev_application_get_toolbars_model (EV_APP), NULL);
3843         egg_editable_toolbar_show (EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar),
3844                                    "DefaultToolBar");
3845         gtk_box_pack_start (GTK_BOX (toolbar_dock), ev_window->priv->toolbar,
3846                             TRUE, TRUE, 0);
3847         gtk_widget_show (ev_window->priv->toolbar);
3848
3849         /* Add the main area */
3850         ev_window->priv->hpaned = gtk_hpaned_new ();
3851         g_signal_connect (ev_window->priv->hpaned,
3852                           "notify::position",
3853                           G_CALLBACK (ev_window_sidebar_position_change_cb),
3854                           ev_window);
3855         
3856         gtk_paned_set_position (GTK_PANED (ev_window->priv->hpaned), SIDEBAR_DEFAULT_SIZE);
3857         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), ev_window->priv->hpaned,
3858                             TRUE, TRUE, 0);
3859         gtk_widget_show (ev_window->priv->hpaned);
3860         
3861         ev_window->priv->sidebar = ev_sidebar_new ();
3862         gtk_paned_pack1 (GTK_PANED (ev_window->priv->hpaned),
3863                          ev_window->priv->sidebar, FALSE, FALSE);
3864         gtk_widget_show (ev_window->priv->sidebar);
3865
3866         /* Stub sidebar, for now */
3867
3868         sidebar_widget = ev_sidebar_links_new ();
3869         ev_window->priv->sidebar_links = sidebar_widget;
3870         g_signal_connect (sidebar_widget,
3871                           "notify::model",
3872                           G_CALLBACK (sidebar_widget_model_set),
3873                           ev_window);
3874         g_signal_connect (sidebar_widget,
3875                           "link_activated",
3876                           G_CALLBACK (sidebar_links_link_activated_cb),
3877                           ev_window);
3878         sidebar_page_main_widget_update_cb (G_OBJECT (sidebar_widget), NULL, ev_window);
3879         gtk_widget_show (sidebar_widget);
3880         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
3881                              sidebar_widget);
3882
3883         sidebar_widget = ev_sidebar_attachments_new ();
3884         ev_window->priv->sidebar_attachments = sidebar_widget;
3885         g_signal_connect_object (sidebar_widget,
3886                                  "popup",
3887                                  G_CALLBACK (attachment_bar_menu_popup_cb),
3888                                  ev_window, 0);
3889         gtk_widget_show (sidebar_widget);
3890         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
3891                              sidebar_widget);
3892
3893         sidebar_widget = ev_sidebar_thumbnails_new ();
3894         ev_window->priv->sidebar_thumbs = sidebar_widget;
3895         g_signal_connect (sidebar_widget,
3896                           "notify::main-widget",
3897                           G_CALLBACK (sidebar_page_main_widget_update_cb),
3898                           ev_window);
3899         sidebar_page_main_widget_update_cb (G_OBJECT (sidebar_widget), NULL, ev_window);
3900         gtk_widget_show (sidebar_widget);
3901         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
3902                              sidebar_widget);
3903
3904         ev_window->priv->scrolled_window =
3905                 GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
3906                                           "shadow-type", GTK_SHADOW_IN,
3907                                           NULL));
3908         gtk_widget_show (ev_window->priv->scrolled_window);
3909
3910         gtk_paned_add2 (GTK_PANED (ev_window->priv->hpaned),
3911                         ev_window->priv->scrolled_window);
3912
3913         ev_window->priv->view = ev_view_new ();
3914         ev_window->priv->password_view = ev_password_view_new ();
3915         g_signal_connect_swapped (ev_window->priv->password_view,
3916                                   "unlock",
3917                                   G_CALLBACK (ev_window_popup_password_dialog),
3918                                   ev_window);
3919         g_signal_connect_object (ev_window->priv->view, "focus_in_event",
3920                                  G_CALLBACK (view_actions_focus_in_cb),
3921                                  ev_window, 0);
3922         g_signal_connect_object (ev_window->priv->view, "focus_out_event",
3923                                  G_CALLBACK (view_actions_focus_out_cb),
3924                                  ev_window, 0);
3925         g_signal_connect_object (ev_window->priv->view, "external-link",
3926                                  G_CALLBACK (view_external_link_cb),
3927                                  ev_window, 0);
3928         g_signal_connect_object (ev_window->priv->view,
3929                                  "popup",
3930                                  G_CALLBACK (view_menu_popup_cb),
3931                                  ev_window, 0);
3932         gtk_widget_show (ev_window->priv->view);
3933         gtk_widget_show (ev_window->priv->password_view);
3934
3935         /* Find Bar */
3936         ev_window->priv->find_bar = egg_find_bar_new ();
3937         gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
3938                           ev_window->priv->find_bar,
3939                           FALSE, TRUE, 0);
3940
3941         /* We own a ref on these widgets, as we can swap them in and out */
3942         g_object_ref (ev_window->priv->view);
3943         g_object_ref (ev_window->priv->password_view);
3944
3945         gtk_container_add (GTK_CONTAINER (ev_window->priv->scrolled_window),
3946                            ev_window->priv->view);
3947
3948         g_signal_connect (ev_window->priv->view,
3949                           "notify::find-status",
3950                           G_CALLBACK (view_find_status_changed_cb),
3951                           ev_window);
3952         g_signal_connect (ev_window->priv->view,
3953                           "notify::sizing-mode",
3954                           G_CALLBACK (ev_window_sizing_mode_changed_cb),
3955                           ev_window);
3956         g_signal_connect (ev_window->priv->view,
3957                           "notify::zoom",
3958                           G_CALLBACK (ev_window_zoom_changed_cb),
3959                           ev_window);
3960         g_signal_connect (ev_window->priv->view,
3961                           "notify::dual-page",
3962                           G_CALLBACK (ev_window_dual_mode_changed_cb),
3963                           ev_window);
3964         g_signal_connect (ev_window->priv->view,
3965                           "notify::continuous",
3966                           G_CALLBACK (ev_window_continuous_changed_cb),
3967                           ev_window);
3968         g_signal_connect (ev_window->priv->view,
3969                           "notify::rotation",
3970                           G_CALLBACK (ev_window_rotation_changed_cb),
3971                           ev_window);
3972         g_signal_connect (ev_window->priv->view,
3973                           "notify::has-selection",
3974                           G_CALLBACK (ev_window_has_selection_changed_cb),
3975                           ev_window);
3976
3977         /* Connect sidebar signals */
3978         g_signal_connect (ev_window->priv->sidebar,
3979                           "notify::visible",
3980                           G_CALLBACK (ev_window_sidebar_visibility_changed_cb),
3981                           ev_window);
3982         g_signal_connect (ev_window->priv->sidebar,
3983                           "notify::current-page",
3984                           G_CALLBACK (ev_window_sidebar_current_page_changed_cb),
3985                           ev_window);
3986
3987         /* Connect to find bar signals */
3988         g_signal_connect (ev_window->priv->find_bar,
3989                           "previous",
3990                           G_CALLBACK (find_bar_previous_cb),
3991                           ev_window);
3992         g_signal_connect (ev_window->priv->find_bar,
3993                           "next",
3994                           G_CALLBACK (find_bar_next_cb),
3995                           ev_window);
3996         g_signal_connect (ev_window->priv->find_bar,
3997                           "close",
3998                           G_CALLBACK (find_bar_close_cb),
3999                           ev_window);
4000         g_signal_connect (ev_window->priv->find_bar,
4001                           "notify::search-string",
4002                           G_CALLBACK (find_bar_search_changed_cb),
4003                           ev_window);
4004         g_signal_connect (ev_window->priv->find_bar,
4005                           "notify::case-sensitive",
4006                           G_CALLBACK (find_bar_search_changed_cb),
4007                           ev_window);
4008         g_signal_connect (ev_window->priv->find_bar,
4009                           "notify::visible",
4010                           G_CALLBACK (find_bar_search_changed_cb),
4011                           ev_window);
4012         g_signal_connect (ev_window->priv->find_bar,
4013                           "scroll",
4014                           G_CALLBACK (find_bar_scroll),
4015                           ev_window);
4016
4017         /* Popups */
4018         ev_window->priv->view_popup = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
4019                                                                  "/DocumentPopup");
4020         ev_window->priv->link = NULL;
4021
4022         ev_window->priv->attachment_popup = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
4023                                                                        "/AttachmentPopup");
4024         ev_window->priv->attach_list = NULL;
4025
4026         /* Give focus to the document view */
4027         gtk_widget_grab_focus (ev_window->priv->view);
4028
4029         /* Drag and Drop */
4030         gtk_drag_dest_unset (GTK_WIDGET (ev_window->priv->view));
4031         gtk_drag_dest_set (GTK_WIDGET (ev_window->priv->view),
4032                            GTK_DEST_DEFAULT_ALL,
4033                            ev_drop_types,
4034                            sizeof (ev_drop_types) / sizeof (ev_drop_types[0]),
4035                            GDK_ACTION_COPY);
4036         g_signal_connect_swapped (G_OBJECT (ev_window->priv->view), "drag-data-received",
4037                                   G_CALLBACK (drag_data_received_cb),
4038                                   ev_window);
4039         
4040         /* Set it user interface params */
4041
4042         ev_window_setup_recent (ev_window);
4043
4044         setup_chrome_from_metadata (ev_window);
4045         set_chrome_actions (ev_window);
4046         update_chrome_visibility (ev_window);
4047
4048         gtk_window_set_default_size (GTK_WINDOW (ev_window), 600, 600);
4049
4050         setup_view_from_metadata (ev_window);
4051         setup_sidebar_from_metadata (ev_window, NULL);
4052
4053         ev_window_sizing_mode_changed_cb (EV_VIEW (ev_window->priv->view), NULL, ev_window);
4054         ev_window_setup_action_sensitivity (ev_window);
4055 }
4056
4057 GtkWidget *
4058 ev_window_new (void)
4059 {
4060         GtkWidget *ev_window;
4061
4062         ev_window = GTK_WIDGET (g_object_new (EV_TYPE_WINDOW,
4063                                               "type", GTK_WINDOW_TOPLEVEL,
4064                                               NULL));
4065
4066         return ev_window;
4067 }