draw: store parser_data made by extents call

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2008-06-23 13:09:42 +02:00
parent 00b119c1ac
commit 7aab504350
6 changed files with 117 additions and 86 deletions

View File

@ -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

View File

@ -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 *);

26
mouse.c
View File

@ -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), "<text align=\"center\"/>%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);
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}