From 7aab504350102b1a1ed6dd18a96937ae24d22fdf Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 23 Jun 2008 13:09:42 +0200 Subject: [PATCH] draw: store parser_data made by extents call Signed-off-by: Julien Danjou --- common/draw.c | 120 ++++++++++++++++++++++----------------------- common/draw.h | 25 +++++++++- mouse.c | 26 ++++++---- widgets/taglist.c | 9 ++-- widgets/tasklist.c | 14 +++--- widgets/textbox.c | 9 ++-- 6 files changed, 117 insertions(+), 86 deletions(-) diff --git a/common/draw.c b/common/draw.c index 2c514669..25bd64f2 100644 --- a/common/draw.c +++ b/common/draw.c @@ -197,26 +197,6 @@ draw_font_delete(font_t **font) } } -typedef struct -{ - xcb_connection_t *connection; - int phys_screen; - buffer_t text; - alignment_t align; - struct - { - int left, right; - } margin; - bool has_bg_color; - xcolor_t bg_color; - draw_image_t *bg_image; - struct - { - int offset; - xcolor_t color; - } shadow; -} draw_parser_data_t; - static void draw_markup_on_event(markup_parser_data_t *p, const char *elem, const char **names, const char **values) @@ -266,7 +246,8 @@ draw_text_markup_expand(draw_parser_data_t *data, const char *str, ssize_t slen) { static char const * const elements[] = { "bg", "text", "margin", NULL }; - markup_parser_data_t p = { + markup_parser_data_t p = + { .elements = elements, .priv = data, .on_element = &draw_markup_on_event, @@ -293,54 +274,65 @@ draw_text_markup_expand(draw_parser_data_t *data, * \param font The font to use. * \param area Area to draw to. * \param text Text to draw. + * \param data Optional parser data. */ void draw_text(draw_context_t *ctx, font_t *font, - area_t area, const char *text) + area_t area, const char *text, draw_parser_data_t *pdata) { int x, y; - ssize_t len, olen; + ssize_t len = 0, olen; PangoRectangle ext; draw_parser_data_t parser_data; if(!(len = a_strlen(text))) return; - p_clear(&parser_data, 1); - parser_data.connection = ctx->connection; - parser_data.phys_screen = ctx->phys_screen; - if(draw_text_markup_expand(&parser_data, text, len)) { - text = parser_data.text.s; - len = parser_data.text.len; + if(!pdata) + { + p_clear(&parser_data, 1); + parser_data.connection = ctx->connection; + parser_data.phys_screen = ctx->phys_screen; + if(draw_text_markup_expand(&parser_data, text, len)) + { + text = parser_data.text.s; + len = parser_data.text.len; + } + pdata = &parser_data; + } + else + { + text = pdata->text.s; + len = pdata->text.len; } olen = len; - if(parser_data.has_bg_color) - draw_rectangle(ctx, area, 1.0, true, parser_data.bg_color); + if(pdata->has_bg_color) + draw_rectangle(ctx, area, 1.0, true, pdata->bg_color); - if(parser_data.bg_image) + if(pdata->bg_image) { - draw_image(ctx, area.x, area.y, 0, parser_data.bg_image); - draw_image_delete(&parser_data.bg_image); + draw_image(ctx, area.x, area.y, 0, pdata->bg_image); + draw_image_delete(&pdata->bg_image); } pango_layout_set_width(ctx->layout, pango_units_from_double(area.width - - (parser_data.margin.left - + parser_data.margin.right))); + - (pdata->margin.left + + pdata->margin.right))); pango_layout_set_ellipsize(ctx->layout, PANGO_ELLIPSIZE_END); pango_layout_set_markup(ctx->layout, text, len); pango_layout_set_font_description(ctx->layout, font->desc); pango_layout_get_pixel_extents(ctx->layout, NULL, &ext); - x = area.x + parser_data.margin.left; + x = area.x + pdata->margin.left; /* + 1 is added for rounding, so that in any case of doubt we rather draw * the text 1px lower than too high which usually results in a better type * face */ y = area.y + (ctx->height - font->height + 1) / 2; - switch(parser_data.align) + switch(pdata->align) { case AlignCenter: x += (area.width - ext.width) / 2; @@ -352,14 +344,14 @@ draw_text(draw_context_t *ctx, font_t *font, break; } - if(parser_data.shadow.offset) + if(pdata->shadow.offset) { cairo_set_source_rgba(ctx->cr, - parser_data.shadow.color.red / 65535.0, - parser_data.shadow.color.green / 65535.0, - parser_data.shadow.color.blue / 65535.0, - parser_data.shadow.color.alpha / 65535.0); - cairo_move_to(ctx->cr, x + parser_data.shadow.offset, y + parser_data.shadow.offset); + pdata->shadow.color.red / 65535.0, + pdata->shadow.color.green / 65535.0, + pdata->shadow.color.blue / 65535.0, + pdata->shadow.color.alpha / 65535.0); + cairo_move_to(ctx->cr, x + pdata->shadow.offset, y + pdata->shadow.offset); pango_cairo_update_layout(ctx->cr, ctx->layout); pango_cairo_show_layout(ctx->cr, ctx->layout); } @@ -374,7 +366,7 @@ draw_text(draw_context_t *ctx, font_t *font, pango_cairo_update_layout(ctx->cr, ctx->layout); pango_cairo_show_layout(ctx->cr, ctx->layout); - buffer_wipe(&parser_data.text); + buffer_wipe(&pdata->text); } /** Setup color-source for cairo (gradient or mono). @@ -963,10 +955,11 @@ draw_rotate(draw_context_t *ctx, * \param phys_screen Physical screen number. * \param font Font to use. * \param text The text. + * \param pdata The parser data to fill. * \return Text height and width. */ area_t -draw_text_extents(xcb_connection_t *conn, int phys_screen, font_t *font, const char *text) +draw_text_extents(xcb_connection_t *conn, int phys_screen, font_t *font, const char *text, draw_parser_data_t *parser_data) { cairo_surface_t *surface; cairo_t *cr; @@ -975,17 +968,18 @@ draw_text_extents(xcb_connection_t *conn, int phys_screen, font_t *font, const c xcb_screen_t *s = xutil_screen_get(conn, phys_screen); area_t geom = { 0, 0, 0, 0 }; ssize_t len; - draw_parser_data_t parser_data; + + p_clear(parser_data, 1); if(!(len = a_strlen(text))) return geom; - p_clear(&parser_data, 1); - parser_data.connection = conn; - parser_data.phys_screen = phys_screen; - if(draw_text_markup_expand(&parser_data, text, len)) { - text = parser_data.text.s; - len = parser_data.text.len; + parser_data->connection = conn; + parser_data->phys_screen = phys_screen; + if(draw_text_markup_expand(parser_data, text, len)) + { + text = parser_data->text.s; + len = parser_data->text.len; } surface = cairo_xcb_surface_create(conn, phys_screen, @@ -1005,7 +999,6 @@ draw_text_extents(xcb_connection_t *conn, int phys_screen, font_t *font, const c geom.width = ext.width; geom.height = ext.height * 1.5; - buffer_wipe(&parser_data.text); return geom; } @@ -1018,7 +1011,8 @@ draw_text_extents(xcb_connection_t *conn, int phys_screen, font_t *font, const c alignment_t draw_align_get_from_str(const char *align) { - switch (a_tokenize(align, -1)) { + switch (a_tokenize(align, -1)) + { case A_TK_LEFT: return AlignLeft; case A_TK_CENTER: return AlignCenter; case A_TK_RIGHT: return AlignRight; @@ -1143,8 +1137,7 @@ area_array_remove(area_array_t *areas, area_t elem) * (1) we remove elements ; * (2) the one we add to the end are okay wrt the invariants */ - for (int i = areas->len - 1; i >= 0; i--) - { + for(int i = areas->len - 1; i >= 0; i--) if(area_intersect_area(areas->tab[i], elem)) { /* remove it from the list */ @@ -1153,7 +1146,8 @@ area_array_remove(area_array_t *areas, area_t elem) if(AREA_LEFT(inter) > AREA_LEFT(r)) { - area_t extra = { + area_t extra = + { .x = r.x, .y = r.y, .width = AREA_LEFT(inter) - r.x, @@ -1164,7 +1158,8 @@ area_array_remove(area_array_t *areas, area_t elem) if(AREA_TOP(inter) > AREA_TOP(r)) { - area_t extra = { + area_t extra = + { .x = r.x, .y = r.y, .width = r.width, @@ -1175,7 +1170,8 @@ area_array_remove(area_array_t *areas, area_t elem) if(AREA_RIGHT(inter) < AREA_RIGHT(r)) { - area_t extra = { + area_t extra = + { .x = AREA_RIGHT(inter), .y = r.y, .width = AREA_RIGHT(r) - AREA_RIGHT(inter), @@ -1186,7 +1182,8 @@ area_array_remove(area_array_t *areas, area_t elem) if(AREA_BOTTOM(inter) < AREA_BOTTOM(r)) { - area_t extra = { + area_t extra = + { .x = r.x, .y = AREA_BOTTOM(inter), .width = r.width, @@ -1195,7 +1192,6 @@ area_array_remove(area_array_t *areas, area_t elem) area_array_append(areas, extra); } } - } } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/common/draw.h b/common/draw.h index cf1434cf..edb85d5f 100644 --- a/common/draw.h +++ b/common/draw.h @@ -29,6 +29,7 @@ #include "common/array.h" #include "common/list.h" +#include "common/buffer.h" typedef struct { @@ -153,7 +154,27 @@ a_iso2utf8(const char *str, char **res) return false; } -void draw_text(draw_context_t *, font_t *, area_t, const char *); +typedef struct +{ + xcb_connection_t *connection; + int phys_screen; + buffer_t text; + alignment_t align; + struct + { + int left, right; + } margin; + bool has_bg_color; + xcolor_t bg_color; + draw_image_t *bg_image; + struct + { + int offset; + xcolor_t color; + } shadow; +} draw_parser_data_t; + +void draw_text(draw_context_t *, font_t *, area_t, const char *, draw_parser_data_t *); void draw_rectangle(draw_context_t *, area_t, float, bool, xcolor_t); void draw_rectangle_gradient(draw_context_t *, area_t, float, bool, area_t, xcolor_t *, xcolor_t *, xcolor_t *); @@ -166,7 +187,7 @@ void draw_image_delete(draw_image_t **); void draw_image(draw_context_t *, int, int, int, draw_image_t *); void draw_image_from_argb_data(draw_context_t *, int, int, int, int, int, unsigned char *); void draw_rotate(draw_context_t *, xcb_drawable_t, xcb_drawable_t, int, int, int, int, double, int, int); -area_t draw_text_extents(xcb_connection_t *, int, font_t *, const char *); +area_t draw_text_extents(xcb_connection_t *, int, font_t *, const char *, draw_parser_data_t *); alignment_t draw_align_get_from_str(const char *); bool xcolor_new(xcb_connection_t *, int, const char *, xcolor_t *); diff --git a/mouse.c b/mouse.c index 94843c72..17c7f446 100644 --- a/mouse.c +++ b/mouse.c @@ -234,12 +234,14 @@ mouse_snap_to_corner(area_t a, int *x, int *y, corner_t corner) /** Redraw the infobox. * \param ctx Draw context. * \param sw The simple window. + * \param pdata The draw parser data. * \param geometry The geometry to use for the box. * \param border The client border size. */ static void mouse_infobox_draw(draw_context_t *ctx, simple_window_t *sw, + draw_parser_data_t *pdata, area_t geometry, int border) { area_t draw_geometry = { 0, 0, ctx->width, ctx->height }; @@ -248,7 +250,7 @@ mouse_infobox_draw(draw_context_t *ctx, snprintf(size, sizeof(size), "%dx%d+%d+%d", geometry.width, geometry.height, geometry.x, geometry.y); draw_rectangle(ctx, draw_geometry, 1.0, true, globalconf.colors.bg); - draw_text(ctx, globalconf.font, draw_geometry, size); + draw_text(ctx, globalconf.font, draw_geometry, size, pdata); simplewindow_move(sw, geometry.x + ((2 * border + geometry.width) - sw->geometry.width) / 2, geometry.y + ((2 * border + geometry.height) - sw->geometry.height) / 2); @@ -260,11 +262,12 @@ mouse_infobox_draw(draw_context_t *ctx, * \param border Border size of the client. * \param geometry Client geometry. * \param ctx Draw context to create. + * \param pdata The draw parser data to fill. * \return The simple window. */ static simple_window_t * mouse_infobox_new(int phys_screen, int border, area_t geometry, - draw_context_t **ctx) + draw_context_t **ctx, draw_parser_data_t *pdata) { simple_window_t *sw; area_t geom; @@ -272,7 +275,7 @@ mouse_infobox_new(int phys_screen, int border, area_t geometry, geom = draw_text_extents(globalconf.connection, globalconf.default_screen, globalconf.font, - "0000x0000+0000+0000"); + "0000x0000+0000+0000", pdata); geom.x = geometry.x + ((2 * border + geometry.width) - geom.width) / 2; geom.y = geometry.y + ((2 * border + geometry.height) - geom.height) / 2; @@ -287,7 +290,7 @@ mouse_infobox_new(int phys_screen, int border, area_t geometry, globalconf.colors.bg); xcb_map_window(globalconf.connection, sw->window); - mouse_infobox_draw(*ctx, sw, geometry, border); + mouse_infobox_draw(*ctx, sw, pdata, geometry, border); return sw; } @@ -458,6 +461,7 @@ mouse_client_move(client_t *c, int snap, bool infobox) draw_context_t *ctx; /* the root window */ xcb_window_t root; + draw_parser_data_t pdata; layout = layout_get_current(c->screen); root = xutil_screen_get(globalconf.connection, c->phys_screen)->root; @@ -472,7 +476,7 @@ mouse_client_move(client_t *c, int snap, bool infobox) if(infobox && (c->isfloating || layout == layout_floating)) { - sw = mouse_infobox_new(c->phys_screen, c->border, c->geometry, &ctx); + sw = mouse_infobox_new(c->phys_screen, c->border, c->geometry, &ctx, &pdata); xcb_aux_sync(globalconf.connection); } @@ -497,7 +501,7 @@ mouse_client_move(client_t *c, int snap, bool infobox) /* draw the infobox */ if(sw) { - mouse_infobox_draw(ctx, sw, c->geometry, c->border); + mouse_infobox_draw(ctx, sw, &pdata, c->geometry, c->border); xcb_aux_sync(globalconf.connection); } @@ -566,6 +570,7 @@ mouse_client_resize_floating(client_t *c, corner_t corner, bool infobox) draw_context_t *ctx; size_t cursor = CurResize; int top, bottom, left, right; + draw_parser_data_t pdata; screen = xutil_screen_get(globalconf.connection, c->phys_screen); @@ -611,7 +616,7 @@ mouse_client_resize_floating(client_t *c, corner_t corner, bool infobox) /* create the infobox */ if(infobox) { - sw = mouse_infobox_new(c->phys_screen, c->border, c->geometry, &ctx); + sw = mouse_infobox_new(c->phys_screen, c->border, c->geometry, &ctx, &pdata); xcb_aux_sync(globalconf.connection); } @@ -685,7 +690,7 @@ mouse_client_resize_floating(client_t *c, corner_t corner, bool infobox) /* draw the infobox */ if(sw) - mouse_infobox_draw(ctx, sw, c->geometry, c->border); + mouse_infobox_draw(ctx, sw, &pdata, c->geometry, c->border); xcb_aux_sync(globalconf.connection); } @@ -822,6 +827,7 @@ mouse_client_resize_magnified(client_t *c, bool infobox) simple_window_t *sw = NULL; draw_context_t *ctx; xcb_window_t root; + draw_parser_data_t pdata; tag = tags_get_current(c->screen)[0]; @@ -867,7 +873,7 @@ mouse_client_resize_magnified(client_t *c, bool infobox) /* create the infobox */ if(infobox) - sw = mouse_infobox_new(c->phys_screen, c->border, c->geometry, &ctx); + sw = mouse_infobox_new(c->phys_screen, c->border, c->geometry, &ctx, &pdata); xcb_aux_sync(globalconf.connection); @@ -899,7 +905,7 @@ mouse_client_resize_magnified(client_t *c, bool infobox) /* draw the infobox */ if(sw) { - mouse_infobox_draw(ctx, sw, c->geometry, c->border); + mouse_infobox_draw(ctx, sw, &pdata, c->geometry, c->border); xcb_aux_sync(globalconf.connection); } } diff --git a/widgets/taglist.c b/widgets/taglist.c index a7ea02f2..e53cbc93 100644 --- a/widgets/taglist.c +++ b/widgets/taglist.c @@ -141,6 +141,7 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, area_t area, rectangle = { 0, 0, 0, 0 }; char **text = NULL; taglist_drawn_area_t *tda; + draw_parser_data_t *pdata = NULL; w->area.width = w->area.y = 0; @@ -163,10 +164,11 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, for(tag = vscreen->tags; tag; tag = tag->next, i++) { p_realloc(&text, i + 1); + p_realloc(&pdata, i + 1); text[i] = taglist_text_get(tag, data); text[i] = tag_markup_parse(tag, text[i], a_strlen(text[i])); area = draw_text_extents(ctx->connection, ctx->phys_screen, - globalconf.font, text[i]); + globalconf.font, text[i], &pdata[i]); if (data->show_empty || tag->selected || tag_isoccupied(tag)) w->area.width += area.width; @@ -182,7 +184,7 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, { area_t *r = &tda->areas.tab[i]; - if (!data->show_empty && !tag->selected && !tag_isoccupied(tag)) + if(!data->show_empty && !tag->selected && !tag_isoccupied(tag)) { p_delete(&text[i]); continue; @@ -190,7 +192,7 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, r->x = w->area.x + prev_width; prev_width += r->width; - draw_text(ctx, globalconf.font, *r, text[i]); + draw_text(ctx, globalconf.font, *r, text[i], &pdata[i]); p_delete(&text[i]); if(tag_isoccupied(tag)) @@ -204,6 +206,7 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, } p_delete(&text); + p_delete(&pdata); w->area.height = ctx->height; return w->area.width; diff --git a/widgets/tasklist.c b/widgets/tasklist.c index 3b2873c8..36368cd8 100644 --- a/widgets/tasklist.c +++ b/widgets/tasklist.c @@ -63,7 +63,8 @@ tasklist_isvisible(client_t *c, int screen, showclient_t show) return false; } -struct tasklist_hook_data { +struct tasklist_hook_data +{ draw_context_t *ctx; area_t *area; }; @@ -75,8 +76,9 @@ tasklist_markup_on_elem(markup_parser_data_t *p, const char *elem, struct tasklist_hook_data *data = p->priv; draw_context_t *ctx = data->ctx; - assert (!strcmp(elem, "bg")); - for (; *names; names++, values++) { + assert(!strcmp(elem, "bg")); + for(; *names; names++, values++) + { if(!a_strcmp(*names, "color")) { xcolor_t bg_color; @@ -138,7 +140,8 @@ tasklist_draw(draw_context_t *ctx, int screen, { static char const * const elements[] = { "bg", NULL }; struct tasklist_hook_data data = { .ctx = ctx, .area = &area }; - markup_parser_data_t p = { + markup_parser_data_t p = + { .elements = elements, .on_element = &tasklist_markup_on_elem, .priv = &data, @@ -187,8 +190,7 @@ tasklist_draw(draw_context_t *ctx, int screen, if(i == n - 1) area.width += box_width_rest; - draw_text(ctx, globalconf.font, - area, text); + draw_text(ctx, globalconf.font, area, text, NULL); p_delete(&text); diff --git a/widgets/textbox.c b/widgets/textbox.c index 83f92f0f..5aa3cf68 100644 --- a/widgets/textbox.c +++ b/widgets/textbox.c @@ -40,16 +40,20 @@ textbox_draw(draw_context_t *ctx, int screen __attribute__ ((unused)), void *p __attribute__ ((unused))) { textbox_data_t *d = w->widget->data; + draw_parser_data_t pdata, *pdata_arg = NULL; if(d->width) w->area.width = d->width; else if(w->widget->align == AlignFlex) w->area.width = ctx->width - used; else + { w->area.width = MIN(draw_text_extents(ctx->connection, ctx->phys_screen, - globalconf.font, d->text).width, + globalconf.font, d->text, &pdata).width, ctx->width - used); + pdata_arg = &pdata; + } w->area.height = ctx->height; @@ -59,8 +63,7 @@ textbox_draw(draw_context_t *ctx, int screen __attribute__ ((unused)), w->widget->align); w->area.y = 0; - draw_text(ctx, globalconf.font, - w->area, d->text); + draw_text(ctx, globalconf.font, w->area, d->text, pdata_arg); return w->area.width; }