com gtk/php-gtk: Make GtkTreeStore and GtkListStore work like iterators (with some supporting classes). This allows for some cool tricks.: ext/gtk+/gtktreeview.overrides ext/gtk+/php_gtk+.c ext/gt k+/php_gtk+.h ext/gtk+/php_gtk+_types.c
[email protected] (David Soria Parra) Sat, 18 Feb 2006 19:49:34 +0000
| Newsgroups | php.gtk.cvs |
|---|---|
| Message-ID | <[email protected]> |
Commit: 52037e58f002142efc52ed05b40b5213a9d691d1 Author: Andrei Zmievski <[email protected]> Sat, 18 Feb 2006 19:49:34 +0000 Parents: 2ddcf43b706599ac4a84ac032c7c4bf8db30006d Branches: master Link: http://git.php.net/?p=gtk/php-gtk.git;a=commitdiff;h=52037e58f002142efc52ed05b40b5213a9d691d1 Log: Make GtkTreeStore and GtkListStore work like iterators (with some supporting classes). This allows for some cool tricks. Changed paths: M ext/gtk+/gtktreeview.overrides M ext/gtk+/php_gtk+.c M ext/gtk+/php_gtk+.h M ext/gtk+/php_gtk+_types.c
diff_52037e58f002142efc52ed05b40b5213a9d691d1.txt
(text/plain, 30.7 KB)
52037e58f002142efc52ed05b40b5213a9d691d1
diff --git a/ext/gtk+/gtktreeview.overrides b/ext/gtk+/gtktreeview.overrides
index 686b9fe..ca63717 100644
--- a/ext/gtk+/gtktreeview.overrides
+++ b/ext/gtk+/gtktreeview.overrides
@@ -3,8 +3,26 @@
%%
headers
+#include "zend_interfaces.h"
+
static void phpg_cell_data_func_marshal(GtkCellLayout *cell_layout, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
static void phpg_store_set_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_tree);
+static zval* phpg_gtktreemodel_read_dimension_handler(zval *object, zval *offset, int type TSRMLS_DC);
+static int phpg_gtktreemodel_has_dimension_handler(zval *object, zval *offset, int check_empty TSRMLS_DC);
+static void phpg_gtktreemodel_write_dimension_handler(zval *object, zval *offset, zval *value TSRMLS_DC);
+static int phpg_gtktreemodel_count_elements_handler(zval *object, long *count TSRMLS_DC);
+
+%%
+post-registration GtkListStore
+
+ gtkliststore_ce->get_iterator = phpg_treemodel_get_iterator;
+ zend_class_implements(gtkliststore_ce TSRMLS_CC, 1, zend_ce_traversable);
+
+%%
+post-registration GtkTreeStore
+
+ gtktreestore_ce->get_iterator = phpg_treemodel_get_iterator;
+ zend_class_implements(gtktreestore_ce TSRMLS_CC, 1, zend_ce_traversable);
%% {{{ ignores
@@ -105,7 +123,6 @@ PHP_METHOD
%% }}}
-
%% {{{ GtkCellView
%%
@@ -133,7 +150,6 @@ PHP_METHOD
%% }}}
-
%% {{{ GtkListStore
%%
add-arginfo GtkListStore __construct
@@ -202,7 +218,7 @@ PHP_METHOD
gtk_list_store_append(GTK_LIST_STORE(PHPG_GOBJECT(this_ptr)), &iter);
- if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items) == FAILURE)
+ if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items TSRMLS_CC) == FAILURE)
return;
phpg_gboxed_new(&return_value, GTK_TYPE_TREE_ITER, &iter, TRUE, TRUE TSRMLS_CC);
@@ -229,7 +245,7 @@ PHP_METHOD
gtk_list_store_prepend(GTK_LIST_STORE(PHPG_GOBJECT(this_ptr)), &iter);
- if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items) == FAILURE)
+ if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items TSRMLS_CC) == FAILURE)
return;
phpg_gboxed_new(&return_value, GTK_TYPE_TREE_ITER, &iter, TRUE, TRUE TSRMLS_CC);
@@ -404,6 +420,42 @@ PHP_METHOD
{
phpg_store_set_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE);
}
+
+%%
+override-handler GtkListStore count_elements
+static int phpg_gtkliststore_count_elements_handler(zval *object, long *count TSRMLS_DC)
+{
+ return phpg_gtktreemodel_count_elements_handler(object, count TSRMLS_CC);
+}
+
+%%
+override-handler GtkListStore has_dimension
+static int phpg_gtkliststore_has_dimension_handler(zval *object, zval *offset, int check_empty TSRMLS_DC)
+{
+ return phpg_gtktreemodel_has_dimension_handler(object, offset, check_empty TSRMLS_CC);
+}
+
+%%
+override-handler GtkListStore read_dimension
+static zval* phpg_gtkliststore_read_dimension_handler(zval *object, zval *offset, int type TSRMLS_DC)
+{
+ return phpg_gtktreemodel_read_dimension_handler(object, offset, type TSRMLS_CC);
+}
+
+%%
+override-handler GtkListStore write_dimension
+static void phpg_gtkliststore_write_dimension_handler(zval *object, zval *offset, zval *value TSRMLS_DC)
+{
+ phpg_gtktreemodel_write_dimension_handler(object, offset, value TSRMLS_CC);
+}
+
+%%
+override-handler GtkListStore unset_dimension
+static void phpg_gtkliststore_unset_dimension_handler(zval *object, zval *offset TSRMLS_DC)
+{
+ phpg_gtktreemodel_write_dimension_handler(object, offset, NULL TSRMLS_CC);
+}
+
%% }}}
%% {{{ GtkTreeStore
@@ -481,7 +533,7 @@ PHP_METHOD
gtk_tree_store_append(GTK_TREE_STORE(PHPG_GOBJECT(this_ptr)), &iter, parent_iter);
- if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items) == FAILURE)
+ if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items TSRMLS_CC) == FAILURE)
return;
phpg_gboxed_new(&return_value, GTK_TYPE_TREE_ITER, &iter, TRUE, TRUE TSRMLS_CC);
@@ -518,7 +570,7 @@ PHP_METHOD
gtk_tree_store_insert(GTK_TREE_STORE(PHPG_GOBJECT(this_ptr)), &iter, parent_iter, position);
- if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items) == FAILURE)
+ if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items TSRMLS_CC) == FAILURE)
return;
phpg_gboxed_new(&return_value, GTK_TYPE_TREE_ITER, &iter, TRUE, TRUE TSRMLS_CC);
@@ -557,7 +609,7 @@ PHP_METHOD
gtk_tree_store_insert_before(GTK_TREE_STORE(PHPG_GOBJECT(this_ptr)), &iter, parent_iter, sibling_iter);
- if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items) == FAILURE)
+ if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items TSRMLS_CC) == FAILURE)
return;
phpg_gboxed_new(&return_value, GTK_TYPE_TREE_ITER, &iter, TRUE, TRUE TSRMLS_CC);
@@ -596,7 +648,7 @@ PHP_METHOD
gtk_tree_store_insert_after(GTK_TREE_STORE(PHPG_GOBJECT(this_ptr)), &iter, parent_iter, sibling_iter);
- if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items) == FAILURE)
+ if (items && phpg_model_set_row(GTK_TREE_MODEL(PHPG_GOBJECT(this_ptr)), &iter, items TSRMLS_CC) == FAILURE)
return;
phpg_gboxed_new(&return_value, GTK_TYPE_TREE_ITER, &iter, TRUE, TRUE TSRMLS_CC);
@@ -620,6 +672,178 @@ PHP_METHOD
{
phpg_store_set_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, TRUE);
}
+
+
+%%
+override-handler GtkTreeStore count_elements
+
+static int phpg_gtktreemodel_count_elements_handler(zval *object, long *count TSRMLS_DC)
+{
+ *count = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(PHPG_GOBJECT(object)), NULL);
+ return SUCCESS;
+}
+
+static int phpg_gtktreestore_count_elements_handler(zval *object, long *count TSRMLS_DC)
+{
+ return phpg_gtktreemodel_count_elements_handler(object, count TSRMLS_CC);
+}
+
+
+%%
+override-handler GtkTreeStore has_dimension
+
+static int phpg_gtktreemodel_has_dimension_handler(zval *object, zval *offset, int check_empty TSRMLS_DC)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ zval tmp_offset;
+ GtkTreePath *path = NULL;
+ int result = 1;
+
+ if (phpg_gboxed_check(offset, GTK_TYPE_TREE_ITER, TRUE TSRMLS_CC)) {
+ return 1;
+ }
+
+ model = GTK_TREE_MODEL(PHPG_GOBJECT(object));
+
+ if (Z_TYPE_P(offset) == IS_LONG && Z_LVAL_P(offset) < 0) {
+ int n_columns = gtk_tree_model_get_n_columns(model);
+ tmp_offset = *offset;
+ ZVAL_LONG(&tmp_offset, Z_LVAL_P(offset) + n_columns);
+ offset = &tmp_offset;
+ }
+
+ if (phpg_tree_path_from_zval(offset, &path TSRMLS_CC) == FAILURE) {
+ return 0;
+ }
+
+ if (!gtk_tree_model_get_iter(model, &iter, path)) {
+ result = 0;
+ }
+
+ gtk_tree_path_free(path);
+ return result;
+}
+
+static int phpg_gtktreestore_has_dimension_handler(zval *object, zval *offset, int check_empty TSRMLS_DC)
+{
+ return phpg_gtktreemodel_has_dimension_handler(object, offset, check_empty TSRMLS_CC);
+}
+
+%%
+override-handler GtkTreeStore read_dimension
+
+static zval* phpg_gtktreemodel_read_dimension_handler(zval *object, zval *offset, int type TSRMLS_DC)
+{
+ GtkTreeModel *model;
+ GtkTreePath *path = NULL;
+ GtkTreeIter iter;
+ zval tmp_offset;
+ zval *result = NULL;
+
+ MAKE_STD_ZVAL(result);
+ ZVAL_NULL(result);
+ result->refcount = 0;
+ result->is_ref = 0;
+
+ if (phpg_gboxed_check(offset, GTK_TYPE_TREE_ITER, TRUE TSRMLS_CC)) {
+ phpg_modelrow_new(&result, GTK_TREE_MODEL(PHPG_GOBJECT(object)), (GtkTreeIter *)
+ PHPG_GBOXED(offset) TSRMLS_CC);
+ return result;
+ }
+
+ model = GTK_TREE_MODEL(PHPG_GOBJECT(object));
+
+ if (Z_TYPE_P(offset) == IS_LONG && Z_LVAL_P(offset) < 0) {
+ int n_columns = gtk_tree_model_get_n_columns(model);
+ tmp_offset = *offset;
+ ZVAL_LONG(&tmp_offset, Z_LVAL_P(offset) + n_columns);
+ offset = &tmp_offset;
+ }
+
+ if (phpg_tree_path_from_zval(offset, &path TSRMLS_CC) == FAILURE) {
+ php_error(E_WARNING, "Could not parse index as a tree path");
+ zval_dtor(result);
+ FREE_ZVAL(result);
+ return EG(uninitialized_zval_ptr);
+ }
+
+ if (gtk_tree_model_get_iter(model, &iter, path)) {
+ phpg_modelrow_new(&result, model, &iter TSRMLS_CC);
+ } else {
+ php_error(E_WARNING, "Invalid tree path");
+ zval_dtor(result);
+ FREE_ZVAL(result);
+ result = EG(uninitialized_zval_ptr);
+ }
+ gtk_tree_path_free(path);
+
+ return result;
+}
+
+static zval* phpg_gtktreestore_read_dimension_handler(zval *object, zval *offset, int type TSRMLS_DC)
+{
+ return phpg_gtktreemodel_read_dimension_handler(object, offset, type TSRMLS_CC);
+}
+
+%%
+override-handler GtkTreeStore write_dimension
+
+static void phpg_gtktreemodel_write_dimension_handler(zval *object, zval *offset, zval *value TSRMLS_DC)
+{
+ GtkTreeIter *iter, tmp_iter;
+ GtkTreeModel *model;
+
+ model = GTK_TREE_MODEL(PHPG_GOBJECT(object));
+
+ if (phpg_gboxed_check(offset, GTK_TYPE_TREE_ITER, TRUE TSRMLS_CC)) {
+ iter = (GtkTreeIter *) PHPG_GBOXED(offset);
+ } else {
+ GtkTreePath *path;
+ zval tmp_offset;
+
+ if (Z_TYPE_P(offset) == IS_LONG && Z_LVAL_P(offset) < 0) {
+ int n_columns = gtk_tree_model_get_n_columns(model);
+ tmp_offset = *offset;
+ ZVAL_LONG(&tmp_offset, Z_LVAL_P(offset) + n_columns);
+ offset = &tmp_offset;
+ }
+
+ if (phpg_tree_path_from_zval(offset, &path TSRMLS_CC) == FAILURE) {
+ php_error(E_WARNING, "Could not parse index as a tree path");
+ return;
+ }
+
+ if (!gtk_tree_model_get_iter(model, &tmp_iter, path)) {
+ php_error(E_WARNING, "Invalid tree path");
+ gtk_tree_path_free(path);
+ return;
+ }
+
+ iter = &tmp_iter;
+ gtk_tree_path_free(path);
+ }
+
+ if (value == NULL) {
+ phpg_model_remove_row(model, iter TSRMLS_CC);
+ } else {
+ phpg_model_set_row(model, iter, value TSRMLS_CC);
+ }
+}
+
+static void phpg_gtktreestore_write_dimension_handler(zval *object, zval *offset, zval *value TSRMLS_DC)
+{
+ phpg_gtktreemodel_write_dimension_handler(object, offset, value TSRMLS_CC);
+}
+
+%%
+override-handler GtkTreeStore unset_dimension
+
+static void phpg_gtktreestore_unset_dimension_handler(zval *object, zval *offset TSRMLS_DC)
+{
+ phpg_gtktreemodel_write_dimension_handler(object, offset, NULL TSRMLS_CC);
+}
+
%% }}}
%% {{{ GtkTreeModel
diff --git a/ext/gtk+/php_gtk+.c b/ext/gtk+/php_gtk+.c
index c74cb27..3344bac 100644
--- a/ext/gtk+/php_gtk+.c
+++ b/ext/gtk+/php_gtk+.c
@@ -192,7 +192,7 @@ PHP_GTK_XINIT_FUNCTION(gtk_plus)
php_gdk_register_keysyms();
- php_gtk_plus_register_types();
+ php_gtk_plus_register_types(TSRMLS_C);
return SUCCESS;
}
diff --git a/ext/gtk+/php_gtk+.h b/ext/gtk+/php_gtk+.h
index 089343d..8ba9304 100644
--- a/ext/gtk+/php_gtk+.h
+++ b/ext/gtk+/php_gtk+.h
@@ -29,6 +29,9 @@
extern php_gtk_ext_entry gtk_plus_ext_entry;
#define php_gtk_ext_gtk__ptr >k_plus_ext_entry
+PHP_GTK_API extern PHP_GTK_EXPORT_CE(gtktreemodelrow_ce);
+PHP_GTK_API extern PHP_GTK_EXPORT_CE(gtktreemodelrowiter_ce);
+
typedef enum { STYLE_COLOR_ARRAY, STYLE_GC_ARRAY, STYLE_PIXMAP_ARRAY } style_helper_type;
PHP_GTK_API int phpg_rectangle_from_zval(zval *value, GdkRectangle *rectangle TSRMLS_DC);
@@ -36,7 +39,10 @@ PHP_GTK_API void phpg_create_style_helper(zval **zobj, GtkStyle *style, int type
PHP_GTK_API int phpg_tree_path_from_zval(const zval *value, GtkTreePath **path TSRMLS_DC);
PHP_GTK_API int phpg_tree_path_to_zval(GtkTreePath *path, zval **value TSRMLS_DC);
-int phpg_model_set_row(GtkTreeModel *model, GtkTreeIter *iter, zval *items);
+int phpg_model_set_row(GtkTreeModel *model, GtkTreeIter *iter, zval *items TSRMLS_DC);
+int phpg_model_remove_row(GtkTreeModel *model, GtkTreeIter *iter TSRMLS_DC);
+zend_object_iterator* phpg_treemodel_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC);
+void phpg_modelrow_new(zval **zobj, GtkTreeModel *model, GtkTreeIter *iter TSRMLS_DC);
void phpg_atk_register_constants(const char *strip_prefix);
void phpg_pango_register_constants(const char *strip_prefix);
@@ -47,6 +53,6 @@ void phpg_pango_register_classes(void);
void phpg_gdk_register_classes(void);
void phpg_gtk_register_classes(void);
-void php_gtk_plus_register_types();
+void php_gtk_plus_register_types(TSRMLS_D);
#endif /* _PHP_GTK_PLUS_H */
diff --git a/ext/gtk+/php_gtk+_types.c b/ext/gtk+/php_gtk+_types.c
index da29a56..f768883 100644
--- a/ext/gtk+/php_gtk+_types.c
+++ b/ext/gtk+/php_gtk+_types.c
@@ -24,6 +24,7 @@
#if HAVE_PHP_GTK
+#include "zend_interfaces.h"
#include "gen_gdk.h"
/* {{{ phpg_rectangle_from_zval */
@@ -74,6 +75,8 @@ static int phpg_gdk_rectangle_to_zval(const GValue *gvalue, zval **value TSRMLS_
/* {{{ phpg_tree_path_from_zval */
PHP_GTK_API int phpg_tree_path_from_zval(const zval *value, GtkTreePath **path TSRMLS_DC)
{
+ assert(path != NULL);
+
switch (Z_TYPE_P(value)) {
case IS_STRING:
*path = gtk_tree_path_new_from_string(Z_STRVAL_P(value));
@@ -149,8 +152,8 @@ static int phpg_gtk_tree_path_from_zval(const zval *value, GValue *gvalue TSRMLS
static int phpg_gtk_tree_path_to_zval(const GValue *gvalue, zval **value TSRMLS_DC)
{
- GtkTreePath *path = (GtkTreePath *)g_value_get_boxed(gvalue);;
- return phpg_tree_path_to_zval(path, value TSRMLS_CC);;
+ GtkTreePath *path = (GtkTreePath *)g_value_get_boxed(gvalue);
+ return phpg_tree_path_to_zval(path, value TSRMLS_CC);
}
/* }}} */
@@ -165,17 +168,12 @@ typedef struct {
static const int STYLE_NUM_STATES = 5;
-static zval *style_helper_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
+static zval* style_helper_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
{
zval *result = NULL;
long index;
style_helper *sh = (style_helper *) zend_object_store_get_object(object TSRMLS_CC);
- MAKE_STD_ZVAL(result);
- ZVAL_NULL(result);
- result->refcount = 0;
- result->is_ref = 0;
-
if (Z_TYPE_P(offset) != IS_LONG) {
php_error(E_WARNING, "Illegal index type");
return EG(uninitialized_zval_ptr);
@@ -187,6 +185,11 @@ static zval *style_helper_read_dimension(zval *object, zval *offset, int type TS
return EG(uninitialized_zval_ptr);
}
+ MAKE_STD_ZVAL(result);
+ ZVAL_NULL(result);
+ result->refcount = 0;
+ result->is_ref = 0;
+
switch (sh->type) {
case STYLE_COLOR_ARRAY:
{
@@ -290,7 +293,7 @@ static int style_helper_has_dimension(zval *object, zval *offset, int check_empt
return 0;
}
- if (Z_LVAL_P(offset) < 0 && Z_LVAL_P(offset) >= STYLE_NUM_STATES) {
+ if (Z_LVAL_P(offset) < 0 || Z_LVAL_P(offset) >= STYLE_NUM_STATES) {
php_error(E_WARNING, "Index out of range");
return 0;
}
@@ -391,7 +394,8 @@ PHP_GTK_API void phpg_create_style_helper(zval **zobj, GtkStyle *style, int type
/* }}} */
/* {{{ GtkTreeModel */
-int phpg_model_set_row(GtkTreeModel *model, GtkTreeIter *iter, zval *items)
+
+int phpg_model_set_row(GtkTreeModel *model, GtkTreeIter *iter, zval *items TSRMLS_DC)
{
gint n_cols, i;
GtkTreeModel *child;
@@ -410,13 +414,13 @@ int phpg_model_set_row(GtkTreeModel *model, GtkTreeIter *iter, zval *items)
if (GTK_IS_TREE_MODEL_SORT(model)) {
child = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model));
gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(model), &child_iter, iter);
- return phpg_model_set_row(child, &child_iter, items);
+ return phpg_model_set_row(child, &child_iter, items TSRMLS_CC);
}
if (GTK_IS_TREE_MODEL_FILTER(model)) {
child = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model));
gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(model), &child_iter, iter);
- return phpg_model_set_row(child, &child_iter, items);
+ return phpg_model_set_row(child, &child_iter, items TSRMLS_CC);
}
n_cols = gtk_tree_model_get_n_columns(model);
@@ -446,10 +450,482 @@ int phpg_model_set_row(GtkTreeModel *model, GtkTreeIter *iter, zval *items)
return SUCCESS;
}
+
+int phpg_model_remove_row(GtkTreeModel *model, GtkTreeIter *iter TSRMLS_DC)
+{
+ GtkTreeModel *child;
+ GtkTreeIter child_iter;
+
+ if (GTK_IS_LIST_STORE(model)) {
+ gtk_list_store_remove(GTK_LIST_STORE(model), iter);
+ return SUCCESS;
+ }
+
+ if (GTK_IS_TREE_STORE(model)) {
+ gtk_tree_store_remove(GTK_TREE_STORE(model), iter);
+ return SUCCESS;
+ }
+
+ if (GTK_IS_TREE_MODEL_SORT(model)) {
+ child = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model));
+ gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(model), &child_iter, iter);
+ return phpg_model_remove_row(child, &child_iter TSRMLS_CC);
+ }
+
+ if (GTK_IS_TREE_MODEL_FILTER(model)) {
+ child = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model));
+ gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(model), &child_iter, iter);
+ return phpg_model_remove_row(child, &child_iter TSRMLS_CC);
+ }
+
+ php_error(E_WARNING, "Cannot remove row: unknown model type");
+ return FAILURE;
+}
+
+/* }}} */
+
+/* {{{ GtkTreeModelRow and GtkTreeModelRowIter */
+
+typedef struct {
+ PHPG_OBJ_HEADER
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+} phpg_modelrow_t;
+
+typedef struct {
+ PHPG_OBJ_HEADER
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeIter *parent_iter;
+ gboolean is_valid;
+ int32_t index;
+ zval *current;
+ zend_object_iterator ziter;
+} phpg_modelrowiter_t;
+
+PHP_GTK_API PHP_GTK_EXPORT_CE(gtktreemodelrow_ce) = NULL;
+PHP_GTK_API PHP_GTK_EXPORT_CE(gtktreemodelrowiter_ce) = NULL;
+
+static zend_object_handlers gtktreemodelrow_handlers;
+
+static void phpg_modelrowiter_new(zval **zobj, GtkTreeModel *model, GtkTreeIter *parent_iter TSRMLS_DC);
+
+static PHP_METHOD(GtkTreeModelRow, children)
+{
+ NOT_STATIC_METHOD();
+ phpg_modelrow_t *row;
+
+ if (!php_gtk_parse_args(ZEND_NUM_ARGS(), "")) {
+ return;
+ }
+
+ row = zend_object_store_get_object(this_ptr TSRMLS_CC);
+ phpg_modelrowiter_new(&return_value, row->model, &row->iter TSRMLS_CC);
+}
+
+static zend_function_entry gtktreemodelrow_methods[] = {
+ PHP_ME_MAPPING(__construct, no_direct_constructor, NULL)
+ PHP_ME(GtkTreeModelRow, children, NULL, ZEND_ACC_PUBLIC)
+ { NULL, NULL, NULL }
+};
+
+
+PHPG_PROP_READER(GtkTreeModelRow, model)
+{
+ GtkTreeModel *model = ((phpg_modelrow_t *)object)->model;
+ phpg_gobject_new(&return_value, (GObject *)model TSRMLS_CC);
+ return SUCCESS;
+}
+
+PHPG_PROP_READER(GtkTreeModelRow, next)
+{
+ phpg_modelrow_t *row = (phpg_modelrow_t *) object;
+ GtkTreeIter iter = row->iter;
+
+ if (gtk_tree_model_iter_next(row->model, &iter)) {
+ phpg_modelrow_new(&return_value, row->model, &iter TSRMLS_CC);
+ } else {
+ ZVAL_NULL(return_value);
+ }
+ return SUCCESS;
+}
+
+PHPG_PROP_READER(GtkTreeModelRow, parent)
+{
+ phpg_modelrow_t *row = (phpg_modelrow_t *) object;
+ GtkTreeIter parent;
+
+ if (gtk_tree_model_iter_parent(row->model, &parent, &row->iter)) {
+ phpg_modelrow_new(&return_value, row->model, &parent TSRMLS_CC);
+ } else {
+ ZVAL_NULL(return_value);
+ }
+ return SUCCESS;
+}
+
+PHPG_PROP_READER(GtkTreeModelRow, iter)
+{
+ GtkTreeIter *iter = &((phpg_modelrow_t *)object)->iter;
+ phpg_gboxed_new(&return_value, GTK_TYPE_TREE_ITER, iter, TRUE, TRUE TSRMLS_CC);
+ return SUCCESS;
+}
+
+PHPG_PROP_READER(GtkTreeModelRow, path)
+{
+ GtkTreePath *path;
+ phpg_modelrow_t *row = (phpg_modelrow_t *) object;
+
+ path = gtk_tree_model_get_path(row->model, &row->iter);
+ if (path) {
+ phpg_tree_path_to_zval(path, &return_value TSRMLS_CC);
+ gtk_tree_path_free(path);
+ return SUCCESS;
+ } else {
+ php_error(E_WARNING, "Could not get tree path");
+ return FAILURE;
+ }
+}
+
+static prop_info_t gtktreemodelrow_prop_info[] = {
+ { "model", PHPG_PROP_READ_FN(GtkTreeModelRow, model), NULL },
+ { "next", PHPG_PROP_READ_FN(GtkTreeModelRow, next), NULL },
+ { "parent", PHPG_PROP_READ_FN(GtkTreeModelRow, parent), NULL },
+ { "iter", PHPG_PROP_READ_FN(GtkTreeModelRow, iter), NULL },
+ { "path", PHPG_PROP_READ_FN(GtkTreeModelRow, path), NULL },
+ { NULL, NULL, NULL }
+};
+
+static void phpg_modelrow_free_object_storage(phpg_modelrow_t *object TSRMLS_DC)
+{
+ zend_hash_destroy(object->zobj.properties);
+ FREE_HASHTABLE(object->zobj.properties);
+ g_object_unref(object->model);
+ efree(object);
+}
+
+static zend_object_value phpg_modelrow_create_object(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value zov;
+ phpg_modelrow_t *object;
+
+ object = emalloc(sizeof(phpg_modelrow_t));
+ memset(object, 0, sizeof(phpg_modelrow_t));
+ phpg_init_object(object, ce);
+
+ zov.handlers = >ktreemodelrow_handlers;
+ zov.handle = zend_objects_store_put(object, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) phpg_modelrow_free_object_storage, NULL TSRMLS_CC);
+
+ return zov;
+}
+
+void phpg_modelrow_new(zval **zobj, GtkTreeModel *model, GtkTreeIter *iter TSRMLS_DC)
+{
+ phpg_modelrow_t *pobj = NULL;
+
+ assert(zobj != NULL);
+ if (*zobj == NULL) {
+ MAKE_STD_ZVAL(*zobj);
+ }
+ ZVAL_NULL(*zobj);
+
+ phpg_return_if_fail(model != NULL);
+ object_init_ex(*zobj, gtktreemodelrow_ce);
+ pobj = zend_object_store_get_object(*zobj TSRMLS_CC);
+ pobj->model = g_object_ref(model);
+ pobj->iter = *iter;
+}
+
+static void phpg_modelrowiter_new(zval **zobj, GtkTreeModel *model, GtkTreeIter *parent_iter TSRMLS_DC)
+{
+ phpg_modelrowiter_t *pobj = NULL;
+
+ assert(zobj != NULL);
+ if (*zobj == NULL) {
+ MAKE_STD_ZVAL(*zobj);
+ }
+ ZVAL_NULL(*zobj);
+
+ phpg_return_if_fail(model != NULL);
+ object_init_ex(*zobj, gtktreemodelrowiter_ce);
+ pobj = zend_object_store_get_object(*zobj TSRMLS_CC);
+ pobj->model = g_object_ref(model);
+ pobj->parent_iter = parent_iter;
+ pobj->is_valid = gtk_tree_model_iter_children(pobj->model, &pobj->iter, pobj->parent_iter);
+}
+
+static void phpg_modelrowiter_free_object_storage(phpg_modelrowiter_t *object TSRMLS_DC)
+{
+ zend_hash_destroy(object->zobj.properties);
+ FREE_HASHTABLE(object->zobj.properties);
+ if (object->current) {
+ zval_ptr_dtor(&object->current);
+ }
+ g_object_unref(object->model);
+ efree(object);
+}
+
+static zend_object_value phpg_modelrowiter_create_object(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value zov;
+ phpg_modelrowiter_t *object;
+
+ object = emalloc(sizeof(phpg_modelrowiter_t));
+ memset(object, 0, sizeof(phpg_modelrowiter_t));
+ phpg_init_object(object, ce);
+
+ zov.handlers = &php_gtk_handlers;
+ zov.handle = zend_objects_store_put(object, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) phpg_modelrowiter_free_object_storage, NULL TSRMLS_CC);
+
+ return zov;
+}
+
+static inline phpg_modelrowiter_t* modelrowiter_to_obj(zend_object_iterator *iter)
+{
+ return (phpg_modelrowiter_t *)((char*)iter - offsetof(phpg_modelrowiter_t, ziter));
+}
+
+static void treemodelrow_iter_dtor(zend_object_iterator* iter TSRMLS_DC)
+{
+ phpg_modelrowiter_t *object = modelrowiter_to_obj(iter);
+ zval *zobj = (zval *) object->ziter.data;
+
+ zval_ptr_dtor(&zobj);
+}
+
+static int treemodelrow_iter_valid(zend_object_iterator* iter TSRMLS_DC)
+{
+ phpg_modelrowiter_t *object = modelrowiter_to_obj(iter);
+
+ if (object->is_valid)
+ return SUCCESS;
+ else
+ return FAILURE;
+}
+
+static void treemodelrow_iter_get_current_data(zend_object_iterator* iter, zval*** data TSRMLS_DC)
+{
+ phpg_modelrowiter_t *object = modelrowiter_to_obj(iter);
+
+ if (!object->current) {
+ MAKE_STD_ZVAL(object->current);
+ phpg_modelrow_new(&object->current, object->model, &object->iter TSRMLS_CC);
+ }
+
+ *data = &object->current;
+}
+
+static int treemodelrow_iter_get_current_key(zend_object_iterator* iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+{
+ phpg_modelrowiter_t *object = modelrowiter_to_obj(iter);
+
+ *int_key = object->index;
+ return HASH_KEY_IS_LONG;
+}
+
+static void treemodelrow_iter_move_forward(zend_object_iterator* iter TSRMLS_DC)
+{
+ phpg_modelrowiter_t *object = modelrowiter_to_obj(iter);
+
+ object->is_valid = gtk_tree_model_iter_next(object->model, &object->iter);
+ object->index++;
+ if (object->current) {
+ zval_ptr_dtor(&object->current);
+ object->current = NULL;
+ }
+}
+
+static void treemodelrow_iter_rewind(zend_object_iterator* iter TSRMLS_DC)
+{
+ phpg_modelrowiter_t *object = modelrowiter_to_obj(iter);
+
+ object->is_valid = gtk_tree_model_iter_children(object->model, &object->iter,
+ object->parent_iter);
+ object->index = 0;
+ if (object->current) {
+ zval_ptr_dtor(&object->current);
+ object->current = NULL;
+ }
+}
+
+
+static zend_object_iterator_funcs treemodelrow_iter_funcs = {
+ treemodelrow_iter_dtor,
+ treemodelrow_iter_valid,
+ treemodelrow_iter_get_current_data,
+ treemodelrow_iter_get_current_key,
+ treemodelrow_iter_move_forward,
+ treemodelrow_iter_rewind,
+};
+
+zend_object_iterator* phpg_modelrowiter_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC)
+{
+ phpg_modelrowiter_t *iter_obj;
+
+ /* TODO see if Marcus can do the by_ref stuff for PHP 5
+ if (by_ref) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+ */
+
+ iter_obj = (phpg_modelrowiter_t *) zend_object_store_get_object(object TSRMLS_CC);
+
+ ZVAL_ADDREF(object);
+ iter_obj->ziter.data = (void *) object;
+ iter_obj->ziter.funcs = &treemodelrow_iter_funcs;
+
+ return (zend_object_iterator *) &iter_obj->ziter;
+}
+
+zend_object_iterator* phpg_treemodel_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC)
+{
+ phpg_modelrowiter_t *iter_obj;
+ zval *zobj = NULL;
+
+ /* TODO see if Marcus can do the by_ref stuff for PHP 5
+ if (by_ref) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+ */
+
+ phpg_modelrowiter_new(&zobj, GTK_TREE_MODEL(PHPG_GOBJECT(object)), NULL TSRMLS_CC);
+ iter_obj = (phpg_modelrowiter_t *) zend_object_store_get_object(zobj TSRMLS_CC);
+
+ iter_obj->ziter.data = (void *) zobj;
+ iter_obj->ziter.funcs = &treemodelrow_iter_funcs;
+
+ return (zend_object_iterator *) &iter_obj->ziter;
+}
+
+
+static zval* treemodelrow_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
+{
+ phpg_modelrow_t *row;
+ GValue gvalue = { 0, };
+ zval *value = NULL;
+ int n_columns;
+ int column;
+
+ if (Z_TYPE_P(offset) != IS_LONG) {
+ php_error(E_WARNING, "Illegal index type");
+ return 0;
+ }
+
+ row = zend_object_store_get_object(object TSRMLS_CC);
+ n_columns = gtk_tree_model_get_n_columns(row->model);
+ column = Z_LVAL_P(offset);
+
+ if (column < 0) {
+ column += n_columns;
+ }
+
+ if (column < 0 || column >= n_columns) {
+ php_error(E_WARNING, "Index out of range");
+ return 0;
+ }
+
+ MAKE_STD_ZVAL(value);
+ ZVAL_NULL(value);
+ value->refcount = 0;
+ value->is_ref = 0;
+
+ gtk_tree_model_get_value(row->model, &row->iter, column, &gvalue);
+ phpg_gvalue_to_zval(&gvalue, &value, TRUE, TRUE TSRMLS_CC);
+ g_value_unset(&gvalue);
+
+ return value;
+}
+
+static void treemodelrow_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
+{
+ phpg_modelrow_t *row;
+ GValue gvalue = { 0, };
+ int n_columns;
+ int column;
+
+ if (Z_TYPE_P(offset) != IS_LONG) {
+ php_error(E_WARNING, "Illegal index type");
+ return;
+ }
+
+ row = zend_object_store_get_object(object TSRMLS_CC);
+ if (!GTK_IS_LIST_STORE(row->model) && !GTK_IS_TREE_STORE(row->model)) {
+ php_error(E_WARNING, "Unknown tree model");
+ return;
+ }
+
+ n_columns = gtk_tree_model_get_n_columns(row->model);
+ column = Z_LVAL_P(offset);
+
+ if (column < 0) {
+ column += n_columns;
+ }
+
+ if (column < 0 || column >= n_columns) {
+ php_error(E_WARNING, "Index out of range");
+ return;
+ }
+
+ g_value_init(&gvalue, gtk_tree_model_get_column_type(row->model, column));
+ if (phpg_gvalue_from_zval(&gvalue, value, TRUE TSRMLS_CC) == FAILURE) {
+ php_error(E_WARNING, "Cannot set cell: the type of value does not match the model column");
+ return;
+ }
+
+ if (GTK_IS_LIST_STORE(row->model)) {
+ gtk_list_store_set_value(GTK_LIST_STORE(row->model), &row->iter, column, &gvalue);
+ } else {
+ gtk_tree_store_set_value(GTK_TREE_STORE(row->model), &row->iter, column, &gvalue);
+ }
+
+ g_value_unset(&gvalue);
+}
+
+static int treemodelrow_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC)
+{
+ phpg_modelrow_t *row;
+ int n_columns;
+ int column;
+
+ if (Z_TYPE_P(offset) != IS_LONG) {
+ php_error(E_WARNING, "Illegal index type");
+ return 0;
+ }
+
+ row = zend_object_store_get_object(object TSRMLS_CC);
+ n_columns = gtk_tree_model_get_n_columns(row->model);
+ column = Z_LVAL_P(offset);
+
+ if (column + n_columns < 0 || column >= n_columns) {
+ php_error(E_WARNING, "Index out of range");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int treemodelrow_count_elements(zval *object, long *count TSRMLS_DC)
+{
+ phpg_modelrow_t *row = zend_object_store_get_object(object TSRMLS_CC);
+ *count = gtk_tree_model_get_n_columns(row->model);
+ return SUCCESS;
+}
+
/* }}} */
-void php_gtk_plus_register_types()
+void php_gtk_plus_register_types(TSRMLS_D)
{
+ gtktreemodelrow_ce = phpg_register_class("GtkTreeModelRow", gtktreemodelrow_methods, NULL, ZEND_ACC_FINAL_CLASS, gtktreemodelrow_prop_info, phpg_modelrow_create_object, 0 TSRMLS_CC);
+ gtktreemodelrow_handlers = php_gtk_handlers;
+ gtktreemodelrow_handlers.read_dimension = treemodelrow_read_dimension;
+ gtktreemodelrow_handlers.write_dimension = treemodelrow_write_dimension;
+ gtktreemodelrow_handlers.has_dimension = treemodelrow_has_dimension;
+ gtktreemodelrow_handlers.count_elements = treemodelrow_count_elements;
+
+ gtktreemodelrowiter_ce = phpg_register_class("GtkTreeModelRowIterator", NULL, NULL, ZEND_ACC_FINAL_CLASS, NULL, phpg_modelrowiter_create_object, 0 TSRMLS_CC);
+ gtktreemodelrowiter_ce->get_iterator = phpg_modelrowiter_get_iterator;
+ zend_class_implements(gtktreemodelrowiter_ce TSRMLS_CC, 1, zend_ce_traversable);
+
+
phpg_gboxed_register_custom(GDK_TYPE_RECTANGLE,
phpg_gdk_rectangle_from_zval,
phpg_gdk_rectangle_to_zval);