diff --git a/common/list.c b/common/list.c index a7585a311..d57234e33 100644 --- a/common/list.c +++ b/common/list.c @@ -59,7 +59,7 @@ void list_cat(list_t *list, list_t *source) { } } -void list_qsort(list_t* list, int compare(const void *left, const void *right)) { +void list_qsort(list_t *list, int compare(const void *left, const void *right)) { qsort(list->items, list->length, sizeof(void *), compare); } @@ -72,3 +72,60 @@ int list_seq_find(list_t *list, int compare(const void *item, const void *data), } return -1; } + +static void list_swap(list_t *list, int src, int dest) { + void *tmp = list->items[src]; + list->items[src] = list->items[dest]; + list->items[dest] = tmp; +} + +static void list_rotate(list_t *list, int from, int to) { + void *tmp = list->items[to]; + + while (to > from) { + list->items[to] = list->items[to - 1]; + to--; + } + + list->items[from] = tmp; +} + +static void list_inplace_merge(list_t *list, int left, int last, int mid, int compare(const void *a, const void *b)) { + int right = mid + 1; + + if (compare(&list->items[mid], &list->items[right]) <= 0) { + return; + } + + while (left <= mid && right <= last) { + if (compare(&list->items[left], &list->items[right]) <= 0) { + left++; + } else { + list_rotate(list, left, right); + left++; + mid++; + right++; + } + } +} + +static void list_inplace_sort(list_t *list, int first, int last, int compare(const void *a, const void *b)) { + if (first >= last) { + return; + } else if ((last - first) == 1) { + if (compare(&list->items[first], &list->items[last]) > 0) { + list_swap(list, first, last); + } + } else { + int mid = (int)((last + first) / 2); + list_inplace_sort(list, first, mid, compare); + list_inplace_sort(list, mid + 1, last, compare); + list_inplace_merge(list, first, last, mid, compare); + } +} + +void list_stable_sort(list_t *list, int compare(const void *a, const void *b)) { + if (list->length > 1) { + list_inplace_sort(list, 0, list->length - 1, compare); + } +} diff --git a/include/list.h b/include/list.h index b2e26f958..f478b6bb8 100644 --- a/include/list.h +++ b/include/list.h @@ -20,5 +20,6 @@ void list_qsort(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); - +// stable sort since qsort is not guaranteed to be stable +void list_stable_sort(list_t *list, int compare(const void *a, const void *b)); #endif diff --git a/include/output.h b/include/output.h index 12bc478f1..10c5bb533 100644 --- a/include/output.h +++ b/include/output.h @@ -16,7 +16,7 @@ void get_absolute_position(swayc_t *container, struct wlc_point *point); // given wlc_point. void get_absolute_center_position(swayc_t *container, struct wlc_point *point); -int sort_workspace_cmp_qsort(const void *a, const void *b); +// stable sort workspaces on this output void sort_workspaces(swayc_t *output); #endif diff --git a/sway/output.c b/sway/output.c index 53b242324..d56a2f308 100644 --- a/sway/output.c +++ b/sway/output.c @@ -3,6 +3,7 @@ #include #include "output.h" #include "log.h" +#include "list.h" swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos) { if (strcasecmp(name, "left") == 0) { @@ -180,7 +181,7 @@ void get_absolute_center_position(swayc_t *container, struct wlc_point *point) { point->y += container->height/2; } -int sort_workspace_cmp_qsort(const void *_a, const void *_b) { +static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { swayc_t *a = *(void **)_a; swayc_t *b = *(void **)_b; int retval = 0; @@ -199,5 +200,5 @@ int sort_workspace_cmp_qsort(const void *_a, const void *_b) { } void sort_workspaces(swayc_t *output) { - list_qsort(output->children, sort_workspace_cmp_qsort); + list_stable_sort(output->children, sort_workspace_cmp_qsort); }