From 80722aeda0df83efa844e72e44b94c2d7f676b74 Mon Sep 17 00:00:00 2001 From: Aki Date: Tue, 14 Sep 2021 22:31:01 +0200 Subject: Added custom pango attribute to store uri --- text.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/text.c b/text.c index 24cfb3e..256e804 100644 --- a/text.c +++ b/text.c @@ -28,8 +28,9 @@ union Command } block; struct { int type; - int position; - int length; + int start; + int end; + const char * uri; } span; }; @@ -65,20 +66,29 @@ struct Layout int setup(struct State *); void finalize(struct State *, struct Layout *); int handle(struct State *, xcb_generic_event_t *); +xcb_visualtype_t * find_visual(xcb_screen_t *); +PangoAttribute * find_link_under(PangoLayout *, PangoAttrList *, int, int); void arrange(struct State *, struct Layout *, union Command[]); void draw(struct State *, struct Layout *); -xcb_visualtype_t * find_visual(xcb_screen_t *); +PangoAttribute * attr_hyperlink_new(const char *); +PangoAttribute * attr_string_copy(const PangoAttribute *); +void attr_string_destroy(PangoAttribute *); +gboolean attr_string_equal(const PangoAttribute *, const PangoAttribute *); +PangoAttribute * attr_string_new(const PangoAttrClass *, const char *); static const int MARGIN = 20; static const char * const FONT = "Serif 16"; +static PangoAttrType PANGO_CUSTOM_ATTR_HYPERLINK; +static PangoAttrClass hyperlink_klass; // TODO: Separate almost-pango-internals somewhere to minimize clutter. #define _BLOCK(_txt) {.block = {.type = COMMAND_BLOCK, .length = sizeof(_txt) - 1, .data = _txt}} union Command body[] = { - {.span = {.type = COMMAND_SPAN, .position = 28, .length = 11}}, + {.span = {.type = COMMAND_SPAN, .start = 28, .end = 39, .uri = "https://ignore.pl/consectetur"}}, _BLOCK( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam auctor porta eros at tempus. Aliquam " "elementum lectus id mi fermentum, non consectetur urna lobortis." ), + {.span = {.type = COMMAND_SPAN, .start = 10, .end = 19, .uri = "https://ignore.pl/dignissim"}}, _BLOCK("Phasellus dignissim rhoncus magna at imperdiet."), {.type = COMMAND_DONE}, }; @@ -89,6 +99,13 @@ int main(int argc, const char ** argv) { (void) argc; (void) argv; + PANGO_CUSTOM_ATTR_HYPERLINK = pango_attr_type_register("hyperlink"); + hyperlink_klass = (PangoAttrClass){ + PANGO_CUSTOM_ATTR_HYPERLINK, + attr_string_copy, + attr_string_destroy, + attr_string_equal, + }; struct State state; if (-1 == setup(&state)) { @@ -264,8 +281,12 @@ void arrange(struct State * state, struct Layout * layout, union Command body[]) case COMMAND_SPAN: ; PangoAttribute * attr = pango_attr_foreground_new(0x0000, 0x0000, 0xffff); - attr->start_index = c->span.position; - attr->end_index = c->span.position + c->span.length; + attr->start_index = c->span.start; + attr->end_index = c->span.end; + pango_attr_list_change(attrs, attr); + attr = attr_hyperlink_new(c->span.uri); + attr->start_index = c->span.start; + attr->end_index = c->span.end; pango_attr_list_change(attrs, attr); break; case COMMAND_BLOCK: @@ -273,7 +294,7 @@ void arrange(struct State * state, struct Layout * layout, union Command body[]) attr = find_link_under(layout->v[i], attrs, state->pointer_x - MARGIN, state->pointer_y - MARGIN); if (NULL != attr) pango_attr_list_change(attrs, attr); - pango_layout_set_attributes(layout->v[i], attrs); // TODO-maybe: Don't reset everything? + pango_layout_set_attributes(layout->v[i], attrs); pango_attr_list_unref(attrs); attrs = pango_attr_list_new(); pango_layout_set_font_description(layout->v[i], layout->desc); @@ -309,3 +330,38 @@ void draw(struct State * state, struct Layout * layout) cairo_surface_flush(state->surface); xcb_flush(state->c); } + + +PangoAttribute * attr_hyperlink_new(const char * uri) +{ + return attr_string_new(&hyperlink_klass, uri); +} + + +PangoAttribute * attr_string_copy(const PangoAttribute * src) +{ + return attr_string_new(src->klass, ((PangoAttrString *) src)->value); +} + + +void attr_string_destroy(PangoAttribute * attr) +{ + PangoAttrString * str = (PangoAttrString *) attr; + g_free(str->value); + g_slice_free(PangoAttrString, str); +} + + +gboolean attr_string_equal(const PangoAttribute * lhs, const PangoAttribute * rhs) +{ + return 0 == strcmp(((PangoAttrString *) lhs)->value, ((PangoAttrString *) rhs)->value); +} + + +PangoAttribute * attr_string_new(const PangoAttrClass * klass, const char * uri) +{ + PangoAttrString * str = g_slice_new(PangoAttrString); + pango_attribute_init(&str->attr, klass); + str->value = g_strdup(uri); + return (PangoAttribute *) str; +} -- cgit v1.1