summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--text.c157
1 files changed, 87 insertions, 70 deletions
diff --git a/text.c b/text.c
index 9daedc0..8ad0d75 100644
--- a/text.c
+++ b/text.c
@@ -32,21 +32,27 @@ union Command
} span;
};
-int init_x(void);
-void draw_body(cairo_t *);
+struct State
+{
+ int width;
+ int height;
+ xcb_connection_t * c;
+ xcb_screen_t * s;
+ xcb_visualtype_t * v;
+ xcb_window_t w;
+ cairo_t * ctx;
+ cairo_surface_t * surface;
+};
+
+int setup(struct State *);
+void finalize(struct State *);
+int handle(struct State *, xcb_generic_event_t *);
+void draw_body(struct State *, union Command *);
xcb_visualtype_t * find_visual(xcb_screen_t *);
static const int MARGIN = 20;
static const char * const FONT = "Serif 16";
-static int width = 800;
-static int height = 600;
-
-static xcb_connection_t * c;
-static xcb_screen_t * s;
-static xcb_visualtype_t * v;
-static xcb_window_t w;
-
#define _BLOCK(_txt) {.block = {.type = COMMAND_BLOCK, .length = sizeof(_txt) - 1, .data = _txt}}
union Command body[] = {
{.span = {.type = COMMAND_SPAN, .position = 28, .length = 11}},
@@ -64,73 +70,84 @@ int main(int argc, const char ** argv)
{
(void) argc;
(void) argv;
- const int res = init_x();
- if (-1 == res)
+ struct State state;
+ if (-1 == setup(&state))
+ {
+ dprintf(2, "Could not connect to X server\n"); // TODO: Helpful (specific) errors.
return 1;
- cairo_surface_t * surface = cairo_xcb_surface_create(c, w, v, width, height);
- cairo_t * ctx = cairo_create(surface);
- xcb_map_window(c, w);
- xcb_flush(c);
- int done = 0;
- xcb_generic_event_t * e;
- while (!done)
+ }
+ for (;;)
{
- e = xcb_wait_for_event(c);
- if (NULL == e)
+ xcb_generic_event_t * e = xcb_wait_for_event(state.c); // TODO: Change it to poll-like behaviour.
+ if (handle(&state, e))
break;
- switch (XCB_EVENT_RESPONSE_TYPE(e))
- {
- default:
- break;
- case XCB_KEY_PRESS:
- done = 1;
- break;
- case XCB_EXPOSE:
- cairo_set_source_rgb(ctx, 1., 1., 1.);
- cairo_paint(ctx);
- draw_body(ctx);
- cairo_surface_flush(surface);
- xcb_flush(c);
- break;
- case XCB_CONFIGURE_NOTIFY:
- ;
- xcb_configure_notify_event_t * conf = (xcb_configure_notify_event_t *) e;
- if (width != conf->width || height != conf->height)
- {
- cairo_xcb_surface_set_size(surface, conf->width, conf->height);
- width = conf->width;
- height = conf->height;
- }
- break;
- }
- free(e);
}
- cairo_destroy(ctx);
- cairo_surface_destroy(surface);
- xcb_disconnect(c);
+ finalize(&state);
}
-int init_x(void)
+int setup(struct State * state)
{
- c = xcb_connect(NULL, NULL);
- if (xcb_connection_has_error(c))
- {
- dprintf(2, "Could not connect to X11 server");
+ static const int initial_width = 800;
+ static const int initial_height = 600;
+ state->c = xcb_connect(NULL, NULL);
+ if (xcb_connection_has_error(state->c))
return -1;
- }
- s = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
- w = xcb_generate_id(c);
- v = find_visual(s);
+ state->s = xcb_setup_roots_iterator(xcb_get_setup(state->c)).data;
+ state->w = xcb_generate_id(state->c);
+ state->v = find_visual(state->s);
const uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
const uint32_t values[] = {
- s->white_pixel,
+ state->s->white_pixel,
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_STRUCTURE_NOTIFY,
};
xcb_create_window(
- c, XCB_COPY_FROM_PARENT, w, s->root, 0, 0, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
- s->root_visual, mask, values);
- xcb_flush(c);
+ state->c, XCB_COPY_FROM_PARENT, state->w, state->s->root, 0, 0, initial_width, initial_height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, state->s->root_visual, mask, values);
+ state->surface = cairo_xcb_surface_create(state->c, state->w, state->v, initial_width, initial_height);
+ state->ctx = cairo_create(state->surface);
+ xcb_map_window(state->c, state->w);
+ xcb_flush(state->c);
+ return 0;
+}
+
+
+void finalize(struct State * state)
+{
+ cairo_destroy(state->ctx);
+ cairo_surface_destroy(state->surface);
+ xcb_disconnect(state->c);
+}
+
+
+int handle(struct State * state, xcb_generic_event_t * e)
+{
+ switch (XCB_EVENT_RESPONSE_TYPE(e))
+ {
+ case XCB_KEY_PRESS:
+ free(e);
+ return 1;
+ case XCB_EXPOSE:
+ cairo_set_source_rgb(state->ctx, 1., 1., 1.);
+ cairo_paint(state->ctx);
+ draw_body(state, body); // TODO: Redraw outside of handler and don't use global body.
+ cairo_surface_flush(state->surface);
+ xcb_flush(state->c);
+ break;
+ case XCB_CONFIGURE_NOTIFY:
+ ;
+ xcb_configure_notify_event_t * conf = (xcb_configure_notify_event_t *) e;
+ if (state->width != conf->width || state->height != conf->height)
+ {
+ cairo_xcb_surface_set_size(state->surface, conf->width, conf->height);
+ state->width = conf->width;
+ state->height = conf->height;
+ }
+ break;
+ default:
+ break;
+ }
+ free(e);
return 0;
}
@@ -149,10 +166,10 @@ xcb_visualtype_t * find_visual(xcb_screen_t * screen)
}
-void draw_body(cairo_t * ctx)
+void draw_body(struct State * state, union Command * body)
{
PangoFontDescription * desc = pango_font_description_from_string(FONT);
- cairo_set_source_rgb(ctx, 0., 0., 0.);
+ cairo_set_source_rgb(state->ctx, 0., 0., 0.);
int y = MARGIN;
PangoAttrList * attrs = pango_attr_list_new(); // TODO-maybe: Don't recreate attributes lists each redraw?
for (union Command * command = body; COMMAND_DONE != command->type; ++command)
@@ -167,17 +184,17 @@ void draw_body(cairo_t * ctx)
pango_attr_list_change(attrs, attr);
break;
case COMMAND_BLOCK:
- cairo_move_to(ctx, MARGIN, y);
- PangoLayout * layout = pango_cairo_create_layout(ctx);
+ cairo_move_to(state->ctx, MARGIN, y);
+ PangoLayout * layout = pango_cairo_create_layout(state->ctx);
pango_layout_set_attributes(layout, attrs);
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, (width - 2 * MARGIN) * PANGO_SCALE);
+ 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(ctx, layout);
- pango_cairo_show_layout(ctx, layout);
+ 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;