i3bar: implement custom workspace numbers config
Patch status: needinfo
Patch by Tony Crisci
Long description:
Implement the configuration option within the bar config directive to disable workspace numbers with the directive `workspace_numbers no`. This directive strips the workspace name of the number prefix and delimiter. For example: * "2:5" -> "5" * "4:$" -> "$" * "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
To apply this patch, use:
curl http://cr.i3wm.org/patch/509/raw.patch | git am
b/i3bar/include/config.h
| 36 |
@@ -27,6 +27,7 @@ typedef struct config_t {
|
| 37 |
struct xcb_color_strings_t colors; |
| 38 |
bool disable_binding_mode_indicator; |
| 39 |
bool disable_ws; |
| 40 |
+ bool disable_ws_numbers; |
| 41 |
char *bar_id; |
| 42 |
char *command; |
| 43 |
char *fontname; |
b/i3bar/include/workspaces.h
| 48 |
@@ -31,7 +31,8 @@ void free_workspaces(void); |
| 49 |
|
| 50 |
struct i3_ws {
|
| 51 |
int num; /* The internal number of the ws */ |
| 52 |
- i3String *name; /* The name of the ws */ |
| 53 |
+ char *canonical_name; /* The true name of the ws according to the ipc */ |
| 54 |
+ i3String *name; /* The name of the ws that is displayed on the bar */ |
| 55 |
int name_width; /* The rendered width of the name */ |
| 56 |
bool visible; /* If the ws is currently visible on an output */ |
| 57 |
bool focused; /* If the ws is currently focused */ |
b/i3bar/src/config.c
| 62 |
@@ -201,6 +201,12 @@ static int config_boolean_cb(void *params_, int val) {
|
| 63 |
return 1; |
| 64 |
} |
| 65 |
|
| 66 |
+ if (!strcmp(cur_key, "workspace_numbers")) {
|
| 67 |
+ DLOG("workspace_numbers = %d\n", val);
|
| 68 |
+ config.disable_ws_numbers = !val; |
| 69 |
+ return 1; |
| 70 |
+ } |
| 71 |
+ |
| 72 |
if (!strcmp(cur_key, "verbose")) {
|
| 73 |
DLOG("verbose = %d\n", val);
|
| 74 |
config.verbose = val; |
b/i3bar/src/workspaces.c
| 79 |
@@ -103,24 +103,49 @@ static int workspaces_integer_cb(void *params_, long val) {
|
| 80 |
* Parse a string (name, output) |
| 81 |
* |
| 82 |
*/ |
| 83 |
-#if YAJL_MAJOR >= 2 |
| 84 |
static int workspaces_string_cb(void *params_, const unsigned char *val, size_t len) {
|
| 85 |
-#else |
| 86 |
-static int workspaces_string_cb(void *params_, const unsigned char *val, unsigned int len) {
|
| 87 |
-#endif |
| 88 |
struct workspaces_json_params *params = (struct workspaces_json_params*) params_; |
| 89 |
|
| 90 |
char *output_name; |
| 91 |
|
| 92 |
if (!strcmp(params->cur_key, "name")) {
|
| 93 |
- /* Save the name */ |
| 94 |
- params->workspaces_walk->name = i3string_from_utf8_with_length((const char *)val, len); |
| 95 |
+ const char *ws_name = (const char*)val; |
| 96 |
+ params->workspaces_walk->canonical_name = strndup(ws_name, len); |
| 97 |
+ |
| 98 |
+ if (config.disable_ws_numbers) {
|
| 99 |
+ /* Special case: strip off the workspace number */ |
| 100 |
+ char *ws_num = malloc(sizeof(char) * 10); |
| 101 |
+ sprintf(ws_num, "%d", atoi(ws_name)); |
| 102 |
+ |
| 103 |
+ /* Calculate the length of the number str in the name */ |
| 104 |
+ int offset = strspn(ws_name, ws_num); |
| 105 |
+ |
| 106 |
+ /* Also strip off one of the conventional ws name delimiters */ |
| 107 |
+ if (offset |
| 108 |
+ && (ws_name[offset] == ':' |
| 109 |
+ || ws_name[offset] == ' ' |
| 110 |
+ || ws_name[offset] == '|')) {
|
| 111 |
+ offset += 1; |
| 112 |
+ } |
| 113 |
+ |
| 114 |
+ /* Offset may be equal to length, in which case just display a |
| 115 |
+ * space */ |
| 116 |
+ params->workspaces_walk->name = (offset < len |
| 117 |
+ ? i3string_from_utf8_with_length(ws_name + offset, len - offset) |
| 118 |
+ : i3string_from_utf8(" "));
|
| 119 |
+ |
| 120 |
+ FREE(ws_num); |
| 121 |
+ } else {
|
| 122 |
+ /* Default case: just save the name */ |
| 123 |
+ params->workspaces_walk->name = i3string_from_utf8_with_length(ws_name, len); |
| 124 |
+ } |
| 125 |
|
| 126 |
/* Save its rendered width */ |
| 127 |
params->workspaces_walk->name_width = |
| 128 |
predict_text_width(params->workspaces_walk->name); |
| 129 |
|
| 130 |
- DLOG("Got Workspace %s, name_width: %d, glyphs: %zu\n",
|
| 131 |
+ DLOG("Got Workspace canonical: %s, name: '%s', name_width: %d, glyphs: %zu\n",
|
| 132 |
+ params->workspaces_walk->canonical_name, |
| 133 |
i3string_as_utf8(params->workspaces_walk->name), |
| 134 |
params->workspaces_walk->name_width, |
| 135 |
i3string_get_num_glyphs(params->workspaces_walk->name)); |
| 136 |
@@ -267,6 +292,7 @@ void free_workspaces(void) {
|
| 137 |
if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) {
|
| 138 |
TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
|
| 139 |
I3STRING_FREE(ws_walk->name); |
| 140 |
+ FREE(ws_walk->canonical_name); |
| 141 |
} |
| 142 |
FREE_TAILQ(outputs_walk->workspaces, i3_ws); |
| 143 |
} |
b/i3bar/src/xcb.c
| 148 |
@@ -406,7 +406,7 @@ void handle_button(xcb_button_press_event_t *event) {
|
| 149 |
* buffer, then we copy character by character. */ |
| 150 |
int num_quotes = 0; |
| 151 |
size_t namelen = 0; |
| 152 |
- const char *utf8_name = i3string_as_utf8(cur_ws->name); |
| 153 |
+ const char *utf8_name = cur_ws->canonical_name; |
| 154 |
for (const char *walk = utf8_name; *walk != '\0'; walk++) {
|
| 155 |
if (*walk == '"') |
| 156 |
num_quotes++; |
b/include/config.h
| 161 |
@@ -267,6 +267,11 @@ struct Barconfig {
|
| 162 |
* zero. */ |
| 163 |
bool hide_workspace_buttons; |
| 164 |
|
| 165 |
+ /** Hide workspace numbers? Configuration option is 'workspace_numbers no' |
| 166 |
+ * but we invert the bool. This is for supporting custom keyboard layouts. |
| 167 |
+ * */ |
| 168 |
+ bool hide_workspace_numbers; |
| 169 |
+ |
| 170 |
/** Hide mode button? Configuration option is 'binding_mode_indicator no' |
| 171 |
* but we invert the bool for the same reason as hide_workspace_buttons.*/ |
| 172 |
bool hide_binding_mode_indicator; |
b/parser-specs/config.spec
| 177 |
@@ -358,6 +358,7 @@ state BAR: |
| 178 |
'font' -> BAR_FONT |
| 179 |
'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR |
| 180 |
'workspace_buttons' -> BAR_WORKSPACE_BUTTONS |
| 181 |
+ 'workspace_numbers' -> BAR_WORKSPACE_NUMBERS |
| 182 |
'verbose' -> BAR_VERBOSE |
| 183 |
'colors' -> BAR_COLORS_BRACE |
| 184 |
'}' |
| 185 |
@@ -420,6 +421,10 @@ state BAR_WORKSPACE_BUTTONS: |
| 186 |
value = word |
| 187 |
-> call cfg_bar_workspace_buttons($value); BAR |
| 188 |
|
| 189 |
+state BAR_WORKSPACE_NUMBERS: |
| 190 |
+ value = word |
| 191 |
+ -> call cfg_bar_workspace_numbers($value); BAR |
| 192 |
+ |
| 193 |
state BAR_VERBOSE: |
| 194 |
value = word |
| 195 |
-> call cfg_bar_verbose($value); BAR |
b/src/config_directives.c
| 200 |
@@ -517,6 +517,10 @@ CFGFUN(bar_workspace_buttons, const char *value) {
|
| 201 |
current_bar.hide_workspace_buttons = !eval_boolstr(value); |
| 202 |
} |
| 203 |
|
| 204 |
+CFGFUN(bar_workspace_numbers, const char *value) {
|
| 205 |
+ current_bar.hide_workspace_numbers = !eval_boolstr(value); |
| 206 |
+} |
| 207 |
+ |
| 208 |
CFGFUN(bar_finish) {
|
| 209 |
DLOG("\t new bar configuration finished, saving.\n");
|
| 210 |
/* Generate a unique ID for this bar if not already configured */ |
b/src/ipc.c
| 215 |
@@ -747,6 +747,9 @@ IPC_HANDLER(get_bar_config) {
|
| 216 |
ystr("workspace_buttons");
|
| 217 |
y(bool, !config->hide_workspace_buttons); |
| 218 |
|
| 219 |
+ ystr("workspace_numbers");
|
| 220 |
+ y(bool, !config->hide_workspace_numbers); |
| 221 |
+ |
| 222 |
ystr("binding_mode_indicator");
|
| 223 |
y(bool, !config->hide_binding_mode_indicator); |
| 224 |
|