From e18e2b9f988f42b0a858b634fa997289418e544a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 12 Feb 2015 14:45:34 -0500 Subject: [PATCH] i3bar: use Pango markup Parse text within workspace buttons and the i3bar statusline as Pango markup. This lets people specify things like font weight, text color, background color, font size, and font family in the text of i3bar. fixes #1468 --- docs/i3bar-protocol | 3 ++- docs/userguide | 5 +++++ i3bar/src/child.c | 6 +++--- i3bar/src/workspaces.c | 6 +++--- include/libi3.h | 18 ++++++++++++++++++ libi3/font.c | 24 +++++++++++++++++------- libi3/string.c | 35 +++++++++++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 14 deletions(-) diff --git a/docs/i3bar-protocol b/docs/i3bar-protocol index 0ca2fd82..8fd51ae9 100644 --- a/docs/i3bar-protocol +++ b/docs/i3bar-protocol @@ -119,7 +119,8 @@ click_events:: full_text:: The most simple block you can think of is one which just includes the only required key, the +full_text+ key. i3bar will display the string - value and that’s it. + value parsed as + https://developer.gnome.org/pango/stable/PangoMarkupFormat.html[Pango markup]. short_text:: Where appropriate, the +short_text+ (string) entry should also be provided. It will be used in case the status line needs to be shortened diff --git a/docs/userguide b/docs/userguide index 4b4dacc8..45b05a06 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1625,6 +1625,10 @@ container to the next/previous workspace and +move container to workspace curren See <> for how to move a container/workspace to a different RandR output. +Workspace names are parsed as +https://developer.gnome.org/pango/stable/PangoMarkupFormat.html[Pango markup] +by i3bar. + [[back_and_forth]] To switch back to the previously focused workspace, use +workspace back_and_forth+; likewise, you can move containers to the previously focused @@ -1646,6 +1650,7 @@ move [window|container] [to] workspace ------------------------- bindsym $mod+1 workspace 1 bindsym $mod+2 workspace 2 +bindsym $mod+3 workspace 3:vim ... bindsym $mod+Shift+1 move container to workspace 1 diff --git a/i3bar/src/child.c b/i3bar/src/child.c index d0f0c5fb..2f7dd76e 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -182,7 +182,7 @@ static int stdin_boolean(void *context, int val) { static int stdin_string(void *context, const unsigned char *val, size_t len) { parser_ctx *ctx = context; if (strcasecmp(ctx->last_map_key, "full_text") == 0) { - ctx->block.full_text = i3string_from_utf8_with_length((const char *)val, len); + ctx->block.full_text = i3string_from_markup_with_length((const char *)val, len); } if (strcasecmp(ctx->last_map_key, "color") == 0) { sasprintf(&(ctx->block.color), "%.*s", len, val); @@ -196,7 +196,7 @@ static int stdin_string(void *context, const unsigned char *val, size_t len) { ctx->block.align = ALIGN_LEFT; } } else if (strcasecmp(ctx->last_map_key, "min_width") == 0) { - i3String *text = i3string_from_utf8_with_length((const char *)val, len); + i3String *text = i3string_from_markup_with_length((const char *)val, len); ctx->block.min_width = (uint32_t)predict_text_width(text); i3string_free(text); } @@ -304,7 +304,7 @@ static void read_flat_input(char *buffer, int length) { buffer[length - 1] = '\0'; else buffer[length] = '\0'; - first->full_text = i3string_from_utf8(buffer); + first->full_text = i3string_from_markup(buffer); } static bool read_json_input(unsigned char *input, int length) { diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index e8184d40..45b511ff 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -123,12 +123,12 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, size_t /* Offset may be equal to length, in which case display the number */ params->workspaces_walk->name = (offset < len - ? i3string_from_utf8_with_length(ws_name + offset, len - offset) - : i3string_from_utf8(ws_num)); + ? i3string_from_markup_with_length(ws_name + offset, len - offset) + : i3string_from_markup(ws_num)); } else { /* Default case: just save the name */ - params->workspaces_walk->name = i3string_from_utf8_with_length(ws_name, len); + params->workspaces_walk->name = i3string_from_markup_with_length(ws_name, len); } /* Save its rendered width */ diff --git a/include/libi3.h b/include/libi3.h index 7a2bdf58..c1a11dfc 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -141,6 +141,12 @@ int sasprintf(char **strp, const char *fmt, ...); */ i3String *i3string_from_utf8(const char *from_utf8); +/** + * Build an i3String from an UTF-8 encoded string in Pango markup. + * + */ +i3String *i3string_from_markup(const char *from_markup); + /** * Build an i3String from an UTF-8 encoded string with fixed length. * To be used when no proper NUL-terminaison is available. @@ -149,6 +155,13 @@ i3String *i3string_from_utf8(const char *from_utf8); */ i3String *i3string_from_utf8_with_length(const char *from_utf8, size_t num_bytes); +/** + * Build an i3String from an UTF-8 encoded string in Pango markup with fixed + * length. + * + */ +i3String *i3string_from_markup_with_length(const char *from_markup, size_t num_bytes); + /** * Build an i3String from an UCS-2 encoded string. * Returns the newly-allocated i3String. @@ -193,6 +206,11 @@ const xcb_char2b_t *i3string_as_ucs2(i3String *str); */ size_t i3string_get_num_bytes(i3String *str); +/** + * Whether the given i3String is in Pango markup. + */ +bool i3string_is_markup(i3String *str); + /** * Returns the number of glyphs in an i3String. * diff --git a/libi3/font.c b/libi3/font.c index a338f975..f2a7e1fb 100644 --- a/libi3/font.c +++ b/libi3/font.c @@ -102,7 +102,8 @@ static bool load_pango_font(i3Font *font, const char *desc) { * */ static void draw_text_pango(const char *text, size_t text_len, - xcb_drawable_t drawable, int x, int y, int max_width) { + xcb_drawable_t drawable, int x, int y, + int max_width, bool is_markup) { /* Create the Pango layout */ /* root_visual_type is cached in load_pango_font */ cairo_surface_t *surface = cairo_xcb_surface_create(conn, drawable, @@ -116,7 +117,10 @@ static void draw_text_pango(const char *text, size_t text_len, pango_layout_set_wrap(layout, PANGO_WRAP_CHAR); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); - pango_layout_set_text(layout, text, text_len); + if (is_markup) + pango_layout_set_markup(layout, text, text_len); + else + pango_layout_set_text(layout, text, text_len); /* Do the drawing */ cairo_set_source_rgb(cr, pango_font_red, pango_font_green, pango_font_blue); @@ -135,7 +139,7 @@ static void draw_text_pango(const char *text, size_t text_len, * Calculate the text width using Pango rendering. * */ -static int predict_text_width_pango(const char *text, size_t text_len) { +static int predict_text_width_pango(const char *text, size_t text_len, bool is_markup) { /* Create a dummy Pango layout */ /* root_visual_type is cached in load_pango_font */ cairo_surface_t *surface = cairo_xcb_surface_create(conn, root_screen->root, root_visual_type, 1, 1); @@ -145,7 +149,12 @@ static int predict_text_width_pango(const char *text, size_t text_len) { /* Get the font width */ gint width; pango_layout_set_font_description(layout, savedFont->specific.pango_desc); - pango_layout_set_text(layout, text, text_len); + + if (is_markup) + pango_layout_set_markup(layout, text, text_len); + else + pango_layout_set_text(layout, text, text_len); + pango_cairo_update_layout(cr, layout); pango_layout_get_pixel_size(layout, &width, NULL); @@ -383,7 +392,7 @@ void draw_text(i3String *text, xcb_drawable_t drawable, case FONT_TYPE_PANGO: /* Render the text using Pango */ draw_text_pango(i3string_as_utf8(text), i3string_get_num_bytes(text), - drawable, x, y, max_width); + drawable, x, y, max_width, i3string_is_markup(text)); return; #endif default: @@ -422,7 +431,7 @@ void draw_text_ascii(const char *text, xcb_drawable_t drawable, case FONT_TYPE_PANGO: /* Render the text using Pango */ draw_text_pango(text, strlen(text), - drawable, x, y, max_width); + drawable, x, y, max_width, false); return; #endif default: @@ -518,7 +527,8 @@ int predict_text_width(i3String *text) { #if PANGO_SUPPORT case FONT_TYPE_PANGO: /* Calculate extents using Pango */ - return predict_text_width_pango(i3string_as_utf8(text), i3string_get_num_bytes(text)); + return predict_text_width_pango(i3string_as_utf8(text), i3string_get_num_bytes(text), + i3string_is_markup(text)); #endif default: assert(false); diff --git a/libi3/string.c b/libi3/string.c index 009312d6..afeca974 100644 --- a/libi3/string.c +++ b/libi3/string.c @@ -20,6 +20,7 @@ struct _i3String { xcb_char2b_t *ucs2; size_t num_glyphs; size_t num_bytes; + bool is_markup; }; /* @@ -39,6 +40,19 @@ i3String *i3string_from_utf8(const char *from_utf8) { return str; } +/* + * Build an i3String from an UTF-8 encoded string in Pango markup. + * + */ +i3String *i3string_from_markup(const char *from_markup) { + i3String *str = i3string_from_utf8(from_markup); + + /* Set the markup flag */ + str->is_markup = true; + + return str; +} + /* * Build an i3String from an UTF-8 encoded string with fixed length. * To be used when no proper NUL-terminaison is available. @@ -59,6 +73,20 @@ i3String *i3string_from_utf8_with_length(const char *from_utf8, size_t num_bytes return str; } +/* + * Build an i3String from an UTF-8 encoded string in Pango markup with fixed + * length. + * + */ +i3String *i3string_from_markup_with_length(const char *from_markup, size_t num_bytes) { + i3String *str = i3string_from_utf8_with_length(from_markup, num_bytes); + + /* set the markup flag */ + str->is_markup = true; + + return str; +} + /* * Build an i3String from an UCS-2 encoded string. * Returns the newly-allocated i3String. @@ -133,6 +161,13 @@ size_t i3string_get_num_bytes(i3String *str) { return str->num_bytes; } +/* + * Whether the given i3String is in Pango markup. + */ +bool i3string_is_markup(i3String *str) { + return str->is_markup; +} + /* * Returns the number of glyphs in an i3String. *