]> www.fi.muni.cz Git - evince.git/blobdiff - libview/ev-view.c
libview: clear caches after destroying child widgets.
[evince.git] / libview / ev-view.c
index 47fb438c94f2c97b90e09f71a3feafffb31b58df..cbc6b4ac1286bace33bdc6d7218833bffe5ae680 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #include "config.h"
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 
-#include "ev-mapping.h"
+#include "ev-mapping-list.h"
 #include "ev-document-forms.h"
 #include "ev-document-images.h"
 #include "ev-document-links.h"
+#include "ev-document-layers.h"
 #include "ev-document-misc.h"
 #include "ev-pixbuf-cache.h"
 #include "ev-page-cache.h"
 #include "ev-view-marshal.h"
 #include "ev-document-annotations.h"
 #include "ev-annotation-window.h"
+#include "ev-loading-window.h"
 #include "ev-view.h"
 #include "ev-view-accessible.h"
 #include "ev-view-private.h"
@@ -53,6 +55,9 @@ enum {
        SIGNAL_EXTERNAL_LINK,
        SIGNAL_POPUP_MENU,
        SIGNAL_SELECTION_CHANGED,
+       SIGNAL_SYNC_SOURCE,
+       SIGNAL_ANNOT_ADDED,
+       SIGNAL_LAYERS_CHANGED,
        N_SIGNALS
 };
 
@@ -62,6 +67,14 @@ enum {
        TARGET_DND_IMAGE
 };
 
+enum {
+       PROP_0,
+       PROP_HADJUSTMENT,
+       PROP_VADJUSTMENT,
+       PROP_HSCROLL_POLICY,
+       PROP_VSCROLL_POLICY
+};
+
 static guint signals[N_SIGNALS];
 
 typedef enum {
@@ -69,19 +82,25 @@ typedef enum {
        EV_VIEW_FIND_PREV
 } EvViewFindDirection;
 
+typedef struct {
+       GtkWidget  *widget;
+
+       /* View coords */
+       gint        x;
+       gint        y;
+
+       /* Document */
+       guint       page;
+       EvRectangle doc_rect;
+} EvViewChild;
+
 #define ZOOM_IN_FACTOR  1.2
 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
 
 #define SCROLL_TIME 150
 
 /*** Scrolling ***/
-static void       ev_view_set_scroll_adjustments             (GtkLayout          *layout,
-                                                             GtkAdjustment      *hadjustment,
-                                                             GtkAdjustment      *vadjustment);
 static void       view_update_range_and_current_page         (EvView             *view);
-static void       set_scroll_adjustment                      (EvView             *view,
-                                                             GtkOrientation      orientation,
-                                                             GtkAdjustment      *adjustment);
 static void       add_scroll_binding_keypad                  (GtkBindingSet      *binding_set,
                                                              guint               keyval,
                                                              GdkModifierType modifiers,
@@ -98,10 +117,6 @@ static void       compute_border                             (EvView
 static void       get_page_y_offset                          (EvView             *view,
                                                              int                 page,
                                                              int                *y_offset);
-static gboolean   get_page_extents                           (EvView             *view,
-                                                             gint                page,
-                                                             GdkRectangle       *page_area,
-                                                             GtkBorder          *border);
 static void       view_rect_to_doc_rect                      (EvView             *view,
                                                              GdkRectangle       *view_rect,
                                                              GdkRectangle       *page_area,
@@ -153,11 +168,10 @@ static void       ev_view_size_request                       (GtkWidget
                                                              GtkRequisition     *requisition);
 static void       ev_view_size_allocate                      (GtkWidget          *widget,
                                                              GtkAllocation      *allocation);
-static void       ev_view_realize                            (GtkWidget          *widget);
 static gboolean   ev_view_scroll_event                       (GtkWidget          *widget,
                                                              GdkEventScroll     *event);
-static gboolean   ev_view_expose_event                       (GtkWidget          *widget,
-                                                             GdkEventExpose     *event);
+static gboolean   ev_view_draw                               (GtkWidget          *widget,
+                                                              cairo_t            *cr);
 static gboolean   ev_view_popup_menu                         (GtkWidget         *widget);
 static gboolean   ev_view_button_press_event                 (GtkWidget          *widget,
                                                              GdkEventButton     *event);
@@ -169,20 +183,22 @@ static gboolean   ev_view_enter_notify_event                 (GtkWidget
                                                              GdkEventCrossing   *event);
 static gboolean   ev_view_leave_notify_event                 (GtkWidget          *widget,
                                                              GdkEventCrossing   *event);
-static void       ev_view_style_set                          (GtkWidget          *widget,
-                                                             GtkStyle           *old_style);
+static void       ev_view_style_updated                      (GtkWidget          *widget);
 static void       ev_view_remove_all                         (EvView             *view);
 
 static AtkObject *ev_view_get_accessible                     (GtkWidget *widget);
 
 /*** Drawing ***/
-static guint32    ev_gdk_color_to_rgb                        (const GdkColor     *color);
-static void       draw_rubberband                            (GtkWidget          *widget,
-                                                             GdkWindow          *window,
-                                                             const GdkRectangle *rect,
-                                                             guchar              alpha);
 static void       highlight_find_results                     (EvView             *view,
+                                                              cairo_t            *cr,
                                                              int                 page);
+static void       highlight_forward_search_results           (EvView             *view,
+                                                              cairo_t            *cr,
+                                                             int                 page);
+static void       focus_annotation                           (EvView             *view,
+                                                              cairo_t            *cr,
+                                                             int                 page,
+                                                             GdkRectangle       *clip);
 static void       draw_one_page                              (EvView             *view,
                                                              gint                page,
                                                              cairo_t            *cr,
@@ -190,18 +206,18 @@ static void       draw_one_page                              (EvView
                                                              GtkBorder          *border,
                                                              GdkRectangle       *expose_area,
                                                              gboolean           *page_ready);
-static void      draw_loading_text                          (EvView             *view,
-                                                             GdkRectangle       *page_area,
-                                                             GdkRectangle       *expose_area);
+static void       show_loading_window                        (EvView             *view);
+static void       hide_loading_window                        (EvView             *view);
 static void       ev_view_reload_page                        (EvView             *view,
                                                              gint                page,
-                                                             GdkRegion          *region);
+                                                             cairo_region_t     *region);
+static void       ev_view_loading_window_move                (EvView             *view);
 
 /*** Callbacks ***/
 static void       ev_view_change_page                        (EvView             *view,
                                                              gint                new_page);
 static void       job_finished_cb                            (EvPixbufCache      *pixbuf_cache,
-                                                             GdkRegion          *region,
+                                                             cairo_region_t     *region,
                                                              EvView             *view);
 static void       ev_view_page_changed_cb                    (EvDocumentModel    *model,
                                                              gint                old_page,
@@ -212,7 +228,7 @@ static void       on_adjustment_value_changed                (GtkAdjustment
 
 /*** GObject ***/
 static void       ev_view_finalize                           (GObject            *object);
-static void       ev_view_destroy                            (GtkObject          *object);
+static void       ev_view_dispose                            (GObject            *object);
 static void       ev_view_class_init                         (EvViewClass        *class);
 static void       ev_view_init                               (EvView             *view);
 
@@ -261,7 +277,6 @@ static void       jump_to_find_result                        (EvView
 static void       jump_to_find_page                          (EvView             *view, 
                                                              EvViewFindDirection direction,
                                                              gint                shift);
-
 /*** Selection ***/
 static void       compute_selections                         (EvView             *view,
                                                              EvSelectionStyle    style,
@@ -279,7 +294,8 @@ static void       ev_view_primary_clear_cb                   (GtkClipboard
                                                              gpointer            data);
 static void       ev_view_update_primary_selection           (EvView             *ev_view);
 
-G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_LAYOUT)
+G_DEFINE_TYPE_WITH_CODE (EvView, ev_view, GTK_TYPE_CONTAINER,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
 
 /* HeightToPage cache */
 #define EV_HEIGHT_TO_PAGE_CACHE_KEY "ev-height-to-page-cache"
@@ -457,26 +473,29 @@ ev_view_get_scrollbar_size (EvView        *view,
        GtkWidget *widget = GTK_WIDGET (view);
        GtkWidget *sb;
        GtkWidget *swindow = gtk_widget_get_parent (GTK_WIDGET (view));
+       GtkAllocation allocation;
        GtkRequisition req;
        gint spacing;
 
        if (!GTK_IS_SCROLLED_WINDOW (swindow))
                return 0;
 
+       gtk_widget_get_allocation (widget, &allocation);
+
        if (orientation == GTK_ORIENTATION_VERTICAL) {
-               if (widget->allocation.height >= widget->requisition.height)
+               if (allocation.height >= view->requisition.height)
                        sb = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (swindow));
                else
                        return 0;
        } else {
-               if (widget->allocation.width >= widget->requisition.width)
+               if (allocation.width >= view->requisition.width)
                        sb = gtk_scrolled_window_get_hscrollbar (GTK_SCROLLED_WINDOW (swindow));
                else
                        return 0;
        }
 
        gtk_widget_style_get (swindow, "scrollbar_spacing", &spacing, NULL);
-       gtk_widget_size_request (sb, &req);
+       gtk_widget_get_preferred_size (sb, &req, NULL);
 
        return (orientation == GTK_ORIENTATION_VERTICAL ? req.width : req.height) + spacing;
 }
@@ -487,28 +506,33 @@ scroll_to_point (EvView        *view,
                 gdouble        y,
                 GtkOrientation orientation)
 {
+       gdouble page_size;
+       gdouble upper, lower;
+
        if (orientation == GTK_ORIENTATION_VERTICAL) {
+               page_size = gtk_adjustment_get_page_size (view->vadjustment);
+               upper = gtk_adjustment_get_upper (view->vadjustment);
+               lower = gtk_adjustment_get_lower (view->vadjustment);
+
                if (view->continuous) {
                        gtk_adjustment_clamp_page (view->vadjustment,
                                                   y - view->spacing / 2,
-                                                  y + view->vadjustment->page_size);
+                                                  y + page_size);
                } else {
                        gtk_adjustment_set_value (view->vadjustment,
-                                                 CLAMP (y,
-                                                 view->vadjustment->lower,
-                                                 view->vadjustment->upper -
-                                                 view->vadjustment->page_size));
+                                                 CLAMP (y, lower, upper - page_size));
                }
        } else {
+               page_size = gtk_adjustment_get_page_size (view->hadjustment);
+               upper = gtk_adjustment_get_upper (view->hadjustment);
+               lower = gtk_adjustment_get_lower (view->hadjustment);
+
                if (view->dual_page) {
                        gtk_adjustment_clamp_page (view->hadjustment, x,
-                                                  x + view->hadjustment->page_size);
+                                                  x + page_size);
                } else {
                        gtk_adjustment_set_value (view->hadjustment,
-                                                 CLAMP (x,
-                                                 view->hadjustment->lower,
-                                                 view->hadjustment->upper -
-                                                 view->hadjustment->page_size));
+                                                 CLAMP (x, lower, upper - page_size));
                }
        }
 }
@@ -526,7 +550,7 @@ ev_view_scroll_to_page_position (EvView *view, GtkOrientation orientation)
                GdkRectangle page_area;
                GtkBorder    border;
 
-               get_page_extents (view, view->current_page, &page_area, &border);
+               ev_view_get_page_extents (view, view->current_page, &page_area, &border);
                x = page_area.x;
                y = page_area.y;
        } else {
@@ -542,24 +566,29 @@ ev_view_scroll_to_page_position (EvView *view, GtkOrientation orientation)
 }
 
 static void
-view_set_adjustment_values (EvView         *view,
-                           GtkOrientation  orientation)
+ev_view_set_adjustment_values (EvView         *view,
+                              GtkOrientation  orientation)
 {
        GtkWidget *widget = GTK_WIDGET (view);
        GtkAdjustment *adjustment;
-       int requisition;
-       int allocation;
-
+       GtkAllocation allocation;
+       int req_size;
+       int alloc_size;
+       gdouble page_size;
+       gdouble value;
+       gdouble upper;
        double factor;
        gint new_value;
 
+       gtk_widget_get_allocation (widget, &allocation);
+
        if (orientation == GTK_ORIENTATION_HORIZONTAL)  {
-               requisition = widget->requisition.width;
-               allocation = widget->allocation.width;
+               req_size = view->requisition.width;
+               alloc_size = allocation.width;
                adjustment = view->hadjustment;
        } else {
-               requisition = widget->requisition.height;
-               allocation = widget->allocation.height;
+               req_size = view->requisition.height;
+               alloc_size = allocation.height;
                adjustment = view->vadjustment;
        }
 
@@ -567,23 +596,30 @@ view_set_adjustment_values (EvView         *view,
                return;
 
        factor = 1.0;
+       value = gtk_adjustment_get_value (adjustment);
+       upper = gtk_adjustment_get_upper (adjustment);
+       page_size = gtk_adjustment_get_page_size (adjustment);
+
        switch (view->pending_scroll) {
                case SCROLL_TO_KEEP_POSITION:
                case SCROLL_TO_FIND_LOCATION:
-                       factor = (adjustment->value) / adjustment->upper;
+                       factor = value / upper;
                        break;
                case SCROLL_TO_PAGE_POSITION:
                        break;
                case SCROLL_TO_CENTER:
-                       factor = (adjustment->value + adjustment->page_size * 0.5) / adjustment->upper;
+                       factor = (value + page_size * 0.5) / upper;
                        break;
        }
 
-       adjustment->page_size = allocation;
-       adjustment->step_increment = allocation * 0.1;
-       adjustment->page_increment = allocation * 0.9;
-       adjustment->lower = 0;
-       adjustment->upper = MAX (allocation, requisition);
+       upper = MAX (alloc_size, req_size);
+       page_size = alloc_size;
+
+       gtk_adjustment_set_page_size (adjustment, page_size);
+       gtk_adjustment_set_step_increment (adjustment, alloc_size * 0.1);
+       gtk_adjustment_set_page_increment (adjustment, alloc_size * 0.9);
+       gtk_adjustment_set_lower (adjustment, 0);
+       gtk_adjustment_set_upper (adjustment, upper);
 
        /*
         * We add 0.5 to the values before to average out our rounding errors.
@@ -591,15 +627,15 @@ view_set_adjustment_values (EvView         *view,
        switch (view->pending_scroll) {
                case SCROLL_TO_KEEP_POSITION:
                case SCROLL_TO_FIND_LOCATION:
-                       new_value = CLAMP (adjustment->upper * factor + 0.5, 0, adjustment->upper - adjustment->page_size);
+                       new_value = CLAMP (upper * factor + 0.5, 0, upper - page_size);
                        gtk_adjustment_set_value (adjustment, (int)new_value);
                        break;
                case SCROLL_TO_PAGE_POSITION:
                        ev_view_scroll_to_page_position (view, orientation);
                        break;
                case SCROLL_TO_CENTER:
-                       new_value = CLAMP (adjustment->upper * factor - adjustment->page_size * 0.5 + 0.5,
-                                          0, adjustment->upper - adjustment->page_size);
+                       new_value = CLAMP (upper * factor - page_size * 0.5 + 0.5,
+                                          0, upper - page_size);
                        gtk_adjustment_set_value (adjustment, (int)new_value);
                        break;
        }
@@ -628,14 +664,14 @@ view_update_range_and_current_page (EvView *view)
                if (!(view->vadjustment && view->hadjustment))
                        return;
 
-               current_area.x = view->hadjustment->value;
-               current_area.width = view->hadjustment->page_size;
-               current_area.y = view->vadjustment->value;
-               current_area.height = view->vadjustment->page_size;
+               current_area.x = gtk_adjustment_get_value (view->hadjustment);
+               current_area.width = gtk_adjustment_get_page_size (view->hadjustment);
+               current_area.y = gtk_adjustment_get_value (view->vadjustment);
+               current_area.height = gtk_adjustment_get_page_size (view->vadjustment);
 
                for (i = 0; i < ev_document_get_n_pages (view->document); i++) {
 
-                       get_page_extents (view, i, &page_area, &border);
+                       ev_view_get_page_extents (view, i, &page_area, &border);
 
                        if (gdk_rectangle_intersect (&current_area, &page_area, &unused)) {
                                area = unused.width * unused.height;
@@ -670,6 +706,7 @@ view_update_range_and_current_page (EvView *view)
 
                        if (view->current_page != best_current_page) {
                                view->current_page = best_current_page;
+                               hide_loading_window (view);
                                ev_document_model_set_page (view->model, best_current_page);
                        }
                }
@@ -692,6 +729,9 @@ view_update_range_and_current_page (EvView *view)
                view->end_page = view->current_page;
        }
 
+       if (view->start_page == -1 || view->end_page == -1)
+               return;
+
        if (start != view->start_page || end != view->end_page) {
                gint i;
 
@@ -710,8 +750,6 @@ view_update_range_and_current_page (EvView *view)
        ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
                                        view->start_page,
                                        view->end_page,
-                                       view->rotation,
-                                       view->scale,
                                        view->selection_info.selections);
 
        if (ev_pixbuf_cache_get_surface (view->pixbuf_cache, view->current_page))
@@ -719,47 +757,40 @@ view_update_range_and_current_page (EvView *view)
 }
 
 static void
-set_scroll_adjustment (EvView *view,
-                      GtkOrientation  orientation,
-                      GtkAdjustment  *adjustment)
+ev_view_set_scroll_adjustment (EvView         *view,
+                              GtkOrientation  orientation,
+                              GtkAdjustment  *adjustment)
 {
        GtkAdjustment **to_set;
+       const gchar    *prop_name;
 
-       if (orientation == GTK_ORIENTATION_HORIZONTAL)
+       if (orientation == GTK_ORIENTATION_HORIZONTAL) {
                to_set = &view->hadjustment;
-       else
+               prop_name = "hadjustment";
+       } else {
                to_set = &view->vadjustment;
+               prop_name = "vadjustment";
+       }
 
-       if (*to_set != adjustment) {
-               if (*to_set) {
-                       g_signal_handlers_disconnect_by_func (*to_set,
-                                                             (gpointer) on_adjustment_value_changed,
-                                                             view);
-                       g_object_unref (*to_set);
-               }
-
-               *to_set = adjustment;
-               view_set_adjustment_values (view, orientation);
+       if (adjustment && adjustment == *to_set)
+               return;
 
-               if (*to_set) {
-                       g_object_ref (*to_set);
-                       g_signal_connect (*to_set, "value_changed",
-                                         G_CALLBACK (on_adjustment_value_changed), view);
-               }
+       if (*to_set) {
+               g_signal_handlers_disconnect_by_func (*to_set,
+                                                     (gpointer) on_adjustment_value_changed,
+                                                     view);
+               g_object_unref (*to_set);
        }
-}
 
-static void
-ev_view_set_scroll_adjustments (GtkLayout      *layout,
-                               GtkAdjustment  *hadjustment,
-                               GtkAdjustment  *vadjustment)
-{
-       EvView *view = EV_VIEW (layout);
-       
-       set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL, hadjustment);
-       set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL, vadjustment);
-       
-       on_adjustment_value_changed (NULL, view);
+       if (!adjustment)
+               adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+       g_signal_connect (adjustment, "value_changed",
+                         G_CALLBACK (on_adjustment_value_changed),
+                         view);
+       *to_set = g_object_ref_sink (adjustment);
+       ev_view_set_adjustment_values (view, orientation);
+
+       g_object_notify (G_OBJECT (view), prop_name);
 }
 
 static void
@@ -769,7 +800,7 @@ add_scroll_binding_keypad (GtkBindingSet  *binding_set,
                           GtkScrollType   scroll,
                           gboolean        horizontal)
 {
-  guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
+  guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left;
 
   gtk_binding_entry_add_signal (binding_set, keyval, modifiers,
                                 "binding_activated", 2,
@@ -787,28 +818,28 @@ compute_scroll_increment (EvView        *view,
 {
        GtkWidget *widget = GTK_WIDGET (view);
        GtkAdjustment *adjustment = view->vadjustment;
-       GdkRegion *text_region, *region;
+       cairo_region_t *text_region, *region;
+       GtkAllocation allocation;
        gint page;
        GdkRectangle rect;
        EvRectangle doc_rect;
        GdkRectangle page_area;
        GtkBorder border;
-       GdkRectangle *recs;
-       gint n_recs;
        gdouble fraction = 1.0;
 
        if (scroll != GTK_SCROLL_PAGE_BACKWARD && scroll != GTK_SCROLL_PAGE_FORWARD)
-               return adjustment->page_size;
+               return gtk_adjustment_get_page_size (adjustment);
 
        page = scroll == GTK_SCROLL_PAGE_BACKWARD ? view->start_page : view->end_page;
 
        text_region = ev_page_cache_get_text_mapping (view->page_cache, page);
-       if (!text_region || gdk_region_empty (text_region))
-               return adjustment->page_size;
+       if (!text_region || cairo_region_is_empty (text_region))
+               return gtk_adjustment_get_page_size (adjustment);
 
-       get_page_extents (view, page, &page_area, &border);
+       gtk_widget_get_allocation (widget, &allocation);
+       ev_view_get_page_extents (view, page, &page_area, &border);
        rect.x = page_area.x + view->scroll_x;
-       rect.y = view->scroll_y + (scroll == GTK_SCROLL_PAGE_BACKWARD ? 5 : widget->allocation.height - 5);
+       rect.y = view->scroll_y + (scroll == GTK_SCROLL_PAGE_BACKWARD ? 5 : allocation.height - 5);
        rect.width = page_area.width;
        rect.height = 1;
        view_rect_to_doc_rect (view, &rect, &page_area, &doc_rect);
@@ -818,39 +849,39 @@ compute_scroll_increment (EvView        *view,
        rect.y = doc_rect.y1;
        rect.width = doc_rect.x2 - doc_rect.x1;
        rect.height = MAX (1, doc_rect.y2 - doc_rect.y1);
-       region = gdk_region_rectangle (&rect);
+       region = cairo_region_create_rectangle (&rect);
 
-       gdk_region_intersect (region, text_region);
-       gdk_region_get_rectangles (region, &recs, &n_recs);
-       gdk_region_destroy (region);
-       if (n_recs > 0) {
+       cairo_region_intersect (region, text_region);
+       if (cairo_region_num_rectangles (region)) {
                EvRenderContext *rc;
                EvPage  *ev_page;
+               cairo_region_t *sel_region;
 
+               cairo_region_get_rectangle (region, 0, &rect);
                ev_page = ev_document_get_page (view->document, page);
                rc = ev_render_context_new (ev_page, view->rotation, view->scale);
                g_object_unref (ev_page);
                /* Get the selection region to know the height of the line */
-               doc_rect.x1 = doc_rect.x2 = recs[0].x + 0.5;
-               doc_rect.y1 = doc_rect.y2 = recs[0].y + 0.5;
+               doc_rect.x1 = doc_rect.x2 = rect.x + 0.5;
+               doc_rect.y1 = doc_rect.y2 = rect.y + 0.5;
 
                ev_document_doc_mutex_lock ();
-               region = ev_selection_get_selection_region (EV_SELECTION (view->document),
-                                                           rc, EV_SELECTION_STYLE_LINE,
-                                                           &doc_rect);
+               sel_region = ev_selection_get_selection_region (EV_SELECTION (view->document),
+                                                               rc, EV_SELECTION_STYLE_LINE,
+                                                               &doc_rect);
                ev_document_doc_mutex_unlock ();
 
                g_object_unref (rc);
-               g_free (recs);
-               gdk_region_get_rectangles (region, &recs, &n_recs);
-               gdk_region_destroy (region);
-               if (n_recs > 0) {
-                       fraction = 1 - (recs[0].height / adjustment->page_size);
+
+               if (cairo_region_num_rectangles (sel_region) > 0) {
+                       cairo_region_get_rectangle (sel_region, 0, &rect);
+                       fraction = 1 - (rect.height / gtk_adjustment_get_page_size (adjustment));
                }
-               g_free (recs);
+               cairo_region_destroy (sel_region);
        }
+       cairo_region_destroy (region);
 
-       return adjustment->page_size * fraction;
+       return gtk_adjustment_get_page_size (adjustment) * fraction;
 
 }
 
@@ -861,6 +892,9 @@ ev_view_scroll (EvView        *view,
 {
        GtkAdjustment *adjustment;
        double value, increment;
+       gdouble upper, lower;
+       gdouble page_size;
+       gdouble step_increment;
        gboolean first_page = FALSE;
        gboolean last_page = FALSE;
 
@@ -884,7 +918,11 @@ ev_view_scroll (EvView        *view,
 
        /* Assign values for increment and vertical adjustment */
        adjustment = horizontal ? view->hadjustment : view->vadjustment;
-       value = adjustment->value;
+       value = gtk_adjustment_get_value (adjustment);
+       upper = gtk_adjustment_get_upper (adjustment);
+       lower = gtk_adjustment_get_lower (adjustment);
+       page_size = gtk_adjustment_get_page_size (adjustment);
+       step_increment = gtk_adjustment_get_step_increment (adjustment);
 
        /* Assign boolean for first and last page */
        if (view->current_page == 0)
@@ -895,50 +933,49 @@ ev_view_scroll (EvView        *view,
        switch (scroll) {
                case GTK_SCROLL_PAGE_BACKWARD:
                        /* Do not jump backwards if at the first page */
-                       if (value == (adjustment->lower) && first_page) {
+                       if (value == lower && first_page) {
                                /* Do nothing */
                                /* At the top of a page, assign the upper bound limit of previous page */
-                       } else if (value == (adjustment->lower)) {
-                               value = adjustment->upper - adjustment->page_size;
+                       } else if (value == lower) {
+                               value = upper - page_size;
                                ev_view_previous_page (view);
                                /* Jump to the top */
                        } else {
                                increment = compute_scroll_increment (view, GTK_SCROLL_PAGE_BACKWARD);
-                               value = MAX (value - increment, adjustment->lower);
+                               value = MAX (value - increment, lower);
                        }
                        break;
                case GTK_SCROLL_PAGE_FORWARD:
                        /* Do not jump forward if at the last page */
-                       if (value == (adjustment->upper - adjustment->page_size) && last_page) {
+                       if (value == (upper - page_size) && last_page) {
                                /* Do nothing */
                        /* At the bottom of a page, assign the lower bound limit of next page */
-                       } else if (value == (adjustment->upper - adjustment->page_size)) {
+                       } else if (value == (upper - page_size)) {
                                value = 0;
                                ev_view_next_page (view);
                        /* Jump to the bottom */
                        } else {
                                increment = compute_scroll_increment (view, GTK_SCROLL_PAGE_FORWARD);
-                               value = MIN (value + increment, adjustment->upper - adjustment->page_size);
+                               value = MIN (value + increment, upper - page_size);
                        }
                        break;
                case GTK_SCROLL_STEP_BACKWARD:
-                       value -= adjustment->step_increment;
+                       value -= step_increment;
                        break;
                case GTK_SCROLL_STEP_FORWARD:
-                       value += adjustment->step_increment;
+                       value += step_increment;
                        break;
                case GTK_SCROLL_STEP_DOWN:
-                       value -= adjustment->step_increment / 10;
+                       value -= step_increment / 10;
                        break;
                case GTK_SCROLL_STEP_UP:
-                       value += adjustment->step_increment / 10;
+                       value += step_increment / 10;
                        break;
                default:
                        break;
        }
 
-       value = CLAMP (value, adjustment->lower,
-                      adjustment->upper - adjustment->page_size);      
+       value = CLAMP (value, lower, upper - page_size);
 
        gtk_adjustment_set_value (adjustment, value);
 }
@@ -950,31 +987,35 @@ ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect)
 {
        GtkWidget *widget = GTK_WIDGET (view);
        GtkAdjustment *adjustment;
+       GtkAllocation allocation;
+       gdouble adj_value;
        int value;
 
        view->pending_scroll = SCROLL_TO_FIND_LOCATION;
 
+       gtk_widget_get_allocation (widget, &allocation);
+
        adjustment = view->vadjustment;
+       adj_value = gtk_adjustment_get_value (adjustment);
 
-       if (rect->y < adjustment->value) {
-               value = MAX (adjustment->lower, rect->y - MARGIN);
+       if (rect->y < adj_value) {
+               value = MAX (gtk_adjustment_get_lower (adjustment), rect->y - MARGIN);
                gtk_adjustment_set_value (view->vadjustment, value);
-       } else if (rect->y + rect->height >
-                  adjustment->value + widget->allocation.height) {
-               value = MIN (adjustment->upper, rect->y + rect->height -
-                            widget->allocation.height + MARGIN);
+       } else if (rect->y + rect->height > adj_value + allocation.height) {
+               value = MIN (gtk_adjustment_get_upper (adjustment), rect->y + rect->height -
+                            allocation.height + MARGIN);
                gtk_adjustment_set_value (view->vadjustment, value);
        }
 
        adjustment = view->hadjustment;
+       adj_value = gtk_adjustment_get_value (adjustment);
 
-       if (rect->x < adjustment->value) {
-               value = MAX (adjustment->lower, rect->x - MARGIN);
+       if (rect->x < adj_value) {
+               value = MAX (gtk_adjustment_get_lower (adjustment), rect->x - MARGIN);
                gtk_adjustment_set_value (view->hadjustment, value);
-       } else if (rect->x + rect->height >
-                  adjustment->value + widget->allocation.width) {
-               value = MIN (adjustment->upper, rect->x + rect->width -
-                            widget->allocation.width + MARGIN);
+       } else if (rect->x + rect->height > adj_value + allocation.width) {
+               value = MIN (gtk_adjustment_get_upper (adjustment), rect->x + rect->width -
+                            allocation.width + MARGIN);
                gtk_adjustment_set_value (view->hadjustment, value);
        }
 
@@ -1068,16 +1109,18 @@ get_page_y_offset (EvView *view, int page, int *y_offset)
        return;
 }
 
-static gboolean
-get_page_extents (EvView       *view,
-                 gint          page,
-                 GdkRectangle *page_area,
-                 GtkBorder    *border)
+gboolean
+ev_view_get_page_extents (EvView       *view,
+                         gint          page,
+                         GdkRectangle *page_area,
+                         GtkBorder    *border)
 {
        GtkWidget *widget;
        int width, height;
+       GtkAllocation allocation;
 
        widget = GTK_WIDGET (view);
+       gtk_widget_get_allocation (widget, &allocation);
 
        /* Get the size of the page */
        ev_view_get_page_size (view, page, &width, &height);
@@ -1094,12 +1137,12 @@ get_page_extents (EvView       *view,
                /* Get the location of the bounding box */
                if (view->dual_page) {
                        x = view->spacing + ((page % 2 == get_dual_even_left (view)) ? 0 : 1) * (max_width + view->spacing);
-                       x = x + MAX (0, widget->allocation.width - (max_width * 2 + view->spacing * 3)) / 2;
+                       x = x + MAX (0, allocation.width - (max_width * 2 + view->spacing * 3)) / 2;
                        if (page % 2 == get_dual_even_left (view))
                                x = x + (max_width - width - border->left - border->right);
                } else {
                        x = view->spacing;
-                       x = x + MAX (0, widget->allocation.width - (width + view->spacing * 2)) / 2;
+                       x = x + MAX (0, allocation.width - (width + view->spacing * 2)) / 2;
                }
 
                get_page_y_offset (view, page, &y);
@@ -1142,16 +1185,16 @@ get_page_extents (EvView       *view,
                        y = y + (max_height - height)/2;
 
                        /* Adjust for extra allocation */
-                       x = x + MAX (0, widget->allocation.width -
+                       x = x + MAX (0, allocation.width -
                                     ((max_width + overall_border.left + overall_border.right) * 2 + view->spacing * 3))/2;
-                       y = y + MAX (0, widget->allocation.height - (height + view->spacing * 2))/2;
+                       y = y + MAX (0, allocation.height - (height + view->spacing * 2))/2;
                } else {
                        x = view->spacing;
                        y = view->spacing;
 
                        /* Adjust for extra allocation */
-                       x = x + MAX (0, widget->allocation.width - (width + border->left + border->right + view->spacing * 2))/2;
-                       y = y + MAX (0, widget->allocation.height - (height + border->top + border->bottom +  view->spacing * 2))/2;
+                       x = x + MAX (0, allocation.width - (width + border->left + border->right + view->spacing * 2))/2;
+                       y = y + MAX (0, allocation.height - (height + border->top + border->bottom +  view->spacing * 2))/2;
                }
 
                page_area->x = x;
@@ -1231,7 +1274,7 @@ doc_point_to_view_point (EvView       *view,
                g_assert_not_reached ();
        }
 
-       get_page_extents (view, page, &page_area, &border);
+       ev_view_get_page_extents (view, page, &page_area, &border);
 
        view_x = CLAMP (x * view->scale, 0, page_area.width);
        view_y = CLAMP (y * view->scale, 0, page_area.height);
@@ -1276,7 +1319,7 @@ doc_rect_to_view_rect (EvView       *view,
                g_assert_not_reached ();
        }
 
-       get_page_extents (view, page, &page_area, &border);
+       ev_view_get_page_extents (view, page, &page_area, &border);
 
        view_rect->x = x * view->scale + page_area.x;
        view_rect->y = y * view->scale + page_area.y;
@@ -1311,7 +1354,7 @@ find_page_at_location (EvView  *view,
                GdkRectangle page_area;
                GtkBorder border;
 
-               if (! get_page_extents (view, i, &page_area, &border))
+               if (! ev_view_get_page_extents (view, i, &page_area, &border))
                        continue;
 
                if ((x >= page_area.x + border.left) &&
@@ -1333,7 +1376,7 @@ location_in_text (EvView  *view,
                  gdouble  x,
                  gdouble  y)
 {
-       GdkRegion *region;
+       cairo_region_t *region;
        gint page = -1;
        gint x_offset = 0, y_offset = 0;
 
@@ -1345,23 +1388,11 @@ location_in_text (EvView  *view,
        region = ev_page_cache_get_text_mapping (view->page_cache, page);
 
        if (region)
-               return gdk_region_point_in (region, x_offset / view->scale, y_offset / view->scale);
+               return cairo_region_contains_point (region, x_offset / view->scale, y_offset / view->scale);
        else
                return FALSE;
 }
 
-static int
-ev_view_get_width (EvView *view)
-{
-       return GTK_WIDGET (view)->allocation.width;
-}
-
-static int
-ev_view_get_height (EvView *view)
-{
-       return GTK_WIDGET (view)->allocation.height;
-}
-
 static gboolean
 location_in_selected_text (EvView  *view,
                           gdouble  x,
@@ -1381,7 +1412,7 @@ location_in_selected_text (EvView  *view,
                        continue;
                
                if (selection->covered_region &&
-                   gdk_region_point_in (selection->covered_region, x_offset, y_offset))
+                   cairo_region_contains_point (selection->covered_region, x_offset, y_offset))
                        return TRUE;
        }
 
@@ -1446,11 +1477,11 @@ get_doc_point_from_location (EvView  *view,
 }
 
 static void
-ev_view_get_area_from_mapping (EvView       *view,
-                              guint         page,
-                              GList        *mapping_list,
-                              gconstpointer data,
-                              GdkRectangle *area)
+ev_view_get_area_from_mapping (EvView        *view,
+                              guint          page,
+                              EvMappingList *mapping_list,
+                              gconstpointer  data,
+                              GdkRectangle  *area)
 {
        EvMapping *mapping;
 
@@ -1460,6 +1491,41 @@ ev_view_get_area_from_mapping (EvView       *view,
        area->y -= view->scroll_y;
 }
 
+static void
+ev_view_put (EvView      *view,
+            GtkWidget   *child_widget,
+            gint         x,
+            gint         y,
+            guint        page,
+            EvRectangle *doc_rect)
+{
+       EvViewChild *child;
+
+       child = g_slice_new (EvViewChild);
+
+       child->widget = child_widget;
+       child->x = x;
+       child->y = y;
+       child->page = page;
+       child->doc_rect = *doc_rect;
+
+       gtk_widget_set_parent (child_widget, GTK_WIDGET (view));
+       view->children = g_list_append (view->children, child);
+}
+
+static void
+ev_view_put_to_doc_rect (EvView      *view,
+                        GtkWidget   *child_widget,
+                        guint        page,
+                        EvRectangle *doc_rect)
+{
+       GdkRectangle area;
+
+       doc_rect_to_view_rect (view, page, doc_rect, &area);
+       area.x -= view->scroll_x;
+       area.y -= view->scroll_y;
+       ev_view_put (view, child_widget, area.x, area.y, page, doc_rect);
+}
 
 /*** Hyperref ***/
 static EvLink *
@@ -1469,7 +1535,7 @@ ev_view_get_link_at_location (EvView  *view,
 {
        gint page = -1;
        gint x_new = 0, y_new = 0;
-       GList *link_mapping;
+       EvMappingList *link_mapping;
 
        if (!EV_IS_DOCUMENT_LINKS (view->document))
                return NULL;
@@ -1491,14 +1557,17 @@ goto_fitr_dest (EvView *view, EvLinkDest *dest)
        EvPoint doc_point;
        gdouble zoom, left, top;
        gboolean change_left, change_top;
+       GtkAllocation allocation;
+
+       gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
 
        left = ev_link_dest_get_left (dest, &change_left);
        top = ev_link_dest_get_top (dest, &change_top);
 
        zoom = zoom_for_size_best_fit (ev_link_dest_get_right (dest) - left,
                                       ev_link_dest_get_bottom (dest) - top,
-                                      ev_view_get_width (view),
-                                      ev_view_get_height (view));
+                                      allocation.width,
+                                      allocation.height);
 
        ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
        ev_document_model_set_scale (view->model, zoom);
@@ -1518,6 +1587,9 @@ goto_fitv_dest (EvView *view, EvLinkDest *dest)
        gint page;
        double zoom, left;
        gboolean change_left;
+       GtkAllocation allocation;
+
+       gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
 
        page = ev_link_dest_get_page (dest);
        ev_document_get_page_size (view->document, page, &doc_width, &doc_height);
@@ -1527,8 +1599,8 @@ goto_fitv_dest (EvView *view, EvLinkDest *dest)
        doc_point.y = 0;
 
        zoom = zoom_for_size_fit_height (doc_width - doc_point.x , doc_height,
-                                        ev_view_get_width (view),
-                                        ev_view_get_height (view));
+                                        allocation.width,
+                                        allocation.height);
 
        ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
        ev_document_model_set_scale (view->model, zoom);
@@ -1546,6 +1618,9 @@ goto_fith_dest (EvView *view, EvLinkDest *dest)
        gint page;
        gdouble zoom, top;
        gboolean change_top;
+       GtkAllocation allocation;
+
+       gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
 
        page = ev_link_dest_get_page (dest);
        ev_document_get_page_size (view->document, page, &doc_width, &doc_height);
@@ -1556,8 +1631,8 @@ goto_fith_dest (EvView *view, EvLinkDest *dest)
        doc_point.y = change_top ? top : 0;
 
        zoom = zoom_for_size_fit_width (doc_width, top,
-                                       ev_view_get_width (view),
-                                       ev_view_get_height (view));
+                                       allocation.width,
+                                       allocation.height);
 
        ev_document_model_set_sizing_mode (view->model, EV_SIZING_FIT_WIDTH);
        ev_document_model_set_scale (view->model, zoom);
@@ -1573,13 +1648,16 @@ goto_fit_dest (EvView *view, EvLinkDest *dest)
        double zoom;
        gdouble doc_width, doc_height;
        int page;
+       GtkAllocation allocation;
+
+       gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
 
        page = ev_link_dest_get_page (dest);
        ev_document_get_page_size (view->document, page, &doc_width, &doc_height);
 
        zoom = zoom_for_size_best_fit (doc_width, doc_height,
-                                      ev_view_get_width (view),
-                                      ev_view_get_height (view));
+                                      allocation.width,
+                                      allocation.height);
 
        ev_document_model_set_sizing_mode (view->model, EV_SIZING_BEST_FIT);
        ev_document_model_set_scale (view->model, zoom);
@@ -1706,6 +1784,38 @@ ev_view_handle_link (EvView *view, EvLink *link)
                        ev_view_goto_dest (view, dest);
                }
                        break;
+               case EV_LINK_ACTION_TYPE_LAYERS_STATE: {
+                       GList            *show, *hide, *toggle;
+                       GList            *l;
+                       EvDocumentLayers *document_layers;
+
+                       document_layers = EV_DOCUMENT_LAYERS (view->document);
+
+                       show = ev_link_action_get_show_list (action);
+                       for (l = show; l; l = g_list_next (l)) {
+                               ev_document_layers_show_layer (document_layers, EV_LAYER (l->data));
+                       }
+
+                       hide = ev_link_action_get_hide_list (action);
+                       for (l = hide; l; l = g_list_next (l)) {
+                               ev_document_layers_hide_layer (document_layers, EV_LAYER (l->data));
+                       }
+
+                       toggle = ev_link_action_get_toggle_list (action);
+                       for (l = toggle; l; l = g_list_next (l)) {
+                               EvLayer *layer = EV_LAYER (l->data);
+
+                               if (ev_document_layers_layer_is_visible (document_layers, layer)) {
+                                       ev_document_layers_hide_layer (document_layers, layer);
+                               } else {
+                                       ev_document_layers_show_layer (document_layers, layer);
+                               }
+                       }
+
+                       g_signal_emit (view, signals[SIGNAL_LAYERS_CHANGED], 0);
+                       ev_view_reload_page (view, view->current_page, NULL);
+               }
+                       break;
                case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
                case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
                case EV_LINK_ACTION_TYPE_LAUNCH:
@@ -1801,6 +1911,12 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
        if (view->cursor == EV_VIEW_CURSOR_HIDDEN)
                return;
 
+       if (view->adding_annot) {
+               if (view->cursor != EV_VIEW_CURSOR_ADD)
+                       ev_view_set_cursor (view, EV_VIEW_CURSOR_ADD);
+               return;
+       }
+
        if (view->drag_info.in_drag) {
                if (view->cursor != EV_VIEW_CURSOR_DRAG)
                        ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
@@ -1835,7 +1951,8 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
                if (view->cursor == EV_VIEW_CURSOR_LINK ||
                    view->cursor == EV_VIEW_CURSOR_IBEAM ||
                    view->cursor == EV_VIEW_CURSOR_DRAG ||
-                   view->cursor == EV_VIEW_CURSOR_AUTOSCROLL)
+                   view->cursor == EV_VIEW_CURSOR_AUTOSCROLL ||
+                   view->cursor == EV_VIEW_CURSOR_ADD)
                        ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
        }
 
@@ -1851,7 +1968,7 @@ ev_view_get_image_at_location (EvView  *view,
 {
        gint page = -1;
        gint x_new = 0, y_new = 0;
-       GList *image_mapping;
+       EvMappingList *image_mapping;
 
        if (!EV_IS_DOCUMENT_IMAGES (view->document))
                return NULL;
@@ -1875,7 +1992,7 @@ ev_view_get_form_field_at_location (EvView  *view,
 {
        gint page = -1;
        gint x_new = 0, y_new = 0;
-       GList *forms_mapping;
+       EvMappingList *forms_mapping;
        
        if (!EV_IS_DOCUMENT_FORMS (view->document))
                return NULL;
@@ -1891,12 +2008,12 @@ ev_view_get_form_field_at_location (EvView  *view,
                return NULL;
 }
 
-static GdkRegion *
+static cairo_region_t *
 ev_view_form_field_get_region (EvView      *view,
                               EvFormField *field)
 {
-       GdkRectangle view_area;
-       GList       *forms_mapping;
+       GdkRectangle   view_area;
+       EvMappingList *forms_mapping;
 
        forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
                                                              field->page->index);
@@ -1904,7 +2021,7 @@ ev_view_form_field_get_region (EvView      *view,
                                       forms_mapping,
                                       field, &view_area);
 
-       return gdk_region_rectangle (&view_area);
+       return cairo_region_create_rectangle (&view_area);
 }
 
 static gboolean
@@ -1927,15 +2044,16 @@ ev_view_form_field_button_create_widget (EvView      *view,
                                         EvFormField *field)
 {
        EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field);
-       GdkRegion         *field_region = NULL;
+       cairo_region_t    *field_region = NULL;
        
        switch (field_button->type) {
                case EV_FORM_FIELD_BUTTON_PUSH:
                        return NULL;
                case EV_FORM_FIELD_BUTTON_CHECK:
                case EV_FORM_FIELD_BUTTON_RADIO: {
-                       gboolean  state;
-                       GList    *forms_mapping, *l;
+                       gboolean       state;
+                       EvMappingList *forms_mapping;
+                       GList         *l;
 
                        state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document),
                                                                               field);
@@ -1952,9 +2070,9 @@ ev_view_form_field_button_create_widget (EvView      *view,
                         */
                        forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
                                                                              field->page->index);
-                       for (l = forms_mapping; l; l = g_list_next (l)) {
+                       for (l = ev_mapping_list_get_list (forms_mapping); l; l = g_list_next (l)) {
                                EvFormField *button = ((EvMapping *)(l->data))->data;
-                               GdkRegion   *button_region;
+                               cairo_region_t *button_region;
 
                                if (button->id == field->id)
                                        continue;
@@ -1966,8 +2084,8 @@ ev_view_form_field_button_create_widget (EvView      *view,
                                        continue;
 
                                button_region = ev_view_form_field_get_region (view, button);
-                               gdk_region_union (field_region, button_region);
-                               gdk_region_destroy (button_region);
+                               cairo_region_union (field_region, button_region);
+                               cairo_region_destroy (button_region);
                        }
                        
                        ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document),
@@ -1978,7 +2096,7 @@ ev_view_form_field_button_create_widget (EvView      *view,
        }
 
        ev_view_reload_page (view, field->page->index, field_region);
-       gdk_region_destroy (field_region);
+       cairo_region_destroy (field_region);
        
        return NULL;
 }
@@ -1996,7 +2114,7 @@ ev_view_form_field_text_save (EvView    *view,
        
        if (field->changed) {
                EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
-               GdkRegion       *field_region;
+               cairo_region_t  *field_region;
 
                field_region = ev_view_form_field_get_region (view, field);
                
@@ -2004,7 +2122,7 @@ ev_view_form_field_text_save (EvView    *view,
                                                            field, field_text->text);
                field->changed = FALSE;
                ev_view_reload_page (view, field->page->index, field_region);
-               gdk_region_destroy (field_region);
+               cairo_region_destroy (field_region);
        }
 }
 
@@ -2033,6 +2151,16 @@ ev_view_form_field_text_changed (GtkWidget   *widget,
        }
 }
 
+static gboolean
+ev_view_form_field_text_focus_out (GtkWidget     *widget,
+                                  GdkEventFocus *event,
+                                  EvView        *view)
+{
+       ev_view_form_field_text_save (view, widget);
+
+       return FALSE;
+}
+
 static GtkWidget *
 ev_view_form_field_text_create_widget (EvView      *view,
                                       EvFormField *field)
@@ -2058,6 +2186,9 @@ ev_view_form_field_text_create_widget (EvView      *view,
                                g_free (txt);
                        }
 
+                       g_signal_connect (text, "focus-out-event",
+                                         G_CALLBACK (ev_view_form_field_text_focus_out),
+                                         view);
                        g_signal_connect (text, "changed",
                                          G_CALLBACK (ev_view_form_field_text_changed),
                                          field);
@@ -2075,7 +2206,10 @@ ev_view_form_field_text_create_widget (EvView      *view,
                                gtk_text_buffer_set_text (buffer, txt, -1);
                                g_free (txt);
                        }
-                       
+
+                       g_signal_connect( buffer, "focus-out-event",
+                                         G_CALLBACK (ev_view_form_field_text_focus_out),
+                                         view);
                        g_signal_connect (buffer, "changed",
                                          G_CALLBACK (ev_view_form_field_text_changed),
                                          field);
@@ -2104,7 +2238,7 @@ ev_view_form_field_choice_save (EvView    *view,
        if (field->changed) {
                GList             *l;
                EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
-               GdkRegion         *field_region;
+               cairo_region_t    *field_region;
 
                field_region = ev_view_form_field_get_region (view, field);
 
@@ -2121,7 +2255,7 @@ ev_view_form_field_choice_save (EvView    *view,
                }
                field->changed = FALSE;
                ev_view_reload_page (view, field->page->index, field_region);
-               gdk_region_destroy (field_region);
+               cairo_region_destroy (field_region);
        }
 }
 
@@ -2144,14 +2278,14 @@ ev_view_form_field_choice_changed (GtkWidget   *widget,
                        field->changed = TRUE;
                }
 
-               if (GTK_IS_COMBO_BOX_ENTRY (widget)) {
-                       gchar *text;
-                       
-                       text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (widget));
+               if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget))) {
+                       const gchar *text;
+
+                       text = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (widget))));
                        if (!field_choice->text ||
                            (field_choice->text && g_ascii_strcasecmp (field_choice->text, text) != 0)) {
                                g_free (field_choice->text);
-                               field_choice->text = text;
+                               field_choice->text = g_strdup (text);
                                field->changed = TRUE;
                        }
                }
@@ -2258,8 +2392,10 @@ ev_view_form_field_choice_create_widget (EvView      *view,
                                        view);
        } else if (field_choice->is_editable) { /* ComboBoxEntry */
                gchar *text;
-               
-               choice = gtk_combo_box_entry_new_with_model (model, 0);
+
+                /* FIXME once gtk bug 633050 is fixed */
+                choice = g_object_new (GTK_TYPE_COMBO_BOX, "has-entry", TRUE, "model", model, NULL);
+
                text = ev_document_forms_form_field_choice_get_text (EV_DOCUMENT_FORMS (view->document), field);
                if (text) {
                        gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (choice))), text);
@@ -2269,7 +2405,8 @@ ev_view_form_field_choice_create_widget (EvView      *view,
                g_signal_connect (choice, "changed",
                                  G_CALLBACK (ev_view_form_field_choice_changed),
                                  field);
-               g_signal_connect_after (GTK_BIN(choice)->child, "activate",
+               g_signal_connect_after (gtk_bin_get_child (GTK_BIN (choice)),
+                                       "activate",
                                        G_CALLBACK (ev_view_form_field_destroy),
                                        view);
        } else { /* ComboBoxText */
@@ -2309,9 +2446,9 @@ ev_view_handle_form_field (EvView      *view,
                           gdouble      x,
                           gdouble      y)
 {
-       GtkWidget   *field_widget = NULL;
-       GList       *form_field_mapping;
-       GdkRectangle view_area;
+       GtkWidget     *field_widget = NULL;
+       EvMappingList *form_field_mapping;
+       EvMapping     *mapping;
 
        if (field->is_read_only)
                return;
@@ -2336,11 +2473,8 @@ ev_view_handle_form_field (EvView      *view,
 
        form_field_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
                                                                   field->page->index);
-       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);
+       mapping = ev_mapping_list_find (form_field_mapping, field);
+       ev_view_put_to_doc_rect (view, field_widget, field->page->index, &mapping->area);
        gtk_widget_show (field_widget);
        gtk_widget_grab_focus (field_widget);
 }
@@ -2371,11 +2505,19 @@ ev_view_window_child_move (EvView            *view,
                           gint               x,
                           gint               y)
 {
+       GtkAllocation allocation;
+       gint          width, height;
+
+       gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
+       gtk_window_get_size (GTK_WINDOW (child->window), &width, &height);
+
        child->x = x;
        child->y = y;
        gtk_window_move (GTK_WINDOW (child->window),
-                        MAX (child->parent_x, x),
-                        MAX (child->parent_y, y));
+                        CLAMP (x, child->parent_x,
+                               child->parent_x + allocation.width - width),
+                        CLAMP (y, child->parent_y,
+                               child->parent_y + allocation.height - height));
 }
 
 static void
@@ -2398,7 +2540,7 @@ ev_view_window_child_move_with_parent (EvView    *view,
                ev_view_window_child_move (view, child, dest_x, dest_y);
        }
 
-       if (child->visible && !GTK_WIDGET_VISIBLE (window))
+       if (child->visible && !gtk_widget_get_visible (window))
                gtk_widget_show (window);
 }
 
@@ -2453,7 +2595,7 @@ ev_view_find_window_child_for_annot (EvView       *view,
                        continue;
 
                wannot = ev_annotation_window_get_annotation (EV_ANNOTATION_WINDOW (child->window));
-               if (wannot == annot || strcmp (wannot->name, annot->name) == 0)
+               if (ev_annotation_equal (wannot, annot))
                        return child;
        }
 
@@ -2529,44 +2671,80 @@ annotation_window_moved (EvAnnotationWindow *window,
        view_rect.width = width;
        view_rect.height = height;
 
-       get_page_extents (view, child->page, &page_area, &border);
+       ev_view_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)
+ev_view_annotation_save_contents (EvView       *view,
+                                 GParamSpec   *pspec,
+                                 EvAnnotation *annot)
 {
        if (!view->document)
                return;
 
-       if (!annot->changed)
-               return;
+       ev_document_doc_mutex_lock ();
+       ev_document_annotations_save_annotation (EV_DOCUMENT_ANNOTATIONS (view->document),
+                                                annot, EV_ANNOTATIONS_SAVE_CONTENTS);
+       ev_document_doc_mutex_unlock ();
+}
+
+static GtkWidget *
+ev_view_create_annotation_window (EvView       *view,
+                                 EvAnnotation *annot,
+                                 GtkWindow    *parent)
+{
+       GtkWidget   *window;
+       EvRectangle  doc_rect;
+       GdkRectangle view_rect;
+       guint        page;
+
+       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_signal_connect_swapped (annot, "notify::contents",
+                                 G_CALLBACK (ev_view_annotation_save_contents),
+                                 view);
+       g_object_set_data (G_OBJECT (annot), "popup", window);
+
+       page = ev_annotation_get_page_index (annot);
+       ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (window), &doc_rect);
+       doc_rect_to_view_rect (view, page, &doc_rect, &view_rect);
+       view_rect.x -= view->scroll_x;
+       view_rect.y -= view->scroll_y;
 
-       ev_document_annotations_annotation_set_contents (EV_DOCUMENT_ANNOTATIONS (view->document),
-                                                        annot, annot->contents);
-       annot->changed = FALSE;
+       ev_view_window_child_put (view, window, page,
+                                 view_rect.x, view_rect.y,
+                                 doc_rect.x1, doc_rect.y1);
+
+       return window;
 }
 
 static void
 show_annotation_windows (EvView *view,
                         gint    page)
 {
-       GList     *annots, *l;
-       GtkWindow *parent;
+       EvMappingList *annots;
+       GList         *l;
+       GtkWindow     *parent;
 
        parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
 
        annots = ev_page_cache_get_annot_mapping (view->page_cache, page);
 
-       for (l = annots; l && l->data; l = g_list_next (l)) {
+       for (l = ev_mapping_list_get_list (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;
 
@@ -2590,30 +2768,7 @@ show_annotation_windows (EvView *view,
                        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);
+                       ev_view_create_annotation_window (view, annot, parent);
                }
        }
 }
@@ -2622,11 +2777,12 @@ static void
 hide_annotation_windows (EvView *view,
                         gint    page)
 {
-       GList *annots, *l;
+       EvMappingList *annots;
+       GList         *l;
 
        annots = ev_page_cache_get_annot_mapping (view->page_cache, page);
 
-       for (l = annots; l && l->data; l = g_list_next (l)) {
+       for (l = ev_mapping_list_get_list (annots); l && l->data; l = g_list_next (l)) {
                EvAnnotation *annot;
                GtkWidget    *window;
 
@@ -2648,7 +2804,7 @@ ev_view_get_annotation_at_location (EvView  *view,
 {
        gint page = -1;
        gint x_new = 0, y_new = 0;
-       GList *annotations_mapping;
+       EvMappingList *annotations_mapping;
 
        if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document))
                return NULL;
@@ -2664,6 +2820,23 @@ ev_view_get_annotation_at_location (EvView  *view,
                return NULL;
 }
 
+static void
+ev_view_annotation_show_popup_window (EvView    *view,
+                                     GtkWidget *window)
+{
+       EvViewWindowChild *child;
+
+       if (!window)
+               return;
+
+       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);
+       }
+}
+
 static void
 ev_view_handle_annotation (EvView       *view,
                           EvAnnotation *annot,
@@ -2675,21 +2848,13 @@ ev_view_handle_annotation (EvView       *view,
                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);
-                       }
-               }
+               ev_view_annotation_show_popup_window (view, window);
        }
 
        if (EV_IS_ANNOTATION_ATTACHMENT (annot)) {
-               EvAttachment *attachment = EV_ANNOTATION_ATTACHMENT (annot)->attachment;
+               EvAttachment *attachment;
 
+               attachment = ev_annotation_attachment_get_attachment (EV_ANNOTATION_ATTACHMENT (annot));
                if (attachment) {
                        GError *error = NULL;
 
@@ -2706,6 +2871,170 @@ ev_view_handle_annotation (EvView       *view,
        }
 }
 
+static void
+ev_view_create_annotation (EvView          *view,
+                          EvAnnotationType annot_type,
+                          gint             x,
+                          gint             y)
+{
+       EvAnnotation   *annot;
+       GdkPoint        point;
+       GdkRectangle    page_area;
+       GtkBorder       border;
+       EvRectangle     doc_rect, popup_rect;
+       EvPage         *page;
+       GdkColor        color = { 0, 65535, 65535, 0 };
+       GdkRectangle    view_rect;
+       cairo_region_t *region;
+
+       point.x = x;
+       point.y = y;
+       ev_view_get_page_extents (view, view->current_page, &page_area, &border);
+       view_point_to_doc_point (view, &point, &page_area,
+                                &doc_rect.x1, &doc_rect.y1);
+       doc_rect.x2 = doc_rect.x1 + 24;
+       doc_rect.y2 = doc_rect.y1 + 24;
+
+       ev_document_doc_mutex_lock ();
+       page = ev_document_get_page (view->document, view->current_page);
+       switch (annot_type) {
+       case EV_ANNOTATION_TYPE_TEXT:
+               annot = ev_annotation_text_new (page);
+               break;
+       case EV_ANNOTATION_TYPE_ATTACHMENT:
+               /* TODO */
+               g_object_unref (page);
+               ev_document_doc_mutex_unlock ();
+               return;
+       default:
+               g_assert_not_reached ();
+       }
+       g_object_unref (page);
+
+       ev_annotation_set_color (annot, &color);
+
+       if (EV_IS_ANNOTATION_MARKUP (annot)) {
+               popup_rect.x1 = doc_rect.x2;
+               popup_rect.x2 = popup_rect.x1 + 200;
+               popup_rect.y1 = doc_rect.y2;
+               popup_rect.y2 = popup_rect.y1 + 150;
+               g_object_set (annot,
+                             "rectangle", &popup_rect,
+                             "has_popup", TRUE,
+                             "popup_is_open", FALSE,
+                             "label", g_get_real_name (),
+                             "opacity", 1.0,
+                             NULL);
+       }
+       ev_document_annotations_add_annotation (EV_DOCUMENT_ANNOTATIONS (view->document),
+                                               annot, &doc_rect);
+       ev_document_doc_mutex_unlock ();
+
+       /* If the page didn't have annots, mark the cache as dirty */
+       if (!ev_page_cache_get_annot_mapping (view->page_cache, view->current_page))
+               ev_page_cache_mark_dirty (view->page_cache, view->current_page);
+
+       if (EV_IS_ANNOTATION_MARKUP (annot)) {
+               GtkWindow *parent;
+               GtkWidget *window;
+
+               parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
+               window = ev_view_create_annotation_window (view, annot, parent);
+
+               /* Show the annot window the first time */
+               ev_view_annotation_show_popup_window (view, window);
+       }
+
+       doc_rect_to_view_rect (view, view->current_page, &doc_rect, &view_rect);
+       view_rect.x -= view->scroll_x;
+       view_rect.y -= view->scroll_y;
+       region = cairo_region_create_rectangle (&view_rect);
+       ev_view_reload_page (view, view->current_page, region);
+       cairo_region_destroy (region);
+
+       g_signal_emit (view, signals[SIGNAL_ANNOT_ADDED], 0, annot);
+}
+
+void
+ev_view_focus_annotation (EvView    *view,
+                         EvMapping *annot_mapping)
+{
+       GdkRectangle  view_rect;
+       EvAnnotation *annot;
+       guint         page;
+
+       if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document))
+               return;
+
+       if (view->focus_annotation == annot_mapping)
+               return;
+
+       view->focus_annotation = annot_mapping;
+       annot = (EvAnnotation *)annot_mapping->data;
+
+       page = ev_annotation_get_page_index (annot);
+       ev_document_model_set_page (view->model, page);
+
+       doc_rect_to_view_rect (view, page,
+                              &annot_mapping->area, &view_rect);
+       ensure_rectangle_is_visible (view, &view_rect);
+       gtk_widget_queue_draw (GTK_WIDGET (view));
+}
+
+void
+ev_view_begin_add_annotation (EvView          *view,
+                             EvAnnotationType annot_type)
+{
+       if (annot_type == EV_ANNOTATION_TYPE_UNKNOWN)
+               return;
+
+       if (view->adding_annot)
+               return;
+
+       view->adding_annot = TRUE;
+       view->adding_annot_type = annot_type;
+       ev_view_set_cursor (view, EV_VIEW_CURSOR_ADD);
+}
+
+void
+ev_view_cancel_add_annotation (EvView *view)
+{
+       gint x, y;
+
+       if (!view->adding_annot)
+               return;
+
+       view->adding_annot = FALSE;
+       gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
+       ev_view_handle_cursor_over_xy (view, x, y);
+}
+
+static gboolean
+ev_view_synctex_backward_search (EvView *view,
+                                gdouble x,
+                                gdouble y)
+{
+       gint page = -1;
+       gint x_new = 0, y_new = 0;
+       EvSourceLink *link;
+
+       if (!ev_document_has_synctex (view->document))
+               return FALSE;
+
+       if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
+               return FALSE;
+
+       link = ev_document_synctex_backward_search (view->document, page, x_new, y_new);
+       if (link) {
+               g_signal_emit (view, signals[SIGNAL_SYNC_SOURCE], 0, link);
+               g_free (link);
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
 /*** GtkWidget implementation ***/
 
 static void
@@ -2828,21 +3157,64 @@ ev_view_size_request (GtkWidget      *widget,
                      GtkRequisition *requisition)
 {
        EvView *view = EV_VIEW (widget);
-       
+
        if (view->document == NULL) {
-               requisition->width = 1;
-               requisition->height = 1;
+               view->requisition.width = 1;
+               view->requisition.height = 1;
+
+               *requisition = view->requisition;
+
                return;
        }
 
+       /* Get zoom for size here when not called from
+        * ev_view_size_allocate()
+        */
+       if (!view->internal_size_request &&
+           (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
+            view->sizing_mode == EV_SIZING_BEST_FIT)) {
+               GtkAllocation allocation;
+
+               gtk_widget_get_allocation (widget, &allocation);
+               ev_view_zoom_for_size (view,
+                                      allocation.width,
+                                      allocation.height);
+       }
+
        if (view->continuous && view->dual_page)
-               ev_view_size_request_continuous_dual_page (view, requisition);
+               ev_view_size_request_continuous_dual_page (view, &view->requisition);
        else if (view->continuous)
-               ev_view_size_request_continuous (view, requisition);
+               ev_view_size_request_continuous (view, &view->requisition);
        else if (view->dual_page)
-               ev_view_size_request_dual_page (view, requisition);
+               ev_view_size_request_dual_page (view, &view->requisition);
        else
-               ev_view_size_request_single_page (view, requisition);
+               ev_view_size_request_single_page (view, &view->requisition);
+
+       *requisition = view->requisition;
+}
+
+static void
+ev_view_get_preferred_width (GtkWidget *widget,
+                             gint      *minimum,
+                             gint      *natural)
+{
+        GtkRequisition requisition;
+
+        ev_view_size_request (widget, &requisition);
+
+        *minimum = *natural = requisition.width;
+}
+
+static void
+ev_view_get_preferred_height (GtkWidget *widget,
+                              gint      *minimum,
+                              gint      *natural)
+{
+        GtkRequisition requisition;
+
+        ev_view_size_request (widget, &requisition);
+
+        *minimum = *natural = requisition.height;
 }
 
 static void
@@ -2850,21 +3222,35 @@ ev_view_size_allocate (GtkWidget      *widget,
                       GtkAllocation  *allocation)
 {
        EvView *view = EV_VIEW (widget);
-       GList  *children, *l;
+       GList  *l;
        gint    root_x, root_y;
 
-       GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
-       
+       gtk_widget_set_allocation (widget, allocation);
+
+       if (gtk_widget_get_realized (widget))
+               gdk_window_move_resize (gtk_widget_get_window (widget),
+                                       allocation->x,
+                                       allocation->y,
+                                       allocation->width,
+                                       allocation->height);
+
+       if (!view->document)
+               return;
+
        if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
            view->sizing_mode == EV_SIZING_BEST_FIT) {
+               GtkRequisition req;
+
                ev_view_zoom_for_size (view,
                                       allocation->width,
                                       allocation->height);
-               ev_view_size_request (widget, &widget->requisition);
+               view->internal_size_request = TRUE;
+               ev_view_size_request (widget, &req);
+               view->internal_size_request = FALSE;
        }
-       
-       view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
-       view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
+
+       ev_view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
+       ev_view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
 
        if (view->document)
                view_update_range_and_current_page (view);
@@ -2874,41 +3260,20 @@ ev_view_size_allocate (GtkWidget      *widget,
        view->pending_point.x = 0;
        view->pending_point.y = 0;
 
-       children = gtk_container_get_children (GTK_CONTAINER (widget));
-       for (l = children; l && l->data; l = g_list_next (l)) {
-               EvFormField   *field;
-               GdkRectangle   view_area;
-               GList         *form_field_mapping;
-               GtkAllocation  child_allocation;
-               GtkRequisition child_requisition;
-               GtkWidget     *child = (GtkWidget *)l->data;
-               
-               field = g_object_get_data (G_OBJECT (child), "form-field");
-               if (!field)
+       for (l = view->children; l && l->data; l = g_list_next (l)) {
+               GdkRectangle view_area;
+               EvViewChild *child = (EvViewChild *)l->data;
+
+               if (!gtk_widget_get_visible (child->widget))
                        continue;
 
-               form_field_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
-                                                                          field->page->index);
-               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 ||
-                   child_requisition.height != view_area.height)
-                       gtk_widget_set_size_request (child, view_area.width, view_area.height);
-
-               gtk_container_child_get (GTK_CONTAINER (widget),
-                                        child,
-                                        "x", &child_allocation.x,
-                                        "y", &child_allocation.y,
-                                        NULL);
-               if (child_allocation.x != view_area.x ||
-                   child_allocation.y != view_area.y) {
-                       gtk_layout_move (GTK_LAYOUT (widget), child, view_area.x, view_area.y);
-               }
+               doc_rect_to_view_rect (view, child->page, &child->doc_rect, &view_area);
+               view_area.x -= view->scroll_x;
+               view_area.y -= view->scroll_y;
+
+               gtk_widget_set_size_request (child->widget, view_area.width, view_area.height);
+               gtk_widget_size_allocate (child->widget, &view_area);
        }
-       g_list_free (children);
 
        if (view->window_children)
                gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)),
@@ -2921,7 +3286,7 @@ ev_view_size_allocate (GtkWidget      *widget,
 
                child = (EvViewWindowChild *)l->data;
 
-               doc_rect = *ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (child->window));
+               ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (child->window), &doc_rect);
                if (child->moved) {
                        doc_rect.x1 = child->orig_x;
                        doc_rect.y1 = child->orig_y;
@@ -2938,31 +3303,6 @@ ev_view_size_allocate (GtkWidget      *widget,
        }
 }
 
-static void
-ev_view_realize (GtkWidget *widget)
-{
-       EvView *view = EV_VIEW (widget);
-
-       if (GTK_WIDGET_CLASS (ev_view_parent_class)->realize)
-               (* GTK_WIDGET_CLASS (ev_view_parent_class)->realize) (widget);
-
-       gdk_window_set_events (view->layout.bin_window,
-                              (gdk_window_get_events (view->layout.bin_window) | 
-                               GDK_EXPOSURE_MASK |
-                               GDK_BUTTON_PRESS_MASK |
-                               GDK_BUTTON_RELEASE_MASK |
-                               GDK_SCROLL_MASK |
-                               GDK_KEY_PRESS_MASK |
-                               GDK_POINTER_MOTION_MASK |
-                               GDK_POINTER_MOTION_HINT_MASK |
-                               GDK_ENTER_NOTIFY_MASK |
-                               GDK_LEAVE_NOTIFY_MASK));
-
-       gdk_window_set_background (view->layout.bin_window, &widget->style->mid [GTK_STATE_NORMAL]);
-
-       on_adjustment_value_changed (NULL, view);
-}
-
 static gboolean
 ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
 {
@@ -3040,53 +3380,84 @@ find_selection_for_page (EvView *view,
        return NULL;
 }
 
+static void
+ev_view_realize (GtkWidget *widget)
+{
+       GtkAllocation allocation;
+       GdkWindow *window;
+       GdkWindowAttr attributes;
+       gint attributes_mask;
+
+       gtk_widget_set_realized (widget, TRUE);
+
+       gtk_widget_get_allocation (widget, &allocation);
+
+       attributes.window_type = GDK_WINDOW_CHILD;
+       attributes.x = allocation.x;
+       attributes.y = allocation.y;
+       attributes.width = allocation.width;
+       attributes.height = allocation.height;
+       attributes.wclass = GDK_INPUT_OUTPUT;
+       attributes.visual = gtk_widget_get_visual (widget);
+       attributes.event_mask = gtk_widget_get_events (widget);
+
+       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+
+       window = gdk_window_new (gtk_widget_get_parent_window (widget),
+                                &attributes, attributes_mask);
+       gtk_widget_set_window (widget, window);
+       gdk_window_set_user_data (window, widget);
+
+       gtk_style_context_set_background (gtk_widget_get_style_context (widget),
+                                         window);
+}
+
 static gboolean
-ev_view_expose_event (GtkWidget      *widget,
-                     GdkEventExpose *event)
+ev_view_draw (GtkWidget *widget,
+              cairo_t   *cr)
 {
-       EvView  *view = EV_VIEW (widget);
-       cairo_t *cr;
-       gint     i;
+       EvView      *view = EV_VIEW (widget);
+       gint         i;
+       GdkRectangle clip_rect;
 
        if (view->loading) {
-               GdkRectangle area = {0};
-               
-               area.width = widget->allocation.width;
-               area.height = widget->allocation.height;
-
-               draw_loading_text (view,
-                                  &area,
-                                  &(event->area));
+               show_loading_window (view);
+       } else if (view->loading_window &&
+                  gtk_widget_get_visible (view->loading_window)) {
+               ev_view_loading_window_move (view);
        }
 
        if (view->document == NULL)
                return FALSE;
 
-       cr = gdk_cairo_create (view->layout.bin_window);
+        if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect))
+                return FALSE;
 
        for (i = view->start_page; i >= 0 && i <= view->end_page; i++) {
                GdkRectangle page_area;
                GtkBorder border;
                gboolean page_ready = TRUE;
 
-               if (!get_page_extents (view, i, &page_area, &border))
+               if (!ev_view_get_page_extents (view, i, &page_area, &border))
                        continue;
 
                page_area.x -= view->scroll_x;
                page_area.y -= view->scroll_y;
 
-               draw_one_page (view, i, cr, &page_area, &border, &(event->area), &page_ready);
+               draw_one_page (view, i, cr, &page_area, &border, &clip_rect, &page_ready);
 
                if (page_ready && view->find_pages && view->highlight_find_results)
-                       highlight_find_results (view, i);
+                       highlight_find_results (view, cr, i);
                if (page_ready && EV_IS_DOCUMENT_ANNOTATIONS (view->document))
                        show_annotation_windows (view, i);
+               if (page_ready && view->focus_annotation)
+                        focus_annotation (view, cr, i, &clip_rect);
+               if (page_ready && view->synctex_result)
+                       highlight_forward_search_results (view, cr, i);
        }
 
-       cairo_destroy (cr);
-
-       if (GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event)
-               (* GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (widget, event);
+        if (GTK_WIDGET_CLASS (ev_view_parent_class)->draw)
+                GTK_WIDGET_CLASS (ev_view_parent_class)->draw (widget, cr);
 
        return FALSE;
 }
@@ -3096,29 +3467,26 @@ ev_view_do_popup_menu (EvView *view,
                       gdouble x,
                       gdouble y)
 {
+       GList        *items = NULL;
        EvLink       *link;
        EvImage      *image;
        EvAnnotation *annot;
 
        image = ev_view_get_image_at_location (view, x, y);
-       if (image) {
-               g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, image);
-               return TRUE;
-       }
+       if (image)
+               items = g_list_prepend (items, image);
 
        link = ev_view_get_link_at_location (view, x, y);
-       if (link) {
-               g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, link);
-               return TRUE;
-       }
+       if (link)
+               items = g_list_prepend (items, link);
 
        annot = ev_view_get_annotation_at_location (view, x, y);
-       if (annot) {
-               g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, annot);
-               return TRUE;
-       }
+       if (annot)
+               items = g_list_prepend (items, annot);
+
+       g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, items);
 
-       g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, NULL);
+       g_list_free (items);
 
        return TRUE;
 }
@@ -3139,9 +3507,9 @@ get_link_area (EvView       *view,
               EvLink       *link,
               GdkRectangle *area)
 {
-       GList *link_mapping;
-       gint   page;
-       gint   x_offset = 0, y_offset = 0;
+       EvMappingList *link_mapping;
+       gint           page;
+       gint           x_offset = 0, y_offset = 0;
 
        x += view->scroll_x;
        y += view->scroll_y;
@@ -3161,9 +3529,9 @@ get_annot_area (EvView       *view,
               EvAnnotation *annot,
               GdkRectangle *area)
 {
-       GList *annot_mapping;
-       gint   page;
-       gint   x_offset = 0, y_offset = 0;
+       EvMappingList *annot_mapping;
+       gint           page;
+       gint           x_offset = 0, y_offset = 0;
 
        x += view->scroll_x;
        y += view->scroll_y;
@@ -3189,14 +3557,18 @@ ev_view_query_tooltip (GtkWidget  *widget,
        gchar        *text;
 
        annot = ev_view_get_annotation_at_location (view, x, y);
-       if (annot && annot->contents) {
-               GdkRectangle annot_area;
+       if (annot) {
+               const gchar *contents;
 
-               get_annot_area (view, x, y, annot, &annot_area);
-               gtk_tooltip_set_text (tooltip, annot->contents);
-               gtk_tooltip_set_tip_area (tooltip, &annot_area);
+               if ((contents = ev_annotation_get_contents (annot))) {
+                       GdkRectangle annot_area;
 
-               return TRUE;
+                       get_annot_area (view, x, y, annot, &annot_area);
+                       gtk_tooltip_set_text (tooltip, contents);
+                       gtk_tooltip_set_tip_area (tooltip, &annot_area);
+
+                       return TRUE;
+               }
        }
 
        link = ev_view_get_link_at_location (view, x, y);
@@ -3210,10 +3582,13 @@ ev_view_query_tooltip (GtkWidget  *widget,
                get_link_area (view, x, y, link, &link_area);
                gtk_tooltip_set_text (tooltip, text);
                gtk_tooltip_set_tip_area (tooltip, &link_area);
+               g_free (text);
+
+               return TRUE;
        }
        g_free (text);
 
-       return TRUE;
+       return FALSE;
 }
 
 static void
@@ -3253,7 +3628,7 @@ ev_view_button_press_event (GtkWidget      *widget,
        if (!view->document)
                return FALSE;
        
-       if (!GTK_WIDGET_HAS_FOCUS (widget)) {
+       if (!gtk_widget_has_focus (widget)) {
                gtk_widget_grab_focus (widget);
        }
 
@@ -3264,13 +3639,15 @@ ev_view_button_press_event (GtkWidget      *widget,
                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;
 
+       if (view->adding_annot)
+               return FALSE;
+
        if (view->scroll_info.autoscrolling)
                return TRUE;
        
@@ -3280,6 +3657,9 @@ ev_view_button_press_event (GtkWidget      *widget,
                        EvAnnotation *annot;
                        EvFormField *field;
 
+                       if (event->state & GDK_CONTROL_MASK)
+                               return ev_view_synctex_backward_search (view, event->x , event->y);
+
                        if (EV_IS_SELECTION (view->document) && view->selection_info.selections) {
                                if (event->type == GDK_3BUTTON_PRESS) {
                                        start_selection_for_event (view, event);
@@ -3308,7 +3688,16 @@ ev_view_button_press_event (GtkWidget      *widget,
                                view->image_dnd_info.start.y = event->y + view->scroll_y;
                        } else {
                                ev_view_remove_all (view);
-                               
+
+                               if (view->synctex_result) {
+                                       g_free (view->synctex_result);
+                                       view->synctex_result = NULL;
+                                       gtk_widget_queue_draw (widget);
+                               }
+
+                               if (view->focus_annotation)
+                                       view->focus_annotation = NULL;
+
                                if (EV_IS_SELECTION (view->document))
                                        start_selection_for_event (view, event);
                        }
@@ -3336,14 +3725,7 @@ ev_view_button_press_event (GtkWidget      *widget,
 static void
 ev_view_remove_all (EvView *view)
 {
-       GList *children, *child;
-
-       children = gtk_container_get_children (GTK_CONTAINER (view));
-       for (child = children; child && child->data; child = g_list_next (child)) {
-               gtk_container_remove (GTK_CONTAINER (view),
-                                     GTK_WIDGET (child->data));
-       }
-       g_list_free (children);
+       gtk_container_foreach (GTK_CONTAINER (view), (GtkCallback) gtk_widget_destroy, NULL);
 }
 
 /*** Drag and Drop ***/
@@ -3413,7 +3795,7 @@ ev_view_drag_motion (GtkWidget      *widget,
        if (gtk_drag_get_source_widget (context) == widget)
                gdk_drag_status (context, 0, time);
        else
-               gdk_drag_status (context, context->suggested_action, time);
+               gdk_drag_status (context, gdk_drag_context_get_suggested_action (context), time);
        
        return TRUE;
 }
@@ -3434,34 +3816,36 @@ selection_scroll_timeout_cb (EvView *view)
 {      
        gint x, y, shift = 0;
        GtkWidget *widget = GTK_WIDGET (view);
-       
+       GtkAllocation allocation;
+
+       gtk_widget_get_allocation (widget, &allocation);
        gtk_widget_get_pointer (widget, &x, &y);
 
-       if (y > widget->allocation.height) {
-               shift = (y - widget->allocation.height) / 2;
+       if (y > allocation.height) {
+               shift = (y - allocation.height) / 2;
        } else if (y < 0) {
                shift = y / 2;
        }
 
        if (shift)
                gtk_adjustment_set_value (view->vadjustment,
-                                         CLAMP (view->vadjustment->value + shift,
-                                         view->vadjustment->lower,
-                                         view->vadjustment->upper -
-                                         view->vadjustment->page_size));       
+                                         CLAMP (gtk_adjustment_get_value (view->vadjustment) + shift,
+                                                gtk_adjustment_get_lower (view->vadjustment),
+                                                gtk_adjustment_get_upper (view->vadjustment) -
+                                                gtk_adjustment_get_page_size (view->vadjustment)));
 
-       if (x > widget->allocation.width) {
-               shift = (x - widget->allocation.width) / 2;
+       if (x > allocation.width) {
+               shift = (x - allocation.width) / 2;
        } else if (x < 0) {
                shift = x / 2;
        }
 
        if (shift)
                gtk_adjustment_set_value (view->hadjustment,
-                                         CLAMP (view->hadjustment->value + shift,
-                                         view->hadjustment->lower,
-                                         view->hadjustment->upper -
-                                         view->hadjustment->page_size));       
+                                         CLAMP (gtk_adjustment_get_value (view->hadjustment) + shift,
+                                                gtk_adjustment_get_lower (view->hadjustment),
+                                                gtk_adjustment_get_upper (view->hadjustment) -
+                                                gtk_adjustment_get_page_size (view->hadjustment)));
 
        return TRUE;
 }
@@ -3493,36 +3877,47 @@ ev_view_scroll_drag_release (EvView *view)
 {
        gdouble dhadj_value, dvadj_value;
        gdouble oldhadjustment, oldvadjustment;
+       gdouble h_page_size, v_page_size;
+       gdouble h_upper, v_upper;
+       GtkAllocation allocation;
 
        view->drag_info.momentum.x /= 1.2;
        view->drag_info.momentum.y /= 1.2; /* Alter these constants to change "friction" */
 
-       dhadj_value = view->hadjustment->page_size *
-                     (gdouble)view->drag_info.momentum.x / GTK_WIDGET (view)->allocation.width;
-       dvadj_value = view->vadjustment->page_size *
-                     (gdouble)view->drag_info.momentum.y / GTK_WIDGET (view)->allocation.height;
+       gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
+
+       h_page_size = gtk_adjustment_get_page_size (view->hadjustment);
+       v_page_size = gtk_adjustment_get_page_size (view->vadjustment);
+
+       dhadj_value = h_page_size *
+                     (gdouble)view->drag_info.momentum.x / allocation.width;
+       dvadj_value = v_page_size *
+                     (gdouble)view->drag_info.momentum.y / allocation.height;
 
        oldhadjustment = gtk_adjustment_get_value (view->hadjustment);
        oldvadjustment = gtk_adjustment_get_value (view->vadjustment);
 
-     /* When we reach the edges, we need either to absorb some momentum and bounce by
-      * multiplying it on -0.5 or stop scrolling by setting momentum to 0. */  
-     if (((oldhadjustment + dhadj_value) > (view->hadjustment->upper - view->hadjustment->page_size)) ||
-          ((oldhadjustment + dhadj_value) < 0))
+       h_upper = gtk_adjustment_get_upper (view->hadjustment);
+       v_upper = gtk_adjustment_get_upper (view->vadjustment);
+
+       /* When we reach the edges, we need either to absorb some momentum and bounce by
+        * multiplying it on -0.5 or stop scrolling by setting momentum to 0. */
+       if (((oldhadjustment + dhadj_value) > (h_upper - h_page_size)) ||
+           ((oldhadjustment + dhadj_value) < 0))
                view->drag_info.momentum.x = 0;
-       if (((oldvadjustment + dvadj_value) > (view->vadjustment->upper - view->vadjustment->page_size)) ||
-          ((oldvadjustment + dvadj_value) < 0))
+       if (((oldvadjustment + dvadj_value) > (v_upper - v_page_size)) ||
+           ((oldvadjustment + dvadj_value) < 0))
                view->drag_info.momentum.y = 0;
 
        gtk_adjustment_set_value (view->hadjustment,
-                               MIN (oldhadjustment + dhadj_value,
-                               view->hadjustment->upper - view->hadjustment->page_size));
+                                 MIN (oldhadjustment + dhadj_value,
+                                      h_upper - h_page_size));
        gtk_adjustment_set_value (view->vadjustment,
-                               MIN (oldvadjustment + dvadj_value,
-                               view->vadjustment->upper - view->vadjustment->page_size));
+                                 MIN (oldvadjustment + dvadj_value,
+                                      v_upper - v_page_size));
 
        if (((view->drag_info.momentum.x < 1) && (view->drag_info.momentum.x > -1)) &&
-          ((view->drag_info.momentum.y < 1) && (view->drag_info.momentum.y > -1)))
+           ((view->drag_info.momentum.y < 1) && (view->drag_info.momentum.y > -1)))
                return FALSE;
        else
                return TRUE;
@@ -3532,13 +3927,16 @@ static gboolean
 ev_view_motion_notify_event (GtkWidget      *widget,
                             GdkEventMotion *event)
 {
-       EvView *view = EV_VIEW (widget);
-       gint x, y;
+       EvView    *view = EV_VIEW (widget);
+       GdkWindow *window;
+       gint       x, y;
 
        if (!view->document)
                return FALSE;
 
-        if (event->is_hint || event->window != view->layout.bin_window) {
+       window = gtk_widget_get_window (widget);
+
+        if (event->is_hint || event->window != window) {
            gtk_widget_get_pointer (widget, &x, &y);
         } else {
            x = event->x;
@@ -3647,6 +4045,7 @@ ev_view_motion_notify_event (GtkWidget      *widget,
                if (view->drag_info.in_drag) {
                        int dx, dy;
                        gdouble dhadj_value, dvadj_value;
+                       GtkAllocation allocation;
 
                        view->drag_info.buffer[0].x = event->x;
                        view->drag_info.buffer[0].y = event->y;
@@ -3654,20 +4053,22 @@ ev_view_motion_notify_event (GtkWidget      *widget,
                        dx = event->x_root - view->drag_info.start.x;
                        dy = event->y_root - view->drag_info.start.y;
 
-                       dhadj_value = view->hadjustment->page_size *
-                                     (gdouble)dx / widget->allocation.width;
-                       dvadj_value = view->vadjustment->page_size *
-                                     (gdouble)dy / widget->allocation.height;
+                       gtk_widget_get_allocation (widget, &allocation);
+
+                       dhadj_value = gtk_adjustment_get_page_size (view->hadjustment) *
+                                     (gdouble)dx / allocation.width;
+                       dvadj_value = gtk_adjustment_get_page_size (view->vadjustment) *
+                                     (gdouble)dy / allocation.height;
 
                        /* clamp scrolling to visible area */
                        gtk_adjustment_set_value (view->hadjustment,
-                                                 MIN(view->drag_info.hadj - dhadj_value,
-                                                     view->hadjustment->upper -
-                                                     view->hadjustment->page_size));
+                                                 MIN (view->drag_info.hadj - dhadj_value,
+                                                      gtk_adjustment_get_upper (view->hadjustment) -
+                                                      gtk_adjustment_get_page_size (view->hadjustment)));
                        gtk_adjustment_set_value (view->vadjustment,
-                                                 MIN(view->drag_info.vadj - dvadj_value,
-                                                     view->vadjustment->upper -
-                                                     view->vadjustment->page_size));
+                                                 MIN (view->drag_info.vadj - dvadj_value,
+                                                      gtk_adjustment_get_upper (view->vadjustment) -
+                                                      gtk_adjustment_get_page_size (view->vadjustment)));
 
                        return TRUE;
                }
@@ -3694,7 +4095,12 @@ ev_view_button_release_event (GtkWidget      *widget,
                view->pressed_button = -1;
 
                return TRUE;
-       } 
+       }
+
+       if (view->pressed_button == 1 && event->state & GDK_CONTROL_MASK) {
+               view->pressed_button = -1;
+               return TRUE;
+       }
 
        if (view->drag_info.in_drag) {
                view->drag_info.release_timeout_id =
@@ -3708,6 +4114,19 @@ ev_view_button_release_event (GtkWidget      *widget,
 
        view->drag_info.in_drag = FALSE;
 
+       if (view->adding_annot && view->pressed_button == 1) {
+               view->adding_annot = FALSE;
+               ev_view_handle_cursor_over_xy (view, event->x, event->y);
+               view->pressed_button = -1;
+
+               ev_view_create_annotation (view,
+                                          view->adding_annot_type,
+                                          event->x + view->scroll_x,
+                                          event->y + view->scroll_y);
+
+               return FALSE;
+       }
+
        if (view->pressed_button == 2) {
                ev_view_handle_cursor_over_xy (view, event->x, event->y);
        }
@@ -3765,7 +4184,7 @@ ev_view_key_press_event (GtkWidget   *widget,
        if (!view->document)
                return FALSE;
 
-       if (!GTK_WIDGET_HAS_FOCUS (widget)) {
+       if (!gtk_widget_has_focus (widget)) {
                /* Forward key events to current focused window child */
                if (view->window_child_focus) {
                        GdkEventKey *new_event;
@@ -3773,7 +4192,9 @@ ev_view_key_press_event (GtkWidget   *widget,
 
                        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);
+                       new_event->window = gtk_widget_get_window (view->window_child_focus->window);
+                       if (new_event->window)
+                               g_object_ref (new_event->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);
@@ -3784,7 +4205,7 @@ ev_view_key_press_event (GtkWidget   *widget,
                return FALSE;
        }
 
-       return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
+       return gtk_bindings_activate_event (G_OBJECT (widget), event);
 }
 
 static gint
@@ -3831,149 +4252,188 @@ ev_view_enter_notify_event (GtkWidget *widget, GdkEventCrossing   *event)
 }
 
 static void
-ev_view_style_set (GtkWidget *widget,
-                  GtkStyle  *old_style)
+ev_view_style_updated (GtkWidget *widget)
 {
        if (EV_VIEW (widget)->pixbuf_cache)
                ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
 
-       GTK_WIDGET_CLASS (ev_view_parent_class)->style_set (widget, old_style);
+       GTK_WIDGET_CLASS (ev_view_parent_class)->style_updated (widget);
 }
 
 /*** Drawing ***/
 
-static guint32
-ev_gdk_color_to_rgb (const GdkColor *color)
-{
-  guint32 result;
-  result = (0xff0000 | (color->red & 0xff00));
-  result <<= 8;
-  result |= ((color->green & 0xff00) | (color->blue >> 8));
-  return result;
-}
-
 static void
-draw_rubberband (GtkWidget *widget, GdkWindow *window,
-                const GdkRectangle *rect, guchar alpha)
+draw_rubberband (EvView             *view,
+                cairo_t            *cr,
+                const GdkRectangle *rect,
+                gdouble             alpha)
 {
-       GdkGC *gc;
-       GdkPixbuf *pixbuf;
-       GdkColor *fill_color_gdk;
-       guint fill_color;
+       GtkStyleContext *context;
+       GdkRGBA          color;
 
-       fill_color_gdk = gdk_color_copy (&GTK_WIDGET (widget)->style->base[GTK_STATE_SELECTED]);
-       fill_color = ev_gdk_color_to_rgb (fill_color_gdk) << 8 | alpha;
+       context = gtk_widget_get_style_context (GTK_WIDGET (view));
+       gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED, &color);
+        cairo_save (cr);
 
-       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
-                                rect->width, rect->height);
-       gdk_pixbuf_fill (pixbuf, fill_color);
+       cairo_set_source_rgba (cr, color.red, color.green, color.blue, alpha);
+       cairo_rectangle (cr,
+                        rect->x - view->scroll_x,
+                        rect->y - view->scroll_y,
+                        rect->width, rect->height);
+       cairo_fill_preserve (cr);
 
-       gdk_draw_pixbuf (window, NULL, pixbuf,
-                        0, 0,
-                        rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
-                        rect->width, rect->height,
-                        GDK_RGB_DITHER_NONE,
-                        0, 0);
+       cairo_set_line_width (cr, 0.5);
+       cairo_set_source_rgb (cr, color.red, color.green, color.blue);
+       cairo_stroke (cr);
 
-       g_object_unref (pixbuf);
-
-       gc = gdk_gc_new (window);
-       gdk_gc_set_rgb_fg_color (gc, fill_color_gdk);
-       gdk_draw_rectangle (window, gc, FALSE,
-                           rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
-                           rect->width - 1,
-                           rect->height - 1);
-       g_object_unref (gc);
-
-       gdk_color_free (fill_color_gdk);
+       cairo_restore (cr);
 }
 
 
 static void
-highlight_find_results (EvView *view, int page)
+highlight_find_results (EvView *view,
+                        cairo_t *cr,
+                        int page)
 {
-       gint i, n_results = 0;
-
+       gint       i, n_results = 0;
        n_results = ev_view_find_get_n_results (view, page);
 
        for (i = 0; i < n_results; i++) {
                EvRectangle *rectangle;
                GdkRectangle view_rectangle;
-               guchar alpha;
+               gdouble      alpha;
 
                if (i == view->find_result && page == view->current_page) {
-                       alpha = 0x90;
+                       alpha = 0.6;
                } else {
-                       alpha = 0x20;
+                       alpha = 0.3;
                }
 
                rectangle = ev_view_find_get_result (view, page, i);
                doc_rect_to_view_rect (view, page, rectangle, &view_rectangle);
-               draw_rubberband (GTK_WIDGET (view), view->layout.bin_window,
-                                &view_rectangle, alpha);
+               draw_rubberband (view, cr, &view_rectangle, alpha);
         }
 }
 
 static void
-draw_loading_text (EvView       *view,
-                  GdkRectangle *page_area,
-                  GdkRectangle *expose_area)
+highlight_forward_search_results (EvView *view,
+                                  cairo_t *cr,
+                                  int page)
 {
-       cairo_t *cr;
-       gint     width, height;
+       GdkRectangle rect;
+       EvMapping   *mapping = view->synctex_result;
 
-       if (!view->loading_text) {
-               const gchar *loading_text = _("Loading...");
-               PangoLayout *layout;
-               PangoFontDescription *font_desc;
-               PangoRectangle logical_rect;
-               gint target_width;
-               gdouble real_scale;
+       if (GPOINTER_TO_INT (mapping->data) != page)
+               return;
 
-               ev_document_fc_mutex_lock ();
+       doc_rect_to_view_rect (view, page, &mapping->area, &rect);
 
-               layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), loading_text);
-               
-               font_desc = pango_font_description_new ();
-               
-               /* We set the font to be 10 points, get the size, and scale appropriately */
-               pango_font_description_set_size (font_desc, 10 * PANGO_SCALE);
-               pango_layout_set_font_description (layout, font_desc);
-               pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
-               target_width = MAX (page_area->width / 2, 1);
-               real_scale = ((double)target_width / (double) logical_rect.width) * (PANGO_SCALE * 10);
-               pango_font_description_set_size (font_desc, (int)real_scale);
-               pango_layout_set_font_description (layout, font_desc);
-               pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
-               view->loading_text = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                                                logical_rect.width,
-                                                                logical_rect.height);
-               cr = cairo_create (view->loading_text);
-               cairo_set_source_rgb (cr,
-                                     155 / (double)255,
-                                     155 / (double)255,
-                                     155 / (double)255);
-               pango_cairo_show_layout (cr, layout);
-               cairo_destroy (cr);
-
-               pango_font_description_free (font_desc);
-               g_object_unref (layout);
-
-               ev_document_fc_mutex_unlock ();
-       }
-
-       width = (page_area->width - cairo_image_surface_get_width (view->loading_text)) / 2;
-       height = (page_area->height - cairo_image_surface_get_height (view->loading_text)) / 2;
-       
-       cr = gdk_cairo_create (view->layout.bin_window);
-       cairo_translate (cr,
-                        page_area->x + width,
-                        page_area->y + height);
-       cairo_set_source_surface (cr, view->loading_text, 0, 0);
-       cairo_paint (cr);
-       cairo_destroy (cr);
+        cairo_save (cr);
+       cairo_set_source_rgb (cr, 1., 0., 0.);
+       cairo_rectangle (cr,
+                        rect.x - view->scroll_x,
+                        rect.y - view->scroll_y,
+                        rect.width, rect.height);
+       cairo_stroke (cr);
+       cairo_restore (cr);
+}
+
+static void
+focus_annotation (EvView       *view,
+                  cairo_t      *cr,
+                 gint          page,
+                 GdkRectangle *clip)
+{
+       GtkWidget    *widget = GTK_WIDGET (view);
+       GdkRectangle  rect;
+       EvMapping    *mapping = view->focus_annotation;
+       EvAnnotation *annot = (EvAnnotation *)mapping->data;
+
+       if (ev_annotation_get_page_index (annot) != page)
+               return;
+
+       doc_rect_to_view_rect (view, page, &mapping->area, &rect);
+
+        gtk_render_focus (gtk_widget_get_style_context (widget),
+                          cr,
+                          rect.x - view->scroll_x,
+                          rect.y - view->scroll_y,
+                          rect.width + 1, rect.height + 1);
+}
+
+static void
+ev_view_loading_window_move (EvView *view)
+{
+       GtkWidget       *widget = GTK_WIDGET (view);
+       EvLoadingWindow *window = EV_LOADING_WINDOW (view->loading_window);
+       gint             root_x, root_y;
+       gint             window_width;
+       GtkAllocation    allocation;
+
+       gtk_widget_get_allocation (widget, &allocation);
+       gdk_window_get_origin (gtk_widget_get_window (widget), &root_x, &root_y);
+       ev_loading_window_get_size (window, &window_width, NULL);
+
+       root_x += allocation.width - window_width - 10;
+       root_y += 10;
+
+       ev_loading_window_move (window, root_x, root_y);
+}
+
+static gboolean
+show_loading_window_cb (EvView *view)
+{
+       if (!view->loading_window) {
+               GtkWindow *parent;
+               GdkScreen *screen;
+
+               parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
+               view->loading_window = ev_loading_window_new (parent);
+
+               /* Show the window off screen to get a valid size asap */
+               screen = gtk_widget_get_screen (GTK_WIDGET (view));
+               gtk_window_move (GTK_WINDOW (view->loading_window),
+                                gdk_screen_get_width (screen) + 1,
+                                gdk_screen_get_height (screen) + 1);
+               gtk_widget_show (view->loading_window);
+       }
+
+       ev_view_loading_window_move (view);
+
+       gtk_widget_show (view->loading_window);
+
+       view->loading_timeout = 0;
+
+       return FALSE;
+}
+
+static void
+show_loading_window (EvView *view)
+{
+       if (view->loading_window && gtk_widget_get_visible (view->loading_window)) {
+               ev_view_loading_window_move (view);
+               return;
+       }
+
+       if (!view->loading_timeout) {
+               view->loading_timeout =
+                       g_timeout_add_full (G_PRIORITY_LOW,
+                                           0.5, (GSourceFunc)show_loading_window_cb,
+                                           view, NULL);
+       }
+}
+
+static void
+hide_loading_window (EvView *view)
+{
+       if (view->loading_timeout) {
+               g_source_remove (view->loading_timeout);
+               view->loading_timeout = 0;
+       }
+
+       if (view->loading_window && gtk_widget_get_visible (view->loading_window)) {
+               gtk_widget_hide (view->loading_window);
+       }
 }
 
 static void
@@ -3988,6 +4448,7 @@ draw_one_page (EvView       *view,
        GdkRectangle overlap;
        GdkRectangle real_page_area;
        gint         current_page;
+       gboolean     inverted_colors;
 
        g_assert (view->document);
 
@@ -4004,10 +4465,12 @@ draw_one_page (EvView       *view,
        *page_ready = TRUE;
 
        current_page = ev_document_model_get_page (view->model);
-       ev_document_misc_paint_one_page (view->layout.bin_window,
+       inverted_colors = ev_document_model_get_inverted_colors (view->model);
+       ev_document_misc_paint_one_page (cr,
                                         GTK_WIDGET (view),
                                         page_area, border,
-                                        page == current_page);
+                                        page == current_page,
+                                        inverted_colors);
 
        if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) {
                gint             width, height;
@@ -4019,15 +4482,17 @@ draw_one_page (EvView       *view,
                page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page);
 
                if (!page_surface) {
-                       draw_loading_text (view,
-                                          &real_page_area,
-                                          expose_area);
+                       if (page == current_page)
+                               show_loading_window (view);
 
                        *page_ready = FALSE;
 
                        return;
                }
 
+               if (page == current_page)
+                       hide_loading_window (view);
+
                ev_view_get_page_size (view, page, &width, &height);
 
                page_width = cairo_image_surface_get_width (page_surface);
@@ -4082,6 +4547,7 @@ draw_one_page (EvView       *view,
                cairo_surface_set_device_offset (selection_surface,
                                                 overlap.x - real_page_area.x,
                                                 overlap.y - real_page_area.y);
+
                cairo_set_source_surface (cr, selection_surface, 0, 0);
                cairo_paint (cr);
                cairo_restore (cr);
@@ -4098,6 +4564,11 @@ ev_view_finalize (GObject *object)
        clear_selection (view);
        clear_link_selected (view);
 
+       if (view->synctex_result) {
+               g_free (view->synctex_result);
+               view->synctex_result = NULL;
+       }
+
        if (view->image_dnd_info.image)
                g_object_unref (view->image_dnd_info.image);
        view->image_dnd_info.image = NULL;
@@ -4106,7 +4577,7 @@ ev_view_finalize (GObject *object)
 }
 
 static void
-ev_view_destroy (GtkObject *object)
+ev_view_dispose (GObject *object)
 {
        EvView *view = EV_VIEW (object);
 
@@ -4142,11 +4613,6 @@ ev_view_destroy (GtkObject *object)
            view->selection_update_id = 0;
        }
 
-       if (view->loading_text) {
-               cairo_surface_destroy (view->loading_text);
-               view->loading_text = NULL;
-       }
-
        if (view->scroll_info.timeout_id) {
            g_source_remove (view->scroll_info.timeout_id);
            view->scroll_info.timeout_id = 0;
@@ -4162,21 +4628,86 @@ ev_view_destroy (GtkObject *object)
                view->drag_info.release_timeout_id = 0;
        }
 
-       ev_view_set_scroll_adjustments (GTK_LAYOUT (view), NULL, NULL);
+       if (view->loading_timeout) {
+               g_source_remove (view->loading_timeout);
+               view->loading_timeout = 0;
+       }
+
+        gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (view), NULL);
+        gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (view), NULL);
 
-       GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
+       G_OBJECT_CLASS (ev_view_parent_class)->dispose (object);
 }
 
-static AtkObject *
-ev_view_get_accessible (GtkWidget *widget)
+static void
+ev_view_get_property (GObject     *object,
+                     guint        prop_id,
+                     GValue      *value,
+                     GParamSpec  *pspec)
+{
+       EvView *view = EV_VIEW (object);
+
+       switch (prop_id) {
+       case PROP_HADJUSTMENT:
+               g_value_set_object (value, view->hadjustment);
+               break;
+       case PROP_VADJUSTMENT:
+               g_value_set_object (value, view->vadjustment);
+               break;
+       case PROP_HSCROLL_POLICY:
+               g_value_set_enum (value, view->hscroll_policy);
+               break;
+       case PROP_VSCROLL_POLICY:
+               g_value_set_enum (value, view->vscroll_policy);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+ev_view_set_property (GObject      *object,
+                     guint         prop_id,
+                     const GValue *value,
+                     GParamSpec   *pspec)
+{
+       EvView *view = EV_VIEW (object);
+
+       switch (prop_id) {
+       case PROP_HADJUSTMENT:
+               ev_view_set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL,
+                                              (GtkAdjustment *) g_value_get_object (value));
+               break;
+       case PROP_VADJUSTMENT:
+               ev_view_set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL,
+                                              (GtkAdjustment *) g_value_get_object (value));
+               break;
+       case PROP_HSCROLL_POLICY:
+               view->hscroll_policy = g_value_get_enum (value);
+               gtk_widget_queue_resize (GTK_WIDGET (view));
+               break;
+       case PROP_VSCROLL_POLICY:
+               view->vscroll_policy = g_value_get_enum (value);
+               gtk_widget_queue_resize (GTK_WIDGET (view));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+/* Accessibility */
+static void
+ev_view_init_accessibility (EvView *view)
 {
        static gboolean first_time = TRUE;
 
        if (first_time) {
                AtkObjectFactory *factory;
                AtkRegistry *registry;
-               GType derived_type; 
-               GType derived_atk_type; 
+               GType derived_type;
+               GType derived_atk_type;
 
                /*
                 * Figure out whether accessibility is enabled by looking at the
@@ -4189,27 +4720,89 @@ ev_view_get_accessible (GtkWidget *widget)
                factory = atk_registry_get_factory (registry,
                                                    derived_type);
                derived_atk_type = atk_object_factory_get_accessible_type (factory);
-               if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) 
-                       atk_registry_set_factory_type (registry, 
+               if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) {
+                       atk_registry_set_factory_type (registry,
                                                       EV_TYPE_VIEW,
                                                       ev_view_accessible_factory_get_type ());
+                       view->a11y_enabled = TRUE;
+               }
                first_time = FALSE;
-       } 
+       }
+}
+
+static AtkObject *
+ev_view_get_accessible (GtkWidget *widget)
+{
+       ev_view_init_accessibility (EV_VIEW (widget));
        return GTK_WIDGET_CLASS (ev_view_parent_class)->get_accessible (widget);
 }
 
+static gboolean
+ev_view_is_a11y_enabled (EvView *view)
+{
+       ev_view_init_accessibility (view);
+       return view->a11y_enabled;
+}
+
+/* GtkContainer */
+static void
+ev_view_remove (GtkContainer *container,
+               GtkWidget    *widget)
+{
+       EvView *view = EV_VIEW (container);
+       GList *tmp_list = view->children;
+       EvViewChild *child;
+
+       while (tmp_list) {
+               child = tmp_list->data;
+
+               if (child->widget == widget) {
+                       gtk_widget_unparent (widget);
+
+                       view->children = g_list_remove_link (view->children, tmp_list);
+                       g_list_free_1 (tmp_list);
+                       g_slice_free (EvViewChild, child);
+
+                       return;
+               }
+
+               tmp_list = tmp_list->next;
+       }
+}
+
+static void
+ev_view_forall (GtkContainer *container,
+               gboolean      include_internals,
+               GtkCallback   callback,
+               gpointer      callback_data)
+{
+       EvView *view = EV_VIEW (container);
+       GList *tmp_list = view->children;
+       EvViewChild *child;
+
+       while (tmp_list) {
+               child = tmp_list->data;
+               tmp_list = tmp_list->next;
+
+               (* callback) (child->widget, callback_data);
+       }
+}
+
 static void
 ev_view_class_init (EvViewClass *class)
 {
        GObjectClass *object_class = G_OBJECT_CLASS (class);
-       GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
-       GtkLayoutClass *layout_class = GTK_LAYOUT_CLASS (class);
+       GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
        GtkBindingSet *binding_set;
 
+       object_class->get_property = ev_view_get_property;
+       object_class->set_property = ev_view_set_property;
+        object_class->dispose = ev_view_dispose;
        object_class->finalize = ev_view_finalize;
 
-       widget_class->expose_event = ev_view_expose_event;
+       widget_class->realize = ev_view_realize;
+        widget_class->draw = ev_view_draw;
        widget_class->button_press_event = ev_view_button_press_event;
        widget_class->motion_notify_event = ev_view_motion_notify_event;
        widget_class->button_release_event = ev_view_button_release_event;
@@ -4217,24 +4810,29 @@ ev_view_class_init (EvViewClass *class)
        widget_class->focus_in_event = ev_view_focus_in;
        widget_class->focus_out_event = ev_view_focus_out;
        widget_class->get_accessible = ev_view_get_accessible;
-       widget_class->size_request = ev_view_size_request;
+       widget_class->get_preferred_width = ev_view_get_preferred_width;
+       widget_class->get_preferred_height = ev_view_get_preferred_height;
        widget_class->size_allocate = ev_view_size_allocate;
-       widget_class->realize = ev_view_realize;
        widget_class->scroll_event = ev_view_scroll_event;
        widget_class->enter_notify_event = ev_view_enter_notify_event;
        widget_class->leave_notify_event = ev_view_leave_notify_event;
-       widget_class->style_set = ev_view_style_set;
+       widget_class->style_updated = ev_view_style_updated;
        widget_class->drag_data_get = ev_view_drag_data_get;
        widget_class->drag_motion = ev_view_drag_motion;
        widget_class->popup_menu = ev_view_popup_menu;
        widget_class->query_tooltip = ev_view_query_tooltip;
 
-       gtk_object_class->destroy = ev_view_destroy;
+       container_class->remove = ev_view_remove;
+       container_class->forall = ev_view_forall;
 
-       layout_class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
-       
        class->binding_activated = ev_view_scroll;
 
+       /* Scrollable interface */
+       g_object_class_override_property (object_class, PROP_HADJUSTMENT, "hadjustment");
+       g_object_class_override_property (object_class, PROP_VADJUSTMENT, "vadjustment");
+       g_object_class_override_property (object_class, PROP_HSCROLL_POLICY, "hscroll-policy");
+       g_object_class_override_property (object_class, PROP_VSCROLL_POLICY, "vscroll-policy");
+
        signals[SIGNAL_BINDING_ACTIVATED] = g_signal_new ("binding_activated",
                         G_TYPE_FROM_CLASS (object_class),
                         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
@@ -4265,9 +4863,9 @@ ev_view_class_init (EvViewClass *class)
                         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                         G_STRUCT_OFFSET (EvViewClass, popup_menu),
                         NULL, NULL,
-                        g_cclosure_marshal_VOID__OBJECT,
+                        g_cclosure_marshal_VOID__POINTER,
                         G_TYPE_NONE, 1,
-                        G_TYPE_OBJECT);
+                        G_TYPE_POINTER);
        signals[SIGNAL_SELECTION_CHANGED] = g_signal_new ("selection-changed",
                          G_TYPE_FROM_CLASS (object_class),
                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
@@ -4276,24 +4874,48 @@ ev_view_class_init (EvViewClass *class)
                         g_cclosure_marshal_VOID__VOID,
                          G_TYPE_NONE, 0,
                          G_TYPE_NONE);
+       signals[SIGNAL_SYNC_SOURCE] = g_signal_new ("sync-source",
+                        G_TYPE_FROM_CLASS (object_class),
+                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                        G_STRUCT_OFFSET (EvViewClass, sync_source),
+                        NULL, NULL,
+                        g_cclosure_marshal_VOID__POINTER,
+                        G_TYPE_NONE, 1,
+                        G_TYPE_POINTER);
+       signals[SIGNAL_ANNOT_ADDED] = g_signal_new ("annot-added",
+                        G_TYPE_FROM_CLASS (object_class),
+                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                        G_STRUCT_OFFSET (EvViewClass, annot_added),
+                        NULL, NULL,
+                        g_cclosure_marshal_VOID__OBJECT,
+                        G_TYPE_NONE, 1,
+                        EV_TYPE_ANNOTATION);
+       signals[SIGNAL_LAYERS_CHANGED] = g_signal_new ("layers-changed",
+                        G_TYPE_FROM_CLASS (object_class),
+                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                        G_STRUCT_OFFSET (EvViewClass, layers_changed),
+                        NULL, NULL,
+                        g_cclosure_marshal_VOID__VOID,
+                        G_TYPE_NONE, 0,
+                        G_TYPE_NONE);
 
        binding_set = gtk_binding_set_by_class (class);
 
-       add_scroll_binding_keypad (binding_set, GDK_Left,  0, GTK_SCROLL_STEP_BACKWARD, TRUE);
-       add_scroll_binding_keypad (binding_set, GDK_Right, 0, GTK_SCROLL_STEP_FORWARD,  TRUE);
-       add_scroll_binding_keypad (binding_set, GDK_Left,  GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, TRUE);
-       add_scroll_binding_keypad (binding_set, GDK_Right, GDK_MOD1_MASK, GTK_SCROLL_STEP_UP,  TRUE);
-       add_scroll_binding_keypad (binding_set, GDK_Up,    0, GTK_SCROLL_STEP_BACKWARD, FALSE);
-       add_scroll_binding_keypad (binding_set, GDK_Down,  0, GTK_SCROLL_STEP_FORWARD,  FALSE);
-       add_scroll_binding_keypad (binding_set, GDK_Up,    GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, FALSE);
-       add_scroll_binding_keypad (binding_set, GDK_Down,  GDK_MOD1_MASK, GTK_SCROLL_STEP_UP,  FALSE);
-       gtk_binding_entry_add_signal (binding_set, GDK_H, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
+        add_scroll_binding_keypad (binding_set, GDK_KEY_Left,  0, GTK_SCROLL_STEP_BACKWARD, TRUE);
+        add_scroll_binding_keypad (binding_set, GDK_KEY_Right, 0, GTK_SCROLL_STEP_FORWARD,  TRUE);
+        add_scroll_binding_keypad (binding_set, GDK_KEY_Left,  GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, TRUE);
+        add_scroll_binding_keypad (binding_set, GDK_KEY_Right, GDK_MOD1_MASK, GTK_SCROLL_STEP_UP,  TRUE);
+        add_scroll_binding_keypad (binding_set, GDK_KEY_Up,    0, GTK_SCROLL_STEP_BACKWARD, FALSE);
+        add_scroll_binding_keypad (binding_set, GDK_KEY_Down,  0, GTK_SCROLL_STEP_FORWARD,  FALSE);
+        add_scroll_binding_keypad (binding_set, GDK_KEY_Up,    GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, FALSE);
+        add_scroll_binding_keypad (binding_set, GDK_KEY_Down,  GDK_MOD1_MASK, GTK_SCROLL_STEP_UP,  FALSE);
+        gtk_binding_entry_add_signal (binding_set, GDK_KEY_H, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
                                      GTK_SCROLL_STEP_BACKWARD, G_TYPE_BOOLEAN, TRUE);
-       gtk_binding_entry_add_signal (binding_set, GDK_J, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
+       gtk_binding_entry_add_signal (binding_set, GDK_KEY_J, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
                                      GTK_SCROLL_STEP_FORWARD, G_TYPE_BOOLEAN, FALSE);
-       gtk_binding_entry_add_signal (binding_set, GDK_K, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
+       gtk_binding_entry_add_signal (binding_set, GDK_KEY_K, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
                                      GTK_SCROLL_STEP_BACKWARD, G_TYPE_BOOLEAN, FALSE);
-       gtk_binding_entry_add_signal (binding_set, GDK_L, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
+       gtk_binding_entry_add_signal (binding_set, GDK_KEY_L, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
                                      GTK_SCROLL_STEP_FORWARD, G_TYPE_BOOLEAN, TRUE);
        
 }
@@ -4301,7 +4923,21 @@ ev_view_class_init (EvViewClass *class)
 static void
 ev_view_init (EvView *view)
 {
-       GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
+       gtk_widget_set_has_window (GTK_WIDGET (view), TRUE);
+       gtk_widget_set_can_focus (GTK_WIDGET (view), TRUE);
+       gtk_widget_set_redraw_on_allocate (GTK_WIDGET (view), FALSE);
+       gtk_container_set_resize_mode (GTK_CONTAINER (view), GTK_RESIZE_QUEUE);
+
+       gtk_widget_set_events (GTK_WIDGET (view),
+                              GDK_EXPOSURE_MASK |
+                              GDK_BUTTON_PRESS_MASK |
+                              GDK_BUTTON_RELEASE_MASK |
+                              GDK_SCROLL_MASK |
+                              GDK_KEY_PRESS_MASK |
+                              GDK_POINTER_MOTION_MASK |
+                              GDK_POINTER_MOTION_HINT_MASK |
+                              GDK_ENTER_NOTIFY_MASK |
+                              GDK_LEAVE_NOTIFY_MASK);
 
        view->start_page = -1;
        view->end_page = -1;
@@ -4323,9 +4959,6 @@ ev_view_init (EvView *view)
        view->pending_scroll = SCROLL_TO_KEEP_POSITION;
        view->jump_to_find_result = TRUE;
        view->highlight_find_results = FALSE;
-
-       gtk_layout_set_hadjustment (GTK_LAYOUT (view), NULL);
-       gtk_layout_set_vadjustment (GTK_LAYOUT (view), NULL);
 }
 
 /*** Callbacks ***/
@@ -4339,6 +4972,8 @@ ev_view_change_page (EvView *view,
        view->current_page = new_page;
        view->pending_scroll = SCROLL_TO_PAGE_POSITION;
 
+       hide_loading_window (view);
+
        gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
        ev_view_handle_cursor_over_xy (view, x, y);
 
@@ -4346,13 +4981,12 @@ ev_view_change_page (EvView *view,
 }
 
 static void
-job_finished_cb (EvPixbufCache *pixbuf_cache,
-                GdkRegion     *region,
-                EvView        *view)
+job_finished_cb (EvPixbufCache  *pixbuf_cache,
+                cairo_region_t *region,
+                EvView         *view)
 {
        if (region) {
-               gdk_window_invalidate_region (view->layout.bin_window,
-                                             region, TRUE);
+               gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)), region, TRUE);
        } else {
                gtk_widget_queue_draw (GTK_WIDGET (view));
        }
@@ -4380,40 +5014,39 @@ static void
 on_adjustment_value_changed (GtkAdjustment *adjustment,
                             EvView        *view)
 {
+       GtkWidget *widget = GTK_WIDGET (view);
        int dx = 0, dy = 0;
        gint x, y;
-       GList *children, *l;
+       gint value;
+       GList *l;
 
-       if (! GTK_WIDGET_REALIZED (view))
+       if (!gtk_widget_get_realized (widget))
                return;
 
        if (view->hadjustment) {
-               dx = view->scroll_x - (int) view->hadjustment->value;
-               view->scroll_x = (int) view->hadjustment->value;
+               value = (gint) gtk_adjustment_get_value (view->hadjustment);
+               dx = view->scroll_x - value;
+               view->scroll_x = value;
        } else {
                view->scroll_x = 0;
        }
 
        if (view->vadjustment) {
-               dy = view->scroll_y - (int) view->vadjustment->value;
-               view->scroll_y = (int) view->vadjustment->value;
+               value = (gint) gtk_adjustment_get_value (view->vadjustment);
+               dy = view->scroll_y - value;
+               view->scroll_y = value;
        } else {
                view->scroll_y = 0;
        }
 
-       children = gtk_container_get_children (GTK_CONTAINER (view));
-       for (l = children; l && l->data; l = g_list_next (l)) {
-               gint       child_x, child_y;
-               GtkWidget *child = (GtkWidget *)l->data;
-               
-               gtk_container_child_get (GTK_CONTAINER (view),
-                                        child,
-                                        "x", &child_x,
-                                        "y", &child_y,
-                                        NULL);
-               gtk_layout_move (GTK_LAYOUT (view), child, child_x + dx, child_y + dy);
+       for (l = view->children; l && l->data; l = g_list_next (l)) {
+               EvViewChild *child = (EvViewChild *)l->data;
+
+               child->x += dx;
+               child->y += dy;
+               if (gtk_widget_get_visible (child->widget) && gtk_widget_get_visible (widget))
+                       gtk_widget_queue_resize (widget);
        }
-       g_list_free (children);
 
        for (l = view->window_children; l && l->data; l = g_list_next (l)) {
                EvViewWindowChild *child;
@@ -4422,13 +5055,14 @@ on_adjustment_value_changed (GtkAdjustment *adjustment,
 
                ev_view_window_child_move (view, child, child->x + dx, child->y + dy);
        }
-       
-       if (view->pending_resize)
-               gtk_widget_queue_draw (GTK_WIDGET (view));
-       else
-               gdk_window_scroll (view->layout.bin_window, dx, dy);
-               
-       gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
+
+       if (view->pending_resize) {
+               gtk_widget_queue_draw (widget);
+       } else {
+               gdk_window_scroll (gtk_widget_get_window (widget), dx, dy);
+       }
+
+       gtk_widget_get_pointer (widget, &x, &y);
        ev_view_handle_cursor_over_xy (view, x, y);
 
        if (view->document)
@@ -4451,8 +5085,16 @@ setup_caches (EvView *view)
        gboolean inverted_colors;
 
        view->height_to_page_cache = ev_view_get_height_to_page_cache (view);
-       view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->document);
+       view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->model, view->pixbuf_cache_size);
        view->page_cache = ev_page_cache_new (view->document);
+       if (ev_view_is_a11y_enabled (view)) {
+               EvJobPageDataFlags flags = ev_page_cache_get_flags (view->page_cache);
+
+               ev_page_cache_set_flags (view->page_cache,
+                                        flags |
+                                        EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT |
+                                        EV_PAGE_DATA_INCLUDE_TEXT);
+       }
        inverted_colors = ev_document_model_get_inverted_colors (view->model);
        ev_pixbuf_cache_set_inverted_colors (view->pixbuf_cache, inverted_colors);
        g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view);
@@ -4472,10 +5114,37 @@ clear_caches (EvView *view)
        }
 }
 
+/**
+ * ev_view_set_page_cache_size:
+ * @view:
+ * @cache_size:
+ *
+ * Sets the maximum size in bytes that will be used to cache
+ * rendered pages. Use 0 to disable caching rendered pages.
+ *
+ * Note that this limit doesn't affect the current visible page range,
+ * which will always be rendered. In order to limit the total memory used
+ * you have to use ev_document_model_set_max_scale() too.
+ *
+ */
+void
+ev_view_set_page_cache_size (EvView *view,
+                            gsize   cache_size)
+{
+       if (view->pixbuf_cache_size == cache_size)
+               return;
+
+       view->pixbuf_cache_size = cache_size;
+       if (view->pixbuf_cache)
+               ev_pixbuf_cache_set_max_size (view->pixbuf_cache, cache_size);
+}
+
 void
 ev_view_set_loading (EvView      *view,
                     gboolean      loading)
 {
+       if (view->loading && !loading)
+               hide_loading_window (view);
        view->loading = loading;
        gtk_widget_queue_draw (GTK_WIDGET (view));
 }
@@ -4507,7 +5176,9 @@ ev_view_autoscroll_cb (EvView *view)
                speed = pow ((((gdouble)view->scroll_info.last_y - view->scroll_info.start_y) / 100), 3);
        
        value = gtk_adjustment_get_value (view->vadjustment);
-       value = CLAMP (value + speed, 0, view->vadjustment->upper - view->vadjustment->page_size);
+       value = CLAMP (value + speed, 0,
+                      gtk_adjustment_get_upper (view->vadjustment) -
+                      gtk_adjustment_get_page_size (view->vadjustment));
        gtk_adjustment_set_value (view->vadjustment, value);
        
        return TRUE;
@@ -4560,11 +5231,10 @@ ev_view_document_changed_cb (EvDocumentModel *model,
 {
        EvDocument *document = ev_document_model_get_document (model);
 
-       view->loading = FALSE;
-
        if (document != view->document) {
                gint current_page;
 
+               ev_view_remove_all (view);
                clear_caches (view);
 
                if (view->document) {
@@ -4575,6 +5245,7 @@ ev_view_document_changed_cb (EvDocumentModel *model,
                view->find_result = 0;
 
                if (view->document) {
+                       view->loading = FALSE;
                        g_object_ref (view->document);
                        setup_caches (view);
                 }
@@ -4648,11 +5319,6 @@ ev_view_scale_changed_cb (EvDocumentModel *model,
        if (ABS (view->scale - scale) < EPSILON)
                return;
 
-       if (view->loading_text) {
-               cairo_surface_destroy (view->loading_text);
-               view->loading_text = NULL;
-       }
-
        view->scale = scale;
 
        view->pending_resize = TRUE;
@@ -4758,9 +5424,9 @@ ev_view_set_model (EvView          *view,
 }
 
 static void
-ev_view_reload_page (EvView    *view,
-                    gint       page,
-                    GdkRegion *region)
+ev_view_reload_page (EvView         *view,
+                    gint            page,
+                    cairo_region_t *region)
 {
        ev_pixbuf_cache_reload_page (view->pixbuf_cache,
                                     region,
@@ -4855,6 +5521,7 @@ ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
        gdouble doc_width, doc_height;
        GtkBorder border;
        gdouble scale;
+       gint sb_size;
 
        ev_document_get_max_page_size (view->document, &doc_width, &doc_height);
        if (view->rotation == 90 || view->rotation == 270) {
@@ -4871,13 +5538,12 @@ ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
        width -= (2 * (border.left + border.right) + 3 * view->spacing);
        height -= (border.top + border.bottom + 2 * view->spacing - 1);
 
-       if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
-               gint sb_size;
+       sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
 
-               sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
+       if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
                scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
        } else if (view->sizing_mode == EV_SIZING_BEST_FIT)
-               scale = zoom_for_size_best_fit (doc_width, doc_height, width, height);
+               scale = zoom_for_size_best_fit (doc_width, doc_height, width - sb_size, height);
        else
                g_assert_not_reached ();
 
@@ -4892,6 +5558,7 @@ ev_view_zoom_for_size_continuous (EvView *view,
        gdouble doc_width, doc_height;
        GtkBorder border;
        gdouble scale;
+       gint sb_size;
 
        ev_document_get_max_page_size (view->document, &doc_width, &doc_height);
        if (view->rotation == 90 || view->rotation == 270) {
@@ -4907,13 +5574,12 @@ ev_view_zoom_for_size_continuous (EvView *view,
        width -= (border.left + border.right + 2 * view->spacing);
        height -= (border.top + border.bottom + 2 * view->spacing - 1);
 
-       if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
-               gint sb_size;
+       sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
 
-               sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
+       if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
                scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
        } else if (view->sizing_mode == EV_SIZING_BEST_FIT)
-               scale = zoom_for_size_best_fit (doc_width, doc_height, width, height);
+               scale = zoom_for_size_best_fit (doc_width, doc_height, width - sb_size, height);
        else
                g_assert_not_reached ();
 
@@ -5154,6 +5820,34 @@ ev_view_find_cancel (EvView *view)
        view->find_pages = NULL;
 }
 
+/*** Synctex ***/
+void
+ev_view_highlight_forward_search (EvView       *view,
+                                 EvSourceLink *link)
+{
+       EvMapping   *mapping;
+       gint         page;
+       GdkRectangle view_rect;
+
+       if (!ev_document_has_synctex (view->document))
+               return;
+
+       mapping = ev_document_synctex_forward_search (view->document, link);
+       if (!mapping)
+               return;
+
+       if (view->synctex_result)
+               g_free (view->synctex_result);
+       view->synctex_result = mapping;
+
+       page = GPOINTER_TO_INT (mapping->data);
+       ev_document_model_set_page (view->model, page);
+
+       doc_rect_to_view_rect (view, page, &mapping->area, &view_rect);
+       ensure_rectangle_is_visible (view, &view_rect);
+       gtk_widget_queue_draw (GTK_WIDGET (view));
+}
+
 /*** Selections ***/
 
 /* compute_new_selection_rect/text calculates the area currently selected by
@@ -5181,7 +5875,7 @@ compute_new_selection_rect (EvView       *view,
                GdkRectangle page_area;
                GtkBorder border;
                
-               if (get_page_extents (view, i, &page_area, &border)) {
+               if (ev_view_get_page_extents (view, i, &page_area, &border)) {
                        GdkRectangle overlap;
 
                        if (gdk_rectangle_intersect (&page_area, &view_rect, &overlap)) {
@@ -5245,7 +5939,7 @@ compute_new_selection_text (EvView          *view,
                GdkRectangle page_area;
                GtkBorder border;
                
-               get_page_extents (view, i, &page_area, &border);
+               ev_view_get_page_extents (view, i, &page_area, &border);
                if (gdk_rectangle_point_in (&page_area, start) || 
                    gdk_rectangle_point_in (&page_area, stop)) {
                        if (first == n_pages)
@@ -5272,7 +5966,7 @@ compute_new_selection_text (EvView          *view,
                selection->rect.x2 = width;
                selection->rect.y2 = height;
 
-               get_page_extents (view, i, &page_area, &border);
+               ev_view_get_page_extents (view, i, &page_area, &border);
 
                if (gdk_rectangle_point_in (&page_area, start))
                        point = start;
@@ -5325,7 +6019,7 @@ merge_selection_region (EvView *view,
        while (new_list_ptr || old_list_ptr) {
                EvViewSelection *old_sel, *new_sel;
                int cur_page;
-               GdkRegion *region = NULL;
+               cairo_region_t *region = NULL;
 
                new_sel = (new_list_ptr) ? (new_list_ptr->data) : NULL;
                old_sel = (old_list_ptr) ? (old_list_ptr->data) : NULL;
@@ -5360,15 +6054,15 @@ merge_selection_region (EvView *view,
                /* seed the cache with a new page.  We are going to need the new
                 * region too. */
                if (new_sel) {
-                       GdkRegion *tmp_region = NULL;
+                       cairo_region_t *tmp_region = NULL;
 
                        ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache,
                                                               cur_page,
                                                               view->scale,
                                                               &tmp_region);
 
-                       if (tmp_region) {
-                               new_sel->covered_region = gdk_region_copy (tmp_region);
+                       if (tmp_region && !cairo_region_is_empty (tmp_region)) {
+                               new_sel->covered_region = cairo_region_reference (tmp_region);
                        }
                }
 
@@ -5378,24 +6072,52 @@ merge_selection_region (EvView *view,
                                /* We only want to redraw the areas that have
                                 * changed, so we xor the old and new regions
                                 * and redraw if it's different */
-                               region = gdk_region_copy (old_sel->covered_region);
-                               gdk_region_xor (region, new_sel->covered_region);
-                               if (gdk_region_empty (region)) {
-                                       gdk_region_destroy (region);
+                               region = cairo_region_copy (old_sel->covered_region);
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 9, 12)
+                               cairo_region_xor (region, new_sel->covered_region);
+#else
+                               cairo_region_t *tbr;
+                               tbr = cairo_region_copy (new_sel->covered_region);
+
+                               /* xor old_sel, new_sel*/
+                               cairo_region_subtract (tbr, region);
+                               cairo_region_subtract (region, new_sel->covered_region);
+                               cairo_region_union (region, tbr);
+                               cairo_region_destroy (tbr);
+#endif
+
+                               if (cairo_region_is_empty (region)) {
+                                       cairo_region_destroy (region);
                                        region = NULL;
+                               } else {
+                                       gint num_rectangles = cairo_region_num_rectangles (region);
+                                       GdkRectangle r;
+
+                                       /* We need to make the damage region a little bigger
+                                        * because the edges of the old selection might change
+                                        */
+                                       cairo_region_get_rectangle (region, 0, &r);
+                                       r.x -= 5;
+                                       r.width = 5;
+                                       cairo_region_union_rectangle (region, &r);
+
+                                       cairo_region_get_rectangle (region, num_rectangles - 1, &r);
+                                       r.x += r.width;
+                                       r.width = 5;
+                                       cairo_region_union_rectangle (region, &r);
                                }
                        } else if (old_sel->covered_region) {
-                               region = gdk_region_copy (old_sel->covered_region);
+                               region = cairo_region_copy (old_sel->covered_region);
                        } else if (new_sel->covered_region) {
-                               region = gdk_region_copy (new_sel->covered_region);
+                               region = cairo_region_copy (new_sel->covered_region);
                        }
                } else if (old_sel && !new_sel) {
-                       if (old_sel->covered_region && !gdk_region_empty (old_sel->covered_region)) {
-                               region = gdk_region_copy (old_sel->covered_region);
+                       if (old_sel->covered_region && !cairo_region_is_empty (old_sel->covered_region)) {
+                               region = cairo_region_copy (old_sel->covered_region);
                        }
                } else if (!old_sel && new_sel) {
-                       if (new_sel->covered_region && !gdk_region_empty (new_sel->covered_region)) {
-                               region = gdk_region_copy (new_sel->covered_region);
+                       if (new_sel->covered_region && !cairo_region_is_empty (new_sel->covered_region)) {
+                               region = cairo_region_copy (new_sel->covered_region);
                        }
                } else {
                        g_assert_not_reached ();
@@ -5404,20 +6126,14 @@ merge_selection_region (EvView *view,
                /* Redraw the damaged region! */
                if (region) {
                        GdkRectangle page_area;
-                       GtkBorder border;
-
-                       /* I don't know why but the region is smaller
-                        * than expected. This hack fixes it, I guess
-                        * 10 pixels more won't hurt
-                        */
-                       gdk_region_shrink (region, -5, -5);
+                       GtkBorder    border;
 
-                       get_page_extents (view, cur_page, &page_area, &border);
-                       gdk_region_offset (region,
+                       ev_view_get_page_extents (view, cur_page, &page_area, &border);
+                       cairo_region_translate (region,
                                           page_area.x + border.left - view->scroll_x,
                                           page_area.y + border.top - view->scroll_y);
-                       gdk_window_invalidate_region (view->layout.bin_window, region, TRUE);
-                       gdk_region_destroy (region);
+                       gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)), region, TRUE);
+                       cairo_region_destroy (region);
                }
        }
 
@@ -5447,7 +6163,7 @@ static void
 selection_free (EvViewSelection *selection)
 {
        if (selection->covered_region)
-               gdk_region_destroy (selection->covered_region);
+               cairo_region_destroy (selection->covered_region);
        g_free (selection);
 }
 
@@ -5511,10 +6227,8 @@ get_selected_text (EvView *view)
        GString *text;
        GList *l;
        gchar *normalized_text;
-       EvRenderContext *rc;
 
        text = g_string_new (NULL);
-       rc = ev_render_context_new (NULL, view->rotation, view->scale);
 
        ev_document_doc_mutex_lock ();
 
@@ -5524,19 +6238,14 @@ get_selected_text (EvView *view)
                gchar *tmp;
 
                page = ev_document_get_page (view->document, selection->page);
-               ev_render_context_set_page (rc, page);
-               g_object_unref (page);
-               
                tmp = ev_selection_get_selected_text (EV_SELECTION (view->document),
-                                                     rc, selection->style,
+                                                     page, selection->style,
                                                      &(selection->rect));
-
+               g_object_unref (page);
                g_string_append (text, tmp);
                g_free (tmp);
        }
 
-       g_object_unref (rc);
-       
        ev_document_doc_mutex_unlock ();
        
        normalized_text = g_utf8_normalize (text->str, text->len, G_NORMALIZE_NFKC);
@@ -5661,6 +6370,7 @@ ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
 {
        GdkCursor *cursor = NULL;
        GtkWidget *widget;
+       GdkWindow *window;
 
        if (view->cursor == new_cursor) {
                return;
@@ -5668,12 +6378,13 @@ ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
 
        view->cursor = new_cursor;
 
+       window = gtk_widget_get_window (GTK_WIDGET (view));
        widget = gtk_widget_get_toplevel (GTK_WIDGET (view));
        cursor = ev_view_cursor_new (gtk_widget_get_display (widget), new_cursor);
-       gdk_window_set_cursor (view->layout.bin_window, cursor);
+       gdk_window_set_cursor (window, cursor);
        gdk_flush ();
        if (cursor)
-               gdk_cursor_unref (cursor);
+               g_object_unref (cursor);
 }
 
 void