diff options
-rw-r--r-- | text.c | 107 |
1 files changed, 73 insertions, 34 deletions
@@ -1,5 +1,6 @@ #include <stdint.h> #include <stdio.h> +#include <stdlib.h> #include <cairo.h> #include <cairo-xcb.h> @@ -40,21 +41,29 @@ struct State xcb_screen_t * s; xcb_visualtype_t * v; xcb_window_t w; - cairo_t * ctx; + cairo_t * ctx; // TODO-maybe: separate drawing context, application state and xcb state? cairo_surface_t * surface; }; enum Actions { ACTION_REDRAW = 1 << 0, - ACTION_RELAYOUT = 1 << 1, + ACTION_ARRANGE = 1 << 1, ACTION_CLOSE = 1 << 2, }; +struct Layout +{ + PangoFontDescription * desc; + int size; + PangoLayout ** v; +}; + int setup(struct State *); -void finalize(struct State *); +void finalize(struct State *, struct Layout *); int handle(struct State *, xcb_generic_event_t *); -void draw(struct State *, union Command *); +void arrange(struct State *, struct Layout *, union Command[]); +void draw(struct State *, struct Layout *); xcb_visualtype_t * find_visual(xcb_screen_t *); static const int MARGIN = 20; @@ -83,17 +92,20 @@ int main(int argc, const char ** argv) dprintf(2, "Could not connect to X server\n"); // TODO: Helpful (specific) errors. return 1; } + struct Layout layout = {.desc = NULL, .size = 0, .v = NULL}; + arrange(&state, &layout, body); for (;;) { xcb_generic_event_t * e = xcb_wait_for_event(state.c); // TODO: All events first, then flagged actions. int actions = handle(&state, e); // Obviously, right now this may have at most one action. if (ACTION_CLOSE & actions) break; - // if (ACTION_RELAYOUT & actions) TODO: Implement separate layouting. + if (ACTION_ARRANGE & actions) + arrange(&state, &layout, body); if (ACTION_REDRAW & actions) - draw(&state, body); + draw(&state, &layout); } - finalize(&state); + finalize(&state, &layout); } @@ -123,8 +135,12 @@ int setup(struct State * state) } -void finalize(struct State * state) +void finalize(struct State * state, struct Layout * layout) { + pango_font_description_free(layout->desc); + for (int i = 0; i < layout->size; ++i) + g_object_unref(layout->v[i]); + free(layout->v); cairo_destroy(state->ctx); cairo_surface_destroy(state->surface); xcb_disconnect(state->c); @@ -144,7 +160,7 @@ int handle(struct State * state, xcb_generic_event_t * e) break; case XCB_CONFIGURE_NOTIFY: ; - actions |= ACTION_RELAYOUT; + actions |= ACTION_ARRANGE; xcb_configure_notify_event_t * conf = (xcb_configure_notify_event_t *) e; if (state->width != conf->width || state->height != conf->height) { @@ -175,41 +191,47 @@ xcb_visualtype_t * find_visual(xcb_screen_t * screen) } -void draw(struct State * state, union Command * body) +void arrange(struct State * state, struct Layout * layout, union Command body[]) { - cairo_set_source_rgb(state->ctx, 1., 1., 1.); - cairo_paint(state->ctx); - PangoFontDescription * desc = pango_font_description_from_string(FONT); - cairo_set_source_rgb(state->ctx, 0., 0., 0.); - int y = MARGIN; - PangoAttrList * attrs = pango_attr_list_new(); // TODO: Store layouts and only relayout if needed. - for (union Command * command = body; COMMAND_DONE != command->type; ++command) + if (NULL == layout->desc) + layout->desc = pango_font_description_from_string(FONT); + int size = 0; + for (union Command * c = body; COMMAND_DONE != c->type; ++c) + if (COMMAND_BLOCK == c->type) + size++; + if (size != layout->size) { - switch (command->type) + for (int i = 0; i < layout->size; ++i) + g_object_unref(layout->v[i]); /// TODO-maybe: Reuse already existing layouts of blocks. + layout->v = malloc(sizeof(PangoLayout *) * size); + if (NULL == layout->v) + abort(); // TODO: Be more graceful? + for (int i = 0; i < size; ++i) + layout->v[i] = pango_cairo_create_layout(state->ctx); + layout->size = size; + } + PangoAttrList * attrs = pango_attr_list_new(); + int i = 0; + for (union Command * c = body; COMMAND_DONE != c->type; ++c) + { + switch (c->type) { case COMMAND_SPAN: ; PangoAttribute * attr = pango_attr_foreground_new(0x0000, 0x0000, 0xffff); - attr->start_index = command->span.position; - attr->end_index = command->span.position + command->span.length; + attr->start_index = c->span.position; + attr->end_index = c->span.position + c->span.length; pango_attr_list_change(attrs, attr); break; case COMMAND_BLOCK: - cairo_move_to(state->ctx, MARGIN, y); - PangoLayout * layout = pango_cairo_create_layout(state->ctx); - pango_layout_set_attributes(layout, attrs); + pango_layout_set_attributes(layout->v[i], attrs); // TODO-maybe: Don't reset everything? pango_attr_list_unref(attrs); attrs = pango_attr_list_new(); - pango_layout_set_font_description(layout, desc); - pango_layout_set_wrap(layout, PANGO_WRAP_WORD); - pango_layout_set_width(layout, (state->width - 2 * MARGIN) * PANGO_SCALE); - pango_layout_set_text(layout, command->block.data, command->block.length); - pango_cairo_update_layout(state->ctx, layout); - pango_cairo_show_layout(state->ctx, layout); - int height; - pango_layout_get_pixel_size(layout, NULL, &height); - y += height + MARGIN; - g_object_unref(layout); + pango_layout_set_font_description(layout->v[i], layout->desc); + pango_layout_set_wrap(layout->v[i], PANGO_WRAP_WORD); + pango_layout_set_width(layout->v[i], (state->width - 2 * MARGIN) * PANGO_SCALE); + pango_layout_set_text(layout->v[i], c->block.data, c->block.length); + i++; break; case COMMAND_NOTHING: default: @@ -217,7 +239,24 @@ void draw(struct State * state, union Command * body) } } pango_attr_list_unref(attrs); - pango_font_description_free(desc); +} + + +void draw(struct State * state, struct Layout * layout) +{ + cairo_set_source_rgb(state->ctx, 1., 1., 1.); + cairo_paint(state->ctx); + cairo_set_source_rgb(state->ctx, 0., 0., 0.); + int y = MARGIN; + for (int i = 0; i < layout->size; ++i) + { + cairo_move_to(state->ctx, MARGIN, y); + pango_cairo_update_layout(state->ctx, layout->v[i]); + pango_cairo_show_layout(state->ctx, layout->v[i]); + int height; + pango_layout_get_pixel_size(layout->v[i], NULL, &height); + y += height + MARGIN; + } cairo_surface_flush(state->surface); xcb_flush(state->c); } |