X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;ds=sidebyside;f=libview%2Fev-view.c;h=613236319dc4aa4d4fefbd35b068434289686867;hb=7b5e14ea3df691578a091c563be0081ff850a367;hp=146b229477a7b4cd0a28412a5018c6a0e0c16e5e;hpb=b9b25ee459d24c0bb7132d0b87b6d7227def4d1c;p=evince.git diff --git a/libview/ev-view.c b/libview/ev-view.c index 146b2294..61323631 100644 --- a/libview/ev-view.c +++ b/libview/ev-view.c @@ -28,6 +28,7 @@ #include #include +#include "ev-mapping.h" #include "ev-document-forms.h" #include "ev-document-images.h" #include "ev-document-links.h" @@ -37,6 +38,8 @@ #include "ev-pixbuf-cache.h" #include "ev-transition-animation.h" #include "ev-view-marshal.h" +#include "ev-document-annotations.h" +#include "ev-annotation-window.h" #include "ev-view.h" #include "ev-view-accessible.h" #include "ev-view-private.h" @@ -148,6 +151,14 @@ static EvFormField *ev_view_get_form_field_at_location (EvView gdouble x, gdouble y); +/*** Annotations ***/ +static EvAnnotation *ev_view_get_annotation_at_location (EvView *view, + gdouble x, + gdouble y); +static void show_annotation_windows (EvView *view, + gint page); +static void hide_annotation_windows (EvView *view, + gint page); /*** GtkWidget implementation ***/ static void ev_view_size_request_continuous_dual_page (EvView *view, GtkRequisition *requisition); @@ -427,6 +438,8 @@ view_update_range_and_current_page (EvView *view) { gint current_page; gint best_current_page = -1; + gint start = view->start_page; + gint end = view->end_page; /* Presentation trumps all other modes */ if (view->presentation) { @@ -498,6 +511,18 @@ view_update_range_and_current_page (EvView *view) ev_page_cache_set_current_page (view->page_cache, best_current_page); } + if (start != view->start_page || end != view->end_page) { + gint i; + + for (i = start; i < view->start_page; i++) { + hide_annotation_windows (view, i); + } + + for (i = end; i > view->end_page; i--) { + hide_annotation_windows (view, i); + } + } + ev_pixbuf_cache_set_page_range (view->pixbuf_cache, view->start_page, view->end_page, @@ -1092,6 +1117,41 @@ get_doc_point_from_offset (EvView *view, return TRUE; } +static gboolean +get_doc_point_from_location (EvView *view, + gdouble x, + gdouble y, + gint *page, + gint *x_new, + gint *y_new) +{ + 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); + if (*page == -1) + return FALSE; + + return get_doc_point_from_offset (view, *page, x_offset, y_offset, x_new, y_new); +} + +static void +ev_view_get_area_from_mapping (EvView *view, + guint page, + GList *mapping_list, + gconstpointer data, + GdkRectangle *area) +{ + EvMapping *mapping; + + mapping = ev_mapping_list_find (mapping_list, data); + doc_rect_to_view_rect (view, page, &mapping->area, area); + area->x -= view->scroll_x; + area->y -= view->scroll_y; +} + + /*** Hyperref ***/ static EvLink * ev_view_get_link_at_location (EvView *view, @@ -1099,30 +1159,19 @@ ev_view_get_link_at_location (EvView *view, gdouble y) { gint page = -1; - gint x_offset = 0, y_offset = 0; gint x_new = 0, y_new = 0; GList *link_mapping; if (!EV_IS_DOCUMENT_LINKS (view->document)) return NULL; - - x += view->scroll_x; - y += view->scroll_y; - - find_page_at_location (view, x, y, &page, &x_offset, &y_offset); - - if (page == -1) - return NULL; - - if (get_doc_point_from_offset (view, page, x_offset, - y_offset, &x_new, &y_new) == FALSE) + if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new)) return NULL; link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page); if (link_mapping) - return ev_link_mapping_find (link_mapping, x_new, y_new); + return ev_mapping_list_get_data (link_mapping, x_new, y_new); else return NULL; } @@ -1487,8 +1536,9 @@ tip_from_link (EvView *view, EvLink *link) static void ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) { - EvLink *link; - EvFormField *field; + EvLink *link; + EvFormField *field; + EvAnnotation *annot = NULL; if (view->cursor == EV_VIEW_CURSOR_HIDDEN) return; @@ -1504,10 +1554,9 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) ev_view_set_cursor (view, EV_VIEW_CURSOR_AUTOSCROLL); return; } - + link = ev_view_get_link_at_location (view, x, y); if (link) { - g_object_set (view, "has-tooltip", TRUE, NULL); 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) { @@ -1520,6 +1569,8 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) } else { ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); } + } else if ((annot = ev_view_get_annotation_at_location (view, x, y))) { + 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 { @@ -1529,6 +1580,9 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) view->cursor == EV_VIEW_CURSOR_AUTOSCROLL) ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL); } + + if (link || annot) + g_object_set (view, "has-tooltip", TRUE, NULL); } /*** Images ***/ @@ -1538,29 +1592,19 @@ ev_view_get_image_at_location (EvView *view, gdouble y) { gint page = -1; - gint x_offset = 0, y_offset = 0; gint x_new = 0, y_new = 0; GList *image_mapping; if (!EV_IS_DOCUMENT_IMAGES (view->document)) return NULL; - x += view->scroll_x; - y += view->scroll_y; - - find_page_at_location (view, x, y, &page, &x_offset, &y_offset); - - if (page == -1) - return NULL; - - if (get_doc_point_from_offset (view, page, x_offset, - y_offset, &x_new, &y_new) == FALSE) + if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new)) return NULL; image_mapping = ev_pixbuf_cache_get_image_mapping (view->pixbuf_cache, page); if (image_mapping) - return ev_image_mapping_find (image_mapping, x_new, y_new); + return ev_mapping_list_get_data (image_mapping, x_new, y_new); else return NULL; } @@ -1572,29 +1616,19 @@ ev_view_get_form_field_at_location (EvView *view, gdouble y) { gint page = -1; - gint x_offset = 0, y_offset = 0; gint x_new = 0, y_new = 0; GList *forms_mapping; if (!EV_IS_DOCUMENT_FORMS (view->document)) return NULL; - x += view->scroll_x; - y += view->scroll_y; - - find_page_at_location (view, x, y, &page, &x_offset, &y_offset); - - if (page == -1) - return NULL; - - if (get_doc_point_from_offset (view, page, x_offset, - y_offset, &x_new, &y_new) == FALSE) + if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new)) return NULL; forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page); if (forms_mapping) - return ev_form_field_mapping_find (forms_mapping, x_new, y_new); + return ev_mapping_list_get_data (forms_mapping, x_new, y_new); else return NULL; } @@ -1603,16 +1637,14 @@ 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->index); - ev_form_field_mapping_get_area (forms_mapping, field, &field_area); - doc_rect_to_view_rect (view, field->page->index, &field_area, &view_area); - view_area.x -= view->scroll_x; - view_area.y -= view->scroll_y; + ev_view_get_area_from_mapping (view, field->page->index, + forms_mapping, + field, &view_area); return gdk_region_rectangle (&view_area); } @@ -1663,7 +1695,7 @@ ev_view_form_field_button_create_widget (EvView *view, forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, field->page->index); for (l = forms_mapping; l; l = g_list_next (l)) { - EvFormField *button = ((EvFormFieldMapping *)(l->data))->field; + EvFormField *button = ((EvMapping *)(l->data))->data; GdkRegion *button_region; if (button->id == field->id) @@ -2021,7 +2053,6 @@ ev_view_handle_form_field (EvView *view, { GtkWidget *field_widget = NULL; GList *form_field_mapping; - EvRectangle field_area; GdkRectangle view_area; if (field->is_read_only) @@ -2046,17 +2077,357 @@ ev_view_handle_form_field (EvView *view, (GDestroyNotify)g_object_unref); form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, field->page->index); - ev_form_field_mapping_get_area (form_field_mapping, field, &field_area); - - doc_rect_to_view_rect (view, field->page->index, &field_area, &view_area); - view_area.x -= view->scroll_x; - view_area.y -= view->scroll_y; + ev_view_get_area_from_mapping (view, field->page->index, + form_field_mapping, + field, &view_area); gtk_layout_put (GTK_LAYOUT (view), field_widget, view_area.x, view_area.y); gtk_widget_show (field_widget); gtk_widget_grab_focus (field_widget); } +/* Annotations */ +static EvViewWindowChild * +ev_view_get_window_child (EvView *view, + GtkWidget *window) +{ + GList *children = view->window_children; + + while (children) { + EvViewWindowChild *child; + + child = (EvViewWindowChild *)children->data; + children = children->next; + + if (child->window == window) + return child; + } + + return NULL; +} + +static void +ev_view_window_child_move (EvView *view, + EvViewWindowChild *child, + gint x, + gint y) +{ + child->x = x; + child->y = y; + gtk_window_move (GTK_WINDOW (child->window), + MAX (child->parent_x, x), + MAX (child->parent_y, y)); +} + +static void +ev_view_window_child_move_with_parent (EvView *view, + GtkWidget *window) +{ + EvViewWindowChild *child; + gint root_x, root_y; + + child = ev_view_get_window_child (view, window); + gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)), + &root_x, &root_y); + if (root_x != child->parent_x || root_y != child->parent_y) { + gint dest_x, dest_y; + + dest_x = child->x + (root_x - child->parent_x); + dest_y = child->y + (root_y - child->parent_y); + child->parent_x = root_x; + child->parent_y = root_y; + ev_view_window_child_move (view, child, dest_x, dest_y); + } + + if (child->visible && !GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); +} + +static void +ev_view_window_child_put (EvView *view, + GtkWidget *window, + guint page, + gint x, + gint y, + gdouble orig_x, + gdouble orig_y) +{ + EvViewWindowChild *child; + gint root_x, root_y; + + gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)), + &root_x, &root_y); + + child = g_new0 (EvViewWindowChild, 1); + child->window = window; + child->page = page; + child->orig_x = orig_x; + child->orig_y = orig_y; + child->parent_x = root_x; + child->parent_y = root_y; + child->visible = ev_annotation_window_is_open (EV_ANNOTATION_WINDOW (window)); + ev_view_window_child_move (view, child, x + root_x, y + root_y); + + if (child->visible) + gtk_widget_show (window); + else + gtk_widget_hide (window); + + view->window_children = g_list_append (view->window_children, child); +} + +static EvViewWindowChild * +ev_view_find_window_child_for_annot (EvView *view, + guint page, + EvAnnotation *annot) +{ + GList *children = view->window_children; + + while (children) { + EvViewWindowChild *child; + EvAnnotation *wannot; + + child = (EvViewWindowChild *)children->data; + children = children->next; + + if (child->page != page) + continue; + + wannot = ev_annotation_window_get_annotation (EV_ANNOTATION_WINDOW (child->window)); + if (wannot == annot || strcmp (wannot->name, annot->name) == 0) + return child; + } + + return NULL; +} + +static void +ev_view_window_children_free (EvView *view) +{ + GList *l; + + if (!view->window_children) + return; + + for (l = view->window_children; l && l->data; l = g_list_next (l)) { + EvViewWindowChild *child; + + child = (EvViewWindowChild *)l->data; + gtk_widget_destroy (GTK_WIDGET (child->window)); + g_free (child); + } + g_list_free (view->window_children); + view->window_children = NULL; + view->window_child_focus = NULL; +} + +static void +annotation_window_grab_focus (GtkWidget *widget, + EvView *view) +{ + if (view->window_child_focus) + ev_annotation_window_ungrab_focus (EV_ANNOTATION_WINDOW (view->window_child_focus->window)); + view->window_child_focus = ev_view_get_window_child (view, widget); +} + +static void +annotation_window_closed (EvAnnotationWindow *window, + EvView *view) +{ + EvViewWindowChild *child; + + child = ev_view_get_window_child (view, GTK_WIDGET (window)); + child->visible = FALSE; +} + +static void +annotation_window_moved (EvAnnotationWindow *window, + gint x, + gint y, + EvView *view) +{ + EvViewWindowChild *child; + GdkRectangle page_area; + GtkBorder border; + GdkRectangle view_rect; + EvRectangle doc_rect; + gint width, height; + + child = ev_view_get_window_child (view, GTK_WIDGET (window)); + if (child->x == x && child->y == y) + return; + + child->moved = TRUE; + child->x = x; + child->y = y; + + /* Window has been moved by the user, + * we have to set a new origin in doc coords + */ + gtk_window_get_size (GTK_WINDOW (window), &width, &height); + view_rect.x = (x - child->parent_x) + view->scroll_x; + view_rect.y = (y - child->parent_y) + view->scroll_y; + view_rect.width = width; + view_rect.height = height; + + get_page_extents (view, child->page, &page_area, &border); + view_rect_to_doc_rect (view, &view_rect, &page_area, &doc_rect); + child->orig_x = doc_rect.x1; + child->orig_y = doc_rect.y1; +} + +static void +ev_view_annotation_save (EvView *view, + EvAnnotation *annot) +{ + if (!view->document) + return; + + if (!annot->changed) + return; + + ev_document_annotations_annotation_set_contents (EV_DOCUMENT_ANNOTATIONS (view->document), + annot, annot->contents); + annot->changed = FALSE; +} + +static void +show_annotation_windows (EvView *view, + gint page) +{ + GList *annots, *l; + GtkWindow *parent; + + parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))); + + annots = ev_pixbuf_cache_get_annots_mapping (view->pixbuf_cache, page); + + for (l = annots; l && l->data; l = g_list_next (l)) { + EvAnnotation *annot; + EvViewWindowChild *child; + GtkWidget *window; + EvRectangle *doc_rect; + GdkRectangle view_rect; + + annot = ((EvMapping *)(l->data))->data; + + if (!EV_IS_ANNOTATION_MARKUP (annot)) + continue; + + if (!ev_annotation_markup_has_popup (EV_ANNOTATION_MARKUP (annot))) + continue; + + window = g_object_get_data (G_OBJECT (annot), "popup"); + if (window) { + ev_view_window_child_move_with_parent (view, window); + continue; + } + + /* Look if we already have a popup for this annot */ + child = ev_view_find_window_child_for_annot (view, page, annot); + window = child ? child->window : NULL; + if (window) { + ev_annotation_window_set_annotation (EV_ANNOTATION_WINDOW (window), annot); + g_object_set_data (G_OBJECT (annot), "popup", window); + ev_view_window_child_move_with_parent (view, window); + } else { + window = ev_annotation_window_new (annot, parent); + g_signal_connect (window, "grab_focus", + G_CALLBACK (annotation_window_grab_focus), + view); + g_signal_connect (window, "closed", + G_CALLBACK (annotation_window_closed), + view); + g_signal_connect (window, "moved", + G_CALLBACK (annotation_window_moved), + view); + g_object_set_data (G_OBJECT (annot), "popup", window); + + doc_rect = (EvRectangle *)ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (window)); + doc_rect_to_view_rect (view, page, doc_rect, &view_rect); + view_rect.x -= view->scroll_x; + view_rect.y -= view->scroll_y; + + ev_view_window_child_put (view, window, page, + view_rect.x, view_rect.y, + doc_rect->x1, doc_rect->y1); + + g_object_weak_ref (G_OBJECT (annot), + (GWeakNotify)ev_view_annotation_save, + view); + } + } +} + +static void +hide_annotation_windows (EvView *view, + gint page) +{ + GList *annots, *l; + + annots = ev_pixbuf_cache_get_annots_mapping (view->pixbuf_cache, page); + + for (l = annots; l && l->data; l = g_list_next (l)) { + EvAnnotation *annot; + GtkWidget *window; + + annot = ((EvMapping *)(l->data))->data; + + if (!EV_IS_ANNOTATION_MARKUP (annot)) + continue; + + window = g_object_get_data (G_OBJECT (annot), "popup"); + if (window) + gtk_widget_hide (window); + } +} + +static EvAnnotation * +ev_view_get_annotation_at_location (EvView *view, + gdouble x, + gdouble y) +{ + gint page = -1; + gint x_new = 0, y_new = 0; + GList *annotations_mapping; + + if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document)) + return NULL; + + if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new)) + return NULL; + + annotations_mapping = ev_pixbuf_cache_get_annots_mapping (view->pixbuf_cache, page); + + if (annotations_mapping) + return ev_mapping_list_get_data (annotations_mapping, x_new, y_new); + else + return NULL; +} + +static void +ev_view_handle_annotation (EvView *view, + EvAnnotation *annot, + gdouble x, + gdouble y) +{ + if (EV_IS_ANNOTATION_MARKUP (annot)) { + GtkWidget *window; + + window = g_object_get_data (G_OBJECT (annot), "popup"); + if (window) { + EvViewWindowChild *child; + + child = ev_view_get_window_child (view, window); + if (!child->visible) { + child->visible = TRUE; + ev_view_window_child_move (view, child, child->x, child->y); + gtk_widget_show (window); + } + } + } +} + /*** GtkWidget implementation ***/ static void @@ -2213,14 +2584,13 @@ ev_view_size_allocate (GtkWidget *widget, { EvView *view = EV_VIEW (widget); GList *children, *l; + gint root_x, root_y; GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation); if (view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_BEST_FIT) { - g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0); - ev_view_size_request (widget, &widget->requisition); } @@ -2236,7 +2606,6 @@ ev_view_size_allocate (GtkWidget *widget, children = gtk_container_get_children (GTK_CONTAINER (widget)); for (l = children; l && l->data; l = g_list_next (l)) { EvFormField *field; - EvRectangle field_area; GdkRectangle view_area; GList *form_field_mapping; GtkAllocation child_allocation; @@ -2249,11 +2618,9 @@ ev_view_size_allocate (GtkWidget *widget, form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, field->page->index); - ev_form_field_mapping_get_area (form_field_mapping, field, &field_area); - - doc_rect_to_view_rect (view, field->page->index, &field_area, &view_area); - view_area.x -= view->scroll_x; - view_area.y -= view->scroll_y; + ev_view_get_area_from_mapping (view, field->page->index, + form_field_mapping, + field, &view_area); gtk_widget_size_request (child, &child_requisition); if (child_requisition.width != view_area.width || @@ -2271,6 +2638,33 @@ ev_view_size_allocate (GtkWidget *widget, } } g_list_free (children); + + if (view->window_children) + gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)), + &root_x, &root_y); + + for (l = view->window_children; l && l->data; l = g_list_next (l)) { + EvViewWindowChild *child; + EvRectangle doc_rect; + GdkRectangle view_rect; + + child = (EvViewWindowChild *)l->data; + + doc_rect = *ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (child->window)); + if (child->moved) { + doc_rect.x1 = child->orig_x; + doc_rect.y1 = child->orig_y; + } + doc_rect_to_view_rect (view, child->page, &doc_rect, &view_rect); + view_rect.x -= view->scroll_x; + view_rect.y -= view->scroll_y; + + if (view_rect.x != child->orig_x || view_rect.y != child->orig_y) { + child->parent_x = root_x; + child->parent_y = root_y; + ev_view_window_child_move (view, child, view_rect.x + root_x, view_rect.y + root_y); + } + } } static void @@ -2421,19 +2815,21 @@ ev_view_expose_event (GtkWidget *widget, cairo_t *cr; gint i; - if (view->animation && ev_transition_animation_ready (view->animation)) { - GdkRectangle page_area; - GtkBorder border; + if (view->animation) { + if (ev_transition_animation_ready (view->animation)) { + GdkRectangle page_area; + GtkBorder border; - if (get_page_extents (view, view->current_page, &page_area, &border)) { - cr = gdk_cairo_create (view->layout.bin_window); + if (get_page_extents (view, view->current_page, &page_area, &border)) { + cr = gdk_cairo_create (view->layout.bin_window); - /* normalize to x=0, y=0 */ - cairo_translate (cr, page_area.x, page_area.y); - page_area.x = page_area.y = 0; + /* normalize to x=0, y=0 */ + cairo_translate (cr, page_area.x, page_area.y); + page_area.x = page_area.y = 0; - ev_transition_animation_paint (view->animation, cr, page_area); - cairo_destroy (cr); + ev_transition_animation_paint (view->animation, cr, page_area); + cairo_destroy (cr); + } } return TRUE; @@ -2488,6 +2884,8 @@ ev_view_expose_event (GtkWidget *widget, if (page_ready && view->find_pages && view->highlight_find_results) highlight_find_results (view, i); + if (page_ready && EV_IS_DOCUMENT_ANNOTATIONS (view->document)) + show_annotation_windows (view, i); } cairo_destroy (cr); @@ -2539,10 +2937,9 @@ get_link_area (EvView *view, EvLink *link, GdkRectangle *area) { - EvRectangle ev_rect; - GList *link_mapping; - gint page; - gint x_offset = 0, y_offset = 0; + GList *link_mapping; + gint page; + gint x_offset = 0, y_offset = 0; x += view->scroll_x; y += view->scroll_y; @@ -2550,22 +2947,55 @@ get_link_area (EvView *view, 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); + ev_view_get_area_from_mapping (view, page, + link_mapping, + link, area); +} - doc_rect_to_view_rect (view, page, &ev_rect, area); - area->y -= view->scroll_y ; +static void +get_annot_area (EvView *view, + gint x, + gint y, + EvAnnotation *annot, + GdkRectangle *area) +{ + GList *annots_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); + + annots_mapping = ev_pixbuf_cache_get_annots_mapping (view->pixbuf_cache, page); + ev_view_get_area_from_mapping (view, page, + annots_mapping, + annot, area); } static gboolean -ev_view_query_tooltip (GtkWidget *widget, - gint x, - gint y, - gboolean keyboard_tip, - GtkTooltip *tooltip) +ev_view_query_tooltip (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_tip, + GtkTooltip *tooltip) { - EvView *view = EV_VIEW (widget); - EvLink *link; - gchar *text; + EvView *view = EV_VIEW (widget); + EvLink *link; + EvAnnotation *annot; + gchar *text; + + annot = ev_view_get_annotation_at_location (view, x, y); + if (annot && annot->contents) { + GdkRectangle annot_area; + + get_annot_area (view, x, y, annot, &annot_area); + gtk_tooltip_set_text (tooltip, annot->contents); + gtk_tooltip_set_tip_area (tooltip, &annot_area); + + return TRUE; + } link = ev_view_get_link_at_location (view, x, y); if (!link) @@ -2588,26 +3018,28 @@ 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; + view->selection_info.style = EV_SELECTION_STYLE_WORD; break; case GDK_3BUTTON_PRESS: - style = EV_SELECTION_STYLE_LINE; + view->selection_info.style = EV_SELECTION_STYLE_LINE; break; default: - style = EV_SELECTION_STYLE_GLYPH; - break; + view->selection_info.style = EV_SELECTION_STYLE_GLYPH; + return; } - view->selection_info.style = style; + /* In case of WORD or LINE, compute selections now */ + compute_selections (view, + view->selection_info.style, + &(view->selection_info.start), + &(view->selection_info.start)); } static gboolean @@ -2622,6 +3054,17 @@ ev_view_button_press_event (GtkWidget *widget, if (!GTK_WIDGET_HAS_FOCUS (widget)) { gtk_widget_grab_focus (widget); } + + if (view->window_child_focus) { + EvAnnotationWindow *window; + EvAnnotation *annot; + + window = EV_ANNOTATION_WINDOW (view->window_child_focus->window); + annot = ev_annotation_window_get_annotation (window); + ev_annotation_window_ungrab_focus (window); + ev_view_annotation_save (view, annot); + view->window_child_focus = NULL; + } view->pressed_button = event->button; view->selection_info.in_drag = FALSE; @@ -2632,6 +3075,7 @@ ev_view_button_press_event (GtkWidget *widget, switch (event->button) { case 1: { EvImage *image; + EvAnnotation *annot; EvFormField *field; if (EV_IS_SELECTION (view->document) && view->selection_info.selections) { @@ -2646,6 +3090,8 @@ ev_view_button_press_event (GtkWidget *widget, } gtk_widget_queue_draw (widget); + } else if ((annot = ev_view_get_annotation_at_location (view, event->x, event->y))) { + ev_view_handle_annotation (view, annot, event->x, event->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); @@ -2857,12 +3303,14 @@ ev_view_scroll_drag_release (EvView *view) oldhadjustment = gtk_adjustment_get_value (view->hadjustment); oldvadjustment = gtk_adjustment_get_value (view->vadjustment); - if (((oldhadjustment + dhadj_value) > (view->hadjustment->upper - view->hadjustment->page_size)) || + /* When we reach the edges, we need either to absorb some momentum and bounce by + * multiplying it on -0.5 or stop scrolling by setting momentum to 0. */ + if (((oldhadjustment + dhadj_value) > (view->hadjustment->upper - view->hadjustment->page_size)) || ((oldhadjustment + dhadj_value) < 0)) - view->drag_info.momentum.x *= -0.5; /* 0.5 rather than 1 means the edges absorb some momentum */ + view->drag_info.momentum.x = 0; if (((oldvadjustment + dvadj_value) > (view->vadjustment->upper - view->vadjustment->page_size)) || ((oldvadjustment + dvadj_value) < 0)) - view->drag_info.momentum.y *= -0.5; + view->drag_info.momentum.y = 0; gtk_adjustment_set_value (view->hadjustment, MIN (oldhadjustment + dhadj_value, @@ -3074,14 +3522,6 @@ 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) { clear_link_selected (view); ev_view_update_primary_selection (view); @@ -3335,7 +3775,26 @@ ev_view_key_press_event (GtkWidget *widget, if (!view->document) return FALSE; - + + if (!GTK_WIDGET_HAS_FOCUS (widget)) { + /* Forward key events to current focused window child */ + if (view->window_child_focus) { + GdkEventKey *new_event; + gboolean handled; + + new_event = (GdkEventKey *) gdk_event_copy ((GdkEvent *)event); + g_object_unref (new_event->window); + new_event->window = g_object_ref (view->window_child_focus->window->window); + gtk_widget_realize (view->window_child_focus->window); + handled = gtk_widget_event (view->window_child_focus->window, (GdkEvent *)new_event); + gdk_event_free ((GdkEvent *)new_event); + + return handled; + } + + return FALSE; + } + if (!view->presentation || view->presentation_state == EV_PRESENTATION_END) return gtk_bindings_activate_event (GTK_OBJECT (widget), event); @@ -3751,6 +4210,8 @@ ev_view_destroy (GtkObject *object) view->goto_entry = NULL; } + ev_view_window_children_free (view); + if (view->selection_scroll_id) { g_source_remove (view->selection_scroll_id); view->selection_scroll_id = 0; @@ -4066,6 +4527,8 @@ ev_view_init (EvView *view) { GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS); + view->start_page = -1; + view->end_page = -1; view->spacing = 5; view->scale = 1.0; view->current_page = 0; @@ -4159,10 +4622,14 @@ ev_view_presentation_animation_start (EvView *view, if (!effect) return; - surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, view->current_page); view->animation = ev_transition_animation_new (effect); + + surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, view->current_page); ev_transition_animation_set_origin_surface (view->animation, surface); - + surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, new_page); + if (surface) + ev_transition_animation_set_dest_surface (view->animation, surface); + g_signal_connect (view->animation, "frame", G_CALLBACK (ev_view_transition_animation_frame), view); g_signal_connect (view->animation, "finished", @@ -4244,6 +4711,14 @@ on_adjustment_value_changed (GtkAdjustment *adjustment, gtk_layout_move (GTK_LAYOUT (view), child, child_x + dx, child_y + dy); } g_list_free (children); + + for (l = view->window_children; l && l->data; l = g_list_next (l)) { + EvViewWindowChild *child; + + child = (EvViewWindowChild *)l->data; + + ev_view_window_child_move (view, child, child->x + dx, child->y + dy); + } if (view->pending_resize) gtk_widget_queue_draw (GTK_WIDGET (view)); @@ -4397,6 +4872,8 @@ ev_view_set_document (EvView *view, setup_caches (view); } + view_update_range_and_current_page (view); + gtk_widget_queue_resize (GTK_WIDGET (view)); } } @@ -4439,6 +4916,9 @@ ev_view_set_zoom (EvView *view, view->sizing_mode == EV_SIZING_FREE ? view->min_scale : 0, view->max_scale); + if (scale == view->scale) + return; + if (ABS (view->scale - scale) < EPSILON) return; @@ -5832,38 +6312,3 @@ ev_view_previous_page (EvView *view) } } -/*** Enum description for usage in signal ***/ - -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); - } -}