1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * pygtk- Python bindings for the GTK toolkit.
3  * Copyright (C) 1998-2003  James Henstridge
4  *
5  *   pygtktreemodel.c: stub class to help implement tree models.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20  * USA
21  */
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25 
26 #include "pygtktreemodel.h"
27 #include "pygtk-private.h"
28 
29 /* define this to print out debug messages */
30 #undef DEBUG_TREE_MODEL
31 
32 #ifndef _
33 #  define _(s) (s)
34 #endif
35 
36 #define VALID_ITER(iter, tree_model) \
37  (iter != NULL && iter->stamp == PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp)
38 
39 enum {
40     PROP_LEAK_REFERENCES = 1
41 };
42 
43 static void pygtk_generic_tree_model_class_init(PyGtkGenericTreeModelClass *klass);
44 static void pygtk_generic_tree_model_init(PyGtkGenericTreeModel *self);
45 static void pygtk_generic_tree_model_iface_init(GtkTreeModelIface *iface);
46 static void pygtk_generic_tree_model_set_property (GObject *object,
47 						   guint property_id,
48 						   const GValue *value,
49 						   GParamSpec *pspec);
50 static void pygtk_generic_tree_model_get_property (GObject *object,
51 						   guint property_id,
52 						   GValue *value,
53 						   GParamSpec *pspec);
54 
55 
56 GType
pygtk_generic_tree_model_get_type(void)57 pygtk_generic_tree_model_get_type(void)
58 {
59     static GType object_type = 0;
60 
61     if (!object_type) {
62 	static const GTypeInfo object_info = {
63 	    sizeof(PyGtkGenericTreeModelClass),
64 	    (GBaseInitFunc) NULL,
65 	    (GBaseFinalizeFunc) NULL,
66 	    (GClassInitFunc) pygtk_generic_tree_model_class_init,
67 	    NULL, /* class_finalize */
68 	    NULL, /* class_data */
69 	    sizeof(PyGtkGenericTreeModel),
70 	    0, /* n_preallocs */
71 	    (GInstanceInitFunc) pygtk_generic_tree_model_init,
72 	};
73 	static const GInterfaceInfo tree_model_info = {
74 	    (GInterfaceInitFunc) pygtk_generic_tree_model_iface_init,
75 	    NULL,
76 	    NULL,
77 	};
78 
79 	object_type = g_type_register_static(G_TYPE_OBJECT,
80 					     "PyGtkGenericTreeModel",
81 					     &object_info, 0);
82 	g_type_add_interface_static(object_type,
83 				    GTK_TYPE_TREE_MODEL,
84 				    &tree_model_info);
85     }
86     return object_type;
87 }
88 
89 static void
pygtk_generic_tree_model_class_init(PyGtkGenericTreeModelClass * klass)90 pygtk_generic_tree_model_class_init(PyGtkGenericTreeModelClass *klass)
91 {
92     GObjectClass *object_class = (GObjectClass*) klass;
93 
94     object_class->get_property = pygtk_generic_tree_model_get_property;
95     object_class->set_property = pygtk_generic_tree_model_set_property;
96 
97     g_object_class_install_property (object_class,
98 				     PROP_LEAK_REFERENCES,
99 				     g_param_spec_boolean ("leak_references",
100 					_("Leak references"),
101 					_("Enable referencing iterator "
102 	"objects (this will cause a memory leak or at least a reference "
103 	"counting leak). You might need it though, if you return newly "
104 	"created objects."),
105 					TRUE,
106 					G_PARAM_READWRITE));
107 }
108 
109 static guint pygtk_generic_tree_model_get_flags(GtkTreeModel *tree_model);
110 static gint pygtk_generic_tree_model_get_n_columns(GtkTreeModel *tree_model);
111 static GType pygtk_generic_tree_model_get_column_type(GtkTreeModel *tree_model,
112 					      gint index);
113 static gboolean pygtk_generic_tree_model_get_iter(GtkTreeModel *tree_model,
114 					  GtkTreeIter *iter,
115 					  GtkTreePath *path);
116 static GtkTreePath *pygtk_generic_tree_model_get_path(GtkTreeModel *tree_model,
117 					      GtkTreeIter *iter);
118 static void pygtk_generic_tree_model_get_value(GtkTreeModel*tree_model,
119 				       GtkTreeIter *iter,
120 				       gint column, GValue *value);
121 static gboolean pygtk_generic_tree_model_iter_next(GtkTreeModel *tree_model,
122 					   GtkTreeIter *iter);
123 static gboolean pygtk_generic_tree_model_iter_children(GtkTreeModel *tree_model,
124 					       GtkTreeIter *iter,
125 					       GtkTreeIter *parent);
126 static gboolean pygtk_generic_tree_model_iter_has_child(GtkTreeModel *tree_model,
127 						GtkTreeIter *iter);
128 static gint pygtk_generic_tree_model_iter_n_children(GtkTreeModel *tree_model,
129 					     GtkTreeIter *iter);
130 static gboolean pygtk_generic_tree_model_iter_nth_child(GtkTreeModel *tree_model,
131 						GtkTreeIter  *iter,
132 						GtkTreeIter  *parent,
133 						gint n);
134 static gboolean pygtk_generic_tree_model_iter_parent(GtkTreeModel *tree_model,
135 					     GtkTreeIter *iter,
136 					     GtkTreeIter *child);
137 static void pygtk_generic_tree_model_unref_node(GtkTreeModel *tree_model,
138 					     GtkTreeIter *iter);
139 static void pygtk_generic_tree_model_ref_node(GtkTreeModel *tree_model,
140 					     GtkTreeIter *iter);
141 
142 static void
pygtk_generic_tree_model_iface_init(GtkTreeModelIface * iface)143 pygtk_generic_tree_model_iface_init(GtkTreeModelIface *iface)
144 {
145   iface->get_flags = pygtk_generic_tree_model_get_flags;
146   iface->get_n_columns = pygtk_generic_tree_model_get_n_columns;
147   iface->get_column_type = pygtk_generic_tree_model_get_column_type;
148   iface->get_iter = pygtk_generic_tree_model_get_iter;
149   iface->get_path = pygtk_generic_tree_model_get_path;
150   iface->get_value = pygtk_generic_tree_model_get_value;
151   iface->iter_next = pygtk_generic_tree_model_iter_next;
152   iface->iter_children = pygtk_generic_tree_model_iter_children;
153   iface->iter_has_child = pygtk_generic_tree_model_iter_has_child;
154   iface->iter_n_children = pygtk_generic_tree_model_iter_n_children;
155   iface->iter_nth_child = pygtk_generic_tree_model_iter_nth_child;
156   iface->iter_parent = pygtk_generic_tree_model_iter_parent;
157   iface->ref_node = pygtk_generic_tree_model_ref_node;
158   iface->unref_node = pygtk_generic_tree_model_unref_node;
159 
160 }
161 
162 static void
pygtk_generic_tree_model_init(PyGtkGenericTreeModel * self)163 pygtk_generic_tree_model_init(PyGtkGenericTreeModel *self)
164 {
165     self->leak_references = TRUE;
166     do {
167         self->stamp = g_random_int();
168     } while (self->stamp == 0);
169 }
170 
171 static void
pygtk_generic_tree_model_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)172 pygtk_generic_tree_model_set_property (GObject *object, guint property_id,
173 				       const GValue *value, GParamSpec *pspec)
174 {
175     switch (property_id) {
176     case PROP_LEAK_REFERENCES:
177 	PYGTK_GENERIC_TREE_MODEL (object)->leak_references = g_value_get_boolean (value);
178 	break;
179     default:
180 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
181 	break;
182     }
183  }
184 
185 static void
pygtk_generic_tree_model_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)186 pygtk_generic_tree_model_get_property (GObject *object, guint property_id,
187 				       GValue *value, GParamSpec *pspec)
188 {
189     switch (property_id) {
190     case PROP_LEAK_REFERENCES:
191 	g_value_set_boolean (value,
192 			    PYGTK_GENERIC_TREE_MODEL (object)->leak_references);
193 	break;
194     default:
195 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
196 	break;
197     }
198 }
199 
200 
201 PyGtkGenericTreeModel *
pygtk_generic_tree_model_new(void)202 pygtk_generic_tree_model_new(void)
203 {
204     return PYGTK_GENERIC_TREE_MODEL(
205 	g_object_new(PYGTK_TYPE_GENERIC_TREE_MODEL, NULL));
206 }
207 
208 
209 /* format of GtkTreeIter's for PyGtkGenericTreeModel:
210  *  user_data == python object
211  *  user_data2 == floating reference?
212  *
213  * I haven't worked out how everything should work.  For now I will
214  * leak references.
215  */
216 
217 #define METHOD_PREFIX "on_"
218 
219 static guint
pygtk_generic_tree_model_get_flags(GtkTreeModel * tree_model)220 pygtk_generic_tree_model_get_flags(GtkTreeModel *tree_model)
221 {
222     PyGILState_STATE state;
223     PyObject *self, *py_ret;
224     guint ret = 0;
225     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), 0);
226 
227     state = pyg_gil_state_ensure();
228 
229     /* this call finds the wrapper for this GObject */
230     self = pygobject_new((GObject *)tree_model);
231 
232 #ifdef DEBUG_TREE_MODEL
233     g_message("get_flags()");
234 #endif
235     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_flags", "");
236     Py_DECREF(self);
237     if (py_ret) {
238 	ret = PyInt_AsLong(py_ret);
239 	Py_DECREF(py_ret);
240     } else {
241 	PyErr_Print();
242     }
243 
244     pyg_gil_state_release(state);
245     return ret;
246 }
247 
248 static gint
pygtk_generic_tree_model_get_n_columns(GtkTreeModel * tree_model)249 pygtk_generic_tree_model_get_n_columns(GtkTreeModel *tree_model)
250 {
251     PyGILState_STATE state;
252     PyObject *self, *py_ret;
253     gint ret = 0;
254 
255     g_return_val_if_fail(tree_model != NULL, 0);
256     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), 0);
257 
258     state = pyg_gil_state_ensure();
259 
260     /* this call finds the wrapper for this GObject */
261     self = pygobject_new((GObject *)tree_model);
262 
263 #ifdef DEBUG_TREE_MODEL
264     g_message("get_n_columns()");
265 #endif
266     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_n_columns", "");
267     Py_DECREF(self);
268     if (py_ret) {
269 	ret = PyInt_AsLong(py_ret);
270 	Py_DECREF(py_ret);
271     } else {
272 	PyErr_Print();
273     }
274     pyg_gil_state_release(state);
275     return ret;
276 }
277 
278 static GType
pygtk_generic_tree_model_get_column_type(GtkTreeModel * tree_model,gint index)279 pygtk_generic_tree_model_get_column_type(GtkTreeModel *tree_model, gint index)
280 {
281     PyGILState_STATE state;
282     PyObject *self, *py_ret;
283     GType ret = G_TYPE_INVALID;
284 
285     g_return_val_if_fail(tree_model != NULL, G_TYPE_INVALID);
286     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), G_TYPE_INVALID);
287     state = pyg_gil_state_ensure();
288 
289     /* this call finds the wrapper for this GObject */
290     self = pygobject_new((GObject *)tree_model);
291 
292 #ifdef DEBUG_TREE_MODEL
293     g_message("get_column_type(%d)", index);
294 #endif
295     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_column_type",
296 				 "(i)", index);
297     Py_DECREF(self);
298     if (py_ret) {
299 	ret = pyg_type_from_object(py_ret);
300 	Py_DECREF(py_ret);
301     } else {
302 	PyErr_Print();
303     }
304     pyg_gil_state_release(state);
305     return ret;
306 }
307 
308 static gboolean
pygtk_generic_tree_model_get_iter(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreePath * path)309 pygtk_generic_tree_model_get_iter(GtkTreeModel *tree_model,
310                                   GtkTreeIter *iter, GtkTreePath *path)
311 {
312     PyGILState_STATE state;
313     PyObject *self, *py_path, *py_ret;
314     gboolean ret = FALSE;
315 
316     g_return_val_if_fail(tree_model != NULL, FALSE);
317     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE);
318     g_return_val_if_fail(iter != NULL, FALSE);
319     g_return_val_if_fail(path != NULL, FALSE);
320 
321     state = pyg_gil_state_ensure();
322 
323     /* this call finds the wrapper for this GObject */
324     self = pygobject_new((GObject *)tree_model);
325 
326 #ifdef DEBUG_TREE_MODEL
327     g_message("get_iter(%p)", path);
328 #endif
329     py_path = pygtk_tree_path_to_pyobject(path);
330     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_iter",
331 				 "(O)", py_path);
332     Py_DECREF(self);
333     Py_DECREF(py_path);
334 
335     if (py_ret) {
336 	if (py_ret != Py_None) {
337 	    iter->user_data = py_ret;
338             iter->stamp = PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp;
339 	    if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) {
340 		Py_DECREF((PyObject *)iter->user_data);
341 	    }
342 	    ret = TRUE;
343 	} else {
344 	    iter->user_data = NULL;
345 	    Py_DECREF(py_ret);
346 	}
347     } else {
348 	PyErr_Print();
349 	iter->user_data = NULL;
350     }
351 
352     pyg_gil_state_release(state);
353     return ret;
354 }
355 
356 static GtkTreePath *
pygtk_generic_tree_model_get_path(GtkTreeModel * tree_model,GtkTreeIter * iter)357 pygtk_generic_tree_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter)
358 {
359     PyGILState_STATE state;
360     PyObject *self, *py_ret, *py_iter;
361     GtkTreePath *path = NULL;
362 
363     g_return_val_if_fail(tree_model != NULL, NULL);
364     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), NULL);
365     g_return_val_if_fail(VALID_ITER(iter, tree_model), NULL);
366 
367     state = pyg_gil_state_ensure();
368 
369     /* this call finds the wrapper for this GObject */
370     self = pygobject_new((GObject *)tree_model);
371 
372 #ifdef DEBUG_TREE_MODEL
373     g_message("get_path(%p)", iter);
374 #endif
375     py_iter = (PyObject *)iter->user_data;
376     if (py_iter == NULL)
377 	py_iter = Py_None;
378 
379     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_path", "(O)",
380                                  py_iter);
381     Py_DECREF(self);
382     if (py_ret) {
383 	path = pygtk_tree_path_from_pyobject(py_ret);
384 
385 	if (!path)
386 	    g_warning("could not convert return value of get_path() to "
387 		      "a GtkTreePath");
388 	Py_DECREF(py_ret);
389     } else {
390 	PyErr_Print();
391     }
392 
393     pyg_gil_state_release(state);
394     return path;
395 }
396 
397 static void
pygtk_generic_tree_model_get_value(GtkTreeModel * tree_model,GtkTreeIter * iter,gint column,GValue * value)398 pygtk_generic_tree_model_get_value(GtkTreeModel*tree_model, GtkTreeIter *iter,
399                                    gint column, GValue *value)
400 {
401     PyGILState_STATE state;
402     PyObject *self, *py_value, *py_iter;
403 
404     g_return_if_fail(tree_model != NULL);
405     g_return_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model));
406     g_return_if_fail(VALID_ITER(iter, tree_model));
407 
408     state = pyg_gil_state_ensure();
409 
410     /* this call finds the wrapper for this GObject */
411     self = pygobject_new((GObject *)tree_model);
412 
413 #ifdef DEBUG_TREE_MODEL
414     g_message("get_value(%p, %d)", iter, column);
415     _PyObject_Dump (iter->user_data);
416 #endif
417     /* init value to column type */
418     g_value_init(value, pygtk_generic_tree_model_get_column_type(tree_model,
419                                                                  column));
420 
421     py_iter = (PyObject *)iter->user_data;
422     if (py_iter == NULL)
423 	py_iter = Py_None;
424     py_value = PyObject_CallMethod(self, METHOD_PREFIX "get_value",
425 				   "(Oi)", py_iter,column);
426     Py_DECREF(self);
427 
428     if (py_value) {
429         if (py_value != Py_None)
430             pyg_value_from_pyobject(value, py_value);
431         Py_DECREF(py_value);
432     } else {
433 	PyErr_Print();
434     }
435     pyg_gil_state_release(state);
436 }
437 
438 static gboolean
pygtk_generic_tree_model_iter_next(GtkTreeModel * tree_model,GtkTreeIter * iter)439 pygtk_generic_tree_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter)
440 {
441     PyGILState_STATE state;
442     PyObject *self, *py_ret, *py_iter;
443     gboolean ret = FALSE;
444 
445     g_return_val_if_fail(tree_model != NULL, FALSE);
446     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE);
447     g_return_val_if_fail(VALID_ITER(iter, tree_model), FALSE);
448 
449     state = pyg_gil_state_ensure();
450 
451     /* this call finds the wrapper for this GObject */
452     self = pygobject_new((GObject *)tree_model);
453 
454 #ifdef DEBUG_TREE_MODEL
455     g_message("iter_next(%p)", iter);
456 #endif
457     py_iter = (PyObject *)iter->user_data;
458     if (py_iter == NULL)
459 	py_iter = Py_None;
460 
461     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_next", "(O)",
462                                  py_iter);
463     Py_DECREF(self);
464     if (py_ret) {
465 	if (py_ret != Py_None) {
466 	    /* XXXX handle reference counting here */
467 	    iter->user_data = py_ret;
468 	    if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) {
469 		Py_DECREF((PyObject *)iter->user_data);
470 	    }
471 	    ret = TRUE;
472 	} else {
473 	    iter->user_data = NULL;
474 	    Py_DECREF(py_ret);
475 	}
476     } else {
477         iter->user_data = NULL;
478 	PyErr_Print();
479     }
480 
481     pyg_gil_state_release(state);
482     return ret;
483 }
484 
485 static gboolean
pygtk_generic_tree_model_iter_children(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent)486 pygtk_generic_tree_model_iter_children(GtkTreeModel *tree_model,
487                                        GtkTreeIter *iter,
488                                        GtkTreeIter *parent)
489 {
490     PyGILState_STATE state;
491     PyObject *self, *py_ret, *py_parent = Py_None;
492     gboolean ret = FALSE;
493 
494     g_return_val_if_fail(tree_model != NULL, FALSE);
495     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE);
496     g_return_val_if_fail(iter != NULL, FALSE);
497     g_return_val_if_fail(parent == NULL || parent->stamp == PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp, FALSE);
498 
499     state = pyg_gil_state_ensure();
500 
501     /* this call finds the wrapper for this GObject */
502     self = pygobject_new((GObject *)tree_model);
503 
504 #ifdef DEBUG_TREE_MODEL
505     g_message("iter_children(%p, %p)", iter, parent);
506 #endif
507     if (parent && parent->user_data != NULL)
508 	py_parent = (PyObject *)parent->user_data;
509     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_children",
510 				 "(O)", py_parent);
511     Py_DECREF(self);
512     if (py_ret) {
513 	if (py_ret != Py_None) {
514 	    /* XXXX handle reference counting here */
515 	    iter->user_data = py_ret;
516             iter->stamp = PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp;
517 	    if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) {
518 		Py_DECREF((PyObject *)iter->user_data);
519 	    }
520 	    ret = TRUE;
521 	} else {
522 	    iter->user_data = NULL;
523 	    Py_DECREF(py_ret);
524 	}
525     } else {
526 	iter->user_data = NULL;
527 	PyErr_Print();
528     }
529 
530     pyg_gil_state_release(state);
531     return ret;
532 }
533 
534 static gboolean
pygtk_generic_tree_model_iter_has_child(GtkTreeModel * tree_model,GtkTreeIter * iter)535 pygtk_generic_tree_model_iter_has_child(GtkTreeModel *tree_model,
536                                         GtkTreeIter *iter)
537 {
538     PyGILState_STATE state;
539     PyObject *self, *py_ret, *py_iter;
540     gboolean ret = FALSE;
541 
542     g_return_val_if_fail(tree_model != NULL, FALSE);
543     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE);
544     g_return_val_if_fail(VALID_ITER(iter, tree_model), FALSE);
545 
546     state = pyg_gil_state_ensure();
547 
548     /* this call finds the wrapper for this GObject */
549     self = pygobject_new((GObject *)tree_model);
550 
551 #ifdef DEBUG_TREE_MODEL
552     g_message("iter_has_child(%p)", iter);
553 #endif
554     py_iter = (PyObject *)iter->user_data;
555     if (py_iter == NULL)
556 	py_iter = Py_None;
557 
558     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_has_child",
559 				 "(O)", py_iter);
560     Py_DECREF(self);
561     if (py_ret) {
562 	ret = PyObject_IsTrue(py_ret);
563 
564 	Py_DECREF(py_ret);
565     } else {
566 	PyErr_Print();
567     }
568 
569     pyg_gil_state_release(state);
570     return ret;
571 }
572 
573 static gint
pygtk_generic_tree_model_iter_n_children(GtkTreeModel * tree_model,GtkTreeIter * iter)574 pygtk_generic_tree_model_iter_n_children(GtkTreeModel *tree_model,
575                                          GtkTreeIter *iter)
576 {
577     PyGILState_STATE state;
578     PyObject *self, *py_ret, *py_iter;
579     guint ret = FALSE;
580 
581     g_return_val_if_fail(tree_model != NULL, 0);
582     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), 0);
583     g_return_val_if_fail(iter == NULL || iter->stamp == PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp, 0);
584 
585     state = pyg_gil_state_ensure();
586 
587     /* this call finds the wrapper for this GObject */
588     self = pygobject_new((GObject *)tree_model);
589 
590 #ifdef DEBUG_TREE_MODEL
591     g_message("iter_n_children(%p)", iter);
592 #endif
593 
594     py_iter = iter != NULL ? (PyObject *)iter->user_data : Py_None;
595 
596     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_n_children",
597 				 "(O)", py_iter);
598     Py_DECREF(self);
599     if (py_ret) {
600 	ret = PyInt_AsLong(py_ret);
601 
602 	Py_DECREF(py_ret);
603     } else {
604 	PyErr_Print();
605     }
606 
607     pyg_gil_state_release(state);
608     return ret;
609 }
610 
611 static gboolean
pygtk_generic_tree_model_iter_nth_child(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent,gint n)612 pygtk_generic_tree_model_iter_nth_child(GtkTreeModel *tree_model,
613                                         GtkTreeIter  *iter,
614                                         GtkTreeIter  *parent, gint n)
615 {
616     PyGILState_STATE state;
617     PyObject *self, *py_ret, *py_parent = Py_None;
618     gboolean ret = FALSE;
619 
620     g_return_val_if_fail(tree_model != NULL, FALSE);
621     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE);
622     g_return_val_if_fail(iter != NULL, FALSE);
623     g_return_val_if_fail(parent == NULL || parent->stamp == PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp, FALSE);
624 
625     state = pyg_gil_state_ensure();
626 
627     /* this call finds the wrapper for this GObject */
628     self = pygobject_new((GObject *)tree_model);
629 
630 #ifdef DEBUG_TREE_MODEL
631     g_message("iter_nth_child(%p, %p, %d)", iter, parent, n);
632 #endif
633     if (parent && parent->user_data != NULL)
634 	py_parent = (PyObject *)parent->user_data;
635     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_nth_child",
636 				 "(Oi)", py_parent, n);
637     Py_DECREF(self);
638     if (py_ret) {
639 	if (py_ret != Py_None) {
640 	    /* XXXX handle reference counting here */
641 	    iter->user_data = py_ret;
642             iter->stamp = PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp;
643 	    if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) {
644 		Py_DECREF((PyObject *)iter->user_data);
645 	    }
646 	    ret = TRUE;
647 	} else {
648 	    iter->user_data = NULL;
649 	    Py_DECREF(py_ret);
650 	}
651     } else {
652 	iter->user_data = NULL;
653 	PyErr_Print();
654     }
655 
656     pyg_gil_state_release(state);
657     return ret;
658 }
659 
660 static gboolean
pygtk_generic_tree_model_iter_parent(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * child)661 pygtk_generic_tree_model_iter_parent(GtkTreeModel *tree_model,
662                                      GtkTreeIter *iter,
663                                      GtkTreeIter *child)
664 {
665     PyGILState_STATE state;
666     PyObject *self, *py_ret, *py_child = Py_None;
667     gboolean ret = FALSE;
668 
669     g_return_val_if_fail(tree_model != NULL, FALSE);
670     g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE);
671     g_return_val_if_fail(iter != NULL, FALSE);
672     g_return_val_if_fail(VALID_ITER(child, tree_model), FALSE);
673 
674     state = pyg_gil_state_ensure();
675 
676     /* this call finds the wrapper for this GObject */
677     self = pygobject_new((GObject *)tree_model);
678 
679 #ifdef DEBUG_TREE_MODEL
680     g_message("iter_parent(%p, %p)", iter, child);
681 #endif
682     if (child && child->user_data != NULL)
683 	py_child = (PyObject *)child->user_data;
684     py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_parent",
685 				 "(O)", py_child);
686     Py_DECREF(self);
687     if (py_ret) {
688 	if (py_ret != Py_None) {
689 	    /* XXXX handle reference counting here */
690 	    iter->user_data = py_ret;
691             iter->stamp = PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp;
692 	    if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) {
693 		Py_DECREF((PyObject *)iter->user_data);
694 	    }
695 	    ret = TRUE;
696 	} else {
697 	    iter->user_data = NULL;
698 	    Py_DECREF(py_ret);
699 	}
700     } else {
701 	iter->user_data = NULL;
702 	PyErr_Print();
703     }
704 
705     pyg_gil_state_release(state);
706     return ret;
707 }
708 
709 static void
pygtk_generic_tree_model_unref_node(GtkTreeModel * tree_model,GtkTreeIter * iter)710 pygtk_generic_tree_model_unref_node(GtkTreeModel *tree_model, GtkTreeIter *iter)
711 {
712     PyGILState_STATE state;
713     PyObject *self, *py_ret, *py_iter, *method;
714 
715     g_return_if_fail(tree_model != NULL);
716     g_return_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model));
717     g_return_if_fail(VALID_ITER(iter, tree_model));
718 
719     state = pyg_gil_state_ensure();
720 
721     /* this call finds the wrapper for this GObject */
722     self = pygobject_new((GObject *)tree_model);
723 
724 #ifdef DEBUG_TREE_MODEL
725     g_message("unref_node(%p)", iter);
726 #endif
727     py_iter = (PyObject *)iter->user_data;
728     if (py_iter == NULL)
729 	py_iter = Py_None;
730 
731     method = PyObject_GetAttrString(self, METHOD_PREFIX "unref_node");
732     if (method == NULL)
733 	PyErr_Clear();
734     else {
735 	py_ret = PyObject_CallFunction(method, "(O)", py_iter);
736 	if (py_ret) {
737 	    Py_DECREF(py_ret);
738 	} else {
739 	    PyErr_Print();
740 	}
741     }
742     Py_DECREF(self);
743 
744     pyg_gil_state_release(state);
745 }
746 
747 static void
pygtk_generic_tree_model_ref_node(GtkTreeModel * tree_model,GtkTreeIter * iter)748 pygtk_generic_tree_model_ref_node(GtkTreeModel *tree_model, GtkTreeIter *iter)
749 {
750     PyGILState_STATE state;
751     PyObject *self, *py_ret, *py_iter, *method;
752 
753     g_return_if_fail(tree_model != NULL);
754     g_return_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model));
755     g_return_if_fail(VALID_ITER(iter, tree_model));
756 
757     state = pyg_gil_state_ensure();
758 
759     /* this call finds the wrapper for this GObject */
760     self = pygobject_new((GObject *)tree_model);
761 
762 #ifdef DEBUG_TREE_MODEL
763     g_message("ref_node(%p)", iter);
764 #endif
765     py_iter = (PyObject *)iter->user_data;
766     if (py_iter == NULL)
767 	py_iter = Py_None;
768 
769     method = PyObject_GetAttrString(self, METHOD_PREFIX "ref_node");
770     if (method == NULL)
771 	PyErr_Clear();
772     else {
773 	py_ret = PyObject_CallFunction(method, "(O)", py_iter);
774 	if (py_ret) {
775 	    Py_DECREF(py_ret);
776 	} else {
777 	    PyErr_Print();
778 	}
779     }
780     Py_DECREF(self);
781 
782     pyg_gil_state_release(state);
783 }
784 
785 void
pygtk_generic_tree_model_invalidate_iters(PyGtkGenericTreeModel * tree_model)786 pygtk_generic_tree_model_invalidate_iters(PyGtkGenericTreeModel *tree_model)
787 {
788     g_return_if_fail(tree_model != NULL);
789 
790     do {
791         tree_model->stamp++;
792     } while (tree_model->stamp == 0);
793 }
794 
795 gboolean
pygtk_generic_tree_model_iter_is_valid(PyGtkGenericTreeModel * tree_model,GtkTreeIter * iter)796 pygtk_generic_tree_model_iter_is_valid(PyGtkGenericTreeModel *tree_model,
797                                        GtkTreeIter *iter)
798 {
799     g_return_val_if_fail(tree_model != NULL, FALSE);
800 
801     return VALID_ITER(iter, tree_model);
802 }
803 
804 PyObject *
pygtk_generic_tree_model_get_user_data(PyGtkGenericTreeModel * tree_model,GtkTreeIter * iter)805 pygtk_generic_tree_model_get_user_data(PyGtkGenericTreeModel *tree_model,
806                                        GtkTreeIter *iter)
807 {
808     g_return_val_if_fail(tree_model != NULL, NULL);
809 
810     if (VALID_ITER(iter, tree_model)) {
811         /* Py_INCREF and NULL checking is done at _wrap_*() level. */
812         return iter->user_data;
813     }
814     else {
815         g_warning("iter is not valid for the tree model");
816         return NULL;
817     }
818 }
819 
820 GtkTreeIter
pygtk_generic_tree_model_create_tree_iter(PyGtkGenericTreeModel * tree_model,PyObject * user_data)821 pygtk_generic_tree_model_create_tree_iter(PyGtkGenericTreeModel *tree_model,
822                                           PyObject *user_data)
823 {
824     GtkTreeIter  iter = {0,};
825 
826     if (tree_model != NULL) {
827 	iter.user_data = user_data;
828 	iter.stamp = PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp;
829 
830 	/* Otherwise, caller is supposed to hold a reference somewhere. */
831 	if (PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references)
832 	    Py_INCREF(user_data);
833     }
834     else {
835 	/* FIXME: I guess this is still not enough. */
836 	iter.user_data = NULL;
837 	iter.stamp = 0;
838     }
839 
840     return iter;
841 }
842