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