1/* gtktreemodel.c
2 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19#include <stdlib.h>
20#include <string.h>
21#include <glib.h>
22#include <glib/gprintf.h>
23#include <gobject/gvaluecollector.h>
24#include "gtktreemodel.h"
25#include "gtktreeview.h"
26#include "gtktreeprivate.h"
27#include "gtkmarshalers.h"
28#include "gtkintl.h"
29
30/**
31 * GtkTreeModel:
32 *
33 * The tree interface used by GtkTreeView
34 *
35 * The `GtkTreeModel` interface defines a generic tree interface for
36 * use by the `GtkTreeView` widget. It is an abstract interface, and
37 * is designed to be usable with any appropriate data structure. The
38 * programmer just has to implement this interface on their own data
39 * type for it to be viewable by a `GtkTreeView` widget.
40 *
41 * The model is represented as a hierarchical tree of strongly-typed,
42 * columned data. In other words, the model can be seen as a tree where
43 * every node has different values depending on which column is being
44 * queried. The type of data found in a column is determined by using
45 * the GType system (ie. %G_TYPE_INT, %GTK_TYPE_BUTTON, %G_TYPE_POINTER,
46 * etc). The types are homogeneous per column across all nodes. It is
47 * important to note that this interface only provides a way of examining
48 * a model and observing changes. The implementation of each individual
49 * model decides how and if changes are made.
50 *
51 * In order to make life simpler for programmers who do not need to
52 * write their own specialized model, two generic models are provided
53 * — the `GtkTreeStore` and the `GtkListStore`. To use these, the
54 * developer simply pushes data into these models as necessary. These
55 * models provide the data structure as well as all appropriate tree
56 * interfaces. As a result, implementing drag and drop, sorting, and
57 * storing data is trivial. For the vast majority of trees and lists,
58 * these two models are sufficient.
59 *
60 * Models are accessed on a node/column level of granularity. One can
61 * query for the value of a model at a certain node and a certain
62 * column on that node. There are two structures used to reference a
63 * particular node in a model. They are the [struct@Gtk.TreePath] and
64 * the [struct@Gtk.TreeIter] (“iter” is short for iterator). Most of the
65 * interface consists of operations on a [struct@Gtk.TreeIter].
66 *
67 * A path is essentially a potential node. It is a location on a model
68 * that may or may not actually correspond to a node on a specific
69 * model. A [struct@Gtk.TreePath] can be converted into either an
70 * array of unsigned integers or a string. The string form is a list
71 * of numbers separated by a colon. Each number refers to the offset
72 * at that level. Thus, the path `0` refers to the root
73 * node and the path `2:4` refers to the fifth child of
74 * the third node.
75 *
76 * By contrast, a [struct@Gtk.TreeIter] is a reference to a specific node on
77 * a specific model. It is a generic struct with an integer and three
78 * generic pointers. These are filled in by the model in a model-specific
79 * way. One can convert a path to an iterator by calling
80 * gtk_tree_model_get_iter(). These iterators are the primary way
81 * of accessing a model and are similar to the iterators used by
82 * `GtkTextBuffer`. They are generally statically allocated on the
83 * stack and only used for a short time. The model interface defines
84 * a set of operations using them for navigating the model.
85 *
86 * It is expected that models fill in the iterator with private data.
87 * For example, the `GtkListStore` model, which is internally a simple
88 * linked list, stores a list node in one of the pointers. The
89 * `GtkTreeModel`Sort stores an array and an offset in two of the
90 * pointers. Additionally, there is an integer field. This field is
91 * generally filled with a unique stamp per model. This stamp is for
92 * catching errors resulting from using invalid iterators with a model.
93 *
94 * The lifecycle of an iterator can be a little confusing at first.
95 * Iterators are expected to always be valid for as long as the model
96 * is unchanged (and doesn’t emit a signal). The model is considered
97 * to own all outstanding iterators and nothing needs to be done to
98 * free them from the user’s point of view. Additionally, some models
99 * guarantee that an iterator is valid for as long as the node it refers
100 * to is valid (most notably the `GtkTreeStore` and `GtkListStore`).
101 * Although generally uninteresting, as one always has to allow for
102 * the case where iterators do not persist beyond a signal, some very
103 * important performance enhancements were made in the sort model.
104 * As a result, the %GTK_TREE_MODEL_ITERS_PERSIST flag was added to
105 * indicate this behavior.
106 *
107 * To help show some common operation of a model, some examples are
108 * provided. The first example shows three ways of getting the iter at
109 * the location `3:2:5`. While the first method shown is
110 * easier, the second is much more common, as you often get paths from
111 * callbacks.
112 *
113 * ## Acquiring a `GtkTreeIter`
114 *
115 * ```c
116 * // Three ways of getting the iter pointing to the location
117 * GtkTreePath *path;
118 * GtkTreeIter iter;
119 * GtkTreeIter parent_iter;
120 *
121 * // get the iterator from a string
122 * gtk_tree_model_get_iter_from_string (model,
123 * &iter,
124 * "3:2:5");
125 *
126 * // get the iterator from a path
127 * path = gtk_tree_path_new_from_string ("3:2:5");
128 * gtk_tree_model_get_iter (model, &iter, path);
129 * gtk_tree_path_free (path);
130 *
131 * // walk the tree to find the iterator
132 * gtk_tree_model_iter_nth_child (model, &iter,
133 * NULL, 3);
134 * parent_iter = iter;
135 * gtk_tree_model_iter_nth_child (model, &iter,
136 * &parent_iter, 2);
137 * parent_iter = iter;
138 * gtk_tree_model_iter_nth_child (model, &iter,
139 * &parent_iter, 5);
140 * ```
141 *
142 * This second example shows a quick way of iterating through a list
143 * and getting a string and an integer from each row. The
144 * populate_model() function used below is not
145 * shown, as it is specific to the `GtkListStore`. For information on
146 * how to write such a function, see the `GtkListStore` documentation.
147 *
148 * ## Reading data from a `GtkTreeModel`
149 *
150 * ```c
151 * enum
152 * {
153 * STRING_COLUMN,
154 * INT_COLUMN,
155 * N_COLUMNS
156 * };
157 *
158 * ...
159 *
160 * GtkTreeModel *list_store;
161 * GtkTreeIter iter;
162 * gboolean valid;
163 * int row_count = 0;
164 *
165 * // make a new list_store
166 * list_store = gtk_list_store_new (N_COLUMNS,
167 * G_TYPE_STRING,
168 * G_TYPE_INT);
169 *
170 * // Fill the list store with data
171 * populate_model (list_store);
172 *
173 * // Get the first iter in the list, check it is valid and walk
174 * // through the list, reading each row.
175 *
176 * valid = gtk_tree_model_get_iter_first (list_store,
177 * &iter);
178 * while (valid)
179 * {
180 * char *str_data;
181 * int int_data;
182 *
183 * // Make sure you terminate calls to gtk_tree_model_get() with a “-1” value
184 * gtk_tree_model_get (list_store, &iter,
185 * STRING_COLUMN, &str_data,
186 * INT_COLUMN, &int_data,
187 * -1);
188 *
189 * // Do something with the data
190 * g_print ("Row %d: (%s,%d)\n",
191 * row_count, str_data, int_data);
192 * g_free (str_data);
193 *
194 * valid = gtk_tree_model_iter_next (list_store,
195 * &iter);
196 * row_count++;
197 * }
198 * ```
199 *
200 * The `GtkTreeModel` interface contains two methods for reference
201 * counting: gtk_tree_model_ref_node() and gtk_tree_model_unref_node().
202 * These two methods are optional to implement. The reference counting
203 * is meant as a way for views to let models know when nodes are being
204 * displayed. `GtkTreeView` will take a reference on a node when it is
205 * visible, which means the node is either in the toplevel or expanded.
206 * Being displayed does not mean that the node is currently directly
207 * visible to the user in the viewport. Based on this reference counting
208 * scheme a caching model, for example, can decide whether or not to cache
209 * a node based on the reference count. A file-system based model would
210 * not want to keep the entire file hierarchy in memory, but just the
211 * folders that are currently expanded in every current view.
212 *
213 * When working with reference counting, the following rules must be taken
214 * into account:
215 *
216 * - Never take a reference on a node without owning a reference on its parent.
217 * This means that all parent nodes of a referenced node must be referenced
218 * as well.
219 *
220 * - Outstanding references on a deleted node are not released. This is not
221 * possible because the node has already been deleted by the time the
222 * row-deleted signal is received.
223 *
224 * - Models are not obligated to emit a signal on rows of which none of its
225 * siblings are referenced. To phrase this differently, signals are only
226 * required for levels in which nodes are referenced. For the root level
227 * however, signals must be emitted at all times (however the root level
228 * is always referenced when any view is attached).
229 */
230
231#define INITIALIZE_TREE_ITER(Iter) \
232 G_STMT_START{ \
233 (Iter)->stamp = 0; \
234 (Iter)->user_data = NULL; \
235 (Iter)->user_data2 = NULL; \
236 (Iter)->user_data3 = NULL; \
237 }G_STMT_END
238
239#define ROW_REF_DATA_STRING "gtk-tree-row-refs"
240
241enum {
242 ROW_CHANGED,
243 ROW_INSERTED,
244 ROW_HAS_CHILD_TOGGLED,
245 ROW_DELETED,
246 ROWS_REORDERED,
247 LAST_SIGNAL
248};
249
250static guint tree_model_signals[LAST_SIGNAL] = { 0 };
251
252/**
253 * GtkTreePath:
254 *
255 * An opaque structure representing a path to a row in a model.
256 */
257struct _GtkTreePath
258{
259 int depth; /* Number of elements */
260 int alloc; /* Number of allocated elements */
261 int *indices;
262};
263
264typedef struct
265{
266 GSList *list;
267} RowRefList;
268
269static void gtk_tree_model_base_init (gpointer g_class);
270
271/* custom closures */
272static void row_inserted_marshal (GClosure *closure,
273 GValue /* out */ *return_value,
274 guint n_param_value,
275 const GValue *param_values,
276 gpointer invocation_hint,
277 gpointer marshal_data);
278static void row_deleted_marshal (GClosure *closure,
279 GValue /* out */ *return_value,
280 guint n_param_value,
281 const GValue *param_values,
282 gpointer invocation_hint,
283 gpointer marshal_data);
284static void rows_reordered_marshal (GClosure *closure,
285 GValue /* out */ *return_value,
286 guint n_param_value,
287 const GValue *param_values,
288 gpointer invocation_hint,
289 gpointer marshal_data);
290
291static void gtk_tree_row_ref_inserted (RowRefList *refs,
292 GtkTreePath *path,
293 GtkTreeIter *iter);
294static void gtk_tree_row_ref_deleted (RowRefList *refs,
295 GtkTreePath *path);
296static void gtk_tree_row_ref_reordered (RowRefList *refs,
297 GtkTreePath *path,
298 GtkTreeIter *iter,
299 int *new_order);
300
301GType
302gtk_tree_model_get_type (void)
303{
304 static GType tree_model_type = 0;
305
306 if (! tree_model_type)
307 {
308 const GTypeInfo tree_model_info =
309 {
310 sizeof (GtkTreeModelIface), /* class_size */
311 gtk_tree_model_base_init, /* base_init */
312 NULL, /* base_finalize */
313 NULL,
314 NULL, /* class_finalize */
315 NULL, /* class_data */
316 0,
317 0, /* n_preallocs */
318 NULL
319 };
320
321 tree_model_type =
322 g_type_register_static (G_TYPE_INTERFACE, I_("GtkTreeModel"),
323 info: &tree_model_info, flags: 0);
324
325 g_type_interface_add_prerequisite (interface_type: tree_model_type, G_TYPE_OBJECT);
326 }
327
328 return tree_model_type;
329}
330
331static void
332gtk_tree_model_base_init (gpointer g_class)
333{
334 static gboolean initialized = FALSE;
335 GClosure *closure;
336
337 if (! initialized)
338 {
339 GType row_inserted_params[2];
340 GType row_deleted_params[1];
341 GType rows_reordered_params[3];
342
343 row_inserted_params[0] = GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE;
344 row_inserted_params[1] = GTK_TYPE_TREE_ITER;
345
346 row_deleted_params[0] = GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE;
347
348 rows_reordered_params[0] = GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE;
349 rows_reordered_params[1] = GTK_TYPE_TREE_ITER;
350 rows_reordered_params[2] = G_TYPE_POINTER;
351
352 /**
353 * GtkTreeModel::row-changed:
354 * @tree_model: the `GtkTreeModel` on which the signal is emitted
355 * @path: a `GtkTreePath` identifying the changed row
356 * @iter: a valid `GtkTreeIter` pointing to the changed row
357 *
358 * This signal is emitted when a row in the model has changed.
359 */
360 tree_model_signals[ROW_CHANGED] =
361 g_signal_new (I_("row-changed"),
362 GTK_TYPE_TREE_MODEL,
363 signal_flags: G_SIGNAL_RUN_LAST,
364 G_STRUCT_OFFSET (GtkTreeModelIface, row_changed),
365 NULL, NULL,
366 c_marshaller: _gtk_marshal_VOID__BOXED_BOXED,
367 G_TYPE_NONE, n_params: 2,
368 GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE,
369 GTK_TYPE_TREE_ITER);
370 g_signal_set_va_marshaller (signal_id: tree_model_signals[ROW_CHANGED],
371 G_TYPE_FROM_CLASS (g_class),
372 va_marshaller: _gtk_marshal_VOID__BOXED_BOXEDv);
373
374 /* We need to get notification about structure changes
375 * to update row references., so instead of using the
376 * standard g_signal_new() with an offset into our interface
377 * structure, we use a customs closures for the class
378 * closures (default handlers) that first update row references
379 * and then calls the function from the interface structure.
380 *
381 * The reason we don't simply update the row references from
382 * the wrapper functions (gtk_tree_model_row_inserted(), etc.)
383 * is to keep proper ordering with respect to signal handlers
384 * connected normally and after.
385 */
386
387 /**
388 * GtkTreeModel::row-inserted:
389 * @tree_model: the `GtkTreeModel` on which the signal is emitted
390 * @path: a `GtkTreePath` identifying the new row
391 * @iter: a valid `GtkTreeIter` pointing to the new row
392 *
393 * This signal is emitted when a new row has been inserted in
394 * the model.
395 *
396 * Note that the row may still be empty at this point, since
397 * it is a common pattern to first insert an empty row, and
398 * then fill it with the desired values.
399 */
400 closure = g_closure_new_simple (sizeof_closure: sizeof (GClosure), NULL);
401 g_closure_set_marshal (closure, marshal: row_inserted_marshal);
402 tree_model_signals[ROW_INSERTED] =
403 g_signal_newv (I_("row-inserted"),
404 GTK_TYPE_TREE_MODEL,
405 signal_flags: G_SIGNAL_RUN_FIRST,
406 class_closure: closure,
407 NULL, NULL,
408 c_marshaller: _gtk_marshal_VOID__BOXED_BOXED,
409 G_TYPE_NONE, n_params: 2,
410 param_types: row_inserted_params);
411 g_signal_set_va_marshaller (signal_id: tree_model_signals[ROW_INSERTED],
412 G_TYPE_FROM_CLASS (g_class),
413 va_marshaller: _gtk_marshal_VOID__BOXED_BOXEDv);
414
415 /**
416 * GtkTreeModel::row-has-child-toggled:
417 * @tree_model: the `GtkTreeModel` on which the signal is emitted
418 * @path: a `GtkTreePath` identifying the row
419 * @iter: a valid `GtkTreeIter` pointing to the row
420 *
421 * This signal is emitted when a row has gotten the first child
422 * row or lost its last child row.
423 */
424 tree_model_signals[ROW_HAS_CHILD_TOGGLED] =
425 g_signal_new (I_("row-has-child-toggled"),
426 GTK_TYPE_TREE_MODEL,
427 signal_flags: G_SIGNAL_RUN_LAST,
428 G_STRUCT_OFFSET (GtkTreeModelIface, row_has_child_toggled),
429 NULL, NULL,
430 c_marshaller: _gtk_marshal_VOID__BOXED_BOXED,
431 G_TYPE_NONE, n_params: 2,
432 GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE,
433 GTK_TYPE_TREE_ITER);
434 g_signal_set_va_marshaller (signal_id: tree_model_signals[ROW_HAS_CHILD_TOGGLED],
435 G_TYPE_FROM_CLASS (g_class),
436 va_marshaller: _gtk_marshal_VOID__BOXED_BOXEDv);
437
438 /**
439 * GtkTreeModel::row-deleted:
440 * @tree_model: the `GtkTreeModel` on which the signal is emitted
441 * @path: a `GtkTreePath` identifying the row
442 *
443 * This signal is emitted when a row has been deleted.
444 *
445 * Note that no iterator is passed to the signal handler,
446 * since the row is already deleted.
447 *
448 * This should be called by models after a row has been removed.
449 * The location pointed to by @path should be the location that
450 * the row previously was at. It may not be a valid location anymore.
451 */
452 closure = g_closure_new_simple (sizeof_closure: sizeof (GClosure), NULL);
453 g_closure_set_marshal (closure, marshal: row_deleted_marshal);
454 tree_model_signals[ROW_DELETED] =
455 g_signal_newv (I_("row-deleted"),
456 GTK_TYPE_TREE_MODEL,
457 signal_flags: G_SIGNAL_RUN_FIRST,
458 class_closure: closure,
459 NULL, NULL,
460 NULL,
461 G_TYPE_NONE, n_params: 1,
462 param_types: row_deleted_params);
463
464 /**
465 * GtkTreeModel::rows-reordered: (skip)
466 * @tree_model: the `GtkTreeModel` on which the signal is emitted
467 * @path: a `GtkTreePath` identifying the tree node whose children
468 * have been reordered
469 * @iter: a valid `GtkTreeIter` pointing to the node whose children
470 * have been reordered, or %NULL if the depth of @path is 0
471 * @new_order: an array of integers mapping the current position
472 * of each child to its old position before the re-ordering,
473 * i.e. @new_order`[newpos] = oldpos`
474 *
475 * This signal is emitted when the children of a node in the
476 * `GtkTreeModel` have been reordered.
477 *
478 * Note that this signal is not emitted
479 * when rows are reordered by DND, since this is implemented
480 * by removing and then reinserting the row.
481 */
482 closure = g_closure_new_simple (sizeof_closure: sizeof (GClosure), NULL);
483 g_closure_set_marshal (closure, marshal: rows_reordered_marshal);
484 tree_model_signals[ROWS_REORDERED] =
485 g_signal_newv (I_("rows-reordered"),
486 GTK_TYPE_TREE_MODEL,
487 signal_flags: G_SIGNAL_RUN_FIRST,
488 class_closure: closure,
489 NULL, NULL,
490 c_marshaller: _gtk_marshal_VOID__BOXED_BOXED_POINTER,
491 G_TYPE_NONE, n_params: 3,
492 param_types: rows_reordered_params);
493 g_signal_set_va_marshaller (signal_id: tree_model_signals[ROWS_REORDERED],
494 G_TYPE_FROM_CLASS (g_class),
495 va_marshaller: _gtk_marshal_VOID__BOXED_BOXED_POINTERv);
496 initialized = TRUE;
497 }
498}
499
500static void
501row_inserted_marshal (GClosure *closure,
502 GValue /* out */ *return_value,
503 guint n_param_values,
504 const GValue *param_values,
505 gpointer invocation_hint,
506 gpointer marshal_data)
507{
508 GtkTreeModelIface *iface;
509
510 void (* row_inserted_callback) (GtkTreeModel *tree_model,
511 GtkTreePath *path,
512 GtkTreeIter *iter) = NULL;
513
514 GObject *model = g_value_get_object (value: param_values + 0);
515 GtkTreePath *path = (GtkTreePath *)g_value_get_boxed (value: param_values + 1);
516 GtkTreeIter *iter = (GtkTreeIter *)g_value_get_boxed (value: param_values + 2);
517
518 /* first, we need to update internal row references */
519 gtk_tree_row_ref_inserted (refs: (RowRefList *)g_object_get_data (object: model, ROW_REF_DATA_STRING),
520 path, iter);
521
522 /* fetch the interface ->row_inserted implementation */
523 iface = GTK_TREE_MODEL_GET_IFACE (model);
524 row_inserted_callback = G_STRUCT_MEMBER (gpointer, iface,
525 G_STRUCT_OFFSET (GtkTreeModelIface,
526 row_inserted));
527
528 /* Call that default signal handler, it if has been set */
529 if (row_inserted_callback)
530 row_inserted_callback (GTK_TREE_MODEL (model), path, iter);
531}
532
533static void
534row_deleted_marshal (GClosure *closure,
535 GValue /* out */ *return_value,
536 guint n_param_values,
537 const GValue *param_values,
538 gpointer invocation_hint,
539 gpointer marshal_data)
540{
541 GtkTreeModelIface *iface;
542 void (* row_deleted_callback) (GtkTreeModel *tree_model,
543 GtkTreePath *path) = NULL;
544 GObject *model = g_value_get_object (value: param_values + 0);
545 GtkTreePath *path = (GtkTreePath *)g_value_get_boxed (value: param_values + 1);
546
547 /* first, we need to update internal row references */
548 gtk_tree_row_ref_deleted (refs: (RowRefList *)g_object_get_data (object: model, ROW_REF_DATA_STRING),
549 path);
550
551 /* fetch the interface ->row_deleted implementation */
552 iface = GTK_TREE_MODEL_GET_IFACE (model);
553 row_deleted_callback = G_STRUCT_MEMBER (gpointer, iface,
554 G_STRUCT_OFFSET (GtkTreeModelIface,
555 row_deleted));
556
557 /* Call that default signal handler, it if has been set */
558 if (row_deleted_callback)
559 row_deleted_callback (GTK_TREE_MODEL (model), path);
560}
561
562static void
563rows_reordered_marshal (GClosure *closure,
564 GValue /* out */ *return_value,
565 guint n_param_values,
566 const GValue *param_values,
567 gpointer invocation_hint,
568 gpointer marshal_data)
569{
570 GtkTreeModelIface *iface;
571 void (* rows_reordered_callback) (GtkTreeModel *tree_model,
572 GtkTreePath *path,
573 GtkTreeIter *iter,
574 int *new_order);
575
576 GObject *model = g_value_get_object (value: param_values + 0);
577 GtkTreePath *path = (GtkTreePath *)g_value_get_boxed (value: param_values + 1);
578 GtkTreeIter *iter = (GtkTreeIter *)g_value_get_boxed (value: param_values + 2);
579 int *new_order = (int *)g_value_get_pointer (value: param_values + 3);
580
581 /* first, we need to update internal row references */
582 gtk_tree_row_ref_reordered (refs: (RowRefList *)g_object_get_data (object: model, ROW_REF_DATA_STRING),
583 path, iter, new_order);
584
585 /* fetch the interface ->rows_reordered implementation */
586 iface = GTK_TREE_MODEL_GET_IFACE (model);
587 rows_reordered_callback = G_STRUCT_MEMBER (gpointer, iface,
588 G_STRUCT_OFFSET (GtkTreeModelIface,
589 rows_reordered));
590
591 /* Call that default signal handler, it if has been set */
592 if (rows_reordered_callback)
593 rows_reordered_callback (GTK_TREE_MODEL (model), path, iter, new_order);
594}
595
596/**
597 * gtk_tree_path_new:
598 *
599 * Creates a new `GtkTreePath`
600 * This refers to a row.
601 *
602 * Returns: A newly created `GtkTreePath`.
603 */
604GtkTreePath *
605gtk_tree_path_new (void)
606{
607 GtkTreePath *retval;
608 retval = g_slice_new (GtkTreePath);
609 retval->depth = 0;
610 retval->alloc = 0;
611 retval->indices = NULL;
612
613 return retval;
614}
615
616/**
617 * gtk_tree_path_new_from_string:
618 * @path: The string representation of a path
619 *
620 * Creates a new `GtkTreePath` initialized to @path.
621 *
622 * @path is expected to be a colon separated list of numbers.
623 * For example, the string “10:4:0” would create a path of depth
624 * 3 pointing to the 11th child of the root node, the 5th
625 * child of that 11th child, and the 1st child of that 5th child.
626 * If an invalid path string is passed in, %NULL is returned.
627 *
628 * Returns: (nullable): A newly-created `GtkTreePath`
629 */
630GtkTreePath *
631gtk_tree_path_new_from_string (const char *path)
632{
633 GtkTreePath *retval;
634 const char *orig_path = path;
635 char *ptr;
636 int i;
637
638 g_return_val_if_fail (path != NULL, NULL);
639 g_return_val_if_fail (*path != '\000', NULL);
640
641 retval = gtk_tree_path_new ();
642
643 while (1)
644 {
645 i = strtol (nptr: path, endptr: &ptr, base: 10);
646 if (i < 0)
647 {
648 g_warning (G_STRLOC ": Negative numbers in path %s passed to gtk_tree_path_new_from_string", orig_path);
649 gtk_tree_path_free (path: retval);
650 return NULL;
651 }
652
653 gtk_tree_path_append_index (path: retval, index_: i);
654
655 if (*ptr == '\000')
656 break;
657 if (ptr == path || *ptr != ':')
658 {
659 g_warning (G_STRLOC ": Invalid path %s passed to gtk_tree_path_new_from_string", orig_path);
660 gtk_tree_path_free (path: retval);
661 return NULL;
662 }
663 path = ptr + 1;
664 }
665
666 return retval;
667}
668
669/**
670 * gtk_tree_path_new_from_indices:
671 * @first_index: first integer
672 * @...: list of integers terminated by -1
673 *
674 * Creates a new path with @first_index and @varargs as indices.
675 *
676 * Returns: A newly created `GtkTreePath`
677 */
678GtkTreePath *
679gtk_tree_path_new_from_indices (int first_index,
680 ...)
681{
682 int arg;
683 va_list args;
684 GtkTreePath *path;
685
686 path = gtk_tree_path_new ();
687
688 va_start (args, first_index);
689 arg = first_index;
690
691 while (arg != -1)
692 {
693 gtk_tree_path_append_index (path, index_: arg);
694 arg = va_arg (args, int);
695 }
696
697 va_end (args);
698
699 return path;
700}
701
702/**
703 * gtk_tree_path_new_from_indicesv: (rename-to gtk_tree_path_new_from_indices)
704 * @indices: (array length=length): array of indices
705 * @length: length of @indices array
706 *
707 * Creates a new path with the given @indices array of @length.
708 *
709 * Returns: A newly created `GtkTreePath`
710 */
711GtkTreePath *
712gtk_tree_path_new_from_indicesv (int *indices,
713 gsize length)
714{
715 GtkTreePath *path;
716
717 g_return_val_if_fail (indices != NULL && length != 0, NULL);
718
719 path = gtk_tree_path_new ();
720 path->alloc = length;
721 path->depth = length;
722 path->indices = g_new (int, length);
723 memcpy (dest: path->indices, src: indices, n: length * sizeof (int));
724
725 return path;
726}
727
728/**
729 * gtk_tree_path_to_string:
730 * @path: a `GtkTreePath`
731 *
732 * Generates a string representation of the path.
733 *
734 * This string is a “:” separated list of numbers.
735 * For example, “4:10:0:3” would be an acceptable
736 * return value for this string. If the path has
737 * depth 0, %NULL is returned.
738 *
739 * Returns: (nullable): A newly-allocated string
740 */
741char *
742gtk_tree_path_to_string (GtkTreePath *path)
743{
744 char *retval, *ptr, *end;
745 int i, n;
746
747 g_return_val_if_fail (path != NULL, NULL);
748
749 if (path->depth == 0)
750 return NULL;
751
752 n = path->depth * 12;
753 ptr = retval = g_new0 (char, n);
754 end = ptr + n;
755 g_snprintf (string: retval, n: end - ptr, format: "%d", path->indices[0]);
756 while (*ptr != '\000')
757 ptr++;
758
759 for (i = 1; i < path->depth; i++)
760 {
761 g_snprintf (string: ptr, n: end - ptr, format: ":%d", path->indices[i]);
762 while (*ptr != '\000')
763 ptr++;
764 }
765
766 return retval;
767}
768
769/**
770 * gtk_tree_path_new_first:
771 *
772 * Creates a new `GtkTreePath`.
773 *
774 * The string representation of this path is “0”.
775 *
776 * Returns: A new `GtkTreePath`
777 */
778GtkTreePath *
779gtk_tree_path_new_first (void)
780{
781 GtkTreePath *retval;
782
783 retval = gtk_tree_path_new ();
784 gtk_tree_path_append_index (path: retval, index_: 0);
785
786 return retval;
787}
788
789/**
790 * gtk_tree_path_append_index:
791 * @path: a `GtkTreePath`
792 * @index_: the index
793 *
794 * Appends a new index to a path.
795 *
796 * As a result, the depth of the path is increased.
797 */
798void
799gtk_tree_path_append_index (GtkTreePath *path,
800 int index_)
801{
802 g_return_if_fail (path != NULL);
803 g_return_if_fail (index_ >= 0);
804
805 if (path->depth == path->alloc)
806 {
807 path->alloc = MAX (path->alloc * 2, 1);
808 path->indices = g_renew (int, path->indices, path->alloc);
809 }
810
811 path->depth += 1;
812 path->indices[path->depth - 1] = index_;
813}
814
815/**
816 * gtk_tree_path_prepend_index:
817 * @path: a `GtkTreePath`
818 * @index_: the index
819 *
820 * Prepends a new index to a path.
821 *
822 * As a result, the depth of the path is increased.
823 */
824void
825gtk_tree_path_prepend_index (GtkTreePath *path,
826 int index)
827{
828 if (path->depth == path->alloc)
829 {
830 int *indices;
831 path->alloc = MAX (path->alloc * 2, 1);
832 indices = g_new (int, path->alloc);
833 memcpy (dest: indices + 1, src: path->indices, n: path->depth * sizeof (int));
834 g_free (mem: path->indices);
835 path->indices = indices;
836 }
837 else if (path->depth > 0)
838 memmove (dest: path->indices + 1, src: path->indices, n: path->depth * sizeof (int));
839
840 path->depth += 1;
841 path->indices[0] = index;
842}
843
844/**
845 * gtk_tree_path_get_depth:
846 * @path: a `GtkTreePath`
847 *
848 * Returns the current depth of @path.
849 *
850 * Returns: The depth of @path
851 */
852int
853gtk_tree_path_get_depth (GtkTreePath *path)
854{
855 g_return_val_if_fail (path != NULL, 0);
856
857 return path->depth;
858}
859
860/**
861 * gtk_tree_path_get_indices: (skip)
862 * @path: a `GtkTreePath`
863 *
864 * Returns the current indices of @path.
865 *
866 * This is an array of integers, each representing a node in a tree.
867 * This value should not be freed.
868 *
869 * The length of the array can be obtained with gtk_tree_path_get_depth().
870 *
871 * Returns: (nullable) (transfer none): The current indices
872 */
873int *
874gtk_tree_path_get_indices (GtkTreePath *path)
875{
876 g_return_val_if_fail (path != NULL, NULL);
877
878 return path->indices;
879}
880
881/**
882 * gtk_tree_path_get_indices_with_depth: (rename-to gtk_tree_path_get_indices)
883 * @path: a `GtkTreePath`
884 * @depth: (out) (optional): return location for number of elements
885 * returned in the integer array
886 *
887 * Returns the current indices of @path.
888 *
889 * This is an array of integers, each representing a node in a tree.
890 * It also returns the number of elements in the array.
891 * The array should not be freed.
892 *
893 * Returns: (array length=depth) (transfer none) (nullable): The current
894 * indices
895 */
896int *
897gtk_tree_path_get_indices_with_depth (GtkTreePath *path,
898 int *depth)
899{
900 g_return_val_if_fail (path != NULL, NULL);
901
902 if (depth)
903 *depth = path->depth;
904
905 return path->indices;
906}
907
908/**
909 * gtk_tree_path_free:
910 * @path: (nullable): a `GtkTreePath`
911 *
912 * Frees @path. If @path is %NULL, it simply returns.
913 */
914void
915gtk_tree_path_free (GtkTreePath *path)
916{
917 if (!path)
918 return;
919
920 g_free (mem: path->indices);
921 g_slice_free (GtkTreePath, path);
922}
923
924/**
925 * gtk_tree_path_copy:
926 * @path: a `GtkTreePath`
927 *
928 * Creates a new `GtkTreePath` as a copy of @path.
929 *
930 * Returns: a new `GtkTreePath`
931 */
932GtkTreePath *
933gtk_tree_path_copy (const GtkTreePath *path)
934{
935 GtkTreePath *retval;
936
937 g_return_val_if_fail (path != NULL, NULL);
938
939 retval = g_slice_new (GtkTreePath);
940 retval->depth = path->depth;
941 retval->alloc = retval->depth;
942 retval->indices = g_new (int, path->alloc);
943 memcpy (dest: retval->indices, src: path->indices, n: path->depth * sizeof (int));
944 return retval;
945}
946
947G_DEFINE_BOXED_TYPE (GtkTreePath, gtk_tree_path,
948 gtk_tree_path_copy,
949 gtk_tree_path_free)
950
951/**
952 * gtk_tree_path_compare:
953 * @a: a `GtkTreePath`
954 * @b: a `GtkTreePath` to compare with
955 *
956 * Compares two paths.
957 *
958 * If @a appears before @b in a tree, then -1 is returned.
959 * If @b appears before @a, then 1 is returned.
960 * If the two nodes are equal, then 0 is returned.
961 *
962 * Returns: the relative positions of @a and @b
963 */
964int
965gtk_tree_path_compare (const GtkTreePath *a,
966 const GtkTreePath *b)
967{
968 int p = 0, q = 0;
969
970 g_return_val_if_fail (a != NULL, 0);
971 g_return_val_if_fail (b != NULL, 0);
972 g_return_val_if_fail (a->depth > 0, 0);
973 g_return_val_if_fail (b->depth > 0, 0);
974
975 do
976 {
977 if (a->indices[p] == b->indices[q])
978 continue;
979 return (a->indices[p] < b->indices[q]?-1:1);
980 }
981 while (++p < a->depth && ++q < b->depth);
982 if (a->depth == b->depth)
983 return 0;
984 return (a->depth < b->depth?-1:1);
985}
986
987/**
988 * gtk_tree_path_is_ancestor:
989 * @path: a `GtkTreePath`
990 * @descendant: another `GtkTreePath`
991 *
992 * Returns %TRUE if @descendant is a descendant of @path.
993 *
994 * Returns: %TRUE if @descendant is contained inside @path
995 */
996gboolean
997gtk_tree_path_is_ancestor (GtkTreePath *path,
998 GtkTreePath *descendant)
999{
1000 int i;
1001
1002 g_return_val_if_fail (path != NULL, FALSE);
1003 g_return_val_if_fail (descendant != NULL, FALSE);
1004
1005 /* can't be an ancestor if we're deeper */
1006 if (path->depth >= descendant->depth)
1007 return FALSE;
1008
1009 i = 0;
1010 while (i < path->depth)
1011 {
1012 if (path->indices[i] != descendant->indices[i])
1013 return FALSE;
1014 ++i;
1015 }
1016
1017 return TRUE;
1018}
1019
1020/**
1021 * gtk_tree_path_is_descendant:
1022 * @path: a `GtkTreePath`
1023 * @ancestor: another `GtkTreePath`
1024 *
1025 * Returns %TRUE if @path is a descendant of @ancestor.
1026 *
1027 * Returns: %TRUE if @ancestor contains @path somewhere below it
1028 */
1029gboolean
1030gtk_tree_path_is_descendant (GtkTreePath *path,
1031 GtkTreePath *ancestor)
1032{
1033 int i;
1034
1035 g_return_val_if_fail (path != NULL, FALSE);
1036 g_return_val_if_fail (ancestor != NULL, FALSE);
1037
1038 /* can't be a descendant if we're shallower in the tree */
1039 if (path->depth <= ancestor->depth)
1040 return FALSE;
1041
1042 i = 0;
1043 while (i < ancestor->depth)
1044 {
1045 if (path->indices[i] != ancestor->indices[i])
1046 return FALSE;
1047 ++i;
1048 }
1049
1050 return TRUE;
1051}
1052
1053
1054/**
1055 * gtk_tree_path_next:
1056 * @path: a `GtkTreePath`
1057 *
1058 * Moves the @path to point to the next node at the current depth.
1059 */
1060void
1061gtk_tree_path_next (GtkTreePath *path)
1062{
1063 g_return_if_fail (path != NULL);
1064 g_return_if_fail (path->depth > 0);
1065
1066 path->indices[path->depth - 1] ++;
1067}
1068
1069/**
1070 * gtk_tree_path_prev:
1071 * @path: a `GtkTreePath`
1072 *
1073 * Moves the @path to point to the previous node at the
1074 * current depth, if it exists.
1075 *
1076 * Returns: %TRUE if @path has a previous node, and
1077 * the move was made
1078 */
1079gboolean
1080gtk_tree_path_prev (GtkTreePath *path)
1081{
1082 g_return_val_if_fail (path != NULL, FALSE);
1083
1084 if (path->depth == 0)
1085 return FALSE;
1086
1087 if (path->indices[path->depth - 1] == 0)
1088 return FALSE;
1089
1090 path->indices[path->depth - 1] -= 1;
1091
1092 return TRUE;
1093}
1094
1095/**
1096 * gtk_tree_path_up:
1097 * @path: a `GtkTreePath`
1098 *
1099 * Moves the @path to point to its parent node, if it has a parent.
1100 *
1101 * Returns: %TRUE if @path has a parent, and the move was made
1102 */
1103gboolean
1104gtk_tree_path_up (GtkTreePath *path)
1105{
1106 g_return_val_if_fail (path != NULL, FALSE);
1107
1108 if (path->depth == 0)
1109 return FALSE;
1110
1111 path->depth--;
1112
1113 return TRUE;
1114}
1115
1116/**
1117 * gtk_tree_path_down:
1118 * @path: a `GtkTreePath`
1119 *
1120 * Moves @path to point to the first child of the current path.
1121 */
1122void
1123gtk_tree_path_down (GtkTreePath *path)
1124{
1125 g_return_if_fail (path != NULL);
1126
1127 gtk_tree_path_append_index (path, index_: 0);
1128}
1129
1130/**
1131 * gtk_tree_iter_copy:
1132 * @iter: a `GtkTreeIter`
1133 *
1134 * Creates a dynamically allocated tree iterator as a copy of @iter.
1135 *
1136 * This function is not intended for use in applications,
1137 * because you can just copy the structs by value
1138 * (`GtkTreeIter new_iter = iter;`).
1139 * You must free this iter with gtk_tree_iter_free().
1140 *
1141 * Returns: a newly-allocated copy of @iter
1142 */
1143GtkTreeIter *
1144gtk_tree_iter_copy (GtkTreeIter *iter)
1145{
1146 GtkTreeIter *retval;
1147
1148 g_return_val_if_fail (iter != NULL, NULL);
1149
1150 retval = g_slice_new (GtkTreeIter);
1151 *retval = *iter;
1152
1153 return retval;
1154}
1155
1156/**
1157 * gtk_tree_iter_free:
1158 * @iter: a dynamically allocated tree iterator
1159 *
1160 * Frees an iterator that has been allocated by gtk_tree_iter_copy().
1161 *
1162 * This function is mainly used for language bindings.
1163 */
1164void
1165gtk_tree_iter_free (GtkTreeIter *iter)
1166{
1167 g_return_if_fail (iter != NULL);
1168
1169 g_slice_free (GtkTreeIter, iter);
1170}
1171
1172G_DEFINE_BOXED_TYPE (GtkTreeIter, gtk_tree_iter,
1173 gtk_tree_iter_copy,
1174 gtk_tree_iter_free)
1175
1176/**
1177 * gtk_tree_model_get_flags:
1178 * @tree_model: a `GtkTreeModel`
1179 *
1180 * Returns a set of flags supported by this interface.
1181 *
1182 * The flags are a bitwise combination of `GtkTreeModel`Flags.
1183 * The flags supported should not change during the lifetime
1184 * of the @tree_model.
1185 *
1186 * Returns: the flags supported by this interface
1187 */
1188GtkTreeModelFlags
1189gtk_tree_model_get_flags (GtkTreeModel *tree_model)
1190{
1191 GtkTreeModelIface *iface;
1192
1193 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), 0);
1194
1195 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1196 if (iface->get_flags)
1197 return (* iface->get_flags) (tree_model);
1198
1199 return 0;
1200}
1201
1202/**
1203 * gtk_tree_model_get_n_columns:
1204 * @tree_model: a `GtkTreeModel`
1205 *
1206 * Returns the number of columns supported by @tree_model.
1207 *
1208 * Returns: the number of columns
1209 */
1210int
1211gtk_tree_model_get_n_columns (GtkTreeModel *tree_model)
1212{
1213 GtkTreeModelIface *iface;
1214 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), 0);
1215
1216 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1217 g_return_val_if_fail (iface->get_n_columns != NULL, 0);
1218
1219 return (* iface->get_n_columns) (tree_model);
1220}
1221
1222/**
1223 * gtk_tree_model_get_column_type:
1224 * @tree_model: a `GtkTreeModel`
1225 * @index_: the column index
1226 *
1227 * Returns the type of the column.
1228 *
1229 * Returns: the type of the column
1230 */
1231GType
1232gtk_tree_model_get_column_type (GtkTreeModel *tree_model,
1233 int index)
1234{
1235 GtkTreeModelIface *iface;
1236
1237 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), G_TYPE_INVALID);
1238
1239 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1240 g_return_val_if_fail (iface->get_column_type != NULL, G_TYPE_INVALID);
1241 g_return_val_if_fail (index >= 0, G_TYPE_INVALID);
1242
1243 return (* iface->get_column_type) (tree_model, index);
1244}
1245
1246/**
1247 * gtk_tree_model_get_iter:
1248 * @tree_model: a `GtkTreeModel`
1249 * @iter: (out): the uninitialized `GtkTreeIter`
1250 * @path: the `GtkTreePath`
1251 *
1252 * Sets @iter to a valid iterator pointing to @path.
1253 *
1254 * If @path does not exist, @iter is set to an invalid
1255 * iterator and %FALSE is returned.
1256 *
1257 * Returns: %TRUE, if @iter was set
1258 */
1259gboolean
1260gtk_tree_model_get_iter (GtkTreeModel *tree_model,
1261 GtkTreeIter *iter,
1262 GtkTreePath *path)
1263{
1264 GtkTreeModelIface *iface;
1265
1266 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
1267 g_return_val_if_fail (iter != NULL, FALSE);
1268 g_return_val_if_fail (path != NULL, FALSE);
1269
1270 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1271 g_return_val_if_fail (iface->get_iter != NULL, FALSE);
1272 g_return_val_if_fail (path->depth > 0, FALSE);
1273
1274 INITIALIZE_TREE_ITER (iter);
1275
1276 return (* iface->get_iter) (tree_model, iter, path);
1277}
1278
1279/**
1280 * gtk_tree_model_get_iter_from_string:
1281 * @tree_model: a `GtkTreeModel`
1282 * @iter: (out): an uninitialized `GtkTreeIter`
1283 * @path_string: a string representation of a `GtkTreePath`
1284 *
1285 * Sets @iter to a valid iterator pointing to @path_string, if it
1286 * exists.
1287 *
1288 * Otherwise, @iter is left invalid and %FALSE is returned.
1289 *
1290 * Returns: %TRUE, if @iter was set
1291 */
1292gboolean
1293gtk_tree_model_get_iter_from_string (GtkTreeModel *tree_model,
1294 GtkTreeIter *iter,
1295 const char *path_string)
1296{
1297 gboolean retval;
1298 GtkTreePath *path;
1299
1300 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
1301 g_return_val_if_fail (iter != NULL, FALSE);
1302 g_return_val_if_fail (path_string != NULL, FALSE);
1303
1304 path = gtk_tree_path_new_from_string (path: path_string);
1305
1306 g_return_val_if_fail (path != NULL, FALSE);
1307
1308 retval = gtk_tree_model_get_iter (tree_model, iter, path);
1309 gtk_tree_path_free (path);
1310
1311 return retval;
1312}
1313
1314/**
1315 * gtk_tree_model_get_string_from_iter:
1316 * @tree_model: a `GtkTreeModel`
1317 * @iter: a `GtkTreeIter`
1318 *
1319 * Generates a string representation of the iter.
1320 *
1321 * This string is a “:” separated list of numbers.
1322 * For example, “4:10:0:3” would be an acceptable
1323 * return value for this string.
1324 *
1325 * Returns: (nullable): a newly-allocated string
1326 */
1327char *
1328gtk_tree_model_get_string_from_iter (GtkTreeModel *tree_model,
1329 GtkTreeIter *iter)
1330{
1331 GtkTreePath *path;
1332 char *ret;
1333
1334 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), NULL);
1335 g_return_val_if_fail (iter != NULL, NULL);
1336
1337 path = gtk_tree_model_get_path (tree_model, iter);
1338
1339 g_return_val_if_fail (path != NULL, NULL);
1340
1341 ret = gtk_tree_path_to_string (path);
1342 gtk_tree_path_free (path);
1343
1344 return ret;
1345}
1346
1347/**
1348 * gtk_tree_model_get_iter_first:
1349 * @tree_model: a `GtkTreeModel`
1350 * @iter: (out): the uninitialized `GtkTreeIter`
1351 *
1352 * Initializes @iter with the first iterator in the tree
1353 * (the one at the path "0").
1354 *
1355 * Returns %FALSE if the tree is empty, %TRUE otherwise.
1356 *
1357 * Returns: %TRUE, if @iter was set
1358 */
1359gboolean
1360gtk_tree_model_get_iter_first (GtkTreeModel *tree_model,
1361 GtkTreeIter *iter)
1362{
1363 GtkTreePath *path;
1364 gboolean retval;
1365
1366 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
1367 g_return_val_if_fail (iter != NULL, FALSE);
1368
1369 path = gtk_tree_path_new_first ();
1370 retval = gtk_tree_model_get_iter (tree_model, iter, path);
1371 gtk_tree_path_free (path);
1372
1373 return retval;
1374}
1375
1376/**
1377 * gtk_tree_model_get_path:
1378 * @tree_model: a `GtkTreeModel`
1379 * @iter: the `GtkTreeIter`
1380 *
1381 * Returns a newly-created `GtkTreePath` referenced by @iter.
1382 *
1383 * This path should be freed with gtk_tree_path_free().
1384 *
1385 * Returns: a newly-created `GtkTreePath`
1386 */
1387GtkTreePath *
1388gtk_tree_model_get_path (GtkTreeModel *tree_model,
1389 GtkTreeIter *iter)
1390{
1391 GtkTreeModelIface *iface;
1392
1393 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), NULL);
1394 g_return_val_if_fail (iter != NULL, NULL);
1395
1396 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1397 g_return_val_if_fail (iface->get_path != NULL, NULL);
1398
1399 return (* iface->get_path) (tree_model, iter);
1400}
1401
1402/**
1403 * gtk_tree_model_get_value:
1404 * @tree_model: a `GtkTreeModel`
1405 * @iter: the `GtkTreeIter`
1406 * @column: the column to lookup the value at
1407 * @value: (out) (transfer none): an empty `GValue` to set
1408 *
1409 * Initializes and sets @value to that at @column.
1410 *
1411 * When done with @value, g_value_unset() needs to be called
1412 * to free any allocated memory.
1413 */
1414void
1415gtk_tree_model_get_value (GtkTreeModel *tree_model,
1416 GtkTreeIter *iter,
1417 int column,
1418 GValue *value)
1419{
1420 GtkTreeModelIface *iface;
1421
1422 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1423 g_return_if_fail (iter != NULL);
1424 g_return_if_fail (value != NULL);
1425
1426 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1427 g_return_if_fail (iface->get_value != NULL);
1428
1429 (* iface->get_value) (tree_model, iter, column, value);
1430}
1431
1432/**
1433 * gtk_tree_model_iter_next:
1434 * @tree_model: a `GtkTreeModel`
1435 * @iter: (in): the `GtkTreeIter`
1436 *
1437 * Sets @iter to point to the node following it at the current level.
1438 *
1439 * If there is no next @iter, %FALSE is returned and @iter is set
1440 * to be invalid.
1441 *
1442 * Returns: %TRUE if @iter has been changed to the next node
1443 */
1444gboolean
1445gtk_tree_model_iter_next (GtkTreeModel *tree_model,
1446 GtkTreeIter *iter)
1447{
1448 GtkTreeModelIface *iface;
1449
1450 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
1451 g_return_val_if_fail (iter != NULL, FALSE);
1452
1453 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1454 g_return_val_if_fail (iface->iter_next != NULL, FALSE);
1455
1456 return (* iface->iter_next) (tree_model, iter);
1457}
1458
1459static gboolean
1460gtk_tree_model_iter_previous_default (GtkTreeModel *tree_model,
1461 GtkTreeIter *iter)
1462{
1463 gboolean retval;
1464 GtkTreePath *path;
1465
1466 path = gtk_tree_model_get_path (tree_model, iter);
1467 if (path == NULL)
1468 return FALSE;
1469
1470 retval = gtk_tree_path_prev (path) &&
1471 gtk_tree_model_get_iter (tree_model, iter, path);
1472 if (retval == FALSE)
1473 iter->stamp = 0;
1474
1475 gtk_tree_path_free (path);
1476
1477 return retval;
1478}
1479
1480/**
1481 * gtk_tree_model_iter_previous:
1482 * @tree_model: a `GtkTreeModel`
1483 * @iter: (in): the `GtkTreeIter`
1484 *
1485 * Sets @iter to point to the previous node at the current level.
1486 *
1487 * If there is no previous @iter, %FALSE is returned and @iter is
1488 * set to be invalid.
1489 *
1490 * Returns: %TRUE if @iter has been changed to the previous node
1491 */
1492gboolean
1493gtk_tree_model_iter_previous (GtkTreeModel *tree_model,
1494 GtkTreeIter *iter)
1495{
1496 gboolean retval;
1497 GtkTreeModelIface *iface;
1498
1499 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
1500 g_return_val_if_fail (iter != NULL, FALSE);
1501
1502 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1503
1504 if (iface->iter_previous)
1505 retval = (* iface->iter_previous) (tree_model, iter);
1506 else
1507 retval = gtk_tree_model_iter_previous_default (tree_model, iter);
1508
1509 return retval;
1510}
1511
1512/**
1513 * gtk_tree_model_iter_children:
1514 * @tree_model: a `GtkTreeModel`
1515 * @iter: (out): the new `GtkTreeIter` to be set to the child
1516 * @parent: (nullable): the `GtkTreeIter`
1517 *
1518 * Sets @iter to point to the first child of @parent.
1519 *
1520 * If @parent has no children, %FALSE is returned and @iter is
1521 * set to be invalid. @parent will remain a valid node after this
1522 * function has been called.
1523 *
1524 * If @parent is %NULL returns the first node, equivalent to
1525 * `gtk_tree_model_get_iter_first (tree_model, iter);`
1526 *
1527 * Returns: %TRUE, if @iter has been set to the first child
1528 */
1529gboolean
1530gtk_tree_model_iter_children (GtkTreeModel *tree_model,
1531 GtkTreeIter *iter,
1532 GtkTreeIter *parent)
1533{
1534 GtkTreeModelIface *iface;
1535
1536 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
1537 g_return_val_if_fail (iter != NULL, FALSE);
1538
1539 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1540 g_return_val_if_fail (iface->iter_children != NULL, FALSE);
1541
1542 INITIALIZE_TREE_ITER (iter);
1543
1544 return (* iface->iter_children) (tree_model, iter, parent);
1545}
1546
1547/**
1548 * gtk_tree_model_iter_has_child:
1549 * @tree_model: a `GtkTreeModel`
1550 * @iter: the `GtkTreeIter` to test for children
1551 *
1552 * Returns %TRUE if @iter has children, %FALSE otherwise.
1553 *
1554 * Returns: %TRUE if @iter has children
1555 */
1556gboolean
1557gtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
1558 GtkTreeIter *iter)
1559{
1560 GtkTreeModelIface *iface;
1561
1562 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
1563 g_return_val_if_fail (iter != NULL, FALSE);
1564
1565 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1566 g_return_val_if_fail (iface->iter_has_child != NULL, FALSE);
1567
1568 return (* iface->iter_has_child) (tree_model, iter);
1569}
1570
1571/**
1572 * gtk_tree_model_iter_n_children:
1573 * @tree_model: a `GtkTreeModel`
1574 * @iter: (nullable): the `GtkTreeIter`
1575 *
1576 * Returns the number of children that @iter has.
1577 *
1578 * As a special case, if @iter is %NULL, then the number
1579 * of toplevel nodes is returned.
1580 *
1581 * Returns: the number of children of @iter
1582 */
1583int
1584gtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
1585 GtkTreeIter *iter)
1586{
1587 GtkTreeModelIface *iface;
1588
1589 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), 0);
1590
1591 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1592 g_return_val_if_fail (iface->iter_n_children != NULL, 0);
1593
1594 return (* iface->iter_n_children) (tree_model, iter);
1595}
1596
1597/**
1598 * gtk_tree_model_iter_nth_child:
1599 * @tree_model: a `GtkTreeModel`
1600 * @iter: (out): the `GtkTreeIter` to set to the nth child
1601 * @parent: (nullable): the `GtkTreeIter` to get the child from
1602 * @n: the index of the desired child
1603 *
1604 * Sets @iter to be the child of @parent, using the given index.
1605 *
1606 * The first index is 0. If @n is too big, or @parent has no children,
1607 * @iter is set to an invalid iterator and %FALSE is returned. @parent
1608 * will remain a valid node after this function has been called. As a
1609 * special case, if @parent is %NULL, then the @n-th root node
1610 * is set.
1611 *
1612 * Returns: %TRUE, if @parent has an @n-th child
1613 */
1614gboolean
1615gtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
1616 GtkTreeIter *iter,
1617 GtkTreeIter *parent,
1618 int n)
1619{
1620 GtkTreeModelIface *iface;
1621
1622 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
1623 g_return_val_if_fail (iter != NULL, FALSE);
1624 g_return_val_if_fail (n >= 0, FALSE);
1625
1626 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1627 g_return_val_if_fail (iface->iter_nth_child != NULL, FALSE);
1628
1629 INITIALIZE_TREE_ITER (iter);
1630
1631 return (* iface->iter_nth_child) (tree_model, iter, parent, n);
1632}
1633
1634/**
1635 * gtk_tree_model_iter_parent:
1636 * @tree_model: a `GtkTreeModel`
1637 * @iter: (out): the new `GtkTreeIter` to set to the parent
1638 * @child: the `GtkTreeIter`
1639 *
1640 * Sets @iter to be the parent of @child.
1641 *
1642 * If @child is at the toplevel, and doesn’t have a parent, then
1643 * @iter is set to an invalid iterator and %FALSE is returned.
1644 * @child will remain a valid node after this function has been
1645 * called.
1646 *
1647 * @iter will be initialized before the lookup is performed, so @child
1648 * and @iter cannot point to the same memory location.
1649 *
1650 * Returns: %TRUE, if @iter is set to the parent of @child
1651 */
1652gboolean
1653gtk_tree_model_iter_parent (GtkTreeModel *tree_model,
1654 GtkTreeIter *iter,
1655 GtkTreeIter *child)
1656{
1657 GtkTreeModelIface *iface;
1658
1659 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
1660 g_return_val_if_fail (iter != NULL, FALSE);
1661 g_return_val_if_fail (child != NULL, FALSE);
1662
1663 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1664 g_return_val_if_fail (iface->iter_parent != NULL, FALSE);
1665
1666 INITIALIZE_TREE_ITER (iter);
1667
1668 return (* iface->iter_parent) (tree_model, iter, child);
1669}
1670
1671/**
1672 * gtk_tree_model_ref_node:
1673 * @tree_model: a `GtkTreeModel`
1674 * @iter: the `GtkTreeIter`
1675 *
1676 * Lets the tree ref the node.
1677 *
1678 * This is an optional method for models to implement.
1679 * To be more specific, models may ignore this call as it exists
1680 * primarily for performance reasons.
1681 *
1682 * This function is primarily meant as a way for views to let
1683 * caching models know when nodes are being displayed (and hence,
1684 * whether or not to cache that node). Being displayed means a node
1685 * is in an expanded branch, regardless of whether the node is currently
1686 * visible in the viewport. For example, a file-system based model
1687 * would not want to keep the entire file-hierarchy in memory,
1688 * just the sections that are currently being displayed by
1689 * every current view.
1690 *
1691 * A model should be expected to be able to get an iter independent
1692 * of its reffed state.
1693 */
1694void
1695gtk_tree_model_ref_node (GtkTreeModel *tree_model,
1696 GtkTreeIter *iter)
1697{
1698 GtkTreeModelIface *iface;
1699
1700 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1701
1702 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1703 if (iface->ref_node)
1704 (* iface->ref_node) (tree_model, iter);
1705}
1706
1707/**
1708 * gtk_tree_model_unref_node:
1709 * @tree_model: a `GtkTreeModel`
1710 * @iter: the `GtkTreeIter`
1711 *
1712 * Lets the tree unref the node.
1713 *
1714 * This is an optional method for models to implement.
1715 * To be more specific, models may ignore this call as it exists
1716 * primarily for performance reasons. For more information on what
1717 * this means, see gtk_tree_model_ref_node().
1718 *
1719 * Please note that nodes that are deleted are not unreffed.
1720 */
1721void
1722gtk_tree_model_unref_node (GtkTreeModel *tree_model,
1723 GtkTreeIter *iter)
1724{
1725 GtkTreeModelIface *iface;
1726
1727 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1728 g_return_if_fail (iter != NULL);
1729
1730 iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
1731 if (iface->unref_node)
1732 (* iface->unref_node) (tree_model, iter);
1733}
1734
1735/**
1736 * gtk_tree_model_get:
1737 * @tree_model: a `GtkTreeModel`
1738 * @iter: a row in @tree_model
1739 * @...: pairs of column number and value return locations,
1740 * terminated by -1
1741 *
1742 * Gets the value of one or more cells in the row referenced by @iter.
1743 *
1744 * The variable argument list should contain integer column numbers,
1745 * each column number followed by a place to store the value being
1746 * retrieved. The list is terminated by a -1. For example, to get a
1747 * value from column 0 with type %G_TYPE_STRING, you would
1748 * write: `gtk_tree_model_get (model, iter, 0, &place_string_here, -1)`,
1749 * where `place_string_here` is a #gchararray
1750 * to be filled with the string.
1751 *
1752 * Returned values with type %G_TYPE_OBJECT have to be unreferenced,
1753 * values with type %G_TYPE_STRING or %G_TYPE_BOXED have to be freed.
1754 * Other values are passed by value.
1755 */
1756void
1757gtk_tree_model_get (GtkTreeModel *tree_model,
1758 GtkTreeIter *iter,
1759 ...)
1760{
1761 va_list var_args;
1762
1763 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1764 g_return_if_fail (iter != NULL);
1765
1766 va_start (var_args, iter);
1767 gtk_tree_model_get_valist (tree_model, iter, var_args);
1768 va_end (var_args);
1769}
1770
1771/**
1772 * gtk_tree_model_get_valist:
1773 * @tree_model: a `GtkTreeModel`
1774 * @iter: a row in @tree_model
1775 * @var_args: va_list of column/return location pairs
1776 *
1777 * Gets the value of one or more cells in the row referenced by @iter.
1778 *
1779 * See [method@Gtk.TreeModel.get], this version takes a va_list
1780 * for language bindings to use.
1781 */
1782void
1783gtk_tree_model_get_valist (GtkTreeModel *tree_model,
1784 GtkTreeIter *iter,
1785 va_list var_args)
1786{
1787 int column;
1788
1789 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1790 g_return_if_fail (iter != NULL);
1791
1792 column = va_arg (var_args, int);
1793
1794 while (column != -1)
1795 {
1796 GValue value = G_VALUE_INIT;
1797 char *error = NULL;
1798
1799 if (column >= gtk_tree_model_get_n_columns (tree_model))
1800 {
1801 g_warning ("%s: Invalid column number %d accessed (remember to end your list of columns with a -1)", G_STRLOC, column);
1802 break;
1803 }
1804
1805 gtk_tree_model_get_value (GTK_TREE_MODEL (tree_model), iter, column, value: &value);
1806
1807 G_VALUE_LCOPY (&value, var_args, 0, &error);
1808 if (error)
1809 {
1810 g_warning ("%s: %s", G_STRLOC, error);
1811 g_free (mem: error);
1812
1813 /* we purposely leak the value here, it might not be
1814 * in a sane state if an error condition occurred
1815 */
1816 break;
1817 }
1818
1819 g_value_unset (value: &value);
1820
1821 column = va_arg (var_args, int);
1822 }
1823}
1824
1825/**
1826 * gtk_tree_model_row_changed:
1827 * @tree_model: a `GtkTreeModel`
1828 * @path: a `GtkTreePath` pointing to the changed row
1829 * @iter: a valid `GtkTreeIter` pointing to the changed row
1830 *
1831 * Emits the ::row-changed signal on @tree_model.
1832 *
1833 * See [signal@Gtk.TreeModel::row-changed].
1834 */
1835void
1836gtk_tree_model_row_changed (GtkTreeModel *tree_model,
1837 GtkTreePath *path,
1838 GtkTreeIter *iter)
1839{
1840 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1841 g_return_if_fail (path != NULL);
1842 g_return_if_fail (iter != NULL);
1843
1844 g_signal_emit (instance: tree_model, signal_id: tree_model_signals[ROW_CHANGED], detail: 0, path, iter);
1845}
1846
1847/**
1848 * gtk_tree_model_row_inserted:
1849 * @tree_model: a `GtkTreeModel`
1850 * @path: a `GtkTreePath` pointing to the inserted row
1851 * @iter: a valid `GtkTreeIter` pointing to the inserted row
1852 *
1853 * Emits the ::row-inserted signal on @tree_model.
1854 *
1855 * See [signal@Gtk.TreeModel::row-inserted].
1856 */
1857void
1858gtk_tree_model_row_inserted (GtkTreeModel *tree_model,
1859 GtkTreePath *path,
1860 GtkTreeIter *iter)
1861{
1862 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1863 g_return_if_fail (path != NULL);
1864 g_return_if_fail (iter != NULL);
1865
1866 g_signal_emit (instance: tree_model, signal_id: tree_model_signals[ROW_INSERTED], detail: 0, path, iter);
1867}
1868
1869/**
1870 * gtk_tree_model_row_has_child_toggled:
1871 * @tree_model: a `GtkTreeModel`
1872 * @path: a `GtkTreePath` pointing to the changed row
1873 * @iter: a valid `GtkTreeIter` pointing to the changed row
1874 *
1875 * Emits the ::row-has-child-toggled signal on @tree_model.
1876 *
1877 * See [signal@Gtk.TreeModel::row-has-child-toggled].
1878 *
1879 * This should be called by models after the child
1880 * state of a node changes.
1881 */
1882void
1883gtk_tree_model_row_has_child_toggled (GtkTreeModel *tree_model,
1884 GtkTreePath *path,
1885 GtkTreeIter *iter)
1886{
1887 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1888 g_return_if_fail (path != NULL);
1889 g_return_if_fail (iter != NULL);
1890
1891 g_signal_emit (instance: tree_model, signal_id: tree_model_signals[ROW_HAS_CHILD_TOGGLED], detail: 0, path, iter);
1892}
1893
1894/**
1895 * gtk_tree_model_row_deleted:
1896 * @tree_model: a `GtkTreeModel`
1897 * @path: a `GtkTreePath` pointing to the previous location of
1898 * the deleted row
1899 *
1900 * Emits the ::row-deleted signal on @tree_model.
1901 *
1902 * See [signal@Gtk.TreeModel::row-deleted].
1903 *
1904 * This should be called by models after a row has been removed.
1905 * The location pointed to by @path should be the location that
1906 * the row previously was at. It may not be a valid location anymore.
1907 *
1908 * Nodes that are deleted are not unreffed, this means that any
1909 * outstanding references on the deleted node should not be released.
1910 */
1911void
1912gtk_tree_model_row_deleted (GtkTreeModel *tree_model,
1913 GtkTreePath *path)
1914{
1915 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1916 g_return_if_fail (path != NULL);
1917
1918 g_signal_emit (instance: tree_model, signal_id: tree_model_signals[ROW_DELETED], detail: 0, path);
1919}
1920
1921/**
1922 * gtk_tree_model_rows_reordered: (skip)
1923 * @tree_model: a `GtkTreeModel`
1924 * @path: a `GtkTreePath` pointing to the tree node whose children
1925 * have been reordered
1926 * @iter: a valid `GtkTreeIter` pointing to the node whose children
1927 * have been reordered, or %NULL if the depth of @path is 0
1928 * @new_order: an array of integers mapping the current position of
1929 * each child to its old position before the re-ordering,
1930 * i.e. @new_order`[newpos] = oldpos`
1931 *
1932 * Emits the ::rows-reordered signal on @tree_model.
1933 *
1934 * See [signal@Gtk.TreeModel::rows-reordered].
1935 *
1936 * This should be called by models when their rows have been
1937 * reordered.
1938 */
1939void
1940gtk_tree_model_rows_reordered (GtkTreeModel *tree_model,
1941 GtkTreePath *path,
1942 GtkTreeIter *iter,
1943 int *new_order)
1944{
1945 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1946 g_return_if_fail (new_order != NULL);
1947
1948 g_signal_emit (instance: tree_model, signal_id: tree_model_signals[ROWS_REORDERED], detail: 0, path, iter, new_order);
1949}
1950
1951/**
1952 * gtk_tree_model_rows_reordered_with_length: (rename-to gtk_tree_model_rows_reordered)
1953 * @tree_model: a `GtkTreeModel`
1954 * @path: a `GtkTreePath` pointing to the tree node whose children
1955 * have been reordered
1956 * @iter: (nullable): a valid `GtkTreeIter` pointing to the node
1957 * whose children have been reordered, or %NULL if the depth
1958 * of @path is 0
1959 * @new_order: (array length=length): an array of integers
1960 * mapping the current position of each child to its old
1961 * position before the re-ordering,
1962 * i.e. @new_order`[newpos] = oldpos`
1963 * @length: length of @new_order array
1964 *
1965 * Emits the ::rows-reordered signal on @tree_model.
1966 *
1967 * See [signal@Gtk.TreeModel::rows-reordered].
1968 *
1969 * This should be called by models when their rows have been
1970 * reordered.
1971 */
1972void
1973gtk_tree_model_rows_reordered_with_length (GtkTreeModel *tree_model,
1974 GtkTreePath *path,
1975 GtkTreeIter *iter,
1976 int *new_order,
1977 int length)
1978{
1979 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1980 g_return_if_fail (new_order != NULL);
1981 g_return_if_fail (length == gtk_tree_model_iter_n_children (tree_model, iter));
1982
1983 g_signal_emit (instance: tree_model, signal_id: tree_model_signals[ROWS_REORDERED], detail: 0, path, iter, new_order);
1984}
1985
1986static gboolean
1987gtk_tree_model_foreach_helper (GtkTreeModel *model,
1988 GtkTreeIter *iter,
1989 GtkTreePath *path,
1990 GtkTreeModelForeachFunc func,
1991 gpointer user_data)
1992{
1993 gboolean iters_persist;
1994
1995 iters_persist = gtk_tree_model_get_flags (tree_model: model) & GTK_TREE_MODEL_ITERS_PERSIST;
1996
1997 do
1998 {
1999 GtkTreeIter child;
2000
2001 if ((* func) (model, path, iter, user_data))
2002 return TRUE;
2003
2004 if (!iters_persist)
2005 {
2006 if (!gtk_tree_model_get_iter (tree_model: model, iter, path))
2007 return TRUE;
2008 }
2009
2010 if (gtk_tree_model_iter_children (tree_model: model, iter: &child, parent: iter))
2011 {
2012 gtk_tree_path_down (path);
2013 if (gtk_tree_model_foreach_helper (model, iter: &child, path, func, user_data))
2014 return TRUE;
2015 gtk_tree_path_up (path);
2016 }
2017
2018 gtk_tree_path_next (path);
2019 }
2020 while (gtk_tree_model_iter_next (tree_model: model, iter));
2021
2022 return FALSE;
2023}
2024
2025/**
2026 * gtk_tree_model_foreach:
2027 * @model: a `GtkTreeModel`
2028 * @func: (scope call): a function to be called on each row
2029 * @user_data: (closure): user data to passed to @func
2030 *
2031 * Calls @func on each node in model in a depth-first fashion.
2032 *
2033 * If @func returns %TRUE, then the tree ceases to be walked,
2034 * and gtk_tree_model_foreach() returns.
2035 */
2036void
2037gtk_tree_model_foreach (GtkTreeModel *model,
2038 GtkTreeModelForeachFunc func,
2039 gpointer user_data)
2040{
2041 GtkTreePath *path;
2042 GtkTreeIter iter;
2043
2044 g_return_if_fail (GTK_IS_TREE_MODEL (model));
2045 g_return_if_fail (func != NULL);
2046
2047 path = gtk_tree_path_new_first ();
2048 if (!gtk_tree_model_get_iter (tree_model: model, iter: &iter, path))
2049 {
2050 gtk_tree_path_free (path);
2051 return;
2052 }
2053
2054 gtk_tree_model_foreach_helper (model, iter: &iter, path, func, user_data);
2055 gtk_tree_path_free (path);
2056}
2057
2058
2059/*
2060 * GtkTreeRowReference
2061 */
2062
2063static void gtk_tree_row_reference_unref_path (GtkTreePath *path,
2064 GtkTreeModel *model,
2065 int depth);
2066
2067
2068G_DEFINE_BOXED_TYPE (GtkTreeRowReference, gtk_tree_row_reference,
2069 gtk_tree_row_reference_copy,
2070 gtk_tree_row_reference_free)
2071
2072struct _GtkTreeRowReference
2073{
2074 GObject *proxy;
2075 GtkTreeModel *model;
2076 GtkTreePath *path;
2077};
2078
2079
2080static void
2081release_row_references (gpointer data)
2082{
2083 RowRefList *refs = data;
2084 GSList *tmp_list = NULL;
2085
2086 tmp_list = refs->list;
2087 while (tmp_list != NULL)
2088 {
2089 GtkTreeRowReference *reference = tmp_list->data;
2090
2091 if (reference->proxy == (GObject *)reference->model)
2092 reference->model = NULL;
2093 reference->proxy = NULL;
2094
2095 /* we don't free the reference, users are responsible for that. */
2096
2097 tmp_list = tmp_list->next;
2098 }
2099
2100 g_slist_free (list: refs->list);
2101 g_free (mem: refs);
2102}
2103
2104static void
2105gtk_tree_row_ref_inserted (RowRefList *refs,
2106 GtkTreePath *path,
2107 GtkTreeIter *iter)
2108{
2109 GSList *tmp_list;
2110
2111 if (refs == NULL)
2112 return;
2113
2114 /* This function corrects the path stored in the reference to
2115 * account for an insertion. Note that it's called _after_ the
2116 * insertion with the path to the newly-inserted row. Which means
2117 * that the inserted path is in a different "coordinate system" than
2118 * the old path (e.g. if the inserted path was just before the old
2119 * path, then inserted path and old path will be the same, and old
2120 * path must be moved down one).
2121 */
2122
2123 tmp_list = refs->list;
2124
2125 while (tmp_list != NULL)
2126 {
2127 GtkTreeRowReference *reference = tmp_list->data;
2128
2129 if (reference->path == NULL)
2130 goto done;
2131
2132 if (reference->path->depth >= path->depth)
2133 {
2134 int i;
2135 gboolean ancestor = TRUE;
2136
2137 for (i = 0; i < path->depth - 1; i ++)
2138 {
2139 if (path->indices[i] != reference->path->indices[i])
2140 {
2141 ancestor = FALSE;
2142 break;
2143 }
2144 }
2145 if (ancestor == FALSE)
2146 goto done;
2147
2148 if (path->indices[path->depth-1] <= reference->path->indices[path->depth-1])
2149 reference->path->indices[path->depth-1] += 1;
2150 }
2151 done:
2152 tmp_list = tmp_list->next;
2153 }
2154}
2155
2156static void
2157gtk_tree_row_ref_deleted (RowRefList *refs,
2158 GtkTreePath *path)
2159{
2160 GSList *tmp_list;
2161
2162 if (refs == NULL)
2163 return;
2164
2165 /* This function corrects the path stored in the reference to
2166 * account for a deletion. Note that it's called _after_ the
2167 * deletion with the old path of the just-deleted row. Which means
2168 * that the deleted path is the same now-defunct "coordinate system"
2169 * as the path saved in the reference, which is what we want to fix.
2170 */
2171
2172 tmp_list = refs->list;
2173
2174 while (tmp_list != NULL)
2175 {
2176 GtkTreeRowReference *reference = tmp_list->data;
2177
2178 if (reference->path)
2179 {
2180 int i;
2181
2182 if (path->depth > reference->path->depth)
2183 goto next;
2184 for (i = 0; i < path->depth - 1; i++)
2185 {
2186 if (path->indices[i] != reference->path->indices[i])
2187 goto next;
2188 }
2189
2190 /* We know it affects us. */
2191 if (path->indices[i] == reference->path->indices[i])
2192 {
2193 if (reference->path->depth > path->depth)
2194 /* some parent was deleted, trying to unref any node
2195 * between the deleted parent and the node the reference
2196 * is pointing to is bad, as those nodes are already gone.
2197 */
2198 gtk_tree_row_reference_unref_path (path: reference->path, model: reference->model, depth: path->depth - 1);
2199 else
2200 gtk_tree_row_reference_unref_path (path: reference->path, model: reference->model, depth: reference->path->depth - 1);
2201 gtk_tree_path_free (path: reference->path);
2202 reference->path = NULL;
2203 }
2204 else if (path->indices[i] < reference->path->indices[i])
2205 {
2206 reference->path->indices[path->depth-1]-=1;
2207 }
2208 }
2209
2210next:
2211 tmp_list = tmp_list->next;
2212 }
2213}
2214
2215static void
2216gtk_tree_row_ref_reordered (RowRefList *refs,
2217 GtkTreePath *path,
2218 GtkTreeIter *iter,
2219 int *new_order)
2220{
2221 GSList *tmp_list;
2222 int length;
2223
2224 if (refs == NULL)
2225 return;
2226
2227 tmp_list = refs->list;
2228
2229 while (tmp_list != NULL)
2230 {
2231 GtkTreeRowReference *reference = tmp_list->data;
2232
2233 length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (reference->model), iter);
2234
2235 if (length < 2)
2236 return;
2237
2238 if ((reference->path) &&
2239 (gtk_tree_path_is_ancestor (path, descendant: reference->path)))
2240 {
2241 int ref_depth = gtk_tree_path_get_depth (path: reference->path);
2242 int depth = gtk_tree_path_get_depth (path);
2243
2244 if (ref_depth > depth)
2245 {
2246 int i;
2247 int *indices = gtk_tree_path_get_indices (path: reference->path);
2248
2249 for (i = 0; i < length; i++)
2250 {
2251 if (new_order[i] == indices[depth])
2252 {
2253 indices[depth] = i;
2254 break;
2255 }
2256 }
2257 }
2258 }
2259
2260 tmp_list = tmp_list->next;
2261 }
2262}
2263
2264/* We do this recursively so that we can unref children nodes
2265 * before their parent
2266 */
2267static void
2268gtk_tree_row_reference_unref_path_helper (GtkTreePath *path,
2269 GtkTreeModel *model,
2270 GtkTreeIter *parent_iter,
2271 int depth,
2272 int current_depth)
2273{
2274 GtkTreeIter iter;
2275
2276 if (depth == current_depth)
2277 return;
2278
2279 gtk_tree_model_iter_nth_child (tree_model: model, iter: &iter, parent: parent_iter, n: path->indices[current_depth]);
2280 gtk_tree_row_reference_unref_path_helper (path, model, parent_iter: &iter, depth, current_depth: current_depth + 1);
2281 gtk_tree_model_unref_node (tree_model: model, iter: &iter);
2282}
2283
2284static void
2285gtk_tree_row_reference_unref_path (GtkTreePath *path,
2286 GtkTreeModel *model,
2287 int depth)
2288{
2289 GtkTreeIter iter;
2290
2291 if (depth <= 0)
2292 return;
2293
2294 gtk_tree_model_iter_nth_child (tree_model: model, iter: &iter, NULL, n: path->indices[0]);
2295 gtk_tree_row_reference_unref_path_helper (path, model, parent_iter: &iter, depth, current_depth: 1);
2296 gtk_tree_model_unref_node (tree_model: model, iter: &iter);
2297}
2298
2299/**
2300 * gtk_tree_row_reference_new:
2301 * @model: a `GtkTreeModel`
2302 * @path: a valid `GtkTreePath` to monitor
2303 *
2304 * Creates a row reference based on @path.
2305 *
2306 * This reference will keep pointing to the node pointed to
2307 * by @path, so long as it exists. Any changes that occur on @model are
2308 * propagated, and the path is updated appropriately. If
2309 * @path isn’t a valid path in @model, then %NULL is returned.
2310 *
2311 * Returns: (nullable): a newly allocated `GtkTreeRowReference`
2312 */
2313GtkTreeRowReference *
2314gtk_tree_row_reference_new (GtkTreeModel *model,
2315 GtkTreePath *path)
2316{
2317 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
2318 g_return_val_if_fail (path != NULL, NULL);
2319
2320 /* We use the model itself as the proxy object; and call
2321 * gtk_tree_row_reference_inserted(), etc, in the
2322 * class closure (default handler) marshalers for the signal.
2323 */
2324 return gtk_tree_row_reference_new_proxy (G_OBJECT (model), model, path);
2325}
2326
2327/**
2328 * gtk_tree_row_reference_new_proxy:
2329 * @proxy: a proxy `GObject`
2330 * @model: a `GtkTreeModel`
2331 * @path: a valid `GtkTreePath` to monitor
2332 *
2333 * You do not need to use this function.
2334 *
2335 * Creates a row reference based on @path.
2336 *
2337 * This reference will keep pointing to the node pointed to
2338 * by @path, so long as it exists. If @path isn’t a valid
2339 * path in @model, then %NULL is returned. However, unlike
2340 * references created with gtk_tree_row_reference_new(), it
2341 * does not listen to the model for changes. The creator of
2342 * the row reference must do this explicitly using
2343 * gtk_tree_row_reference_inserted(), gtk_tree_row_reference_deleted(),
2344 * gtk_tree_row_reference_reordered().
2345 *
2346 * These functions must be called exactly once per proxy when the
2347 * corresponding signal on the model is emitted. This single call
2348 * updates all row references for that proxy. Since built-in GTK
2349 * objects like `GtkTreeView` already use this mechanism internally,
2350 * using them as the proxy object will produce unpredictable results.
2351 * Further more, passing the same object as @model and @proxy
2352 * doesn’t work for reasons of internal implementation.
2353 *
2354 * This type of row reference is primarily meant by structures that
2355 * need to carefully monitor exactly when a row reference updates
2356 * itself, and is not generally needed by most applications.
2357 *
2358 * Returns: (nullable): a newly allocated `GtkTreeRowReference`
2359 */
2360GtkTreeRowReference *
2361gtk_tree_row_reference_new_proxy (GObject *proxy,
2362 GtkTreeModel *model,
2363 GtkTreePath *path)
2364{
2365 GtkTreeRowReference *reference;
2366 RowRefList *refs;
2367 GtkTreeIter parent_iter;
2368 int i;
2369
2370 g_return_val_if_fail (G_IS_OBJECT (proxy), NULL);
2371 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
2372 g_return_val_if_fail (path != NULL, NULL);
2373 g_return_val_if_fail (path->depth > 0, NULL);
2374
2375 /* check that the path is valid */
2376 if (gtk_tree_model_get_iter (tree_model: model, iter: &parent_iter, path) == FALSE)
2377 return NULL;
2378
2379 /* Now we want to ref every node */
2380 gtk_tree_model_iter_nth_child (tree_model: model, iter: &parent_iter, NULL, n: path->indices[0]);
2381 gtk_tree_model_ref_node (tree_model: model, iter: &parent_iter);
2382
2383 for (i = 1; i < path->depth; i++)
2384 {
2385 GtkTreeIter iter;
2386 gtk_tree_model_iter_nth_child (tree_model: model, iter: &iter, parent: &parent_iter, n: path->indices[i]);
2387 gtk_tree_model_ref_node (tree_model: model, iter: &iter);
2388 parent_iter = iter;
2389 }
2390
2391 /* Make the row reference */
2392 reference = g_new (GtkTreeRowReference, 1);
2393
2394 g_object_ref (proxy);
2395 g_object_ref (model);
2396 reference->proxy = proxy;
2397 reference->model = model;
2398 reference->path = gtk_tree_path_copy (path);
2399
2400 refs = g_object_get_data (G_OBJECT (proxy), ROW_REF_DATA_STRING);
2401
2402 if (refs == NULL)
2403 {
2404 refs = g_new (RowRefList, 1);
2405 refs->list = NULL;
2406
2407 g_object_set_data_full (G_OBJECT (proxy),
2408 I_(ROW_REF_DATA_STRING),
2409 data: refs, destroy: release_row_references);
2410 }
2411
2412 refs->list = g_slist_prepend (list: refs->list, data: reference);
2413
2414 return reference;
2415}
2416
2417/**
2418 * gtk_tree_row_reference_get_path:
2419 * @reference: a `GtkTreeRowReference`
2420 *
2421 * Returns a path that the row reference currently points to,
2422 * or %NULL if the path pointed to is no longer valid.
2423 *
2424 * Returns: (nullable) (transfer full): a current path
2425 */
2426GtkTreePath *
2427gtk_tree_row_reference_get_path (GtkTreeRowReference *reference)
2428{
2429 g_return_val_if_fail (reference != NULL, NULL);
2430
2431 if (reference->proxy == NULL)
2432 return NULL;
2433
2434 if (reference->path == NULL)
2435 return NULL;
2436
2437 return gtk_tree_path_copy (path: reference->path);
2438}
2439
2440/**
2441 * gtk_tree_row_reference_get_model:
2442 * @reference: a `GtkTreeRowReference`
2443 *
2444 * Returns the model that the row reference is monitoring.
2445 *
2446 * Returns: (transfer none): the model
2447 */
2448GtkTreeModel *
2449gtk_tree_row_reference_get_model (GtkTreeRowReference *reference)
2450{
2451 g_return_val_if_fail (reference != NULL, NULL);
2452
2453 return reference->model;
2454}
2455
2456/**
2457 * gtk_tree_row_reference_valid:
2458 * @reference: (nullable): a `GtkTreeRowReference`
2459 *
2460 * Returns %TRUE if the @reference is non-%NULL and refers to
2461 * a current valid path.
2462 *
2463 * Returns: %TRUE if @reference points to a valid path
2464 */
2465gboolean
2466gtk_tree_row_reference_valid (GtkTreeRowReference *reference)
2467{
2468 if (reference == NULL || reference->path == NULL)
2469 return FALSE;
2470
2471 return TRUE;
2472}
2473
2474
2475/**
2476 * gtk_tree_row_reference_copy:
2477 * @reference: a `GtkTreeRowReference`
2478 *
2479 * Copies a `GtkTreeRowReference`.
2480 *
2481 * Returns: a copy of @reference
2482 */
2483GtkTreeRowReference *
2484gtk_tree_row_reference_copy (GtkTreeRowReference *reference)
2485{
2486 return gtk_tree_row_reference_new_proxy (proxy: reference->proxy,
2487 model: reference->model,
2488 path: reference->path);
2489}
2490
2491/**
2492 * gtk_tree_row_reference_free:
2493 * @reference: (nullable): a `GtkTreeRowReference`
2494 *
2495 * Free’s @reference. @reference may be %NULL
2496 */
2497void
2498gtk_tree_row_reference_free (GtkTreeRowReference *reference)
2499{
2500 RowRefList *refs;
2501
2502 if (reference == NULL)
2503 return;
2504
2505 refs = g_object_get_data (G_OBJECT (reference->proxy), ROW_REF_DATA_STRING);
2506
2507 if (refs == NULL)
2508 {
2509 g_warning (G_STRLOC": bad row reference, proxy has no outstanding row references");
2510 return;
2511 }
2512
2513 refs->list = g_slist_remove (list: refs->list, data: reference);
2514
2515 if (refs->list == NULL)
2516 {
2517 g_object_set_data (G_OBJECT (reference->proxy),
2518 I_(ROW_REF_DATA_STRING),
2519 NULL);
2520 }
2521
2522 if (reference->path)
2523 {
2524 gtk_tree_row_reference_unref_path (path: reference->path, model: reference->model, depth: reference->path->depth);
2525 gtk_tree_path_free (path: reference->path);
2526 }
2527
2528 g_object_unref (object: reference->proxy);
2529 g_object_unref (object: reference->model);
2530 g_free (mem: reference);
2531}
2532
2533/**
2534 * gtk_tree_row_reference_inserted:
2535 * @proxy: a `GObject`
2536 * @path: the row position that was inserted
2537 *
2538 * Lets a set of row reference created by
2539 * gtk_tree_row_reference_new_proxy() know that the
2540 * model emitted the ::row-inserted signal.
2541 */
2542void
2543gtk_tree_row_reference_inserted (GObject *proxy,
2544 GtkTreePath *path)
2545{
2546 g_return_if_fail (G_IS_OBJECT (proxy));
2547
2548 gtk_tree_row_ref_inserted (refs: (RowRefList *)g_object_get_data (object: proxy, ROW_REF_DATA_STRING), path, NULL);
2549}
2550
2551/**
2552 * gtk_tree_row_reference_deleted:
2553 * @proxy: a `GObject`
2554 * @path: the path position that was deleted
2555 *
2556 * Lets a set of row reference created by
2557 * gtk_tree_row_reference_new_proxy() know that the
2558 * model emitted the ::row-deleted signal.
2559 */
2560void
2561gtk_tree_row_reference_deleted (GObject *proxy,
2562 GtkTreePath *path)
2563{
2564 g_return_if_fail (G_IS_OBJECT (proxy));
2565
2566 gtk_tree_row_ref_deleted (refs: (RowRefList *)g_object_get_data (object: proxy, ROW_REF_DATA_STRING), path);
2567}
2568
2569/**
2570 * gtk_tree_row_reference_reordered: (skip)
2571 * @proxy: a `GObject`
2572 * @path: the parent path of the reordered signal
2573 * @iter: the iter pointing to the parent of the reordered
2574 * @new_order: (array): the new order of rows
2575 *
2576 * Lets a set of row reference created by
2577 * gtk_tree_row_reference_new_proxy() know that the
2578 * model emitted the ::rows-reordered signal.
2579 */
2580void
2581gtk_tree_row_reference_reordered (GObject *proxy,
2582 GtkTreePath *path,
2583 GtkTreeIter *iter,
2584 int *new_order)
2585{
2586 g_return_if_fail (G_IS_OBJECT (proxy));
2587
2588 gtk_tree_row_ref_reordered (refs: (RowRefList *)g_object_get_data (object: proxy, ROW_REF_DATA_STRING), path, iter, new_order);
2589}
2590

source code of gtk/gtk/gtktreemodel.c