]> www.fi.muni.cz Git - evince.git/blob - shell/ev-window.c
Add pixbuf backend.
[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-sidebar.h"
33 #include "ev-sidebar-bookmarks.h"
34 #include "ev-sidebar-thumbnails.h"
35 #include "ev-view.h"
36 #include "eggfindbar.h"
37
38 #include "pdf-document.h"
39 #include "pixbuf-document.h"
40 #include "gtkgs.h"
41
42 #include <glib/gi18n.h>
43 #include <gtk/gtk.h>
44 #include <libgnomevfs/gnome-vfs-mime-utils.h>
45
46 #include <string.h>
47
48 #include "ev-application.h"
49 #include "ev-stock-icons.h"
50
51 enum {
52         PROP_0,
53         PROP_ATTRIBUTE
54 };
55
56 enum {
57         SIGNAL,
58         N_SIGNALS
59 };
60
61 struct _EvWindowPrivate {
62         GtkWidget *main_box;
63         GtkWidget *hpaned;
64         GtkWidget *sidebar;
65         GtkWidget *find_bar;
66         GtkWidget *view;
67         GtkActionGroup *action_group;
68         GtkUIManager *ui_manager;
69         GtkWidget *statusbar;
70         guint help_message_cid;
71         GtkWidget *exit_fullscreen_popup;
72
73         EvDocument *document;
74
75         gboolean fullscreen_mode;
76 };
77
78 #if 0
79 /* enable these to add support for signals */
80 static guint ev_window_signals [N_SIGNALS] = { 0 };
81 #endif
82
83 static GObjectClass *parent_class = NULL;
84
85 G_DEFINE_TYPE (EvWindow, ev_window, GTK_TYPE_WINDOW)
86
87 #define EV_WINDOW_GET_PRIVATE(object) \
88         (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_WINDOW, EvWindowPrivate))
89
90 #if 0
91 const char *
92 ev_window_get_attribute (EvWindow *self)
93 {
94         g_return_val_if_fail (self != NULL && EV_IS_WINDOW (self), NULL);
95         
96         return self->priv->attribute;
97 }
98
99 void
100 ev_window_set_attribute (EvWindow* self, const char *attribute)
101 {
102         g_assert (self != NULL && EV_IS_WINDOW (self));
103         g_assert (attribute != NULL);
104
105         if (self->priv->attribute != NULL) {
106                 g_free (self->priv->attribute);
107         }
108
109         self->priv->attribute = g_strdup (attribute);
110
111         g_object_notify (G_OBJECT (self), "attribute");
112 }
113
114 static void
115 ev_window_get_property (GObject *object, guint prop_id, GValue *value,
116                         GParamSpec *param_spec)
117 {
118         EvWindow *self;
119
120         self = EV_WINDOW (object);
121
122         switch (prop_id) {
123         case PROP_ATTRIBUTE:
124                 g_value_set_string (value, self->priv->attribute);
125                 break;
126         default:
127                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
128                                                    prop_id,
129                                                    param_spec);
130                 break;
131         }
132 }
133
134 static void
135 ev_window_set_property (GObject *object, guint prop_id, const GValue *value,
136                         GParamSpec *param_spec)
137 {
138         EvWindow *self;
139         
140         self = EV_WINDOW (object);
141         
142         switch (prop_id) {
143         case PROP_ATTRIBUTE:
144                 ev_window_set_attribute (self, g_value_get_string (value));
145                 break;
146         default:
147                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
148                                                    prop_id,
149                                                    param_spec);
150                 break;
151         }
152 }
153 #endif
154
155 static void
156 set_action_sensitive (EvWindow   *ev_window,
157                       const char *name,
158                       gboolean    sensitive)
159 {
160         GtkAction *action = gtk_action_group_get_action (ev_window->priv->action_group,
161                                                          name);
162         gtk_action_set_sensitive (action, sensitive);
163 }
164
165 static void
166 update_action_sensitivity (EvWindow *ev_window)
167 {
168         int n_pages;
169         int page;
170
171         if (ev_window->priv->document)
172                 n_pages = ev_document_get_n_pages (ev_window->priv->document);
173         else
174                 n_pages = 1;
175
176         page = ev_view_get_page (EV_VIEW (ev_window->priv->view));
177
178         set_action_sensitive (ev_window, "GoFirstPage", page > 1);
179         set_action_sensitive (ev_window, "GoPreviousPage", page > 1);
180         set_action_sensitive (ev_window, "GoNextPage", page < n_pages);
181         set_action_sensitive (ev_window, "GoLastPage", page < n_pages);
182 }
183
184 gboolean
185 ev_window_is_empty (const EvWindow *ev_window)
186 {
187         g_return_val_if_fail (EV_IS_WINDOW (ev_window), FALSE);
188         
189         return ev_window->priv->document == NULL;
190 }
191
192 static void
193 unable_to_load (EvWindow   *ev_window,
194                 const char *error_message)
195 {
196         GtkWidget *dialog;
197
198         dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
199                                          GTK_DIALOG_DESTROY_WITH_PARENT,
200                                          GTK_MESSAGE_ERROR,
201                                          GTK_BUTTONS_CLOSE,
202                                          _("Unable to open document"));
203         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
204                                                   "%s", error_message);
205         gtk_dialog_run (GTK_DIALOG (dialog));
206         gtk_widget_destroy (dialog);
207 }
208
209 /* Would be nice to have this in gdk-pixbuf */
210 static gboolean
211 mime_type_supported_by_gdk_pixbuf (const gchar *mime_type)
212 {
213         GSList *formats, *list;
214         gboolean retval = FALSE;
215         
216         formats = gdk_pixbuf_get_formats ();
217         
218         list = formats;
219         while (list) {
220                 GdkPixbufFormat *format = list->data;
221                 int i;
222                 gchar **mime_types;
223                 
224                 if (gdk_pixbuf_format_is_disabled (format))
225                         continue;
226
227                 mime_types = gdk_pixbuf_format_get_mime_types (format);
228                 
229                 for (i = 0; mime_types[i] != NULL; i++) {
230                         if (strcmp (mime_types[i], mime_type) == 0) {
231                                 retval = TRUE;
232                                 break;
233                         }
234                 }
235                 
236                 if (retval)
237                         break;
238                 
239                 list = list->next;
240         }
241         
242         g_slist_free (formats);
243
244         return retval;
245 }
246
247 void
248 ev_window_open (EvWindow *ev_window, const char *uri)
249 {
250         EvDocument *document = NULL;
251         char *mime_type;
252
253         mime_type = gnome_vfs_get_mime_type (uri);
254
255         if (!strcmp (mime_type, "application/pdf"))
256                 document = g_object_new (PDF_TYPE_DOCUMENT, NULL);
257         else if (!strcmp (mime_type, "application/postscript"))
258                 document = g_object_new (GTK_GS_TYPE, NULL);
259         else if (mime_type_supported_by_gdk_pixbuf (mime_type))
260                 document = g_object_new (PIXBUF_TYPE_DOCUMENT, NULL);
261         
262         if (document) {
263                 GError *error = NULL;
264
265                 if (ev_document_load (document, uri, &error)) {
266                         if (ev_window->priv->document)
267                                 g_object_unref (ev_window->priv->document);
268                         ev_window->priv->document = document;
269
270                         ev_view_set_document (EV_VIEW (ev_window->priv->view),
271                                               document);
272
273                         update_action_sensitivity (ev_window);
274                 
275                 } else {
276                         g_assert (error != NULL);
277                         g_object_unref (document);
278                         unable_to_load (ev_window, error->message);
279                         g_error_free (error);
280                 }
281         } else {
282                 char *error_message;
283
284                 error_message = g_strdup_printf (_("Unhandled MIME type: '%s'"),
285                                                  mime_type);
286                 unable_to_load (ev_window, error_message);
287                 g_free (error_message);
288         }
289
290         g_free (mime_type);
291 }
292
293 static void
294 ev_window_cmd_file_open (GtkAction *action, EvWindow *ev_window)
295 {
296         ev_application_open (EV_APP, NULL);
297 }
298
299 static void
300 ev_window_cmd_file_print (GtkAction *action, EvWindow *ev_window)
301 {
302         g_return_if_fail (EV_IS_WINDOW (ev_window));
303         /* FIXME */
304 }
305
306 static void
307 ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
308 {
309         g_return_if_fail (EV_IS_WINDOW (ev_window));
310
311         gtk_widget_destroy (GTK_WIDGET (ev_window));
312 }
313
314 static void
315 ev_window_cmd_edit_find (GtkAction *action, EvWindow *ev_window)
316 {
317         g_return_if_fail (EV_IS_WINDOW (ev_window));
318
319         gtk_widget_show (ev_window->priv->find_bar);
320         egg_find_bar_grab_focus (EGG_FIND_BAR (ev_window->priv->find_bar));
321 }
322
323 static void
324 ev_window_cmd_edit_copy (GtkAction *action, EvWindow *ev_window)
325 {
326         g_return_if_fail (EV_IS_WINDOW (ev_window));
327
328         /* FIXME */
329 }
330
331 static void
332 update_fullscreen_popup (EvWindow *window)
333 {
334         GtkWidget *popup = window->priv->exit_fullscreen_popup;
335         int popup_width, popup_height;
336         GdkRectangle screen_rect;
337
338         g_return_if_fail (popup != NULL);
339
340         popup_width = popup->requisition.width;
341         popup_height = popup->requisition.height;
342
343         /* FIXME multihead */
344         gdk_screen_get_monitor_geometry (gdk_screen_get_default (),
345                         gdk_screen_get_monitor_at_window
346                         (gdk_screen_get_default (),
347                          GTK_WIDGET (window)->window),
348                          &screen_rect);
349
350         if (gtk_widget_get_direction (popup) == GTK_TEXT_DIR_RTL)
351         {
352                 gtk_window_move (GTK_WINDOW (popup),
353                                  screen_rect.x + screen_rect.width - popup_width,
354                                  screen_rect.height - popup_height);
355         }
356         else
357         {
358                 gtk_window_move (GTK_WINDOW (popup),
359                                 screen_rect.x, screen_rect.height - popup_height);
360         }
361 }
362
363 static void
364 screen_size_changed_cb (GdkScreen *screen,
365                         EvWindow *window)
366 {
367         update_fullscreen_popup (window);
368 }
369
370 static void
371 destroy_exit_fullscreen_popup (EvWindow *window)
372 {
373         if (window->priv->exit_fullscreen_popup != NULL)
374         {
375                 /* FIXME multihead */
376                 g_signal_handlers_disconnect_by_func
377                         (gdk_screen_get_default (),
378                          G_CALLBACK (screen_size_changed_cb), window);
379
380                 gtk_widget_destroy (window->priv->exit_fullscreen_popup);
381                 window->priv->exit_fullscreen_popup = NULL;
382         }
383 }
384
385 static void
386 exit_fullscreen_button_clicked_cb (GtkWidget *button, EvWindow *window)
387 {
388         GtkAction *action;
389
390         action = gtk_action_group_get_action (window->priv->action_group, "ViewFullscreen");
391         g_return_if_fail (action != NULL);
392
393         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
394 }
395
396 static void
397 fullscreen_popup_size_request_cb (GtkWidget *popup, GtkRequisition *req, EvWindow *window)
398 {
399         update_fullscreen_popup (window);
400 }
401
402 static void
403 ev_window_fullscreen (EvWindow *window)
404 {
405         GtkWidget *popup, *button, *icon, *label, *hbox;
406
407         window->priv->fullscreen_mode = TRUE;
408
409         popup = gtk_window_new (GTK_WINDOW_POPUP);
410         window->priv->exit_fullscreen_popup = popup;
411
412         button = gtk_button_new ();
413         g_signal_connect (button, "clicked",
414                           G_CALLBACK (exit_fullscreen_button_clicked_cb),
415                           window);
416         gtk_widget_show (button);
417         gtk_container_add (GTK_CONTAINER (popup), button);
418
419         hbox = gtk_hbox_new (FALSE, 2);
420         gtk_widget_show (hbox);
421         gtk_container_add (GTK_CONTAINER (button), hbox);
422
423         icon = gtk_image_new_from_stock (GTK_STOCK_QUIT, GTK_ICON_SIZE_BUTTON);
424         gtk_widget_show (icon);
425         gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
426
427         label = gtk_label_new (_("Exit Fullscreen"));
428         gtk_widget_show (label);
429         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
430
431         gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
432
433         /* FIXME multihead */
434         g_signal_connect (gdk_screen_get_default (), "size-changed",
435                           G_CALLBACK (screen_size_changed_cb), window);
436         g_signal_connect (popup, "size_request",
437                           G_CALLBACK (fullscreen_popup_size_request_cb), window);
438
439         update_fullscreen_popup (window);
440
441         gtk_widget_show (popup);
442 }
443
444 static void
445 ev_window_unfullscreen (EvWindow *window)
446 {
447         window->priv->fullscreen_mode = FALSE;
448
449         destroy_exit_fullscreen_popup (window);
450 }
451  
452 static void
453 ev_window_cmd_view_fullscreen (GtkAction *action, EvWindow *ev_window)
454 {
455         gboolean fullscreen;
456         
457         g_return_if_fail (EV_IS_WINDOW (ev_window));
458
459         fullscreen = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
460
461         if (fullscreen) {
462                 gtk_window_fullscreen (GTK_WINDOW (ev_window));
463         } else {
464                 gtk_window_unfullscreen (GTK_WINDOW (ev_window));
465         }
466 }
467
468 static gboolean
469 ev_window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event, EvWindow *window)
470 {
471         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
472         {
473                 GtkActionGroup *action_group;
474                 GtkAction *action;
475                 GtkWidget *main_menu;
476                 gboolean fullscreen;
477
478                 fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
479
480                 if (fullscreen)
481                 {
482                         ev_window_fullscreen (window);
483                 }
484                 else
485                 {
486                         ev_window_unfullscreen (window);
487                 }
488
489                 action_group = window->priv->action_group;
490
491                 action = gtk_action_group_get_action (action_group, "ViewFullscreen");
492                 g_signal_handlers_block_by_func
493                         (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
494                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fullscreen);
495                 g_signal_handlers_unblock_by_func
496                         (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
497
498                 main_menu = gtk_ui_manager_get_widget (window->priv->ui_manager, "/MainMenu");
499                 g_object_set (main_menu, "visible", !fullscreen, NULL);
500         }
501
502         return FALSE;
503 }
504
505 static void
506 ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window)
507 {
508         g_return_if_fail (EV_IS_WINDOW (ev_window));
509
510         ev_view_zoom_in (EV_VIEW (ev_window->priv->view));
511 }
512
513 static void
514 ev_window_cmd_view_zoom_out (GtkAction *action, EvWindow *ev_window)
515 {
516         g_return_if_fail (EV_IS_WINDOW (ev_window));
517
518         ev_view_zoom_out (EV_VIEW (ev_window->priv->view));
519 }
520
521 static void
522 ev_window_cmd_view_normal_size (GtkAction *action, EvWindow *ev_window)
523 {
524         g_return_if_fail (EV_IS_WINDOW (ev_window));
525
526         ev_view_normal_size (EV_VIEW (ev_window->priv->view));
527 }
528
529 static void
530 ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
531 {
532         g_return_if_fail (EV_IS_WINDOW (ev_window));
533
534         ev_view_best_fit (EV_VIEW (ev_window->priv->view));
535 }
536
537 static void
538 ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
539 {
540         g_return_if_fail (EV_IS_WINDOW (ev_window));
541
542         ev_view_fit_width (EV_VIEW (ev_window->priv->view));
543 }
544
545 static void
546 ev_window_cmd_go_back (GtkAction *action, EvWindow *ev_window)
547 {
548         g_return_if_fail (EV_IS_WINDOW (ev_window));
549
550         /* FIXME */
551 }
552
553 static void
554 ev_window_cmd_go_forward (GtkAction *action, EvWindow *ev_window)
555 {
556         g_return_if_fail (EV_IS_WINDOW (ev_window));
557
558         /* FIXME */
559 }
560
561 static void
562 ev_window_cmd_go_previous_page (GtkAction *action, EvWindow *ev_window)
563 {
564         g_return_if_fail (EV_IS_WINDOW (ev_window));
565
566         ev_view_set_page (EV_VIEW (ev_window->priv->view),
567                           ev_view_get_page (EV_VIEW (ev_window->priv->view)) - 1);
568 }
569
570 static void
571 ev_window_cmd_go_next_page (GtkAction *action, EvWindow *ev_window)
572 {
573         g_return_if_fail (EV_IS_WINDOW (ev_window));
574
575         ev_view_set_page (EV_VIEW (ev_window->priv->view),
576                           ev_view_get_page (EV_VIEW (ev_window->priv->view)) + 1);
577 }
578
579 static void
580 ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window)
581 {
582         g_return_if_fail (EV_IS_WINDOW (ev_window));
583
584         ev_view_set_page (EV_VIEW (ev_window->priv->view), 1);
585 }
586
587 static void
588 ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window)
589 {
590         g_return_if_fail (EV_IS_WINDOW (ev_window));
591
592         ev_view_set_page (EV_VIEW (ev_window->priv->view), G_MAXINT);
593 }
594
595 static void
596 ev_window_cmd_help_contents (GtkAction *action, EvWindow *ev_window)
597 {
598         g_return_if_fail (EV_IS_WINDOW (ev_window));
599
600         /* FIXME */
601 }
602
603 static void
604 ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
605 {
606         const char *authors[] = {
607                 N_("Many..."),
608                 NULL
609         };
610
611         const char *documenters[] = {
612                 N_("Not so many..."),
613                 NULL
614         };
615
616         const char *license[] = {
617                 N_("Evince is free software; you can redistribute it and/or modify\n"
618                    "it under the terms of the GNU General Public License as published by\n"
619                    "the Free Software Foundation; either version 2 of the License, or\n"
620                    "(at your option) any later version.\n"),            
621                 N_("Evince is distributed in the hope that it will be useful,\n"
622                    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
623                    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
624                    "GNU General Public License for more details.\n"),
625                 N_("You should have received a copy of the GNU General Public License\n"
626                    "along with Evince; if not, write to the Free Software Foundation, Inc.,\n"
627                    "59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n")
628         };
629
630         char *license_trans;
631
632 #ifdef ENABLE_NLS
633         const char **p;
634
635         for (p = authors; *p; ++p)
636                 *p = _(*p);
637
638         for (p = documenters; *p; ++p)
639                 *p = _(*p);
640 #endif
641
642         license_trans = g_strconcat (_(license[0]), "\n", _(license[1]), "\n",
643                                      _(license[2]), "\n", NULL);
644
645         gtk_show_about_dialog (
646                 GTK_WINDOW (ev_window),
647                 "name", _("Evince"),
648                 "version", VERSION,
649                 "copyright",
650                 _("\xc2\xa9 1996-2004 The Evince authors"),
651                 "license", license_trans,
652                 "website", "http://www.gnome.org/projects/evince",
653                 "comments", _("PostScript and PDF File Viewer."),
654                 "authors", authors,
655                 "documenters", documenters,
656                 "translator-credits", _("translator-credits"),
657                 NULL);
658
659         g_free (license_trans);
660 }
661
662 static void
663 ev_window_view_toolbar_cb (GtkAction *action, EvWindow *ev_window)
664 {
665         g_object_set (
666                 G_OBJECT (gtk_ui_manager_get_widget (
667                                   ev_window->priv->ui_manager,
668                                   "/ToolBar")),
669                 "visible",
670                 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)),
671                 NULL);
672 }
673
674 static void
675 ev_window_view_statusbar_cb (GtkAction *action, EvWindow *ev_window)
676 {
677         g_object_set (
678                 ev_window->priv->statusbar,
679                 "visible",
680                 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)),
681                 NULL);
682 }
683
684 static void
685 ev_window_view_sidebar_cb (GtkAction *action, EvWindow *ev_window)
686 {
687         /* FIXME */
688 }
689
690 static void
691 menu_item_select_cb (GtkMenuItem *proxy, EvWindow *ev_window)
692 {
693         GtkAction *action;
694         char *message;
695
696         action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
697         g_return_if_fail (action != NULL);
698         
699         g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
700         if (message) {
701                 gtk_statusbar_push (GTK_STATUSBAR (ev_window->priv->statusbar),
702                                     ev_window->priv->help_message_cid, message);
703                 g_free (message);
704         }
705 }
706
707 static void
708 menu_item_deselect_cb (GtkMenuItem *proxy, EvWindow *ev_window)
709 {
710         gtk_statusbar_pop (GTK_STATUSBAR (ev_window->priv->statusbar),
711                            ev_window->priv->help_message_cid);
712 }
713
714 static void
715 connect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action,
716                   GtkWidget *proxy, EvWindow *ev_window)
717 {
718         if (GTK_IS_MENU_ITEM (proxy)) {
719                 g_signal_connect (proxy, "select",
720                                   G_CALLBACK (menu_item_select_cb), ev_window);
721                 g_signal_connect (proxy, "deselect",
722                                   G_CALLBACK (menu_item_deselect_cb),
723                                   ev_window);
724         }
725 }
726
727 static void
728 disconnect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action,
729                      GtkWidget *proxy, EvWindow *ev_window)
730 {
731         if (GTK_IS_MENU_ITEM (proxy)) {
732                 g_signal_handlers_disconnect_by_func
733                         (proxy, G_CALLBACK (menu_item_select_cb), ev_window);
734                 g_signal_handlers_disconnect_by_func
735                         (proxy, G_CALLBACK (menu_item_deselect_cb), ev_window);
736         }
737 }
738
739 static void
740 view_page_changed_cb (EvView   *view,
741                       EvWindow *ev_window)
742 {
743         update_action_sensitivity (ev_window);
744 }
745
746 static void
747 find_bar_previous_cb (EggFindBar *find_bar,
748                       EvWindow   *ev_window)
749 {
750         /* FIXME - highlight previous result */
751         g_printerr ("Find Previous\n");
752
753 }
754
755 static void
756 find_bar_next_cb (EggFindBar *find_bar,
757                   EvWindow   *ev_window)
758 {
759         /* FIXME - highlight next result */
760         g_printerr ("Find Next\n");
761 }
762
763 static void
764 find_bar_close_cb (EggFindBar *find_bar,
765                    EvWindow   *ev_window)
766 {
767         gtk_widget_hide (ev_window->priv->find_bar);
768 }
769
770 static void
771 find_bar_search_changed_cb (EggFindBar *find_bar,
772                             GParamSpec *param,
773                             EvWindow   *ev_window)
774 {
775         gboolean case_sensitive;
776         gboolean visible;
777         const char *search_string;
778
779         g_return_if_fail (EV_IS_WINDOW (ev_window));
780         
781         /* Either the string or case sensitivity could have changed,
782          * we connect this callback to both. We also connect it
783          * to ::visible so when the find bar is hidden, we should
784          * pretend the search string is NULL/""
785          */
786
787         case_sensitive = egg_find_bar_get_case_sensitive (find_bar);
788         visible = GTK_WIDGET_VISIBLE (find_bar);
789         search_string = egg_find_bar_get_search_string (find_bar);
790         
791 #if 0
792         g_printerr ("search for '%s'\n", search_string ? search_string : "(nil)");
793 #endif
794
795         /* We don't require begin/end find calls to be matched up, it's really
796          * start_find and cancel_any_find_that_may_not_be_finished
797          */
798         if (visible && search_string) {
799                 ev_document_begin_find (ev_window->priv->document, search_string, case_sensitive);
800         } else {
801                 ev_document_end_find (ev_window->priv->document);
802         }
803 }
804
805 static void
806 ev_window_dispose (GObject *object)
807 {
808         EvWindowPrivate *priv;
809
810         g_return_if_fail (object != NULL && EV_IS_WINDOW (object));
811
812         priv = EV_WINDOW (object)->priv;
813
814         if (priv->ui_manager) {
815                 g_object_unref (priv->ui_manager);
816                 priv->ui_manager = NULL;
817         }
818
819         if (priv->action_group) {
820                 g_object_unref (priv->action_group);
821                 priv->action_group = NULL;
822         }
823         
824         G_OBJECT_CLASS (parent_class)->dispose (object);
825 }
826
827 static void
828 ev_window_class_init (EvWindowClass *ev_window_class)
829 {
830         GObjectClass *g_object_class;
831
832         parent_class = g_type_class_peek_parent (ev_window_class);
833
834         g_object_class = G_OBJECT_CLASS (ev_window_class);
835         g_object_class->dispose = ev_window_dispose;
836
837         g_type_class_add_private (g_object_class, sizeof (EvWindowPrivate));
838
839 #if 0
840         /* setting up signal system */
841         ev_window_class->signal = ev_window_signal;
842
843         ev_window_signals [SIGNAL] = g_signal_new (
844                 "signal",
845                 EV_TYPE_WINDOW,
846                 G_SIGNAL_RUN_LAST,
847                 G_STRUCT_OFFSET (EvWindowClass,
848                                  signal),
849                 NULL,
850                 NULL,
851                 g_cclosure_marshal_VOID__STRING,
852                 G_TYPE_NONE,
853                 0);
854         /* setting up property system */
855         g_object_class->set_property = ev_window_set_property;
856         g_object_class->get_property = ev_window_get_property;
857
858         g_object_class_install_property (
859                 g_object_class,
860                 PROP_ATTRIBUTE,
861                 g_param_spec_string ("attribute",
862                                      "Attribute",
863                                      "A simple unneccessary attribute that "
864                                      "does nothing special except being a "
865                                      "demonstration for the correct implem"
866                                      "entation of a GObject property",
867                                      "default_value",
868                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
869 #endif
870 }
871
872 /* Normal items */
873 static GtkActionEntry entries[] = {
874         { "File", NULL, N_("_File") },
875         { "Edit", NULL, N_("_Edit") },
876         { "View", NULL, N_("_View") },
877         { "Go", NULL, N_("_Go") },
878         { "Help", NULL, N_("_Help") },
879
880         /* File menu */
881         { "FileOpen", GTK_STOCK_OPEN, N_("_Open"), "<control>O",
882           N_("Open a file"),
883           G_CALLBACK (ev_window_cmd_file_open) },
884         { "FilePrint", GTK_STOCK_PRINT, N_("_Print"), "<control>P",
885           N_("Print this document"),
886           G_CALLBACK (ev_window_cmd_file_print) },
887         { "FileCloseWindow", GTK_STOCK_CLOSE, N_("_Close"), "<control>W",
888           N_("Close this window"),
889           G_CALLBACK (ev_window_cmd_file_close_window) },
890
891         /* Edit menu */
892         { "EditCopy", GTK_STOCK_COPY, N_("_Copy"), "<control>C",
893           N_("Copy text from the document"),
894           G_CALLBACK (ev_window_cmd_edit_copy) },
895         
896         { "EditFind", GTK_STOCK_FIND, N_("_Find"), "<control>F",
897           N_("Find a word or phrase in the document"),
898           G_CALLBACK (ev_window_cmd_edit_find) },
899
900         /* View menu */
901         { "ViewZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), "<control>plus",
902           N_("Enlarge the document"),
903           G_CALLBACK (ev_window_cmd_view_zoom_in) },
904         { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "<control>minus",
905           N_("Shrink the document"),
906           G_CALLBACK (ev_window_cmd_view_zoom_out) },
907         { "ViewNormalSize", GTK_STOCK_ZOOM_100, N_("_Normal Size"), "<control>0",
908           N_("Zoom to the normal size"),
909           G_CALLBACK (ev_window_cmd_view_normal_size) },
910         { "ViewBestFit", GTK_STOCK_ZOOM_FIT, N_("_Best Fit"), NULL,
911           N_("Zoom to fit the document to the current window"),
912           G_CALLBACK (ev_window_cmd_view_best_fit) },
913         { "ViewPageWidth", EV_STOCK_ZOOM_FIT_WIDTH, N_("Fit Page _Width"), NULL,
914           N_("Zoom to fit the width of the current window "),
915           G_CALLBACK (ev_window_cmd_view_page_width) },
916
917         /* Go menu */
918         { "GoBack", GTK_STOCK_GO_BACK, N_("_Back"), "<mod1>Left",
919           N_("Go to the page viewed before this one"),
920           G_CALLBACK (ev_window_cmd_go_back) },
921         { "GoForward", GTK_STOCK_GO_FORWARD, N_("Fo_rward"), "<mod1>Right",
922           N_("Go to the page viewed before this one"),
923           G_CALLBACK (ev_window_cmd_go_forward) },
924         { "GoPreviousPage", GTK_STOCK_GO_BACK, N_("_Previous Page"), "<control>Page_Up",
925           N_("Go to the previous page"),
926           G_CALLBACK (ev_window_cmd_go_previous_page) },
927         { "GoNextPage", GTK_STOCK_GO_FORWARD, N_("_Next Page"), "<control>Page_Down",
928           N_("Go to the next page"),
929           G_CALLBACK (ev_window_cmd_go_next_page) },
930         { "GoFirstPage", GTK_STOCK_GOTO_FIRST, N_("_First Page"), "<control>Home",
931           N_("Go to the first page"),
932           G_CALLBACK (ev_window_cmd_go_first_page) },        
933         { "GoLastPage", GTK_STOCK_GOTO_LAST, N_("_Last Page"), "<control>End",
934           N_("Go to the last page"),
935           G_CALLBACK (ev_window_cmd_go_last_page) },
936         
937         /* Help menu */
938         { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), NULL,
939           N_("Display help for the viewer application"),
940           G_CALLBACK (ev_window_cmd_help_contents) },
941         
942         { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL,
943           N_("Display credits for the document viewer creators"),
944           G_CALLBACK (ev_window_cmd_help_about) },
945 };
946
947 /* Toggle items */
948 static GtkToggleActionEntry toggle_entries[] = {
949         /* View Menu */
950         { "ViewToolbar", NULL, N_("_Toolbar"), "<shift><control>T",
951           N_("Show or hide toolbar"),
952           G_CALLBACK (ev_window_view_toolbar_cb), TRUE },
953         { "ViewStatusbar", NULL, N_("_Statusbar"), NULL,
954           N_("Show or hide statusbar"),
955           G_CALLBACK (ev_window_view_statusbar_cb), TRUE },
956         { "ViewSidebar", NULL, N_("Side_bar"), "F9",
957           N_("Show or hide sidebar"),
958           G_CALLBACK (ev_window_view_sidebar_cb), FALSE },
959         { "ViewFullscreen", NULL, N_("_Fullscreen"), "F11",
960           N_("Expand the window to fill the screen"),
961           G_CALLBACK (ev_window_cmd_view_fullscreen) },
962 };
963
964 static void
965 ev_window_init (EvWindow *ev_window)
966 {
967         GtkActionGroup *action_group;
968         GtkAccelGroup *accel_group;
969         GError *error = NULL;
970         GtkWidget *scrolled_window;
971         GtkWidget *menubar;
972         GtkWidget *toolbar;
973         GtkWidget *sidebar_widget;
974
975         ev_window->priv = EV_WINDOW_GET_PRIVATE (ev_window);
976
977         gtk_window_set_title (GTK_WINDOW (ev_window), _("Document Viewer"));
978
979         ev_window->priv->main_box = gtk_vbox_new (FALSE, 0);
980         gtk_container_add (GTK_CONTAINER (ev_window), ev_window->priv->main_box);
981         gtk_widget_show (ev_window->priv->main_box);
982         
983         action_group = gtk_action_group_new ("MenuActions");
984         ev_window->priv->action_group = action_group;
985         gtk_action_group_set_translation_domain (action_group, NULL);
986         gtk_action_group_add_actions (action_group, entries,
987                                       G_N_ELEMENTS (entries), ev_window);
988         gtk_action_group_add_toggle_actions (action_group, toggle_entries,
989                                              G_N_ELEMENTS (toggle_entries),
990                                              ev_window);
991
992         ev_window->priv->ui_manager = gtk_ui_manager_new ();
993         gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
994                                             action_group, 0);
995
996         accel_group =
997                 gtk_ui_manager_get_accel_group (ev_window->priv->ui_manager);
998         gtk_window_add_accel_group (GTK_WINDOW (ev_window), accel_group);
999
1000         g_signal_connect (ev_window->priv->ui_manager, "connect_proxy",
1001                           G_CALLBACK (connect_proxy_cb), ev_window);
1002         g_signal_connect (ev_window->priv->ui_manager, "disconnect_proxy",
1003                           G_CALLBACK (disconnect_proxy_cb), ev_window);
1004
1005         if (!gtk_ui_manager_add_ui_from_file (ev_window->priv->ui_manager,
1006                                               DATADIR"/evince-ui.xml",
1007                                               &error)) {
1008                 g_message ("building menus failed: %s", error->message);
1009                 g_error_free (error);
1010         }
1011
1012         menubar = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
1013                                              "/MainMenu");
1014         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), menubar,
1015                             FALSE, FALSE, 0);
1016
1017         toolbar = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
1018                                              "/ToolBar");
1019         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), toolbar,
1020                             FALSE, FALSE, 0);
1021
1022         /* Add the main area */
1023         ev_window->priv->hpaned = gtk_hpaned_new ();
1024         gtk_widget_show (ev_window->priv->hpaned);
1025         gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box), ev_window->priv->hpaned,
1026                             TRUE, TRUE, 0);
1027
1028         ev_window->priv->sidebar = ev_sidebar_new ();
1029         gtk_widget_show (ev_window->priv->sidebar);
1030         gtk_paned_add1 (GTK_PANED (ev_window->priv->hpaned),
1031                         ev_window->priv->sidebar);
1032
1033         /* Stub sidebar, for now */
1034         sidebar_widget = ev_sidebar_bookmarks_new ();
1035         gtk_widget_show (sidebar_widget);
1036         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
1037                              "bookmarks",
1038                              _("Bookmarks"),
1039                              sidebar_widget);
1040
1041         sidebar_widget = ev_sidebar_thumbnails_new ();
1042         gtk_widget_show (sidebar_widget);
1043         ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
1044                              "thumbnails",
1045                              _("Thumbnails"),
1046                              sidebar_widget);
1047         
1048         scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1049         gtk_widget_show (scrolled_window);
1050         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1051                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1052
1053         gtk_paned_add2 (GTK_PANED (ev_window->priv->hpaned),
1054                         scrolled_window);
1055
1056         ev_window->priv->view = ev_view_new ();
1057         gtk_widget_show (ev_window->priv->view);
1058         gtk_container_add (GTK_CONTAINER (scrolled_window),
1059                            ev_window->priv->view);
1060         g_signal_connect (ev_window->priv->view,
1061                           "page-changed",
1062                           G_CALLBACK (view_page_changed_cb),
1063                           ev_window);
1064
1065         ev_window->priv->statusbar = gtk_statusbar_new ();
1066         gtk_widget_show (ev_window->priv->statusbar);
1067         gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
1068                           ev_window->priv->statusbar,
1069                           FALSE, TRUE, 0);
1070         ev_window->priv->help_message_cid = gtk_statusbar_get_context_id
1071                 (GTK_STATUSBAR (ev_window->priv->statusbar), "help_message");
1072
1073         ev_window->priv->find_bar = egg_find_bar_new ();
1074         gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
1075                           ev_window->priv->find_bar,
1076                           FALSE, TRUE, 0);
1077         
1078         /* Connect to find bar signals */
1079         g_signal_connect (ev_window->priv->find_bar,
1080                           "previous",
1081                           G_CALLBACK (find_bar_previous_cb),
1082                           ev_window);
1083         g_signal_connect (ev_window->priv->find_bar,
1084                           "next",
1085                           G_CALLBACK (find_bar_next_cb),
1086                           ev_window);
1087         g_signal_connect (ev_window->priv->find_bar,
1088                           "close",
1089                           G_CALLBACK (find_bar_close_cb),
1090                           ev_window);
1091         g_signal_connect (ev_window->priv->find_bar,
1092                           "notify::search-string",
1093                           G_CALLBACK (find_bar_search_changed_cb),
1094                           ev_window);
1095         g_signal_connect (ev_window->priv->find_bar,
1096                           "notify::case-sensitive",
1097                           G_CALLBACK (find_bar_search_changed_cb),
1098                           ev_window);
1099         g_signal_connect (ev_window->priv->find_bar,
1100                           "notify::visible",
1101                           G_CALLBACK (find_bar_search_changed_cb),
1102                           ev_window);
1103
1104         g_signal_connect (ev_window, "window-state-event",
1105                           G_CALLBACK (ev_window_state_event_cb),
1106                           ev_window);
1107         
1108         /* Give focus to the scrolled window */
1109         gtk_widget_grab_focus (scrolled_window);
1110         
1111         update_action_sensitivity (ev_window);
1112