i3 - improved tiling WM


Abstract binding configuration to bindings.[ch]

Patch status: needinfo

Patch by Tony Crisci

Long description:

Create files bindings.[ch] to contain functions for configuring,
finding, and running bindings.

Use the new function `configure_binding` for binding configuration. This
function adds a binding from config parameters.

Export the function `modifiers_from_str` from config_directives.h.

This change is made in preparation for the new bindmouse functionality.

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

b/include/all.h

28
@@ -79,6 +79,7 @@
29
 #include "scratchpad.h"
30
 #include "commands.h"
31
 #include "commands_parser.h"
32
+#include "bindings.h"
33
 #include "config_directives.h"
34
 #include "config_parser.h"
35
 #include "fake_outputs.h"

b/include/bindings.h

41
@@ -0,0 +1,24 @@
42
+/*
43
+ * vim:ts=4:sw=4:expandtab
44
+ *
45
+ * i3 - an improved dynamic tiling window manager
46
+ * © 2009-2014 Michael Stapelberg and contributors (see also: LICENSE)
47
+ *
48
+ * bindings.h: Functions for configuring, finding, and running bindings.
49
+ *
50
+ */
51
+#pragma once
52
+
53
+/**
54
+ * The name of the default mode.
55
+ *
56
+ */
57
+#define DEFAULT_BINDING_MODE "default"
58
+
59
+/**
60
+ * Adds a binding from config parameters given as strings and returns a
61
+ * pointer to the binding structure. Returns NULL if the input code could not
62
+ * be parsed.
63
+ *
64
+ */
65
+Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code, const char *release, const char *command, const char *mode);

b/include/config_directives.h

70
@@ -11,6 +11,12 @@
71
 
72
 #include "config_parser.h"
73
 
74
+/**
75
+ * A utility function to convert a string of modifiers to the corresponding bit
76
+ * mask.
77
+ */
78
+uint32_t modifiers_from_str(const char *str);
79
+
80
 /** The beginning of the prototype for every cfg_ function. */
81
 #define I3_CFG Match *current_match, struct ConfigResult *result
82
 

b/src/bindings.c

88
@@ -0,0 +1,62 @@
89
+/*
90
+ * vim:ts=4:sw=4:expandtab
91
+ *
92
+ * i3 - an improved dynamic tiling window manager
93
+ * © 2009-2014 Michael Stapelberg and contributors (see also: LICENSE)
94
+ *
95
+ * bindings.c: Functions for configuring, finding and, running bindings.
96
+ */
97
+#include "all.h"
98
+
99
+/*
100
+ * Returns the mode specified by `name` or creates a new mode and adds it to
101
+ * the list of modes.
102
+ *
103
+ */
104
+static struct Mode *mode_from_name(const char *name) {
105
+    struct Mode *mode;
106
+    SLIST_FOREACH(mode, &modes, modes) {
107
+        if (strcmp(mode->name, name) == 0)
108
+            break;
109
+    }
110
+
111
+    if (mode == NULL) {
112
+        mode = scalloc(sizeof(struct Mode));
113
+        mode->name = sstrdup(name);
114
+        mode->bindings = scalloc(sizeof(struct bindings_head));
115
+        TAILQ_INIT(mode->bindings);
116
+        SLIST_INSERT_HEAD(&modes, mode, modes);
117
+    }
118
+
119
+    return mode;
120
+}
121
+
122
+/*
123
+ * Adds a binding from config parameters given as strings and returns a
124
+ * pointer to the binding structure. Returns NULL if the input code could not
125
+ * be parsed.
126
+ *
127
+ */
128
+Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code, const char *release, const char *command, const char *modename) {
129
+    Binding *new_binding = scalloc(sizeof(Binding));
130
+    DLOG("bindtype %s, modifiers %s, input code %s, release %s\n", bindtype, modifiers, input_code, release);
131
+    new_binding->release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS);
132
+    if (strcmp(bindtype, "bindsym") == 0) {
133
+        new_binding->symbol = sstrdup(input_code);
134
+    } else {
135
+        // TODO: strtol with proper error handling
136
+        new_binding->keycode = atoi(input_code);
137
+        if (new_binding->keycode == 0) {
138
+            ELOG("Could not parse \"%s\" as an input code, ignoring this binding.\n", input_code);
139
+            return NULL;
140
+        }
141
+    }
142
+    new_binding->mods = modifiers_from_str(modifiers);
143
+    new_binding->command = sstrdup(command);
144
+    new_binding->input_type = B_KEYBOARD;
145
+
146
+    struct Mode *mode = mode_from_name(modename);
147
+    TAILQ_INSERT_TAIL(mode->bindings, new_binding, bindings);
148
+
149
+    return new_binding;
150
+}

b/src/config_directives.c

155
@@ -130,7 +130,11 @@ static bool eval_boolstr(const char *str) {
156
             strcasecmp(str, "active") == 0);
157
 }
158
 
159
-static uint32_t modifiers_from_str(const char *str) {
160
+/*
161
+ * A utility function to convert a string of modifiers to the corresponding bit
162
+ * mask.
163
+ */
164
+uint32_t modifiers_from_str(const char *str) {
165
     /* It might be better to use strtok() here, but the simpler strstr() should
166
      * do for now. */
167
     uint32_t result = 0;
168
@@ -167,24 +171,8 @@ CFGFUN(font, const char *font) {
169
 	font_pattern = sstrdup(font);
170
 }
171
 
172
-// TODO: refactor with mode_binding
173
 CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *command) {
174
-    Binding *new_binding = scalloc(sizeof(Binding));
175
-    DLOG("bindtype %s, modifiers %s, key %s, release %s\n", bindtype, modifiers, key, release);
176
-    new_binding->release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS);
177
-    if (strcmp(bindtype, "bindsym") == 0) {
178
-        new_binding->symbol = sstrdup(key);
179
-    } else {
180
-        // TODO: strtol with proper error handling
181
-        new_binding->keycode = atoi(key);
182
-        if (new_binding->keycode == 0) {
183
-            ELOG("Could not parse \"%s\" as a keycode, ignoring this binding.\n", key);
184
-            return;
185
-        }
186
-    }
187
-    new_binding->mods = modifiers_from_str(modifiers);
188
-    new_binding->command = sstrdup(command);
189
-    TAILQ_INSERT_TAIL(bindings, new_binding, bindings);
190
+    configure_binding(bindtype, modifiers, key, release, command, DEFAULT_BINDING_MODE);
191
 }
192
 
193
 
194
@@ -192,39 +180,20 @@ CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, co
195
  * Mode handling
196
  ******************************************************************************/
197
 
198
-static struct bindings_head *current_bindings;
199
+static char *current_mode;
200
 
201
 CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *command) {
202
-    Binding *new_binding = scalloc(sizeof(Binding));
203
-    DLOG("bindtype %s, modifiers %s, key %s, release %s\n", bindtype, modifiers, key, release);
204
-    new_binding->release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS);
205
-    if (strcmp(bindtype, "bindsym") == 0) {
206
-        new_binding->symbol = sstrdup(key);
207
-    } else {
208
-        // TODO: strtol with proper error handling
209
-        new_binding->keycode = atoi(key);
210
-        if (new_binding->keycode == 0) {
211
-            ELOG("Could not parse \"%s\" as a keycode, ignoring this binding.\n", key);
212
-            return;
213
-        }
214
-    }
215
-    new_binding->mods = modifiers_from_str(modifiers);
216
-    new_binding->command = sstrdup(command);
217
-    TAILQ_INSERT_TAIL(current_bindings, new_binding, bindings);
218
+    configure_binding(bindtype, modifiers, key, release, command, current_mode);
219
 }
220
 
221
 CFGFUN(enter_mode, const char *modename) {
222
-    if (strcasecmp(modename, "default") == 0) {
223
-        ELOG("You cannot use the name \"default\" for your mode\n");
224
+    if (strcasecmp(modename, DEFAULT_BINDING_MODE) == 0) {
225
+        ELOG("You cannot use the name %s for your mode\n", DEFAULT_BINDING_MODE);
226
         exit(1);
227
     }
228
     DLOG("\t now in mode %s\n", modename);
229
-    struct Mode *mode = scalloc(sizeof(struct Mode));
230
-    mode->name = sstrdup(modename);
231
-    mode->bindings = scalloc(sizeof(struct bindings_head));
232
-    TAILQ_INIT(mode->bindings);
233
-    current_bindings = mode->bindings;
234
-    SLIST_INSERT_HEAD(&modes, mode, modes);
235
+    FREE(current_mode);
236
+    current_mode = sstrdup(modename);
237
 }
238
 
239
 CFGFUN(exec, const char *exectype, const char *no_startup_id, const char *command) {