From e8149c77b3bd12e0b371e7c1fe55dc1deca52893 Mon Sep 17 00:00:00 2001 From: Antoine Millet Date: Sun, 2 Dec 2012 13:20:06 +0100 Subject: [PATCH] i3bar: add min_width and align keys to blocks --- docs/i3bar-protocol | 12 ++++++++++++ i3bar/include/common.h | 12 +++++++++++- i3bar/src/child.c | 22 ++++++++++++++++++++++ i3bar/src/xcb.c | 27 ++++++++++++++++++++++++--- 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/docs/i3bar-protocol b/docs/i3bar-protocol index e3e42d10..2cf6dd0a 100644 --- a/docs/i3bar-protocol +++ b/docs/i3bar-protocol @@ -134,6 +134,16 @@ color:: when it is associated. Colors are specified in hex (like in HTML), starting with a leading hash sign. For example, +#ff0000+ means red. +min_width:: + The minimum width (in pixels) of the block. If the content of the + +full_text+ key take less space than the specified min_width, the block + will be padded to the left and/or the right side, according to the +align+ + key. This is useful when you want to prevent the whole status line to shift + when value take more or less space between each iteration. +align:: + Align text on the +center+ (default), +right+ or +left+ of the block, when + the minimum width of the latter, specified by the +min_width+ key, is not + reached. name and instance:: Every block should have a unique +name+ (string) entry so that it can be easily identified in scripts which process the output. i3bar @@ -166,6 +176,8 @@ An example of a block which uses all possible entries follows: "full_text": "E: 10.0.0.1 (1000 Mbit/s)", "short_text": "10.0.0.1", "color": "#00ff00", + "min_width": 300, + "align": "right", "urgent": false, "name": "ethernet", "instance": "eth0" diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 870e6dbe..05fb5aa1 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -27,18 +27,28 @@ struct rect_t { int h; }; +typedef enum { + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT +} blockalign_t; + /* This data structure represents one JSON dictionary, multiple of these make * up one status line. */ struct status_block { i3String *full_text; char *color; + uint32_t min_width; + blockalign_t align; bool urgent; - /* The amount of pixels necessary to render this block. This variable is + /* The amount of pixels necessary to render this block. These variables are * only temporarily used in refresh_statusline(). */ uint32_t width; + uint32_t x_offset; + uint32_t x_append; TAILQ_ENTRY(status_block) blocks; }; diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 9a89d3c6..bea1d58e 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -132,6 +132,27 @@ static int stdin_string(void *context, const unsigned char *val, unsigned int le if (strcasecmp(ctx->last_map_key, "color") == 0) { sasprintf(&(ctx->block.color), "%.*s", len, val); } + if (strcasecmp(ctx->last_map_key, "align") == 0) { + if (len == strlen("left") && !strncmp((const char*)val, "left", strlen("left"))) { + ctx->block.align = ALIGN_LEFT; + } else if (len == strlen("right") && !strncmp((const char*)val, "right", strlen("right"))) { + ctx->block.align = ALIGN_RIGHT; + } else { + ctx->block.align = ALIGN_CENTER; + } + } + return 1; +} + +#if YAJL_MAJOR >= 2 +static int stdin_integer(void *context, long long val) { +#else +static int stdin_integer(void *context, long val) { +#endif + parser_ctx *ctx = context; + if (strcasecmp(ctx->last_map_key, "min_width") == 0) { + ctx->block.min_width = (uint32_t)val; + } return 1; } @@ -313,6 +334,7 @@ void start_child(char *command) { callbacks.yajl_map_key = stdin_map_key; callbacks.yajl_boolean = stdin_boolean; callbacks.yajl_string = stdin_string; + callbacks.yajl_integer = stdin_integer; callbacks.yajl_start_array = stdin_start_array; callbacks.yajl_end_array = stdin_end_array; callbacks.yajl_start_map = stdin_start_map; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 5ae8023a..6bd8039b 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -123,10 +123,31 @@ void refresh_statusline(void) { continue; block->width = predict_text_width(block->full_text); + + /* Compute offset and append for text aligment in min_width. */ + if (block->min_width <= block->width) { + block->x_offset = 0; + block->x_append = 0; + } else { + uint32_t padding_width = block->min_width - block->width; + switch (block->align) { + case ALIGN_LEFT: + block->x_append = padding_width; + break; + case ALIGN_RIGHT: + block->x_offset = padding_width; + break; + case ALIGN_CENTER: + block->x_offset = padding_width / 2; + block->x_append = padding_width / 2 + padding_width % 2; + break; + } + } + /* If this is not the last block, add some pixels for a separator. */ if (TAILQ_NEXT(block, blocks) != NULL) block->width += 9; - statusline_width += block->width; + statusline_width += block->width + block->x_offset + block->x_append; } /* If the statusline is bigger than our screen we need to make sure that @@ -147,8 +168,8 @@ void refresh_statusline(void) { uint32_t colorpixel = (block->color ? get_colorpixel(block->color) : colors.bar_fg); set_font_colors(statusline_ctx, colorpixel, colors.bar_bg); - draw_text(block->full_text, statusline_pm, statusline_ctx, x, 0, block->width); - x += block->width; + draw_text(block->full_text, statusline_pm, statusline_ctx, x + block->x_offset, 0, block->width); + x += block->width + block->x_offset + block->x_append; if (TAILQ_NEXT(block, blocks) != NULL) { /* This is not the last block, draw a separator. */ -- 2.39.5