From d4f7d26a6179034637cb302b4850c8febd5df01a Mon Sep 17 00:00:00 2001 From: Aki Date: Wed, 15 Sep 2021 22:41:49 +0200 Subject: Added handler for hyperlink clicking --- text.c | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/text.c b/text.c index 256e804..9560edd 100644 --- a/text.c +++ b/text.c @@ -40,6 +40,7 @@ struct State int height; int pointer_x; int pointer_y; + int follow; // TODO: Rethink how pointer events are handled. xcb_connection_t * c; xcb_screen_t * s; xcb_visualtype_t * v; @@ -54,6 +55,7 @@ enum Actions ACTION_ARRANGE = 1 << 1, ACTION_CLOSE = 1 << 2, ACTION_POINTER = 1 << 3, + ACTION_CLICK = 1 << 4, }; struct Layout @@ -67,7 +69,7 @@ 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); +PangoAttribute * find_link_under(struct State *, PangoLayout *, PangoAttrList *, int, int); void arrange(struct State *, struct Layout *, union Command[]); void draw(struct State *, struct Layout *); PangoAttribute * attr_hyperlink_new(const char *); @@ -109,7 +111,7 @@ int main(int argc, const char ** argv) struct State state; if (-1 == setup(&state)) { - dprintf(2, "Could not connect to X server\n"); // TODO: Helpful (specific) errors. + dprintf(2, "Could not connect to X server\n"); return 1; } struct Layout layout = {.desc = NULL, .size = 0, .v = NULL}; @@ -120,10 +122,12 @@ int main(int argc, const char ** argv) int actions = handle(&state, e); // Obviously, right now this may have at most one action. if (ACTION_CLOSE & actions) break; - if ((ACTION_ARRANGE | ACTION_POINTER) & actions) // TODO: Separate implementation for pointer. + // TODO: Arranging, rearranging and (obviously) reacting to pointer events are all different things. + if ((ACTION_ARRANGE | ACTION_POINTER | ACTION_CLICK) & actions) arrange(&state, &layout, body); if ((ACTION_REDRAW | ACTION_POINTER) & actions) draw(&state, &layout); + state.follow = 0; } finalize(&state, &layout); } @@ -143,7 +147,7 @@ int setup(struct State * state) const uint32_t values[] = { state->s->white_pixel, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_POINTER_MOTION, + XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS, }; xcb_create_window( state->c, XCB_COPY_FROM_PARENT, state->w, state->s->root, 0, 0, initial_width, initial_height, 0, @@ -154,6 +158,7 @@ int setup(struct State * state) xcb_flush(state->c); state->pointer_x = 0; state->pointer_y = 0; + state->follow = 0; return 0; } @@ -188,6 +193,15 @@ int handle(struct State * state, xcb_generic_event_t * e) state->pointer_x = motion->event_x; state->pointer_y = motion->event_y; break; + case XCB_BUTTON_PRESS: + break; + case XCB_BUTTON_RELEASE: + ; + xcb_button_release_event_t * button = (xcb_button_release_event_t *) e; + if (1 == button->detail) + state->follow = 1; + actions |= ACTION_CLICK; + break; case XCB_CONFIGURE_NOTIFY: ; actions |= ACTION_ARRANGE; @@ -221,7 +235,7 @@ xcb_visualtype_t * find_visual(xcb_screen_t * screen) } -PangoAttribute * find_link_under(PangoLayout * layout, PangoAttrList * attrs, int x, int y) +PangoAttribute * find_link_under(struct State * state, PangoLayout * layout, PangoAttrList * attrs, int x, int y) { int index; int trailing; @@ -245,6 +259,13 @@ PangoAttribute * find_link_under(PangoLayout * layout, PangoAttrList * attrs, in attr = pango_attr_foreground_new(0xffff, 0x0000, 0x0000); attr->start_index = start; attr->end_index = end; + if (state->follow) + { + state->follow = 0; + PangoAttribute * link = pango_attr_iterator_get(iter, PANGO_CUSTOM_ATTR_HYPERLINK); + if (NULL != link) + printf("%s\n", ((PangoAttrString *) link)->value); + } goto done; } done: @@ -264,7 +285,7 @@ void arrange(struct State * state, struct Layout * layout, union Command body[]) if (size != layout->size) { for (int i = 0; i < layout->size; ++i) - g_object_unref(layout->v[i]); /// TODO-maybe: Reuse already existing layouts of blocks. + g_object_unref(layout->v[i]); layout->v = malloc(sizeof(PangoLayout *) * size); if (NULL == layout->v) abort(); // TODO: Be more graceful? @@ -280,18 +301,18 @@ void arrange(struct State * state, struct Layout * layout, union Command body[]) { case COMMAND_SPAN: ; - PangoAttribute * attr = pango_attr_foreground_new(0x0000, 0x0000, 0xffff); + PangoAttribute * 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); - attr = attr_hyperlink_new(c->span.uri); + attr = pango_attr_foreground_new(0x0000, 0x0000, 0xffff); attr->start_index = c->span.start; attr->end_index = c->span.end; pango_attr_list_change(attrs, attr); break; case COMMAND_BLOCK: ; - attr = find_link_under(layout->v[i], attrs, state->pointer_x - MARGIN, state->pointer_y - MARGIN); + attr = find_link_under(state, 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); -- cgit v1.1