X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=shell%2Fev-view.c;h=311504b147e4116a9e6b844ad92bfbbe709d11d6;hb=f693b48e9ca24fec37c190cdb90682c67e8e6c28;hp=a9418dac2337e6a2d9ed3e99238731e1869295b4;hpb=a0af7b2e9d42e05aa0108ae6dc9c34deb9723404;p=evince.git diff --git a/shell/ev-view.c b/shell/ev-view.c index a9418dac..311504b1 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -64,6 +64,7 @@ enum { SIGNAL_BINDING_ACTIVATED, SIGNAL_ZOOM_INVALID, SIGNAL_EXTERNAL_LINK, + SIGNAL_POPUP_MENU, N_SIGNALS, }; @@ -95,6 +96,8 @@ typedef enum { #define MIN_SCALE 0.05409 #define MAX_SCALE 4.0 +#define SCROLL_TIME 150 + /*** Scrolling ***/ static void scroll_to_current_page (EvView *view, GtkOrientation orientation); @@ -145,11 +148,14 @@ static void find_page_at_location (EvView gint *page, gint *x_offset, gint *y_offset); - +static gboolean doc_point_to_view_point (EvView *view, + int page, + EvPoint *doc_point, + GdkPoint *view_point); /*** Hyperrefs ***/ -static EvLink* get_link_at_location (EvView *view, - gdouble x, - gdouble y); +static EvLink * ev_view_get_link_at_location (EvView *view, + gdouble x, + gdouble y); static char* tip_from_link (EvView *view, EvLink *link); static void handle_link_over_xy (EvView *view, @@ -173,6 +179,7 @@ static gboolean ev_view_scroll_event (GtkWidget GdkEventScroll *event); static gboolean ev_view_expose_event (GtkWidget *widget, GdkEventExpose *event); +static gboolean ev_view_popup_menu (GtkWidget *widget); static gboolean ev_view_button_press_event (GtkWidget *widget, GdkEventButton *event); static gboolean ev_view_motion_notify_event (GtkWidget *widget, @@ -305,32 +312,40 @@ G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET) static void scroll_to_current_page (EvView *view, GtkOrientation orientation) { - GdkRectangle page_area; - GtkBorder border; + GdkPoint view_point; if (view->document == NULL) { return; } - get_page_extents (view, view->current_page, &page_area, &border); + 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, - page_area.y - view->spacing, - page_area.y + view->vadjustment->page_size); + view_point.y - view->spacing / 2, + view_point.y + view->vadjustment->page_size); } else { gtk_adjustment_set_value (view->vadjustment, - view->vadjustment->lower); + CLAMP (view_point.y, + view->vadjustment->lower, + view->vadjustment->upper - + view->vadjustment->page_size)); } } else { if (view->dual_page) { gtk_adjustment_clamp_page (view->hadjustment, - page_area.x, - page_area.x + view->hadjustment->page_size); + view_point.x, + view_point.x + view->hadjustment->page_size); } else { gtk_adjustment_set_value (view->hadjustment, - CLAMP (view->hadjustment->value, + CLAMP (view_point.x, view->hadjustment->lower, view->hadjustment->upper - view->hadjustment->page_size)); @@ -368,7 +383,7 @@ view_set_adjustment_values (EvView *view, case SCROLL_TO_KEEP_POSITION: factor = (adjustment->value) / adjustment->upper; break; - case SCROLL_TO_CURRENT_PAGE: + case SCROLL_TO_PAGE_POSITION: break; case SCROLL_TO_CENTER: factor = (adjustment->value + adjustment->page_size * 0.5) / adjustment->upper; @@ -389,7 +404,7 @@ view_set_adjustment_values (EvView *view, new_value = CLAMP (adjustment->upper * factor + 0.5, 0, adjustment->upper - adjustment->page_size); gtk_adjustment_set_value (adjustment, (int)new_value); break; - case SCROLL_TO_CURRENT_PAGE: + case SCROLL_TO_PAGE_POSITION: scroll_to_current_page (view, orientation); break; case SCROLL_TO_CENTER: @@ -405,6 +420,8 @@ view_set_adjustment_values (EvView *view, static void view_update_range_and_current_page (EvView *view) { + gint current_page; + if (view->pending_scroll != SCROLL_TO_KEEP_POSITION) return; @@ -415,7 +432,6 @@ view_update_range_and_current_page (EvView *view) } else if (view->continuous) { GdkRectangle current_area, unused, page_area; GtkBorder border; - gint current_page; gboolean found = FALSE; int i; @@ -443,28 +459,33 @@ view_update_range_and_current_page (EvView *view) } } - current_page = ev_page_cache_get_current_page (view->page_cache); - - if (current_page < view->start_page || current_page > view->end_page) { - view->current_page = view->start_page; - ev_page_cache_set_current_page (view->page_cache, view->start_page); - } } else { if (view->dual_page) { - if (view->current_page % 2 == 0) { + if (view->current_page % 2 == DUAL_EVEN_LEFT) { view->start_page = view->current_page; if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache)) view->end_page = view->start_page + 1; else view->end_page = view->start_page; } else { - view->start_page = view->current_page - 1; + if (view->current_page - 1 < 0) + view->start_page = view->current_page; + else + view->start_page = view->current_page - 1; view->end_page = view->current_page; } } else { view->start_page = view->current_page; view->end_page = view->current_page; } + + } + + current_page = ev_page_cache_get_current_page (view->page_cache); + + if (current_page < view->start_page || current_page > view->end_page) { + view->current_page = view->start_page; + ev_page_cache_set_current_page (view->page_cache, view->start_page); } ev_pixbuf_cache_set_page_range (view->pixbuf_cache, @@ -563,7 +584,7 @@ ev_view_scroll (EvView *view, /* 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; - ev_page_cache_set_current_page (view->page_cache, view->current_page - 1); + ev_view_previous_page (view); /* Jump to the top */ } else { value = MAX (value - increment, adjustment->lower); @@ -576,7 +597,7 @@ ev_view_scroll (EvView *view, /* At the bottom of a page, assign the lower bound limit of next page */ } else if (value == (adjustment->upper - adjustment->page_size)) { value = 0; - ev_page_cache_set_current_page (view->page_cache, view->current_page + 1); + ev_view_next_page (view); /* Jump to the bottom */ } else { value = MIN (value + increment, adjustment->upper - adjustment->page_size); @@ -702,7 +723,7 @@ get_page_y_offset (EvView *view, int page, double zoom, int *y_offset) if (view->dual_page) { ev_page_cache_get_height_to_page (view->page_cache, page, view->rotation, zoom, NULL, &offset); - offset += (page / 2 + 1) * view->spacing + (page / 2) * (border.top + border.bottom); + offset += ((page + DUAL_EVEN_LEFT) / 2 + 1) * view->spacing + ((page + DUAL_EVEN_LEFT) / 2 ) * (border.top + border.bottom); } else { ev_page_cache_get_height_to_page (view->page_cache, page, view->rotation, zoom, &offset, NULL); @@ -745,9 +766,9 @@ get_page_extents (EvView *view, max_width = max_width + border->left + border->right; /* Get the location of the bounding box */ if (view->dual_page) { - x = view->spacing + (page % 2) * (max_width + view->spacing); + x = view->spacing + ((page % 2 == DUAL_EVEN_LEFT) ? 0 : 1) * (max_width + view->spacing); x = x + MAX (0, widget->allocation.width - (max_width * 2 + view->spacing * 3)) / 2; - if (page % 2 == 0) + if (page % 2 == DUAL_EVEN_LEFT) x = x + (max_width - width - border->left - border->right); } else { x = view->spacing; @@ -767,10 +788,11 @@ get_page_extents (EvView *view, GtkBorder overall_border; gint other_page; - other_page = page ^ 1; + other_page = (page % 2 == DUAL_EVEN_LEFT) ? page + 1: page - 1; /* First, we get the bounding box of the two pages */ - if (other_page < ev_page_cache_get_n_pages (view->page_cache)) { + if (other_page < ev_page_cache_get_n_pages (view->page_cache) + && (0 <= other_page)) { ev_page_cache_get_size (view->page_cache, other_page, view->rotation, @@ -788,7 +810,7 @@ get_page_extents (EvView *view, y = view->spacing; /* Adjust for being the left or right page */ - if (page % 2 == 0) + if (page % 2 == DUAL_EVEN_LEFT) x = x + max_width - width; else x = x + (max_width + overall_border.left + overall_border.right) + view->spacing; @@ -1029,13 +1051,16 @@ location_in_selected_text (EvView *view, /*** Hyperref ***/ static EvLink * -get_link_at_location (EvView *view, - gdouble x, - gdouble y) +ev_view_get_link_at_location (EvView *view, + gdouble x, + gdouble y) { gint page = -1; gint x_offset = 0, y_offset = 0; GList *link_mapping; + + x += view->scroll_x; + y += view->scroll_y; find_page_at_location (view, x, y, &page, &x_offset, &y_offset); @@ -1053,17 +1078,10 @@ get_link_at_location (EvView *view, static void goto_fitr_link (EvView *view, EvLink *link) { - GdkPoint view_point; EvPoint doc_point; - int doc_width, doc_height, page; + int page; double zoom; - page = ev_link_get_page (link); - ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height); - - doc_point.x = ev_link_get_left (link); - doc_point.y = ev_link_get_top (link); - zoom = zoom_for_size_best_fit (ev_link_get_right (link) - ev_link_get_left (link), ev_link_get_top (link) - ev_link_get_bottom (link), ev_view_get_width (view), @@ -1071,18 +1089,21 @@ goto_fitr_link (EvView *view, EvLink *link) ev_view_set_sizing_mode (view, EV_SIZING_FREE); ev_view_set_zoom (view, zoom, FALSE); - ev_page_cache_set_current_page (view->page_cache, page); - if (doc_point_to_view_point (view, page, &doc_point, &view_point)) { - gtk_adjustment_set_value (view->hadjustment, view_point.x); - gtk_adjustment_set_value (view->vadjustment, view_point.y); - } + page = ev_link_get_page (link); + doc_point.x = ev_link_get_left (link); + doc_point.y = ev_link_get_top (link); + + view->current_page = page; + view->pending_point = doc_point; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; + + gtk_widget_queue_resize (GTK_WIDGET (view)); } static void goto_fitv_link (EvView *view, EvLink *link) { - GdkPoint view_point; EvPoint doc_point; int doc_width, doc_height, page; double zoom; @@ -1099,17 +1120,17 @@ goto_fitv_link (EvView *view, EvLink *link) ev_view_set_sizing_mode (view, EV_SIZING_FREE); ev_view_set_zoom (view, zoom, FALSE); - ev_page_cache_set_current_page (view->page_cache, page); - if (doc_point_to_view_point (view, page, &doc_point, &view_point)) { - gtk_adjustment_set_value (view->hadjustment, view_point.x); - } + view->current_page = page; + view->pending_point = doc_point; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; + + gtk_widget_queue_resize (GTK_WIDGET (view)); } static void goto_fith_link (EvView *view, EvLink *link) { - GdkPoint view_point; EvPoint doc_point; int doc_width, doc_height, page; double zoom; @@ -1127,11 +1148,11 @@ goto_fith_link (EvView *view, EvLink *link) ev_view_set_sizing_mode (view, EV_SIZING_FREE); ev_view_set_zoom (view, zoom, FALSE); - if (doc_point_to_view_point (view, page, &doc_point, &view_point)) { - gtk_adjustment_set_value (view->vadjustment, view_point.y); - } else { - ev_page_cache_set_current_page (view->page_cache, page); - } + view->current_page = page; + view->pending_point = doc_point; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; + + gtk_widget_queue_resize (GTK_WIDGET (view)); } static void @@ -1149,13 +1170,16 @@ goto_fit_link (EvView *view, EvLink *link) ev_view_set_sizing_mode (view, EV_SIZING_FREE); ev_view_set_zoom (view, zoom, FALSE); - ev_page_cache_set_current_page (view->page_cache, page); + + view->current_page = page; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; + + gtk_widget_queue_resize (GTK_WIDGET (view)); } static void goto_xyz_link (EvView *view, EvLink *link) { - GdkPoint view_point; EvPoint doc_point; int height, page; double zoom; @@ -1164,20 +1188,19 @@ goto_xyz_link (EvView *view, EvLink *link) page = ev_link_get_page (link); ev_page_cache_get_size (view->page_cache, page, 0, 1.0, NULL, &height); - ev_view_set_sizing_mode (view, EV_SIZING_FREE); if (zoom != 0) { + ev_view_set_sizing_mode (view, EV_SIZING_FREE); ev_view_set_zoom (view, zoom, FALSE); } doc_point.x = ev_link_get_left (link); doc_point.y = height - ev_link_get_top (link); - if (doc_point_to_view_point (view, page, &doc_point, &view_point)) { - gtk_adjustment_set_value (view->hadjustment, view_point.x); - gtk_adjustment_set_value (view->vadjustment, view_point.y); - } else { - ev_page_cache_set_current_page (view->page_cache, page); - } + view->current_page = page; + view->pending_point = doc_point; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; + + gtk_widget_queue_resize (GTK_WIDGET (view)); } void @@ -1252,7 +1275,7 @@ handle_link_over_xy (EvView *view, gint x, gint y) { EvLink *link; - link = get_link_at_location (view, x + view->scroll_x, y + view->scroll_y); + link = ev_view_get_link_at_location (view, x, y); if (view->link_tooltip == NULL) { view->link_tooltip = ev_tooltip_new (GTK_WIDGET (view)); @@ -1487,6 +1510,7 @@ ev_view_realize (GtkWidget *widget) GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK | GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK; @@ -1609,11 +1633,25 @@ ev_view_expose_event (GtkWidget *widget, return FALSE; } +static gboolean +ev_view_popup_menu (GtkWidget *widget) +{ + gint x, y; + EvLink *link; + EvView *view = EV_VIEW (widget); + + gtk_widget_get_pointer (widget, &x, &y); + link = ev_view_get_link_at_location (view, x, y); + g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, link); + return TRUE; +} + static gboolean ev_view_button_press_event (GtkWidget *widget, GdkEventButton *event) { EvView *view = EV_VIEW (widget); + EvLink *link; if (!GTK_WIDGET_HAS_FOCUS (widget)) { gtk_widget_grab_focus (widget); @@ -1650,6 +1688,10 @@ ev_view_button_press_event (GtkWidget *widget, ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG); + return TRUE; + case 3: + link = ev_view_get_link_at_location (view, event->x, event->y); + g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, link); return TRUE; } @@ -1680,29 +1722,70 @@ ev_view_drag_data_get (GtkWidget *widget, static gboolean selection_update_idle_cb (EvView *view) { - GdkPoint point; - point.x = view->motion_x; - point.y = view->motion_y; - compute_selections (view, &view->selection_info.start, &point); - + compute_selections (view, &view->selection_info.start, &view->motion); view->selection_update_id = 0; return FALSE; } +static gboolean +selection_scroll_timeout_cb (EvView *view) +{ + gint x, y, shift = 0; + GtkWidget *widget = GTK_WIDGET (view); + + gtk_widget_get_pointer (widget, &x, &y); + + if (y > widget->allocation.height) { + shift = (y - widget->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)); + + if (x > widget->allocation.width) { + shift = (x - widget->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)); + + return TRUE; +} + static gboolean ev_view_motion_notify_event (GtkWidget *widget, GdkEventMotion *event) { EvView *view = EV_VIEW (widget); + gint x, y; if (!view->document) return FALSE; + + if (event->is_hint || event->window != widget->window) { + gtk_widget_get_pointer (widget, &x, &y); + } else { + x = event->x; + y = event->y; + } if (view->selection_info.in_drag) { if (gtk_drag_check_threshold (widget, view->selection_info.start.x, view->selection_info.start.y, - event->x, event->y)) { + x, y)) { GdkDragContext *context; GtkTargetList *target_list = gtk_target_list_new (NULL, 0); @@ -1724,16 +1807,24 @@ ev_view_motion_notify_event (GtkWidget *widget, * documents only. */ if (view->pressed_button == 1 && view->rotation == 0) { + + /* Schedule timeout to scroll during selection and additionally + * scroll once to allow arbitrary speed. */ + if (!view->selection_scroll_id) + view->selection_scroll_id = g_timeout_add (SCROLL_TIME, (GSourceFunc)selection_scroll_timeout_cb, view); + else + selection_scroll_timeout_cb (view); + view->selection_info.in_selection = TRUE; - view->motion_x = event->x + view->scroll_x; - view->motion_y = event->y + view->scroll_y; + view->motion.x = x + view->scroll_x; + view->motion.y = y + view->scroll_y; /* Queue an idle to handle the motion. We do this because * handling any selection events in the motion could be slower * than new motion events reach us. We always put it in the * idle to make sure we catch up and don't visibly lag the * mouse. */ - if (! view->selection_update_id) + if (!view->selection_update_id) view->selection_update_id = g_idle_add ((GSourceFunc)selection_update_idle_cb, view); return TRUE; @@ -1778,7 +1869,7 @@ ev_view_motion_notify_event (GtkWidget *widget, */ } else if (view->pressed_button <= 0 && view->rotation == 0) { - handle_link_over_xy (view, event->x, event->y); + handle_link_over_xy (view, x, y); return TRUE; } @@ -1797,8 +1888,7 @@ ev_view_button_release_event (GtkWidget *widget, } if (view->document) { - link = get_link_at_location (view, event->x + view->scroll_x, - event->y + view->scroll_y); + link = ev_view_get_link_at_location (view, event->x, event->y); } else { link = NULL; } @@ -1806,6 +1896,15 @@ ev_view_button_release_event (GtkWidget *widget, view->pressed_button = -1; view->drag_info.in_drag = FALSE; + if (view->selection_scroll_id) { + g_source_remove (view->selection_scroll_id); + view->selection_scroll_id = 0; + } + if (view->selection_update_id) { + g_source_remove (view->selection_update_id); + view->selection_update_id = 0; + } + if (view->selection_info.selections) { ev_view_update_primary_selection (view); @@ -2156,6 +2255,16 @@ ev_view_destroy (GtkObject *object) gtk_widget_destroy (view->link_tooltip); } + if (view->selection_scroll_id) { + g_source_remove (view->selection_scroll_id); + view->selection_scroll_id = 0; + } + + if (view->selection_update_id) { + g_source_remove (view->selection_update_id); + view->selection_update_id = 0; + } + ev_view_set_scroll_adjustments (view, NULL, NULL); GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object); @@ -2301,6 +2410,7 @@ ev_view_class_init (EvViewClass *class) widget_class->leave_notify_event = ev_view_leave_notify_event; widget_class->style_set = ev_view_style_set; widget_class->drag_data_get = ev_view_drag_data_get; + widget_class->popup_menu = ev_view_popup_menu; gtk_object_class->destroy = ev_view_destroy; class->set_scroll_adjustments = ev_view_set_scroll_adjustments; @@ -2342,6 +2452,14 @@ ev_view_class_init (EvViewClass *class) g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); + signals[SIGNAL_POPUP_MENU] = g_signal_new ("popup", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvViewClass, popup_menu), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); g_object_class_install_property (object_class, PROP_STATUS, @@ -2483,7 +2601,7 @@ page_changed_cb (EvPageCache *page_cache, if (view->current_page != new_page) { view->current_page = new_page; - view->pending_scroll = SCROLL_TO_CURRENT_PAGE; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; gtk_widget_queue_resize (GTK_WIDGET (view)); if (EV_IS_DOCUMENT_FIND (view->document)) { @@ -2649,7 +2767,7 @@ ev_view_set_continuous (EvView *view, if (view->continuous != continuous) { view->continuous = continuous; - view->pending_scroll = SCROLL_TO_CURRENT_PAGE; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; gtk_widget_queue_resize (GTK_WIDGET (view)); } @@ -2675,7 +2793,7 @@ ev_view_set_dual_page (EvView *view, if (view->dual_page == dual_page) return; - view->pending_scroll = SCROLL_TO_CURRENT_PAGE; + 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. @@ -2722,7 +2840,7 @@ ev_view_set_presentation (EvView *view, return; view->presentation = presentation; - view->pending_scroll = SCROLL_TO_CURRENT_PAGE; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; gtk_widget_queue_resize (GTK_WIDGET (view)); if (GTK_WIDGET_REALIZED (view)) { @@ -3827,6 +3945,9 @@ ev_view_next_page (EvView *view) if (page < ev_page_cache_get_n_pages (view->page_cache)) { ev_page_cache_set_current_page (view->page_cache, page); return TRUE; + } else if (ev_view_get_dual_page (view) && page == ev_page_cache_get_n_pages (view->page_cache)) { + ev_page_cache_set_current_page (view->page_cache, page - 1); + return TRUE; } else { return FALSE; } @@ -3845,7 +3966,10 @@ ev_view_previous_page (EvView *view) if (page >= 0) { ev_page_cache_set_current_page (view->page_cache, page); return TRUE; - } else { + } else if (ev_view_get_dual_page (view) && page == -1) { + ev_page_cache_set_current_page (view->page_cache, 0); + return TRUE; + } else { return FALSE; } }