X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=libview%2Fev-view.c;h=973da901eb5be6aaaa2f7194e47873086be2d3e3;hb=5f554d8e362a35e05840068e1b3ea935be5d3c47;hp=830530846849f61cc8f5750e67b014aa82b9c279;hpb=3b5294efda84103bc09484ac182afd3ac69ee356;p=evince.git diff --git a/libview/ev-view.c b/libview/ev-view.c index 83053084..973da901 100644 --- a/libview/ev-view.c +++ b/libview/ev-view.c @@ -87,8 +87,6 @@ typedef enum { #define SCROLL_TIME 150 /*** Scrolling ***/ -static void scroll_to_current_page (EvView *view, - GtkOrientation orientation); static void ev_view_set_scroll_adjustments (GtkLayout *layout, GtkAdjustment *hadjustment, GtkAdjustment *vadjustment); @@ -131,7 +129,7 @@ static void find_page_at_location (EvView gint *page, gint *x_offset, gint *y_offset); -static gboolean doc_point_to_view_point (EvView *view, +static void doc_point_to_view_point (EvView *view, int page, EvPoint *doc_point, GdkPoint *view_point); @@ -212,6 +210,9 @@ static void ev_view_reload_page (EvView GdkRegion *region); /*** Callbacks ***/ +static void ev_view_change_page (EvView *view, + gint new_page, + gboolean start_transition); static void job_finished_cb (EvPixbufCache *pixbuf_cache, GdkRegion *region, EvView *view); @@ -480,42 +481,30 @@ ev_view_get_height_to_page (EvView *view, } static void -scroll_to_current_page (EvView *view, GtkOrientation orientation) +scroll_to_point (EvView *view, + gdouble x, + gdouble y, + GtkOrientation orientation) { - GdkPoint view_point; - - if (view->document == NULL) { - return; - } - - doc_point_to_view_point (view, view->current_page, &view->pending_point, &view_point); - - if (orientation == GTK_ORIENTATION_VERTICAL) { - view->pending_point.y = 0; - } else { - view->pending_point.x = 0; - } - if (orientation == GTK_ORIENTATION_VERTICAL) { if (view->continuous) { gtk_adjustment_clamp_page (view->vadjustment, - view_point.y - view->spacing / 2, - view_point.y + view->vadjustment->page_size); + y - view->spacing / 2, + y + view->vadjustment->page_size); } else { gtk_adjustment_set_value (view->vadjustment, - CLAMP (view_point.y, + CLAMP (y, view->vadjustment->lower, view->vadjustment->upper - view->vadjustment->page_size)); } } else { if (view->dual_page) { - gtk_adjustment_clamp_page (view->hadjustment, - view_point.x, - view_point.x + view->hadjustment->page_size); + gtk_adjustment_clamp_page (view->hadjustment, x, + x + view->hadjustment->page_size); } else { gtk_adjustment_set_value (view->hadjustment, - CLAMP (view_point.x, + CLAMP (x, view->hadjustment->lower, view->hadjustment->upper - view->hadjustment->page_size)); @@ -523,6 +512,34 @@ scroll_to_current_page (EvView *view, GtkOrientation orientation) } } +static void +ev_view_scroll_to_page_position (EvView *view, GtkOrientation orientation) +{ + gdouble x, y; + + if (!view->document) + return; + + if ((orientation == GTK_ORIENTATION_VERTICAL && view->pending_point.y == 0) || + (orientation == GTK_ORIENTATION_HORIZONTAL && view->pending_point.x == 0)) { + GdkRectangle page_area; + GtkBorder border; + + get_page_extents (view, view->current_page, &page_area, &border); + x = page_area.x; + y = page_area.y; + } else { + GdkPoint view_point; + + doc_point_to_view_point (view, view->current_page, + &view->pending_point, &view_point); + x = view_point.x; + y = view_point.y; + } + + scroll_to_point (view, x, y, orientation); +} + static void view_set_adjustment_values (EvView *view, GtkOrientation orientation) @@ -577,7 +594,7 @@ view_set_adjustment_values (EvView *view, gtk_adjustment_set_value (adjustment, (int)new_value); break; case SCROLL_TO_PAGE_POSITION: - scroll_to_current_page (view, orientation); + 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, @@ -750,6 +767,79 @@ add_scroll_binding_keypad (GtkBindingSet *binding_set, G_TYPE_BOOLEAN, horizontal); } +static gdouble +compute_scroll_increment (EvView *view, + GtkScrollType scroll) +{ + GtkWidget *widget = GTK_WIDGET (view); + GtkAdjustment *adjustment = view->vadjustment; + GdkRegion *text_region, *region; + 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; + + page = scroll == GTK_SCROLL_PAGE_BACKWARD ? view->start_page : view->end_page; + + text_region = ev_pixbuf_cache_get_text_mapping (view->pixbuf_cache, page); + if (!text_region || gdk_region_empty (text_region)) + return adjustment->page_size; + + 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.width = page_area.width; + rect.height = 1; + view_rect_to_doc_rect (view, &rect, &page_area, &doc_rect); + + /* Convert the doc rectangle into a GdkRectangle */ + rect.x = doc_rect.x1; + 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); + + gdk_region_intersect (region, text_region); + gdk_region_get_rectangles (region, &recs, &n_recs); + gdk_region_destroy (region); + if (n_recs > 0) { + EvRenderContext *rc; + EvPage *ev_page; + + 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; + + ev_document_doc_mutex_lock (); + 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); + } + g_free (recs); + } + + return adjustment->page_size * fraction; + +} + void ev_view_scroll (EvView *view, GtkScrollType scroll, @@ -780,7 +870,6 @@ ev_view_scroll (EvView *view, /* Assign values for increment and vertical adjustment */ adjustment = horizontal ? view->hadjustment : view->vadjustment; - increment = adjustment->page_size * 0.75; value = adjustment->value; /* Assign boolean for first and last page */ @@ -800,6 +889,7 @@ ev_view_scroll (EvView *view, 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); } break; @@ -813,6 +903,7 @@ ev_view_scroll (EvView *view, 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); } break; @@ -1107,7 +1198,7 @@ view_rect_to_doc_rect (EvView *view, doc_rect->y2 = doc_rect->y1 + (double) view_rect->height / view->scale; } -static gboolean +static void doc_point_to_view_point (EvView *view, int page, EvPoint *doc_point, @@ -1138,13 +1229,10 @@ doc_point_to_view_point (EvView *view, get_page_extents (view, page, &page_area, &border); - view_x = x * view->scale; - view_y = y * view->scale; + view_x = CLAMP (x * view->scale, 0, page_area.width); + view_y = CLAMP (y * view->scale, 0, page_area.height); view_point->x = view_x + page_area.x; view_point->y = view_y + page_area.y; - - return (view_x > 0 && view_x <= page_area.width && - view_y > 0 && view_y <= page_area.height); } static void @@ -1413,13 +1501,9 @@ goto_fitr_dest (EvView *view, EvLinkDest *dest) doc_point.x = change_left ? left : 0; doc_point.y = change_top ? top : 0; - - view->current_page = ev_link_dest_get_page (dest); - if (change_left || change_top) - view->pending_point = doc_point; - view->pending_scroll = SCROLL_TO_PAGE_POSITION; + view->pending_point = doc_point; - gtk_widget_queue_resize (GTK_WIDGET (view)); + ev_view_change_page (view, ev_link_dest_get_page (dest), TRUE); } static void @@ -1445,12 +1529,9 @@ goto_fitv_dest (EvView *view, EvLinkDest *dest) ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE); ev_document_model_set_scale (view->model, zoom); - view->current_page = page; - if (change_left) - view->pending_point = doc_point; - view->pending_scroll = SCROLL_TO_PAGE_POSITION; + view->pending_point = doc_point; - gtk_widget_queue_resize (GTK_WIDGET (view)); + ev_view_change_page (view, page, TRUE); } static void @@ -1477,12 +1558,9 @@ goto_fith_dest (EvView *view, EvLinkDest *dest) ev_document_model_set_sizing_mode (view->model, EV_SIZING_FIT_WIDTH); ev_document_model_set_scale (view->model, zoom); - view->current_page = page; - if (change_top) - view->pending_point = doc_point; - view->pending_scroll = SCROLL_TO_PAGE_POSITION; + view->pending_point = doc_point; - gtk_widget_queue_resize (GTK_WIDGET (view)); + ev_view_change_page (view, page, TRUE); } static void @@ -1502,10 +1580,7 @@ goto_fit_dest (EvView *view, EvLinkDest *dest) ev_document_model_set_sizing_mode (view->model, EV_SIZING_BEST_FIT); ev_document_model_set_scale (view->model, zoom); - view->current_page = page; - view->pending_scroll = SCROLL_TO_PAGE_POSITION; - - gtk_widget_queue_resize (GTK_WIDGET (view)); + ev_view_change_page (view, page, TRUE); } static void @@ -1529,13 +1604,9 @@ goto_xyz_dest (EvView *view, EvLinkDest *dest) doc_point.x = change_left ? left : 0; doc_point.y = change_top ? top : 0; + view->pending_point = doc_point; - view->current_page = page; - if (change_left || change_top) - view->pending_point = doc_point; - view->pending_scroll = SCROLL_TO_PAGE_POSITION; - - gtk_widget_queue_resize (GTK_WIDGET (view)); + ev_view_change_page (view, page, TRUE); } static void @@ -2812,6 +2883,8 @@ ev_view_size_allocate (GtkWidget *widget, view->pending_scroll = SCROLL_TO_KEEP_POSITION; view->pending_resize = FALSE; + 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)) { @@ -5094,9 +5167,13 @@ ev_view_rotation_changed_cb (EvDocumentModel *model, if (view->pixbuf_cache) { ev_pixbuf_cache_clear (view->pixbuf_cache); + if (!ev_document_is_page_size_uniform (view->document)) + view->pending_scroll = SCROLL_TO_PAGE_POSITION; gtk_widget_queue_resize (GTK_WIDGET (view)); } + ev_view_remove_all (view); + if (rotation != 0) clear_selection (view); } @@ -5136,6 +5213,44 @@ ev_view_scale_changed_cb (EvDocumentModel *model, gtk_widget_queue_resize (GTK_WIDGET (view)); } +static void +ev_view_continuous_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvView *view) +{ + gboolean continuous = ev_document_model_get_continuous (model); + + ev_view_set_continuous (view, continuous); + view->pending_scroll = SCROLL_TO_PAGE_POSITION; + gtk_widget_queue_resize (GTK_WIDGET (view)); +} + +static void +ev_view_dual_page_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvView *view) +{ + gboolean dual_page = ev_document_model_get_dual_page (model); + + ev_view_set_dual_page (view, dual_page); + view->pending_scroll = SCROLL_TO_PAGE_POSITION; + /* FIXME: if we're keeping the pixbuf cache around, we should extend the + * preload_cache_size to be 2 if dual_page is set. + */ + gtk_widget_queue_resize (GTK_WIDGET (view)); +} + +static void +ev_view_fullscreen_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvView *view) +{ + gboolean fullscreen = ev_document_model_get_fullscreen (model); + + ev_view_set_fullscreen (view, fullscreen); + gtk_widget_queue_resize (GTK_WIDGET (view)); +} + void ev_view_set_model (EvView *view, EvDocumentModel *model) @@ -5168,6 +5283,15 @@ ev_view_set_model (EvView *view, g_signal_connect (view->model, "notify::scale", G_CALLBACK (ev_view_scale_changed_cb), view); + g_signal_connect (view->model, "notify::continuous", + G_CALLBACK (ev_view_continuous_changed_cb), + view); + g_signal_connect (view->model, "notify::dual-page", + G_CALLBACK (ev_view_dual_page_changed_cb), + view); + g_signal_connect (view->model, "notify::fullscreen", + G_CALLBACK (ev_view_fullscreen_changed_cb), + view); g_signal_connect (view->model, "page-changed", G_CALLBACK (ev_view_page_changed_cb), view); @@ -5209,16 +5333,6 @@ ev_view_get_zoom (EvView *view) return view->scale; } -void -ev_view_set_screen_dpi (EvView *view, - gdouble dpi) -{ - g_return_if_fail (EV_IS_VIEW (view)); - g_return_if_fail (dpi > 0); - - view->dpi = dpi; -} - gboolean ev_view_get_continuous (EvView *view) { @@ -5233,13 +5347,7 @@ ev_view_set_continuous (EvView *view, { g_return_if_fail (EV_IS_VIEW (view)); - continuous = continuous != FALSE; - - if (view->continuous != continuous) { - view->continuous = continuous; - view->pending_scroll = SCROLL_TO_PAGE_POSITION; - gtk_widget_queue_resize (GTK_WIDGET (view)); - } + view->continuous = continuous; g_object_notify (G_OBJECT (view), "continuous"); } @@ -5258,17 +5366,7 @@ ev_view_set_dual_page (EvView *view, { g_return_if_fail (EV_IS_VIEW (view)); - dual_page = dual_page != FALSE; - - if (view->dual_page == dual_page) - return; - - view->pending_scroll = SCROLL_TO_PAGE_POSITION; view->dual_page = dual_page; - /* FIXME: if we're keeping the pixbuf cache around, we should extend the - * preload_cache_size to be 2 if dual_page is set. - */ - gtk_widget_queue_resize (GTK_WIDGET (view)); g_object_notify (G_OBJECT (view), "dual-page"); } @@ -5279,14 +5377,8 @@ ev_view_set_fullscreen (EvView *view, { g_return_if_fail (EV_IS_VIEW (view)); - fullscreen = fullscreen != FALSE; - - if (view->fullscreen == fullscreen) - return; - view->fullscreen = fullscreen; - gtk_widget_queue_resize (GTK_WIDGET (view)); - + g_object_notify (G_OBJECT (view), "fullscreen"); }