X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fconfig.c;h=572b4ab9f93075a73a22e9886fa80f94b24c5eea;hb=5ae4620a2484a390dd63642ba66fbb4ca09cbd21;hp=8d129bf445605daf9ec252eb4d0417a020caab07;hpb=4ace0d2138c607f2b26f431a7e141a9ee943bb15;p=i3%2Fi3 diff --git a/src/config.c b/src/config.c index 8d129bf4..572b4ab9 100644 --- a/src/config.c +++ b/src/config.c @@ -1,9 +1,9 @@ /* - * vim:ts=8:expandtab + * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager * - * © 2009 Michael Stapelberg and contributors + * © 2009-2010 Michael Stapelberg and contributors * * See file LICENSE for license information. * @@ -12,97 +12,97 @@ * mode). * */ -#include -#include -#include -#include -#include /* We need Xlib for XStringToKeysym */ #include +#include -#include - -#include "i3.h" -#include "util.h" -#include "config.h" -#include "xcb.h" -#include "table.h" -#include "workspace.h" +#include "all.h" +char *current_configpath = NULL; Config config; struct modes_head modes; -/* - * This function resolves ~ in pathnames. - * - */ -static char *glob_path(const char *path) { - static glob_t globbuf; - if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) - die("glob() failed"); - char *result = sstrdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); - globfree(&globbuf); - return result; -} - /** * Ungrabs all keys, to be called before re-grabbing the keys because of a * mapping_notify event or a configuration file reload * */ void ungrab_all_keys(xcb_connection_t *conn) { - LOG("Ungrabbing all keys\n"); + DLOG("Ungrabbing all keys\n"); xcb_ungrab_key(conn, XCB_GRAB_ANY, root, XCB_BUTTON_MASK_ANY); } static void grab_keycode_for_binding(xcb_connection_t *conn, Binding *bind, uint32_t keycode) { - LOG("Grabbing %d\n", keycode); - if ((bind->mods & BIND_MODE_SWITCH) != 0) - xcb_grab_key(conn, 0, root, 0, keycode, - XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC); - else { - /* Grab the key in all combinations */ - #define GRAB_KEY(modifier) xcb_grab_key(conn, 0, root, modifier, keycode, \ - XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC) - GRAB_KEY(bind->mods); - GRAB_KEY(bind->mods | xcb_numlock_mask); - GRAB_KEY(bind->mods | xcb_numlock_mask | XCB_MOD_MASK_LOCK); + DLOG("Grabbing %d\n", keycode); + /* Grab the key in all combinations */ + #define GRAB_KEY(modifier) \ + do { \ + xcb_grab_key(conn, 0, root, modifier, keycode, \ + XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); \ + } while (0) + int mods = bind->mods; + if ((bind->mods & BIND_MODE_SWITCH) != 0) { + mods &= ~BIND_MODE_SWITCH; + if (mods == 0) + mods = XCB_MOD_MASK_ANY; } + GRAB_KEY(mods); + GRAB_KEY(mods | xcb_numlock_mask); + GRAB_KEY(mods | xcb_numlock_mask | XCB_MOD_MASK_LOCK); } /* - * Grab the bound keys (tell X to send us keypress events for those keycodes) + * Returns a pointer to the Binding with the specified modifiers and keycode + * or NULL if no such binding exists. * */ -void grab_all_keys(xcb_connection_t *conn) { +Binding *get_binding(uint16_t modifiers, xcb_keycode_t keycode) { Binding *bind; + TAILQ_FOREACH(bind, bindings, bindings) { - /* The easy case: the user specified a keycode directly. */ - if (bind->keycode > 0) { - grab_keycode_for_binding(conn, bind, bind->keycode); + /* First compare the modifiers */ + if (bind->mods != modifiers) continue; + + /* If a symbol was specified by the user, we need to look in + * the array of translated keycodes for the event’s keycode */ + if (bind->symbol != NULL) { + if (memmem(bind->translated_to, + bind->number_keycodes * sizeof(xcb_keycode_t), + &keycode, sizeof(xcb_keycode_t)) != NULL) + break; + } else { + /* This case is easier: The user specified a keycode */ + if (bind->keycode == keycode) + break; } + } + + return (bind == TAILQ_END(bindings) ? NULL : bind); +} + +/* + * Translates keysymbols to keycodes for all bindings which use keysyms. + * + */ +void translate_keysyms() { + Binding *bind; + TAILQ_FOREACH(bind, bindings, bindings) { + if (bind->keycode > 0) + continue; /* We need to translate the symbol to a keycode */ xcb_keysym_t keysym = XStringToKeysym(bind->symbol); if (keysym == NoSymbol) { - LOG("Could not translate string to key symbol: \"%s\"\n", bind->symbol); + ELOG("Could not translate string to key symbol: \"%s\"\n", bind->symbol); continue; } -#ifdef OLD_XCB_KEYSYMS_API - bind->number_keycodes = 1; - xcb_keycode_t code = xcb_key_symbols_get_keycode(keysyms, keysym); - LOG("Translated symbol \"%s\" to 1 keycode (%d)\n", bind->symbol, code); - grab_keycode_for_binding(conn, bind, code); - bind->translated_to = smalloc(sizeof(xcb_keycode_t)); - memcpy(bind->translated_to, &code, sizeof(xcb_keycode_t)); -#else uint32_t last_keycode = 0; xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, keysym); if (keycodes == NULL) { - LOG("Could not translate symbol \"%s\"\n", bind->symbol); + DLOG("Could not translate symbol \"%s\"\n", bind->symbol); continue; } @@ -113,15 +113,36 @@ void grab_all_keys(xcb_connection_t *conn) { * and skip them */ if (last_keycode == *walk) continue; - grab_keycode_for_binding(conn, bind, *walk); last_keycode = *walk; bind->number_keycodes++; } - LOG("Translated symbol \"%s\" to %d keycode\n", bind->symbol, bind->number_keycodes); + DLOG("Translated symbol \"%s\" to %d keycode\n", bind->symbol, bind->number_keycodes); bind->translated_to = smalloc(bind->number_keycodes * sizeof(xcb_keycode_t)); memcpy(bind->translated_to, keycodes, bind->number_keycodes * sizeof(xcb_keycode_t)); free(keycodes); -#endif + } +} + +/* + * Grab the bound keys (tell X to send us keypress events for those keycodes) + * + */ +void grab_all_keys(xcb_connection_t *conn, bool bind_mode_switch) { + Binding *bind; + TAILQ_FOREACH(bind, bindings, bindings) { + if ((bind_mode_switch && (bind->mods & BIND_MODE_SWITCH) == 0) || + (!bind_mode_switch && (bind->mods & BIND_MODE_SWITCH) != 0)) + continue; + + /* The easy case: the user specified a keycode directly. */ + if (bind->keycode > 0) { + grab_keycode_for_binding(conn, bind, bind->keycode); + continue; + } + + xcb_keycode_t *walk = bind->translated_to; + for (int i = 0; i < bind->number_keycodes; i++) + grab_keycode_for_binding(conn, bind, *walk); } } @@ -140,11 +161,81 @@ void switch_mode(xcb_connection_t *conn, const char *new_mode) { ungrab_all_keys(conn); bindings = mode->bindings; - grab_all_keys(conn); + translate_keysyms(); + grab_all_keys(conn, false); return; } - LOG("ERROR: Mode not found\n"); + ELOG("ERROR: Mode not found\n"); +} + +/* + * Get the path of the first configuration file found. If override_configpath + * is specified, that path is returned and saved for further calls. Otherwise, + * checks the home directory first, then the system directory first, always + * taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME, + * $XDG_CONFIG_DIRS) + * + */ +static char *get_config_path(const char *override_configpath) { + char *xdg_config_home, *xdg_config_dirs, *config_path; + + static const char *saved_configpath = NULL; + + if (override_configpath != NULL) { + saved_configpath = override_configpath; + return sstrdup(saved_configpath); + } + + if (saved_configpath != NULL) + return sstrdup(saved_configpath); + + /* 1: check the traditional path under the home directory */ + config_path = resolve_tilde("~/.i3/config"); + if (path_exists(config_path)) + return config_path; + + /* 2: check for $XDG_CONFIG_HOME/i3/config */ + if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL) + xdg_config_home = "~/.config"; + + xdg_config_home = resolve_tilde(xdg_config_home); + if (asprintf(&config_path, "%s/i3/config", xdg_config_home) == -1) + die("asprintf() failed"); + free(xdg_config_home); + + if (path_exists(config_path)) + return config_path; + free(config_path); + + /* 3: check the traditional path under /etc */ + config_path = SYSCONFDIR "/i3/config"; + if (path_exists(config_path)) + return sstrdup(config_path); + + /* 4: check for $XDG_CONFIG_DIRS/i3/config */ + if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL) + xdg_config_dirs = "/etc/xdg"; + + char *buf = sstrdup(xdg_config_dirs); + char *tok = strtok(buf, ":"); + while (tok != NULL) { + tok = resolve_tilde(tok); + if (asprintf(&config_path, "%s/i3/config", tok) == -1) + die("asprintf() failed"); + free(tok); + if (path_exists(config_path)) { + free(buf); + return config_path; + } + free(config_path); + tok = strtok(NULL, ":"); + } + free(buf); + + die("Unable to find the configuration file (looked at " + "~/.i3/config, $XDG_CONFIG_HOME/i3/config, " + SYSCONFDIR "i3/config and $XDG_CONFIG_DIRS/i3/config)"); } /* @@ -154,23 +245,11 @@ void switch_mode(xcb_connection_t *conn, const char *new_mode) { * */ static void parse_configuration(const char *override_configpath) { - if (override_configpath != NULL) { - parse_file(override_configpath); - return; - } - - FILE *handle; - char *globbed = glob_path("~/.i3/config"); - if ((handle = fopen(globbed, "r")) == NULL) { - if ((handle = fopen("/etc/i3/config", "r")) == NULL) - die("Neither \"%s\" nor /etc/i3/config could be opened\n", globbed); - - parse_file("/etc/i3/config"); - return; - } - - parse_file(globbed); - fclose(handle); + char *path = get_config_path(override_configpath); + DLOG("Parsing configfile %s\n", path); + FREE(current_configpath); + current_configpath = path; + parse_file(path); } /* @@ -201,6 +280,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, SLIST_REMOVE(&modes, mode, Mode, modes); } +#if 0 struct Assignment *assign; while (!TAILQ_EMPTY(&assignments)) { assign = TAILQ_FIRST(&assignments); @@ -208,6 +288,14 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, TAILQ_REMOVE(&assignments, assign, assignments); FREE(assign); } +#endif + + /* Clear workspace names */ +#if 0 + Workspace *ws; + TAILQ_FOREACH(ws, workspaces, workspaces) + workspace_set_name(ws, NULL); +#endif } SLIST_INIT(&modes); @@ -230,11 +318,12 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, /* Initialize default colors */ #define INIT_COLOR(x, cborder, cbackground, ctext) \ do { \ - x.border = get_colorpixel(conn, cborder); \ - x.background = get_colorpixel(conn, cbackground); \ - x.text = get_colorpixel(conn, ctext); \ + x.border = get_colorpixel(cborder); \ + x.background = get_colorpixel(cbackground); \ + x.text = get_colorpixel(ctext); \ } while (0) + config.client.background = get_colorpixel("#000000"); INIT_COLOR(config.client.focused, "#4c7899", "#285577", "#ffffff"); INIT_COLOR(config.client.focused_inactive, "#333333", "#5f676a", "#ffffff"); INIT_COLOR(config.client.unfocused, "#333333", "#222222", "#888888"); @@ -243,13 +332,23 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, INIT_COLOR(config.bar.unfocused, "#333333", "#222222", "#888888"); INIT_COLOR(config.bar.urgent, "#2f343a", "#900000", "#ffffff"); + config.default_border = BS_NORMAL; + /* Set default_orientation to NO_ORIENTATION for auto orientation. */ + config.default_orientation = NO_ORIENTATION; + parse_configuration(override_configpath); - if (reload) - grab_all_keys(conn); + if (reload) { + translate_keysyms(); + grab_all_keys(conn, false); + } - REQUIRED_OPTION(font); + if (config.font.id == 0) { + ELOG("You did not specify required configuration option \"font\"\n"); + config.font = load_font("fixed", true); + } +#if 0 /* Set an empty name for every workspace which got no name */ Workspace *ws; TAILQ_FOREACH(ws, workspaces, workspaces) { @@ -264,4 +363,5 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, workspace_set_name(ws, NULL); } +#endif }