On Thu, Oct 11, 2001 at 03:18:31PM -0500, Skip Montanaro wrote: > Havoc> It's actually a bit overcomplex for many uses, .... However if > Havoc> you are just making a simple list, clist is fine. > > Which suggests to me that either clist shouldn't be deprecated or there > should be a simpler way to use treeview/treeselection/liststore to create > simple lists. For all the power of the treeview stuff, most of the time I > think people just need single-column lists.
It's not really that hard. The biggest missing piece is a pointer array collection that also exports a GtkTreeModel interface. For example, see the attached code. -- Victory to the Divine Mother!! http://sahajayoga.org
/* GLIB - Library of useful routines for C programming * Copyright (C) 2001 Joshua Nathaniel Pritikin * * 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 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* originally adapted from g_ptr_array */ #ifndef _G_PTRSET_H_ #define _G_PTRSET_H_ #include <glib-object.h> typedef struct _GPtrSetClass GPtrSetClass; typedef struct _GPtrSet GPtrSet; #define G_TYPE_PTR_SET (g_ptr_set_get_type()) #define G_PTR_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PTR_SET, GPtrSet)) #define G_IS_PTR_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PTR_SET)) #define G_PTR_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PTR_SET, GPtrSetClass)) #define G_PTR_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PTR_SET, GPtrSetClass)) #define G_IS_PTR_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PTR_SET)) struct _GPtrSetClass { GObjectClass parent_class; void (*delete_elem) (GPtrSet *set, gint index, gpointer data); void (*insert_elem) (GPtrSet *set, gint index); }; struct _GPtrSet { GObject parent_instance; gpointer * pdata; gint len; gint alloc; gconstpointer compare_data; GCompareDataFunc ptr_compare; GCompareDataFunc key_compare; GDestroyNotify destroy_func; guint is_refcounted : 1; }; #define g_ptr_set_at(set,index) ((set)->pdata)[(index)] #define g_ptr_set_len(set) ((set)->len) GType g_ptr_set_get_type (void); GPtrSet * g_ptr_set_new (GCompareDataFunc ptr_compare, gconstpointer compare_data); void g_ptr_set_set_key_compare (GPtrSet *set, GCompareDataFunc key_compare); void g_ptr_set_free (GPtrSet *set); gpointer g_ptr_set_remove_index (GPtrSet * set, gint index); gint g_ptr_set_add_index (GPtrSet * set, gint index, gpointer data); gboolean g_ptr_set_lookup (GPtrSet * set, gint * ret, gconstpointer sample); gboolean g_ptr_set_lookup_ptr (GPtrSet * fset, gint * ret, gconstpointer sample); gboolean g_ptr_set_lookup_key (GPtrSet * set, gint * ret, gconstpointer sample_key); gint g_ptr_set_add (GPtrSet * set, gpointer data); gboolean g_ptr_set_try_remove (GPtrSet * fset, gpointer data); void g_ptr_set_remove (GPtrSet * set, gpointer data); void g_ptr_set_remove_all (GPtrSet *ps); void g_ptr_set_sync_to_slist (GPtrSet *ps, GSList *target); #endif
/* GLIB - Library of useful routines for C programming * Copyright (C) 2001 Joshua Nathaniel Pritikin * * 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 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include <glib.h> #include <string.h> #include "gptrset.h" #include "appmarshal.h" enum { PROP_0, PROP_COMPARE_DATA, PROP_KEY_COMPARE, PROP_PTR_COMPARE, PROP_DESTROY_FUNC, PROP_IS_REFCOUNTED }; enum { DELETE_ELEM, INSERT_ELEM, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; #define MIN_SET_SIZE 16 static void g_ptr_set_maybe_expand (GPtrSet *set, gint len); static void g_ptr_set_verify_sort (GPtrSet *set) { if (!set->ptr_compare) return; if (set->len <= 1) return; for (gint xx=0; xx < set->len - 1; xx++) { if (set->ptr_compare (g_ptr_set_at (set, xx), g_ptr_set_at (set, xx + 1), (gpointer) set->compare_data) > 0) g_critical ("%d, %d are unsorted", xx, xx+1); } } static gint g_nearest_pow (gint num) { gint n = 1; while (n < num) n <<= 1; return n; } GPtrSet * g_ptr_set_new (GCompareDataFunc ptr_compare, gconstpointer compare_data) { GPtrSet *set; set = G_PTR_SET (g_object_new (g_ptr_set_get_type(), 0)); set->ptr_compare = ptr_compare; set->compare_data = compare_data; return set; } void g_ptr_set_set_key_compare (GPtrSet *set, GCompareDataFunc key_compare) { set->key_compare = key_compare; } static void g_ptr_set_init (GPtrSet *set) { /* zero fill is good */ } // g_ptr_set_maybe_shrink XXX static void g_ptr_set_maybe_expand (GPtrSet *set, gint len) { if ((set->len + len) > set->alloc) { #ifdef ENABLE_GC_FRIENDLY gint old_alloc = set->alloc; #endif /* ENABLE_GC_FRIENDLY */ set->alloc = g_nearest_pow (set->len + len); set->alloc = MAX (set->alloc, MIN_SET_SIZE); set->pdata = g_realloc (set->pdata, sizeof(gpointer) * set->alloc); #ifdef ENABLE_GC_FRIENDLY for ( ; old_alloc < set->alloc; old_alloc++) set->pdata [old_alloc] = NULL; #endif /* ENABLE_GC_FRIENDLY */ } } static gboolean _ptr_set_lookup (GPtrSet * fset, gint * ret, GCompareDataFunc compare, gconstpointer sample) { gint first, last; gint mid; gint midsize; gint cmp; gint tx; g_return_val_if_fail (compare, FALSE); if (!fset->len) { if (ret) *ret = 0; return FALSE; } first = 0; last = fset->len - 1; midsize = last - first; while (midsize > 1) { mid = first + midsize / 2; cmp = (*compare) (sample, g_ptr_set_at (fset, mid), (gpointer) fset->compare_data); if (cmp == 0) { // if there are multiple matches then scan for the first match while (mid > 0 && (*compare) (sample, g_ptr_set_at (fset, mid - 1), (gpointer) fset->compare_data) == 0) --mid; if (ret) *ret = mid; return TRUE; } if (cmp < 0) last = mid-1; else first = mid+1; midsize = last - first; } for (tx = first; tx <= last; tx++) { cmp = (*compare) (sample, g_ptr_set_at (fset, tx), (gpointer) fset->compare_data); if (cmp < 0) { if (ret) *ret = tx; return FALSE; } if (cmp == 0) { if (ret) *ret = tx; return TRUE; } } if (ret) *ret = last+1; return FALSE; } gboolean g_ptr_set_lookup (GPtrSet * fset, gint * ret, gconstpointer sample) { g_return_val_if_fail (fset, FALSE); return _ptr_set_lookup (fset, ret, fset->ptr_compare, sample); } gboolean g_ptr_set_lookup_ptr (GPtrSet * fset, gint * ret, gconstpointer sample) { g_return_val_if_fail (fset, FALSE); gint at; if (!_ptr_set_lookup (fset, &at, fset->ptr_compare, sample)) return FALSE; // cope with non-unique sets of unique pointers while (g_ptr_set_at (fset, at) != sample) { if (at < fset->len - 1 && (*fset->ptr_compare) (sample, g_ptr_set_at (fset, at+1), (gpointer) fset->compare_data) == 0) { ++at; continue; } return FALSE; } if (ret) *ret = at; return TRUE; } gboolean g_ptr_set_lookup_key (GPtrSet * set, gint * ret, gconstpointer sample_key) { g_return_val_if_fail (set, FALSE); return _ptr_set_lookup (set, ret, set->key_compare, sample_key); } gpointer g_ptr_set_remove_index (GPtrSet* fset, gint index) { gpointer result; g_return_val_if_fail (fset, NULL); g_return_val_if_fail (0 <= index && index < fset->len, NULL); result = fset->pdata[index]; if (index != fset->len - 1) g_memmove (fset->pdata + index, fset->pdata + index + 1, sizeof (gpointer) * (fset->len - index - 1)); fset->len -= 1; #ifdef ENABLE_GC_FRIENDLY fset->pdata[fset->len] = NULL; #endif /* ENABLE_GC_FRIENDLY */ g_ptr_set_verify_sort (fset); g_signal_emit (fset, signals[DELETE_ELEM], 0, index, result); if (fset->destroy_func) (*fset->destroy_func) (result); if (fset->is_refcounted) g_object_unref (result); return result; } gboolean g_ptr_set_try_remove (GPtrSet* fset, gpointer data) { g_return_val_if_fail (fset, FALSE); g_return_val_if_fail (data, FALSE); // only remove first match gint at; if (!g_ptr_set_lookup_ptr (fset, &at, data)) return FALSE; gpointer removed = g_ptr_set_remove_index (fset, at); g_assert (data == removed); return TRUE; } void g_ptr_set_remove (GPtrSet* fset, gpointer data) { gboolean removed = g_ptr_set_try_remove (fset, data); g_assert (removed); } gint g_ptr_set_add_index (GPtrSet * set, gint index, gpointer data) { g_return_val_if_fail (set, -1); g_return_val_if_fail (0 <= index && index <= set->len, -1); if (set->is_refcounted) g_object_ref (data); g_ptr_set_maybe_expand ((GPtrSet*) set, 1); g_memmove (&g_ptr_set_at (set, 1 + index), &g_ptr_set_at (set, index), sizeof(gpointer) * (set->len - index)); g_ptr_set_at (set, index) = data; set->len += 1; g_ptr_set_verify_sort (set); g_signal_emit (set, signals[INSERT_ELEM], 0, index); return index; } gint g_ptr_set_add (GPtrSet * set, gpointer data) { gint at; g_return_val_if_fail (set, -1); g_return_val_if_fail (data, -1); if (g_ptr_set_lookup (set, &at, data)) ++at; // reduce memmove return g_ptr_set_add_index (set, at, data); } void g_ptr_set_remove_all (GPtrSet *ps) { g_return_if_fail (ps); gint old_len = ps->len; gpointer *pdata = ps->pdata; ps->alloc = 0; ps->pdata = NULL; ps->len = 0; // For this emission, we always use the zeroth index // because downstream handlers don't know what we're doing. // for (gint xx=0; xx < old_len; xx++) g_signal_emit (ps, signals[DELETE_ELEM], 0, 0, pdata[xx]); if (ps->destroy_func) for (gint xx=0; xx < old_len; xx++) (*ps->destroy_func) (pdata[xx]); if (ps->is_refcounted) for (gint xx=0; xx < old_len; xx++) g_object_unref (pdata[xx]); g_free (pdata); } // Do the minimum number of adds/removes. // void g_ptr_set_sync_to_slist (GPtrSet *ps, GSList *target) { gint xx=0; while (xx < g_ptr_set_len (ps)) { gpointer data = g_ptr_set_at (ps, xx); if (!g_slist_find (target, data)) g_ptr_set_remove (ps, data); else ++xx; } for (GSList *elem = target; elem; elem = g_slist_next (elem)) { gpointer data = elem->data; if (!g_ptr_set_lookup (ps, NULL, data)) g_ptr_set_add (ps, data); } } static void g_ptr_set_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GPtrSet *set = G_PTR_SET (object); g_return_if_fail (set->len == 0); switch (prop_id) { case PROP_COMPARE_DATA: set->compare_data = g_value_get_pointer (value); break; case PROP_KEY_COMPARE: set->key_compare = g_value_get_pointer (value); break; case PROP_PTR_COMPARE: set->ptr_compare = g_value_get_pointer (value); break; case PROP_DESTROY_FUNC: set->destroy_func = g_value_get_pointer (value); break; case PROP_IS_REFCOUNTED: set->is_refcounted = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void g_ptr_set_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GPtrSet *set = G_PTR_SET (object); switch (prop_id) { case PROP_COMPARE_DATA: g_value_set_pointer (value, (gpointer) set->compare_data); break; case PROP_KEY_COMPARE: g_value_set_pointer (value, set->key_compare); break; case PROP_PTR_COMPARE: g_value_set_pointer (value, set->ptr_compare); break; case PROP_DESTROY_FUNC: g_value_set_pointer (value, set->destroy_func); break; case PROP_IS_REFCOUNTED: g_value_set_boolean (value, set->is_refcounted); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObjectClass *parent_class; static void g_ptr_set_finalize (GObject *object) { GPtrSet *set; gint xx; g_return_if_fail (G_IS_PTR_SET (object)); set = G_PTR_SET (object); if (set->destroy_func) for (xx=0; xx < set->len; xx++) (* set->destroy_func) (g_ptr_set_at (set, xx)); if (set->is_refcounted) for (xx=0; xx < set->len; xx++) g_object_unref (g_ptr_set_at (set, xx)); g_free (set->pdata); set->pdata = NULL; (* G_OBJECT_CLASS(parent_class)->finalize) (object); } static void g_ptr_set_class_init(GPtrSetClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); parent_class = g_type_class_peek_parent (klass); object_class->set_property = g_ptr_set_set_property; object_class->get_property = g_ptr_set_get_property; object_class->finalize = g_ptr_set_finalize; g_object_class_install_property (object_class, PROP_COMPARE_DATA, g_param_spec_pointer ("compare-data", "", "", G_PARAM_READABLE|G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_KEY_COMPARE, g_param_spec_pointer ("key-compare", "", "GCompareDataFunc", G_PARAM_READABLE|G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_PTR_COMPARE, g_param_spec_pointer ("ptr-compare", "", "GCompareDataFunc", G_PARAM_READABLE|G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_DESTROY_FUNC, g_param_spec_pointer ("destroy-func", "", "GDestroyNotify", G_PARAM_READABLE|G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_IS_REFCOUNTED, g_param_spec_boolean ("is-refcounted", "", "Whether to do reference count the elements.", FALSE, G_PARAM_READABLE|G_PARAM_WRITABLE)); signals[DELETE_ELEM] = g_signal_new ("delete_elem", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, // ACTION? XXX G_STRUCT_OFFSET (GPtrSetClass, delete_elem), NULL, NULL, app_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER); signals[INSERT_ELEM] = g_signal_new ("insert_elem", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GPtrSetClass, insert_elem), NULL, NULL, app_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); } GType g_ptr_set_get_type (void) { static GType our_type = 0; if (our_type == 0) { static const GTypeInfo our_info = { sizeof(GPtrSetClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) g_ptr_set_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GPtrSet), 0, /* n_preallocs */ (GInstanceInitFunc) g_ptr_set_init, NULL }; our_type = g_type_register_static (G_TYPE_OBJECT, "GPtrSet", &our_info, 0); } return our_type; }
#include <gtk/gtk.h> #include "gptrset.h" #define APP_TYPE_LIST_STORE (app_list_store_get_type ()) #define APP_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), APP_TYPE_LIST_STORE, AppListStore)) #define APP_LIST_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), APP_TYPE_LIST_STORE, AppListStoreClass)) #define APP_IS_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), APP_TYPE_LIST_STORE)) #define APP_IS_LIST_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), APP_TYPE_LIST_STORE)) #define APP_LIST_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_TYPE_LIST_STORE, AppListStoreClass)) typedef struct _AppListStore AppListStore; typedef struct _AppListStoreClass AppListStoreClass; GType app_list_store_get_type (void); AppListStore *app_list_store_new (GCompareDataFunc ptr_compare, gconstpointer compare_data); struct _AppListStore { GPtrSet parent; gint stamp; }; struct _AppListStoreClass { GPtrSetClass parent_class; };
#include "appliststore.h" static gint _direct_ptr_compare (gpointer p1, gpointer p2) { if (p1==p2) return 0; else if (p1 < p2) return -1; else return 1; } AppListStore * app_list_store_new (GCompareDataFunc ptr_compare, gconstpointer compare_data) { AppListStore *ret; GPtrSet *ps; ret = APP_LIST_STORE (g_object_new (APP_TYPE_LIST_STORE, NULL)); ps = G_PTR_SET (ret); ps->ptr_compare = (ptr_compare? ptr_compare : (GCompareDataFunc) _direct_ptr_compare); ps->compare_data = compare_data; return ret; } static guint app_list_store_get_flags (GtkTreeModel *tree_model) { g_return_val_if_fail (APP_IS_LIST_STORE (tree_model), 0); return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY; } static gint app_list_store_get_n_columns (GtkTreeModel *tree_model) { g_return_val_if_fail (APP_IS_LIST_STORE (tree_model), 0); return 1; } static GType app_list_store_get_column_type (GtkTreeModel *tree_model, gint index) { g_return_val_if_fail (APP_IS_LIST_STORE (tree_model), G_TYPE_INVALID); g_return_val_if_fail (index == 0, G_TYPE_INVALID); return G_PTR_SET (tree_model)->is_refcounted? G_TYPE_OBJECT : G_TYPE_POINTER; } static gboolean app_list_store_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) { gint i; g_return_val_if_fail (APP_IS_LIST_STORE (tree_model), FALSE); g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE); i = gtk_tree_path_get_indices (path)[0]; if (i >= G_PTR_SET (tree_model)->len) return FALSE; iter->stamp = APP_LIST_STORE (tree_model)->stamp; iter->user_data = GINT_TO_POINTER (i); return TRUE; } static GtkTreePath * app_list_store_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter) { GtkTreePath *retval; g_return_val_if_fail (APP_IS_LIST_STORE (tree_model), NULL); g_return_val_if_fail (iter->stamp == APP_LIST_STORE (tree_model)->stamp, NULL); retval = gtk_tree_path_new (); gtk_tree_path_append_index (retval, GPOINTER_TO_INT (iter->user_data)); return retval; } static void app_list_store_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) { GPtrSet *ps; g_return_if_fail (APP_IS_LIST_STORE (tree_model)); g_return_if_fail (column < 1); g_return_if_fail (APP_LIST_STORE (tree_model)->stamp == iter->stamp); ps = G_PTR_SET (tree_model); if (ps->is_refcounted) { g_value_init (value, G_TYPE_OBJECT); g_value_set_object (value, g_ptr_set_at (ps, GPOINTER_TO_INT(iter->user_data))); } else { g_value_init (value, G_TYPE_POINTER); g_value_set_pointer (value, g_ptr_set_at (ps, GPOINTER_TO_INT(iter->user_data))); } } static gboolean app_list_store_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter) { gint at; g_return_val_if_fail (APP_IS_LIST_STORE (tree_model), FALSE); g_return_val_if_fail (APP_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE); at = GPOINTER_TO_INT (iter->user_data) + 1; iter->user_data = GINT_TO_POINTER (at); return at < G_PTR_SET(tree_model)->len; } static gboolean app_list_store_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { if (parent) return FALSE; if (G_PTR_SET (tree_model)->len) { iter->stamp = APP_LIST_STORE (tree_model)->stamp; iter->user_data = 0; return TRUE; } else return FALSE; } static gboolean app_list_store_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter) { return FALSE; } static gint app_list_store_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter) { g_return_val_if_fail (APP_IS_LIST_STORE (tree_model), -1); if (iter == NULL) return G_PTR_SET (tree_model)->len; g_return_val_if_fail (APP_LIST_STORE (tree_model)->stamp == iter->stamp, -1); return 0; } static gboolean app_list_store_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) { g_return_val_if_fail (APP_IS_LIST_STORE (tree_model), FALSE); if (parent) return FALSE; if (n <= G_PTR_SET(tree_model)->len) { iter->stamp = APP_LIST_STORE (tree_model)->stamp; iter->user_data = GINT_TO_POINTER (n); return TRUE; } else return FALSE; } static gboolean app_list_store_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) { return FALSE; } static void app_list_store_delete_elem (GPtrSet *ps, gint index, gpointer data) { AppListStore *list_store; GtkTreePath *path; list_store = APP_LIST_STORE (ps); ++list_store->stamp; path = gtk_tree_path_new (); gtk_tree_path_append_index (path, index); gtk_tree_model_row_deleted (GTK_TREE_MODEL (ps), path); gtk_tree_path_free (path); } static void app_list_store_insert_elem (GPtrSet *ps, gint index) { AppListStore *list_store; GtkTreePath *path; GtkTreeIter iter; list_store = APP_LIST_STORE (ps); ++list_store->stamp; iter.stamp = list_store->stamp; iter.user_data = GINT_TO_POINTER (index); path = gtk_tree_path_new (); gtk_tree_path_append_index (path, index); gtk_tree_model_row_inserted (GTK_TREE_MODEL (ps), path, &iter); gtk_tree_path_free (path); } static void app_list_store_init (AppListStore *list_store) { list_store->stamp = g_random_int (); } static void app_list_store_class_init (AppListStoreClass *klass) { GPtrSetClass *ps_class; ps_class = (GPtrSetClass*) klass; ps_class->delete_elem = app_list_store_delete_elem; ps_class->insert_elem = app_list_store_insert_elem; } static void app_list_store_tree_model_init (GtkTreeModelIface *iface) { iface->get_flags = app_list_store_get_flags; iface->get_n_columns = app_list_store_get_n_columns; iface->get_column_type = app_list_store_get_column_type; iface->get_iter = app_list_store_get_iter; iface->get_path = app_list_store_get_path; iface->get_value = app_list_store_get_value; iface->iter_next = app_list_store_iter_next; iface->iter_children = app_list_store_iter_children; iface->iter_has_child = app_list_store_iter_has_child; iface->iter_n_children = app_list_store_iter_n_children; iface->iter_nth_child = app_list_store_iter_nth_child; iface->iter_parent = app_list_store_iter_parent; } GType app_list_store_get_type (void) { static GType list_store_type = 0; if (!list_store_type) { static const GTypeInfo list_store_info = { sizeof (AppListStoreClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) app_list_store_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (AppListStore), 0, (GInstanceInitFunc) app_list_store_init, NULL }; static const GInterfaceInfo tree_model_info = { (GInterfaceInitFunc) app_list_store_tree_model_init, NULL, NULL }; list_store_type = g_type_register_static (G_TYPE_PTR_SET, "AppListStore", &list_store_info, 0); g_type_add_interface_static (list_store_type, GTK_TYPE_TREE_MODEL, &tree_model_info); } return list_store_type; }