Merge pull request #1747 from Airblader/feature-1723
Implement "title_format"
This commit is contained in:
commit
8df7e4ecb9
|
@ -564,6 +564,8 @@ hide_edge_borders vertical
|
||||||
|
|
||||||
=== Arbitrary commands for specific windows (for_window)
|
=== Arbitrary commands for specific windows (for_window)
|
||||||
|
|
||||||
|
[[for_window]]
|
||||||
|
|
||||||
With the +for_window+ command, you can let i3 execute any command when it
|
With the +for_window+ command, you can let i3 execute any command when it
|
||||||
encounters a specific window. This can be used to set windows to floating or to
|
encounters a specific window. This can be used to set windows to floating or to
|
||||||
change their border style, for example.
|
change their border style, for example.
|
||||||
|
@ -2083,6 +2085,37 @@ Alternatively, if you do not want to mess with +i3-input+, you could create
|
||||||
seperate bindings for a specific set of labels and then only use those labels.
|
seperate bindings for a specific set of labels and then only use those labels.
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
=== Window title format
|
||||||
|
|
||||||
|
By default, i3 will simply print the X11 window title. Using +title_format+,
|
||||||
|
this can be customized by setting the format to the desired output. This
|
||||||
|
directive supports
|
||||||
|
https://developer.gnome.org/pango/stable/PangoMarkupFormat.html[Pango markup]
|
||||||
|
and the following placeholders which will be replaced:
|
||||||
|
|
||||||
|
+%title+::
|
||||||
|
The X11 window title (_NET_WM_NAME or WM_NAME as fallback).
|
||||||
|
|
||||||
|
Using the <<for_window>> directive, you can set the title format for any window
|
||||||
|
based on <<command_criteria>>.
|
||||||
|
|
||||||
|
*Syntax*:
|
||||||
|
---------------------
|
||||||
|
title_format <format>
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
*Examples*:
|
||||||
|
-------------------------------------------------------------------------------------
|
||||||
|
# give the focused window a prefix
|
||||||
|
bindsym $mod+p title_format "Important | %title"
|
||||||
|
|
||||||
|
# print all window titles bold
|
||||||
|
for_window [class=".*"] title_format "<b>%title</b>"
|
||||||
|
|
||||||
|
# print window titles of firefox windows red
|
||||||
|
for_window [class="(?i)firefox"] title_format "<span foreground='red'>%title</span>"
|
||||||
|
-------------------------------------------------------------------------------------
|
||||||
|
|
||||||
=== Changing border style
|
=== Changing border style
|
||||||
|
|
||||||
To change the border of the current client, you can use +border normal+ to use the normal
|
To change the border of the current client, you can use +border normal+ to use the normal
|
||||||
|
|
|
@ -276,6 +276,12 @@ void cmd_move_scratchpad(I3_CMD);
|
||||||
*/
|
*/
|
||||||
void cmd_scratchpad_show(I3_CMD);
|
void cmd_scratchpad_show(I3_CMD);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of 'title_format <format>'
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void cmd_title_format(I3_CMD, char *format);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of 'rename workspace <name> to <name>'
|
* Implementation of 'rename workspace <name> to <name>'
|
||||||
*
|
*
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
12
libi3/font.c
12
libi3/font.c
|
@ -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,
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -37,6 +37,7 @@ state INITIAL:
|
||||||
'rename' -> RENAME
|
'rename' -> RENAME
|
||||||
'nop' -> NOP
|
'nop' -> NOP
|
||||||
'scratchpad' -> SCRATCHPAD
|
'scratchpad' -> SCRATCHPAD
|
||||||
|
'title_format' -> TITLE_FORMAT
|
||||||
'mode' -> MODE
|
'mode' -> MODE
|
||||||
'bar' -> BAR
|
'bar' -> BAR
|
||||||
|
|
||||||
|
@ -374,6 +375,10 @@ state SCRATCHPAD:
|
||||||
'show'
|
'show'
|
||||||
-> call cmd_scratchpad_show()
|
-> call cmd_scratchpad_show()
|
||||||
|
|
||||||
|
state TITLE_FORMAT:
|
||||||
|
format = string
|
||||||
|
-> call cmd_title_format($format)
|
||||||
|
|
||||||
# bar (hidden_state hide|show|toggle)|(mode dock|hide|invisible|toggle) [<bar_id>]
|
# bar (hidden_state hide|show|toggle)|(mode dock|hide|invisible|toggle) [<bar_id>]
|
||||||
state BAR:
|
state BAR:
|
||||||
bar_type = 'hidden_state'
|
bar_type = 'hidden_state'
|
||||||
|
|
|
@ -1899,6 +1899,35 @@ void cmd_scratchpad_show(I3_CMD) {
|
||||||
ysuccess(true);
|
ysuccess(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation of 'title_format <format>'
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void cmd_title_format(I3_CMD, char *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;
|
||||||
|
ysuccess(true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implementation of 'rename workspace [<name>] to <name>'
|
* Implementation of 'rename workspace [<name>] to <name>'
|
||||||
*
|
*
|
||||||
|
|
44
src/x.c
44
src/x.c
|
@ -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 don’t clip the text at all, it might in some cases be painted
|
/* Since we don’t clip the text at all, it might in some cases be painted
|
||||||
|
|
|
@ -144,7 +144,7 @@ is(parser_calls("\nworkspace test"),
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
is(parser_calls('unknown_literal'),
|
is(parser_calls('unknown_literal'),
|
||||||
"ERROR: Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'shmlog', 'debuglog', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'unmark', 'resize', 'rename', 'nop', 'scratchpad', 'mode', 'bar'\n" .
|
"ERROR: Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'shmlog', 'debuglog', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'unmark', 'resize', 'rename', 'nop', 'scratchpad', 'title_format', 'mode', 'bar'\n" .
|
||||||
"ERROR: Your command: unknown_literal\n" .
|
"ERROR: Your command: unknown_literal\n" .
|
||||||
"ERROR: ^^^^^^^^^^^^^^^",
|
"ERROR: ^^^^^^^^^^^^^^^",
|
||||||
'error for unknown literal ok');
|
'error for unknown literal ok');
|
||||||
|
|
Loading…
Reference in New Issue