+ if (error) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+ }
+ }
+}
+
+static void
+ev_view_create_annotation (EvView *view,
+ EvAnnotationType annot_type,
+ gint x,
+ gint y)
+{
+ EvAnnotation *annot;
+ GdkPoint point;
+ GdkRectangle page_area;
+ GtkBorder border;
+ EvRectangle doc_rect, popup_rect;
+ EvPage *page;
+ GdkColor color = { 0, 65535, 65535, 0 };
+ GdkRectangle view_rect;
+ cairo_region_t *region;
+
+ point.x = x;
+ point.y = y;
+ ev_view_get_page_extents (view, view->current_page, &page_area, &border);
+ view_point_to_doc_point (view, &point, &page_area,
+ &doc_rect.x1, &doc_rect.y1);
+ doc_rect.x2 = doc_rect.x1 + 24;
+ doc_rect.y2 = doc_rect.y1 + 24;
+
+ ev_document_doc_mutex_lock ();
+ page = ev_document_get_page (view->document, view->current_page);
+ switch (annot_type) {
+ case EV_ANNOTATION_TYPE_TEXT:
+ annot = ev_annotation_text_new (page);
+ break;
+ case EV_ANNOTATION_TYPE_ATTACHMENT:
+ /* TODO */
+ g_object_unref (page);
+ ev_document_doc_mutex_unlock ();
+ return;
+ default:
+ g_assert_not_reached ();
+ }
+ g_object_unref (page);
+
+ ev_annotation_set_color (annot, &color);
+
+ if (EV_IS_ANNOTATION_MARKUP (annot)) {
+ popup_rect.x1 = doc_rect.x2;
+ popup_rect.x2 = popup_rect.x1 + 200;
+ popup_rect.y1 = doc_rect.y2;
+ popup_rect.y2 = popup_rect.y1 + 150;
+ g_object_set (annot,
+ "rectangle", &popup_rect,
+ "has_popup", TRUE,
+ "popup_is_open", FALSE,
+ "label", g_get_real_name (),
+ "opacity", 1.0,
+ NULL);
+ }
+ ev_document_annotations_add_annotation (EV_DOCUMENT_ANNOTATIONS (view->document),
+ annot, &doc_rect);
+ ev_document_doc_mutex_unlock ();
+
+ /* If the page didn't have annots, mark the cache as dirty */
+ if (!ev_page_cache_get_annot_mapping (view->page_cache, view->current_page))
+ ev_page_cache_mark_dirty (view->page_cache, view->current_page);
+
+ if (EV_IS_ANNOTATION_MARKUP (annot)) {
+ GtkWindow *parent;
+ GtkWidget *window;
+
+ parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
+ window = ev_view_create_annotation_window (view, annot, parent);
+
+ /* Show the annot window the first time */
+ ev_view_annotation_show_popup_window (view, window);
+ }
+
+ doc_rect_to_view_rect (view, view->current_page, &doc_rect, &view_rect);
+ view_rect.x -= view->scroll_x;
+ view_rect.y -= view->scroll_y;
+ region = cairo_region_create_rectangle (&view_rect);
+ ev_view_reload_page (view, view->current_page, region);
+ cairo_region_destroy (region);
+
+ g_signal_emit (view, signals[SIGNAL_ANNOT_ADDED], 0, annot);
+}
+
+void
+ev_view_focus_annotation (EvView *view,
+ EvMapping *annot_mapping)
+{
+ GdkRectangle view_rect;
+ EvAnnotation *annot;
+ guint page;
+
+ if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document))
+ return;
+
+ if (view->focus_annotation == annot_mapping)
+ return;
+
+ view->focus_annotation = annot_mapping;
+ annot = (EvAnnotation *)annot_mapping->data;
+
+ page = ev_annotation_get_page_index (annot);
+ ev_document_model_set_page (view->model, page);
+
+ doc_rect_to_view_rect (view, page,
+ &annot_mapping->area, &view_rect);
+ ensure_rectangle_is_visible (view, &view_rect);
+ gtk_widget_queue_draw (GTK_WIDGET (view));
+}
+
+void
+ev_view_begin_add_annotation (EvView *view,
+ EvAnnotationType annot_type)
+{
+ if (annot_type == EV_ANNOTATION_TYPE_UNKNOWN)
+ return;
+
+ if (view->adding_annot)
+ return;
+
+ view->adding_annot = TRUE;
+ view->adding_annot_type = annot_type;
+ ev_view_set_cursor (view, EV_VIEW_CURSOR_ADD);
+}
+
+void
+ev_view_cancel_add_annotation (EvView *view)
+{
+ gint x, y;
+
+ if (!view->adding_annot)
+ return;
+
+ view->adding_annot = FALSE;
+ gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
+ ev_view_handle_cursor_over_xy (view, x, y);
+}
+
+static gboolean
+ev_view_synctex_backward_search (EvView *view,
+ gdouble x,
+ gdouble y)
+{
+ gint page = -1;
+ gint x_new = 0, y_new = 0;
+ EvSourceLink *link;
+
+ if (!ev_document_has_synctex (view->document))
+ return FALSE;
+
+ if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
+ return FALSE;
+
+ link = ev_document_synctex_backward_search (view->document, page, x_new, y_new);
+ if (link) {
+ g_signal_emit (view, signals[SIGNAL_SYNC_SOURCE], 0, link);
+ g_free (link);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*** GtkWidget implementation ***/
+
+static void
+ev_view_size_request_continuous_dual_page (EvView *view,
+ GtkRequisition *requisition)
+{
+ gint n_pages;
+
+ n_pages = ev_document_get_n_pages (view->document) + 1;
+ get_page_y_offset (view, n_pages, &requisition->height);
+
+ switch (view->sizing_mode) {
+ case EV_SIZING_FIT_WIDTH:
+ case EV_SIZING_BEST_FIT:
+ requisition->width = 1;
+
+ break;
+ case EV_SIZING_FREE: {
+ gint max_width;
+ GtkBorder border;
+
+ ev_view_get_max_page_size (view, &max_width, NULL);
+ compute_border (view, max_width, max_width, &border);
+ requisition->width = (max_width + border.left + border.right) * 2 + (view->spacing * 3);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+ev_view_size_request_continuous (EvView *view,
+ GtkRequisition *requisition)
+{
+ gint n_pages;
+
+ n_pages = ev_document_get_n_pages (view->document);
+ get_page_y_offset (view, n_pages, &requisition->height);
+
+ switch (view->sizing_mode) {
+ case EV_SIZING_FIT_WIDTH:
+ case EV_SIZING_BEST_FIT:
+ requisition->width = 1;
+
+ break;
+ case EV_SIZING_FREE: {
+ gint max_width;
+ GtkBorder border;
+
+ ev_view_get_max_page_size (view, &max_width, NULL);
+ compute_border (view, max_width, max_width, &border);
+ requisition->width = max_width + (view->spacing * 2) + border.left + border.right;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+ev_view_size_request_dual_page (EvView *view,
+ GtkRequisition *requisition)
+{
+ GtkBorder border;
+ gint width, height;
+
+ if (view->sizing_mode == EV_SIZING_BEST_FIT) {
+ requisition->width = 1;
+ requisition->height = 1;
+
+ return;
+ }
+
+ /* Find the largest of the two. */
+ ev_view_get_page_size (view,
+ view->current_page,
+ &width, &height);
+ if (view->current_page + 1 < ev_document_get_n_pages (view->document)) {
+ gint width_2, height_2;
+ ev_view_get_page_size (view,
+ view->current_page + 1,
+ &width_2, &height_2);
+ if (width_2 > width) {
+ width = width_2;
+ height = height_2;
+ }
+ }
+ compute_border (view, width, height, &border);
+
+ requisition->width = view->sizing_mode == EV_SIZING_FIT_WIDTH ? 1 :
+ ((width + border.left + border.right) * 2) + (view->spacing * 3);
+ requisition->height = (height + border.top + border.bottom) + (view->spacing * 2);
+}
+
+static void
+ev_view_size_request_single_page (EvView *view,
+ GtkRequisition *requisition)
+{
+ GtkBorder border;
+ gint width, height;
+
+ if (view->sizing_mode == EV_SIZING_BEST_FIT) {
+ requisition->width = 1;
+ requisition->height = 1;
+
+ return;
+ }
+
+ ev_view_get_page_size (view, view->current_page, &width, &height);
+ compute_border (view, width, height, &border);
+
+ requisition->width = view->sizing_mode == EV_SIZING_FIT_WIDTH ? 1 :
+ width + border.left + border.right + (2 * view->spacing);
+ requisition->height = height + border.top + border.bottom + (2 * view->spacing);
+}
+
+static void
+ev_view_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ EvView *view = EV_VIEW (widget);
+
+ if (view->document == NULL) {
+ view->requisition.width = 1;
+ view->requisition.height = 1;
+
+ *requisition = view->requisition;
+
+ return;
+ }
+
+ /* Get zoom for size here when not called from
+ * ev_view_size_allocate()
+ */
+ if (!view->internal_size_request &&
+ (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
+ view->sizing_mode == EV_SIZING_BEST_FIT)) {
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation (widget, &allocation);
+ ev_view_zoom_for_size (view,
+ allocation.width,
+ allocation.height);
+ }
+
+ if (view->continuous && view->dual_page)
+ ev_view_size_request_continuous_dual_page (view, &view->requisition);
+ else if (view->continuous)
+ ev_view_size_request_continuous (view, &view->requisition);
+ else if (view->dual_page)
+ ev_view_size_request_dual_page (view, &view->requisition);
+ else
+ ev_view_size_request_single_page (view, &view->requisition);
+
+ *requisition = view->requisition;
+}
+
+static void
+ev_view_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ 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->document)
+ return;
+
+ if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
+ view->sizing_mode == EV_SIZING_BEST_FIT) {
+ GtkRequisition req;
+
+ ev_view_zoom_for_size (view,
+ allocation->width,
+ allocation->height);
+ view->internal_size_request = TRUE;
+ ev_view_size_request (widget, &req);
+ view->internal_size_request = FALSE;
+ }
+
+ view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
+ view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
+
+ if (view->document)
+ view_update_range_and_current_page (view);
+
+ view->pending_scroll = SCROLL_TO_KEEP_POSITION;
+ view->pending_resize = FALSE;
+ view->pending_point.x = 0;
+ view->pending_point.y = 0;
+
+ children = gtk_container_get_children (GTK_CONTAINER (widget));
+ for (l = children; l && l->data; l = g_list_next (l)) {
+ EvFormField *field;
+ GdkRectangle view_area;
+ EvMappingList *form_field_mapping;
+ GtkAllocation child_allocation;
+ GtkRequisition child_requisition;
+ GtkWidget *child = (GtkWidget *)l->data;
+
+ field = g_object_get_data (G_OBJECT (child), "form-field");
+ if (!field)
+ continue;
+
+ form_field_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
+ field->page->index);
+ 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 ||
+ child_requisition.height != view_area.height)
+ gtk_widget_set_size_request (child, view_area.width, view_area.height);
+
+ gtk_container_child_get (GTK_CONTAINER (widget),
+ child,
+ "x", &child_allocation.x,
+ "y", &child_allocation.y,
+ NULL);
+ if (child_allocation.x != view_area.x ||
+ child_allocation.y != view_area.y) {
+ gtk_layout_move (GTK_LAYOUT (widget), child, view_area.x, view_area.y);
+ }
+ }
+ 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;
+
+ ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (child->window), &doc_rect);
+ 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
+ev_view_realize (GtkWidget *widget)
+{
+ EvView *view = EV_VIEW (widget);
+ GdkWindow *bin_window;
+ GtkStyle *style;
+
+ if (GTK_WIDGET_CLASS (ev_view_parent_class)->realize)
+ (* GTK_WIDGET_CLASS (ev_view_parent_class)->realize) (widget);
+
+ bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view));
+ gdk_window_set_events (bin_window,
+ (gdk_window_get_events (bin_window) |
+ GDK_EXPOSURE_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_SCROLL_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_POINTER_MOTION_HINT_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK));
+
+ style = gtk_widget_get_style (widget);
+ gdk_window_set_background (bin_window, &style->mid[GTK_STATE_NORMAL]);
+
+ on_adjustment_value_changed (NULL, view);
+}
+
+static gboolean
+ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
+{
+ EvView *view = EV_VIEW (widget);
+ guint state;
+
+ state = event->state & gtk_accelerator_get_default_mod_mask ();
+
+ if (state == GDK_CONTROL_MASK) {
+ ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
+ if (event->direction == GDK_SCROLL_UP ||
+ event->direction == GDK_SCROLL_LEFT) {
+ if (ev_view_can_zoom_in (view)) {
+ ev_view_zoom_in (view);
+ }
+ } else {
+ if (ev_view_can_zoom_out (view)) {
+ ev_view_zoom_out (view);
+ }
+ }
+
+ 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)
+ event->direction = GDK_SCROLL_LEFT;
+ else if (event->direction == GDK_SCROLL_LEFT)
+ event->direction = GDK_SCROLL_UP;
+ else if (event->direction == GDK_SCROLL_DOWN)
+ event->direction = GDK_SCROLL_RIGHT;
+ else if (event->direction == GDK_SCROLL_RIGHT)
+ event->direction = GDK_SCROLL_DOWN;
+
+ event->state &= ~GDK_SHIFT_MASK;
+ state &= ~GDK_SHIFT_MASK;
+ }
+
+ if (state == 0 && view->sizing_mode == EV_SIZING_BEST_FIT && !view->continuous) {