aboutsummaryrefslogtreecommitdiff
path: root/sway/config
diff options
context:
space:
mode:
Diffstat (limited to 'sway/config')
-rw-r--r--sway/config/input.c134
1 files changed, 105 insertions, 29 deletions
diff --git a/sway/config/input.c b/sway/config/input.c
index 9c533e71..c4f64eb8 100644
--- a/sway/config/input.c
+++ b/sway/config/input.c
@@ -3,6 +3,7 @@
#include <limits.h>
#include <float.h>
#include "sway/config.h"
+#include "sway/input/keyboard.h"
#include "log.h"
struct input_config *new_input_config(const char* identifier) {
@@ -133,22 +134,82 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
}
}
-static void merge_wildcard_on_all(struct input_config *wildcard) {
+static bool validate_xkb_merge(struct input_config *dest,
+ struct input_config *src, char **xkb_error) {
+ struct input_config *temp = new_input_config("temp");
+ if (dest) {
+ merge_input_config(temp, dest);
+ }
+ merge_input_config(temp, src);
+
+ struct xkb_keymap *keymap = sway_keyboard_compile_keymap(temp, xkb_error);
+ free_input_config(temp);
+ if (!keymap) {
+ return false;
+ }
+
+ xkb_keymap_unref(keymap);
+ return true;
+}
+
+static bool validate_wildcard_on_all(struct input_config *wildcard,
+ char **error) {
for (int i = 0; i < config->input_configs->length; i++) {
struct input_config *ic = config->input_configs->items[i];
if (strcmp(wildcard->identifier, ic->identifier) != 0) {
- sway_log(SWAY_DEBUG, "Merging input * config on %s", ic->identifier);
- merge_input_config(ic, wildcard);
+ sway_log(SWAY_DEBUG, "Validating xkb merge of * on %s",
+ ic->identifier);
+ if (!validate_xkb_merge(ic, wildcard, error)) {
+ return false;
+ }
}
}
for (int i = 0; i < config->input_type_configs->length; i++) {
struct input_config *ic = config->input_type_configs->items[i];
+ sway_log(SWAY_DEBUG, "Validating xkb merge of * config on %s",
+ ic->identifier);
+ if (!validate_xkb_merge(ic, wildcard, error)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void merge_wildcard_on_all(struct input_config *wildcard) {
+ for (int i = 0; i < config->input_configs->length; i++) {
+ struct input_config *ic = config->input_configs->items[i];
if (strcmp(wildcard->identifier, ic->identifier) != 0) {
sway_log(SWAY_DEBUG, "Merging input * config on %s", ic->identifier);
merge_input_config(ic, wildcard);
}
}
+
+ for (int i = 0; i < config->input_type_configs->length; i++) {
+ struct input_config *ic = config->input_type_configs->items[i];
+ sway_log(SWAY_DEBUG, "Merging input * config on %s", ic->identifier);
+ merge_input_config(ic, wildcard);
+ }
+}
+
+static bool validate_type_on_existing(struct input_config *type_wildcard,
+ char **error) {
+ for (int i = 0; i < config->input_configs->length; i++) {
+ struct input_config *ic = config->input_configs->items[i];
+ if (ic->input_type == NULL) {
+ continue;
+ }
+
+ if (strcmp(ic->input_type, type_wildcard->identifier + 5) == 0) {
+ sway_log(SWAY_DEBUG, "Validating merge of %s on %s",
+ type_wildcard->identifier, ic->identifier);
+ if (!validate_xkb_merge(ic, type_wildcard, error)) {
+ return false;
+ }
+ }
+ }
+ return true;
}
static void merge_type_on_existing(struct input_config *type_wildcard) {
@@ -167,44 +228,59 @@ static void merge_type_on_existing(struct input_config *type_wildcard) {
}
}
-struct input_config *store_input_config(struct input_config *ic) {
+struct input_config *store_input_config(struct input_config *ic,
+ char **error) {
bool wildcard = strcmp(ic->identifier, "*") == 0;
+ if (wildcard && error && !validate_wildcard_on_all(ic, error)) {
+ return NULL;
+ }
+
+ bool type = strncmp(ic->identifier, "type:", strlen("type:")) == 0;
+ if (type && error && !validate_type_on_existing(ic, error)) {
+ return NULL;
+ }
+
+ list_t *config_list = type ? config->input_type_configs
+ : config->input_configs;
+
+ struct input_config *current = NULL;
+ bool new_current = false;
+
+ int i = list_seq_find(config_list, input_identifier_cmp, ic->identifier);
+ if (i >= 0) {
+ current = config_list->items[i];
+ }
+
+ i = list_seq_find(config->input_configs, input_identifier_cmp, "*");
+ if (!current && i >= 0) {
+ current = new_input_config(ic->identifier);
+ merge_input_config(current, config->input_configs->items[i]);
+ new_current = true;
+ }
+
+ if (error && !validate_xkb_merge(current, ic, error)) {
+ if (new_current) {
+ free_input_config(current);
+ }
+ return NULL;
+ }
+
if (wildcard) {
merge_wildcard_on_all(ic);
}
- list_t *config_list = NULL;
- if (strncmp(ic->identifier, "type:", 5) == 0) {
- config_list = config->input_type_configs;
+ if (type) {
merge_type_on_existing(ic);
- } else {
- config_list = config->input_configs;
}
- int i = list_seq_find(config_list, input_identifier_cmp,
- ic->identifier);
- if (i >= 0) {
- sway_log(SWAY_DEBUG, "Merging on top of existing input config");
- struct input_config *current = config_list->items[i];
+ if (current) {
merge_input_config(current, ic);
free_input_config(ic);
ic = current;
- } else if (!wildcard) {
- sway_log(SWAY_DEBUG, "Adding non-wildcard input config");
- i = list_seq_find(config->input_configs, input_identifier_cmp, "*");
- if (i >= 0) {
- sway_log(SWAY_DEBUG, "Merging on top of input * config");
- struct input_config *current = new_input_config(ic->identifier);
- merge_input_config(current, config->input_configs->items[i]);
- merge_input_config(current, ic);
- free_input_config(ic);
- ic = current;
- }
+ }
+
+ if (!current || new_current) {
list_add(config_list, ic);
- } else {
- // New wildcard config. Just add it
- sway_log(SWAY_DEBUG, "Adding input * config");
- list_add(config->input_configs, ic);
}
sway_log(SWAY_DEBUG, "Config stored for input %s", ic->identifier);