/* -*- Mode: C; c-basic-offset: 4 -*- */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "pygtktreemodel.h" #include #include "pygobject.h" #include "pygtk-private.h" /* define this to print out debug messages */ #undef DEBUG_TREE_MODEL #ifndef _ # define _(s) (s) #endif enum { PROP_LEAK_REFERENCES = 1 }; static void pygtk_generic_tree_model_class_init(PyGtkGenericTreeModelClass *klass); static void pygtk_generic_tree_model_init(PyGtkGenericTreeModel *self); static void pygtk_generic_tree_model_iface_init(GtkTreeModelIface *iface); static void pygtk_generic_tree_model_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void pygtk_generic_tree_model_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); GType pygtk_generic_tree_model_get_type(void) { static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof(PyGtkGenericTreeModelClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) pygtk_generic_tree_model_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof(PyGtkGenericTreeModel), 0, /* n_preallocs */ (GInstanceInitFunc) pygtk_generic_tree_model_init, }; static const GInterfaceInfo tree_model_info = { (GInterfaceInitFunc) pygtk_generic_tree_model_iface_init, NULL, NULL, }; object_type = g_type_register_static(G_TYPE_OBJECT, "PyGtkGenericTreeModel", &object_info, 0); g_type_add_interface_static(object_type, GTK_TYPE_TREE_MODEL, &tree_model_info); } return object_type; } static void pygtk_generic_tree_model_class_init(PyGtkGenericTreeModelClass *klass) { GObjectClass *object_class = (GObjectClass*) klass; object_class->get_property = pygtk_generic_tree_model_get_property; object_class->set_property = pygtk_generic_tree_model_set_property; g_object_class_install_property (object_class, PROP_LEAK_REFERENCES, g_param_spec_boolean ("leak_references", _("Leak references"), _("Enable referencing iterator " "objects (this will cause a memory leak or at least a reference " "counting leak). You might need it though, if you return newly " "created objects."), TRUE, G_PARAM_READWRITE)); } static guint pygtk_generic_tree_model_get_flags(GtkTreeModel *tree_model); static gint pygtk_generic_tree_model_get_n_columns(GtkTreeModel *tree_model); static GType pygtk_generic_tree_model_get_column_type(GtkTreeModel *tree_model, gint index); static gboolean pygtk_generic_tree_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path); static GtkTreePath *pygtk_generic_tree_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter); static void pygtk_generic_tree_model_get_value(GtkTreeModel*tree_model, GtkTreeIter *iter, gint column, GValue *value); static gboolean pygtk_generic_tree_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter); static gboolean pygtk_generic_tree_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent); static gboolean pygtk_generic_tree_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter); static gint pygtk_generic_tree_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter); static gboolean pygtk_generic_tree_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n); static gboolean pygtk_generic_tree_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child); static void pygtk_generic_tree_model_iface_init(GtkTreeModelIface *iface) { iface->get_flags = pygtk_generic_tree_model_get_flags; iface->get_n_columns = pygtk_generic_tree_model_get_n_columns; iface->get_column_type = pygtk_generic_tree_model_get_column_type; iface->get_iter = pygtk_generic_tree_model_get_iter; iface->get_path = pygtk_generic_tree_model_get_path; iface->get_value = pygtk_generic_tree_model_get_value; iface->iter_next = pygtk_generic_tree_model_iter_next; iface->iter_children = pygtk_generic_tree_model_iter_children; iface->iter_has_child = pygtk_generic_tree_model_iter_has_child; iface->iter_n_children = pygtk_generic_tree_model_iter_n_children; iface->iter_nth_child = pygtk_generic_tree_model_iter_nth_child; iface->iter_parent = pygtk_generic_tree_model_iter_parent; } static void pygtk_generic_tree_model_init(PyGtkGenericTreeModel *self) { self->leak_references = TRUE; } static void pygtk_generic_tree_model_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_LEAK_REFERENCES: PYGTK_GENERIC_TREE_MODEL (object)->leak_references = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void pygtk_generic_tree_model_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_LEAK_REFERENCES: g_value_set_boolean (value, PYGTK_GENERIC_TREE_MODEL (object)->leak_references); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } PyGtkGenericTreeModel * pygtk_generic_tree_model_new(void) { return PYGTK_GENERIC_TREE_MODEL( g_object_new(PYGTK_TYPE_GENERIC_TREE_MODEL, NULL)); } /* format of GtkTreeIter's for PyGtkGenericTreeModel: * user_data == python object * user_data2 == floating reference? * * I haven't worked out how everything should work. For now I will * leak references. */ #define METHOD_PREFIX "on_" static guint pygtk_generic_tree_model_get_flags(GtkTreeModel *tree_model) { PyObject *self, *py_ret; g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), 0); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("get_flags()"); #endif py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_flags", ""); if (py_ret) { guint ret = PyInt_AsLong(py_ret); Py_DECREF(py_ret); pyg_unblock_threads(); return ret; } else { PyErr_Print(); pyg_unblock_threads(); return 0; } } static gint pygtk_generic_tree_model_get_n_columns(GtkTreeModel *tree_model) { PyObject *self, *py_ret; g_return_val_if_fail(tree_model != NULL, 0); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), 0); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("get_n_columns()"); #endif py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_n_columns", ""); if (py_ret) { gint ret = PyInt_AsLong(py_ret); Py_DECREF(py_ret); pyg_unblock_threads(); return ret; } else { PyErr_Print(); pyg_unblock_threads(); return 0; } } static GType pygtk_generic_tree_model_get_column_type(GtkTreeModel *tree_model, gint index) { PyObject *self, *py_ret; g_return_val_if_fail(tree_model != NULL, G_TYPE_INVALID); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), G_TYPE_INVALID); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("get_column_type(%d)", index); #endif py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_column_type", "(i)", index); if (py_ret) { GType ret = pyg_type_from_object(py_ret); Py_DECREF(py_ret); pyg_unblock_threads(); return ret; } else { PyErr_Print(); pyg_unblock_threads(); return G_TYPE_INVALID; } } static gboolean pygtk_generic_tree_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) { PyObject *self, *py_path, *py_ret; g_return_val_if_fail(tree_model != NULL, FALSE); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE); g_return_val_if_fail(iter != NULL, FALSE); g_return_val_if_fail(path != NULL, FALSE); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("get_iter(%p)", path); #endif py_path = pygtk_tree_path_to_pyobject(path); py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_iter", "(O)", py_path); Py_DECREF(py_path); if (py_ret) { if (py_ret != Py_None) { iter->user_data = py_ret; if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) { Py_DECREF((PyObject *)iter->user_data); } pyg_unblock_threads(); return TRUE; } else { iter->user_data = NULL; Py_DECREF(py_ret); pyg_unblock_threads(); return FALSE; } } else { PyErr_Print(); iter->user_data = NULL; pyg_unblock_threads(); return FALSE; } } static GtkTreePath * pygtk_generic_tree_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter) { PyObject *self, *py_ret; g_return_val_if_fail(tree_model != NULL, NULL); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), NULL); g_return_val_if_fail(iter != NULL, NULL); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("get_path(%p)", iter); #endif pyg_block_threads(); py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_path", "(O)", (PyObject *)iter->user_data); if (py_ret) { GtkTreePath *path = pygtk_tree_path_from_pyobject(py_ret); if (!path) g_warning("could not convert return value of get_path() to " "a GtkTreePath"); Py_DECREF(py_ret); pyg_unblock_threads(); return path; } else { PyErr_Print(); pyg_unblock_threads(); return NULL; } } static void pygtk_generic_tree_model_get_value(GtkTreeModel*tree_model, GtkTreeIter *iter, gint column, GValue *value) { PyObject *self, *py_value; g_return_if_fail(tree_model != NULL); g_return_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model)); g_return_if_fail(iter != NULL); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("get_value(%p, %d)", iter, column); _PyObject_Dump (iter->user_data); #endif /* init value to column type */ g_value_init(value, pygtk_generic_tree_model_get_column_type(tree_model, column)); py_value = PyObject_CallMethod(self, METHOD_PREFIX "get_value", "(Oi)", (PyObject *)iter->user_data,column); if (py_value) { pyg_value_from_pyobject(value, py_value); Py_DECREF(py_value); } else { PyErr_Print(); } pyg_unblock_threads(); } static gboolean pygtk_generic_tree_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter) { PyObject *self, *py_ret; g_return_val_if_fail(tree_model != NULL, FALSE); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE); g_return_val_if_fail(iter != NULL, FALSE); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("iter_next(%p)", iter); #endif py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_next", "(O)", (PyObject *)iter->user_data); if (py_ret) { if (py_ret != Py_None) { /* XXXX handle reference counting here */ iter->user_data = py_ret; if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) { Py_DECREF((PyObject *)iter->user_data); } pyg_unblock_threads(); return TRUE; } else { iter->user_data = NULL; Py_DECREF(py_ret); pyg_unblock_threads(); return FALSE; } } else { iter->user_data = NULL; PyErr_Print(); pyg_unblock_threads(); return FALSE; } } static gboolean pygtk_generic_tree_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { PyObject *self, *py_ret, *py_parent = Py_None; g_return_val_if_fail(tree_model != NULL, FALSE); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE); g_return_val_if_fail(iter != NULL, FALSE); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("iter_children(%p, %p)", iter, parent); #endif if (parent && parent->user_data != NULL) py_parent = (PyObject *)parent->user_data; py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_children", "(O)", py_parent); if (py_ret) { if (py_ret != Py_None) { /* XXXX handle reference counting here */ iter->user_data = py_ret; if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) { Py_DECREF((PyObject *)iter->user_data); } pyg_unblock_threads(); return TRUE; } else { iter->user_data = NULL; Py_DECREF(py_ret); pyg_unblock_threads(); return FALSE; } } else { iter->user_data = NULL; PyErr_Print(); pyg_unblock_threads(); return FALSE; } } static gboolean pygtk_generic_tree_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter) { PyObject *self, *py_ret; g_return_val_if_fail(tree_model != NULL, FALSE); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE); g_return_val_if_fail(iter != NULL, FALSE); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("iter_has_child(%p)", iter); #endif py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_has_child", "(O)", (PyObject *)iter->user_data); if (py_ret) { gboolean ret = PyObject_IsTrue(py_ret); Py_DECREF(py_ret); pyg_unblock_threads(); return ret; } else { PyErr_Print(); pyg_unblock_threads(); return FALSE; } } static gint pygtk_generic_tree_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter) { PyObject *self, *py_ret; g_return_val_if_fail(tree_model != NULL, FALSE); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE); g_return_val_if_fail(iter != NULL, FALSE); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("iter_n_children(%p)", iter); #endif py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_n_children", "(O)", (PyObject *)iter->user_data); if (py_ret) { gint ret = PyInt_AsLong(py_ret); Py_DECREF(py_ret); pyg_unblock_threads(); return ret; } else { PyErr_Print(); pyg_unblock_threads(); return 0; } } static gboolean pygtk_generic_tree_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) { PyObject *self, *py_ret, *py_parent = Py_None; g_return_val_if_fail(tree_model != NULL, FALSE); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE); g_return_val_if_fail(iter != NULL, FALSE); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("iter_nth_child(%p, %p, %d)", iter, parent, n); #endif if (parent && parent->user_data != NULL) py_parent = (PyObject *)parent->user_data; py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_nth_child", "(Oi)", py_parent, n); if (py_ret) { if (py_ret != Py_None) { /* XXXX handle reference counting here */ iter->user_data = py_ret; if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) { Py_DECREF((PyObject *)iter->user_data); } pyg_unblock_threads(); return TRUE; } else { iter->user_data = NULL; Py_DECREF(py_ret); pyg_unblock_threads(); return FALSE; } } else { iter->user_data = NULL; PyErr_Print(); pyg_unblock_threads(); return FALSE; } } static gboolean pygtk_generic_tree_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) { PyObject *self, *py_ret, *py_child = Py_None; g_return_val_if_fail(tree_model != NULL, FALSE); g_return_val_if_fail(PYGTK_IS_GENERIC_TREE_MODEL(tree_model), FALSE); g_return_val_if_fail(iter != NULL, FALSE); pyg_block_threads(); /* this call finds the wrapper for this GObject */ self = pygobject_new((GObject *)tree_model); #ifdef DEBUG_TREE_MODEL g_message("iter_parent(%p, %p)", iter, child); #endif if (child && child->user_data != NULL) py_child = (PyObject *)child->user_data; py_ret = PyObject_CallMethod(self, METHOD_PREFIX "iter_parent", "(O)", py_child); if (py_ret) { if (py_ret != Py_None) { /* XXXX handle reference counting here */ iter->user_data = py_ret; if (!PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) { Py_DECREF((PyObject *)iter->user_data); } pyg_unblock_threads(); return TRUE; } else { iter->user_data = NULL; Py_DECREF(py_ret); pyg_unblock_threads(); return FALSE; } } else { iter->user_data = NULL; PyErr_Print(); pyg_unblock_threads(); return FALSE; } }