diff --git a/meson.build b/meson.build index 0476cf1..73978a8 100644 --- a/meson.build +++ b/meson.build @@ -14,8 +14,8 @@ version_array = version.split('.') # * If any of the exported datastructures have changed in a incompatible way # bump SOMAJOR and set SOMINOR to 0. # * If a function has been added bump SOMINOR. -plugin_api_version = '3' -plugin_abi_version = '4' +plugin_api_version = '4' +plugin_abi_version = '5' conf_data = configuration_data() conf_data.set('ZVMAJOR', version_array[0]) diff --git a/zathura/page-widget.c b/zathura/page-widget.c index f38249a..643cc9e 100644 --- a/zathura/page-widget.c +++ b/zathura/page-widget.c @@ -38,6 +38,12 @@ typedef struct zathura_page_widget_private_s { gboolean draw; /**< Draw search results */ } search; + struct { + girara_list_t *list; /**< List of selection rectangles that should be drawn */ + zathura_rectangle_t bounds; /** Bounds of highlighted selection */ + gboolean draw; /** Used to clear previous selection */ + } selection; + struct { girara_list_t* list; /**< List of images on the page */ gboolean retrieved; /**< True if we already tried to retrieve the list of images */ @@ -617,13 +623,14 @@ zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo) ++idx; ); } - /* draw selection */ - if (priv->mouse.selection.y2 != -1 && priv->mouse.selection.x2 != -1) { + if (priv->selection.list != NULL && priv->selection.draw == true) { const GdkRGBA color = priv->zathura->ui.colors.highlight_color; cairo_set_source_rgba(cairo, color.red, color.green, color.blue, transparency); - cairo_rectangle(cairo, priv->mouse.selection.x1, priv->mouse.selection.y1, - (priv->mouse.selection.x2 - priv->mouse.selection.x1), (priv->mouse.selection.y2 - priv->mouse.selection.y1)); - cairo_fill(cairo); + GIRARA_LIST_FOREACH_BODY(priv->selection.list, zathura_rectangle_t*, rect, + zathura_rectangle_t rectangle = recalc_rectangle(priv->page, *rect); + cairo_rectangle(cairo, rectangle.x1, rectangle.y1, rectangle.x2 - rectangle.x1, rectangle.y2 - rectangle.y1); + cairo_fill(cairo); + ); } } else { /* set background color */ @@ -881,6 +888,11 @@ cb_zathura_page_widget_button_press_event(GtkWidget* widget, GdkEventButton* but return true; } + if (priv->selection.list != NULL) { + priv->selection.draw = false; + redraw_rect(page, &priv->selection.bounds); + } + if (button->button == GDK_BUTTON_PRIMARY) { /* left click */ if (button->type == GDK_BUTTON_PRESS) { /* start the selection */ @@ -891,6 +903,7 @@ cb_zathura_page_widget_button_press_event(GtkWidget* widget, GdkEventButton* but priv->mouse.selection.y1 = button->y; priv->mouse.selection.x2 = button->x; priv->mouse.selection.y2 = button->y; + } else if (button->type == GDK_2BUTTON_PRESS || button->type == GDK_3BUTTON_PRESS) { /* abort the selection */ priv->mouse.selection_basepoint.x = -1; @@ -962,8 +975,6 @@ cb_zathura_page_widget_button_release_event(GtkWidget* widget, GdkEventButton* b ); } } else { - redraw_rect(ZATHURA_PAGE(widget), &priv->mouse.selection); - zathura_rectangle_t tmp = priv->mouse.selection; tmp.x1 /= scale; @@ -999,6 +1010,9 @@ cb_zathura_page_widget_motion_notify(GtkWidget* widget, GdkEventMotion* event) ZathuraPage* page = ZATHURA_PAGE(widget); ZathuraPagePrivate* priv = zathura_page_widget_get_instance_private(page); + zathura_document_t* document = zathura_page_get_document(priv->page); + const double scale = zathura_document_get_scale(document); + if ((event->state & GDK_BUTTON1_MASK) == 0) { if (priv->links.retrieved == false) { priv->links.list = zathura_page_links_get(priv->page, NULL); @@ -1029,24 +1043,51 @@ cb_zathura_page_widget_motion_notify(GtkWidget* widget, GdkEventMotion* event) return false; } - zathura_rectangle_t tmp = priv->mouse.selection; - if (event->x < priv->mouse.selection_basepoint.x) { - tmp.x1 = event->x; - tmp.x2 = priv->mouse.selection_basepoint.x; - } else { - tmp.x2 = event->x; - tmp.x1 = priv->mouse.selection_basepoint.x; - } - if (event->y < priv->mouse.selection_basepoint.y) { - tmp.y1 = event->y; - tmp.y2 = priv->mouse.selection_basepoint.y; - } else { - tmp.y1 = priv->mouse.selection_basepoint.y; - tmp.y2 = event->y; + const zathura_rectangle_t tmp = { + priv->mouse.selection_basepoint.x, + priv->mouse.selection_basepoint.y, + event->x, + event->y + }; + + if (priv->selection.list != NULL) { + girara_list_free(priv->selection.list); } - redraw_rect(ZATHURA_PAGE(widget), &priv->mouse.selection); - redraw_rect(ZATHURA_PAGE(widget), &tmp); + zathura_rectangle_t scaled_mouse_selection = tmp; + + scaled_mouse_selection.x1 /= scale; + scaled_mouse_selection.x2 /= scale; + scaled_mouse_selection.y1 /= scale; + scaled_mouse_selection.y2 /= scale; + + const unsigned int page_width = gtk_widget_get_allocated_width(widget); + float y1, y2; + + if (tmp.y1 < tmp.y2) { + y1 = tmp.y1; + y2 = tmp.y2; + } else { + y1 = tmp.y2; + y2 = tmp.y1; + } + zathura_rectangle_t redraw_bounds = {0, y1, page_width, y2}; + priv->selection.list = zathura_page_get_selection(priv->page, scaled_mouse_selection, NULL); + + priv->selection.list = zathura_page_get_selection(priv->page, scaled_mouse_selection, NULL); + if (priv->selection.list != NULL && girara_list_size(priv->selection.list) != 0) { + GIRARA_LIST_FOREACH_BODY(priv->selection.list, zathura_rectangle_t*, rect, + redraw_bounds.y1 = fmin(rect->y1 * scale, redraw_bounds.y1); + redraw_bounds.y2 = fmax(rect->y2 * scale, redraw_bounds.y2); + ); + + priv->selection.draw = false; + redraw_rect(page, &priv->selection.bounds); + priv->selection.draw = true; + redraw_rect(page, &redraw_bounds); + + priv->selection.bounds = redraw_bounds; + } priv->mouse.selection = tmp; return false; @@ -1059,6 +1100,10 @@ cb_zathura_page_widget_leave_notify(GtkWidget* widget, GdkEventCrossing* UNUSED( ZathuraPage* page = ZATHURA_PAGE(widget); ZathuraPagePrivate* priv = zathura_page_widget_get_instance_private(page); + if (priv->selection.list != NULL) { + priv->selection.draw = false; + redraw_rect(page, &priv->selection.bounds); + } if (priv->mouse.over_link == true) { g_signal_emit(ZATHURA_PAGE(widget), signals[LEAVE_LINK], 0); priv->mouse.over_link = false; diff --git a/zathura/page.c b/zathura/page.c index 1a28951..8c7be99 100644 --- a/zathura/page.c +++ b/zathura/page.c @@ -344,6 +344,28 @@ zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathu return functions->page_get_text(page, page->data, rectangle, error); } +girara_list_t* +zathura_page_get_selection(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_error_t* error) +{ + if (page == NULL || page->document == NULL ) { + if (error) { + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; + } + return NULL; + } + + zathura_plugin_t* plugin = zathura_document_get_plugin(page->document); + const zathura_plugin_functions_t* functions = zathura_plugin_get_functions(plugin); + if (functions->page_get_selection == NULL) { + if (error) { + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; + } + return NULL; + } + + return functions->page_get_selection(page, page->data, rectangle, error); +} + zathura_error_t zathura_page_render(zathura_page_t* page, cairo_t* cairo, bool printing) { diff --git a/zathura/page.h b/zathura/page.h index 572157e..da14278 100644 --- a/zathura/page.h +++ b/zathura/page.h @@ -192,6 +192,16 @@ ZATHURA_PLUGIN_API cairo_surface_t* zathura_page_image_get_cairo(zathura_page_t* */ ZATHURA_PLUGIN_API char* zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_error_t* error); +/** + * Get rectangles from selection + * @param page Page + * @param rectangle Selection + * @param error Set to an error value (see \ref zathura_error_t) if an error + * occurred + * @return List of rectangles or NULL if an error occurred + */ +ZATHURA_PLUGIN_API girara_list_t* zathura_page_get_selection(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_error_t* error); + /** * Render page * diff --git a/zathura/plugin-api.h b/zathura/plugin-api.h index 9077927..c090918 100644 --- a/zathura/plugin-api.h +++ b/zathura/plugin-api.h @@ -88,6 +88,11 @@ typedef cairo_surface_t* (*zathura_plugin_page_image_get_cairo_t)(zathura_page_t */ typedef char* (*zathura_plugin_page_get_text_t)(zathura_page_t* page, void* data, zathura_rectangle_t rectangle, zathura_error_t* error); +/** + * Get rectangles from selection + */ +typedef girara_list_t* (*zathura_plugin_page_get_selection_t)(zathura_page_t* page, void* data, zathura_rectangle_t rectangle, zathura_error_t* error); + /** * Renders the page */ @@ -181,6 +186,11 @@ struct zathura_plugin_functions_s */ zathura_plugin_page_get_text_t page_get_text; + /** + * Get text for selection + */ + zathura_plugin_page_get_selection_t page_get_selection; + /** * Renders the page */