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 |
|