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