i3 - improved tiling WM


Add mouse binding pointer position configuration

Patch status: merged

Patch by Tony Crisci

Long description:

Add the `--whole-window` switch for mouse bindings. This switch controls
what part of the container the pointer must be over to trigger a mouse
binding. The default is to only trigger mouse bindings over the
titlebars. With this switch, a mouse binding will be triggered over the
main part of the window as well.

This is a breaking change to the previous behavior, which would trigger
a mouse binding with a modifier over any part of the window.

fixes #1429

To apply this patch, use:
curl http://cr.i3wm.org/patch/706/raw.patch | git am

b/docs/userguide

31
@@ -404,12 +404,12 @@ can configure mouse bindings in a similar way to key bindings.
32
 
33
 *Syntax*:
34
 ----------------------------------
35
-bindsym [Modifiers+]button[n] command
36
+bindsym [--whole-window] [Modifiers+]button[n] command
37
 ----------------------------------
38
 
39
-If the binding has no modifiers, it will only run when you click on the
40
-titlebar of the window. Otherwise, it will run when any part of the window is
41
-clicked.
42
+By default, the binding will only run when you click on the titlebar of the
43
+window. If the +--whole-window+ flag is given, it will run when any part of the
44
+window is clicked.
45
 
46
 *Examples*:
47
 --------------------------------
48
@@ -417,7 +417,7 @@ clicked.
49
 bindsym button2 kill
50
 
51
 # The middle button and a modifer over any part of the window kills the window
52
-bindsym $mod+button2 kill
53
+bindsym --whole-window $mod+button2 kill
54
 
55
 # The right button toggles floating
56
 bindsym button3 floating toggle

b/include/bindings.h

61
@@ -24,7 +24,7 @@ const char *DEFAULT_BINDING_MODE;
62
  *
63
  */
64
 Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code,
65
-                           const char *release, const char *command, const char *mode);
66
+                           const char *release, const char *whole_window, const char *command, const char *mode);
67
 
68
 /**
69
  * Grab the bound keys (tell X to send us keypress events for those keycodes)

b/include/config_directives.h

74
@@ -61,10 +61,10 @@ CFGFUN(color_single, const char *colorclass, const char *color);
75
 CFGFUN(floating_modifier, const char *modifiers);
76
 CFGFUN(new_window, const char *windowtype, const char *border, const long width);
77
 CFGFUN(workspace, const char *workspace, const char *output);
78
-CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *command);
79
+CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command);
80
 
81
 CFGFUN(enter_mode, const char *mode);
82
-CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *command);
83
+CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command);
84
 
85
 CFGFUN(bar_font, const char *font);
86
 CFGFUN(bar_mode, const char *mode);

b/include/data.h

91
@@ -255,6 +255,11 @@ struct Binding {
92
         B_UPON_KEYRELEASE_IGNORE_MODS = 2,
93
     } release;
94
 
95
+    /** If this is true for a mouse binding, the binding should be executed
96
+     * when the button is pressed over any part of the window, not just the
97
+     * title bar (default). */
98
+    bool whole_window;
99
+
100
     uint32_t number_keycodes;
101
 
102
     /** Keycode to bind */

b/parser-specs/config.spec

107
@@ -278,6 +278,8 @@ state FONT:
108
 state BINDING:
109
   release = '--release'
110
       ->
111
+  whole_window = '--whole-window'
112
+      ->
113
   modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', '$mod'
114
       ->
115
   '+'
116
@@ -288,8 +290,10 @@ state BINDING:
117
 state BINDCOMMAND:
118
   release = '--release'
119
       ->
120
+  whole_window = '--whole-window'
121
+      ->
122
   command = string
123
-      -> call cfg_binding($bindtype, $modifiers, $key, $release, $command)
124
+      -> call cfg_binding($bindtype, $modifiers, $key, $release, $whole_window, $command)
125
 
126
 ################################################################################
127
 # Mode configuration
128
@@ -333,8 +337,10 @@ state MODE_BINDING:
129
 state MODE_BINDCOMMAND:
130
   release = '--release'
131
       ->
132
+  whole_window = '--whole-window'
133
+      ->
134
   command = string
135
-      -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $command); MODE
136
+      -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $whole_window, $command); MODE
137
 
138
 ################################################################################
139
 # Bar configuration (i3bar)

b/src/bindings.c

144
@@ -49,10 +49,11 @@ static struct Mode *mode_from_name(const char *name) {
145
  *
146
  */
147
 Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code,
148
-                           const char *release, const char *command, const char *modename) {
149
+                           const char *release, const char *whole_window, const char *command, const char *modename) {
150
     Binding *new_binding = scalloc(sizeof(Binding));
151
     DLOG("bindtype %s, modifiers %s, input code %s, release %s\n", bindtype, modifiers, input_code, release);
152
     new_binding->release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS);
153
+    new_binding->whole_window = (whole_window != NULL);
154
     if (strcmp(bindtype, "bindsym") == 0) {
155
         new_binding->input_type = (strncasecmp(input_code, "button", (sizeof("button") - 1)) == 0
156
                                        ? B_MOUSE

b/src/click.c

161
@@ -182,9 +182,9 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod
162
     if (dest == CLICK_DECORATION || dest == CLICK_INSIDE) {
163
         Binding *bind = get_binding_from_xcb_event((xcb_generic_event_t *)event);
164
         /* clicks over a window decoration will always trigger the binding and
165
-         * clicks on the inside of the window will only trigger a binding if it
166
-         * has modifiers. */
167
-        if (bind && (dest == CLICK_DECORATION || (bind->mods && dest == CLICK_INSIDE))) {
168
+         * clicks on the inside of the window will only trigger a binding if
169
+         * the --whole-window flag was given for the binding. */
170
+        if (bind && (dest == CLICK_DECORATION || bind->whole_window)) {
171
             CommandResult *result = run_binding(bind, con);
172
 
173
             /* ASYNC_POINTER eats the event */

b/src/config_directives.c

178
@@ -171,8 +171,8 @@ CFGFUN(font, const char *font) {
179
     font_pattern = sstrdup(font);
180
 }
181
 
182
-CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *command) {
183
-    configure_binding(bindtype, modifiers, key, release, command, DEFAULT_BINDING_MODE);
184
+CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command) {
185
+    configure_binding(bindtype, modifiers, key, release, whole_window, command, DEFAULT_BINDING_MODE);
186
 }
187
 
188
 /*******************************************************************************
189
@@ -181,8 +181,8 @@ CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, co
190
 
191
 static char *current_mode;
192
 
193
-CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *command) {
194
-    configure_binding(bindtype, modifiers, key, release, command, current_mode);
195
+CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command) {
196
+    configure_binding(bindtype, modifiers, key, release, whole_window, command, current_mode);
197
 }
198
 
199
 CFGFUN(enter_mode, const char *modename) {

b/testcases/t/201-config-parser.t

204
@@ -50,9 +50,9 @@ EOT
205
 
206
 my $expected = <<'EOT';
207
 cfg_enter_mode(meh)
208
-cfg_mode_binding(bindsym, Mod1,Shift, x, (null), resize grow)
209
-cfg_mode_binding(bindcode, Mod1, 44, (null), resize shrink)
210
-cfg_mode_binding(bindsym, Mod1, x, --release, exec foo)
211
+cfg_mode_binding(bindsym, Mod1,Shift, x, (null), (null), resize grow)
212
+cfg_mode_binding(bindcode, Mod1, 44, (null), (null), resize shrink)
213
+cfg_mode_binding(bindsym, Mod1, x, --release, (null), exec foo)
214
 EOT
215
 
216
 is(parser_calls($config),
217
@@ -618,7 +618,7 @@ EOT
218
 
219
 $expected = <<'EOT';
220
 cfg_enter_mode(yo)
221
-cfg_mode_binding(bindsym, (null), x, (null), resize shrink left)
222
+cfg_mode_binding(bindsym, (null), x, (null), (null), resize shrink left)
223
 ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'bindsym', 'bindcode', 'bind', '}'
224
 ERROR: CONFIG: (in file <stdin>)
225
 ERROR: CONFIG: Line   1: mode "yo" {