i3bar: implement custom mouse wheel commands
Patch status: merged
Patch by Tony Crisci
Long description:
Users can specify a command to run when a button was pressed on i3bar to override the default behavior. Currently only the mouse wheel buttons are supported. This is useful for disabling the scroll wheel action or running scripts that implement custom behavior for these buttons. Example: bar { wheel_up_cmd nop wheel_down_cmd exec ~/.i3/scripts/custom_wheel_down } fixes #1104
To apply this patch, use:
curl http://cr.i3wm.org/patch/619/raw.patch | git am
b/docs/userguide
35 |
@@ -1104,6 +1104,27 @@ bar { |
36 |
|
37 |
Available modifiers are Mod1-Mod5, Shift, Control (see +xmodmap(1)+). |
38 |
|
39 |
+=== Mouse button commands |
40 |
+ |
41 |
+Specifies a command to run when a button was pressed on i3bar to override the |
42 |
+default behavior. Currently only the mouse wheel buttons are supported. This is |
43 |
+useful for disabling the scroll wheel action or running scripts that implement |
44 |
+custom behavior for these buttons. |
45 |
+ |
46 |
+*Syntax*: |
47 |
+--------------------- |
48 |
+wheel_up_cmd <command> |
49 |
+wheel_down_cmd <command> |
50 |
+--------------------- |
51 |
+ |
52 |
+*Example*: |
53 |
+--------------------- |
54 |
+bar { |
55 |
+ wheel_up_cmd nop |
56 |
+ wheel_down_cmd exec ~/.i3/scripts/custom_wheel_down |
57 |
+} |
58 |
+--------------------- |
59 |
+ |
60 |
=== Bar ID |
61 |
|
62 |
Specifies the bar ID for the configured bar instance. If this option is missing, |
b/i3bar/include/config.h
67 |
@@ -24,6 +24,8 @@ typedef enum { M_DOCK = 0, |
68 |
|
69 |
typedef struct config_t { |
70 |
int modifier; |
71 |
+ char *wheel_up_cmd; |
72 |
+ char *wheel_down_cmd; |
73 |
position_t position; |
74 |
int verbose; |
75 |
struct xcb_color_strings_t colors; |
b/i3bar/src/config.c
80 |
@@ -112,6 +112,20 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len |
81 |
return 1; |
82 |
} |
83 |
|
84 |
+ if (!strcmp(cur_key, "wheel_up_cmd")) { |
85 |
+ DLOG("wheel_up_cmd = %.*s\n", len, val); |
86 |
+ FREE(config.wheel_up_cmd); |
87 |
+ sasprintf(&config.wheel_up_cmd, "%.*s", len, val); |
88 |
+ return 1; |
89 |
+ } |
90 |
+ |
91 |
+ if (!strcmp(cur_key, "wheel_down_cmd")) { |
92 |
+ DLOG("wheel_down_cmd = %.*s\n", len, val); |
93 |
+ FREE(config.wheel_down_cmd); |
94 |
+ sasprintf(&config.wheel_down_cmd, "%.*s", len, val); |
95 |
+ return 1; |
96 |
+ } |
97 |
+ |
98 |
if (!strcmp(cur_key, "position")) { |
99 |
DLOG("position = %.*s\n", len, val); |
100 |
config.position = (len == 3 && !strncmp((const char *)val, "top", strlen("top")) ? POS_TOP : POS_BOT); |
b/i3bar/src/xcb.c
105 |
@@ -370,6 +370,14 @@ void handle_button(xcb_button_press_event_t *event) { |
106 |
* If there is no more workspace, don’t even send the workspace |
107 |
* command, otherwise (with workspace auto_back_and_forth) we’d end |
108 |
* up on the wrong workspace. */ |
109 |
+ |
110 |
+ /* If `wheel_up_cmd [COMMAND]` was specified, it should override |
111 |
+ * the default behavior */ |
112 |
+ if (config.wheel_up_cmd) { |
113 |
+ i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, config.wheel_up_cmd); |
114 |
+ return; |
115 |
+ } |
116 |
+ |
117 |
if (cur_ws == TAILQ_FIRST(walk->workspaces)) |
118 |
return; |
119 |
|
120 |
@@ -380,6 +388,14 @@ void handle_button(xcb_button_press_event_t *event) { |
121 |
* If there is no more workspace, don’t even send the workspace |
122 |
* command, otherwise (with workspace auto_back_and_forth) we’d end |
123 |
* up on the wrong workspace. */ |
124 |
+ |
125 |
+ /* if `wheel_down_cmd [COMMAND]` was specified, it should override |
126 |
+ * the default behavior */ |
127 |
+ if (config.wheel_down_cmd) { |
128 |
+ i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, config.wheel_down_cmd); |
129 |
+ return; |
130 |
+ } |
131 |
+ |
132 |
if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head)) |
133 |
return; |
134 |
|
b/include/config.h
139 |
@@ -261,6 +261,14 @@ struct Barconfig { |
140 |
M_MOD5 = 7 |
141 |
} modifier; |
142 |
|
143 |
+ /** Command that should be run when mouse wheel up button is pressed over |
144 |
+ * i3bar to override the default behavior. */ |
145 |
+ char *wheel_up_cmd; |
146 |
+ |
147 |
+ /** Command that should be run when mouse wheel down button is pressed over |
148 |
+ * i3bar to override the default behavior. */ |
149 |
+ char *wheel_down_cmd; |
150 |
+ |
151 |
/** Bar position (bottom by default). */ |
152 |
enum { P_BOTTOM = 0, |
153 |
P_TOP = 1 } position; |
b/include/config_directives.h
158 |
@@ -73,6 +73,8 @@ CFGFUN(bar_id, const char *bar_id); |
159 |
CFGFUN(bar_output, const char *output); |
160 |
CFGFUN(bar_verbose, const char *verbose); |
161 |
CFGFUN(bar_modifier, const char *modifier); |
162 |
+CFGFUN(bar_wheel_up_cmd, const char *command); |
163 |
+CFGFUN(bar_wheel_down_cmd, const char *command); |
164 |
CFGFUN(bar_position, const char *position); |
165 |
CFGFUN(bar_i3bar_command, const char *i3bar_command); |
166 |
CFGFUN(bar_color, const char *colorclass, const char *border, const char *background, const char *text); |
b/parser-specs/config.spec
171 |
@@ -358,6 +358,8 @@ state BAR: |
172 |
'hidden_state' -> BAR_HIDDEN_STATE |
173 |
'id' -> BAR_ID |
174 |
'modifier' -> BAR_MODIFIER |
175 |
+ 'wheel_up_cmd' -> BAR_WHEEL_UP_CMD |
176 |
+ 'wheel_down_cmd' -> BAR_WHEEL_DOWN_CMD |
177 |
'position' -> BAR_POSITION |
178 |
'output' -> BAR_OUTPUT |
179 |
'tray_output' -> BAR_TRAY_OUTPUT |
180 |
@@ -403,6 +405,14 @@ state BAR_MODIFIER: |
181 |
modifier = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Control', 'Ctrl', 'Shift' |
182 |
-> call cfg_bar_modifier($modifier); BAR |
183 |
|
184 |
+state BAR_WHEEL_UP_CMD: |
185 |
+ command = string |
186 |
+ -> call cfg_bar_wheel_up_cmd($command); BAR |
187 |
+ |
188 |
+state BAR_WHEEL_DOWN_CMD: |
189 |
+ command = string |
190 |
+ -> call cfg_bar_wheel_down_cmd($command); BAR |
191 |
+ |
192 |
state BAR_POSITION: |
193 |
position = 'top', 'bottom' |
194 |
-> call cfg_bar_position($position); BAR |
b/src/config_directives.c
199 |
@@ -459,6 +459,16 @@ CFGFUN(bar_modifier, const char *modifier) { |
200 |
current_bar.modifier = M_SHIFT; |
201 |
} |
202 |
|
203 |
+CFGFUN(bar_wheel_up_cmd, const char *command) { |
204 |
+ FREE(current_bar.wheel_up_cmd); |
205 |
+ current_bar.wheel_up_cmd = sstrdup(command); |
206 |
+} |
207 |
+ |
208 |
+CFGFUN(bar_wheel_down_cmd, const char *command) { |
209 |
+ FREE(current_bar.wheel_down_cmd); |
210 |
+ current_bar.wheel_down_cmd = sstrdup(command); |
211 |
+} |
212 |
+ |
213 |
CFGFUN(bar_position, const char *position) { |
214 |
current_bar.position = (strcmp(position, "top") == 0 ? P_TOP : P_BOTTOM); |
215 |
} |
b/src/ipc.c
220 |
@@ -512,6 +512,16 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) { |
221 |
break; |
222 |
} |
223 |
|
224 |
+ if (config->wheel_up_cmd) { |
225 |
+ ystr("wheel_up_cmd"); |
226 |
+ ystr(config->wheel_up_cmd); |
227 |
+ } |
228 |
+ |
229 |
+ if (config->wheel_down_cmd) { |
230 |
+ ystr("wheel_down_cmd"); |
231 |
+ ystr(config->wheel_down_cmd); |
232 |
+ } |
233 |
+ |
234 |
ystr("position"); |
235 |
if (config->position == P_BOTTOM) |
236 |
ystr("bottom"); |
b/testcases/t/201-config-parser.t
241 |
@@ -645,7 +645,7 @@ EOT |
242 |
|
243 |
$expected = <<'EOT'; |
244 |
cfg_bar_output(LVDS-1) |
245 |
-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', '}' |
246 |
+ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'wheel_up_cmd', 'wheel_down_cmd', 'position', 'output', 'tray_output', 'font', 'binding_mode_indicator', 'workspace_buttons', 'strip_workspace_numbers', 'verbose', 'colors', '}' |
247 |
ERROR: CONFIG: (in file <stdin>) |
248 |
ERROR: CONFIG: Line 1: bar { |
249 |
ERROR: CONFIG: Line 2: output LVDS-1 |