From a33e3badad7fbfa7e229f009c5c1b78c552a935b Mon Sep 17 00:00:00 2001 From: "S. Christoffer Eliesen" Date: Wed, 18 Nov 2015 21:12:20 +0100 Subject: [PATCH 1/3] list: Add list_seq_find. Sometimes one has to traverse a list to find out if some data already exists there in order to avoid dupilcates in the list, and this function facilitates in that without requiring that the data is ordered. --- common/list.c | 10 ++++++++++ include/list.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/common/list.c b/common/list.c index 45efc16f..ef1cfda8 100644 --- a/common/list.c +++ b/common/list.c @@ -53,3 +53,13 @@ void list_cat(list_t *list, list_t *source) { void list_sort(list_t *list, int compare(const void *left, const void *right)) { qsort(list->items, list->length, sizeof(void *), compare); } + +int list_seq_find(list_t *list, int (*cmp)(const void *item, const void *data), const void *data) { + for (int i = 0; i < list->length; i++) { + void *item = list->items[i]; + if ((cmp)(item, data) == 0) { + return i; + } + } + return -1; +} diff --git a/include/list.h b/include/list.h index aff6800f..90d0ad36 100644 --- a/include/list.h +++ b/include/list.h @@ -15,5 +15,8 @@ void list_del(list_t *list, int index); void list_cat(list_t *list, list_t *source); // See qsort void list_sort(list_t *list, int compare(const void *left, const void *right)); +// Return index for first item in list that returns 0 for given compare +// function or -1 if none matches. +int list_seq_find(list_t *list, int compare(const void *item, const void *cmp_to), const void *cmp_to); #endif From d0af224e6da2505601b9c068912903b3d32e37c6 Mon Sep 17 00:00:00 2001 From: "S. Christoffer Eliesen" Date: Thu, 19 Nov 2015 11:52:58 +0100 Subject: [PATCH 2/3] stringop: lenient_strcmp: Add. --- include/stringop.h | 3 +++ sway/stringop.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/stringop.h b/include/stringop.h index febbbaba..bb681bcd 100644 --- a/include/stringop.h +++ b/include/stringop.h @@ -14,6 +14,9 @@ char *strip_whitespace(char *str); char *strip_comments(char *str); void strip_quotes(char *str); +// strcmp that also handles null pointers. +int lenient_strcmp(char *a, char *b); + // Simply split a string with delims, free with `free_flat_list` list_t *split_string(const char *str, const char *delims); void free_flat_list(list_t *list); diff --git a/sway/stringop.c b/sway/stringop.c index 8d6cac2f..fe5a97ca 100644 --- a/sway/stringop.c +++ b/sway/stringop.c @@ -74,6 +74,19 @@ void strip_quotes(char *str) { *end = '\0'; } +// strcmp that also handles null pointers. +int lenient_strcmp(char *a, char *b) { + if (a == b) { + return 0; + } else if (!a) { + return -1; + } else if (!b) { + return 1; + } else { + return strcmp(a, b); + } +} + list_t *split_string(const char *str, const char *delims) { list_t *res = create_list(); char *copy = strdup(str); From 5531dbe1b2026a88670c812d40f0efccb4b52c7f Mon Sep 17 00:00:00 2001 From: "S. Christoffer Eliesen" Date: Thu, 19 Nov 2015 13:05:59 +0100 Subject: [PATCH 3/3] cmd_workspace: Don't fill up config->workspace_outputs with duplicates. This also fixes a bug where issuing a new "workspace a output b" command for an already assigned workspace would not work (the old config would be found first and used instead). --- common/list.c | 4 ++-- include/config.h | 2 ++ sway/commands.c | 8 +++++++- sway/config.c | 8 ++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/common/list.c b/common/list.c index ef1cfda8..310296d8 100644 --- a/common/list.c +++ b/common/list.c @@ -54,10 +54,10 @@ void list_sort(list_t *list, int compare(const void *left, const void *right)) { qsort(list->items, list->length, sizeof(void *), compare); } -int list_seq_find(list_t *list, int (*cmp)(const void *item, const void *data), const void *data) { +int list_seq_find(list_t *list, int compare(const void *item, const void *data), const void *data) { for (int i = 0; i < list->length; i++) { void *item = list->items[i]; - if ((cmp)(item, data) == 0) { + if (compare(item, data) == 0) { return i; } } diff --git a/include/config.h b/include/config.h index c93f9caf..82aa71bf 100644 --- a/include/config.h +++ b/include/config.h @@ -102,6 +102,8 @@ char *do_var_replacement(char *str); void apply_output_config(struct output_config *oc, swayc_t *output); void free_output_config(struct output_config *oc); +int workspace_output_cmp_workspace(const void *a, const void *b); + /** * Global config singleton. */ diff --git a/sway/commands.c b/sway/commands.c index 173f0f53..7f24f5ab 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -1318,9 +1318,15 @@ static struct cmd_results *cmd_workspace(int argc, char **argv) { return error; } struct workspace_output *wso = calloc(1, sizeof(struct workspace_output)); - sway_log(L_DEBUG, "Assigning workspace %s to output %s", argv[0], argv[2]); wso->workspace = strdup(argv[0]); wso->output = strdup(argv[2]); + int i = -1; + if ((i = list_seq_find(config->workspace_outputs, workspace_output_cmp_workspace, wso)) != -1) { + struct workspace_output *old = config->workspace_outputs->items[i]; + free(old); // workspaces can only be assigned to a single output + list_del(config->workspace_outputs, i); + } + sway_log(L_DEBUG, "Assigning workspace %s to output %s", argv[0], argv[2]); list_add(config->workspace_outputs, wso); if (!config->reading) { // TODO: Move workspace to output. (dont do so when reloading) diff --git a/sway/config.c b/sway/config.c index 725dedd2..2fceb6e2 100644 --- a/sway/config.c +++ b/sway/config.c @@ -375,3 +375,11 @@ char *do_var_replacement(char *str) { } return str; } + +// the naming is intentional (albeit long): a workspace_output_cmp function +// would compare two structs in full, while this method only compares the +// workspace. +int workspace_output_cmp_workspace(const void *a, const void *b) { + const struct workspace_output *wsa = a, *wsb = b; + return lenient_strcmp(wsa->workspace, wsb->workspace); +}