]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-view.c
Fix flickering on resizing
[evince.git] / shell / ev-view.c
index 3e28b0c58f690e9db8088f51f00b27c4e7d77d85..d9dddaf24e61c304635f5d9f6f4af6c34cf571a1 100644 (file)
@@ -51,6 +51,12 @@ enum {
        PROP_SIZING_MODE,
 };
 
+enum {
+       SIGNAL_SCROLL_VIEW,
+       SIGNAL_ZOOM_INVALID,
+       N_SIGNALS,
+};
+
 enum {
        TARGET_STRING,
        TARGET_TEXT,
@@ -66,6 +72,8 @@ static const GtkTargetEntry targets[] = {
        { "UTF8_STRING", 0, TARGET_UTF8_STRING },
 };
 
+static guint signals[N_SIGNALS];
+
 typedef enum {
        EV_VIEW_CURSOR_NORMAL,
        EV_VIEW_CURSOR_LINK,
@@ -141,6 +149,7 @@ struct _EvView {
        EvSizingMode sizing_mode;
        
        PendingScroll pending_scroll;
+       gboolean pending_resize;
 };
 
 struct _EvViewClass {
@@ -152,6 +161,7 @@ struct _EvViewClass {
        void    (*scroll_view)            (EvView         *view,
                                           GtkScrollType   scroll,
                                           gboolean        horizontal);
+       void    (*zoom_invalid)           (EvView         *view);
 };
 
 /*** Scrolling ***/
@@ -281,33 +291,40 @@ static void       ev_view_class_init                         (EvViewClass
 static void       ev_view_init                               (EvView             *view);
 
 /*** Zoom and sizing ***/
-static double     zoom_for_size_fit_width                    (int                 doc_width,
-                                                             int                 doc_height,
-                                                             int                 target_width,
-                                                             int                 target_height);
-static double     zoom_for_size_best_fit                     (int                 doc_width,
-                                                             int                 doc_height,
-                                                             int                 target_width,
-                                                             int                 target_height);
-static void       ev_view_zoom_for_size_presentation         (EvView             *view,
-                                                             int                 width,
-                                                             int                 height);
-static void       ev_view_zoom_for_size_continuous_dual_page (EvView             *view,
-                                                             int                 width,
-                                                             int                 height);
-static void       ev_view_zoom_for_size_continuous           (EvView             *view,
-                                                             int                 width,
-                                                             int                 height);
-static void       ev_view_zoom_for_size_dual_page            (EvView             *view,
-                                                             int                 width,
-                                                             int                 height);
-static void       ev_view_zoom_for_size_single_page          (EvView             *view,
-                                                             int                 width,
-                                                             int                 height);
-static void       ev_view_set_zoom_for_size                  (EvView             *view,
-                                                             int                 width,
-                                                             int                 height);
-
+static double   zoom_for_size_fit_width                             (int doc_width,
+                                                             int doc_height,
+                                                             int target_width,
+                                                             int target_height,
+                                                             int vsb_width);
+static double  zoom_for_size_best_fit                       (int doc_width,
+                                                             int doc_height,
+                                                             int target_width,
+                                                             int target_height,
+                                                             int vsb_width,
+                                                             int hsb_width);
+static void    ev_view_zoom_for_size_presentation           (EvView *view,
+                                                             int     width,
+                                                             int     height);
+static void    ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
+                                                               int     width,
+                                                               int     height,
+                                                               int     vsb_width,
+                                                               int     hsb_height);
+static void    ev_view_zoom_for_size_continuous               (EvView *view,
+                                                               int     width,
+                                                               int     height,
+                                                               int     vsb_width,
+                                                               int     hsb_height);
+static void    ev_view_zoom_for_size_dual_page                (EvView *view,
+                                                               int     width,
+                                                               int     height,
+                                                               int     vsb_width,
+                                                               int     hsb_height);
+static void    ev_view_zoom_for_size_single_page              (EvView *view,
+                                                               int     width,
+                                                               int     height,
+                                                               int     vsb_width,
+                                                               int     hsb_height);
 /*** Cursors ***/
 static GdkCursor* ev_view_create_invisible_cursor            (void);
 static void       ev_view_set_cursor                         (EvView             *view,
@@ -342,17 +359,31 @@ G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET)
 static void
 view_update_adjustments (EvView *view)
 {
-       if (view->hadjustment)
+       int dx = 0, dy = 0;
+
+       if (! GTK_WIDGET_REALIZED (view))
+               return;
+
+       if (view->hadjustment) {
+               dx = view->scroll_x - view->hadjustment->value;
                view->scroll_x = view->hadjustment->value;
-       else
+       } else {
                view->scroll_x = 0;
+       }
 
-       if (view->vadjustment)
+       if (view->vadjustment) {
+               dy = view->scroll_y - view->vadjustment->value;
                view->scroll_y = view->vadjustment->value;
-       else
+       } else {
                view->scroll_y = 0;
-               
-       gtk_widget_queue_draw (GTK_WIDGET (view));
+       }
+       
+       
+       if (view->pending_resize)       
+               gtk_widget_queue_draw (GTK_WIDGET (view));
+       else
+               gdk_window_scroll (GTK_WIDGET (view)->window, dx, dy);
+
 
        if (view->document)
                view_update_range_and_current_page (view);
@@ -510,7 +541,7 @@ view_scroll_to_page (EvView *view, gint new_page)
        EvPageCache *page_cache = view->page_cache;
        int old_width, old_height;
        int new_width, new_height;
-       int max_height, n_rows;
+       int max_height, max_width, n_rows;
 
        ev_page_cache_get_size (page_cache,
                                view->current_page,
@@ -529,11 +560,11 @@ view_scroll_to_page (EvView *view, gint new_page)
        else
                gtk_widget_queue_draw (GTK_WIDGET (view));
        
-       if (view->continuous) {
+       get_bounding_box_size (view, &max_width, &max_height);
+       
+       if (view->continuous && view->vadjustment) {
                
                n_rows = view->dual_page ? new_page / 2 : new_page;
-               
-               get_bounding_box_size (view, NULL, &max_height);
 
                gtk_adjustment_clamp_page(view->vadjustment,
                                          (max_height + view->spacing) * n_rows, 
@@ -543,6 +574,20 @@ view_scroll_to_page (EvView *view, gint new_page)
                gtk_adjustment_set_value (view->vadjustment,
                                          view->vadjustment->lower);
        }
+       
+       if (view->dual_page && view->hadjustment) {
+               if (new_page % 2 == 0) {
+                       gtk_adjustment_set_value (view->hadjustment,
+                                                 view->hadjustment->lower);
+               } else {
+                       gtk_adjustment_clamp_page (view->hadjustment,
+                                                  view->hadjustment->lower + 
+                                                  max_width + view->spacing, 
+                                                  view->hadjustment->lower +
+                                                  max_width + view->spacing +
+                                                  view->hadjustment->page_size);
+               }
+       }
 
        view->current_page = new_page;
        view_update_range_and_current_page (view);
@@ -667,38 +712,32 @@ ev_view_scroll_view (EvView *view,
                     GtkScrollType scroll,
                     gboolean horizontal)
 {
-       if (scroll == GTK_SCROLL_PAGE_BACKWARD) {
-               ev_page_cache_prev_page (view->page_cache);
-       } else if (scroll == GTK_SCROLL_PAGE_FORWARD) {
-               ev_page_cache_next_page (view->page_cache);
-       } else {
-               GtkAdjustment *adjustment;
-               double value;
+       GtkAdjustment *adjustment;
+       double value;
 
-               if (horizontal) {
-                       adjustment = view->hadjustment;
-               } else {
-                       adjustment = view->vadjustment;
-               }
+       if (horizontal) {
+               adjustment = view->hadjustment;
+       } else {
+               adjustment = view->vadjustment;
+       }
 
-               value = adjustment->value;
+       value = adjustment->value;
 
-               switch (scroll) {
-                       case GTK_SCROLL_STEP_BACKWARD:
-                               value -= adjustment->step_increment;
-                               break;
-                       case GTK_SCROLL_STEP_FORWARD:
-                               value += adjustment->step_increment;
-                               break;
-                       default:
-                               break;
-               }
+       switch (scroll) {
+               case GTK_SCROLL_STEP_BACKWARD:
+                       value -= adjustment->step_increment;
+                       break;
+               case GTK_SCROLL_STEP_FORWARD:
+                       value += adjustment->step_increment;
+                       break;
+               default:
+                       break;
+       }
 
-               value = CLAMP (value, adjustment->lower,
-                              adjustment->upper - adjustment->page_size);
+       value = CLAMP (value, adjustment->lower,
+                      adjustment->upper - adjustment->page_size);
 
-               gtk_adjustment_set_value (adjustment, value);
-       }
+       gtk_adjustment_set_value (adjustment, value);
 }
 
 #define MARGIN 5
@@ -1151,9 +1190,6 @@ ev_view_size_request (GtkWidget      *widget,
 {
        EvView *view = EV_VIEW (widget);
 
-       if (!GTK_WIDGET_REALIZED (widget))
-               return;
-
        if (view->document == NULL) {
                requisition->width = 1;
                requisition->height = 1;
@@ -1184,16 +1220,17 @@ ev_view_size_allocate (GtkWidget      *widget,
        
        if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
                  view->sizing_mode == EV_SIZING_BEST_FIT) {
-                           
-                 ev_view_set_zoom_for_size (view, allocation->width, allocation->height);
-                 ev_view_size_request (widget, &widget->requisition);
-       }
-
 
+               g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0);
+               
+               ev_view_size_request (widget, &widget->requisition);
+       }
+       
        view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
        view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
 
        view->pending_scroll = SCROLL_TO_KEEP_POSITION;
+       view->pending_resize = FALSE;
 
        if (view->document)
                view_update_range_and_current_page (view);              
@@ -1239,15 +1276,6 @@ ev_view_realize (GtkWidget *widget)
                gdk_window_set_background (widget->window, &widget->style->black);
        else
                gdk_window_set_background (widget->window, &widget->style->mid [GTK_STATE_NORMAL]);
-
-       if (view->document) {
-               /* We can't get page size without a target, so we have to
-                * queue a size request at realization. Could be fixed
-                * with EvDocument changes to allow setting a GdkScreen
-                * without setting a target.
-                */
-               gtk_widget_queue_resize (widget);
-       }
 }
 
 static void
@@ -1753,7 +1781,7 @@ ev_view_class_init (EvViewClass *class)
                          GTK_TYPE_ADJUSTMENT,
                          GTK_TYPE_ADJUSTMENT);
 
-          g_signal_new ("scroll_view",
+       signals[SIGNAL_SCROLL_VIEW] = g_signal_new ("scroll-view",
                         G_TYPE_FROM_CLASS (object_class),
                         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                         G_STRUCT_OFFSET (EvViewClass, scroll_view),
@@ -1763,6 +1791,14 @@ ev_view_class_init (EvViewClass *class)
                         GTK_TYPE_SCROLL_TYPE,
                         G_TYPE_BOOLEAN);
 
+       signals[SIGNAL_ZOOM_INVALID] = g_signal_new ("zoom-invalid",
+                        G_TYPE_FROM_CLASS (object_class),
+                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                        G_STRUCT_OFFSET (EvViewClass, zoom_invalid),
+                        NULL, NULL,
+                        ev_marshal_VOID__VOID,
+                        G_TYPE_NONE, 0, G_TYPE_NONE);
+
        g_object_class_install_property (object_class,
                                         PROP_STATUS,
                                         g_param_spec_string ("status",
@@ -1824,9 +1860,6 @@ ev_view_class_init (EvViewClass *class)
        add_scroll_binding_keypad (binding_set, GDK_Right, GTK_SCROLL_STEP_FORWARD,  TRUE);
        add_scroll_binding_keypad (binding_set, GDK_Up,    GTK_SCROLL_STEP_BACKWARD, FALSE);
        add_scroll_binding_keypad (binding_set, GDK_Down,  GTK_SCROLL_STEP_FORWARD,  FALSE);
-
-       add_scroll_binding_keypad (binding_set, GDK_Page_Up,   GTK_SCROLL_PAGE_BACKWARD, FALSE);
-       add_scroll_binding_keypad (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_FORWARD,  FALSE);
 }
 
 static void
@@ -1876,7 +1909,13 @@ page_changed_cb (EvPageCache *page_cache,
 {
        if (view->current_page != new_page) {
 
-               view_scroll_to_page (view, new_page);
+               if (view->pending_scroll != SCROLL_TO_CURRENT_PAGE) {
+                       /* Should scroll right now */
+                       view_scroll_to_page (view, new_page);
+               } else {        
+                       /* We'll scroll to new page on allocate */
+                       view->current_page = new_page;
+               }
 
                if (EV_IS_DOCUMENT_FIND (view->document)) {
                        view->find_page = new_page;
@@ -1961,6 +2000,7 @@ ev_view_set_zoom (EvView   *view,
        if (ABS (view->scale - scale) < EPSILON)
                return;
        view->scale = scale;
+       view->pending_resize = TRUE;
 
        gtk_widget_queue_resize (GTK_WIDGET (view));
 }
@@ -2120,20 +2160,19 @@ ev_view_zoom_out (EvView *view)
        ev_view_set_zoom (view, ZOOM_OUT_FACTOR, TRUE);
 }
 
-
-
 static double
 zoom_for_size_fit_width (int doc_width,
                         int doc_height,
                         int target_width,
-                        int target_height)
+                        int target_height,
+                        int vsb_width)
 {
        double scale;
 
        scale = (double)target_width / doc_width;
 
        if (doc_height * scale > target_height)
-               scale = (double) (target_width) / doc_width;
+               scale = (double) (target_width - vsb_width) / doc_width;
 
        return scale;
 }
@@ -2142,7 +2181,9 @@ static double
 zoom_for_size_best_fit (int doc_width,
                        int doc_height,
                        int target_width,
-                       int target_height)
+                       int target_height,
+                       int vsb_width,
+                       int hsb_width)
 {
        double w_scale;
        double h_scale;
@@ -2151,9 +2192,9 @@ zoom_for_size_best_fit (int doc_width,
        h_scale = (double)target_height / doc_height;
 
        if (doc_height * w_scale > target_height)
-               w_scale = (double) target_width / doc_width;
+               w_scale = (double) (target_width - vsb_width) / doc_width;
        if (doc_width * h_scale > target_width)
-               h_scale = (double) target_height / doc_height;
+               h_scale = (double) (target_height - hsb_width) / doc_height;
 
        return MIN (w_scale, h_scale);
 }
@@ -2172,14 +2213,16 @@ ev_view_zoom_for_size_presentation (EvView *view,
                                1.0,
                                &doc_width,
                                &doc_height);
-       scale = zoom_for_size_best_fit (doc_width, doc_height, width, height);
+       scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, 0, 0);
        ev_view_set_zoom (view, scale, FALSE);
 }
 
 static void
-ev_view_zoom_for_size_continuous_dual_page (EvView *view,
+ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
                           int     width,
-                          int     height)
+                          int     height,
+                          int     vsb_width,
+                          int     hsb_height)
 {
        int doc_width, doc_height;
        GtkBorder border;
@@ -2201,9 +2244,9 @@ ev_view_zoom_for_size_continuous_dual_page (EvView *view,
         * page height.  We assume there's always a vertical scrollbar for
         * now.  We need to fix this. */
        if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
-               scale = zoom_for_size_fit_width (doc_width, doc_height, width, height);
+               scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
        else if (view->sizing_mode == EV_SIZING_BEST_FIT)
-               scale = zoom_for_size_best_fit (doc_width, doc_height, widthheight);
+               scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
        else
                g_assert_not_reached ();
 
@@ -2213,7 +2256,9 @@ ev_view_zoom_for_size_continuous_dual_page (EvView *view,
 static void
 ev_view_zoom_for_size_continuous (EvView *view,
                                  int     width,
-                                 int     height)
+                                 int     height,
+                                 int     vsb_width,
+                                 int     hsb_height)
 {
        int doc_width, doc_height;
        GtkBorder border;
@@ -2234,9 +2279,9 @@ ev_view_zoom_for_size_continuous (EvView *view,
         * page height.  We assume there's always a vertical scrollbar for
         * now.  We need to fix this. */
        if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
-               scale = zoom_for_size_fit_width (doc_width, doc_height, width, height);
+               scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
        else if (view->sizing_mode == EV_SIZING_BEST_FIT)
-               scale = zoom_for_size_best_fit (doc_width, doc_height, widthheight);
+               scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
        else
                g_assert_not_reached ();
 
@@ -2246,7 +2291,9 @@ ev_view_zoom_for_size_continuous (EvView *view,
 static void
 ev_view_zoom_for_size_dual_page (EvView *view,
                                 int     width,
-                                int     height)
+                                int     height,
+                                int     vsb_width,
+                                int     hsb_height)
 {
        GtkBorder border;
        gint doc_width, doc_height;
@@ -2279,9 +2326,9 @@ ev_view_zoom_for_size_dual_page (EvView *view,
        height -= (border.top + border.bottom + 2 * view->spacing);
 
        if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
-               scale = zoom_for_size_fit_width (doc_width, doc_height, width, height);
+               scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
        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, height, vsb_width, hsb_height);
        else
                g_assert_not_reached ();
 
@@ -2291,7 +2338,9 @@ ev_view_zoom_for_size_dual_page (EvView *view,
 static void
 ev_view_zoom_for_size_single_page (EvView *view,
                                   int     width,
-                                  int     height)
+                                  int     height,
+                                  int     vsb_width,
+                                  int     hsb_height)
 {
        int doc_width, doc_height;
        GtkBorder border;
@@ -2309,9 +2358,9 @@ ev_view_zoom_for_size_single_page (EvView *view,
        height -= (border.top + border.bottom + 2 * view->spacing);
 
        if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
-               scale = zoom_for_size_fit_width (doc_width, doc_height, width, height);
+               scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
        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, height, vsb_width, hsb_height);
        else
                g_assert_not_reached ();
 
@@ -2321,8 +2370,10 @@ ev_view_zoom_for_size_single_page (EvView *view,
 void
 ev_view_set_zoom_for_size (EvView *view,
                           int     width,
-                          int     height)
-{
+                          int     height,
+                          int     vsb_width,
+                          int     hsb_height)
+{      
        g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
                          view->sizing_mode == EV_SIZING_BEST_FIT);
        g_return_if_fail (width >= 0);
@@ -2334,13 +2385,13 @@ ev_view_set_zoom_for_size (EvView *view,
        if (view->presentation)
                ev_view_zoom_for_size_presentation (view, width, height);
        else if (view->continuous && view->dual_page)
-               ev_view_zoom_for_size_continuous_dual_page (view, width, height);
+               ev_view_zoom_for_size_continuous_and_dual_page (view, width, height, vsb_width, hsb_height);
        else if (view->continuous)
-               ev_view_zoom_for_size_continuous (view, width, height);
+               ev_view_zoom_for_size_continuous (view, width, height, vsb_width, hsb_height);
        else if (view->dual_page)
-               ev_view_zoom_for_size_dual_page (view, width, height);
+               ev_view_zoom_for_size_dual_page (view, width, height, vsb_width, hsb_height);
        else
-               ev_view_zoom_for_size_single_page (view, width, height);
+               ev_view_zoom_for_size_single_page (view, width, height, vsb_width, hsb_height);
 }
 
 /*** Status text messages ***/