[gtk/wip/otte/listview] gtk: Add GtkMultiSelection



commit 18d7a7daaa80af845d8e0b7de7e5fa9f3f366e75
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Jan 5 01:32:53 2019 -0500

    gtk: Add GtkMultiSelection
    
    This is a selection modelt that allows selecting
    more than one item.
    
    The behavior is not 100% right yet for extending
    selections, but it basically works.

 gtk/gtk.h                |   1 +
 gtk/gtklistitemmanager.c |   4 +-
 gtk/gtklistview.c        |   3 +-
 gtk/gtkmultiselection.c  | 329 +++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkmultiselection.h  |  37 ++++++
 gtk/gtkselectionmodel.c  |   8 +-
 gtk/gtkselectionmodel.h  |   6 +-
 gtk/gtkset.c             | 229 +++++++++++++++++++++++++++++++++
 gtk/gtkset.h             |  49 +++++++
 gtk/gtksingleselection.c |   3 +-
 gtk/meson.build          |   2 +
 11 files changed, 662 insertions(+), 9 deletions(-)
---
diff --git a/gtk/gtk.h b/gtk/gtk.h
index bcd144a780..35426397c0 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -157,6 +157,7 @@
 #include <gtk/gtkmessagedialog.h>
 #include <gtk/gtkmodelbutton.h>
 #include <gtk/gtkmountoperation.h>
+#include <gtk/gtkmultiselection.h>
 #include <gtk/gtknativedialog.h>
 #include <gtk/gtknotebook.h>
 #include <gtk/gtkorientable.h>
diff --git a/gtk/gtklistitemmanager.c b/gtk/gtklistitemmanager.c
index 9d8fbbc85a..ef5298a1ca 100644
--- a/gtk/gtklistitemmanager.c
+++ b/gtk/gtklistitemmanager.c
@@ -143,11 +143,11 @@ gtk_list_item_manager_select (GtkListItemManager *self,
       if (gtk_list_item_get_selected (item))
         gtk_selection_model_unselect_item (self->model, pos);
       else
-        gtk_selection_model_select_item (self->model, pos, FALSE);
+        gtk_selection_model_select_item (self->model, pos, FALSE, extend);
     }
   else
     {
-      gtk_selection_model_select_item (self->model, pos, TRUE);
+      gtk_selection_model_select_item (self->model, pos, TRUE, extend);
     }
 }
 
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index f45068f799..f21ce89249 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -29,6 +29,7 @@
 #include "gtkscrollable.h"
 #include "gtkselectionmodel.h"
 #include "gtksingleselection.h"
+#include "gtkmultiselection.h"
 #include "gtksnapshot.h"
 #include "gtkwidgetprivate.h"
 
@@ -1361,7 +1362,7 @@ gtk_list_view_set_model (GtkListView *self,
       if (GTK_IS_SELECTION_MODEL (model))
         selection_model = GTK_SELECTION_MODEL (g_object_ref (model));
       else
-        selection_model = GTK_SELECTION_MODEL (gtk_single_selection_new (model));
+        selection_model = GTK_SELECTION_MODEL (gtk_multi_selection_new (model));
 
       gtk_list_item_manager_set_model (self->item_manager, selection_model);
 
diff --git a/gtk/gtkmultiselection.c b/gtk/gtkmultiselection.c
new file mode 100644
index 0000000000..5b085a248a
--- /dev/null
+++ b/gtk/gtkmultiselection.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gtkmultiselection.h"
+
+#include "gtkintl.h"
+#include "gtkselectionmodel.h"
+#include "gtksingleselection.h"
+#include "gtkset.h"
+
+/**
+ * SECTION:gtkmultiselection
+ * @Short_description: A selection model that allows selecting a multiple items
+ * @Title: GtkMultiSelection
+ * @see_also: #GtkSelectionModel
+ *
+ * GtkMultiSelection is an implementation of the #GtkSelectionModel interface 
+ * that allows selecting multiple elements.
+ */
+
+struct _GtkMultiSelection
+{
+  GObject parent_instance;
+
+  GListModel *model;
+
+  GtkSet *selected;
+  guint last_selected;
+};
+
+struct _GtkMultiSelectionClass
+{
+  GObjectClass parent_class;
+};
+
+enum {
+  PROP_0,
+  PROP_MODEL,
+
+  N_PROPS,
+};
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static GType
+gtk_multi_selection_get_item_type (GListModel *list)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
+
+  return g_list_model_get_item_type (self->model);
+}
+
+static guint
+gtk_multi_selection_get_n_items (GListModel *list)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
+
+  return g_list_model_get_n_items (self->model);
+}
+
+static gpointer
+gtk_multi_selection_get_item (GListModel *list,
+                              guint       position)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
+
+  return g_list_model_get_item (self->model, position);
+}
+
+static void
+gtk_multi_selection_list_model_init (GListModelInterface *iface)
+{
+  iface->get_item_type = gtk_multi_selection_get_item_type;
+  iface->get_n_items = gtk_multi_selection_get_n_items;
+  iface->get_item = gtk_multi_selection_get_item;
+}
+
+static gboolean
+gtk_multi_selection_is_selected (GtkSelectionModel *model,
+                                 guint              position)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
+
+  return gtk_set_contains (self->selected, position);
+}
+
+static gboolean
+gtk_multi_selection_select_range (GtkSelectionModel *model,
+                                  guint              position,
+                                  guint              n_items,
+                                  gboolean           exclusive)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
+
+  if (exclusive)
+    gtk_set_remove_all (self->selected);
+  gtk_set_add_range (self->selected, position, n_items);
+  gtk_selection_model_selection_changed (model, position, n_items);
+
+  return TRUE;
+}
+
+static gboolean
+gtk_multi_selection_unselect_range (GtkSelectionModel *model,
+                                    guint              position,
+                                    guint              n_items)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
+
+  gtk_set_remove_range (self->selected, position, n_items);
+  gtk_selection_model_selection_changed (model, position, n_items);
+
+  return TRUE;
+}
+
+static gboolean
+gtk_multi_selection_select_item (GtkSelectionModel *model,
+                                 guint              position,
+                                 gboolean           exclusive,
+                                 gboolean           extend)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
+  guint pos, n_items;
+
+  if (extend && self->last_selected != GTK_INVALID_LIST_POSITION)
+    {
+      pos = MIN (position, self->last_selected);
+      n_items = MAX (position, self->last_selected) - pos + 1;
+    }
+  else
+    {
+      pos = position;
+      n_items = 1;
+    }
+
+  self->last_selected = position;
+  return gtk_multi_selection_select_range (model, pos, n_items, exclusive);
+}
+
+static gboolean
+gtk_multi_selection_unselect_item (GtkSelectionModel *model,
+                                   guint              position)
+{
+  return gtk_multi_selection_unselect_range (model, position, 1);
+}
+
+static gboolean
+gtk_multi_selection_select_all (GtkSelectionModel *model)
+{
+  return gtk_multi_selection_select_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)), FALSE);
+}
+
+static gboolean
+gtk_multi_selection_unselect_all (GtkSelectionModel *model)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
+  self->last_selected = GTK_INVALID_LIST_POSITION;
+  return gtk_multi_selection_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
+}
+
+
+static void
+gtk_multi_selection_selection_model_init (GtkSelectionModelInterface *iface)
+{
+  iface->is_selected = gtk_multi_selection_is_selected; 
+  iface->select_item = gtk_multi_selection_select_item; 
+  iface->unselect_item = gtk_multi_selection_unselect_item; 
+  iface->select_range = gtk_multi_selection_select_range; 
+  iface->unselect_range = gtk_multi_selection_unselect_range; 
+  iface->select_all = gtk_multi_selection_select_all; 
+  iface->unselect_all = gtk_multi_selection_unselect_all; 
+}
+
+G_DEFINE_TYPE_EXTENDED (GtkMultiSelection, gtk_multi_selection, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
+                                               gtk_multi_selection_list_model_init)
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_SELECTION_MODEL,
+                                               gtk_multi_selection_selection_model_init))
+
+static void
+gtk_multi_selection_items_changed_cb (GListModel        *model,
+                                      guint              position,
+                                      guint              removed,
+                                      guint              added,
+                                      GtkMultiSelection *self)
+{
+  gtk_set_remove_range (self->selected, position, removed);
+  gtk_set_shift (self->selected, position, (int)added - (int)removed);
+  g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
+}
+
+static void
+gtk_multi_selection_clear_model (GtkMultiSelection *self)
+{
+  if (self->model == NULL)
+    return;
+
+  g_signal_handlers_disconnect_by_func (self->model, 
+                                        gtk_multi_selection_items_changed_cb,
+                                        self);
+  g_clear_object (&self->model);
+}
+
+static void
+gtk_multi_selection_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_MODEL:
+      self->model = g_value_dup_object (value);
+      g_warn_if_fail (self->model != NULL);
+      g_signal_connect (self->model,
+                        "items-changed",
+                        G_CALLBACK (gtk_multi_selection_items_changed_cb),
+                        self);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_multi_selection_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_MODEL:
+      g_value_set_object (value, self->model);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_multi_selection_dispose (GObject *object)
+{
+  GtkMultiSelection *self = GTK_MULTI_SELECTION (object);
+
+  gtk_multi_selection_clear_model (self);
+
+  g_clear_pointer (&self->selected, gtk_set_free);
+  self->last_selected = GTK_INVALID_LIST_POSITION;
+
+  G_OBJECT_CLASS (gtk_multi_selection_parent_class)->dispose (object);
+}
+
+static void
+gtk_multi_selection_class_init (GtkMultiSelectionClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->get_property = gtk_multi_selection_get_property;
+  gobject_class->set_property = gtk_multi_selection_set_property;
+  gobject_class->dispose = gtk_multi_selection_dispose;
+
+  /**
+   * GtkMultiSelection:model
+   *
+   * The list managed by this selection
+   */
+  properties[PROP_MODEL] =
+    g_param_spec_object ("model",
+                         P_("Model"),
+                         P_("List managed by this selection"),
+                         G_TYPE_LIST_MODEL,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, properties);
+}
+
+static void
+gtk_multi_selection_init (GtkMultiSelection *self)
+{
+  self->selected = gtk_set_new ();
+  self->last_selected = GTK_INVALID_LIST_POSITION;
+}
+
+/**
+ * gtk_multi_selection_new:
+ * @model: (transfer none): the #GListModel to manage
+ *
+ * Creates a new selection to handle @model.
+ *
+ * Returns: (transfer full) (type GtkMultiSelection): a new #GtkMultiSelection
+ **/
+GListModel *
+gtk_multi_selection_new (GListModel *model)
+{
+  g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
+
+  return g_object_new (GTK_TYPE_MULTI_SELECTION,
+                       "model", model,
+                       NULL);
+}
+
diff --git a/gtk/gtkmultiselection.h b/gtk/gtkmultiselection.h
new file mode 100644
index 0000000000..cca0dc62d2
--- /dev/null
+++ b/gtk/gtkmultiselection.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GTK_MULTI_SELECTION_H__
+#define __GTK_MULTI_SELECTION_H__
+
+#include <gtk/gtktypes.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_MULTI_SELECTION (gtk_multi_selection_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkMultiSelection, gtk_multi_selection, GTK, MULTI_SELECTION, GObject)
+
+GDK_AVAILABLE_IN_ALL
+GListModel *    gtk_multi_selection_new                (GListModel           *model);
+
+G_END_DECLS
+
+#endif /* __GTK_MULTI_SELECTION_H__ */
diff --git a/gtk/gtkselectionmodel.c b/gtk/gtkselectionmodel.c
index 7075402e11..2e026984f1 100644
--- a/gtk/gtkselectionmodel.c
+++ b/gtk/gtkselectionmodel.c
@@ -79,7 +79,8 @@ gtk_selection_model_default_is_selected (GtkSelectionModel *model,
 static gboolean
 gtk_selection_model_default_select_item (GtkSelectionModel *model,
                                          guint              position,
-                                         gboolean           exclusive)
+                                         gboolean           exclusive,
+                                         gboolean           extend)
 {
   return FALSE;
 }
@@ -181,14 +182,15 @@ gtk_selection_model_is_selected (GtkSelectionModel *model,
 gboolean
 gtk_selection_model_select_item (GtkSelectionModel *model,
                                  guint              position,
-                                 gboolean           exclusive)
+                                 gboolean           exclusive,
+                                 gboolean           extend)
 {
   GtkSelectionModelInterface *iface;
 
   g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0);
 
   iface = GTK_SELECTION_MODEL_GET_IFACE (model);
-  return iface->select_item (model, position, exclusive);
+  return iface->select_item (model, position, exclusive, extend);
 }
 
 gboolean
diff --git a/gtk/gtkselectionmodel.h b/gtk/gtkselectionmodel.h
index 9904888d82..f4e5a1eca5 100644
--- a/gtk/gtkselectionmodel.h
+++ b/gtk/gtkselectionmodel.h
@@ -67,7 +67,8 @@ struct _GtkSelectionModelInterface
 
   gboolean              (* select_item)                         (GtkSelectionModel      *model,
                                                                  guint                   position,
-                                                                 gboolean                exclusive);
+                                                                 gboolean                exclusive,
+                                                                 gboolean                extend);
   gboolean              (* unselect_item)                       (GtkSelectionModel      *model,
                                                                  guint                   position);
   gboolean              (* select_range)                        (GtkSelectionModel      *model,
@@ -88,7 +89,8 @@ gboolean                gtk_selection_model_is_selected         (GtkSelectionMod
 GDK_AVAILABLE_IN_ALL
 gboolean                gtk_selection_model_select_item         (GtkSelectionModel      *model,
                                                                  guint                   position,
-                                                                 gboolean                exclusive);
+                                                                 gboolean                exclusive,
+                                                                 gboolean                extend);
 GDK_AVAILABLE_IN_ALL
 gboolean                gtk_selection_model_unselect_item       (GtkSelectionModel      *model,
                                                                  guint                   position);
diff --git a/gtk/gtkset.c b/gtk/gtkset.c
new file mode 100644
index 0000000000..0c2dfffb11
--- /dev/null
+++ b/gtk/gtkset.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "gtkset.h"
+
+/* Store a set of unsigned integers as a sorted array of ranges.
+ */
+
+typedef struct
+{
+  guint first;
+  guint n_items;
+} Range;
+
+struct _GtkSet
+{
+  GArray *ranges;
+};
+
+GtkSet *
+gtk_set_new (void)
+{
+  GtkSet *set;
+
+  set = g_new (GtkSet, 1);
+  set->ranges = g_array_new (FALSE, FALSE, sizeof (Range));
+ 
+  return set;
+}
+
+void
+gtk_set_free (GtkSet *set)
+{
+  g_array_free (set->ranges, TRUE);
+  g_free (set);
+}
+
+gboolean
+gtk_set_contains (GtkSet   *set,
+                  guint     item)
+{
+  int i;
+
+  for (i = 0; i < set->ranges->len; i++)
+    {
+      Range *r = &g_array_index (set->ranges, Range, i);
+
+      if (item < r->first)
+        return FALSE;
+
+      if (item < r->first + r->n_items)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+void
+gtk_set_remove_all (GtkSet *set)
+{
+  g_array_set_size (set->ranges, 0);
+}
+
+static int
+range_compare (Range *r, Range *s)
+{
+  int ret = 0;
+
+  if (r->first + r->n_items < s->first)
+    ret = -1;
+  else if (s->first + s->n_items < r->first)
+    ret = 1;
+
+  return ret;
+}
+
+void
+gtk_set_add_range (GtkSet   *set,
+                   guint     first_item,
+                   guint     n_items)
+{
+  int i;
+  Range s;
+  int first = -1;
+  int last = -1;
+
+  s.first = first_item;
+  s.n_items = n_items;
+
+  for (i = 0; i < set->ranges->len; i++)
+    {
+      Range *r = &g_array_index (set->ranges, Range, i);
+      int cmp = range_compare (&s, r);
+
+      if (cmp < 0)
+        break;
+
+      if (cmp == 0)
+        {
+          if (first < 0)
+            first = i;
+          last = i;
+        }
+    }
+
+  if (first > -1)
+    {
+      Range *r;
+      guint start;
+      guint end;
+
+      r = &g_array_index (set->ranges, Range, first);
+      start = MIN (s.first, r->first);
+
+      r = &g_array_index (set->ranges, Range, last);
+      end = MAX (s.first + s.n_items - 1, r->first + r->n_items - 1);
+
+      s.first = start;
+      s.n_items = end - start + 1;
+
+      g_array_remove_range (set->ranges, first, last - first + 1);
+      g_array_insert_val (set->ranges, first, s);
+    }
+  else
+    g_array_insert_val (set->ranges, i, s);
+}
+
+void
+gtk_set_remove_range (GtkSet *set,
+                      guint   first_item,
+                      guint   n_items)
+{
+  Range s;
+  int i;
+  int first = -1;
+  int last = -1;
+
+  s.first = first_item;
+  s.n_items = n_items;
+
+  for (i = 0; i < set->ranges->len; i++)
+    {
+      Range *r = &g_array_index (set->ranges, Range, i);
+      int cmp = range_compare (&s, r);
+
+      if (cmp < 0)
+        {
+          if (first > -1)
+            {
+              Range a[2];
+              int k = 0;
+
+              r = &g_array_index (set->ranges, Range, first);
+              if (r->first < s.first)
+                {
+                  a[k].first = r->first;
+                  a[k].n_items = s.first - r->first;
+                  k++;
+                }
+              r = &g_array_index (set->ranges, Range, last);
+              if (r->first + r->n_items > s.first + s.n_items)
+                {
+                  a[k].first = s.first + s.n_items;
+                  a[k].n_items = r->first + r->n_items - a[k].first;
+                  k++;
+                }
+              g_array_remove_range (set->ranges, first, last - first + 1);
+              if (k > 0)
+                g_array_insert_vals (set->ranges, first, a, k);
+            }
+        }
+
+      if (cmp == 0)
+        {
+          if (first < 0)
+            first = i;
+          last = i;
+        }
+    }
+}
+
+void
+gtk_set_add_item (GtkSet *set,
+                  guint   item)
+{
+  gtk_set_add_range (set, item, 1);
+}
+
+void
+gtk_set_remove_item (GtkSet   *set,
+                     guint     item)
+{
+  gtk_set_remove_range (set, item, 1);
+}
+
+/* This is peculiar operation: Replace every number n >= first by n + shift
+ * This is only supported for negatie if the shifting does not cause any
+ * ranges to overlap.
+ */
+void
+gtk_set_shift (GtkSet *set,
+               guint first,
+               int shift)
+{
+  int i;
+
+  for (i = 0; i < set->ranges->len; i++)
+    {
+      Range *r = &g_array_index (set->ranges, Range, i);
+      if (r->first >= first)
+        r->first += shift;
+    }
+}
diff --git a/gtk/gtkset.h b/gtk/gtkset.h
new file mode 100644
index 0000000000..c8573d1d43
--- /dev/null
+++ b/gtk/gtkset.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GTK_SET_H__
+#define __GTK_SET_H__
+
+#include <glib.h>
+
+typedef struct _GtkSet GtkSet;
+
+GtkSet   *gtk_set_new          (void);
+void      gtk_set_free         (GtkSet   *set);
+
+gboolean  gtk_set_contains     (GtkSet   *set,
+                                guint     item);
+
+void      gtk_set_remove_all   (GtkSet   *set);
+void      gtk_set_add_item     (GtkSet   *set,
+                                guint     item);
+void      gtk_set_remove_item  (GtkSet   *set,
+                                guint     item);
+void      gtk_set_add_range    (GtkSet   *set,
+                                guint     first,
+                                guint     n);
+void      gtk_set_remove_range (GtkSet   *set,
+                                guint     first,
+                                guint     n);
+
+void      gtk_set_shift        (GtkSet   *set,
+                                guint     first,
+                                int       shift);
+
+#endif  /* __GTK_SET_H__ */
diff --git a/gtk/gtksingleselection.c b/gtk/gtksingleselection.c
index b6ec5d7266..99ef1d9576 100644
--- a/gtk/gtksingleselection.c
+++ b/gtk/gtksingleselection.c
@@ -108,7 +108,8 @@ gtk_single_selection_is_selected (GtkSelectionModel *model,
 static gboolean
 gtk_single_selection_select_item (GtkSelectionModel *model,
                                   guint              position,
-                                  gboolean           exclusive)
+                                  gboolean           exclusive,
+                                  gboolean           extend)
 {
   GtkSingleSelection *self = GTK_SINGLE_SELECTION (model);
 
diff --git a/gtk/meson.build b/gtk/meson.build
index f10346e426..9d0dbbea38 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -137,6 +137,7 @@ gtk_private_sources = files([
   'gtksearchengine.c',
   'gtksearchenginemodel.c',
   'gtksearchenginesimple.c',
+  'gtkset.c',
   'gtksizerequestcache.c',
   'gtkstyleanimation.c',
   'gtkstylecascade.c',
@@ -289,6 +290,7 @@ gtk_public_sources = files([
   'gtkmodelmenuitem.c',
   'gtkmodules.c',
   'gtkmountoperation.c',
+  'gtkmultiselection.c',
   'gtknativedialog.c',
   'gtknomediafile.c',
   'gtknotebook.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]