00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <X11/Xlib.h>
00018
00019 #include "all.h"
00020
00021 char *current_configpath = NULL;
00022 Config config;
00023 struct modes_head modes;
00024
00030 void ungrab_all_keys(xcb_connection_t *conn) {
00031 DLOG("Ungrabbing all keys\n");
00032 xcb_ungrab_key(conn, XCB_GRAB_ANY, root, XCB_BUTTON_MASK_ANY);
00033 }
00034
00035 static void grab_keycode_for_binding(xcb_connection_t *conn, Binding *bind, uint32_t keycode) {
00036 DLOG("Grabbing %d\n", keycode);
00037
00038 #define GRAB_KEY(modifier) \
00039 do { \
00040 xcb_grab_key(conn, 0, root, modifier, keycode, \
00041 XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); \
00042 } while (0)
00043 int mods = bind->mods;
00044 if ((bind->mods & BIND_MODE_SWITCH) != 0) {
00045 mods &= ~BIND_MODE_SWITCH;
00046 if (mods == 0)
00047 mods = XCB_MOD_MASK_ANY;
00048 }
00049 GRAB_KEY(mods);
00050 GRAB_KEY(mods | xcb_numlock_mask);
00051 GRAB_KEY(mods | xcb_numlock_mask | XCB_MOD_MASK_LOCK);
00052 }
00053
00054
00055
00056
00057
00058
00059 Binding *get_binding(uint16_t modifiers, xcb_keycode_t keycode) {
00060 Binding *bind;
00061
00062 TAILQ_FOREACH(bind, bindings, bindings) {
00063
00064 if (bind->mods != modifiers)
00065 continue;
00066
00067
00068
00069 if (bind->symbol != NULL) {
00070 if (memmem(bind->translated_to,
00071 bind->number_keycodes * sizeof(xcb_keycode_t),
00072 &keycode, sizeof(xcb_keycode_t)) != NULL)
00073 break;
00074 } else {
00075
00076 if (bind->keycode == keycode)
00077 break;
00078 }
00079 }
00080
00081 return (bind == TAILQ_END(bindings) ? NULL : bind);
00082 }
00083
00084
00085
00086
00087
00088 void translate_keysyms() {
00089 Binding *bind;
00090 TAILQ_FOREACH(bind, bindings, bindings) {
00091 if (bind->keycode > 0)
00092 continue;
00093
00094
00095 xcb_keysym_t keysym = XStringToKeysym(bind->symbol);
00096 if (keysym == NoSymbol) {
00097 ELOG("Could not translate string to key symbol: \"%s\"\n", bind->symbol);
00098 continue;
00099 }
00100
00101 uint32_t last_keycode = 0;
00102 xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, keysym);
00103 if (keycodes == NULL) {
00104 DLOG("Could not translate symbol \"%s\"\n", bind->symbol);
00105 continue;
00106 }
00107
00108 bind->number_keycodes = 0;
00109
00110 for (xcb_keycode_t *walk = keycodes; *walk != 0; walk++) {
00111
00112
00113 if (last_keycode == *walk)
00114 continue;
00115 last_keycode = *walk;
00116 bind->number_keycodes++;
00117 }
00118 DLOG("Translated symbol \"%s\" to %d keycode\n", bind->symbol, bind->number_keycodes);
00119 bind->translated_to = smalloc(bind->number_keycodes * sizeof(xcb_keycode_t));
00120 memcpy(bind->translated_to, keycodes, bind->number_keycodes * sizeof(xcb_keycode_t));
00121 free(keycodes);
00122 }
00123 }
00124
00125
00126
00127
00128
00129 void grab_all_keys(xcb_connection_t *conn, bool bind_mode_switch) {
00130 Binding *bind;
00131 TAILQ_FOREACH(bind, bindings, bindings) {
00132 if ((bind_mode_switch && (bind->mods & BIND_MODE_SWITCH) == 0) ||
00133 (!bind_mode_switch && (bind->mods & BIND_MODE_SWITCH) != 0))
00134 continue;
00135
00136
00137 if (bind->keycode > 0) {
00138 grab_keycode_for_binding(conn, bind, bind->keycode);
00139 continue;
00140 }
00141
00142 xcb_keycode_t *walk = bind->translated_to;
00143 for (int i = 0; i < bind->number_keycodes; i++)
00144 grab_keycode_for_binding(conn, bind, *walk);
00145 }
00146 }
00147
00148
00149
00150
00151
00152 void switch_mode(const char *new_mode) {
00153 struct Mode *mode;
00154
00155 LOG("Switching to mode %s\n", new_mode);
00156
00157 SLIST_FOREACH(mode, &modes, modes) {
00158 if (strcasecmp(mode->name, new_mode) != 0)
00159 continue;
00160
00161 ungrab_all_keys(conn);
00162 bindings = mode->bindings;
00163 translate_keysyms();
00164 grab_all_keys(conn, false);
00165 return;
00166 }
00167
00168 ELOG("ERROR: Mode not found\n");
00169 }
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 static char *get_config_path(const char *override_configpath) {
00180 char *xdg_config_home, *xdg_config_dirs, *config_path;
00181
00182 static const char *saved_configpath = NULL;
00183
00184 if (override_configpath != NULL) {
00185 saved_configpath = override_configpath;
00186 return sstrdup(saved_configpath);
00187 }
00188
00189 if (saved_configpath != NULL)
00190 return sstrdup(saved_configpath);
00191
00192
00193 config_path = resolve_tilde("~/.i3/config");
00194 if (path_exists(config_path))
00195 return config_path;
00196
00197
00198 if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
00199 xdg_config_home = "~/.config";
00200
00201 xdg_config_home = resolve_tilde(xdg_config_home);
00202 if (asprintf(&config_path, "%s/i3/config", xdg_config_home) == -1)
00203 die("asprintf() failed");
00204 free(xdg_config_home);
00205
00206 if (path_exists(config_path))
00207 return config_path;
00208 free(config_path);
00209
00210
00211 config_path = SYSCONFDIR "/i3/config";
00212 if (path_exists(config_path))
00213 return sstrdup(config_path);
00214
00215
00216 if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL)
00217 xdg_config_dirs = "/etc/xdg";
00218
00219 char *buf = sstrdup(xdg_config_dirs);
00220 char *tok = strtok(buf, ":");
00221 while (tok != NULL) {
00222 tok = resolve_tilde(tok);
00223 if (asprintf(&config_path, "%s/i3/config", tok) == -1)
00224 die("asprintf() failed");
00225 free(tok);
00226 if (path_exists(config_path)) {
00227 free(buf);
00228 return config_path;
00229 }
00230 free(config_path);
00231 tok = strtok(NULL, ":");
00232 }
00233 free(buf);
00234
00235 die("Unable to find the configuration file (looked at "
00236 "~/.i3/config, $XDG_CONFIG_HOME/i3/config, "
00237 SYSCONFDIR "i3/config and $XDG_CONFIG_DIRS/i3/config)");
00238 }
00239
00240
00241
00242
00243
00244
00245
00246 static void parse_configuration(const char *override_configpath) {
00247 char *path = get_config_path(override_configpath);
00248 DLOG("Parsing configfile %s\n", path);
00249 FREE(current_configpath);
00250 current_configpath = path;
00251 parse_file(path);
00252 }
00253
00254
00255
00256
00257
00258 void load_configuration(xcb_connection_t *conn, const char *override_configpath, bool reload) {
00259 if (reload) {
00260
00261 ungrab_all_keys(conn);
00262
00263 struct Mode *mode;
00264 Binding *bind;
00265 while (!SLIST_EMPTY(&modes)) {
00266 mode = SLIST_FIRST(&modes);
00267 FREE(mode->name);
00268
00269
00270 bindings = mode->bindings;
00271 while (!TAILQ_EMPTY(bindings)) {
00272 bind = TAILQ_FIRST(bindings);
00273 TAILQ_REMOVE(bindings, bind, bindings);
00274 FREE(bind->translated_to);
00275 FREE(bind->command);
00276 FREE(bind);
00277 }
00278 FREE(bindings);
00279 SLIST_REMOVE(&modes, mode, Mode, modes);
00280 }
00281
00282 #if 0
00283 struct Assignment *assign;
00284 while (!TAILQ_EMPTY(&assignments)) {
00285 assign = TAILQ_FIRST(&assignments);
00286 FREE(assign->windowclass_title);
00287 TAILQ_REMOVE(&assignments, assign, assignments);
00288 FREE(assign);
00289 }
00290 #endif
00291
00292
00293 #if 0
00294 Workspace *ws;
00295 TAILQ_FOREACH(ws, workspaces, workspaces)
00296 workspace_set_name(ws, NULL);
00297 #endif
00298 }
00299
00300 SLIST_INIT(&modes);
00301
00302 struct Mode *default_mode = scalloc(sizeof(struct Mode));
00303 default_mode->name = sstrdup("default");
00304 default_mode->bindings = scalloc(sizeof(struct bindings_head));
00305 TAILQ_INIT(default_mode->bindings);
00306 SLIST_INSERT_HEAD(&modes, default_mode, modes);
00307
00308 bindings = default_mode->bindings;
00309
00310 #define REQUIRED_OPTION(name) \
00311 if (config.name == NULL) \
00312 die("You did not specify required configuration option " #name "\n");
00313
00314
00315 memset(&config, 0, sizeof(config));
00316
00317
00318 #define INIT_COLOR(x, cborder, cbackground, ctext) \
00319 do { \
00320 x.border = get_colorpixel(cborder); \
00321 x.background = get_colorpixel(cbackground); \
00322 x.text = get_colorpixel(ctext); \
00323 } while (0)
00324
00325 config.client.background = get_colorpixel("#000000");
00326 INIT_COLOR(config.client.focused, "#4c7899", "#285577", "#ffffff");
00327 INIT_COLOR(config.client.focused_inactive, "#333333", "#5f676a", "#ffffff");
00328 INIT_COLOR(config.client.unfocused, "#333333", "#222222", "#888888");
00329 INIT_COLOR(config.client.urgent, "#2f343a", "#900000", "#ffffff");
00330 INIT_COLOR(config.bar.focused, "#4c7899", "#285577", "#ffffff");
00331 INIT_COLOR(config.bar.unfocused, "#333333", "#222222", "#888888");
00332 INIT_COLOR(config.bar.urgent, "#2f343a", "#900000", "#ffffff");
00333
00334 config.default_border = BS_NORMAL;
00335
00336 config.default_orientation = NO_ORIENTATION;
00337
00338 parse_configuration(override_configpath);
00339
00340 if (reload) {
00341 translate_keysyms();
00342 grab_all_keys(conn, false);
00343 }
00344
00345 if (config.font.id == 0) {
00346 ELOG("You did not specify required configuration option \"font\"\n");
00347 config.font = load_font("fixed", true);
00348 }
00349
00350 #if 0
00351
00352 Workspace *ws;
00353 TAILQ_FOREACH(ws, workspaces, workspaces) {
00354 if (ws->name != NULL) {
00355
00356
00357 if (ws->text_width == 0)
00358 ws->text_width = predict_text_width(global_conn,
00359 config.font, ws->name, ws->name_len);
00360 continue;
00361 }
00362
00363 workspace_set_name(ws, NULL);
00364 }
00365 #endif
00366 }