]> www.fi.muni.cz Git - evince.git/blobdiff - libview/ev-view.c
[build] Use AM_V_GEN to make custom commands silent
[evince.git] / libview / ev-view.c
index 8474516c4315a55b9d4328d83422fd6c53091f80..613236319dc4aa4d4fefbd35b068434289686867 100644 (file)
@@ -28,6 +28,7 @@
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 
+#include "ev-mapping.h"
 #include "ev-document-forms.h"
 #include "ev-document-images.h"
 #include "ev-document-links.h"
@@ -37,6 +38,8 @@
 #include "ev-pixbuf-cache.h"
 #include "ev-transition-animation.h"
 #include "ev-view-marshal.h"
+#include "ev-document-annotations.h"
+#include "ev-annotation-window.h"
 #include "ev-view.h"
 #include "ev-view-accessible.h"
 #include "ev-view-private.h"
@@ -148,6 +151,14 @@ static EvFormField *ev_view_get_form_field_at_location       (EvView
                                                               gdouble            x,
                                                               gdouble            y);
 
+/*** Annotations ***/
+static EvAnnotation *ev_view_get_annotation_at_location      (EvView             *view,
+                                                             gdouble             x,
+                                                             gdouble             y);
+static void          show_annotation_windows                 (EvView             *view,
+                                                             gint                page);
+static void          hide_annotation_windows                 (EvView             *view,
+                                                             gint                page);
 /*** GtkWidget implementation ***/
 static void       ev_view_size_request_continuous_dual_page  (EvView             *view,
                                                              GtkRequisition     *requisition);
@@ -427,6 +438,8 @@ view_update_range_and_current_page (EvView *view)
 {
        gint current_page;
        gint best_current_page = -1;
+       gint start = view->start_page;
+       gint end = view->end_page;
        
        /* Presentation trumps all other modes */
        if (view->presentation) {
@@ -498,6 +511,18 @@ view_update_range_and_current_page (EvView *view)
                ev_page_cache_set_current_page (view->page_cache, best_current_page);
        }
 
+       if (start != view->start_page || end != view->end_page) {
+               gint i;
+
+               for (i = start; i < view->start_page; i++) {
+                       hide_annotation_windows (view, i);
+               }
+
+               for (i = end; i > view->end_page; i--) {
+                       hide_annotation_windows (view, i);
+               }
+       }
+
        ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
                                        view->start_page,
                                        view->end_page,
@@ -1092,6 +1117,41 @@ get_doc_point_from_offset (EvView *view,
        return TRUE;
 }
 
+static gboolean
+get_doc_point_from_location (EvView  *view,
+                            gdouble  x,
+                            gdouble  y,
+                            gint    *page,
+                            gint    *x_new,
+                            gint    *y_new)
+{
+       gint x_offset = 0, y_offset = 0;
+
+       x += view->scroll_x;
+       y += view->scroll_y;
+       find_page_at_location (view, x, y, page, &x_offset, &y_offset);
+       if (*page == -1)
+               return FALSE;
+
+       return get_doc_point_from_offset (view, *page, x_offset, y_offset, x_new, y_new);
+}
+
+static void
+ev_view_get_area_from_mapping (EvView       *view,
+                              guint         page,
+                              GList        *mapping_list,
+                              gconstpointer data,
+                              GdkRectangle *area)
+{
+       EvMapping *mapping;
+
+       mapping = ev_mapping_list_find (mapping_list, data);
+       doc_rect_to_view_rect (view, page, &mapping->area, area);
+       area->x -= view->scroll_x;
+       area->y -= view->scroll_y;
+}
+
+
 /*** Hyperref ***/
 static EvLink *
 ev_view_get_link_at_location (EvView  *view,
@@ -1099,30 +1159,19 @@ ev_view_get_link_at_location (EvView  *view,
                              gdouble  y)
 {
        gint page = -1;
-       gint x_offset = 0, y_offset = 0;
        gint x_new = 0, y_new = 0;
        GList *link_mapping;
 
        if (!EV_IS_DOCUMENT_LINKS (view->document))
                return NULL;
-       
-       x += view->scroll_x;
-       y += view->scroll_y;
-
-       find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
-
-       if (page == -1)
-               return NULL;
 
-       
-       if (get_doc_point_from_offset (view, page, x_offset, 
-                                      y_offset, &x_new, &y_new) == FALSE)
+       if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
                return NULL;
 
        link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page);
 
        if (link_mapping)
-               return ev_link_mapping_find (link_mapping, x_new, y_new);
+               return ev_mapping_list_get_data (link_mapping, x_new, y_new);
        else
                return NULL;
 }
@@ -1487,8 +1536,9 @@ tip_from_link (EvView *view, EvLink *link)
 static void
 ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
 {
-       EvLink      *link;
-       EvFormField *field;
+       EvLink       *link;
+       EvFormField  *field;
+       EvAnnotation *annot = NULL;
 
        if (view->cursor == EV_VIEW_CURSOR_HIDDEN)
                return;
@@ -1504,10 +1554,9 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
                        ev_view_set_cursor (view, EV_VIEW_CURSOR_AUTOSCROLL);
                return;
        }
-       
+
        link = ev_view_get_link_at_location (view, x, y);
         if (link) {
-               g_object_set (view, "has-tooltip", TRUE, NULL);
                ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
        } else if ((field = ev_view_get_form_field_at_location (view, x, y))) {
                if (field->is_read_only) {
@@ -1520,6 +1569,8 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
                } else {
                        ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
                }
+       } else if ((annot = ev_view_get_annotation_at_location (view, x, y))) {
+               ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
        } else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) {
                ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM);
        } else {
@@ -1529,6 +1580,9 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
                    view->cursor == EV_VIEW_CURSOR_AUTOSCROLL)
                        ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
        }
+
+       if (link || annot)
+               g_object_set (view, "has-tooltip", TRUE, NULL);
 }
 
 /*** Images ***/
@@ -1538,29 +1592,19 @@ ev_view_get_image_at_location (EvView  *view,
                               gdouble  y)
 {
        gint page = -1;
-       gint x_offset = 0, y_offset = 0;
        gint x_new = 0, y_new = 0;
        GList *image_mapping;
 
        if (!EV_IS_DOCUMENT_IMAGES (view->document))
                return NULL;
 
-       x += view->scroll_x;
-       y += view->scroll_y;
-
-       find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
-
-       if (page == -1)
-               return NULL;
-
-       if (get_doc_point_from_offset (view, page, x_offset,
-                                      y_offset, &x_new, &y_new) == FALSE)
+       if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
                return NULL;
 
        image_mapping = ev_pixbuf_cache_get_image_mapping (view->pixbuf_cache, page);
 
        if (image_mapping)
-               return ev_image_mapping_find (image_mapping, x_new, y_new);
+               return ev_mapping_list_get_data (image_mapping, x_new, y_new);
        else
                return NULL;
 }
@@ -1572,29 +1616,19 @@ ev_view_get_form_field_at_location (EvView  *view,
                                    gdouble  y)
 {
        gint page = -1;
-       gint x_offset = 0, y_offset = 0;
        gint x_new = 0, y_new = 0;
        GList *forms_mapping;
        
        if (!EV_IS_DOCUMENT_FORMS (view->document))
                return NULL;
 
-       x += view->scroll_x;
-       y += view->scroll_y;
-       
-       find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
-       
-       if (page == -1)
-               return NULL;
-
-       if (get_doc_point_from_offset (view, page, x_offset,
-                                      y_offset, &x_new, &y_new) == FALSE)
+       if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
                return NULL;
 
        forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page);
 
        if (forms_mapping)
-               return ev_form_field_mapping_find (forms_mapping, x_new, y_new);
+               return ev_mapping_list_get_data (forms_mapping, x_new, y_new);
        else
                return NULL;
 }
@@ -1603,16 +1637,14 @@ static GdkRegion *
 ev_view_form_field_get_region (EvView      *view,
                               EvFormField *field)
 {
-       EvRectangle  field_area;
        GdkRectangle view_area;
        GList       *forms_mapping;
 
        forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache,
                                                                field->page->index);
-       ev_form_field_mapping_get_area (forms_mapping, field, &field_area);
-       doc_rect_to_view_rect (view, field->page->index, &field_area, &view_area);
-       view_area.x -= view->scroll_x;
-       view_area.y -= view->scroll_y;
+       ev_view_get_area_from_mapping (view, field->page->index,
+                                      forms_mapping,
+                                      field, &view_area);
 
        return gdk_region_rectangle (&view_area);
 }
@@ -1663,7 +1695,7 @@ ev_view_form_field_button_create_widget (EvView      *view,
                        forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache,
                                                                                field->page->index);
                        for (l = forms_mapping; l; l = g_list_next (l)) {
-                               EvFormField *button = ((EvFormFieldMapping *)(l->data))->field;
+                               EvFormField *button = ((EvMapping *)(l->data))->data;
                                GdkRegion   *button_region;
 
                                if (button->id == field->id)
@@ -2021,7 +2053,6 @@ ev_view_handle_form_field (EvView      *view,
 {
        GtkWidget   *field_widget = NULL;
        GList       *form_field_mapping;
-       EvRectangle  field_area;
        GdkRectangle view_area;
 
        if (field->is_read_only)
@@ -2046,17 +2077,357 @@ ev_view_handle_form_field (EvView      *view,
                                (GDestroyNotify)g_object_unref);
 
        form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, field->page->index);
-       ev_form_field_mapping_get_area (form_field_mapping, field, &field_area);
-       
-       doc_rect_to_view_rect (view, field->page->index, &field_area, &view_area);
-       view_area.x -= view->scroll_x;
-       view_area.y -= view->scroll_y;
+       ev_view_get_area_from_mapping (view, field->page->index,
+                                      form_field_mapping,
+                                      field, &view_area);
 
        gtk_layout_put (GTK_LAYOUT (view), field_widget, view_area.x, view_area.y);
        gtk_widget_show (field_widget);
        gtk_widget_grab_focus (field_widget);
 }
 
+/* Annotations */
+static EvViewWindowChild *
+ev_view_get_window_child (EvView    *view,
+                         GtkWidget *window)
+{
+       GList *children = view->window_children;
+
+       while (children) {
+               EvViewWindowChild *child;
+
+               child = (EvViewWindowChild *)children->data;
+               children = children->next;
+
+               if (child->window == window)
+                       return child;
+       }
+
+       return NULL;
+}
+
+static void
+ev_view_window_child_move (EvView            *view,
+                          EvViewWindowChild *child,
+                          gint               x,
+                          gint               y)
+{
+       child->x = x;
+       child->y = y;
+       gtk_window_move (GTK_WINDOW (child->window),
+                        MAX (child->parent_x, x),
+                        MAX (child->parent_y, y));
+}
+
+static void
+ev_view_window_child_move_with_parent (EvView    *view,
+                                      GtkWidget *window)
+{
+       EvViewWindowChild *child;
+       gint               root_x, root_y;
+
+       child = ev_view_get_window_child (view, window);
+       gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)),
+                              &root_x, &root_y);
+       if (root_x != child->parent_x || root_y != child->parent_y) {
+               gint dest_x, dest_y;
+
+               dest_x = child->x + (root_x - child->parent_x);
+               dest_y = child->y + (root_y - child->parent_y);
+               child->parent_x = root_x;
+               child->parent_y = root_y;
+               ev_view_window_child_move (view, child, dest_x, dest_y);
+       }
+
+       if (child->visible && !GTK_WIDGET_VISIBLE (window))
+               gtk_widget_show (window);
+}
+
+static void
+ev_view_window_child_put (EvView    *view,
+                         GtkWidget *window,
+                         guint      page,
+                         gint       x,
+                         gint       y,
+                         gdouble    orig_x,
+                         gdouble    orig_y)
+{
+       EvViewWindowChild *child;
+       gint               root_x, root_y;
+
+       gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)),
+                              &root_x, &root_y);
+
+       child = g_new0 (EvViewWindowChild, 1);
+       child->window = window;
+       child->page = page;
+       child->orig_x = orig_x;
+       child->orig_y = orig_y;
+       child->parent_x = root_x;
+       child->parent_y = root_y;
+       child->visible = ev_annotation_window_is_open (EV_ANNOTATION_WINDOW (window));
+       ev_view_window_child_move (view, child, x + root_x, y + root_y);
+
+       if (child->visible)
+               gtk_widget_show (window);
+       else
+               gtk_widget_hide (window);
+
+       view->window_children = g_list_append (view->window_children, child);
+}
+
+static EvViewWindowChild *
+ev_view_find_window_child_for_annot (EvView       *view,
+                                    guint         page,
+                                    EvAnnotation *annot)
+{
+       GList *children = view->window_children;
+
+       while (children) {
+               EvViewWindowChild *child;
+               EvAnnotation      *wannot;
+
+               child = (EvViewWindowChild *)children->data;
+               children = children->next;
+
+               if (child->page != page)
+                       continue;
+
+               wannot = ev_annotation_window_get_annotation (EV_ANNOTATION_WINDOW (child->window));
+               if (wannot == annot || strcmp (wannot->name, annot->name) == 0)
+                       return child;
+       }
+
+       return NULL;
+}
+
+static void
+ev_view_window_children_free (EvView *view)
+{
+       GList *l;
+
+       if (!view->window_children)
+               return;
+
+       for (l = view->window_children; l && l->data; l = g_list_next (l)) {
+               EvViewWindowChild *child;
+
+               child = (EvViewWindowChild *)l->data;
+               gtk_widget_destroy (GTK_WIDGET (child->window));
+               g_free (child);
+       }
+       g_list_free (view->window_children);
+       view->window_children = NULL;
+       view->window_child_focus = NULL;
+}
+
+static void
+annotation_window_grab_focus (GtkWidget *widget,
+                             EvView    *view)
+{
+       if (view->window_child_focus)
+               ev_annotation_window_ungrab_focus (EV_ANNOTATION_WINDOW (view->window_child_focus->window));
+       view->window_child_focus = ev_view_get_window_child (view, widget);
+}
+
+static void
+annotation_window_closed (EvAnnotationWindow *window,
+                         EvView             *view)
+{
+       EvViewWindowChild *child;
+
+       child = ev_view_get_window_child (view, GTK_WIDGET (window));
+       child->visible = FALSE;
+}
+
+static void
+annotation_window_moved (EvAnnotationWindow *window,
+                        gint                x,
+                        gint                y,
+                        EvView             *view)
+{
+       EvViewWindowChild *child;
+       GdkRectangle       page_area;
+       GtkBorder          border;
+       GdkRectangle       view_rect;
+       EvRectangle        doc_rect;
+       gint               width, height;
+
+       child = ev_view_get_window_child (view, GTK_WIDGET (window));
+       if (child->x == x && child->y == y)
+               return;
+
+       child->moved = TRUE;
+       child->x = x;
+       child->y = y;
+
+       /* Window has been moved by the user,
+        * we have to set a new origin in doc coords
+        */
+       gtk_window_get_size (GTK_WINDOW (window), &width, &height);
+       view_rect.x = (x - child->parent_x) + view->scroll_x;
+       view_rect.y = (y - child->parent_y) + view->scroll_y;
+       view_rect.width = width;
+       view_rect.height = height;
+
+       get_page_extents (view, child->page, &page_area, &border);
+       view_rect_to_doc_rect (view, &view_rect, &page_area, &doc_rect);
+       child->orig_x = doc_rect.x1;
+       child->orig_y = doc_rect.y1;
+}
+
+static void
+ev_view_annotation_save (EvView       *view,
+                        EvAnnotation *annot)
+{
+       if (!view->document)
+               return;
+
+       if (!annot->changed)
+               return;
+
+       ev_document_annotations_annotation_set_contents (EV_DOCUMENT_ANNOTATIONS (view->document),
+                                                        annot, annot->contents);
+       annot->changed = FALSE;
+}
+
+static void
+show_annotation_windows (EvView *view,
+                        gint    page)
+{
+       GList     *annots, *l;
+       GtkWindow *parent;
+
+       parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
+
+       annots = ev_pixbuf_cache_get_annots_mapping (view->pixbuf_cache, page);
+
+       for (l = annots; l && l->data; l = g_list_next (l)) {
+               EvAnnotation      *annot;
+               EvViewWindowChild *child;
+               GtkWidget         *window;
+               EvRectangle       *doc_rect;
+               GdkRectangle       view_rect;
+
+               annot = ((EvMapping *)(l->data))->data;
+
+               if (!EV_IS_ANNOTATION_MARKUP (annot))
+                       continue;
+
+               if (!ev_annotation_markup_has_popup (EV_ANNOTATION_MARKUP (annot)))
+                       continue;
+
+               window = g_object_get_data (G_OBJECT (annot), "popup");
+               if (window) {
+                       ev_view_window_child_move_with_parent (view, window);
+                       continue;
+               }
+
+               /* Look if we already have a popup for this annot */
+               child = ev_view_find_window_child_for_annot (view, page, annot);
+               window = child ? child->window : NULL;
+               if (window) {
+                       ev_annotation_window_set_annotation (EV_ANNOTATION_WINDOW (window), annot);
+                       g_object_set_data (G_OBJECT (annot), "popup", window);
+                       ev_view_window_child_move_with_parent (view, window);
+               } else {
+                       window = ev_annotation_window_new (annot, parent);
+                       g_signal_connect (window, "grab_focus",
+                                         G_CALLBACK (annotation_window_grab_focus),
+                                         view);
+                       g_signal_connect (window, "closed",
+                                         G_CALLBACK (annotation_window_closed),
+                                         view);
+                       g_signal_connect (window, "moved",
+                                         G_CALLBACK (annotation_window_moved),
+                                         view);
+                       g_object_set_data (G_OBJECT (annot), "popup", window);
+
+                       doc_rect = (EvRectangle *)ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (window));
+                       doc_rect_to_view_rect (view, page, doc_rect, &view_rect);
+                       view_rect.x -= view->scroll_x;
+                       view_rect.y -= view->scroll_y;
+
+                       ev_view_window_child_put (view, window, page,
+                                                 view_rect.x, view_rect.y,
+                                                 doc_rect->x1, doc_rect->y1);
+
+                       g_object_weak_ref (G_OBJECT (annot),
+                                          (GWeakNotify)ev_view_annotation_save,
+                                          view);
+               }
+       }
+}
+
+static void
+hide_annotation_windows (EvView *view,
+                        gint    page)
+{
+       GList *annots, *l;
+
+       annots = ev_pixbuf_cache_get_annots_mapping (view->pixbuf_cache, page);
+
+       for (l = annots; l && l->data; l = g_list_next (l)) {
+               EvAnnotation *annot;
+               GtkWidget    *window;
+
+               annot = ((EvMapping *)(l->data))->data;
+
+               if (!EV_IS_ANNOTATION_MARKUP (annot))
+                       continue;
+
+               window = g_object_get_data (G_OBJECT (annot), "popup");
+               if (window)
+                       gtk_widget_hide (window);
+       }
+}
+
+static EvAnnotation *
+ev_view_get_annotation_at_location (EvView  *view,
+                                   gdouble  x,
+                                   gdouble  y)
+{
+       gint page = -1;
+       gint x_new = 0, y_new = 0;
+       GList *annotations_mapping;
+
+       if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document))
+               return NULL;
+
+       if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
+               return NULL;
+
+       annotations_mapping = ev_pixbuf_cache_get_annots_mapping (view->pixbuf_cache, page);
+
+       if (annotations_mapping)
+               return ev_mapping_list_get_data (annotations_mapping, x_new, y_new);
+       else
+               return NULL;
+}
+
+static void
+ev_view_handle_annotation (EvView       *view,
+                          EvAnnotation *annot,
+                          gdouble       x,
+                          gdouble       y)
+{
+       if (EV_IS_ANNOTATION_MARKUP (annot)) {
+               GtkWidget *window;
+
+               window = g_object_get_data (G_OBJECT (annot), "popup");
+               if (window) {
+                       EvViewWindowChild *child;
+
+                       child = ev_view_get_window_child (view, window);
+                       if (!child->visible) {
+                               child->visible = TRUE;
+                               ev_view_window_child_move (view, child, child->x, child->y);
+                               gtk_widget_show (window);
+                       }
+               }
+       }
+}
+
 /*** GtkWidget implementation ***/
 
 static void
@@ -2213,6 +2584,7 @@ ev_view_size_allocate (GtkWidget      *widget,
 {
        EvView *view = EV_VIEW (widget);
        GList  *children, *l;
+       gint    root_x, root_y;
 
        GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
        
@@ -2234,7 +2606,6 @@ ev_view_size_allocate (GtkWidget      *widget,
        children = gtk_container_get_children (GTK_CONTAINER (widget));
        for (l = children; l && l->data; l = g_list_next (l)) {
                EvFormField   *field;
-               EvRectangle    field_area;
                GdkRectangle   view_area;
                GList         *form_field_mapping;
                GtkAllocation  child_allocation;
@@ -2247,11 +2618,9 @@ ev_view_size_allocate (GtkWidget      *widget,
 
                form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache,
                                                                             field->page->index);
-               ev_form_field_mapping_get_area (form_field_mapping, field, &field_area);
-
-               doc_rect_to_view_rect (view, field->page->index, &field_area, &view_area);
-               view_area.x -= view->scroll_x;
-               view_area.y -= view->scroll_y;
+               ev_view_get_area_from_mapping (view, field->page->index,
+                                              form_field_mapping,
+                                              field, &view_area);
 
                gtk_widget_size_request (child, &child_requisition);
                if (child_requisition.width != view_area.width ||
@@ -2269,6 +2638,33 @@ ev_view_size_allocate (GtkWidget      *widget,
                }
        }
        g_list_free (children);
+
+       if (view->window_children)
+               gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)),
+                                      &root_x, &root_y);
+
+       for (l = view->window_children; l && l->data; l = g_list_next (l)) {
+               EvViewWindowChild *child;
+               EvRectangle        doc_rect;
+               GdkRectangle       view_rect;
+
+               child = (EvViewWindowChild *)l->data;
+
+               doc_rect = *ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (child->window));
+               if (child->moved) {
+                       doc_rect.x1 = child->orig_x;
+                       doc_rect.y1 = child->orig_y;
+               }
+               doc_rect_to_view_rect (view, child->page, &doc_rect, &view_rect);
+               view_rect.x -= view->scroll_x;
+               view_rect.y -= view->scroll_y;
+
+               if (view_rect.x != child->orig_x || view_rect.y != child->orig_y) {
+                       child->parent_x = root_x;
+                       child->parent_y = root_y;
+                       ev_view_window_child_move (view, child, view_rect.x + root_x, view_rect.y + root_y);
+               }
+       }
 }
 
 static void
@@ -2488,6 +2884,8 @@ ev_view_expose_event (GtkWidget      *widget,
 
                if (page_ready && view->find_pages && view->highlight_find_results)
                        highlight_find_results (view, i);
+               if (page_ready && EV_IS_DOCUMENT_ANNOTATIONS (view->document))
+                       show_annotation_windows (view, i);
        }
 
        cairo_destroy (cr);
@@ -2539,10 +2937,9 @@ get_link_area (EvView       *view,
               EvLink       *link,
               GdkRectangle *area)
 {
-       EvRectangle  ev_rect;
-       GList       *link_mapping;
-       gint         page;
-       gint         x_offset = 0, y_offset = 0;
+       GList *link_mapping;
+       gint   page;
+       gint   x_offset = 0, y_offset = 0;
 
        x += view->scroll_x;
        y += view->scroll_y;
@@ -2550,22 +2947,55 @@ get_link_area (EvView       *view,
        find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
        
        link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page);
-       ev_link_mapping_get_area (link_mapping, link, &ev_rect);
+       ev_view_get_area_from_mapping (view, page,
+                                      link_mapping,
+                                      link, area);
+}
 
-       doc_rect_to_view_rect (view, page, &ev_rect, area);
-       area->y -= view->scroll_y ;
+static void
+get_annot_area (EvView       *view,
+              gint          x,
+              gint          y,
+              EvAnnotation *annot,
+              GdkRectangle *area)
+{
+       GList *annots_mapping;
+       gint   page;
+       gint   x_offset = 0, y_offset = 0;
+
+       x += view->scroll_x;
+       y += view->scroll_y;
+
+       find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
+
+       annots_mapping = ev_pixbuf_cache_get_annots_mapping (view->pixbuf_cache, page);
+       ev_view_get_area_from_mapping (view, page,
+                                      annots_mapping,
+                                      annot, area);
 }
 
 static gboolean
-ev_view_query_tooltip (GtkWidget         *widget,
-                      gint               x,
-                      gint               y,
-                      gboolean           keyboard_tip,
-                      GtkTooltip        *tooltip)
+ev_view_query_tooltip (GtkWidget  *widget,
+                      gint        x,
+                      gint        y,
+                      gboolean    keyboard_tip,
+                      GtkTooltip *tooltip)
 {
-       EvView *view = EV_VIEW (widget);
-       EvLink *link;
-       gchar  *text;
+       EvView       *view = EV_VIEW (widget);
+       EvLink       *link;
+       EvAnnotation *annot;
+       gchar        *text;
+
+       annot = ev_view_get_annotation_at_location (view, x, y);
+       if (annot && annot->contents) {
+               GdkRectangle annot_area;
+
+               get_annot_area (view, x, y, annot, &annot_area);
+               gtk_tooltip_set_text (tooltip, annot->contents);
+               gtk_tooltip_set_tip_area (tooltip, &annot_area);
+
+               return TRUE;
+       }
 
        link = ev_view_get_link_at_location (view, x, y);
        if (!link)
@@ -2588,26 +3018,28 @@ static void
 start_selection_for_event (EvView         *view,
                           GdkEventButton *event)
 {
-       EvSelectionStyle style;
-
        clear_selection (view);
-       
+
        view->selection_info.start.x = event->x + view->scroll_x;
        view->selection_info.start.y = event->y + view->scroll_y;
 
        switch (event->type) {
                case GDK_2BUTTON_PRESS:
-                       style = EV_SELECTION_STYLE_WORD;
+                       view->selection_info.style = EV_SELECTION_STYLE_WORD;
                        break;
                case GDK_3BUTTON_PRESS:
-                       style = EV_SELECTION_STYLE_LINE;
+                       view->selection_info.style = EV_SELECTION_STYLE_LINE;
                        break;
                default:
-                       style = EV_SELECTION_STYLE_GLYPH;
-                       break;
+                       view->selection_info.style = EV_SELECTION_STYLE_GLYPH;
+                       return;
        }
 
-       view->selection_info.style = style;
+       /* In case of WORD or LINE, compute selections now */
+       compute_selections (view,
+                           view->selection_info.style,
+                           &(view->selection_info.start),
+                           &(view->selection_info.start));
 }
 
 static gboolean
@@ -2622,6 +3054,17 @@ ev_view_button_press_event (GtkWidget      *widget,
        if (!GTK_WIDGET_HAS_FOCUS (widget)) {
                gtk_widget_grab_focus (widget);
        }
+
+       if (view->window_child_focus) {
+               EvAnnotationWindow *window;
+               EvAnnotation       *annot;
+
+               window = EV_ANNOTATION_WINDOW (view->window_child_focus->window);
+               annot = ev_annotation_window_get_annotation (window);
+               ev_annotation_window_ungrab_focus (window);
+               ev_view_annotation_save (view, annot);
+               view->window_child_focus = NULL;
+       }
        
        view->pressed_button = event->button;
        view->selection_info.in_drag = FALSE;
@@ -2632,6 +3075,7 @@ ev_view_button_press_event (GtkWidget      *widget,
        switch (event->button) {
                case 1: {
                        EvImage *image;
+                       EvAnnotation *annot;
                        EvFormField *field;
 
                        if (EV_IS_SELECTION (view->document) && view->selection_info.selections) {
@@ -2646,6 +3090,8 @@ ev_view_button_press_event (GtkWidget      *widget,
                                }
 
                                gtk_widget_queue_draw (widget);
+                       } else if ((annot = ev_view_get_annotation_at_location (view, event->x, event->y))) {
+                               ev_view_handle_annotation (view, annot, event->x, event->y);
                        } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) {
                                ev_view_remove_all (view);
                                ev_view_handle_form_field (view, field, event->x, event->y);
@@ -3076,14 +3522,6 @@ ev_view_button_release_event (GtkWidget      *widget,
            view->selection_update_id = 0;
        }
 
-       if (!view->selection_info.in_selection &&
-           view->selection_info.style != EV_SELECTION_STYLE_GLYPH) {
-               compute_selections (view,
-                                   view->selection_info.style,
-                                   &(view->selection_info.start),
-                                   &(view->selection_info.start));
-       }
-
        if (view->selection_info.selections) {
                clear_link_selected (view);
                ev_view_update_primary_selection (view);
@@ -3337,7 +3775,26 @@ ev_view_key_press_event (GtkWidget   *widget,
 
        if (!view->document)
                return FALSE;
-       
+
+       if (!GTK_WIDGET_HAS_FOCUS (widget)) {
+               /* Forward key events to current focused window child */
+               if (view->window_child_focus) {
+                       GdkEventKey *new_event;
+                       gboolean     handled;
+
+                       new_event = (GdkEventKey *) gdk_event_copy ((GdkEvent *)event);
+                       g_object_unref (new_event->window);
+                       new_event->window = g_object_ref (view->window_child_focus->window->window);
+                       gtk_widget_realize (view->window_child_focus->window);
+                       handled = gtk_widget_event (view->window_child_focus->window, (GdkEvent *)new_event);
+                       gdk_event_free ((GdkEvent *)new_event);
+
+                       return handled;
+               }
+
+               return FALSE;
+       }
+
        if (!view->presentation ||
            view->presentation_state == EV_PRESENTATION_END)
                return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
@@ -3753,6 +4210,8 @@ ev_view_destroy (GtkObject *object)
                view->goto_entry = NULL;
        }
 
+       ev_view_window_children_free (view);
+
        if (view->selection_scroll_id) {
            g_source_remove (view->selection_scroll_id);
            view->selection_scroll_id = 0;
@@ -4068,6 +4527,8 @@ ev_view_init (EvView *view)
 {
        GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
 
+       view->start_page = -1;
+       view->end_page = -1;
        view->spacing = 5;
        view->scale = 1.0;
        view->current_page = 0;
@@ -4161,10 +4622,14 @@ ev_view_presentation_animation_start (EvView *view,
        if (!effect)
                return;
 
-       surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, view->current_page);
        view->animation = ev_transition_animation_new (effect);
+
+       surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, view->current_page);
        ev_transition_animation_set_origin_surface (view->animation, surface);
-               
+       surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, new_page);
+       if (surface)
+               ev_transition_animation_set_dest_surface (view->animation, surface);
+
        g_signal_connect (view->animation, "frame",
                          G_CALLBACK (ev_view_transition_animation_frame), view);
        g_signal_connect (view->animation, "finished",
@@ -4246,6 +4711,14 @@ on_adjustment_value_changed (GtkAdjustment *adjustment,
                gtk_layout_move (GTK_LAYOUT (view), child, child_x + dx, child_y + dy);
        }
        g_list_free (children);
+
+       for (l = view->window_children; l && l->data; l = g_list_next (l)) {
+               EvViewWindowChild *child;
+
+               child = (EvViewWindowChild *)l->data;
+
+               ev_view_window_child_move (view, child, child->x + dx, child->y + dy);
+       }
        
        if (view->pending_resize)
                gtk_widget_queue_draw (GTK_WIDGET (view));
@@ -4399,6 +4872,8 @@ ev_view_set_document (EvView     *view,
                        setup_caches (view);
                 }
 
+               view_update_range_and_current_page (view);
+
                gtk_widget_queue_resize (GTK_WIDGET (view));
        }
 }