diff --git a/gtk/gtkmultisorter.c b/gtk/gtkmultisorter.c index 6d1f2120b0..d25753c6e1 100644 --- a/gtk/gtkmultisorter.c +++ b/gtk/gtkmultisorter.c @@ -23,6 +23,7 @@ #include "gtkbuildable.h" #include "gtkintl.h" +#include "gtksorterprivate.h" #include "gtktypebuiltins.h" #define GDK_ARRAY_TYPE_NAME GtkSorters @@ -48,6 +49,141 @@ struct _GtkMultiSorter GtkSorters sorters; }; +typedef struct _GtkMultiSortKey GtkMultiSortKey; +typedef struct _GtkMultiSortKeys GtkMultiSortKeys; + +struct _GtkMultiSortKey +{ + gsize offset; + GtkSortKeys *keys; +}; + +struct _GtkMultiSortKeys +{ + GtkSortKeys parent_keys; + + guint n_keys; + GtkMultiSortKey keys[]; +}; + +static void +gtk_multi_sort_keys_free (GtkSortKeys *keys) +{ + GtkMultiSortKeys *self = (GtkMultiSortKeys *) keys; + gsize i; + + for (i = 0; i < self->n_keys; i++) + gtk_sort_keys_unref (self->keys[i].keys); + + g_slice_free1 (sizeof (GtkMultiSortKeys) + self->n_keys * sizeof (GtkMultiSortKey), self); +} + +static int +gtk_multi_sort_keys_compare (gconstpointer a, + gconstpointer b, + gpointer data) +{ + GtkMultiSortKeys *self = (GtkMultiSortKeys *) data; + gsize i; + + for (i = 0; i < self->n_keys; i++) + { + GtkOrdering result = gtk_sort_keys_compare (self->keys[i].keys, + ((const char *) a) + self->keys[i].offset, + ((const char *) b) + self->keys[i].offset); + if (result != GTK_ORDERING_EQUAL) + return result; + } + + return GTK_ORDERING_EQUAL; +} + +static gboolean +gtk_multi_sort_keys_is_compatible (GtkSortKeys *keys, + GtkSortKeys *other) +{ + GtkMultiSortKeys *self = (GtkMultiSortKeys *) keys; + GtkMultiSortKeys *compare = (GtkMultiSortKeys *) other; + gsize i; + + if (keys->klass != other->klass) + return FALSE; + + if (self->n_keys != compare->n_keys) + return FALSE; + + for (i = 0; i < self->n_keys; i++) + { + if (!gtk_sort_keys_is_compatible (self->keys[i].keys, compare->keys[i].keys)) + return FALSE; + } + + return TRUE; +} + +static void +gtk_multi_sort_keys_init_key (GtkSortKeys *keys, + gpointer item, + gpointer key_memory) +{ + GtkMultiSortKeys *self = (GtkMultiSortKeys *) keys; + char *key = (char *) key_memory; + gsize i; + + for (i = 0; i < self->n_keys; i++) + gtk_sort_keys_init_key (self->keys[i].keys, item, key + self->keys[i].offset); +} + +static void +gtk_multi_sort_keys_clear_key (GtkSortKeys *keys, + gpointer key_memory) +{ + GtkMultiSortKeys *self = (GtkMultiSortKeys *) keys; + char *key = (char *) key_memory; + gsize i; + + for (i = 0; i < self->n_keys; i++) + gtk_sort_keys_clear_key (self->keys[i].keys, key + self->keys[i].offset); +} + +static const GtkSortKeysClass GTK_MULTI_SORT_KEYS_CLASS = +{ + gtk_multi_sort_keys_free, + gtk_multi_sort_keys_compare, + gtk_multi_sort_keys_is_compatible, + gtk_multi_sort_keys_init_key, + gtk_multi_sort_keys_clear_key, +}; + +static GtkSortKeys * +gtk_multi_sort_keys_new (GtkMultiSorter *self) +{ + GtkMultiSortKeys *result; + GtkSortKeys *keys; + gsize i; + + if (gtk_sorters_get_size (&self->sorters) == 0) + return gtk_sort_keys_new_equal (); + else if (gtk_sorters_get_size (&self->sorters) == 1) + return gtk_sorter_get_keys (gtk_sorters_get (&self->sorters, 0)); + + keys = gtk_sort_keys_alloc (>K_MULTI_SORT_KEYS_CLASS, + sizeof (GtkMultiSortKeys) + gtk_sorters_get_size (&self->sorters) * sizeof (GtkMultiSortKey), + 0, 1); + result = (GtkMultiSortKeys *) keys; + + result->n_keys = gtk_sorters_get_size (&self->sorters); + for (i = 0; i < result->n_keys; i++) + { + result->keys[i].keys = gtk_sorter_get_keys (gtk_sorters_get (&self->sorters, i)); + result->keys[i].offset = GTK_SORT_KEYS_ALIGN (keys->key_size, gtk_sort_keys_get_key_align (result->keys[i].keys)); + keys->key_size = result->keys[i].offset + gtk_sort_keys_get_key_size (result->keys[i].keys); + keys->key_align = MAX (keys->key_align, gtk_sort_keys_get_key_align (result->keys[i].keys)); + } + + return keys; +} + static GType gtk_multi_sorter_get_item_type (GListModel *list) { @@ -186,7 +322,9 @@ gtk_multi_sorter_changed_cb (GtkSorter *sorter, g_assert_not_reached (); change = GTK_SORTER_CHANGE_DIFFERENT; } - gtk_sorter_changed (GTK_SORTER (self), change); + gtk_sorter_changed_with_keys (GTK_SORTER (self), + change, + gtk_multi_sort_keys_new (self)); } static void @@ -221,6 +359,10 @@ static void gtk_multi_sorter_init (GtkMultiSorter *self) { gtk_sorters_init (&self->sorters); + + gtk_sorter_changed_with_keys (GTK_SORTER (self), + GTK_SORTER_CHANGE_DIFFERENT, + gtk_multi_sort_keys_new (self)); } /** @@ -260,7 +402,9 @@ gtk_multi_sorter_append (GtkMultiSorter *self, g_signal_connect (sorter, "changed", G_CALLBACK (gtk_multi_sorter_changed_cb), self); gtk_sorters_append (&self->sorters, sorter); - gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_MORE_STRICT); + gtk_sorter_changed_with_keys (GTK_SORTER (self), + GTK_SORTER_CHANGE_MORE_STRICT, + gtk_multi_sort_keys_new (self)); } /** @@ -290,6 +434,8 @@ gtk_multi_sorter_remove (GtkMultiSorter *self, g_signal_handlers_disconnect_by_func (sorter, gtk_multi_sorter_changed_cb, self); gtk_sorters_splice (&self->sorters, position, 1, NULL, 0); - gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_LESS_STRICT); + gtk_sorter_changed_with_keys (GTK_SORTER (self), + GTK_SORTER_CHANGE_LESS_STRICT, + gtk_multi_sort_keys_new (self)); } diff --git a/gtk/gtksortlistmodel.c b/gtk/gtksortlistmodel.c index ee0c7f785f..3b3e402191 100644 --- a/gtk/gtksortlistmodel.c +++ b/gtk/gtksortlistmodel.c @@ -371,7 +371,7 @@ gtk_sort_list_model_create_keys (GtkSortListModel *self) g_assert (self->key_size == 0); self->sort_keys = gtk_sorter_get_keys (self->sorter); - self->key_size = self->sort_keys->key_size; + self->key_size = gtk_sort_keys_get_key_size (self->sort_keys); self->keys = g_malloc_n (self->n_items, self->key_size); for (i = 0; i < self->n_items; i++) {