X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;ds=inline;f=shell%2Fev-view.c;h=ed55a110b78c8a8dd6c6ceee11dee081b5a094b9;hb=595d902c5518765e086e8a911124ef36ed9300b7;hp=468a8946acd72e84f6efe5429320872f80e90691;hpb=6426ce3672bf190ab39d9c49c841232c127d174f;p=evince.git diff --git a/shell/ev-view.c b/shell/ev-view.c index 468a8946..ed55a110 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -32,7 +32,6 @@ #include "ev-view.h" #include "ev-view-private.h" #include "ev-utils.h" -#include "ev-selection.h" #include "ev-document-links.h" #include "ev-document-images.h" #include "ev-document-find.h" @@ -42,7 +41,9 @@ #include "ev-job-queue.h" #include "ev-page-cache.h" #include "ev-pixbuf-cache.h" +#if !GTK_CHECK_VERSION (2, 11, 7) #include "ev-tooltip.h" +#endif #include "ev-application.h" #define EV_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass)) @@ -52,7 +53,6 @@ enum { PROP_0, - PROP_STATUS, PROP_FIND_STATUS, PROP_CONTINUOUS, PROP_DUAL_PAGE, @@ -218,6 +218,7 @@ static void highlight_find_results (EvView int page); static void draw_one_page (EvView *view, gint page, + cairo_t *cr, GdkRectangle *page_area, GtkBorder *border, GdkRectangle *expose_area, @@ -231,6 +232,7 @@ static void find_changed_cb (EvDocument int page, EvView *view); static void job_finished_cb (EvPixbufCache *pixbuf_cache, + GdkRegion *region, EvView *view); static void page_changed_cb (EvPageCache *page_cache, int new_page, @@ -300,14 +302,11 @@ static void ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y); -/*** Status messages ***/ -static void ev_view_set_status (EvView *view, - const char *message); +/*** Find ***/ 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, @@ -315,6 +314,7 @@ static void jump_to_find_page (EvView /*** Selection ***/ static void compute_selections (EvView *view, + EvSelectionStyle style, GdkPoint *start, GdkPoint *stop); static void clear_selection (EvView *view); @@ -489,7 +489,7 @@ view_update_range_and_current_page (EvView *view) } view->end_page = i; - } else if (found) { + } else if (found && view->current_page <= view->end_page) { break; } } @@ -1457,8 +1457,10 @@ tip_from_link (EvView *view, EvLink *link) case EV_LINK_ACTION_TYPE_GOTO_DEST: page_label = ev_view_page_label_from_dest (view, ev_link_action_get_dest (action)); - msg = g_strdup_printf (_("Go to page %s"), page_label); - g_free (page_label); + if (page_label) { + msg = g_strdup_printf (_("Go to page %s"), page_label); + g_free (page_label); + } break; case EV_LINK_ACTION_TYPE_GOTO_REMOTE: if (title) { @@ -1468,7 +1470,6 @@ tip_from_link (EvView *view, EvLink *link) msg = g_strdup_printf (_("Go to file “%s”"), ev_link_action_get_filename (action)); } - break; case EV_LINK_ACTION_TYPE_EXTERNAL_URI: msg = g_strdup (ev_link_action_get_uri (action)); @@ -1492,10 +1493,21 @@ tip_from_link (EvView *view, EvLink *link) static void ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) { - EvLink *link; + EvLink *link; + EvFormField *field; - link = ev_view_get_link_at_location (view, x, y); + if (view->cursor == EV_VIEW_CURSOR_HIDDEN) + return; + if (view->drag_info.in_drag) { + if (view->cursor != EV_VIEW_CURSOR_DRAG) + ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG); + return; + } + + link = ev_view_get_link_at_location (view, x, y); + +#if !GTK_CHECK_VERSION (2, 11, 7) if (view->link_tooltip == NULL) { view->link_tooltip = ev_tooltip_new (GTK_WIDGET (view)); } @@ -1504,8 +1516,12 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) view->hovered_link = link; ev_tooltip_deactivate (EV_TOOLTIP (view->link_tooltip)); } +#endif if (link) { +#if GTK_CHECK_VERSION (2, 11, 7) + g_object_set (view, "has-tooltip", TRUE, NULL); +#else char *msg = tip_from_link (view, link); if (msg && g_utf8_validate (msg, -1, NULL)) { @@ -1516,14 +1532,21 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) ev_tooltip_activate (tooltip); } g_free (msg); - +#endif ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); + } else if ((field = ev_view_get_form_field_at_location (view, x, y))) { + if (field->is_read_only) { + if (view->cursor == EV_VIEW_CURSOR_LINK || + view->cursor == EV_VIEW_CURSOR_IBEAM) + ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL); + } else if (EV_IS_FORM_FIELD_TEXT (field)) { + ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM); + } else { + ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); + } } else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) { ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM); - } else if (ev_view_get_form_field_at_location (view, x, y)) { - ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); } else { - ev_view_set_status (view, NULL); if (view->cursor == EV_VIEW_CURSOR_LINK || view->cursor == EV_VIEW_CURSOR_IBEAM) ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL); @@ -1598,6 +1621,24 @@ ev_view_get_form_field_at_location (EvView *view, return NULL; } +static GdkRegion * +ev_view_form_field_get_region (EvView *view, + EvFormField *field) +{ + EvRectangle field_area; + GdkRectangle view_area; + GList *forms_mapping; + + forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, + field->page); + ev_form_field_mapping_get_area (forms_mapping, field, &field_area); + doc_rect_to_view_rect (view, field->page, &field_area, &view_area); + view_area.x -= view->scroll_x; + view_area.y -= view->scroll_y; + + return gdk_region_rectangle (&view_area); +} + static gboolean ev_view_forms_remove_widgets (EvView *view) { @@ -1618,25 +1659,62 @@ ev_view_form_field_button_create_widget (EvView *view, EvFormField *field) { EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field); + GdkRegion *field_region = NULL; switch (field_button->type) { case EV_FORM_FIELD_BUTTON_PUSH: - break; + return NULL; case EV_FORM_FIELD_BUTTON_CHECK: case EV_FORM_FIELD_BUTTON_RADIO: { - gboolean state; + gboolean state; + GList *forms_mapping, *l; state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document), field); + + /* FIXME: it actually depends on NoToggleToOff flags */ + if (field_button->type == EV_FORM_FIELD_BUTTON_RADIO && + state && field_button->state) + return NULL; + + field_region = ev_view_form_field_get_region (view, field); + + /* For radio buttons and checkbox buttons that are in a set + * we need to update also the region for the current selected item + */ + forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, + field->page); + for (l = forms_mapping; l; l = g_list_next (l)) { + EvFormField *button = ((EvFormFieldMapping *)(l->data))->field; + GdkRegion *button_region; + + if (button->id == field->id) + continue; + + /* FIXME: only buttons in the same group should be updated */ + if (!EV_IS_FORM_FIELD_BUTTON (button) || + EV_FORM_FIELD_BUTTON (button)->type != field_button->type || + EV_FORM_FIELD_BUTTON (button)->state != TRUE) + continue; + + button_region = ev_view_form_field_get_region (view, button); + gdk_region_union (field_region, button_region); + gdk_region_destroy (button_region); + } + ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document), field, !state); - ev_pixbuf_cache_reload_page (view->pixbuf_cache, - field->page, - view->rotation, - view->scale); + field_button->state = !state; } break; } + + ev_pixbuf_cache_reload_page (view->pixbuf_cache, + field_region, + field->page, + view->rotation, + view->scale); + gdk_region_destroy (field_region); return NULL; } @@ -1647,18 +1725,26 @@ ev_view_form_field_text_save (EvView *view, { EvFormField *field; + if (!view->document) + return; + field = g_object_get_data (G_OBJECT (widget), "form-field"); if (field->changed) { EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field); + GdkRegion *field_region; + + field_region = ev_view_form_field_get_region (view, field); ev_document_forms_form_field_text_set_text (EV_DOCUMENT_FORMS (view->document), field, field_text->text); field->changed = FALSE; ev_pixbuf_cache_reload_page (view->pixbuf_cache, + field_region, field->page, view->rotation, view->scale); + gdk_region_destroy (field_region); } } @@ -1702,12 +1788,10 @@ ev_view_form_field_text_create_widget (EvView *view, case EV_FORM_FIELD_TEXT_FILE_SELECT: /* TODO */ case EV_FORM_FIELD_TEXT_NORMAL: - case EV_FORM_FIELD_TEXT_PASSWORD: text = gtk_entry_new (); gtk_entry_set_has_frame (GTK_ENTRY (text), FALSE); gtk_entry_set_max_length (GTK_ENTRY (text), field_text->max_len); - gtk_entry_set_visibility (GTK_ENTRY (text), - !(field_text->type == EV_FORM_FIELD_TEXT_PASSWORD)); + gtk_entry_set_visibility (GTK_ENTRY (text), !field_text->is_password); if (txt) { gtk_entry_set_text (GTK_ENTRY (text), txt); @@ -1726,7 +1810,7 @@ ev_view_form_field_text_create_widget (EvView *view, text = gtk_text_view_new (); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); - + if (txt) { gtk_text_buffer_set_text (buffer, txt, -1); g_free (txt); @@ -1752,28 +1836,36 @@ ev_view_form_field_choice_save (EvView *view, { EvFormField *field; + if (!view->document) + return; + field = g_object_get_data (G_OBJECT (widget), "form-field"); if (field->changed) { GList *l; EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field); + GdkRegion *field_region; + + field_region = ev_view_form_field_get_region (view, field); if (field_choice->is_editable) { ev_document_forms_form_field_choice_set_text (EV_DOCUMENT_FORMS (view->document), field, field_choice->text); - } - - ev_document_forms_form_field_choice_unselect_all (EV_DOCUMENT_FORMS (view->document), field); - for (l = field_choice->selected_items; l && l->data; l = g_list_next (l)) { - ev_document_forms_form_field_choice_select_item (EV_DOCUMENT_FORMS (view->document), - field, - GPOINTER_TO_INT (l->data)); + } else { + ev_document_forms_form_field_choice_unselect_all (EV_DOCUMENT_FORMS (view->document), field); + for (l = field_choice->selected_items; l; l = g_list_next (l)) { + ev_document_forms_form_field_choice_select_item (EV_DOCUMENT_FORMS (view->document), + field, + GPOINTER_TO_INT (l->data)); + } } field->changed = FALSE; ev_pixbuf_cache_reload_page (view->pixbuf_cache, + field_region, field->page, view->rotation, view->scale); + gdk_region_destroy (field_region); } } @@ -2357,8 +2449,9 @@ static gboolean ev_view_expose_event (GtkWidget *widget, GdkEventExpose *event) { - EvView *view = EV_VIEW (widget); - int i; + EvView *view = EV_VIEW (widget); + cairo_t *cr; + gint i; if (view->presentation) { switch (view->presentation_state) { @@ -2392,6 +2485,8 @@ ev_view_expose_event (GtkWidget *widget, if (view->document == NULL) return FALSE; + cr = gdk_cairo_create (view->layout.bin_window); + for (i = view->start_page; i <= view->end_page; i++) { GdkRectangle page_area; GtkBorder border; @@ -2403,12 +2498,14 @@ ev_view_expose_event (GtkWidget *widget, page_area.x -= view->scroll_x; page_area.y -= view->scroll_y; - draw_one_page (view, i, &page_area, &border, &(event->area), &page_ready); + draw_one_page (view, i, cr, &page_area, &border, &(event->area), &page_ready); - if (page_ready && EV_IS_DOCUMENT_FIND (view->document)) + if (page_ready && EV_IS_DOCUMENT_FIND (view->document) && view->highlight_find_results) highlight_find_results (view, i); } + cairo_destroy (cr); + if (GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (* GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (widget, event); @@ -2449,6 +2546,86 @@ ev_view_popup_menu (GtkWidget *widget) return ev_view_do_popup_menu (EV_VIEW (widget), x, y); } +#if GTK_CHECK_VERSION (2, 11, 7) +static void +get_link_area (EvView *view, + gint x, + gint y, + EvLink *link, + GdkRectangle *area) +{ + EvRectangle ev_rect; + GList *link_mapping; + gint page; + gint x_offset = 0, y_offset = 0; + + x += view->scroll_x; + y += view->scroll_y; + + find_page_at_location (view, x, y, &page, &x_offset, &y_offset); + + link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page); + ev_link_mapping_get_area (link_mapping, link, &ev_rect); + + doc_rect_to_view_rect (view, page, &ev_rect, area); + area->y -= view->scroll_y ; +} + +static gboolean +ev_view_query_tooltip (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_tip, + GtkTooltip *tooltip) +{ + EvView *view = EV_VIEW (widget); + EvLink *link; + gchar *text; + + link = ev_view_get_link_at_location (view, x, y); + if (!link) + return FALSE; + + text = tip_from_link (view, link); + if (text && g_utf8_validate (text, -1, NULL)) { + GdkRectangle link_area; + + get_link_area (view, x, y, link, &link_area); + gtk_tooltip_set_text (tooltip, text); + gtk_tooltip_set_tip_area (tooltip, &link_area); + } + g_free (text); + + return TRUE; +} +#endif /* GTK_CHECK_VERSION (2, 11, 7) */ + +static void +start_selection_for_event (EvView *view, + GdkEventButton *event) +{ + EvSelectionStyle style; + + clear_selection (view); + + view->selection_info.start.x = event->x + view->scroll_x; + view->selection_info.start.y = event->y + view->scroll_y; + + switch (event->type) { + case GDK_2BUTTON_PRESS: + style = EV_SELECTION_STYLE_WORD; + break; + case GDK_3BUTTON_PRESS: + style = EV_SELECTION_STYLE_LINE; + break; + default: + style = EV_SELECTION_STYLE_GLYPH; + break; + } + + view->selection_info.style = style; +} + static gboolean ev_view_button_press_event (GtkWidget *widget, GdkEventButton *event) @@ -2470,19 +2647,21 @@ ev_view_button_press_event (GtkWidget *widget, EvImage *image; EvFormField *field; - if (view->selection_info.selections) { - if (location_in_selected_text (view, + if (EV_IS_SELECTION (view->document) && view->selection_info.selections) { + if (event->type == GDK_3BUTTON_PRESS) { + start_selection_for_event (view, event); + } else 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); - - view->selection_info.start.x = event->x + view->scroll_x; - view->selection_info.start.y = event->y + view->scroll_y; + start_selection_for_event (view, event); } - + gtk_widget_queue_draw (widget); + } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) { + ev_view_remove_all (view); + ev_view_handle_form_field (view, field, event->x, event->y); } else if (!location_in_text (view, event->x + view->scroll_x, event->y + view->scroll_y) && (image = ev_view_get_image_at_location (view, event->x, event->y))) { if (view->image_dnd_info.image) @@ -2492,13 +2671,11 @@ ev_view_button_press_event (GtkWidget *widget, view->image_dnd_info.start.x = event->x + view->scroll_x; view->image_dnd_info.start.y = event->y + view->scroll_y; - } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) { - ev_view_remove_all (view); - ev_view_handle_form_field (view, field, event->x, event->y); } else { ev_view_remove_all (view); - view->selection_info.start.x = event->x + view->scroll_x; - view->selection_info.start.y = event->y + view->scroll_y; + + if (EV_IS_SELECTION (view->document)) + start_selection_for_event (view, event); } } return TRUE; @@ -2545,16 +2722,14 @@ ev_view_drag_data_get (GtkWidget *widget, switch (info) { case TARGET_DND_TEXT: - if (view->selection_info.selections && - ev_document_can_get_text (view->document)) { + if (EV_IS_SELECTION (view->document) && + view->selection_info.selections) { gchar *text; text = get_selected_text (view); - gtk_selection_data_set_text (selection_data, text, strlen (text)); - g_free (text); } break; @@ -2635,7 +2810,10 @@ ev_view_drag_data_received (GtkWidget *widget, static gboolean selection_update_idle_cb (EvView *view) { - compute_selections (view, &view->selection_info.start, &view->motion); + compute_selections (view, + view->selection_info.style, + &view->selection_info.start, + &view->motion); view->selection_update_id = 0; return FALSE; } @@ -2809,21 +2987,20 @@ ev_view_button_release_event (GtkWidget *widget, GdkEventButton *event) { EvView *view = EV_VIEW (widget); - EvLink *link; + EvLink *link = NULL; + + view->drag_info.in_drag = FALSE; + view->image_dnd_info.in_drag = FALSE; if (view->pressed_button == 2) { - ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL); + ev_view_handle_cursor_over_xy (view, event->x, event->y); } if (view->document && view->pressed_button != 3) { link = ev_view_get_link_at_location (view, event->x, event->y); - } else { - link = NULL; } view->pressed_button = -1; - view->drag_info.in_drag = FALSE; - view->image_dnd_info.in_drag = FALSE; if (view->selection_scroll_id) { g_source_remove (view->selection_scroll_id); @@ -2834,6 +3011,14 @@ ev_view_button_release_event (GtkWidget *widget, view->selection_update_id = 0; } + if (!view->selection_info.in_selection && + view->selection_info.style != EV_SELECTION_STYLE_GLYPH) { + compute_selections (view, + view->selection_info.style, + &(view->selection_info.start), + &(view->selection_info.start)); + } + if (view->selection_info.selections) { ev_view_update_primary_selection (view); @@ -3177,18 +3362,17 @@ static gboolean ev_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) { EvView *view = EV_VIEW (widget); - - ev_view_set_status (view, NULL); - if (view->cursor == EV_VIEW_CURSOR_LINK || - view->cursor == EV_VIEW_CURSOR_IBEAM) + if (view->cursor != EV_VIEW_CURSOR_NORMAL) ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL); +#if !GTK_CHECK_VERSION (2, 11, 7) if (view->link_tooltip) { view->hovered_link = NULL; ev_tooltip_deactivate (EV_TOOLTIP (view->link_tooltip)); } - +#endif + return FALSE; } @@ -3360,6 +3544,7 @@ draw_loading_text (EvView *view, static void draw_one_page (EvView *view, gint page, + cairo_t *cr, GdkRectangle *page_area, GtkBorder *border, GdkRectangle *expose_area, @@ -3398,7 +3583,6 @@ draw_one_page (EvView *view, cairo_surface_t *page_surface = NULL; gint selection_width, selection_height; cairo_surface_t *selection_surface = NULL; - cairo_t *cr = NULL; page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page); @@ -3416,16 +3600,10 @@ draw_one_page (EvView *view, view->scale, &width, &height); - cr = gdk_cairo_create (view->layout.bin_window); - - cairo_save (cr); - page_width = cairo_image_surface_get_width (page_surface); page_height = cairo_image_surface_get_height (page_surface); - - cairo_rectangle (cr, overlap.x, overlap.y, overlap.width, overlap.height); - cairo_clip (cr); - + + cairo_save (cr); cairo_translate (cr, overlap.x, overlap.y); if (width != page_width || height != page_height) { @@ -3439,10 +3617,8 @@ draw_one_page (EvView *view, cairo_surface_set_device_offset (page_surface, overlap.x - real_page_area.x, overlap.y - real_page_area.y); - cairo_set_source_surface (cr, page_surface, 0, 0); cairo_paint (cr); - cairo_restore (cr); /* Get the selection pixbuf iff we have something to draw */ @@ -3456,16 +3632,13 @@ draw_one_page (EvView *view, } if (!selection_surface) { - cairo_destroy (cr); return; } selection_width = cairo_image_surface_get_width (selection_surface); selection_height = cairo_image_surface_get_height (selection_surface); - cairo_rectangle (cr, overlap.x, overlap.y, overlap.width, overlap.height); - cairo_clip (cr); - + cairo_save (cr); cairo_translate (cr, overlap.x, overlap.y); if (width != selection_width || height != selection_height) { @@ -3479,10 +3652,9 @@ draw_one_page (EvView *view, cairo_surface_set_device_offset (selection_surface, overlap.x - real_page_area.x, overlap.y - real_page_area.y); - cairo_set_source_surface (cr, selection_surface, 0, 0); cairo_paint (cr); - cairo_destroy (cr); + cairo_restore (cr); } } @@ -3493,7 +3665,6 @@ ev_view_finalize (GObject *object) { EvView *view = EV_VIEW (object); - g_free (view->status); g_free (view->find_status); clear_selection (view); @@ -3520,11 +3691,12 @@ ev_view_destroy (GtkObject *object) view->pixbuf_cache = NULL; } +#if !GTK_CHECK_VERSION (2, 11, 7) if (view->link_tooltip) { gtk_widget_destroy (view->link_tooltip); view->link_tooltip = NULL; } - +#endif if (view->goto_window) { gtk_widget_destroy (view->goto_window); view->goto_window = NULL; @@ -3628,11 +3800,8 @@ ev_view_get_property (GObject *object, EvView *view = EV_VIEW (object); switch (prop_id) { - case PROP_STATUS: - g_value_set_string (value, view->status); - break; case PROP_FIND_STATUS: - g_value_set_string (value, view->status); + g_value_set_string (value, view->find_status); break; case PROP_CONTINUOUS: g_value_set_boolean (value, view->continuous); @@ -3696,6 +3865,9 @@ ev_view_class_init (EvViewClass *class) widget_class->drag_motion = ev_view_drag_motion; widget_class->drag_data_received = ev_view_drag_data_received; widget_class->popup_menu = ev_view_popup_menu; +#if GTK_CHECK_VERSION (2, 11, 7) + widget_class->query_tooltip = ev_view_query_tooltip; +#endif gtk_object_class->destroy = ev_view_destroy; @@ -3745,13 +3917,6 @@ ev_view_class_init (EvViewClass *class) G_TYPE_NONE, 1, G_TYPE_OBJECT); - g_object_class_install_property (object_class, - PROP_STATUS, - g_param_spec_string ("status", - "Status Message", - "The status message", - NULL, - G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_FIND_STATUS, @@ -3836,6 +4001,15 @@ ev_view_class_init (EvViewClass *class) 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); + gtk_binding_entry_add_signal (binding_set, GDK_H, 0, "binding_activated", 2, EV_TYPE_SCROLL_TYPE, + EV_SCROLL_STEP_BACKWARD, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_J, 0, "binding_activated", 2, EV_TYPE_SCROLL_TYPE, + EV_SCROLL_STEP_FORWARD, G_TYPE_BOOLEAN, FALSE); + gtk_binding_entry_add_signal (binding_set, GDK_K, 0, "binding_activated", 2, EV_TYPE_SCROLL_TYPE, + EV_SCROLL_STEP_BACKWARD, G_TYPE_BOOLEAN, FALSE); + gtk_binding_entry_add_signal (binding_set, GDK_L, 0, "binding_activated", 2, EV_TYPE_SCROLL_TYPE, + EV_SCROLL_STEP_FORWARD, G_TYPE_BOOLEAN, TRUE); + } static void @@ -3861,6 +4035,7 @@ ev_view_init (EvView *view) view->sizing_mode = EV_SIZING_FIT_WIDTH; view->pending_scroll = SCROLL_TO_KEEP_POSITION; view->jump_to_find_result = TRUE; + view->highlight_find_results = FALSE; gtk_layout_set_hadjustment (GTK_LAYOUT (view), NULL); gtk_layout_set_vadjustment (GTK_LAYOUT (view), NULL); @@ -3895,9 +4070,15 @@ find_changed_cb (EvDocument *document, int page, EvView *view) static void job_finished_cb (EvPixbufCache *pixbuf_cache, + GdkRegion *region, EvView *view) { - gtk_widget_queue_draw (GTK_WIDGET (view)); + if (region) { + gdk_window_invalidate_region (view->layout.bin_window, + region, TRUE); + } else { + gtk_widget_queue_draw (GTK_WIDGET (view)); + } } static void @@ -4272,10 +4453,19 @@ ev_view_presentation_transition_start (EvView *view) duration = ev_document_transition_get_page_duration (EV_DOCUMENT_TRANSITION (view->document), view->current_page); - if (duration > 0) - view->trans_timeout_id = g_timeout_add (duration * 1000, - (GSourceFunc) transition_next_page, - view); + if (duration > 0) { +#if GLIB_CHECK_VERSION (2, 13, 0) + view->trans_timeout_id = + g_timeout_add_seconds (duration, + (GSourceFunc) transition_next_page, + view); +#else + view->trans_timeout_id = + g_timeout_add (duration * 1000, + (GSourceFunc) transition_next_page, + view); +#endif + } } void @@ -4615,13 +4805,14 @@ ev_view_zoom_for_size_single_page (EvView *view, ev_view_set_zoom (view, scale, FALSE); } -void +static void ev_view_set_zoom_for_size (EvView *view, int width, int height, int vsb_width, int hsb_height) { + g_return_if_fail (EV_IS_VIEW (view)); g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_BEST_FIT); g_return_if_fail (width >= 0); @@ -4642,28 +4833,7 @@ ev_view_set_zoom_for_size (EvView *view, ev_view_zoom_for_size_single_page (view, width, height, vsb_width, hsb_height); } -/*** Status text messages ***/ - -const char * -ev_view_get_status (EvView *view) -{ - g_return_val_if_fail (EV_IS_VIEW (view), NULL); - - return view->status; -} - -static void -ev_view_set_status (EvView *view, const char *message) -{ - g_return_if_fail (EV_IS_VIEW (view)); - - if (message != view->status) { - g_free (view->status); - view->status = g_strdup (message); - g_object_notify (G_OBJECT (view), "status"); - } -} - +/*** Find ***/ static void update_find_status_message (EvView *view, gboolean this_page) { @@ -4713,8 +4883,6 @@ ev_view_set_find_status (EvView *view, const char *message) g_object_notify (G_OBJECT (view), "find-status"); } -/*** Find ***/ - static void jump_to_find_result (EvView *view) { @@ -4869,6 +5037,12 @@ void ev_view_search_changed (EvView *view) view->jump_to_find_result = TRUE; } +void ev_view_set_highlight_search (EvView *view, gboolean value) +{ + view->highlight_find_results = value; + gtk_widget_queue_draw (GTK_WIDGET (view)); +} + /*** Selections ***/ /* compute_new_selection_rect/text calculates the area currently selected by @@ -4926,9 +5100,10 @@ gdk_rectangle_point_in (GdkRectangle *rectangle, } static GList * -compute_new_selection_text (EvView *view, - GdkPoint *start, - GdkPoint *stop) +compute_new_selection_text (EvView *view, + EvSelectionStyle style, + GdkPoint *start, + GdkPoint *stop) { int n_pages, i, first, last; GList *list = NULL; @@ -4983,6 +5158,7 @@ compute_new_selection_text (EvView *view, selection = g_new0 (EvViewSelection, 1); selection->page = i; + selection->style = style; selection->rect.x1 = selection->rect.y1 = 0; selection->rect.x2 = width; selection->rect.y2 = height; @@ -5140,16 +5316,17 @@ merge_selection_region (EvView *view, } static void -compute_selections (EvView *view, - GdkPoint *start, - GdkPoint *stop) +compute_selections (EvView *view, + EvSelectionStyle style, + GdkPoint *start, + GdkPoint *stop) { GList *list; if (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE) list = compute_new_selection_rect (view, start, stop); else - list = compute_new_selection_text (view, start, stop); + list = compute_new_selection_text (view, style, start, stop); merge_selection_region (view, list); } @@ -5174,10 +5351,10 @@ clear_selection (EvView *view) g_object_notify (G_OBJECT (view), "has-selection"); } - void ev_view_select_all (EvView *view) { + GList *selections = NULL; int n_pages, i; /* Disable selection on rotated pages for the 0.4.0 series */ @@ -5185,7 +5362,7 @@ ev_view_select_all (EvView *view) return; clear_selection (view); - + n_pages = ev_page_cache_get_n_pages (view->page_cache); for (i = 0; i < n_pages; i++) { int width, height; @@ -5198,15 +5375,15 @@ ev_view_select_all (EvView *view) selection = g_new0 (EvViewSelection, 1); selection->page = i; + selection->style = EV_SELECTION_STYLE_GLYPH; selection->rect.x1 = selection->rect.y1 = 0; selection->rect.x2 = width; selection->rect.y2 = height; - view->selection_info.selections = g_list_append (view->selection_info.selections, selection); + selections = g_list_append (selections, selection); } - ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, view->selection_info.selections); - g_object_notify (G_OBJECT (view), "has-selection"); + merge_selection_region (view, selections); gtk_widget_queue_draw (GTK_WIDGET (view)); } @@ -5217,29 +5394,35 @@ ev_view_get_has_selection (EvView *view) } static char * -get_selected_text (EvView *ev_view) +get_selected_text (EvView *view) { GString *text; GList *l; gchar *normalized_text; + EvRenderContext *rc; text = g_string_new (NULL); + rc = ev_render_context_new (view->rotation, 1, view->scale); ev_document_doc_mutex_lock (); - for (l = ev_view->selection_info.selections; l != NULL; l = l->next) { + for (l = view->selection_info.selections; l != NULL; l = l->next) { EvViewSelection *selection = (EvViewSelection *)l->data; - char *tmp; + gchar *tmp; + + ev_render_context_set_page (rc, selection->page); + tmp = ev_selection_get_selected_text (EV_SELECTION (view->document), + rc, selection->style, + &(selection->rect)); - tmp = ev_document_get_text (ev_view->document, - selection->page, - &selection->rect); g_string_append (text, tmp); g_free (tmp); } ev_document_doc_mutex_unlock (); + g_object_unref (rc); + normalized_text = g_utf8_normalize (text->str, text->len, G_NORMALIZE_NFKC); g_string_free (text, TRUE); return normalized_text; @@ -5251,9 +5434,8 @@ ev_view_copy (EvView *ev_view) GtkClipboard *clipboard; char *text; - if (!ev_document_can_get_text (ev_view->document)) { + if (!EV_IS_SELECTION (ev_view->document)) return; - } text = get_selected_text (ev_view); clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view), @@ -5271,9 +5453,8 @@ ev_view_primary_get_cb (GtkClipboard *clipboard, EvView *ev_view = EV_VIEW (data); char *text; - if (!ev_document_can_get_text (ev_view->document)) { + if (!EV_IS_SELECTION (ev_view->document)) return; - } text = get_selected_text (ev_view); if (text) { @@ -5517,3 +5698,37 @@ ev_scroll_type_get_type (void) } return etype; } + +void +ev_view_update_view_size (EvView *view, GtkScrolledWindow * scrolled_window) +{ + int width, height; + GtkRequisition vsb_requisition; + GtkRequisition hsb_requisition; + int scrollbar_spacing; + + /* Calculate the width available for the content */ + width = GTK_WIDGET (scrolled_window)->allocation.width; + height = GTK_WIDGET (scrolled_window)->allocation.height; + + if (gtk_scrolled_window_get_shadow_type (scrolled_window) == GTK_SHADOW_IN + && view) { + width -= 2 * GTK_WIDGET(view)->style->xthickness; + height -= 2 * GTK_WIDGET(view)->style->ythickness; + } + + gtk_widget_size_request (scrolled_window->vscrollbar, &vsb_requisition); + gtk_widget_size_request (scrolled_window->hscrollbar, &hsb_requisition); + gtk_widget_style_get (GTK_WIDGET (scrolled_window), + "scrollbar_spacing", + &scrollbar_spacing, + NULL); + + if (EV_IS_VIEW(view)) { + ev_view_set_zoom_for_size (EV_VIEW (view), + MAX (1, width), + MAX (1, height), + vsb_requisition.width + scrollbar_spacing, + hsb_requisition.height + scrollbar_spacing); + } +}