X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fconfig.c;h=a5f635dc5920eaf4c6a07591078cd5d39e5e9c6d;hb=4da54f12797fac971054d94da7de81208b36a69f;hp=1530622f68f3387fd1f73bf8fb3e9876df6ab5e4;hpb=40750e227dc15116c8af0a8723eafa0469b019dc;p=i3%2Fi3 diff --git a/src/config.c b/src/config.c index 1530622f..a5f635dc 100644 --- a/src/config.c +++ b/src/config.c @@ -14,10 +14,17 @@ #include #include +/* We need Xlib for XStringToKeysym */ +#include + +#include + #include "i3.h" #include "util.h" #include "config.h" #include "xcb.h" +#include "table.h" +#include "workspace.h" Config config; @@ -43,9 +50,7 @@ static void replace_variable(char *buffer, const char *key, const char *value) { /* To prevent endless recursions when the user makes an error configuring, * we stop after 100 replacements. That should be vastly more than enough. */ int c = 0; - LOG("Replacing %s with %s\n", key, value); while ((pos = strcasestr(buffer, key)) != NULL && c++ < 100) { - LOG("replacing variable %s in \"%s\" with \"%s\"\n", key, buffer, value); char *rest = pos + strlen(key); *pos = '\0'; char *replaced; @@ -57,33 +62,72 @@ static void replace_variable(char *buffer, const char *key, const char *value) { } } -/* UnGrab the bound keys */ - +/** + * 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) { - Binding *bind; - TAILQ_FOREACH(bind, &bindings, bindings) { - LOG("UnGrabbing %d\n", bind->keycode); - #define UNGRAB_KEY(modifier) xcb_ungrab_key(conn,bind->keycode,root,modifier); - UNGRAB_KEY(bind->keycode); + LOG("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); } } -/* Grab the bound keys */ +/* + * Grab the bound keys (tell X to send us keypress events for those keycodes) + * + */ void grab_all_keys(xcb_connection_t *conn) { Binding *bind; TAILQ_FOREACH(bind, &bindings, bindings) { - LOG("Grabbing %d\n", bind->keycode); - if ( bind->mods & BIND_MODE_SWITCH ) - xcb_grab_key(conn, 0, root, 0, bind->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, bind->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); + /* The easy case: the user specified a keycode directly. */ + if (bind->keycode > 0) { + grab_keycode_for_binding(conn, bind, bind->keycode); + 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); + continue; + } + + xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, keysym); + if (keycodes == NULL) { + LOG("Could not translate symbol \"%s\"\n", bind->symbol); + continue; + } + + uint32_t last_keycode = 0; + bind->number_keycodes = 0; + for (xcb_keycode_t *walk = keycodes; *walk != 0; walk++) { + /* We hope duplicate keycodes will be returned in order + * 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); + 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); } } @@ -94,28 +138,29 @@ void grab_all_keys(xcb_connection_t *conn) { * configuration file. * */ -void load_configuration(xcb_connection_t *conn, const char *override_configpath,bool reload) { - - if(reload) { +void load_configuration(xcb_connection_t *conn, const char *override_configpath, bool reload) { + if (reload) { /* First ungrab the keys */ ungrab_all_keys(conn); - /* clean up lists */ + + /* Clear the old binding and assignment lists */ Binding *bind; - TAILQ_FOREACH(bind,&bindings,bindings) { - TAILQ_REMOVE(&bindings,bind,bindings); - free(bind->command); - free(bind); + while (!TAILQ_EMPTY(&bindings)) { + bind = TAILQ_FIRST(&bindings); + TAILQ_REMOVE(&bindings, bind, bindings); + FREE(bind->command); + FREE(bind); } struct Assignment *assign; - TAILQ_FOREACH(assign,&assignments,assignments) { - TAILQ_REMOVE(&assignments,assign,assignments); - free(assign->windowclass_title); - free(assign) + while (!TAILQ_EMPTY(&assignments)) { + assign = TAILQ_FIRST(&assignments); + FREE(assign->windowclass_title); + TAILQ_REMOVE(&assignments, assign, assignments); + FREE(assign); } } - SLIST_HEAD(variables_head, Variable) variables; #define OPTION_STRING(name) \ @@ -227,7 +272,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, } /* key bindings */ - if (strcasecmp(key, "bind") == 0) { + if (strcasecmp(key, "bind") == 0 || strcasecmp(key, "bindsym") == 0) { #define CHECK_MODIFIER(name) \ if (strncasecmp(walk, #name, strlen(#name)) == 0) { \ modifiers |= BIND_##name; \ @@ -252,14 +297,25 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, break; } - /* Now check for the keycode */ - int keycode = strtol(walk, &rest, 10); - if (!rest || *rest != ' ') - die("Invalid binding\n"); + Binding *new = scalloc(sizeof(Binding)); + + /* Now check for the keycode or copy the symbol */ + if (strcasecmp(key, "bind") == 0) { + int keycode = strtol(walk, &rest, 10); + if (!rest || *rest != ' ') + die("Invalid binding (keycode)\n"); + new->keycode = keycode; + } else { + rest = walk; + char *sym = rest; + while (*rest != '\0' && *rest != ' ') + rest++; + if (*rest != ' ') + die("Invalid binding (keysym)\n"); + new->symbol = strndup(sym, (rest - sym)); + } rest++; - LOG("keycode = %d, modifiers = %d, command = *%s*\n", keycode, modifiers, rest); - Binding *new = smalloc(sizeof(Binding)); - new->keycode = keycode; + LOG("keycode = %d, symbol = %s, modifiers = %d, command = *%s*\n", new->keycode, new->symbol, modifiers, rest); new->mods = modifiers; new->command = sstrdup(rest); TAILQ_INSERT_TAIL(&bindings, new, bindings); @@ -290,26 +346,77 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, continue; } + /* workspace "workspace number" [screen ] ["name of the workspace"] + * with screen := | , e.g. screen 1280 or screen 1 */ + if (strcasecmp(key, "name") == 0 || strcasecmp(key, "workspace") == 0) { + LOG("workspace: %s\n",value); + char *ws_str = sstrdup(value); + char *end = strchr(ws_str, ' '); + if (end == NULL) + die("Malformed name, couln't find terminating space\n"); + *end = '\0'; + + /* Strip trailing whitespace */ + while (strlen(value) > 0 && value[strlen(value)-1] == ' ') + value[strlen(value)-1] = '\0'; + + int ws_num = atoi(ws_str); + + if (ws_num < 1 || ws_num > 10) + die("Malformed name, invalid workspace number\n"); + + /* find the name */ + char *name = value; + name += strlen(ws_str) + 1; + + if (strncasecmp(name, "screen ", strlen("screen ")) == 0) { + char *screen = strdup(name + strlen("screen ")); + if ((end = strchr(screen, ' ')) != NULL) + *end = '\0'; + LOG("Setting preferred screen for workspace %d to \"%s\"\n", ws_num, screen); + workspaces[ws_num - 1].preferred_screen = screen; + + name += strlen("screen ") + strlen(screen); + + } + + /* Strip leading whitespace */ + while (*name != '\0' && *name == ' ') + name++; + + LOG("rest to parse = %s\n", name); + + if (name == '\0') { + free(ws_str); + continue; + } + + LOG("setting name to \"%s\"\n", name); + + workspace_set_name(&(workspaces[ws_num - 1]), name); + free(ws_str); + continue; + } + /* assign window class[/window title] → workspace */ if (strcasecmp(key, "assign") == 0) { LOG("assign: \"%s\"\n", value); - char *class_title = sstrdup(value); + char *class_title; char *target; + char *end; /* If the window class/title is quoted we skip quotes */ - if (class_title[0] == '"') { - class_title++; - char *end = strchr(class_title, '"'); - if (end == NULL) - die("Malformed assignment, couldn't find terminating quote\n"); - *end = '\0'; + if (value[0] == '"') { + class_title = sstrdup(value+1); + end = strchr(class_title, '"'); } else { + class_title = sstrdup(value); /* If it is not quoted, we terminate it at the first space */ - char *end = strchr(class_title, ' '); - if (end == NULL) - die("Malformed assignment, couldn't find terminating space\n"); - *end = '\0'; + end = strchr(class_title, ' '); } + if (end == NULL) + die("Malformed assignment, couldn't find terminating quote\n"); + *end = '\0'; /* Strip trailing whitespace */ while (strlen(value) > 0 && value[strlen(value)-1] == ' ') @@ -317,7 +424,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, /* The target is the last argument separated by a space */ if ((target = strrchr(value, ' ')) == NULL) - die("Malformed assignment, couldn't find target\n"); + die("Malformed assignment, couldn't find target (\"%s\")\n", value); target++; if (strchr(target, '~') == NULL && (atoi(target) < 1 || atoi(target) > 10)) @@ -370,17 +477,21 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, continue; } + if (strcasecmp(key, "ipc-socket") == 0) { + config.ipc_socket_path = sstrdup(value); + continue; + } + die("Unknown configfile option: %s\n", key); } /* now grab all keys again */ - if(reload) - grab_all_keys(conn); + if (reload) + grab_all_keys(conn); fclose(handle); REQUIRED_OPTION(terminal); REQUIRED_OPTION(font); - while (!SLIST_EMPTY(&variables)) { struct Variable *v = SLIST_FIRST(&variables); SLIST_REMOVE_HEAD(&variables, variables); @@ -388,6 +499,21 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, free(v->value); free(v); } + + /* Set an empty name for every workspace which got no name */ + for (int i = 0; i < 10; i++) { + Workspace *ws = &(workspaces[i]); + if (ws->name != NULL) { + /* If the font was not specified when the workspace name + * was loaded, we need to predict the text width now */ + if (ws->text_width == 0) + ws->text_width = predict_text_width(global_conn, + config.font, ws->name, ws->name_len); + continue; + } + + workspace_set_name(&(workspaces[i]), NULL); + } return; }