summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--text.c107
1 files changed, 73 insertions, 34 deletions
diff --git a/text.c b/text.c
index 38ae0b1..187c301 100644
--- a/text.c
+++ b/text.c
@@ -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);
}