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