i3bar: implement custom workspace numbers config

Implement the configuration option within the bar config directive for
custom workspace numbers with the directive `strip_workspace_numbers
yes`.

This directive strips the workspace name of the number prefix and
delimiter. When the workspace name consists only of the number, it will
default to show the number.

For example:

* "2:5" -> "5"
* "4:$" -> "$"
* "8" -> "8"

This allows customization of i3bar for alternate ordering of workspaces
which has a legitimate use for alternate keyboard layouts such as
Dvorak.

fixes #1131
This commit is contained in:
Tony Crisci 2014-05-05 13:56:47 -04:00 committed by Michael Stapelberg
parent e2f47ef466
commit e707e0a5fa
12 changed files with 81 additions and 6 deletions

View File

@ -1191,6 +1191,31 @@ bar {
} }
------------------------ ------------------------
=== Strip workspace numbers
Specifies whether workspace numbers should be displayed within the workspace
buttons. This is useful if you want to have a named workspace that stays in
order on the bar according to its number without displaying the number prefix.
When +strip_workspace_numbers+ is set to +yes+, any workspace that has a name of
the form "[n]:[NAME]" will display only the name. You could use this, for
instance, to display Roman numerals rather than digits by naming your
workspaces to "1:I", "2:II", "3:III", "4:IV", ...
The default is to display the full name within the workspace button.
*Syntax*:
----------------------------------
strip_workspace_numbers <yes|no>
----------------------------------
*Example*:
----------------------------
bar {
strip_workspace_numbers yes
}
----------------------------
=== Binding Mode indicator === Binding Mode indicator
Specifies whether the current binding mode indicator should be shown or not. Specifies whether the current binding mode indicator should be shown or not.

View File

@ -27,6 +27,7 @@ typedef struct config_t {
struct xcb_color_strings_t colors; struct xcb_color_strings_t colors;
bool disable_binding_mode_indicator; bool disable_binding_mode_indicator;
bool disable_ws; bool disable_ws;
bool strip_ws_numbers;
char *bar_id; char *bar_id;
char *command; char *command;
char *fontname; char *fontname;

View File

@ -31,7 +31,8 @@ void free_workspaces(void);
struct i3_ws { struct i3_ws {
int num; /* The internal number of the ws */ int num; /* The internal number of the ws */
i3String *name; /* The name of the ws */ char *canonical_name; /* The true name of the ws according to the ipc */
i3String *name; /* The name of the ws that is displayed on the bar */
int name_width; /* The rendered width of the name */ int name_width; /* The rendered width of the name */
bool visible; /* If the ws is currently visible on an output */ bool visible; /* If the ws is currently visible on an output */
bool focused; /* If the ws is currently focused */ bool focused; /* If the ws is currently focused */

View File

@ -193,6 +193,12 @@ static int config_boolean_cb(void *params_, int val) {
return 1; return 1;
} }
if (!strcmp(cur_key, "strip_workspace_numbers")) {
DLOG("strip_workspace_numbers = %d\n", val);
config.strip_ws_numbers = val;
return 1;
}
if (!strcmp(cur_key, "verbose")) { if (!strcmp(cur_key, "verbose")) {
DLOG("verbose = %d\n", val); DLOG("verbose = %d\n", val);
config.verbose = val; config.verbose = val;

View File

@ -105,14 +105,38 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, size_t
char *output_name; char *output_name;
if (!strcmp(params->cur_key, "name")) { if (!strcmp(params->cur_key, "name")) {
/* Save the name */ const char *ws_name = (const char*)val;
params->workspaces_walk->name = i3string_from_utf8_with_length((const char *)val, len); params->workspaces_walk->canonical_name = strndup(ws_name, len);
if (config.strip_ws_numbers && params->workspaces_walk->num >= 0) {
/* Special case: strip off the workspace number */
static char ws_num[10];
snprintf(ws_num, sizeof(ws_num), "%d", params->workspaces_walk->num);
/* Calculate the length of the number str in the name */
int offset = strspn(ws_name, ws_num);
/* Also strip off the conventional ws name delimiter */
if (offset && ws_name[offset] == ':')
offset += 1;
/* 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));
} else {
/* Default case: just save the name */
params->workspaces_walk->name = i3string_from_utf8_with_length(ws_name, len);
}
/* Save its rendered width */ /* Save its rendered width */
params->workspaces_walk->name_width = params->workspaces_walk->name_width =
predict_text_width(params->workspaces_walk->name); predict_text_width(params->workspaces_walk->name);
DLOG("Got Workspace %s, name_width: %d, glyphs: %zu\n", DLOG("Got Workspace canonical: %s, name: '%s', name_width: %d, glyphs: %zu\n",
params->workspaces_walk->canonical_name,
i3string_as_utf8(params->workspaces_walk->name), i3string_as_utf8(params->workspaces_walk->name),
params->workspaces_walk->name_width, params->workspaces_walk->name_width,
i3string_get_num_glyphs(params->workspaces_walk->name)); i3string_get_num_glyphs(params->workspaces_walk->name));
@ -246,6 +270,7 @@ void free_workspaces(void) {
if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) { if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) {
TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
I3STRING_FREE(ws_walk->name); I3STRING_FREE(ws_walk->name);
FREE(ws_walk->canonical_name);
} }
FREE_TAILQ(outputs_walk->workspaces, i3_ws); FREE_TAILQ(outputs_walk->workspaces, i3_ws);
} }

View File

@ -418,7 +418,7 @@ void handle_button(xcb_button_press_event_t *event) {
* buffer, then we copy character by character. */ * buffer, then we copy character by character. */
int num_quotes = 0; int num_quotes = 0;
size_t namelen = 0; size_t namelen = 0;
const char *utf8_name = i3string_as_utf8(cur_ws->name); const char *utf8_name = cur_ws->canonical_name;
for (const char *walk = utf8_name; *walk != '\0'; walk++) { for (const char *walk = utf8_name; *walk != '\0'; walk++) {
if (*walk == '"') if (*walk == '"')
num_quotes++; num_quotes++;

View File

@ -267,6 +267,10 @@ struct Barconfig {
* zero. */ * zero. */
bool hide_workspace_buttons; bool hide_workspace_buttons;
/** Strip workspace numbers? Configuration option is
* 'strip_workspace_numbers yes'. */
bool strip_workspace_numbers;
/** Hide mode button? Configuration option is 'binding_mode_indicator no' /** Hide mode button? Configuration option is 'binding_mode_indicator no'
* but we invert the bool for the same reason as hide_workspace_buttons.*/ * but we invert the bool for the same reason as hide_workspace_buttons.*/
bool hide_binding_mode_indicator; bool hide_binding_mode_indicator;

View File

@ -81,4 +81,5 @@ CFGFUN(bar_color_single, const char *colorclass, const char *color);
CFGFUN(bar_status_command, const char *command); CFGFUN(bar_status_command, const char *command);
CFGFUN(bar_binding_mode_indicator, const char *value); CFGFUN(bar_binding_mode_indicator, const char *value);
CFGFUN(bar_workspace_buttons, const char *value); CFGFUN(bar_workspace_buttons, const char *value);
CFGFUN(bar_strip_workspace_numbers, const char *value);
CFGFUN(bar_finish); CFGFUN(bar_finish);

View File

@ -358,6 +358,7 @@ state BAR:
'font' -> BAR_FONT 'font' -> BAR_FONT
'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR 'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR
'workspace_buttons' -> BAR_WORKSPACE_BUTTONS 'workspace_buttons' -> BAR_WORKSPACE_BUTTONS
'strip_workspace_numbers' -> BAR_STRIP_WORKSPACE_NUMBERS
'verbose' -> BAR_VERBOSE 'verbose' -> BAR_VERBOSE
'colors' -> BAR_COLORS_BRACE 'colors' -> BAR_COLORS_BRACE
'}' '}'
@ -420,6 +421,10 @@ state BAR_WORKSPACE_BUTTONS:
value = word value = word
-> call cfg_bar_workspace_buttons($value); BAR -> call cfg_bar_workspace_buttons($value); BAR
state BAR_STRIP_WORKSPACE_NUMBERS:
value = word
-> call cfg_bar_strip_workspace_numbers($value); BAR
state BAR_VERBOSE: state BAR_VERBOSE:
value = word value = word
-> call cfg_bar_verbose($value); BAR -> call cfg_bar_verbose($value); BAR

View File

@ -517,6 +517,10 @@ CFGFUN(bar_workspace_buttons, const char *value) {
current_bar.hide_workspace_buttons = !eval_boolstr(value); current_bar.hide_workspace_buttons = !eval_boolstr(value);
} }
CFGFUN(bar_strip_workspace_numbers, const char *value) {
current_bar.strip_workspace_numbers = eval_boolstr(value);
}
CFGFUN(bar_finish) { CFGFUN(bar_finish) {
DLOG("\t new bar configuration finished, saving.\n"); DLOG("\t new bar configuration finished, saving.\n");
/* Generate a unique ID for this bar if not already configured */ /* Generate a unique ID for this bar if not already configured */

View File

@ -514,6 +514,9 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) {
ystr("workspace_buttons"); ystr("workspace_buttons");
y(bool, !config->hide_workspace_buttons); y(bool, !config->hide_workspace_buttons);
ystr("strip_workspace_numbers");
y(bool, config->strip_workspace_numbers);
ystr("binding_mode_indicator"); ystr("binding_mode_indicator");
y(bool, !config->hide_binding_mode_indicator); y(bool, !config->hide_binding_mode_indicator);

View File

@ -627,7 +627,7 @@ EOT
$expected = <<'EOT'; $expected = <<'EOT';
cfg_bar_output(LVDS-1) cfg_bar_output(LVDS-1)
ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'position', 'output', 'tray_output', 'font', 'binding_mode_indicator', 'workspace_buttons', 'verbose', 'colors', '}' ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'position', 'output', 'tray_output', 'font', 'binding_mode_indicator', 'workspace_buttons', 'strip_workspace_numbers', 'verbose', 'colors', '}'
ERROR: CONFIG: (in file <stdin>) ERROR: CONFIG: (in file <stdin>)
ERROR: CONFIG: Line 1: bar { ERROR: CONFIG: Line 1: bar {
ERROR: CONFIG: Line 2: output LVDS-1 ERROR: CONFIG: Line 2: output LVDS-1