Parse the title_format and display the customized window title if a format was set.

The format string set with "title_format" can contain the placeholder "%title" which will be replaced with the actual window title.

By not overwriting window->name itself, we make sure that assignment matching still works as expected.

fixes #1723
This commit is contained in:
Ingo Bürk 2015-06-10 19:01:05 +02:00
parent 55e8d06ee4
commit 5a8d66a1d5
6 changed files with 103 additions and 2 deletions

View File

@ -363,6 +363,8 @@ struct Window {
/** The name of the window. */ /** The name of the window. */
i3String *name; i3String *name;
/** The format with which the window's name should be displayed. */
char *title_format;
/** The WM_WINDOW_ROLE of this window (for example, the pidgin buddy window /** The WM_WINDOW_ROLE of this window (for example, the pidgin buddy window
* sets "buddy list"). Useful to match specific windows in assignments or * sets "buddy list"). Useful to match specific windows in assignments or

View File

@ -243,6 +243,11 @@ bool i3string_is_markup(i3String *str);
*/ */
void i3string_set_markup(i3String *str, bool is_markup); void i3string_set_markup(i3String *str, bool is_markup);
/**
* Escape pango markup characters in the given string.
*/
i3String *i3string_escape_markup(i3String *str);
/** /**
* Returns the number of glyphs in an i3String. * Returns the number of glyphs in an i3String.
* *
@ -381,6 +386,12 @@ xcb_char2b_t *convert_utf8_to_ucs2(char *input, size_t *real_strlen);
*/ */
void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background); void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background);
/**
* Returns true if and only if the current font is a pango font.
*
*/
bool font_is_pango(void);
/** /**
* Draws text onto the specified X drawable (normally a pixmap) at the * Draws text onto the specified X drawable (normally a pixmap) at the
* specified coordinates (from the top left corner of the leftmost, uppermost * specified coordinates (from the top left corner of the leftmost, uppermost

View File

@ -340,6 +340,18 @@ void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background
} }
} }
/*
* Returns true if and only if the current font is a pango font.
*
*/
bool font_is_pango(void) {
#if PANGO_SUPPORT
return savedFont->type == FONT_TYPE_PANGO;
#else
return false;
#endif
}
static int predict_text_width_xcb(const xcb_char2b_t *text, size_t text_len); static int predict_text_width_xcb(const xcb_char2b_t *text, size_t text_len);
static void draw_text_xcb(const xcb_char2b_t *text, size_t text_len, xcb_drawable_t drawable, static void draw_text_xcb(const xcb_char2b_t *text, size_t text_len, xcb_drawable_t drawable,

View File

@ -13,6 +13,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#if PANGO_SUPPORT
#include <glib.h>
#endif
#include "libi3.h" #include "libi3.h"
struct _i3String { struct _i3String {
@ -185,6 +189,18 @@ void i3string_set_markup(i3String *str, bool is_markup) {
str->is_markup = is_markup; str->is_markup = is_markup;
} }
/*
* Escape pango markup characters in the given string.
*/
i3String *i3string_escape_markup(i3String *str) {
#if PANGO_SUPPORT
const char *text = i3string_as_utf8(str);
return i3string_from_utf8(g_markup_escape_text(text, -1));
#else
return str;
#endif
}
/* /*
* Returns the number of glyphs in an i3String. * Returns the number of glyphs in an i3String.
* *

View File

@ -1904,7 +1904,25 @@ void cmd_scratchpad_show(I3_CMD) {
* *
*/ */
void cmd_title_format(I3_CMD, char *format) { void cmd_title_format(I3_CMD, char *format) {
DLOG("setting title_format to %s\n", format); DLOG("setting title_format to \"%s\"\n", format);
HANDLE_EMPTY_MATCH;
owindow *current;
TAILQ_FOREACH(current, &owindows, owindows) {
if (current->con->window == NULL)
continue;
DLOG("setting title_format for %p / %s\n", current->con, current->con->name);
FREE(current->con->window->title_format);
/* If we only display the title without anything else, we can skip the parsing step,
* so we remove the title format altogether. */
if (strcasecmp(format, "%title") != 0)
current->con->window->title_format = sstrdup(format);
/* Make sure the window title is redrawn immediately. */
current->con->window->name_x_changed = true;
}
cmd_output->needs_tree_render = true; cmd_output->needs_tree_render = true;
ysuccess(true); ysuccess(true);

44
src/x.c
View File

@ -302,6 +302,45 @@ void x_window_kill(xcb_window_t window, kill_window_t kill_window) {
free(event); free(event);
} }
static i3String *parse_title_format(char *format, i3String *_title) {
/* We need to ensure that we only escape the window title if pango
* is used by the current font. */
const bool is_markup = font_is_pango();
i3String *title = is_markup ? i3string_escape_markup(_title) : _title;
const char *escaped_title = i3string_as_utf8(title);
/* We have to first iterate over the string to see how much buffer space
* we need to allocate. */
int buffer_len = strlen(format) + 1;
for (char *walk = format; *walk != '\0'; walk++) {
if (STARTS_WITH(walk, "%title")) {
buffer_len = buffer_len - strlen("%title") + strlen(escaped_title);
walk += strlen("%title") - 1;
}
}
/* Now we can parse the format string. */
char buffer[buffer_len];
char *outwalk = buffer;
for (char *walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
*(outwalk++) = *walk;
continue;
}
if (STARTS_WITH(walk + 1, "title")) {
outwalk += sprintf(outwalk, "%s", escaped_title);
walk += strlen("title");
}
}
*outwalk = '\0';
i3String *formatted = i3string_from_utf8(buffer);
i3string_set_markup(formatted, is_markup);
return formatted;
}
/* /*
* Draws the decoration of the given container onto its parent. * Draws the decoration of the given container onto its parent.
* *
@ -549,10 +588,13 @@ void x_draw_decoration(Con *con) {
I3STRING_FREE(mark); I3STRING_FREE(mark);
} }
draw_text(win->name, i3String *title = win->title_format == NULL ? win->name : parse_title_format(win->title_format, win->name);
draw_text(title,
parent->pixmap, parent->pm_gc, parent->pixmap, parent->pm_gc,
con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y, con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y,
con->deco_rect.width - logical_px(2) - indent_px - mark_width - logical_px(2)); con->deco_rect.width - logical_px(2) - indent_px - mark_width - logical_px(2));
if (win->title_format != NULL)
I3STRING_FREE(title);
after_title: after_title:
/* Since we dont clip the text at all, it might in some cases be painted /* Since we dont clip the text at all, it might in some cases be painted