From b68a400abfeb9f17901497eb005862853656287c Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 28 Aug 2015 09:30:28 +0200 Subject: [PATCH] Bugfix: sort bindings, re-ordering once is not enough. Reordering once (as we did it before this commit) would only sort the bindings by the _first_ bit of their event_state_mask, but we need to sort them by _all_ bits of their event_state_mask. fixes #1870 --- src/bindings.c | 53 +++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/bindings.c b/src/bindings.c index 520f5522..f9d2cf8d 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -428,32 +428,41 @@ void switch_mode(const char *new_mode) { ELOG("ERROR: Mode not found\n"); } +static int reorder_binding_cmp(const void *a, const void *b) { + Binding *first = *((Binding **)a); + Binding *second = *((Binding **)b); + if (first->event_state_mask < second->event_state_mask) { + return 1; + } else if (first->event_state_mask == second->event_state_mask) { + return 0; + } else { + return -1; + } +} + static void reorder_bindings_of_mode(struct Mode *mode) { + /* Copy the bindings into an array, so that we can use qsort(3). */ + int n = 0; + Binding *current; + TAILQ_FOREACH(current, mode->bindings, bindings) { + n++; + } + Binding **tmp = scalloc(n, sizeof(Binding *)); + n = 0; + TAILQ_FOREACH(current, mode->bindings, bindings) { + tmp[n++] = current; + } + + qsort(tmp, n, sizeof(Binding *), reorder_binding_cmp); + struct bindings_head *reordered = scalloc(1, sizeof(struct bindings_head)); TAILQ_INIT(reordered); - /* 20 bits are in use in an i3_event_state_mask_t. */ - for (int n = 19; n >= 0; n--) { - Binding *current; - for (current = TAILQ_FIRST(mode->bindings); current != TAILQ_END(mode->bindings);) { - /* Advance |current| so that we can use TAILQ_REMOVE safely. */ - Binding *bind = current; - current = TAILQ_NEXT(current, bindings); - if ((bind->event_state_mask & (1 << n)) == 0) - continue; - TAILQ_REMOVE(mode->bindings, bind, bindings); - TAILQ_INSERT_TAIL(reordered, bind, bindings); - } - } - /* Move over the bindings with event_state_mask == 0x0. */ - Binding *current; - for (current = TAILQ_FIRST(mode->bindings); current != TAILQ_END(mode->bindings);) { - /* Advance |current| so that we can use TAILQ_REMOVE safely. */ - Binding *bind = current; - current = TAILQ_NEXT(current, bindings); - assert(bind->event_state_mask == 0); - TAILQ_REMOVE(mode->bindings, bind, bindings); - TAILQ_INSERT_TAIL(reordered, bind, bindings); + for (int i = 0; i < n; i++) { + current = tmp[i]; + TAILQ_REMOVE(mode->bindings, current, bindings); + TAILQ_INSERT_TAIL(reordered, current, bindings); } + free(tmp); assert(TAILQ_EMPTY(mode->bindings)); /* Free the old bindings_head, which is now empty. */ free(mode->bindings);