diff --git a/config.c b/config.c index ae7f0be5..9a2af7c3 100644 --- a/config.c +++ b/config.c @@ -744,26 +744,40 @@ parse_section_main(const char *key, const char *value, struct config *conf, strcmp(key, "font-bold") == 0 ? 1 : strcmp(key, "font-italic") == 0 ? 2 : 3; - tll_foreach(conf->fonts[idx], it) - config_font_destroy(&it->item); - tll_free(conf->fonts[idx]); + config_font_list_destroy(&conf->fonts[idx]); + + size_t count = 0; + size_t size = 0; + struct config_font *fonts = NULL; char *copy = xstrdup(value); for (const char *font = strtok(copy, ","); font != NULL; font = strtok(NULL, ",")) { /* Trim spaces, strictly speaking not necessary, but looks nice :) */ while (*font != '\0' && isspace(*font)) font++; - if (*font != '\0') { - struct config_font font_data; - if (!config_font_parse(font, &font_data)) { - LOG_ERR("%s:%d: [default]: %s: invalid font specification", - path, lineno, key); - free(copy); - return false; - } - tll_push_back(conf->fonts[idx], font_data); + + if (font[0] == '\0') + continue; + + struct config_font font_data; + if (!config_font_parse(font, &font_data)) { + LOG_ERR("%s:%d: [default]: %s: invalid font specification", + path, lineno, key); + free(copy); + return false; } + + if (count + 1 > size) { + size += 4; + fonts = xrealloc(fonts, size * sizeof(fonts[0])); + } + + xassert(count + 1 <= size); + fonts[count++] = font_data; } + + conf->fonts[idx].count = count; + conf->fonts[idx].arr = fonts; free(copy); } @@ -1356,14 +1370,20 @@ struct key_combo { } m; }; }; -typedef tll(struct key_combo) key_combo_list_t; -static void -free_key_combo_list(key_combo_list_t *key_combos) +struct key_combo_list { + size_t count; + struct key_combo *combos; +}; + +static void NOINLINE +free_key_combo_list(struct key_combo_list *key_combos) { - tll_foreach(*key_combos, it) - free(it->item.text); - tll_free(*key_combos); + for (size_t i = 0; i < key_combos->count; i++) + free(key_combos->combos[i].text); + free(key_combos->combos); + key_combos->count = 0; + key_combos->combos = NULL; } static bool @@ -1402,11 +1422,15 @@ out: } static bool -parse_key_combos(struct config *conf, const char *combos, key_combo_list_t *key_combos, +parse_key_combos(struct config *conf, const char *combos, + struct key_combo_list *key_combos, const char *section, const char *option, const char *path, unsigned lineno) { - xassert(tll_length(*key_combos) == 0); + xassert(key_combos != NULL); + xassert(key_combos->count == 0 && key_combos->combos == NULL); + + size_t size = 0; /* Size of ‘combos’ array in the key-combo list */ char *copy = xstrdup(combos); @@ -1450,18 +1474,25 @@ parse_key_combos(struct config *conf, const char *combos, key_combo_list_t *key_ goto err; } - tll_push_back( - *key_combos, - ((struct key_combo){.text = xstrdup(combo), .modifiers = modifiers, .sym = sym})); + if (key_combos->count + 1 > size) { + size += 4; + key_combos->combos = xrealloc( + key_combos->combos, size * sizeof(key_combos->combos[0])); + } + + xassert(key_combos->count + 1 <= size); + key_combos->combos[key_combos->count++] = (struct key_combo){ + .text = xstrdup(combo), + .modifiers = modifiers, + .sym = sym, + }; } free(copy); return true; err: - tll_foreach(*key_combos, it) - free(it->item.text); - tll_free(*key_combos); + free_key_combo_list(key_combos); free(copy); return false; } @@ -1469,31 +1500,38 @@ err: static bool has_key_binding_collisions(struct config *conf, int action, const char *const action_map[], - config_key_binding_list_t *bindings, - const key_combo_list_t *key_combos, + const struct config_key_binding_list *bindings, + const struct key_combo_list *key_combos, const char *path, unsigned lineno) { - tll_foreach(*bindings, it) { - if (it->item.action == action) + for (size_t j = 0; j < bindings->count; j++) { + const struct config_key_binding *combo1 = &bindings->arr[j]; + + if (combo1->action == BIND_ACTION_NONE) continue; - tll_foreach(*key_combos, it2) { - const struct config_key_modifiers *mods1 = &it->item.modifiers; - const struct config_key_modifiers *mods2 = &it2->item.modifiers; + if (combo1->action == action) + continue; + + for (size_t i = 0; i < key_combos->count; i++) { + const struct key_combo *combo2 = &key_combos->combos[i]; + + const struct config_key_modifiers *mods1 = &combo1->modifiers; + const struct config_key_modifiers *mods2 = &combo2->modifiers; bool shift = mods1->shift == mods2->shift; bool alt = mods1->alt == mods2->alt; bool ctrl = mods1->ctrl == mods2->ctrl; bool meta = mods1->meta == mods2->meta; - bool sym = it->item.sym == it2->item.sym; + bool sym = combo1->sym == combo2->sym; if (shift && alt && ctrl && meta && sym) { - bool has_pipe = it->item.pipe.cmd != NULL; + bool has_pipe = combo1->pipe.cmd != NULL; LOG_AND_NOTIFY_ERR("%s:%d: %s already mapped to '%s%s%s%s'", - path, lineno, it2->item.text, - action_map[it->item.action], + path, lineno, combo2->text, + action_map[combo1->action], has_pipe ? " [" : "", - has_pipe ? it->item.pipe.cmd : "", + has_pipe ? combo1->pipe.cmd : "", has_pipe ? "]" : ""); return true; } @@ -1587,7 +1625,7 @@ static bool NOINLINE parse_key_binding_section( const char *section, const char *key, const char *value, int action_count, const char *const action_map[static action_count], - config_key_binding_list_t *bindings, + struct config_key_binding_list *bindings, struct config *conf, const char *path, unsigned lineno) { char *pipe_cmd; @@ -1610,21 +1648,27 @@ parse_key_binding_section( /* Unset binding */ if (strcasecmp(value, "none") == 0) { - tll_foreach(*bindings, it) { - if (it->item.action == action) { - if (it->item.pipe.master_copy) { - free(it->item.pipe.cmd); - free(it->item.pipe.argv); - } - tll_remove(*bindings, it); + for (size_t i = 0; i < bindings->count; i++) { + struct config_key_binding *binding = &bindings->arr[i]; + + if (binding->action != action) + continue; + + if (binding->pipe.master_copy) { + free(binding->pipe.cmd); + free(binding->pipe.argv); } + binding->action = BIND_ACTION_NONE; + binding->pipe.cmd = NULL; + binding->pipe.argv = NULL; } + free(pipe_argv); free(pipe_cmd); return true; } - key_combo_list_t key_combos = tll_init(); + struct key_combo_list key_combos = {0}; if (!parse_key_combos( conf, value, &key_combos, section, key, path, lineno) || has_key_binding_collisions( @@ -1638,28 +1682,38 @@ parse_key_binding_section( } /* Remove existing bindings for this action+pipe */ - tll_foreach(*bindings, it) { - if (it->item.action == action && - ((it->item.pipe.argv == NULL && pipe_argv == NULL) || - (it->item.pipe.argv != NULL && pipe_argv != NULL && - argv_compare(it->item.pipe.argv, pipe_argv) == 0))) + for (size_t i = 0; i < bindings->count; i++) { + struct config_key_binding *binding = &bindings->arr[i]; + + if (binding->action == action && + ((binding->pipe.argv == NULL && pipe_argv == NULL) || + (binding->pipe.argv != NULL && pipe_argv != NULL && + argv_compare(binding->pipe.argv, pipe_argv) == 0))) { - if (it->item.pipe.master_copy) { - free(it->item.pipe.cmd); - free(it->item.pipe.argv); + if (binding->pipe.master_copy) { + free(binding->pipe.cmd); + free(binding->pipe.argv); } - tll_remove(*bindings, it); + binding->action = BIND_ACTION_NONE; + binding->pipe.cmd = NULL; + binding->pipe.argv = NULL; } } /* Emit key bindings */ + size_t ofs = bindings->count; + bindings->count += key_combos.count; + bindings->arr = xrealloc( + bindings->arr, bindings->count * sizeof(bindings->arr[0])); + bool first = true; - tll_foreach(key_combos, it) { + for (size_t i = 0; i < key_combos.count; i++) { + const struct key_combo *combo = &key_combos.combos[i]; struct config_key_binding binding = { .action = action, - .modifiers = it->item.modifiers, - .sym = it->item.sym, + .modifiers = combo->modifiers, + .sym = combo->sym, .pipe = { .cmd = pipe_cmd, .argv = pipe_argv, @@ -1667,7 +1721,8 @@ parse_key_binding_section( }, }; - tll_push_back(*bindings, binding); + /* TODO: we could re-use free:d slots */ + bindings->arr[ofs + i] = binding; first = false; } @@ -1747,10 +1802,14 @@ parse_section_url_bindings( } static bool -parse_mouse_combos(struct config *conf, const char *combos, key_combo_list_t *key_combos, +parse_mouse_combos(struct config *conf, const char *combos, + struct key_combo_list *key_combos, const char *path, unsigned lineno) { - xassert(tll_length(*key_combos) == 0); + xassert(key_combos != NULL); + xassert(key_combos->count == 0 && key_combos->combos == NULL); + + size_t size = 0; /* Size of the ‘combos’ array in key_combos */ char *copy = xstrdup(combos); @@ -1835,44 +1894,55 @@ parse_mouse_combos(struct config *conf, const char *combos, key_combo_list_t *ke .count = count, }, }; - tll_push_back(*key_combos, new); + + if (key_combos->count + 1 > size) { + size += 4; + key_combos->combos = xrealloc( + key_combos->combos, size * sizeof(key_combos->combos[0])); + } + + xassert(key_combos->count + 1 <= size); + key_combos->combos[key_combos->count++] = new; } free(copy); return true; err: - tll_foreach(*key_combos, it) { - free(it->item.text); - tll_remove(*key_combos, it); - } + free_key_combo_list(key_combos); free(copy); return false; } static bool -has_mouse_binding_collisions(struct config *conf, const key_combo_list_t *key_combos, +has_mouse_binding_collisions(struct config *conf, const struct key_combo_list *key_combos, const char *path, unsigned lineno) { - tll_foreach(conf->bindings.mouse, it) { - tll_foreach(*key_combos, it2) { - const struct config_key_modifiers *mods1 = &it->item.modifiers; - const struct config_key_modifiers *mods2 = &it2->item.modifiers; + for (size_t j = 0; j < conf->bindings.mouse.count; j++) { + const struct config_mouse_binding *combo1 = &conf->bindings.mouse.arr[j]; + if (combo1->action == BIND_ACTION_NONE) + continue; + + for (size_t i = 0; i < key_combos->count; i++) { + const struct key_combo *combo2 = &key_combos->combos[i]; + + const struct config_key_modifiers *mods1 = &combo1->modifiers; + const struct config_key_modifiers *mods2 = &combo2->modifiers; bool shift = mods1->shift == mods2->shift; bool alt = mods1->alt == mods2->alt; bool ctrl = mods1->ctrl == mods2->ctrl; bool meta = mods1->meta == mods2->meta; - bool button = it->item.button == it2->item.m.button; - bool count = it->item.count == it2->item.m.count; + bool button = combo1->button == combo2->m.button; + bool count = combo1->count == combo2->m.count; if (shift && alt && ctrl && meta && button && count) { - bool has_pipe = it->item.pipe.cmd != NULL; + bool has_pipe = combo1->pipe.cmd != NULL; LOG_AND_NOTIFY_ERR("%s:%d: %s already mapped to '%s%s%s%s'", - path, lineno, it2->item.text, - binding_action_map[it->item.action], + path, lineno, combo2->text, + binding_action_map[combo1->action], has_pipe ? " [" : "", - has_pipe ? it->item.pipe.cmd : "", + has_pipe ? combo1->pipe.cmd : "", has_pipe ? "]" : ""); return true; } @@ -1911,13 +1981,18 @@ parse_section_mouse_bindings( /* Unset binding */ if (strcasecmp(value, "none") == 0) { - tll_foreach(conf->bindings.mouse, it) { - if (it->item.action == action) { - if (it->item.pipe.master_copy) { - free(it->item.pipe.cmd); - free(it->item.pipe.argv); + for (size_t i = 0; i < conf->bindings.mouse.count; i++) { + struct config_mouse_binding *binding = + &conf->bindings.mouse.arr[i]; + + if (binding->action == action) { + if (binding->pipe.master_copy) { + free(binding->pipe.cmd); + free(binding->pipe.argv); } - tll_remove(conf->bindings.mouse, it); + binding->action = BIND_ACTION_NONE; + binding->pipe.cmd = NULL; + binding->pipe.argv = NULL; } } free(pipe_argv); @@ -1925,7 +2000,7 @@ parse_section_mouse_bindings( return true; } - key_combo_list_t key_combos = tll_init(); + struct key_combo_list key_combos = {0}; if (!parse_mouse_combos(conf, value, &key_combos, path, lineno) || has_mouse_binding_collisions(conf, &key_combos, path, lineno)) { @@ -1936,35 +2011,47 @@ parse_section_mouse_bindings( } /* Remove existing bindings for this action */ - tll_foreach(conf->bindings.mouse, it) { - if (it->item.action == action && - ((it->item.pipe.argv == NULL && pipe_argv == NULL) || - (it->item.pipe.argv != NULL && pipe_argv != NULL && - argv_compare(it->item.pipe.argv, pipe_argv) == 0))) + for (size_t i = 0; i < conf->bindings.mouse.count; i++) { + struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i]; + + if (binding->action == action && + ((binding->pipe.argv == NULL && pipe_argv == NULL) || + (binding->pipe.argv != NULL && pipe_argv != NULL && + argv_compare(binding->pipe.argv, pipe_argv) == 0))) { - if (it->item.pipe.master_copy) { - free(it->item.pipe.cmd); - free(it->item.pipe.argv); + if (binding->pipe.master_copy) { + free(binding->pipe.cmd); + free(binding->pipe.argv); } - tll_remove(conf->bindings.mouse, it); + binding->action = BIND_ACTION_NONE; + binding->pipe.cmd = NULL; + binding->pipe.argv = NULL; } } /* Emit mouse bindings */ + size_t ofs = conf->bindings.mouse.count; + conf->bindings.mouse.count += key_combos.count; + conf->bindings.mouse.arr = xrealloc( + conf->bindings.mouse.arr, + conf->bindings.mouse.count * sizeof(conf->bindings.mouse.arr[0])); + bool first = true; - tll_foreach(key_combos, it) { + for (size_t i = 0; i < key_combos.count; i++) { + const struct key_combo *combo = &key_combos.combos[i]; struct config_mouse_binding binding = { .action = action, - .modifiers = it->item.modifiers, - .button = it->item.m.button, - .count = it->item.m.count, + .modifiers = combo->modifiers, + .button = combo->m.button, + .count = combo->m.count, .pipe = { .cmd = pipe_cmd, .argv = pipe_argv, .master_copy = first, }, }; - tll_push_back(conf->bindings.mouse, binding); + + conf->bindings.mouse.arr[ofs + i] = binding; first = false; } @@ -2362,137 +2449,112 @@ get_server_socket_path(void) return xasprintf("%s/foot-%s.sock", xdg_runtime, wayland_display); } -static void NOINLINE -add_key_binding(config_key_binding_list_t *list, int action, - const struct config_key_modifiers *mods, xkb_keysym_t sym) -{ - tll_push_back( - *list, - ((struct config_key_binding){action, *mods, sym})); -} +#define m_none {0} +#define m_alt {.alt = true} +#define m_ctrl {.ctrl = true} +#define m_shift {.shift = true} +#define m_ctrl_shift {.ctrl = true, .shift = true} static void add_default_key_bindings(struct config *conf) { - #define add_binding(action, mods, sym) \ - add_key_binding(&conf->bindings.key, action, &mods, sym) + static const struct config_key_binding bindings[] = { + {BIND_ACTION_SCROLLBACK_UP_PAGE, m_shift, XKB_KEY_Page_Up}, + {BIND_ACTION_SCROLLBACK_DOWN_PAGE, m_shift, XKB_KEY_Page_Down}, + {BIND_ACTION_CLIPBOARD_COPY, m_ctrl_shift, XKB_KEY_c}, + {BIND_ACTION_CLIPBOARD_PASTE, m_ctrl_shift, XKB_KEY_v}, + {BIND_ACTION_PRIMARY_PASTE, m_shift, XKB_KEY_Insert}, + {BIND_ACTION_SEARCH_START, m_ctrl_shift, XKB_KEY_r}, + {BIND_ACTION_FONT_SIZE_UP, m_ctrl, XKB_KEY_plus}, + {BIND_ACTION_FONT_SIZE_UP, m_ctrl, XKB_KEY_equal}, + {BIND_ACTION_FONT_SIZE_UP, m_ctrl, XKB_KEY_KP_Add}, + {BIND_ACTION_FONT_SIZE_DOWN, m_ctrl, XKB_KEY_minus}, + {BIND_ACTION_FONT_SIZE_DOWN, m_ctrl, XKB_KEY_KP_Subtract}, + {BIND_ACTION_FONT_SIZE_RESET, m_ctrl, XKB_KEY_0}, + {BIND_ACTION_FONT_SIZE_RESET, m_ctrl, XKB_KEY_KP_0}, + {BIND_ACTION_SPAWN_TERMINAL, m_ctrl_shift, XKB_KEY_n}, + {BIND_ACTION_SHOW_URLS_LAUNCH, m_ctrl_shift, XKB_KEY_u}, + }; - const struct config_key_modifiers shift = {.shift = true}; - const struct config_key_modifiers ctrl = {.ctrl = true}; - const struct config_key_modifiers ctrl_shift = {.ctrl = true, .shift = true}; - - add_binding(BIND_ACTION_SCROLLBACK_UP_PAGE, shift, XKB_KEY_Page_Up); - add_binding(BIND_ACTION_SCROLLBACK_DOWN_PAGE, shift, XKB_KEY_Page_Down); - add_binding(BIND_ACTION_CLIPBOARD_COPY, ctrl_shift, XKB_KEY_c); - add_binding(BIND_ACTION_CLIPBOARD_PASTE, ctrl_shift, XKB_KEY_v); - add_binding(BIND_ACTION_PRIMARY_PASTE, shift, XKB_KEY_Insert); - add_binding(BIND_ACTION_SEARCH_START, ctrl_shift, XKB_KEY_r); - add_binding(BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_plus); - add_binding(BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_equal); - add_binding(BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_KP_Add); - add_binding(BIND_ACTION_FONT_SIZE_DOWN, ctrl, XKB_KEY_minus); - add_binding(BIND_ACTION_FONT_SIZE_DOWN, ctrl, XKB_KEY_KP_Subtract); - add_binding(BIND_ACTION_FONT_SIZE_RESET, ctrl, XKB_KEY_0); - add_binding(BIND_ACTION_FONT_SIZE_RESET, ctrl, XKB_KEY_KP_0); - add_binding(BIND_ACTION_SPAWN_TERMINAL, ctrl_shift, XKB_KEY_n); - add_binding(BIND_ACTION_SHOW_URLS_LAUNCH, ctrl_shift, XKB_KEY_u); - - #undef add_binding + conf->bindings.key.count = ALEN(bindings); + conf->bindings.key.arr = xmalloc(sizeof(bindings)); + memcpy(conf->bindings.key.arr, bindings, sizeof(bindings)); } static void add_default_search_bindings(struct config *conf) { - #define add_binding(action, mods, sym) \ - add_key_binding(&conf->bindings.search, action, &mods, sym) + static const struct config_key_binding bindings[] = { + {BIND_ACTION_SEARCH_CANCEL, m_ctrl, XKB_KEY_c}, + {BIND_ACTION_SEARCH_CANCEL, m_ctrl, XKB_KEY_g}, + {BIND_ACTION_SEARCH_CANCEL, m_none, XKB_KEY_Escape}, + {BIND_ACTION_SEARCH_COMMIT, m_none, XKB_KEY_Return}, + {BIND_ACTION_SEARCH_FIND_PREV, m_ctrl, XKB_KEY_r}, + {BIND_ACTION_SEARCH_FIND_NEXT, m_ctrl, XKB_KEY_s}, + {BIND_ACTION_SEARCH_EDIT_LEFT, m_none, XKB_KEY_Left}, + {BIND_ACTION_SEARCH_EDIT_LEFT, m_ctrl, XKB_KEY_b}, + {BIND_ACTION_SEARCH_EDIT_LEFT_WORD, m_ctrl, XKB_KEY_Left}, + {BIND_ACTION_SEARCH_EDIT_LEFT_WORD, m_alt, XKB_KEY_b}, + {BIND_ACTION_SEARCH_EDIT_RIGHT, m_none, XKB_KEY_Right}, + {BIND_ACTION_SEARCH_EDIT_RIGHT, m_ctrl, XKB_KEY_f}, + {BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, m_ctrl, XKB_KEY_Right}, + {BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, m_alt, XKB_KEY_f}, + {BIND_ACTION_SEARCH_EDIT_HOME, m_none, XKB_KEY_Home}, + {BIND_ACTION_SEARCH_EDIT_HOME, m_ctrl, XKB_KEY_a}, + {BIND_ACTION_SEARCH_EDIT_END, m_none, XKB_KEY_End}, + {BIND_ACTION_SEARCH_EDIT_END, m_ctrl, XKB_KEY_e}, + {BIND_ACTION_SEARCH_DELETE_PREV, m_none, XKB_KEY_BackSpace}, + {BIND_ACTION_SEARCH_DELETE_PREV_WORD, m_ctrl, XKB_KEY_BackSpace}, + {BIND_ACTION_SEARCH_DELETE_PREV_WORD, m_alt, XKB_KEY_BackSpace}, + {BIND_ACTION_SEARCH_DELETE_NEXT, m_none, XKB_KEY_Delete}, + {BIND_ACTION_SEARCH_DELETE_NEXT_WORD, m_ctrl, XKB_KEY_Delete}, + {BIND_ACTION_SEARCH_DELETE_NEXT_WORD, m_alt, XKB_KEY_d}, + {BIND_ACTION_SEARCH_EXTEND_WORD, m_ctrl, XKB_KEY_w}, + {BIND_ACTION_SEARCH_EXTEND_WORD_WS, m_ctrl_shift, XKB_KEY_w}, + {BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, XKB_KEY_v}, + {BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, XKB_KEY_y}, + {BIND_ACTION_SEARCH_PRIMARY_PASTE, m_shift, XKB_KEY_Insert}, + }; - const struct config_key_modifiers none = {0}; - const struct config_key_modifiers alt = {.alt = true}; - const struct config_key_modifiers ctrl = {.ctrl = true}; - const struct config_key_modifiers shift = {.shift = true}; - const struct config_key_modifiers ctrl_shift = {.ctrl = true, .shift = true}; - - add_binding(BIND_ACTION_SEARCH_CANCEL, ctrl, XKB_KEY_c); - add_binding(BIND_ACTION_SEARCH_CANCEL, ctrl, XKB_KEY_g); - add_binding(BIND_ACTION_SEARCH_CANCEL, none, XKB_KEY_Escape); - add_binding(BIND_ACTION_SEARCH_COMMIT, none, XKB_KEY_Return); - add_binding(BIND_ACTION_SEARCH_FIND_PREV, ctrl, XKB_KEY_r); - add_binding(BIND_ACTION_SEARCH_FIND_NEXT, ctrl, XKB_KEY_s); - add_binding(BIND_ACTION_SEARCH_EDIT_LEFT, none, XKB_KEY_Left); - add_binding(BIND_ACTION_SEARCH_EDIT_LEFT, ctrl, XKB_KEY_b); - add_binding(BIND_ACTION_SEARCH_EDIT_LEFT_WORD, ctrl, XKB_KEY_Left); - add_binding(BIND_ACTION_SEARCH_EDIT_LEFT_WORD, alt, XKB_KEY_b); - add_binding(BIND_ACTION_SEARCH_EDIT_RIGHT, none, XKB_KEY_Right); - add_binding(BIND_ACTION_SEARCH_EDIT_RIGHT, ctrl, XKB_KEY_f); - add_binding(BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, ctrl, XKB_KEY_Right); - add_binding(BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, alt, XKB_KEY_f); - add_binding(BIND_ACTION_SEARCH_EDIT_HOME, none, XKB_KEY_Home); - add_binding(BIND_ACTION_SEARCH_EDIT_HOME, ctrl, XKB_KEY_a); - add_binding(BIND_ACTION_SEARCH_EDIT_END, none, XKB_KEY_End); - add_binding(BIND_ACTION_SEARCH_EDIT_END, ctrl, XKB_KEY_e); - add_binding(BIND_ACTION_SEARCH_DELETE_PREV, none, XKB_KEY_BackSpace); - add_binding(BIND_ACTION_SEARCH_DELETE_PREV_WORD, ctrl, XKB_KEY_BackSpace); - add_binding(BIND_ACTION_SEARCH_DELETE_PREV_WORD, alt, XKB_KEY_BackSpace); - add_binding(BIND_ACTION_SEARCH_DELETE_NEXT, none, XKB_KEY_Delete); - add_binding(BIND_ACTION_SEARCH_DELETE_NEXT_WORD, ctrl, XKB_KEY_Delete); - add_binding(BIND_ACTION_SEARCH_DELETE_NEXT_WORD, alt, XKB_KEY_d); - add_binding(BIND_ACTION_SEARCH_EXTEND_WORD, ctrl, XKB_KEY_w); - add_binding(BIND_ACTION_SEARCH_EXTEND_WORD_WS, ctrl_shift, XKB_KEY_w); - add_binding(BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_v); - add_binding(BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_y); - add_binding(BIND_ACTION_SEARCH_PRIMARY_PASTE, shift, XKB_KEY_Insert); - - #undef add_binding + conf->bindings.search.count = ALEN(bindings); + conf->bindings.search.arr = xmalloc(sizeof(bindings)); + memcpy(conf->bindings.search.arr, bindings, sizeof(bindings)); } static void add_default_url_bindings(struct config *conf) { - #define add_binding(action, mods, sym) \ - add_key_binding(&conf->bindings.url, action, &mods, sym) + static const struct config_key_binding bindings[] = { + {BIND_ACTION_URL_CANCEL, m_ctrl, XKB_KEY_c}, + {BIND_ACTION_URL_CANCEL, m_ctrl, XKB_KEY_g}, + {BIND_ACTION_URL_CANCEL, m_ctrl, XKB_KEY_d}, + {BIND_ACTION_URL_CANCEL, m_none, XKB_KEY_Escape}, + {BIND_ACTION_URL_TOGGLE_URL_ON_JUMP_LABEL, m_none, XKB_KEY_t}, + }; - const struct config_key_modifiers none = {0}; - const struct config_key_modifiers ctrl = {.ctrl = true}; - - add_binding(BIND_ACTION_URL_CANCEL, ctrl, XKB_KEY_c); - add_binding(BIND_ACTION_URL_CANCEL, ctrl, XKB_KEY_g); - add_binding(BIND_ACTION_URL_CANCEL, ctrl, XKB_KEY_d); - add_binding(BIND_ACTION_URL_CANCEL, none, XKB_KEY_Escape); - add_binding(BIND_ACTION_URL_TOGGLE_URL_ON_JUMP_LABEL, none, XKB_KEY_t); - - #undef add_binding -} - -static void NOINLINE -add_mouse_binding(config_mouse_binding_list_t *list, int action, - const struct config_key_modifiers *mods, - int button, int count) -{ - tll_push_back( - *list, - ((struct config_mouse_binding){action, *mods, button, count, {0}})); + conf->bindings.url.count = ALEN(bindings); + conf->bindings.url.arr = xmalloc(sizeof(bindings)); + memcpy(conf->bindings.url.arr, bindings, sizeof(bindings)); } static void add_default_mouse_bindings(struct config *conf) { - #define add_binding(action, mods, btn, count) \ - add_mouse_binding(&conf->bindings.mouse, action, &mods, btn, count) + static const struct config_mouse_binding bindings[] = { + {BIND_ACTION_PRIMARY_PASTE, m_none, BTN_MIDDLE, 1}, + {BIND_ACTION_SELECT_BEGIN, m_none, BTN_LEFT, 1}, + {BIND_ACTION_SELECT_BEGIN_BLOCK, m_ctrl, BTN_LEFT, 1}, + {BIND_ACTION_SELECT_EXTEND, m_none, BTN_RIGHT, 1}, + {BIND_ACTION_SELECT_EXTEND_CHAR_WISE, m_ctrl, BTN_RIGHT, 1}, + {BIND_ACTION_SELECT_WORD, m_none, BTN_LEFT, 2}, + {BIND_ACTION_SELECT_WORD_WS, m_ctrl, BTN_LEFT, 2}, + {BIND_ACTION_SELECT_ROW, m_none, BTN_LEFT, 3}, + }; - const struct config_key_modifiers none = {0}; - const struct config_key_modifiers ctrl = {.ctrl = true}; - - add_binding(BIND_ACTION_PRIMARY_PASTE, none, BTN_MIDDLE, 1); - add_binding(BIND_ACTION_SELECT_BEGIN, none, BTN_LEFT, 1); - add_binding(BIND_ACTION_SELECT_BEGIN_BLOCK, ctrl, BTN_LEFT, 1); - add_binding(BIND_ACTION_SELECT_EXTEND, none, BTN_RIGHT, 1); - add_binding(BIND_ACTION_SELECT_EXTEND_CHAR_WISE, ctrl, BTN_RIGHT, 1); - add_binding(BIND_ACTION_SELECT_WORD, none, BTN_LEFT, 2); - add_binding(BIND_ACTION_SELECT_WORD_WS, ctrl, BTN_LEFT, 2); - add_binding(BIND_ACTION_SELECT_ROW, none, BTN_LEFT, 3); - - #undef add_binding + conf->bindings.mouse.count = ALEN(bindings); + conf->bindings.mouse.arr = xmalloc(sizeof(bindings)); + memcpy(conf->bindings.mouse.arr, bindings, sizeof(bindings)); } bool @@ -2521,7 +2583,7 @@ config_load(struct config *conf, const char *conf_path, .palette_based = false, }, .startup_mode = STARTUP_WINDOWED, - .fonts = {tll_init(), tll_init(), tll_init(), tll_init()}, + .fonts = {{0}}, .line_height = {.pt = 0, .px = -1}, .letter_spacing = {.pt = 0, .px = 0}, .horizontal_letter_offset = {.pt = 0, .px = 0}, @@ -2734,13 +2796,16 @@ config_load(struct config *conf, const char *conf_path, conf->colors.selection_bg >> 24 == 0; out: - if (ret && tll_length(conf->fonts[0]) == 0) { + if (ret && conf->fonts[0].count == 0) { struct config_font font; if (!config_font_parse("monospace", &font)) { LOG_ERR("failed to load font 'monospace' - no fonts installed?"); ret = false; - } else - tll_push_back(conf->fonts[0], font); + } else { + conf->fonts[0].count = 1; + conf->fonts[0].arr = malloc(sizeof(font)); + conf->fonts[0].arr[0] = font; + } } free(conf_file.path); @@ -2783,14 +2848,14 @@ config_override_apply(struct config *conf, config_override_t *overrides, bool er return true; } -static void +static void NOINLINE free_spawn_template(struct config_spawn_template *template) { free(template->raw_cmd); free(template->argv); } -static void +static void NOINLINE binding_pipe_free(struct config_binding_pipe *pipe) { if (pipe->master_copy) { @@ -2806,12 +2871,11 @@ key_binding_free(struct config_key_binding *binding) } static void -key_binding_list_free(config_key_binding_list_t *bindings) +key_binding_list_free(struct config_key_binding_list *bindings) { - tll_foreach(*bindings, it) { - key_binding_free(&it->item); - tll_remove(*bindings, it); - } + for (size_t i = 0; i < bindings->count; i++) + key_binding_free(&bindings->arr[i]); + free(bindings->arr); } void @@ -2825,12 +2889,8 @@ config_free(struct config conf) free_spawn_template(&conf.bell.command); free(conf.scrollback.indicator.text); free_spawn_template(&conf.notify); - for (size_t i = 0; i < ALEN(conf.fonts); i++) { - tll_foreach(conf.fonts[i], it) { - config_font_destroy(&it->item); - tll_remove(conf.fonts[i], it); - } - } + for (size_t i = 0; i < ALEN(conf.fonts); i++) + config_font_list_destroy(&conf.fonts[i]); free(conf.server_socket_path); free(conf.url.label_letters); @@ -2843,10 +2903,9 @@ config_free(struct config conf) key_binding_list_free(&conf.bindings.search); key_binding_list_free(&conf.bindings.url); - tll_foreach(conf.bindings.mouse, it) { - binding_pipe_free(&it->item.pipe); - tll_remove(conf.bindings.mouse, it); - } + for (size_t i = 0; i < conf.bindings.mouse.count; i++) + binding_pipe_free(&conf.bindings.mouse.arr[i].pipe); + free(conf.bindings.mouse.arr); user_notifications_free(&conf.notifications); } @@ -2881,9 +2940,11 @@ config_font_parse(const char *pattern, struct config_font *font) } void -config_font_destroy(struct config_font *font) +config_font_list_destroy(struct config_font_list *font_list) { - if (font == NULL) - return; - free(font->pattern); + for (size_t i = 0; i < font_list->count; i++) + free(font_list->arr[i].pattern); + free(font_list->arr); + font_list->count = 0; + font_list->arr = NULL; } diff --git a/config.h b/config.h index 0e060d19..4de024ba 100644 --- a/config.h +++ b/config.h @@ -15,6 +15,12 @@ #define DEFAULT_TERM "xterm-256color" #endif +#define DEFINE_LIST(type) \ + type##_list { \ + size_t count; \ + type *arr; \ + } + enum conf_size_type {CONF_SIZE_PX, CONF_SIZE_CELLS}; struct config_font { @@ -22,7 +28,7 @@ struct config_font { double pt_size; int px_size; }; -typedef tll(struct config_font) config_font_list_t; +DEFINE_LIST(struct config_font); struct config_key_modifiers { bool shift; @@ -43,7 +49,7 @@ struct config_key_binding { xkb_keysym_t sym; struct config_binding_pipe pipe; }; -typedef tll(struct config_key_binding) config_key_binding_list_t; +DEFINE_LIST(struct config_key_binding); struct config_mouse_binding { enum bind_action_normal action; @@ -52,7 +58,7 @@ struct config_mouse_binding { int count; struct config_binding_pipe pipe; }; -typedef tll(struct config_mouse_binding) config_mouse_binding_list_t; +DEFINE_LIST(struct config_mouse_binding); typedef tll(char *) config_override_t; @@ -89,7 +95,7 @@ struct config { enum { STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN } startup_mode; enum {DPI_AWARE_AUTO, DPI_AWARE_YES, DPI_AWARE_NO} dpi_aware; - config_font_list_t fonts[4]; + struct config_font_list fonts[4]; /* Custom font metrics (-1 = use real font metrics) */ struct pt_or_px line_height; @@ -184,8 +190,8 @@ struct config { struct { /* Bindings for "normal" mode */ - config_key_binding_list_t key; - config_mouse_binding_list_t mouse; + struct config_key_binding_list key; + struct config_mouse_binding_list mouse; /* * Special modes @@ -193,10 +199,10 @@ struct config { /* While searching (not - action to *start* a search is in the * 'key' bindings above */ - config_key_binding_list_t search; + struct config_key_binding_list search; /* While showing URL jump labels */ - config_key_binding_list_t url; + struct config_key_binding_list url; } bindings; struct { @@ -257,4 +263,4 @@ bool config_load( void config_free(struct config conf); bool config_font_parse(const char *pattern, struct config_font *font); -void config_font_destroy(struct config_font *font); +void config_font_list_destroy(struct config_font_list *font_list); diff --git a/input.c b/input.c index 707c23f1..50478da3 100644 --- a/input.c +++ b/input.c @@ -527,22 +527,36 @@ convert_key_binding(const struct seat *seat, static void convert_key_bindings(const struct config *conf, struct seat *seat) { - tll_foreach(conf->bindings.key, it) - convert_key_binding(seat, &it->item, &seat->kbd.bindings.key); + for (size_t i = 0; i < conf->bindings.key.count; i++) { + const struct config_key_binding *binding = &conf->bindings.key.arr[i]; + if (binding->action == BIND_ACTION_NONE) + continue; + convert_key_binding(seat, binding, &seat->kbd.bindings.key); + } } static void convert_search_bindings(const struct config *conf, struct seat *seat) { - tll_foreach(conf->bindings.search, it) - convert_key_binding(seat, &it->item, &seat->kbd.bindings.search); + for (size_t i = 0; i < conf->bindings.search.count; i++) { + const struct config_key_binding *binding = &conf->bindings.search.arr[i]; + if (binding->action == BIND_ACTION_SEARCH_NONE) + continue; + convert_key_binding(seat, binding, &seat->kbd.bindings.search); + } } static void convert_url_bindings(const struct config *conf, struct seat *seat) { - tll_foreach(conf->bindings.url, it) - convert_key_binding(seat, &it->item, &seat->kbd.bindings.url); + for (size_t i = 0; i < conf->bindings.url.count; i++) { + const struct config_key_binding *binding = &conf->bindings.url.arr[i]; +#if 0 + if (binding->action == BIND_ACTION_URL_NONE) + continue; +#endif + convert_key_binding(seat, binding, &seat->kbd.bindings.url); + } } static void @@ -562,8 +576,12 @@ convert_mouse_binding(struct seat *seat, static void convert_mouse_bindings(const struct config *conf, struct seat *seat) { - tll_foreach(conf->bindings.mouse, it) - convert_mouse_binding(seat, &it->item); + for (size_t i = 0; i < conf->bindings.mouse.count; i++) { + const struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i]; + if (binding->action == BIND_ACTION_NONE) + continue; + convert_mouse_binding(seat, binding); + } } static void @@ -1924,9 +1942,11 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, else { /* Seat does NOT have a keyboard - use mouse bindings *without* modifiers */ const struct config_mouse_binding *match = NULL; + const struct config *conf = seat->wayl->conf; - tll_foreach(seat->wayl->conf->bindings.mouse, it) { - const struct config_mouse_binding *binding = &it->item; + for (size_t i = 0; i < conf->bindings.mouse.count; i++) { + const struct config_mouse_binding *binding = + &conf->bindings.mouse.arr[i]; if (binding->button != button) { /* Wrong button */ diff --git a/main.c b/main.c index 52ebaca6..df9edfd6 100644 --- a/main.c +++ b/main.c @@ -441,17 +441,22 @@ main(int argc, char *const *argv) if (login_shell) conf.login_shell = true; if (tll_length(conf_fonts) > 0) { - for (size_t i = 0; i < ALEN(conf.fonts); i++) { - tll_foreach(conf.fonts[i], it) - config_font_destroy(&it->item); - tll_free(conf.fonts[i]); - } + for (size_t i = 0; i < ALEN(conf.fonts); i++) + config_font_list_destroy(&conf.fonts[i]); + + struct config_font_list *font_list = &conf.fonts[0]; + xassert(font_list->count == 0); + xassert(font_list->arr == NULL); + + font_list->arr = xmalloc( + tll_length(conf_fonts) * sizeof(font_list->arr[0])); + tll_foreach(conf_fonts, it) { struct config_font font; if (!config_font_parse(it->item, &font)) { LOG_ERR("%s: invalid font specification", it->item); } else - tll_push_back(conf.fonts[0], font); + font_list->arr[font_list->count++] = font; } tll_free(conf_fonts); } diff --git a/terminal.c b/terminal.c index d949388d..e689f4f6 100644 --- a/terminal.c +++ b/terminal.c @@ -808,11 +808,13 @@ font_loader_thread(void *_data) static bool reload_fonts(struct terminal *term) { + const struct config *conf = term->conf; + const size_t counts[4] = { - tll_length(term->conf->fonts[0]), - tll_length(term->conf->fonts[1]), - tll_length(term->conf->fonts[2]), - tll_length(term->conf->fonts[3]), + conf->fonts[0].count, + conf->fonts[1].count, + conf->fonts[2].count, + conf->fonts[3].count, }; /* Configure size (which may have been changed run-time) */ @@ -820,8 +822,10 @@ reload_fonts(struct terminal *term) for (size_t i = 0; i < 4; i++) { names[i] = xmalloc(counts[i] * sizeof(names[i][0])); - size_t j = 0; - tll_foreach(term->conf->fonts[i], it) { + const struct config_font_list *font_list = &conf->fonts[i]; + + for (size_t j = 0; j < font_list->count; j++) { + const struct config_font *font = &font_list->arr[j]; bool use_px_size = term->font_sizes[i][j].px_size > 0; char size[64]; @@ -835,12 +839,11 @@ reload_fonts(struct terminal *term) snprintf(size, sizeof(size), ":size=%.2f", term->font_sizes[i][j].pt_size * (double)scale); - size_t len = strlen(it->item.pattern) + strlen(size) + 1; + size_t len = strlen(font->pattern) + strlen(size) + 1; names[i][j] = xmalloc(len); - strcpy(names[i][j], it->item.pattern); + strcpy(names[i][j], font->pattern); strcat(names[i][j], size); - j++; } } @@ -937,11 +940,15 @@ reload_fonts(struct terminal *term) static bool load_fonts_from_conf(struct terminal *term) { + const struct config *conf = term->conf; + for (size_t i = 0; i < 4; i++) { - size_t j = 0; - tll_foreach(term->conf->fonts[i], it) { + const struct config_font_list *font_list = &conf->fonts[i]; + + for (size_t j = 0; i < font_list->count; j++) { + const struct config_font *font = &font_list->arr[j]; term->font_sizes[i][j++] = (struct config_font){ - .pt_size = it->item.pt_size, .px_size = it->item.px_size}; + .pt_size = font->pt_size, .px_size = font->px_size}; } } @@ -1039,10 +1046,10 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, .ptmx_buffers = tll_init(), .ptmx_paste_buffers = tll_init(), .font_sizes = { - xmalloc(sizeof(term->font_sizes[0][0]) * tll_length(conf->fonts[0])), - xmalloc(sizeof(term->font_sizes[1][0]) * tll_length(conf->fonts[1])), - xmalloc(sizeof(term->font_sizes[2][0]) * tll_length(conf->fonts[2])), - xmalloc(sizeof(term->font_sizes[3][0]) * tll_length(conf->fonts[3])), + xmalloc(sizeof(term->font_sizes[0][0]) * conf->fonts[0].count), + xmalloc(sizeof(term->font_sizes[1][0]) * conf->fonts[1].count), + xmalloc(sizeof(term->font_sizes[2][0]) * conf->fonts[2].count), + xmalloc(sizeof(term->font_sizes[3][0]) * conf->fonts[3].count), }, .font_dpi = 0., .font_subpixel = (conf->colors.alpha == 0xffff /* Can't do subpixel rendering on transparent background */ @@ -1136,10 +1143,11 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, term_update_ascii_printer(term); for (size_t i = 0; i < 4; i++) { - size_t j = 0; - tll_foreach(conf->fonts[i], it) { + const struct config_font_list *font_list = &conf->fonts[i]; + for (size_t j = 0; j < font_list->count; j++) { + const struct config_font *font = &font_list->arr[j]; term->font_sizes[i][j++] = (struct config_font){ - .pt_size = it->item.pt_size, .px_size = it->item.px_size}; + .pt_size = font->pt_size, .px_size = font->px_size}; } } term->font_line_height = conf->line_height; @@ -1716,8 +1724,12 @@ term_reset(struct terminal *term, bool hard) static bool term_font_size_adjust(struct terminal *term, double amount) { + const struct config *conf = term->conf; + for (size_t i = 0; i < 4; i++) { - for (size_t j = 0; j < tll_length(term->conf->fonts[i]); j++) { + const struct config_font_list *font_list = &conf->fonts[i]; + + for (size_t j = 0; j < font_list->count; j++) { double old_pt_size = term->font_sizes[i][j].pt_size; /*