cvs: php-gtk /ext/libglade libglade.overrides
| From: | Andrei Zmievski | Date: | Sat, 05 Nov 2005 08:45:10 +0000 |
| Subject: | cvs: php-gtk /ext/libglade libglade.overrides | ||
| Groups: | php.gtk.cvs | ||
| Request: | Send a blank email to php-gtk-cvs+get-1998@lists.php.net to get a copy of this message | ||
andrei Sat Nov 5 03:45:10 2005 EDT
Modified files:
/php-gtk/ext/libglade libglade.overrides
Log:
* Re-implement GladeXML::signal_autoconnect() (too many changes)
* Add GladeXML::signal_autoconnect_instance()
* Adjust GladeXML::signal_connect() to use 'replace' type connection
when appropriate
http://cvs.php.net/diff.php/php-gtk/ext/libglade/libglade.overrides?r1=1.28&r2=1.29&ty=u Index: php-gtk/ext/libglade/libglade.overrides diff -u php-gtk/ext/libglade/libglade.overrides:1.28 php-gtk/ext/libglade/libglade.overrides:1.29 --- php-gtk/ext/libglade/libglade.overrides:1.28 Wed Nov 2 15:12:55 2005 +++ php-gtk/ext/libglade/libglade.overrides Sat Nov 5 03:45:07 2005 @@ -1,9 +1,18 @@ -/* vim: set ft=cpp: */ +/* vim: set ft=cpp fdm=marker et: */ %% headers #include <glade/glade.h> #include "php_gtk_api.h" +typedef struct { + zval *instance; + zval *extra; +} phpg_autoc_t; + +static void phpg_glade_signal_connect_auto(const gchar *handler_name, GObject *object, + const gchar *signal_name, const gchar *signal_data, + GObject *connect_object, gboolean after, phpg_autoc_t *data); + %% {{{ ignores [confirmed] %% ignore-glob @@ -99,35 +108,24 @@ %% override glade_xml_signal_connect -static void glade_signal_marshal(const gchar *handler_name, GObject *object, - const gchar *signal_name, const gchar *signal_data, - GObject *connect_object, gboolean after, - gpointer *data) +static void phpg_glade_signal_connect_one(const gchar *handler_name, GObject *object, + const gchar *signal_name, const gchar *signal_data, + GObject *connect_object, gboolean after, + gpointer *data) { phpg_cb_data_t *cbd = (phpg_cb_data_t *)data; char *callback_name; - int handler_id, n_args = 0; + int handler_id; GClosure *closure = NULL; zval *php_object = NULL, *php_connect_object = NULL; - zval *hash = NULL, ***args = NULL; TSRMLS_FETCH(); - if (!zend_is_callable(cbd->callback, 0, &callback_name)) { - php_error(E_WARNING, "unable to call GladeXML callback '%s' specified in %s on line %ld\n", - callback_name, cbd->src_filename, cbd->src_lineno); - efree(callback_name); - return; - } - if (connect_object) { phpg_gobject_new(&php_connect_object, (GObject*)connect_object TSRMLS_CC); - args = php_gtk_hash_as_array_offset(cbd->user_args, 1, &n_args); - args[0] = &php_connect_object; - hash = php_gtk_array_as_hash(args, n_args, 0, n_args); - closure = phpg_closure_new(cbd->callback, hash, PHPG_CONNECT_OBJECT TSRMLS_CC); - efree(args); + closure = phpg_closure_new(cbd->callback, cbd->user_args, PHPG_CONNECT_REPLACE, php_connect_object TSRMLS_CC); + zval_ptr_dtor(&php_connect_object); } else { - closure = phpg_closure_new(cbd->callback, cbd->user_args, PHPG_CONNECT_NORMAL TSRMLS_CC); + closure = phpg_closure_new(cbd->callback, cbd->user_args, PHPG_CONNECT_NORMAL, NULL TSRMLS_CC); } phpg_gobject_new(&php_object, (GObject*)object TSRMLS_CC); @@ -135,10 +133,10 @@ handler_id = g_signal_connect_closure(object, signal_name, closure, after); efree(callback_name); - efree(php_object); + zval_ptr_dtor(&php_object); } -PHP_METHOD(glade_xml_signal_connect) +PHP_METHOD { char *handlername = NULL; zval *callback = NULL, *extra = NULL; @@ -154,7 +152,7 @@ data = phpg_cb_data_new(callback, extra TSRMLS_CC); glade_xml_signal_connect_full(GLADE_XML(PHPG_GOBJECT(this_ptr)), handlername, - (GladeXMLConnectFunc)glade_signal_marshal, data); + (GladeXMLConnectFunc)phpg_glade_signal_connect_one, data); if (free_handlername) g_free(handlername); phpg_cb_data_destroy(data); @@ -164,74 +162,168 @@ %% override glade_xml_signal_autoconnect -static void glade_auto_signal_marshal(const gchar *handler_name, GObject *object, - const gchar *signal_name, const gchar *signal_data, - GObject *connect_object, gboolean after, - zval *data) +static void phpg_glade_signal_connect_auto(const gchar *handler_name, GObject *object, + const gchar *signal_name, const gchar *signal_data, + GObject *connect_object, gboolean after, phpg_autoc_t *data) { - zval *callback = NULL, *hash = NULL, ***args = NULL; - zval *php_object = NULL, *php_connect_object = NULL; + zval *callback = NULL, *php_object = NULL, *user_args = NULL; + zval **callback_data = NULL, **callback_ptr = NULL; GClosure *closure = NULL; - int handler_id, n_args = 0, len = 0, gtk_flag = 0; + int handler_id, len = 0, connect_normal = 1; char *php_class = NULL, *php_method = NULL; TSRMLS_FETCH(); - MAKE_STD_ZVAL(callback); - + /* + * First, check if the handler represents a static method. This can be used to invoke + * Gtk/Gdk functions, such as Gtk::main_quit(). It may refer to a user class, of + * course, but those connections are much less useful. + */ if (strstr(handler_name, "::")) { + /* If the handler is prefixed by '-', use simple signal connection. */ + if (handler_name[0] == '-') { + connect_normal = 0; + handler_name++; + } len = strcspn(handler_name, ":"); php_class = safe_estrndup(handler_name, len); php_method = strstr(handler_name, "::") + 2; + MAKE_STD_ZVAL(callback); array_init(callback); add_next_index_string(callback, php_class, 1); add_next_index_string(callback, php_method, 1); - - if (strcmp(php_class, "gtk") == 0 || strcmp(php_class, "gdk") == 0) { - gtk_flag = 1; - } - efree(php_class); } else { - ZVAL_STRING(callback, (char *)handler_name, 0); + /* + * Secondly, check if we are supposed to connect handlers to methods of the + * specified object - signal_autoconnect_instance(). + */ + if (data->instance) { + MAKE_STD_ZVAL(callback); + array_init(callback); + zval_add_ref(&data->instance); + add_next_index_zval(callback, data->instance); + add_next_index_string(callback, (char *)handler_name, 1); + user_args = data->extra; + + /* + * We verify callability right away, because classes cannot acquire new + * methods at runtime (unless you decide to stab yourself in the foot with + * runkit). + */ + if (!zend_is_callable(callback, 0, NULL)) { + php_error(E_NOTICE, "Unable to auto-connect handler '%s': no such method in the specified object of class '%s'", handler_name, Z_OBJCE_P(data->instance)->name); + return; + } + } else { + /* + * Thirdly, if we have no object, we must have a map representing non-default + * handler mappings of the form: + * + * array('handler' => <callback>) + * array('handler' => array(<callback> [, $arg1, $arg2, ...])) + * array('handler' => array(null [, $arg1, $arg2, ...])) + * + * where <callback> is the standard PHP callback form. If null is specified + * instead of callback, the connection will be made to the function of the + * same name as the handler. + */ + if (data->extra && zend_hash_find(Z_ARRVAL_P(data->extra), (char *)handler_name, strlen(handler_name) + 1, (void **)&callback_data) == SUCCESS) { + /* Check if the value is callable. */ + if (zend_is_callable(*callback_data, 0, NULL)) { + zval_add_ref(callback_data); + callback = *callback_data; + } else { + /* + * If not, check that it is an array with at least one entry, which is + * assumed to be the callback reference. + */ + if (Z_TYPE_PP(callback_data) != IS_ARRAY || + zend_hash_index_find(Z_ARRVAL_PP(callback_data), 0, (void **)&callback_ptr) == FAILURE) { + php_error(E_NOTICE, "Unable to auto-connect handler '%s': invalid callback data structure", handler_name); + return; + } + if (Z_TYPE_PP(callback_ptr) != IS_NULL) { + zval_add_ref(callback_ptr); + callback = *callback_ptr; + } + + /* Shift callback data - the rest are extra user arguments. */ + zend_hash_index_del(Z_ARRVAL_PP(callback_data), 0); + user_args = *callback_data; + } + } + } } - if (!zend_is_callable(callback, 0, NULL)) { - php_error(E_WARNING, "%s() is unable to autoconnect callback for handler '%s'", - get_active_function_name(TSRMLS_C), handler_name); - return; + /* + * Make a simple function callback if everything else failed. + */ + if (callback == NULL) { + MAKE_STD_ZVAL(callback); + ZVAL_STRING(callback, (char *)handler_name, 1); } - if (connect_object || gtk_flag) { - if (connect_object) { - phpg_gobject_new(&php_connect_object, (GObject*)connect_object TSRMLS_CC); - args = php_gtk_hash_as_array_offset(data, 1, &n_args); - args[0] = &php_connect_object; - hash = php_gtk_array_as_hash(args, n_args, 0, n_args); - efree(args); - } - closure = phpg_closure_new(callback, hash, PHPG_CONNECT_OBJECT TSRMLS_CC); + /* + * If we have a swapped connection object, make a PHP wrapper for it and use it with + * 'replace' type of connection. + */ + if (connect_object) { + zval *php_connect_object = NULL; + phpg_gobject_new(&php_connect_object, (GObject*)connect_object TSRMLS_CC); + closure = phpg_closure_new(callback, user_args, PHPG_CONNECT_REPLACE, php_connect_object TSRMLS_CC); + /* it's okay to decrement the only reference to the wrapper here - the GObject will save it! */ + zval_ptr_dtor(&php_connect_object); + } else if (!connect_normal) { + closure = phpg_closure_new(callback, user_args, PHPG_CONNECT_SIMPLE, NULL TSRMLS_CC); } else { - closure = phpg_closure_new(callback, data, PHPG_CONNECT_NORMAL TSRMLS_CC); + closure = phpg_closure_new(callback, user_args, PHPG_CONNECT_NORMAL, NULL TSRMLS_CC); } phpg_gobject_new(&php_object, (GObject*)object TSRMLS_CC); phpg_gobject_watch_closure(php_object, closure TSRMLS_CC); handler_id = g_signal_connect_closure(object, signal_name, closure, after); - efree(php_object); + /* same as above - okay to decrement the reference here */ + zval_ptr_dtor(&php_object); + zval_ptr_dtor(&callback); + if (user_args) { + zval_ptr_dtor(&user_args); + } +} + +PHP_METHOD +{ + zval *map = NULL; + phpg_autoc_t data; + + NOT_STATIC_METHOD(); + + if (!php_gtk_parse_args(ZEND_NUM_ARGS(), "|a", &map)) + return; + + data.instance = NULL; + data.extra = map; + glade_xml_signal_autoconnect_full(GLADE_XML(PHPG_GOBJECT(this_ptr)), + (GladeXMLConnectFunc)phpg_glade_signal_connect_auto, &data); } -PHP_METHOD(glade_xml_signal_autoconnect) +%% +add GladeXML signal_autoconnect_instance +PHP_METHOD { + zval *instance = NULL; zval *extra = NULL; + phpg_autoc_t data; NOT_STATIC_METHOD(); - if (!php_gtk_parse_varargs(ZEND_NUM_ARGS(), 0, &extra, "")) + if (!php_gtk_parse_varargs(ZEND_NUM_ARGS(), 1, &extra, "o", &instance)) return; + data.instance = instance; + data.extra = extra; glade_xml_signal_autoconnect_full(GLADE_XML(PHPG_GOBJECT(this_ptr)), - (GladeXMLConnectFunc)glade_auto_signal_marshal, extra); + (GladeXMLConnectFunc)phpg_glade_signal_connect_auto, &data); } %% }}}
http://cvs.php.net/diff.php/php-gtk/ext/libglade/libglade.overrides?r1=1.28&r2=1.29&ty=u Index: php-gtk/ext/libglade/libglade.overrides diff -u php-gtk/ext/libglade/libglade.overrides:1.28 php-gtk/ext/libglade/libglade.overrides:1.29 --- php-gtk/ext/libglade/libglade.overrides:1.28 Wed Nov 2 15:12:55 2005 +++ php-gtk/ext/libglade/libglade.overrides Sat Nov 5 03:45:07 2005 @@ -1,9 +1,18 @@ -/* vim: set ft=cpp: */ +/* vim: set ft=cpp fdm=marker et: */ %% headers #include <glade/glade.h> #include "php_gtk_api.h" +typedef struct { + zval *instance; + zval *extra; +} phpg_autoc_t; + +static void phpg_glade_signal_connect_auto(const gchar *handler_name, GObject *object, + const gchar *signal_name, const gchar *signal_data, + GObject *connect_object, gboolean after, phpg_autoc_t *data); + %% {{{ ignores [confirmed] %% ignore-glob @@ -99,35 +108,24 @@ %% override glade_xml_signal_connect -static void glade_signal_marshal(const gchar *handler_name, GObject *object, - const gchar *signal_name, const gchar *signal_data, - GObject *connect_object, gboolean after, - gpointer *data) +static void phpg_glade_signal_connect_one(const gchar *handler_name, GObject *object, + const gchar *signal_name, const gchar *signal_data, + GObject *connect_object, gboolean after, + gpointer *data) { phpg_cb_data_t *cbd = (phpg_cb_data_t *)data; char *callback_name; - int handler_id, n_args = 0; + int handler_id; GClosure *closure = NULL; zval *php_object = NULL, *php_connect_object = NULL; - zval *hash = NULL, ***args = NULL; TSRMLS_FETCH(); - if (!zend_is_callable(cbd->callback, 0, &callback_name)) { - php_error(E_WARNING, "unable to call GladeXML callback '%s' specified in %s on line %ld\n", - callback_name, cbd->src_filename, cbd->src_lineno); - efree(callback_name); - return; - } - if (connect_object) { phpg_gobject_new(&php_connect_object, (GObject*)connect_object TSRMLS_CC); - args = php_gtk_hash_as_array_offset(cbd->user_args, 1, &n_args); - args[0] = &php_connect_object; - hash = php_gtk_array_as_hash(args, n_args, 0, n_args); - closure = phpg_closure_new(cbd->callback, hash, PHPG_CONNECT_OBJECT TSRMLS_CC); - efree(args); + closure = phpg_closure_new(cbd->callback, cbd->user_args, PHPG_CONNECT_REPLACE, php_connect_object TSRMLS_CC); + zval_ptr_dtor(&php_connect_object); } else { - closure = phpg_closure_new(cbd->callback, cbd->user_args, PHPG_CONNECT_NORMAL TSRMLS_CC); + closure = phpg_closure_new(cbd->callback, cbd->user_args, PHPG_CONNECT_NORMAL, NULL TSRMLS_CC); } phpg_gobject_new(&php_object, (GObject*)object TSRMLS_CC); @@ -135,10 +133,10 @@ handler_id = g_signal_connect_closure(object, signal_name, closure, after); efree(callback_name); - efree(php_object); + zval_ptr_dtor(&php_object); } -PHP_METHOD(glade_xml_signal_connect) +PHP_METHOD { char *handlername = NULL; zval *callback = NULL, *extra = NULL; @@ -154,7 +152,7 @@ data = phpg_cb_data_new(callback, extra TSRMLS_CC); glade_xml_signal_connect_full(GLADE_XML(PHPG_GOBJECT(this_ptr)), handlername, - (GladeXMLConnectFunc)glade_signal_marshal, data); + (GladeXMLConnectFunc)phpg_glade_signal_connect_one, data); if (free_handlername) g_free(handlername); phpg_cb_data_destroy(data); @@ -164,74 +162,168 @@ %% override glade_xml_signal_autoconnect -static void glade_auto_signal_marshal(const gchar *handler_name, GObject *object, - const gchar *signal_name, const gchar *signal_data, - GObject *connect_object, gboolean after, - zval *data) +static void phpg_glade_signal_connect_auto(const gchar *handler_name, GObject *object, + const gchar *signal_name, const gchar *signal_data, + GObject *connect_object, gboolean after, phpg_autoc_t *data) { - zval *callback = NULL, *hash = NULL, ***args = NULL; - zval *php_object = NULL, *php_connect_object = NULL; + zval *callback = NULL, *php_object = NULL, *user_args = NULL; + zval **callback_data = NULL, **callback_ptr = NULL; GClosure *closure = NULL; - int handler_id, n_args = 0, len = 0, gtk_flag = 0; + int handler_id, len = 0, connect_normal = 1; char *php_class = NULL, *php_method = NULL; TSRMLS_FETCH(); - MAKE_STD_ZVAL(callback); - + /* + * First, check if the handler represents a static method. This can be used to invoke + * Gtk/Gdk functions, such as Gtk::main_quit(). It may refer to a user class, of + * course, but those connections are much less useful. + */ if (strstr(handler_name, "::")) { + /* If the handler is prefixed by '-', use simple signal connection. */ + if (handler_name[0] == '-') { + connect_normal = 0; + handler_name++; + } len = strcspn(handler_name, ":"); php_class = safe_estrndup(handler_name, len); php_method = strstr(handler_name, "::") + 2; + MAKE_STD_ZVAL(callback); array_init(callback); add_next_index_string(callback, php_class, 1); add_next_index_string(callback, php_method, 1); - - if (strcmp(php_class, "gtk") == 0 || strcmp(php_class, "gdk") == 0) { - gtk_flag = 1; - } - efree(php_class); } else { - ZVAL_STRING(callback, (char *)handler_name, 0); + /* + * Secondly, check if we are supposed to connect handlers to methods of the + * specified object - signal_autoconnect_instance(). + */ + if (data->instance) { + MAKE_STD_ZVAL(callback); + array_init(callback); + zval_add_ref(&data->instance); + add_next_index_zval(callback, data->instance); + add_next_index_string(callback, (char *)handler_name, 1); + user_args = data->extra; + + /* + * We verify callability right away, because classes cannot acquire new + * methods at runtime (unless you decide to stab yourself in the foot with + * runkit). + */ + if (!zend_is_callable(callback, 0, NULL)) { + php_error(E_NOTICE, "Unable to auto-connect handler '%s': no such method in the specified object of class '%s'", handler_name, Z_OBJCE_P(data->instance)->name); + return; + } + } else { + /* + * Thirdly, if we have no object, we must have a map representing non-default + * handler mappings of the form: + * + * array('handler' => <callback>) + * array('handler' => array(<callback> [, $arg1, $arg2, ...])) + * array('handler' => array(null [, $arg1, $arg2, ...])) + * + * where <callback> is the standard PHP callback form. If null is specified + * instead of callback, the connection will be made to the function of the + * same name as the handler. + */ + if (data->extra && zend_hash_find(Z_ARRVAL_P(data->extra), (char *)handler_name, strlen(handler_name) + 1, (void **)&callback_data) == SUCCESS) { + /* Check if the value is callable. */ + if (zend_is_callable(*callback_data, 0, NULL)) { + zval_add_ref(callback_data); + callback = *callback_data; + } else { + /* + * If not, check that it is an array with at least one entry, which is + * assumed to be the callback reference. + */ + if (Z_TYPE_PP(callback_data) != IS_ARRAY || + zend_hash_index_find(Z_ARRVAL_PP(callback_data), 0, (void **)&callback_ptr) == FAILURE) { + php_error(E_NOTICE, "Unable to auto-connect handler '%s': invalid callback data structure", handler_name); + return; + } + if (Z_TYPE_PP(callback_ptr) != IS_NULL) { + zval_add_ref(callback_ptr); + callback = *callback_ptr; + } + + /* Shift callback data - the rest are extra user arguments. */ + zend_hash_index_del(Z_ARRVAL_PP(callback_data), 0); + user_args = *callback_data; + } + } + } } - if (!zend_is_callable(callback, 0, NULL)) { - php_error(E_WARNING, "%s() is unable to autoconnect callback for handler '%s'", - get_active_function_name(TSRMLS_C), handler_name); - return; + /* + * Make a simple function callback if everything else failed. + */ + if (callback == NULL) { + MAKE_STD_ZVAL(callback); + ZVAL_STRING(callback, (char *)handler_name, 1); } - if (connect_object || gtk_flag) { - if (connect_object) { - phpg_gobject_new(&php_connect_object, (GObject*)connect_object TSRMLS_CC); - args = php_gtk_hash_as_array_offset(data, 1, &n_args); - args[0] = &php_connect_object; - hash = php_gtk_array_as_hash(args, n_args, 0, n_args); - efree(args); - } - closure = phpg_closure_new(callback, hash, PHPG_CONNECT_OBJECT TSRMLS_CC); + /* + * If we have a swapped connection object, make a PHP wrapper for it and use it with + * 'replace' type of connection. + */ + if (connect_object) { + zval *php_connect_object = NULL; + phpg_gobject_new(&php_connect_object, (GObject*)connect_object TSRMLS_CC); + closure = phpg_closure_new(callback, user_args, PHPG_CONNECT_REPLACE, php_connect_object TSRMLS_CC); + /* it's okay to decrement the only reference to the wrapper here - the GObject will save it! */ + zval_ptr_dtor(&php_connect_object); + } else if (!connect_normal) { + closure = phpg_closure_new(callback, user_args, PHPG_CONNECT_SIMPLE, NULL TSRMLS_CC); } else { - closure = phpg_closure_new(callback, data, PHPG_CONNECT_NORMAL TSRMLS_CC); + closure = phpg_closure_new(callback, user_args, PHPG_CONNECT_NORMAL, NULL TSRMLS_CC); } phpg_gobject_new(&php_object, (GObject*)object TSRMLS_CC); phpg_gobject_watch_closure(php_object, closure TSRMLS_CC); handler_id = g_signal_connect_closure(object, signal_name, closure, after); - efree(php_object); + /* same as above - okay to decrement the reference here */ + zval_ptr_dtor(&php_object); + zval_ptr_dtor(&callback); + if (user_args) { + zval_ptr_dtor(&user_args); + } +} + +PHP_METHOD +{ + zval *map = NULL; + phpg_autoc_t data; + + NOT_STATIC_METHOD(); + + if (!php_gtk_parse_args(ZEND_NUM_ARGS(), "|a", &map)) + return; + + data.instance = NULL; + data.extra = map; + glade_xml_signal_autoconnect_full(GLADE_XML(PHPG_GOBJECT(this_ptr)), + (GladeXMLConnectFunc)phpg_glade_signal_connect_auto, &data); } -PHP_METHOD(glade_xml_signal_autoconnect) +%% +add GladeXML signal_autoconnect_instance +PHP_METHOD { + zval *instance = NULL; zval *extra = NULL; + phpg_autoc_t data; NOT_STATIC_METHOD(); - if (!php_gtk_parse_varargs(ZEND_NUM_ARGS(), 0, &extra, "")) + if (!php_gtk_parse_varargs(ZEND_NUM_ARGS(), 1, &extra, "o", &instance)) return; + data.instance = instance; + data.extra = extra; glade_xml_signal_autoconnect_full(GLADE_XML(PHPG_GOBJECT(this_ptr)), - (GladeXMLConnectFunc)glade_auto_signal_marshal, extra); + (GladeXMLConnectFunc)phpg_glade_signal_connect_auto, &data); } %% }}}