config: remove struct key_combo, use config_key_binding instead

This commit is contained in:
Daniel Eklöf 2021-12-04 21:53:48 +01:00
parent 87c454c044
commit fc2bacbb78
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

325
config.c
View file

@ -1443,32 +1443,27 @@ parse_section_csd(struct context *ctx)
return true; return true;
} }
/* Struct that holds temporary key/mouse binding parsed data */ static void
struct key_combo { binding_pipe_free(struct config_binding_pipe *pipe)
char *text; /* Raw text, e.g. "Control+Shift+V" */ {
struct config_key_modifiers modifiers; if (pipe->master_copy)
union { free_argv(&pipe->argv);
xkb_keysym_t sym; /* Key converted to an XKB symbol, e.g. XKB_KEY_V */ }
struct {
int button;
int count;
} m;
};
};
struct key_combo_list {
size_t count;
struct key_combo *combos;
};
static void NOINLINE static void NOINLINE
free_key_combo_list(struct key_combo_list *key_combos) key_binding_list_free(struct config_key_binding_list *bindings)
{ {
for (size_t i = 0; i < key_combos->count; i++) for (size_t i = 0; i < bindings->count; i++)
free(key_combos->combos[i].text); binding_pipe_free(&bindings->arr[i].pipe);
free(key_combos->combos); free(bindings->arr);
key_combos->count = 0; }
key_combos->combos = NULL;
static void
mouse_binding_list_free(struct config_mouse_binding_list *bindings)
{
for (size_t i = 0; i < bindings->count; i++)
binding_pipe_free(&bindings->arr[i].pipe);
free(bindings->arr);
} }
static bool static bool
@ -1511,10 +1506,11 @@ out:
} }
static bool static bool
value_to_key_combos(struct context *ctx, struct key_combo_list *key_combos) value_to_key_combos(struct context *ctx,
struct config_key_binding_list *key_combos)
{ {
xassert(key_combos != NULL); xassert(key_combos != NULL);
xassert(key_combos->count == 0 && key_combos->combos == NULL); xassert(key_combos->count == 0 && key_combos->arr == NULL);
size_t size = 0; /* Size of combos array in the key-combo list */ size_t size = 0; /* Size of combos array in the key-combo list */
@ -1545,13 +1541,12 @@ value_to_key_combos(struct context *ctx, struct key_combo_list *key_combos)
if (key_combos->count + 1 > size) { if (key_combos->count + 1 > size) {
size += 4; size += 4;
key_combos->combos = xrealloc( key_combos->arr = xrealloc(
key_combos->combos, size * sizeof(key_combos->combos[0])); key_combos->arr, size * sizeof(key_combos->arr[0]));
} }
xassert(key_combos->count + 1 <= size); xassert(key_combos->count + 1 <= size);
key_combos->combos[key_combos->count++] = (struct key_combo){ key_combos->arr[key_combos->count++] = (struct config_key_binding){
.text = xstrdup(combo),
.modifiers = modifiers, .modifiers = modifiers,
.sym = sym, .sym = sym,
}; };
@ -1561,7 +1556,7 @@ value_to_key_combos(struct context *ctx, struct key_combo_list *key_combos)
return true; return true;
err: err:
free_key_combo_list(key_combos); key_binding_list_free(key_combos);
free(copy); free(copy);
return false; return false;
} }
@ -1594,11 +1589,45 @@ argv_compare(const struct argv *argv1, const struct argv *argv2)
return 1; return 1;
} }
static bool
modifiers_equal(const struct config_key_modifiers *mods1,
const struct config_key_modifiers *mods2)
{
bool shift = mods1->shift == mods2->shift;
bool alt = mods1->alt == mods2->alt;
bool ctrl = mods1->ctrl == mods2->ctrl;
bool meta = mods1->meta == mods2->meta;
return shift && alt && ctrl && meta;
}
static bool
modifiers_disjoint(const struct config_key_modifiers *mods1,
const struct config_key_modifiers *mods2)
{
bool shift = mods1->shift && mods2->shift;
bool alt = mods1->alt && mods2->alt;
bool ctrl = mods1->ctrl && mods2->ctrl;
bool meta = mods1->meta && mods2->meta;
return !(shift || alt || ctrl || meta);
}
static char *
modifiers_to_str(const struct config_key_modifiers *mods)
{
char *ret = xasprintf("%s%s%s%s",
mods->ctrl ? "Control+" : "",
mods->alt ? "Alt+": "",
mods->meta ? "Meta+": "",
mods->shift ? "Shift+": "");
ret[strlen(ret) - 1] = '\0';
return ret;
}
static bool static bool
has_key_binding_collisions(struct context *ctx, has_key_binding_collisions(struct context *ctx,
int action, const char *const action_map[], int action, const char *const action_map[],
const struct config_key_binding_list *bindings, const struct config_key_binding_list *bindings,
const struct key_combo_list *key_combos, const struct config_key_binding_list *key_combos,
const struct argv *pipe_argv) const struct argv *pipe_argv)
{ {
for (size_t j = 0; j < bindings->count; j++) { for (size_t j = 0; j < bindings->count; j++) {
@ -1613,25 +1642,29 @@ has_key_binding_collisions(struct context *ctx,
} }
for (size_t i = 0; i < key_combos->count; i++) { for (size_t i = 0; i < key_combos->count; i++) {
const struct key_combo *combo2 = &key_combos->combos[i]; const struct config_key_binding *combo2 = &key_combos->arr[i];
const struct config_key_modifiers *mods1 = &combo1->modifiers; const struct config_key_modifiers *mods1 = &combo1->modifiers;
const struct config_key_modifiers *mods2 = &combo2->modifiers; const struct config_key_modifiers *mods2 = &combo2->modifiers;
bool shift = mods1->shift == mods2->shift; bool mods_equal = modifiers_equal(mods1, mods2);
bool alt = mods1->alt == mods2->alt; bool sym_equal = combo1->sym == combo2->sym;
bool ctrl = mods1->ctrl == mods2->ctrl;
bool meta = mods1->meta == mods2->meta;
bool sym = combo1->sym == combo2->sym;
if (shift && alt && ctrl && meta && sym) { if (mods_equal && sym_equal) {
bool has_pipe = combo1->pipe.argv.args != NULL; bool has_pipe = combo1->pipe.argv.args != NULL;
LOG_CONTEXTUAL_ERR("%s already mapped to '%s%s%s%s'",
combo2->text, char *modifier_names = modifiers_to_str(mods2);
char sym_name[64];
xkb_keysym_get_name(combo2->sym, sym_name, sizeof(sym_name));
LOG_CONTEXTUAL_ERR("%s+%s already mapped to '%s%s%s%s'",
modifier_names, sym_name,
action_map[combo1->action], action_map[combo1->action],
has_pipe ? " [" : "", has_pipe ? " [" : "",
has_pipe ? combo1->pipe.argv.args[0] : "", has_pipe ? combo1->pipe.argv.args[0] : "",
has_pipe ? "]" : ""); has_pipe ? "]" : "");
free(modifier_names);
return true; return true;
} }
} }
@ -1757,13 +1790,12 @@ parse_key_binding_section(struct context *ctx,
return true; return true;
} }
struct key_combo_list key_combos = {0}; struct config_key_binding_list key_combos = {0};
if (!value_to_key_combos(ctx, &key_combos) || if (!value_to_key_combos(ctx, &key_combos) ||
has_key_binding_collisions( has_key_binding_collisions(ctx, action, action_map, bindings, &key_combos, &pipe_argv))
ctx, action, action_map, bindings, &key_combos, &pipe_argv))
{ {
free_argv(&pipe_argv); free_argv(&pipe_argv);
free_key_combo_list(&key_combos); key_binding_list_free(&key_combos);
return false; return false;
} }
@ -1777,23 +1809,17 @@ parse_key_binding_section(struct context *ctx,
bool first = true; bool first = true;
for (size_t i = 0; i < key_combos.count; i++) { for (size_t i = 0; i < key_combos.count; i++) {
const struct key_combo *combo = &key_combos.combos[i]; struct config_key_binding *binding = &bindings->arr[ofs + i];
struct config_key_binding binding = {
.action = action, *binding = key_combos.arr[i];
.modifiers = combo->modifiers, binding->action = action;
.sym = combo->sym, binding->pipe.argv = pipe_argv;
.pipe = { binding->pipe.master_copy = first;
.argv = pipe_argv,
.master_copy = first,
},
};
/* TODO: we could re-use free:d slots */
bindings->arr[ofs + i] = binding;
first = false; first = false;
} }
free_key_combo_list(&key_combos); key_binding_list_free(&key_combos);
return true; return true;
} }
@ -1982,10 +2008,11 @@ mouse_event_code_get_name(int code)
} }
static bool static bool
value_to_mouse_combos(struct context *ctx, struct key_combo_list *key_combos) value_to_mouse_combos(struct context *ctx,
struct config_mouse_binding_list *mouse_combos)
{ {
xassert(key_combos != NULL); xassert(mouse_combos != NULL);
xassert(key_combos->count == 0 && key_combos->combos == NULL); xassert(mouse_combos->count == 0 && mouse_combos->arr == NULL);
size_t size = 0; /* Size of the combos array in key_combos */ size_t size = 0; /* Size of the combos array in key_combos */
@ -2042,93 +2069,55 @@ value_to_mouse_combos(struct context *ctx, struct key_combo_list *key_combos)
goto err; goto err;
} }
struct key_combo new = { struct config_mouse_binding new = {
.text = xstrdup(combo),
.modifiers = modifiers, .modifiers = modifiers,
.m = { .button = button,
.button = button, .count = count,
.count = count,
},
}; };
if (key_combos->count + 1 > size) { if (mouse_combos->count + 1 > size) {
size += 4; size += 4;
key_combos->combos = xrealloc( mouse_combos->arr = xrealloc(
key_combos->combos, size * sizeof(key_combos->combos[0])); mouse_combos->arr, size * sizeof(mouse_combos->arr[0]));
} }
xassert(key_combos->count + 1 <= size); xassert(mouse_combos->count + 1 <= size);
key_combos->combos[key_combos->count++] = new; mouse_combos->arr[mouse_combos->count++] = new;
} }
free(copy); free(copy);
return true; return true;
err: err:
free_key_combo_list(key_combos); mouse_binding_list_free(mouse_combos);
free(copy); free(copy);
return false; return false;
} }
static bool
modifiers_equal(const struct config_key_modifiers *mods1,
const struct config_key_modifiers *mods2)
{
bool shift = mods1->shift == mods2->shift;
bool alt = mods1->alt == mods2->alt;
bool ctrl = mods1->ctrl == mods2->ctrl;
bool meta = mods1->meta == mods2->meta;
return shift && alt && ctrl && meta;
}
static bool
modifiers_disjoint(const struct config_key_modifiers *mods1,
const struct config_key_modifiers *mods2)
{
bool shift = mods1->shift && mods2->shift;
bool alt = mods1->alt && mods2->alt;
bool ctrl = mods1->ctrl && mods2->ctrl;
bool meta = mods1->meta && mods2->meta;
return !(shift || alt || ctrl || meta);
}
static char * static char *
modifiers_to_str(const struct config_key_modifiers *mods) mouse_combo_to_str(const struct config_mouse_binding *combo)
{
char *ret = xasprintf("%s%s%s%s",
mods->ctrl ? "Control+" : "",
mods->alt ? "Alt+": "",
mods->meta ? "Meta+": "",
mods->shift ? "Shift+": "");
ret[strlen(ret) - 1] = '\0';
return ret;
}
static char *
mouse_combo_to_str(const struct key_combo *combo)
{ {
char *combo_modifiers_str = modifiers_to_str(&combo->modifiers); char *combo_modifiers_str = modifiers_to_str(&combo->modifiers);
const char *combo_button_str = mouse_event_code_get_name(combo->m.button); const char *combo_button_str = mouse_event_code_get_name(combo->button);
xassert(combo_button_str != NULL); xassert(combo_button_str != NULL);
char *ret; char *ret;
if (combo->m.count == 1) if (combo->count == 1)
ret = xasprintf("%s+%s", combo_modifiers_str, combo_button_str); ret = xasprintf("%s+%s", combo_modifiers_str, combo_button_str);
else else
ret = xasprintf("%s+%s-%d", ret = xasprintf("%s+%s-%d",
combo_modifiers_str, combo_modifiers_str,
combo_button_str, combo_button_str,
combo->m.count); combo->count);
free (combo_modifiers_str); free (combo_modifiers_str);
return ret; return ret;
} }
static bool static bool
selection_override_interferes_with_mouse_binding(struct context *ctx, selection_override_interferes_with_mouse_binding(
int action, struct context *ctx, int action,
const struct key_combo_list *key_combos, const struct config_mouse_binding_list *mouse_combos, bool blame_modifiers)
bool blame_modifiers)
{ {
struct config *conf = ctx->conf; struct config *conf = ctx->conf;
@ -2137,8 +2126,8 @@ selection_override_interferes_with_mouse_binding(struct context *ctx,
const struct config_key_modifiers *override_mods = const struct config_key_modifiers *override_mods =
&conf->mouse.selection_override_modifiers; &conf->mouse.selection_override_modifiers;
for (size_t i = 0; i < key_combos->count; i++) { for (size_t i = 0; i < mouse_combos->count; i++) {
const struct key_combo *combo = &key_combos->combos[i]; const struct config_mouse_binding *combo = &mouse_combos->arr[i];
if (!modifiers_disjoint(&combo->modifiers, override_mods)) { if (!modifiers_disjoint(&combo->modifiers, override_mods)) {
char *modifiers_str = modifiers_to_str(override_mods); char *modifiers_str = modifiers_to_str(override_mods);
@ -2163,8 +2152,9 @@ selection_override_interferes_with_mouse_binding(struct context *ctx,
} }
static bool static bool
has_mouse_binding_collisions(struct context *ctx, has_mouse_binding_collisions(
const struct key_combo_list *key_combos) struct context *ctx,
const struct config_mouse_binding_list *mouse_combos)
{ {
struct config *conf = ctx->conf; struct config *conf = ctx->conf;
@ -2173,23 +2163,33 @@ has_mouse_binding_collisions(struct context *ctx,
if (combo1->action == BIND_ACTION_NONE) if (combo1->action == BIND_ACTION_NONE)
continue; continue;
for (size_t i = 0; i < key_combos->count; i++) { for (size_t i = 0; i < mouse_combos->count; i++) {
const struct key_combo *combo2 = &key_combos->combos[i]; const struct config_mouse_binding *combo2 = &mouse_combos->arr[i];
const struct config_key_modifiers *mods1 = &combo1->modifiers; const struct config_key_modifiers *mods1 = &combo1->modifiers;
const struct config_key_modifiers *mods2 = &combo2->modifiers; const struct config_key_modifiers *mods2 = &combo2->modifiers;
bool button = combo1->button == combo2->m.button; bool button = combo1->button == combo2->button;
bool count = combo1->count == combo2->m.count; bool count = combo1->count == combo2->count;
if (modifiers_equal(mods1, mods2) && button && count) { if (modifiers_equal(mods1, mods2) && button && count) {
bool has_pipe = combo1->pipe.argv.args != NULL; bool has_pipe = combo1->pipe.argv.args != NULL;
LOG_CONTEXTUAL_ERR("%s already mapped to '%s%s%s%s'",
combo2->text, char *modifier_names = modifiers_to_str(mods2);
const char *btn_name = mouse_event_code_get_name(combo2->button);
char count_string[16] = {0};
if (combo2->count > 1)
sprintf(count_string, "-%d", combo2->count);
LOG_CONTEXTUAL_ERR("%s+%s%s already mapped to '%s%s%s%s'",
modifier_names, btn_name, count_string,
binding_action_map[combo1->action], binding_action_map[combo1->action],
has_pipe ? " [" : "", has_pipe ? " [" : "",
has_pipe ? combo1->pipe.argv.args[0] : "", has_pipe ? combo1->pipe.argv.args[0] : "",
has_pipe ? "]" : ""); has_pipe ? "]" : "");
free(modifier_names);
return true; return true;
} }
} }
@ -2215,21 +2215,15 @@ parse_section_mouse_bindings(struct context *ctx)
/* Ensure no existing bindings use these modifiers */ /* Ensure no existing bindings use these modifiers */
for (size_t i = 0; i < conf->bindings.mouse.count; i++) { for (size_t i = 0; i < conf->bindings.mouse.count; i++) {
const struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i]; struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i];
struct key_combo combo = { struct config_mouse_binding_list mouse_combos = {
.modifiers = binding->modifiers,
.m = {
.button = binding->button,
.count = binding->count,
},
};
struct key_combo_list key_combos = {
.count = 1, .count = 1,
.combos = &combo, .arr = binding,
}; };
if (selection_override_interferes_with_mouse_binding(ctx, binding->action, &key_combos, true)) { if (selection_override_interferes_with_mouse_binding(
ctx, binding->action, &mouse_combos, true))
{
return false; return false;
} }
} }
@ -2269,13 +2263,14 @@ parse_section_mouse_bindings(struct context *ctx)
return true; return true;
} }
struct key_combo_list key_combos = {0}; struct config_mouse_binding_list mouse_combos = {0};
if (!value_to_mouse_combos(ctx, &key_combos) || if (!value_to_mouse_combos(ctx, &mouse_combos) ||
has_mouse_binding_collisions(ctx, &key_combos) || has_mouse_binding_collisions(ctx, &mouse_combos) ||
selection_override_interferes_with_mouse_binding(ctx, action, &key_combos, false)) selection_override_interferes_with_mouse_binding(
ctx, action, &mouse_combos, false))
{ {
free_argv(&pipe_argv); free_argv(&pipe_argv);
free_key_combo_list(&key_combos); mouse_binding_list_free(&mouse_combos);
return false; return false;
} }
@ -2295,30 +2290,25 @@ parse_section_mouse_bindings(struct context *ctx)
/* Emit mouse bindings */ /* Emit mouse bindings */
size_t ofs = conf->bindings.mouse.count; size_t ofs = conf->bindings.mouse.count;
conf->bindings.mouse.count += key_combos.count; conf->bindings.mouse.count += mouse_combos.count;
conf->bindings.mouse.arr = xrealloc( conf->bindings.mouse.arr = xrealloc(
conf->bindings.mouse.arr, conf->bindings.mouse.arr,
conf->bindings.mouse.count * sizeof(conf->bindings.mouse.arr[0])); conf->bindings.mouse.count * sizeof(conf->bindings.mouse.arr[0]));
bool first = true; bool first = true;
for (size_t i = 0; i < key_combos.count; i++) { for (size_t i = 0; i < mouse_combos.count; i++) {
const struct key_combo *combo = &key_combos.combos[i]; struct config_mouse_binding *binding =
struct config_mouse_binding binding = { &conf->bindings.mouse.arr[ofs + i];
.action = action,
.modifiers = combo->modifiers, *binding = mouse_combos.arr[i];
.button = combo->m.button, binding->action = action;
.count = combo->m.count, binding->pipe.argv = pipe_argv;
.pipe = { binding->pipe.master_copy = first;
.argv = pipe_argv,
.master_copy = first,
},
};
conf->bindings.mouse.arr[ofs + i] = binding;
first = false; first = false;
} }
free_key_combo_list(&key_combos); mouse_binding_list_free(&mouse_combos);
return true; return true;
} }
@ -3118,13 +3108,6 @@ config_override_apply(struct config *conf, config_override_t *overrides, bool er
return true; return true;
} }
static void
binding_pipe_free(struct config_binding_pipe *pipe)
{
if (pipe->master_copy)
free_argv(&pipe->argv);
}
static void static void
binding_pipe_clone(struct config_binding_pipe *dst, binding_pipe_clone(struct config_binding_pipe *dst,
const struct config_binding_pipe *src) const struct config_binding_pipe *src)
@ -3133,14 +3116,6 @@ binding_pipe_clone(struct config_binding_pipe *dst,
clone_argv(&dst->argv, &src->argv); clone_argv(&dst->argv, &src->argv);
} }
static void NOINLINE
key_binding_list_free(struct config_key_binding_list *bindings)
{
for (size_t i = 0; i < bindings->count; i++)
binding_pipe_free(&bindings->arr[i].pipe);
free(bindings->arr);
}
static void NOINLINE static void NOINLINE
key_binding_list_clone(struct config_key_binding_list *dst, key_binding_list_clone(struct config_key_binding_list *dst,
const struct config_key_binding_list *src) const struct config_key_binding_list *src)
@ -3169,14 +3144,6 @@ key_binding_list_clone(struct config_key_binding_list *dst,
} }
} }
static void
mouse_binding_list_free(struct config_mouse_binding_list *bindings)
{
for (size_t i = 0; i < bindings->count; i++)
binding_pipe_free(&bindings->arr[i].pipe);
free(bindings->arr);
}
static void NOINLINE static void NOINLINE
mouse_binding_list_clone(struct config_mouse_binding_list *dst, mouse_binding_list_clone(struct config_mouse_binding_list *dst,
const struct config_mouse_binding_list *src) const struct config_mouse_binding_list *src)