i3 - improved tiling WM


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