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
This commit is contained in:
Tony Crisci 2015-02-12 14:45:34 -05:00
parent fbe25297b7
commit e18e2b9f98
7 changed files with 83 additions and 14 deletions

View File

@ -119,7 +119,8 @@ click_events::
full_text:: full_text::
The most simple block you can think of is one which just includes the 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 only required key, the +full_text+ key. i3bar will display the string
value and thats it. value parsed as
https://developer.gnome.org/pango/stable/PangoMarkupFormat.html[Pango markup].
short_text:: short_text::
Where appropriate, the +short_text+ (string) entry should also be Where appropriate, the +short_text+ (string) entry should also be
provided. It will be used in case the status line needs to be shortened provided. It will be used in case the status line needs to be shortened

View File

@ -1625,6 +1625,10 @@ container to the next/previous workspace and +move container to workspace curren
See <<move_to_outputs>> for how to move a container/workspace to a different See <<move_to_outputs>> for how to move a container/workspace to a different
RandR output. RandR output.
Workspace names are parsed as
https://developer.gnome.org/pango/stable/PangoMarkupFormat.html[Pango markup]
by i3bar.
[[back_and_forth]] [[back_and_forth]]
To switch back to the previously focused workspace, use +workspace To switch back to the previously focused workspace, use +workspace
back_and_forth+; likewise, you can move containers to the previously focused back_and_forth+; likewise, you can move containers to the previously focused
@ -1646,6 +1650,7 @@ move [window|container] [to] workspace <prev|next|current>
------------------------- -------------------------
bindsym $mod+1 workspace 1 bindsym $mod+1 workspace 1
bindsym $mod+2 workspace 2 bindsym $mod+2 workspace 2
bindsym $mod+3 workspace 3:<span foreground="red">vim</span>
... ...
bindsym $mod+Shift+1 move container to workspace 1 bindsym $mod+Shift+1 move container to workspace 1

View File

@ -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) { static int stdin_string(void *context, const unsigned char *val, size_t len) {
parser_ctx *ctx = context; parser_ctx *ctx = context;
if (strcasecmp(ctx->last_map_key, "full_text") == 0) { 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) { if (strcasecmp(ctx->last_map_key, "color") == 0) {
sasprintf(&(ctx->block.color), "%.*s", len, val); 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; ctx->block.align = ALIGN_LEFT;
} }
} else if (strcasecmp(ctx->last_map_key, "min_width") == 0) { } 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); ctx->block.min_width = (uint32_t)predict_text_width(text);
i3string_free(text); i3string_free(text);
} }
@ -304,7 +304,7 @@ static void read_flat_input(char *buffer, int length) {
buffer[length - 1] = '\0'; buffer[length - 1] = '\0';
else else
buffer[length] = '\0'; 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) { static bool read_json_input(unsigned char *input, int length) {

View File

@ -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 */ /* Offset may be equal to length, in which case display the number */
params->workspaces_walk->name = (offset < len params->workspaces_walk->name = (offset < len
? i3string_from_utf8_with_length(ws_name + offset, len - offset) ? i3string_from_markup_with_length(ws_name + offset, len - offset)
: i3string_from_utf8(ws_num)); : i3string_from_markup(ws_num));
} else { } else {
/* Default case: just save the name */ /* 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 */ /* Save its rendered width */

View File

@ -141,6 +141,12 @@ int sasprintf(char **strp, const char *fmt, ...);
*/ */
i3String *i3string_from_utf8(const char *from_utf8); 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. * Build an i3String from an UTF-8 encoded string with fixed length.
* To be used when no proper NUL-terminaison is available. * 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); 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. * Build an i3String from an UCS-2 encoded string.
* Returns the newly-allocated i3String. * 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); 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. * Returns the number of glyphs in an i3String.
* *

View File

@ -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, 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 */ /* Create the Pango layout */
/* root_visual_type is cached in load_pango_font */ /* root_visual_type is cached in load_pango_font */
cairo_surface_t *surface = cairo_xcb_surface_create(conn, drawable, cairo_surface_t *surface = cairo_xcb_surface_create(conn, drawable,
@ -116,6 +117,9 @@ static void draw_text_pango(const char *text, size_t text_len,
pango_layout_set_wrap(layout, PANGO_WRAP_CHAR); pango_layout_set_wrap(layout, PANGO_WRAP_CHAR);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
if (is_markup)
pango_layout_set_markup(layout, text, text_len);
else
pango_layout_set_text(layout, text, text_len); pango_layout_set_text(layout, text, text_len);
/* Do the drawing */ /* Do the drawing */
@ -135,7 +139,7 @@ static void draw_text_pango(const char *text, size_t text_len,
* Calculate the text width using Pango rendering. * 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 */ /* Create a dummy Pango layout */
/* root_visual_type is cached in load_pango_font */ /* 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); 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 */ /* Get the font width */
gint width; gint width;
pango_layout_set_font_description(layout, savedFont->specific.pango_desc); pango_layout_set_font_description(layout, savedFont->specific.pango_desc);
if (is_markup)
pango_layout_set_markup(layout, text, text_len);
else
pango_layout_set_text(layout, text, text_len); pango_layout_set_text(layout, text, text_len);
pango_cairo_update_layout(cr, layout); pango_cairo_update_layout(cr, layout);
pango_layout_get_pixel_size(layout, &width, NULL); 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: case FONT_TYPE_PANGO:
/* Render the text using Pango */ /* Render the text using Pango */
draw_text_pango(i3string_as_utf8(text), i3string_get_num_bytes(text), 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; return;
#endif #endif
default: default:
@ -422,7 +431,7 @@ void draw_text_ascii(const char *text, xcb_drawable_t drawable,
case FONT_TYPE_PANGO: case FONT_TYPE_PANGO:
/* Render the text using Pango */ /* Render the text using Pango */
draw_text_pango(text, strlen(text), draw_text_pango(text, strlen(text),
drawable, x, y, max_width); drawable, x, y, max_width, false);
return; return;
#endif #endif
default: default:
@ -518,7 +527,8 @@ int predict_text_width(i3String *text) {
#if PANGO_SUPPORT #if PANGO_SUPPORT
case FONT_TYPE_PANGO: case FONT_TYPE_PANGO:
/* Calculate extents using 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 #endif
default: default:
assert(false); assert(false);

View File

@ -20,6 +20,7 @@ struct _i3String {
xcb_char2b_t *ucs2; xcb_char2b_t *ucs2;
size_t num_glyphs; size_t num_glyphs;
size_t num_bytes; size_t num_bytes;
bool is_markup;
}; };
/* /*
@ -39,6 +40,19 @@ i3String *i3string_from_utf8(const char *from_utf8) {
return str; 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. * Build an i3String from an UTF-8 encoded string with fixed length.
* To be used when no proper NUL-terminaison is available. * 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; 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. * Build an i3String from an UCS-2 encoded string.
* Returns the newly-allocated i3String. * Returns the newly-allocated i3String.
@ -133,6 +161,13 @@ size_t i3string_get_num_bytes(i3String *str) {
return str->num_bytes; 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. * Returns the number of glyphs in an i3String.
* *