From 495c7304878bdd010dc5d25620dc68f41ac4cd36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 17 Jun 2021 18:15:29 +0200 Subject: [PATCH] =?UTF-8?q?config:=20don=E2=80=99t=20use=20tllist=20where?= =?UTF-8?q?=20it=20isn=E2=80=99t=20necessary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tllists are great when dealing with dynamically changing lists. They are also very easy to use when building lists/arrays where the final size is unknown. However, this ease of use comes at a price: code size. tll-macros expand to a lot of code. Since things in the config are static, once the config has been loaded, using tllists for configuration data structures doesn’t make much sense. This patch replaces nearly all tllists used by the configuration, with dynamically allocated arrays. --- config.c | 523 ++++++++++++++++++++++++++++++----------------------- config.h | 24 ++- input.c | 40 +++- main.c | 17 +- terminal.c | 52 ++++-- 5 files changed, 380 insertions(+), 276 deletions(-) diff --git a/config.c b/config.c index ae7f0be5..e4c8ca9a 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})); -} +static const struct config_key_modifiers none = {0}; +static const struct config_key_modifiers alt = {.alt = true}; +static const struct config_key_modifiers ctrl = {.ctrl = true}; +static const struct config_key_modifiers shift = {.shift = true}; +static const struct config_key_modifiers 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, shift, XKB_KEY_Page_Up}, + {BIND_ACTION_SCROLLBACK_DOWN_PAGE, shift, XKB_KEY_Page_Down}, + {BIND_ACTION_CLIPBOARD_COPY, ctrl_shift, XKB_KEY_c}, + {BIND_ACTION_CLIPBOARD_PASTE, ctrl_shift, XKB_KEY_v}, + {BIND_ACTION_PRIMARY_PASTE, shift, XKB_KEY_Insert}, + {BIND_ACTION_SEARCH_START, ctrl_shift, XKB_KEY_r}, + {BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_plus}, + {BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_equal}, + {BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_KP_Add}, + {BIND_ACTION_FONT_SIZE_DOWN, ctrl, XKB_KEY_minus}, + {BIND_ACTION_FONT_SIZE_DOWN, ctrl, XKB_KEY_KP_Subtract}, + {BIND_ACTION_FONT_SIZE_RESET, ctrl, XKB_KEY_0}, + {BIND_ACTION_FONT_SIZE_RESET, ctrl, XKB_KEY_KP_0}, + {BIND_ACTION_SPAWN_TERMINAL, ctrl_shift, XKB_KEY_n}, + {BIND_ACTION_SHOW_URLS_LAUNCH, 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, ctrl, XKB_KEY_c}, + {BIND_ACTION_SEARCH_CANCEL, ctrl, XKB_KEY_g}, + {BIND_ACTION_SEARCH_CANCEL, none, XKB_KEY_Escape}, + {BIND_ACTION_SEARCH_COMMIT, none, XKB_KEY_Return}, + {BIND_ACTION_SEARCH_FIND_PREV, ctrl, XKB_KEY_r}, + {BIND_ACTION_SEARCH_FIND_NEXT, ctrl, XKB_KEY_s}, + {BIND_ACTION_SEARCH_EDIT_LEFT, none, XKB_KEY_Left}, + {BIND_ACTION_SEARCH_EDIT_LEFT, ctrl, XKB_KEY_b}, + {BIND_ACTION_SEARCH_EDIT_LEFT_WORD, ctrl, XKB_KEY_Left}, + {BIND_ACTION_SEARCH_EDIT_LEFT_WORD, alt, XKB_KEY_b}, + {BIND_ACTION_SEARCH_EDIT_RIGHT, none, XKB_KEY_Right}, + {BIND_ACTION_SEARCH_EDIT_RIGHT, ctrl, XKB_KEY_f}, + {BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, ctrl, XKB_KEY_Right}, + {BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, alt, XKB_KEY_f}, + {BIND_ACTION_SEARCH_EDIT_HOME, none, XKB_KEY_Home}, + {BIND_ACTION_SEARCH_EDIT_HOME, ctrl, XKB_KEY_a}, + {BIND_ACTION_SEARCH_EDIT_END, none, XKB_KEY_End}, + {BIND_ACTION_SEARCH_EDIT_END, ctrl, XKB_KEY_e}, + {BIND_ACTION_SEARCH_DELETE_PREV, none, XKB_KEY_BackSpace}, + {BIND_ACTION_SEARCH_DELETE_PREV_WORD, ctrl, XKB_KEY_BackSpace}, + {BIND_ACTION_SEARCH_DELETE_PREV_WORD, alt, XKB_KEY_BackSpace}, + {BIND_ACTION_SEARCH_DELETE_NEXT, none, XKB_KEY_Delete}, + {BIND_ACTION_SEARCH_DELETE_NEXT_WORD, ctrl, XKB_KEY_Delete}, + {BIND_ACTION_SEARCH_DELETE_NEXT_WORD, alt, XKB_KEY_d}, + {BIND_ACTION_SEARCH_EXTEND_WORD, ctrl, XKB_KEY_w}, + {BIND_ACTION_SEARCH_EXTEND_WORD_WS, ctrl_shift, XKB_KEY_w}, + {BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_v}, + {BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_y}, + {BIND_ACTION_SEARCH_PRIMARY_PASTE, 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, ctrl, XKB_KEY_c}, + {BIND_ACTION_URL_CANCEL, ctrl, XKB_KEY_g}, + {BIND_ACTION_URL_CANCEL, ctrl, XKB_KEY_d}, + {BIND_ACTION_URL_CANCEL, none, XKB_KEY_Escape}, + {BIND_ACTION_URL_TOGGLE_URL_ON_JUMP_LABEL, 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, none, BTN_MIDDLE, 1}, + {BIND_ACTION_SELECT_BEGIN, none, BTN_LEFT, 1}, + {BIND_ACTION_SELECT_BEGIN_BLOCK, ctrl, BTN_LEFT, 1}, + {BIND_ACTION_SELECT_EXTEND, none, BTN_RIGHT, 1}, + {BIND_ACTION_SELECT_EXTEND_CHAR_WISE, ctrl, BTN_RIGHT, 1}, + {BIND_ACTION_SELECT_WORD, none, BTN_LEFT, 2}, + {BIND_ACTION_SELECT_WORD_WS, ctrl, BTN_LEFT, 2}, + {BIND_ACTION_SELECT_ROW, 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; /*