]> git.sur5r.net Git - i3/i3/blob - src/config.c
Merge branch 'master' into next
[i3/i3] / src / config.c
1 #undef I3__FILE__
2 #define I3__FILE__ "config.c"
3 /*
4  * vim:ts=4:sw=4:expandtab
5  *
6  * i3 - an improved dynamic tiling window manager
7  * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
8  *
9  * config.c: Configuration file (calling the parser (src/cfgparse.y) with the
10  *           correct path, switching key bindings mode).
11  *
12  */
13 #include "all.h"
14
15 /* We need Xlib for XStringToKeysym */
16 #include <X11/Xlib.h>
17
18 char *current_configpath = NULL;
19 Config config;
20 struct modes_head modes;
21 struct barconfig_head barconfigs = TAILQ_HEAD_INITIALIZER(barconfigs);
22
23 /**
24  * Ungrabs all keys, to be called before re-grabbing the keys because of a
25  * mapping_notify event or a configuration file reload
26  *
27  */
28 void ungrab_all_keys(xcb_connection_t *conn) {
29     DLOG("Ungrabbing all keys\n");
30     xcb_ungrab_key(conn, XCB_GRAB_ANY, root, XCB_BUTTON_MASK_ANY);
31 }
32
33 static void grab_keycode_for_binding(xcb_connection_t *conn, Binding *bind, uint32_t keycode) {
34     DLOG("Grabbing %d\n", keycode);
35     /* Grab the key in all combinations */
36     #define GRAB_KEY(modifier) \
37         do { \
38             xcb_grab_key(conn, 0, root, modifier, keycode, \
39                          XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); \
40         } while (0)
41     int mods = bind->mods;
42     if ((bind->mods & BIND_MODE_SWITCH) != 0) {
43         mods &= ~BIND_MODE_SWITCH;
44         if (mods == 0)
45             mods = XCB_MOD_MASK_ANY;
46     }
47     GRAB_KEY(mods);
48     GRAB_KEY(mods | xcb_numlock_mask);
49     GRAB_KEY(mods | XCB_MOD_MASK_LOCK);
50     GRAB_KEY(mods | xcb_numlock_mask | XCB_MOD_MASK_LOCK);
51 }
52
53 /*
54  * Returns a pointer to the Binding with the specified modifiers and keycode
55  * or NULL if no such binding exists.
56  *
57  */
58 Binding *get_binding(uint16_t modifiers, bool key_release, xcb_keycode_t keycode) {
59     Binding *bind;
60
61     if (!key_release) {
62         /* On a KeyPress event, we first reset all
63          * B_UPON_KEYRELEASE_IGNORE_MODS bindings back to B_UPON_KEYRELEASE */
64         TAILQ_FOREACH(bind, bindings, bindings) {
65             if (bind->release == B_UPON_KEYRELEASE_IGNORE_MODS)
66                 bind->release = B_UPON_KEYRELEASE;
67         }
68
69         /* Then we transition the KeyRelease bindings into a state where the
70          * modifiers no longer matter for the KeyRelease event so that users
71          * can release the modifier key before releasing the actual key. */
72         TAILQ_FOREACH(bind, bindings, bindings) {
73             if (bind->release == B_UPON_KEYRELEASE && !key_release)
74                 bind->release = B_UPON_KEYRELEASE_IGNORE_MODS;
75         }
76     }
77
78     TAILQ_FOREACH(bind, bindings, bindings) {
79         /* First compare the modifiers (unless this is a
80          * B_UPON_KEYRELEASE_IGNORE_MODS binding and this is a KeyRelease
81          * event) */
82         if (bind->mods != modifiers &&
83             (bind->release != B_UPON_KEYRELEASE_IGNORE_MODS ||
84              !key_release))
85             continue;
86
87         /* Check if the binding is for a KeyPress or a KeyRelease event */
88         if ((bind->release == B_UPON_KEYPRESS && key_release) ||
89             (bind->release >= B_UPON_KEYRELEASE && !key_release))
90             continue;
91
92         /* If a symbol was specified by the user, we need to look in
93          * the array of translated keycodes for the event’s keycode */
94         if (bind->symbol != NULL) {
95             if (memmem(bind->translated_to,
96                        bind->number_keycodes * sizeof(xcb_keycode_t),
97                        &keycode, sizeof(xcb_keycode_t)) != NULL)
98                 break;
99         } else {
100             /* This case is easier: The user specified a keycode */
101             if (bind->keycode == keycode)
102                 break;
103         }
104     }
105
106     return (bind == TAILQ_END(bindings) ? NULL : bind);
107 }
108
109 /*
110  * Translates keysymbols to keycodes for all bindings which use keysyms.
111  *
112  */
113 void translate_keysyms(void) {
114     Binding *bind;
115     xcb_keysym_t keysym;
116     int col;
117     xcb_keycode_t i,
118                   min_keycode = xcb_get_setup(conn)->min_keycode,
119                   max_keycode = xcb_get_setup(conn)->max_keycode;
120
121     TAILQ_FOREACH(bind, bindings, bindings) {
122         if (bind->keycode > 0)
123             continue;
124
125         /* We need to translate the symbol to a keycode */
126         keysym = XStringToKeysym(bind->symbol);
127         if (keysym == NoSymbol) {
128             ELOG("Could not translate string to key symbol: \"%s\"\n",
129                  bind->symbol);
130             continue;
131         }
132
133         /* Base column we use for looking up key symbols. We always consider
134          * the base column and the corresponding shift column, so without
135          * mode_switch, we look in 0 and 1, with mode_switch we look in 2 and
136          * 3. */
137         col = (bind->mods & BIND_MODE_SWITCH ? 2 : 0);
138
139         FREE(bind->translated_to);
140         bind->number_keycodes = 0;
141
142         for (i = min_keycode; i && i <= max_keycode; i++) {
143             if ((xcb_key_symbols_get_keysym(keysyms, i, col) != keysym) &&
144                 (xcb_key_symbols_get_keysym(keysyms, i, col+1) != keysym))
145                 continue;
146             bind->number_keycodes++;
147             bind->translated_to = srealloc(bind->translated_to,
148                                            (sizeof(xcb_keycode_t) *
149                                             bind->number_keycodes));
150             bind->translated_to[bind->number_keycodes-1] = i;
151         }
152
153         DLOG("Translated symbol \"%s\" to %d keycode\n", bind->symbol,
154              bind->number_keycodes);
155     }
156 }
157
158 /*
159  * Grab the bound keys (tell X to send us keypress events for those keycodes)
160  *
161  */
162 void grab_all_keys(xcb_connection_t *conn, bool bind_mode_switch) {
163     Binding *bind;
164     TAILQ_FOREACH(bind, bindings, bindings) {
165         if ((bind_mode_switch && (bind->mods & BIND_MODE_SWITCH) == 0) ||
166             (!bind_mode_switch && (bind->mods & BIND_MODE_SWITCH) != 0))
167             continue;
168
169         /* The easy case: the user specified a keycode directly. */
170         if (bind->keycode > 0) {
171             grab_keycode_for_binding(conn, bind, bind->keycode);
172             continue;
173         }
174
175         xcb_keycode_t *walk = bind->translated_to;
176         for (int i = 0; i < bind->number_keycodes; i++)
177             grab_keycode_for_binding(conn, bind, *walk++);
178     }
179 }
180
181 /*
182  * Switches the key bindings to the given mode, if the mode exists
183  *
184  */
185 void switch_mode(const char *new_mode) {
186     struct Mode *mode;
187
188     LOG("Switching to mode %s\n", new_mode);
189
190     SLIST_FOREACH(mode, &modes, modes) {
191         if (strcasecmp(mode->name, new_mode) != 0)
192             continue;
193
194         ungrab_all_keys(conn);
195         bindings = mode->bindings;
196         translate_keysyms();
197         grab_all_keys(conn, false);
198
199         char *event_msg;
200         sasprintf(&event_msg, "{\"change\":\"%s\"}", mode->name);
201
202         ipc_send_event("mode", I3_IPC_EVENT_MODE, event_msg);
203         FREE(event_msg);
204
205         return;
206     }
207
208     ELOG("ERROR: Mode not found\n");
209 }
210
211 /*
212  * Get the path of the first configuration file found. If override_configpath
213  * is specified, that path is returned and saved for further calls. Otherwise,
214  * checks the home directory first, then the system directory first, always
215  * taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME,
216  * $XDG_CONFIG_DIRS)
217  *
218  */
219 static char *get_config_path(const char *override_configpath) {
220     char *xdg_config_home, *xdg_config_dirs, *config_path;
221
222     static const char *saved_configpath = NULL;
223
224     if (override_configpath != NULL) {
225         saved_configpath = override_configpath;
226         return sstrdup(saved_configpath);
227     }
228
229     if (saved_configpath != NULL)
230         return sstrdup(saved_configpath);
231
232     /* 1: check the traditional path under the home directory */
233     config_path = resolve_tilde("~/.i3/config");
234     if (path_exists(config_path))
235         return config_path;
236     free(config_path);
237
238     /* 2: check for $XDG_CONFIG_HOME/i3/config */
239     if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
240         xdg_config_home = "~/.config";
241
242     xdg_config_home = resolve_tilde(xdg_config_home);
243     sasprintf(&config_path, "%s/i3/config", xdg_config_home);
244     free(xdg_config_home);
245
246     if (path_exists(config_path))
247         return config_path;
248     free(config_path);
249
250     /* 3: check the traditional path under /etc */
251     config_path = SYSCONFDIR "/i3/config";
252     if (path_exists(config_path))
253         return sstrdup(config_path);
254
255     /* 4: check for $XDG_CONFIG_DIRS/i3/config */
256     if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL)
257         xdg_config_dirs = "/etc/xdg";
258
259     char *buf = sstrdup(xdg_config_dirs);
260     char *tok = strtok(buf, ":");
261     while (tok != NULL) {
262         tok = resolve_tilde(tok);
263         sasprintf(&config_path, "%s/i3/config", tok);
264         free(tok);
265         if (path_exists(config_path)) {
266             free(buf);
267             return config_path;
268         }
269         free(config_path);
270         tok = strtok(NULL, ":");
271     }
272     free(buf);
273
274     die("Unable to find the configuration file (looked at "
275             "~/.i3/config, $XDG_CONFIG_HOME/i3/config, "
276             SYSCONFDIR "/i3/config and $XDG_CONFIG_DIRS/i3/config)");
277 }
278
279 /*
280  * Finds the configuration file to use (either the one specified by
281  * override_configpath), the user’s one or the system default) and calls
282  * parse_file().
283  *
284  */
285 static void parse_configuration(const char *override_configpath) {
286     char *path = get_config_path(override_configpath);
287     LOG("Parsing configfile %s\n", path);
288     FREE(current_configpath);
289     current_configpath = path;
290     parse_file(path);
291 }
292
293 /*
294  * (Re-)loads the configuration file (sets useful defaults before).
295  *
296  */
297 void load_configuration(xcb_connection_t *conn, const char *override_configpath, bool reload) {
298     if (reload) {
299         /* First ungrab the keys */
300         ungrab_all_keys(conn);
301
302         struct Mode *mode;
303         Binding *bind;
304         while (!SLIST_EMPTY(&modes)) {
305             mode = SLIST_FIRST(&modes);
306             FREE(mode->name);
307
308             /* Clear the old binding list */
309             bindings = mode->bindings;
310             while (!TAILQ_EMPTY(bindings)) {
311                 bind = TAILQ_FIRST(bindings);
312                 TAILQ_REMOVE(bindings, bind, bindings);
313                 FREE(bind->translated_to);
314                 FREE(bind->command);
315                 FREE(bind);
316             }
317             FREE(bindings);
318             SLIST_REMOVE(&modes, mode, Mode, modes);
319         }
320
321         struct Assignment *assign;
322         while (!TAILQ_EMPTY(&assignments)) {
323             assign = TAILQ_FIRST(&assignments);
324             if (assign->type == A_TO_WORKSPACE)
325                 FREE(assign->dest.workspace);
326             else if (assign->type == A_TO_OUTPUT)
327                 FREE(assign->dest.output);
328             else if (assign->type == A_COMMAND)
329                 FREE(assign->dest.command);
330             match_free(&(assign->match));
331             TAILQ_REMOVE(&assignments, assign, assignments);
332             FREE(assign);
333         }
334
335         /* Clear bar configs */
336         Barconfig *barconfig;
337         while (!TAILQ_EMPTY(&barconfigs)) {
338             barconfig = TAILQ_FIRST(&barconfigs);
339             FREE(barconfig->id);
340             for (int c = 0; c < barconfig->num_outputs; c++)
341                 free(barconfig->outputs[c]);
342             FREE(barconfig->outputs);
343             FREE(barconfig->tray_output);
344             FREE(barconfig->socket_path);
345             FREE(barconfig->status_command);
346             FREE(barconfig->i3bar_command);
347             FREE(barconfig->font);
348             FREE(barconfig->colors.background);
349             FREE(barconfig->colors.statusline);
350             FREE(barconfig->colors.focused_workspace_border);
351             FREE(barconfig->colors.focused_workspace_bg);
352             FREE(barconfig->colors.focused_workspace_text);
353             FREE(barconfig->colors.active_workspace_border);
354             FREE(barconfig->colors.active_workspace_bg);
355             FREE(barconfig->colors.active_workspace_text);
356             FREE(barconfig->colors.inactive_workspace_border);
357             FREE(barconfig->colors.inactive_workspace_bg);
358             FREE(barconfig->colors.inactive_workspace_text);
359             FREE(barconfig->colors.urgent_workspace_border);
360             FREE(barconfig->colors.urgent_workspace_bg);
361             FREE(barconfig->colors.urgent_workspace_text);
362             TAILQ_REMOVE(&barconfigs, barconfig, configs);
363             FREE(barconfig);
364         }
365
366         /* Clear workspace names */
367 #if 0
368         Workspace *ws;
369         TAILQ_FOREACH(ws, workspaces, workspaces)
370             workspace_set_name(ws, NULL);
371 #endif
372
373         /* Invalidate pixmap caches in case font or colors changed */
374         Con *con;
375         TAILQ_FOREACH(con, &all_cons, all_cons)
376             FREE(con->deco_render_params);
377
378         /* Get rid of the current font */
379         free_font();
380     }
381
382     SLIST_INIT(&modes);
383
384     struct Mode *default_mode = scalloc(sizeof(struct Mode));
385     default_mode->name = sstrdup("default");
386     default_mode->bindings = scalloc(sizeof(struct bindings_head));
387     TAILQ_INIT(default_mode->bindings);
388     SLIST_INSERT_HEAD(&modes, default_mode, modes);
389
390     bindings = default_mode->bindings;
391
392 #define REQUIRED_OPTION(name) \
393     if (config.name == NULL) \
394         die("You did not specify required configuration option " #name "\n");
395
396     /* Clear the old config or initialize the data structure */
397     memset(&config, 0, sizeof(config));
398
399     /* Initialize default colors */
400 #define INIT_COLOR(x, cborder, cbackground, ctext, cindicator) \
401     do { \
402         x.border = get_colorpixel(cborder); \
403         x.background = get_colorpixel(cbackground); \
404         x.text = get_colorpixel(ctext); \
405         x.indicator = get_colorpixel(cindicator); \
406     } while (0)
407
408     config.client.background = get_colorpixel("#000000");
409     INIT_COLOR(config.client.focused, "#4c7899", "#285577", "#ffffff", "#2e9ef4");
410     INIT_COLOR(config.client.focused_inactive, "#333333", "#5f676a", "#ffffff", "#484e50");
411     INIT_COLOR(config.client.unfocused, "#333333", "#222222", "#888888", "#292d2e");
412     INIT_COLOR(config.client.urgent, "#2f343a", "#900000", "#ffffff", "#900000");
413
414     /* the last argument (indicator color) is ignored for bar colors */
415     INIT_COLOR(config.bar.focused, "#4c7899", "#285577", "#ffffff", "#000000");
416     INIT_COLOR(config.bar.unfocused, "#333333", "#222222", "#888888", "#000000");
417     INIT_COLOR(config.bar.urgent, "#2f343a", "#900000", "#ffffff", "#000000");
418
419     config.default_border = BS_NORMAL;
420     config.default_floating_border = BS_NORMAL;
421     config.default_border_width = 2;
422     /* Set default_orientation to NO_ORIENTATION for auto orientation. */
423     config.default_orientation = NO_ORIENTATION;
424
425     /* Set default urgency reset delay to 500ms */
426     if (config.workspace_urgency_timer == 0)
427         config.workspace_urgency_timer = 0.5;
428
429     parse_configuration(override_configpath);
430
431     if (reload) {
432         translate_keysyms();
433         grab_all_keys(conn, false);
434     }
435
436     if (config.font.type == FONT_TYPE_NONE) {
437         ELOG("You did not specify required configuration option \"font\"\n");
438         config.font = load_font("fixed", true);
439         set_font(&config.font);
440     }
441
442     /* Redraw the currently visible decorations on reload, so that
443      * the possibly new drawing parameters changed. */
444     if (reload) {
445         x_deco_recurse(croot);
446         xcb_flush(conn);
447     }
448
449 #if 0
450     /* Set an empty name for every workspace which got no name */
451     Workspace *ws;
452     TAILQ_FOREACH(ws, workspaces, workspaces) {
453             if (ws->name != NULL) {
454                     /* If the font was not specified when the workspace name
455                      * was loaded, we need to predict the text width now */
456                     if (ws->text_width == 0)
457                             ws->text_width = predict_text_width(global_conn,
458                                             config.font, ws->name, ws->name_len);
459                     continue;
460             }
461
462             workspace_set_name(ws, NULL);
463     }
464 #endif
465 }