X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=shell%2Fev-view.c;h=d8a802498de1529a4c8f79733d9f9dbc97a06b1e;hb=a61c4406e2cd4dc8f2d3a981e73dc09ae21e6ece;hp=c5cc5038a7e1018e2126536241960ebfa21a0cf7;hpb=b66c8a73177b462aebcb6e495341807abb31a93f;p=evince.git diff --git a/shell/ev-view.c b/shell/ev-view.c index c5cc5038..d8a80249 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -29,6 +30,7 @@ #include "ev-marshal.h" #include "ev-view.h" +#include "ev-view-private.h" #include "ev-utils.h" #include "ev-selection.h" #include "ev-document-find.h" @@ -55,11 +57,14 @@ enum { PROP_SIZING_MODE, PROP_ZOOM, PROP_ROTATION, + PROP_HAS_SELECTION, }; enum { SIGNAL_BINDING_ACTIVATED, SIGNAL_ZOOM_INVALID, + SIGNAL_EXTERNAL_LINK, + SIGNAL_POPUP_MENU, N_SIGNALS, }; @@ -80,15 +85,6 @@ static const GtkTargetEntry targets[] = { static guint signals[N_SIGNALS]; -typedef enum { - EV_VIEW_CURSOR_NORMAL, - EV_VIEW_CURSOR_IBEAM, - EV_VIEW_CURSOR_LINK, - EV_VIEW_CURSOR_WAIT, - EV_VIEW_CURSOR_HIDDEN, - EV_VIEW_CURSOR_DRAG -} EvViewCursor; - typedef enum { EV_VIEW_FIND_NEXT, EV_VIEW_FIND_PREV @@ -100,95 +96,7 @@ typedef enum { #define MIN_SCALE 0.05409 #define MAX_SCALE 4.0 -/* Information for middle clicking and moving around the doc */ -typedef struct { - gboolean in_drag; - GdkPoint start; - gdouble hadj; - gdouble vadj; -} DragInfo; - -/* Information for handling selection */ -typedef struct { - gboolean in_selection; - GdkPoint start; - GList *selections; -} SelectionInfo; - -typedef enum { - SCROLL_TO_KEEP_POSITION, - SCROLL_TO_CURRENT_PAGE, - SCROLL_TO_CENTER -} PendingScroll; - -struct _EvView { - GtkWidget parent_instance; - - EvDocument *document; - - char *status; - char *find_status; - - /* Scrolling */ - GtkAdjustment *hadjustment; - GtkAdjustment *vadjustment; - - gint scroll_x; - gint scroll_y; - - /* Information for middle clicking and dragging around. */ - DragInfo drag_info; - - /* Selection */ - gint motion_x; - gint motion_y; - guint selection_update_id; - - EvViewSelectionMode selection_mode; - SelectionInfo selection_info; - - int pressed_button; - EvViewCursor cursor; - GtkWidget *link_tooltip; - EvLink *hovered_link; - - EvPageCache *page_cache; - EvPixbufCache *pixbuf_cache; - - gint start_page; - gint end_page; - gint current_page; - - EvJobRender *current_job; - - int find_page; - int find_result; - int spacing; - - int rotation; - double scale; - - gboolean continuous; - gboolean dual_page; - gboolean fullscreen; - gboolean presentation; - EvSizingMode sizing_mode; - - PendingScroll pending_scroll; - gboolean pending_resize; -}; - -struct _EvViewClass { - GtkWidgetClass parent_class; - - void (*set_scroll_adjustments) (EvView *view, - GtkAdjustment *hadjustment, - GtkAdjustment *vadjustment); - void (*binding_activated) (EvView *view, - GtkScrollType scroll, - gboolean horizontal); - void (*zoom_invalid) (EvView *view); -}; +#define SCROLL_TIME 150 /*** Scrolling ***/ static void scroll_to_current_page (EvView *view, @@ -205,10 +113,8 @@ static void ev_view_set_scroll_adjustments (EvView GtkAdjustment *vadjustment); static void add_scroll_binding_keypad (GtkBindingSet *binding_set, guint keyval, - GtkScrollType scroll, - gboolean horizontal); -static void ev_view_binding_activated (EvView *view, - GtkScrollType scroll, + GdkModifierType modifiers, + EvScrollType scroll, gboolean horizontal); static void ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect); @@ -240,11 +146,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, @@ -268,6 +177,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, @@ -281,6 +191,8 @@ static gboolean ev_view_leave_notify_event (GtkWidget static void ev_view_style_set (GtkWidget *widget, GtkStyle *old_style); +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, @@ -294,6 +206,9 @@ static void draw_one_page (EvView GdkRectangle *page_area, GtkBorder *border, GdkRectangle *expose_area); +static void draw_loading_text (EvView *view, + GdkRectangle *page_area, + GdkRectangle *expose_area); /*** Callbacks ***/ static void find_changed_cb (EvDocument *document, @@ -369,13 +284,15 @@ static void ev_view_set_cursor (EvView /*** Status messages ***/ static void ev_view_set_status (EvView *view, const char *message); -static void update_find_status_message (EvView *view); +static void update_find_status_message (EvView *view, + gboolean this_page); static void ev_view_set_find_status (EvView *view, const char *message); /*** Find ***/ static void jump_to_find_result (EvView *view); static void jump_to_find_page (EvView *view, - EvViewFindDirection direction); + EvViewFindDirection direction, + gint shift); /*** Selection ***/ static void compute_selections (EvView *view, @@ -398,32 +315,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)); @@ -461,7 +386,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; @@ -482,7 +407,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: @@ -498,6 +423,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; @@ -508,7 +435,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; @@ -536,28 +462,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 == ev_page_cache_get_dual_even_left (view->page_cache)) { 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) + 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, @@ -613,32 +544,50 @@ ev_view_set_scroll_adjustments (EvView *view, static void add_scroll_binding_keypad (GtkBindingSet *binding_set, guint keyval, - GtkScrollType scroll, + GdkModifierType modifiers, + EvScrollType scroll, gboolean horizontal) { guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left; - gtk_binding_entry_add_signal (binding_set, keyval, 0, + gtk_binding_entry_add_signal (binding_set, keyval, modifiers, "binding_activated", 2, - GTK_TYPE_SCROLL_TYPE, scroll, + EV_TYPE_SCROLL_TYPE, scroll, G_TYPE_BOOLEAN, horizontal); - gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0, + gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers, "binding_activated", 2, - GTK_TYPE_SCROLL_TYPE, scroll, + EV_TYPE_SCROLL_TYPE, scroll, G_TYPE_BOOLEAN, horizontal); } void ev_view_scroll (EvView *view, - EvScrollType scroll) + EvScrollType scroll, + gboolean horizontal) { GtkAdjustment *adjustment; double value, increment; gboolean first_page = FALSE; gboolean last_page = FALSE; + view->jump_to_find_result = FALSE; + + if (view->presentation) { + switch (scroll) { + case EV_SCROLL_STEP_BACKWARD: + ev_view_previous_page (view); + break; + case EV_SCROLL_STEP_FORWARD: + ev_view_next_page (view); + break; + default: + break; + } + return; + } + /* Assign values for increment and vertical adjustment */ - adjustment = view->vadjustment; + adjustment = horizontal ? view->hadjustment : view->vadjustment; increment = adjustment->page_size * 0.75; value = adjustment->value; @@ -656,7 +605,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); @@ -669,64 +618,33 @@ 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); } break; - default: - break; - } - - gtk_adjustment_set_value (adjustment, value); -} - -static void -ev_view_binding_activated (EvView *view, - GtkScrollType scroll, - gboolean horizontal) -{ - GtkAdjustment *adjustment; - double value; - - if (view->presentation) { - switch (scroll) { - case GTK_SCROLL_STEP_BACKWARD: - ev_view_previous_page (view); - break; - case GTK_SCROLL_STEP_FORWARD: - ev_view_next_page (view); - break; - default: - break; - } - return; - } - - if (horizontal) { - adjustment = view->hadjustment; - } else { - adjustment = view->vadjustment; - } - - value = adjustment->value; - - switch (scroll) { - case GTK_SCROLL_STEP_BACKWARD: + case EV_SCROLL_STEP_BACKWARD: value -= adjustment->step_increment; break; - case GTK_SCROLL_STEP_FORWARD: + case EV_SCROLL_STEP_FORWARD: value += adjustment->step_increment; break; - default: + case EV_SCROLL_STEP_DOWN: + value -= adjustment->step_increment / 10; + break; + case EV_SCROLL_STEP_UP: + value += adjustment->step_increment / 10; + break; + default: break; } value = CLAMP (value, adjustment->lower, - adjustment->upper - adjustment->page_size); + adjustment->upper - adjustment->page_size); gtk_adjustment_set_value (adjustment, value); + } #define MARGIN 5 @@ -795,7 +713,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 + ev_page_cache_get_dual_even_left (view->page_cache)) / 2 + 1) * view->spacing + ((page + ev_page_cache_get_dual_even_left (view->page_cache)) / 2 ) * (border.top + border.bottom); } else { ev_page_cache_get_height_to_page (view->page_cache, page, view->rotation, zoom, &offset, NULL); @@ -838,9 +756,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 == ev_page_cache_get_dual_even_left (view->page_cache)) ? 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 == ev_page_cache_get_dual_even_left (view->page_cache)) x = x + (max_width - width - border->left - border->right); } else { x = view->spacing; @@ -860,10 +778,11 @@ get_page_extents (EvView *view, GtkBorder overall_border; gint other_page; - other_page = page ^ 1; + other_page = (page % 2 == ev_page_cache_get_dual_even_left (view->page_cache)) ? 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, @@ -881,7 +800,7 @@ get_page_extents (EvView *view, y = view->spacing; /* Adjust for being the left or right page */ - if (page % 2 == 0) + if (page % 2 == ev_page_cache_get_dual_even_left (view->page_cache)) x = x + max_width - width; else x = x + (max_width + overall_border.left + overall_border.right) + view->spacing; @@ -931,7 +850,7 @@ view_rect_to_doc_rect (EvView *view, doc_rect->y2 = doc_rect->y1 + (double) view_rect->height / view->scale; } -static void +static gboolean doc_point_to_view_point (EvView *view, int page, EvPoint *doc_point, @@ -939,7 +858,7 @@ doc_point_to_view_point (EvView *view, { GdkRectangle page_area; GtkBorder border; - double x, y; + double x, y, view_x, view_y; int width, height; ev_page_cache_get_size (view->page_cache, page, @@ -965,8 +884,13 @@ doc_point_to_view_point (EvView *view, get_page_extents (view, page, &page_area, &border); - view_point->x = x * view->scale + page_area.x; - view_point->y = y * view->scale + page_area.y; + view_x = x * view->scale; + view_y = y * view->scale; + 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 @@ -1089,15 +1013,44 @@ ev_view_get_height (EvView *view) return GTK_WIDGET (view)->allocation.height; } +static gboolean +location_in_selected_text (EvView *view, + gdouble x, + gdouble y) +{ + gint page = -1; + gint x_offset = 0, y_offset = 0; + EvViewSelection *selection; + GList *l = NULL; + + for (l = view->selection_info.selections; l != NULL; l = l->next) { + selection = (EvViewSelection *)l->data; + + find_page_at_location (view, x, y, &page, &x_offset, &y_offset); + + if (page != selection->page) + continue; + + if (selection->covered_region && + gdk_region_point_in (selection->covered_region, x_offset, y_offset)) + return TRUE; + } + + return FALSE; +} + /*** 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); @@ -1115,18 +1068,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); - doc_point_to_view_point (view, page, &doc_point, &view_point); - 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), @@ -1134,14 +1079,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); - gtk_adjustment_set_value (view->hadjustment, view_point.x); + + 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; @@ -1151,7 +1103,6 @@ goto_fitv_link (EvView *view, EvLink *link) doc_point.x = ev_link_get_left (link); doc_point.y = 0; - doc_point_to_view_point (view, page, &doc_point, &view_point); zoom = zoom_for_size_fit_height (doc_width - doc_point.x , doc_height, ev_view_get_width (view), @@ -1159,14 +1110,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); - 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; @@ -1176,7 +1130,6 @@ goto_fith_link (EvView *view, EvLink *link) doc_point.x = 0; doc_point.y = doc_height - ev_link_get_top (link); - doc_point_to_view_point (view, page, &doc_point, &view_point); zoom = zoom_for_size_fit_width (doc_width, ev_link_get_top (link), ev_view_get_width (view), @@ -1184,7 +1137,12 @@ goto_fith_link (EvView *view, EvLink *link) ev_view_set_sizing_mode (view, EV_SIZING_FREE); ev_view_set_zoom (view, zoom, FALSE); - gtk_adjustment_set_value (view->vadjustment, view_point.y); + + 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 @@ -1202,13 +1160,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; @@ -1217,24 +1178,25 @@ 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); - 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); + view->current_page = page; + view->pending_point = doc_point; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; + + gtk_widget_queue_resize (GTK_WIDGET (view)); } void ev_view_goto_link (EvView *view, EvLink *link) { EvLinkType type; - const char *uri; int page; type = ev_link_get_link_type (link); @@ -1262,8 +1224,8 @@ ev_view_goto_link (EvView *view, EvLink *link) goto_xyz_link (view, link); break; case EV_LINK_TYPE_EXTERNAL_URI: - uri = ev_link_get_uri (link); - gnome_vfs_url_show (uri); + case EV_LINK_TYPE_LAUNCH: + g_signal_emit (view, signals[SIGNAL_EXTERNAL_LINK], 0, link); break; } } @@ -1303,7 +1265,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)); @@ -1317,9 +1279,13 @@ handle_link_over_xy (EvView *view, gint x, gint y) if (link) { char *msg = tip_from_link (view, link); - ev_tooltip_set_position (EV_TOOLTIP (view->link_tooltip), x, y); - ev_tooltip_set_text (EV_TOOLTIP (view->link_tooltip), msg); - ev_tooltip_activate (EV_TOOLTIP (view->link_tooltip)); + if (msg && g_utf8_validate (msg, -1, NULL)) { + EvTooltip *tooltip = EV_TOOLTIP (view->link_tooltip); + + ev_tooltip_set_position (tooltip, x, y); + ev_tooltip_set_text (tooltip, msg); + ev_tooltip_activate (tooltip); + } g_free (msg); ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); @@ -1534,6 +1500,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; @@ -1576,6 +1543,7 @@ ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event) return TRUE; } + view->jump_to_find_result = FALSE; /* Shift+Wheel scrolls the in the perpendicular direction */ if (state & GDK_SHIFT_MASK) { if (event->direction == GDK_SCROLL_UP) @@ -1634,6 +1602,12 @@ ev_view_expose_event (GtkWidget *widget, EvView *view = EV_VIEW (widget); int i; + if (view->loading) { + draw_loading_text (view, + &(widget->allocation), + &(event->area)); + } + if (view->document == NULL) return FALSE; @@ -1656,27 +1630,50 @@ 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); } - + view->pressed_button = event->button; - + view->selection_info.in_drag = FALSE; + switch (event->button) { - case 1: + case 1: if (view->selection_info.selections) { - clear_selection (view); + if (location_in_selected_text (view, + event->x + view->scroll_x, + event->y + view->scroll_y)) { + view->selection_info.in_drag = TRUE; + } else { + clear_selection (view); + } + gtk_widget_queue_draw (widget); } view->selection_info.start.x = event->x + view->scroll_x; view->selection_info.start.y = event->y + view->scroll_y; + return TRUE; case 2: /* use root coordinates as reference point because @@ -1688,49 +1685,143 @@ 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; } - + return FALSE; } +static void +ev_view_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + EvView *view = EV_VIEW (widget); + + if (view->selection_info.selections && + ev_document_can_get_text (view->document)) { + gchar *text; + + text = get_selected_text (view); + + gtk_selection_data_set_text (selection_data, text, strlen (text)); + + g_free (text); + } +} 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, + x, y)) { + GdkDragContext *context; + GtkTargetList *target_list = gtk_target_list_new (NULL, 0); + + gtk_target_list_add_text_targets (target_list, 0); + context = gtk_drag_begin (widget, target_list, + GDK_ACTION_COPY, + 1, (GdkEvent *)event); + + view->selection_info.in_drag = FALSE; + + gtk_target_list_unref (target_list); + + return TRUE; + } + } + /* For the Evince 0.4.x release, we limit selection to un-rotated * documents only. */ - if (view->pressed_button == 1 && - view->rotation == 0) { + 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 + /* 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; @@ -1775,7 +1866,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; } @@ -1794,8 +1885,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; } @@ -1803,8 +1893,24 @@ 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); + + if (view->selection_info.in_drag) { + clear_selection (view); + gtk_widget_queue_draw (widget); + } + + view->selection_info.in_drag = FALSE; } else if (link) { ev_view_goto_link (view, link); } else if (view->presentation) { @@ -1882,7 +1988,6 @@ ev_view_style_set (GtkWidget *widget, GTK_WIDGET_CLASS (ev_view_parent_class)->style_set (widget, old_style); } - /*** Drawing ***/ static guint32 @@ -1949,7 +2054,7 @@ highlight_find_results (EvView *view, int page) GdkRectangle view_rectangle; guchar alpha; - if (i == view->find_result && page == view->find_page) { + if (i == view->find_result && page == view->current_page) { alpha = 0x90; } else { alpha = 0x20; @@ -2019,11 +2124,14 @@ draw_one_page (EvView *view, GdkRectangle overlap; GdkRectangle real_page_area; EvViewSelection *selection; + gint current_page; g_assert (view->document); + if (! gdk_rectangle_intersect (page_area, expose_area, &overlap)) return; - + + current_page = ev_page_cache_get_current_page (view->page_cache); selection = find_selection_for_page (view, page); ev_page_cache_get_size (view->page_cache, page, view->rotation, @@ -2039,7 +2147,8 @@ draw_one_page (EvView *view, ev_document_misc_paint_one_page (GTK_WIDGET(view)->window, GTK_WIDGET (view), - page_area, border); + page_area, border, + page == current_page); if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) { GdkPixbuf *selection_pixbuf = NULL; @@ -2147,6 +2256,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); @@ -2188,6 +2307,37 @@ ev_view_set_property (GObject *object, } } +static AtkObject * +ev_view_get_accessible (GtkWidget *widget) +{ + static gboolean first_time = TRUE; + + if (first_time) { + AtkObjectFactory *factory; + AtkRegistry *registry; + GType derived_type; + GType derived_atk_type; + + /* + * Figure out whether accessibility is enabled by looking at the + * type of the accessible object which would be created for + * the parent type of EvView. + */ + derived_type = g_type_parent (EV_TYPE_VIEW); + + registry = atk_get_default_registry (); + 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, + EV_TYPE_VIEW, + ev_view_accessible_factory_get_type ()); + first_time = FALSE; + } + return GTK_WIDGET_CLASS (ev_view_parent_class)->get_accessible (widget); +} + static void ev_view_get_property (GObject *object, guint prop_id, @@ -2225,6 +2375,10 @@ ev_view_get_property (GObject *object, case PROP_ROTATION: g_value_set_int (value, view->rotation); break; + case PROP_HAS_SELECTION: + g_value_set_boolean (value, + view->selection_info.selections != NULL); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -2248,6 +2402,7 @@ ev_view_class_init (EvViewClass *class) widget_class->button_release_event = ev_view_button_release_event; 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->size_allocate = ev_view_size_allocate; widget_class->realize = ev_view_realize; @@ -2255,10 +2410,12 @@ ev_view_class_init (EvViewClass *class) 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->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; - class->binding_activated = ev_view_binding_activated; + class->binding_activated = ev_view_scroll; widget_class->set_scroll_adjustments_signal = g_signal_new ("set-scroll-adjustments", @@ -2288,6 +2445,22 @@ ev_view_class_init (EvViewClass *class) NULL, NULL, ev_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + signals[SIGNAL_EXTERNAL_LINK] = g_signal_new ("external-link", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvViewClass, external_link), + NULL, NULL, + 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, @@ -2362,13 +2535,24 @@ ev_view_class_init (EvViewClass *class) 360, 0, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_HAS_SELECTION, + g_param_spec_boolean ("has-selection", + "Has selection", + "The view has selections", + FALSE, + G_PARAM_READABLE)); binding_set = gtk_binding_set_by_class (class); - add_scroll_binding_keypad (binding_set, GDK_Left, GTK_SCROLL_STEP_BACKWARD, TRUE); - 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_Left, 0, EV_SCROLL_STEP_BACKWARD, TRUE); + add_scroll_binding_keypad (binding_set, GDK_Right, 0, EV_SCROLL_STEP_FORWARD, TRUE); + add_scroll_binding_keypad (binding_set, GDK_Left, GDK_MOD1_MASK, EV_SCROLL_STEP_DOWN, TRUE); + add_scroll_binding_keypad (binding_set, GDK_Right, GDK_MOD1_MASK, EV_SCROLL_STEP_UP, TRUE); + add_scroll_binding_keypad (binding_set, GDK_Up, 0, EV_SCROLL_STEP_BACKWARD, FALSE); + add_scroll_binding_keypad (binding_set, GDK_Down, 0, EV_SCROLL_STEP_FORWARD, FALSE); + add_scroll_binding_keypad (binding_set, GDK_Up, GDK_MOD1_MASK, EV_SCROLL_STEP_DOWN, FALSE); + add_scroll_binding_keypad (binding_set, GDK_Down, GDK_MOD1_MASK, EV_SCROLL_STEP_UP, FALSE); } static void @@ -2382,7 +2566,9 @@ ev_view_init (EvView *view) view->pressed_button = -1; view->cursor = EV_VIEW_CURSOR_NORMAL; view->drag_info.in_drag = FALSE; + view->selection_info.selections = NULL; view->selection_info.in_selection = FALSE; + view->selection_info.in_drag = FALSE; view->selection_mode = EV_VIEW_SELECTION_TEXT; view->continuous = TRUE; view->dual_page = FALSE; @@ -2390,6 +2576,7 @@ ev_view_init (EvView *view) view->fullscreen = FALSE; view->sizing_mode = EV_SIZING_FIT_WIDTH; view->pending_scroll = SCROLL_TO_KEEP_POSITION; + view->jump_to_find_result = TRUE; } /*** Callbacks ***/ @@ -2397,10 +2584,18 @@ ev_view_init (EvView *view) static void find_changed_cb (EvDocument *document, int page, EvView *view) { - jump_to_find_page (view, EV_VIEW_FIND_NEXT); - jump_to_find_result (view); - update_find_status_message (view); + double percent; + int n_pages; + percent = ev_document_find_get_progress + (EV_DOCUMENT_FIND (view->document)); + n_pages = ev_page_cache_get_n_pages (view->page_cache); + + if (view->jump_to_find_result == TRUE) { + jump_to_find_page (view, EV_VIEW_FIND_NEXT, 0); + jump_to_find_result (view); + } + update_find_status_message (view, percent * n_pages >= n_pages - 1 ); if (view->current_page == page) gtk_widget_queue_draw (GTK_WIDGET (view)); } @@ -2418,16 +2613,16 @@ page_changed_cb (EvPageCache *page_cache, EvView *view) { 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)); + } else { + gtk_widget_queue_draw (GTK_WIDGET (view)); + } - if (EV_IS_DOCUMENT_FIND (view->document)) { - view->find_page = new_page; - view->find_result = 0; - update_find_status_message (view); - } + if (EV_IS_DOCUMENT_FIND (view->document)) { + view->find_result = 0; + update_find_status_message (view, TRUE); } } @@ -2496,12 +2691,22 @@ clear_caches (EvView *view) } } +void +ev_view_set_loading (EvView *view, + gboolean loading) +{ + view->loading = loading; + gtk_widget_queue_draw (GTK_WIDGET (view)); +} + void ev_view_set_document (EvView *view, EvDocument *document) { g_return_if_fail (EV_IS_VIEW (view)); + view->loading = FALSE; + if (document != view->document) { clear_caches (view); @@ -2515,7 +2720,6 @@ ev_view_set_document (EvView *view, } view->document = document; - view->find_page = 0; view->find_result = 0; if (view->document) { @@ -2586,7 +2790,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)); } @@ -2612,7 +2816,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. @@ -2659,7 +2863,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)) { @@ -3064,11 +3268,11 @@ ev_view_set_status (EvView *view, const char *message) } static void -update_find_status_message (EvView *view) +update_find_status_message (EvView *view, gboolean this_page) { char *message; - if (view->current_page == view->find_page) { + if (this_page) { int results; results = ev_document_find_get_n_results @@ -3086,13 +3290,9 @@ update_find_status_message (EvView *view) percent = ev_document_find_get_progress (EV_DOCUMENT_FIND (view->document)); - if (percent >= (1.0 - 1e-10)) { - message = g_strdup (_("Not found")); - } else { - message = g_strdup_printf (_("%3d%% remaining to search"), - (int) ((1.0 - percent) * 100)); - } - + message = g_strdup_printf (_("%3d%% remaining to search"), + (int) ((1.0 - percent) * 100)); + } ev_view_set_find_status (view, message); g_free (message); @@ -3125,7 +3325,7 @@ jump_to_find_result (EvView *view) EvRectangle rect; GdkRectangle view_rect; int n_results; - int page = view->find_page; + int page = view->current_page; n_results = ev_document_find_get_n_results (find, page); @@ -3138,8 +3338,18 @@ jump_to_find_result (EvView *view) } } +/** + * jump_to_find_page + * @view: #EvView instance + * @direction: Direction to look + * @shift: Shift from current page + * + * Jumps to the first page that has occurences of searched word. + * Uses a direction where to look and a shift from current page. + * + */ static void -jump_to_find_page (EvView *view, EvViewFindDirection direction) +jump_to_find_page (EvView *view, EvViewFindDirection direction, gint shift) { int n_pages, i; @@ -3150,11 +3360,11 @@ jump_to_find_page (EvView *view, EvViewFindDirection direction) int page; if (direction == EV_VIEW_FIND_NEXT) - page = view->find_page + i; + page = view->current_page + i; else - page = view->find_page - i; - - + page = view->current_page - i; + page += shift; + if (page >= n_pages) { page = page - n_pages; } @@ -3164,7 +3374,6 @@ jump_to_find_page (EvView *view, EvViewFindDirection direction) has_results = ev_document_find_page_has_results (EV_DOCUMENT_FIND (view->document), page); if (has_results == -1) { - view->find_page = page; break; } else if (has_results == 1) { ev_page_cache_set_current_page (view->page_cache, page); @@ -3206,12 +3415,7 @@ ev_view_find_next (EvView *view) if (view->find_result >= n_results) { view->find_result = 0; - view->find_page++; - if (view->find_page >= n_pages) { - view->find_page = 0; - } - - jump_to_find_page (view, EV_VIEW_FIND_NEXT); + jump_to_find_page (view, EV_VIEW_FIND_NEXT, 1); jump_to_find_result (view); } else { jump_to_find_result (view); @@ -3236,12 +3440,7 @@ ev_view_find_previous (EvView *view) if (view->find_result < 0) { - view->find_page--; - if (view->find_page < 0) { - view->find_page = n_pages - 1; - } - - jump_to_find_page (view, EV_VIEW_FIND_PREV); + jump_to_find_page (view, EV_VIEW_FIND_PREV, -1); view->find_result = ev_document_find_get_n_results (find, view->current_page) - 1; jump_to_find_result (view); } else { @@ -3250,6 +3449,12 @@ ev_view_find_previous (EvView *view) } } +void ev_view_search_changed (EvView *view) +{ + /* search string has changed, focus on new search result */ + view->jump_to_find_result = TRUE; +} + /*** Selections ***/ /* compute_new_selection_rect/text calculates the area currently selected by @@ -3414,6 +3619,7 @@ merge_selection_region (EvView *view, g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL); view->selection_info.selections = new_list; ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, new_list); + g_object_notify (G_OBJECT (view), "has-selection"); new_list_ptr = new_list; old_list_ptr = old_list; @@ -3544,6 +3750,7 @@ clear_selection (EvView *view) g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL); view->selection_info.selections = NULL; view->selection_info.in_selection = FALSE; + g_object_notify (G_OBJECT (view), "has-selection"); } @@ -3578,9 +3785,16 @@ ev_view_select_all (EvView *view) } ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, view->selection_info.selections); + g_object_notify (G_OBJECT (view), "has-selection"); gtk_widget_queue_draw (GTK_WIDGET (view)); } +gboolean +ev_view_get_has_selection (EvView *view) +{ + return view->selection_info.selections != NULL; +} + static char * get_selected_text (EvView *ev_view) { @@ -3750,11 +3964,18 @@ ev_view_next_page (EvView *view) g_return_val_if_fail (EV_IS_VIEW (view), FALSE); page = ev_page_cache_get_current_page (view->page_cache); - page = ev_view_get_dual_page (view) ? page + 2 : page + 1; + + if (view->dual_page && !view->presentation) + page = page + 2; + else + page = page + 1; 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; } @@ -3768,12 +3989,19 @@ ev_view_previous_page (EvView *view) g_return_val_if_fail (EV_IS_VIEW (view), FALSE); page = ev_page_cache_get_current_page (view->page_cache); - page = ev_view_get_dual_page (view) ? page - 2 : page - 1; + + if (view->dual_page && !view->presentation) + page = page - 2; + else + page = page - 1; 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; } } @@ -3795,3 +4023,22 @@ ev_sizing_mode_get_type (void) } return etype; } + +GType +ev_scroll_type_get_type (void) +{ + static GType etype = 0; + if (etype == 0) { + static const GEnumValue values[] = { + { EV_SCROLL_PAGE_FORWARD, "EV_SCROLL_PAGE_FORWARD", "scroll-page-forward" }, + { EV_SCROLL_PAGE_BACKWARD, "EV_SCROLL_PAGE_BACKWARD", "scroll-page-backward" }, + { EV_SCROLL_STEP_FORWARD, "EV_SCROLL_STEP_FORWARD", "scroll-step-forward" }, + { EV_SCROLL_STEP_FORWARD, "EV_SCROLL_STEP_FORWARD", "scroll-step-forward" }, + { EV_SCROLL_STEP_UP, "EV_SCROLL_STEP_UP", "scroll-step-up" }, + { EV_SCROLL_STEP_DOWN, "EV_SCROLL_STEP_DOWN", "scroll-step-down" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static ("EvScrollType", values); + } + return etype; +}