mirror of
https://github.com/php/php-gtk-src.git
synced 2026-03-24 01:02:08 +01:00
issue with the zend destructor using type and getting confused when there was no type - only showed up on release builds on win32 (grrr stupid thing) - also fixed the compiler detection and flags. This probably breaks things for older then 2008 compilers, really don't care
556 lines
18 KiB
C
556 lines
18 KiB
C
/*
|
|
* PHP-GTK - The PHP language bindings for GTK+
|
|
*
|
|
* Copyright (C) 2001-2008 Andrei Zmievski <andrei@php.net>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "php_gtk.h"
|
|
|
|
#if HAVE_PHP_GTK
|
|
|
|
/*
|
|
* GValue related functions
|
|
*/
|
|
|
|
|
|
/* {{{ PHP_GTK_API phpg_gvalue_to_zval() */
|
|
PHP_GTK_API int phpg_gvalue_to_zval(const GValue *gval, zval **value, zend_bool copy_boxed, zend_bool do_utf8 TSRMLS_DC)
|
|
{
|
|
assert(value != NULL);
|
|
|
|
switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(gval))) {
|
|
case G_TYPE_INVALID:
|
|
case G_TYPE_NONE:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_NULL(*value);
|
|
break;
|
|
|
|
case G_TYPE_CHAR:
|
|
{
|
|
gchar val = g_value_get_char(gval);
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_STRINGL(*value, (char *)&val, 1, 1);
|
|
}
|
|
break;
|
|
|
|
case G_TYPE_UCHAR:
|
|
{
|
|
guchar val = g_value_get_uchar(gval);
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_STRINGL(*value, (char *)&val, 1, 1);
|
|
}
|
|
break;
|
|
|
|
case G_TYPE_BOOLEAN:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_BOOL(*value, g_value_get_boolean(gval));
|
|
break;
|
|
|
|
case G_TYPE_INT:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_LONG(*value, (long)g_value_get_int(gval));
|
|
break;
|
|
|
|
case G_TYPE_LONG:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_LONG(*value, (long)g_value_get_long(gval));
|
|
break;
|
|
|
|
case G_TYPE_UINT:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_LONG(*value, (long)g_value_get_uint(gval));
|
|
break;
|
|
|
|
case G_TYPE_ULONG:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_LONG(*value, (long)g_value_get_ulong(gval));
|
|
break;
|
|
|
|
case G_TYPE_FLOAT:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_DOUBLE(*value, (double)g_value_get_float(gval));
|
|
break;
|
|
|
|
case G_TYPE_DOUBLE:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_DOUBLE(*value, (double)g_value_get_double(gval));
|
|
break;
|
|
|
|
case G_TYPE_ENUM:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_LONG(*value, (long)g_value_get_enum(gval));
|
|
break;
|
|
|
|
case G_TYPE_FLAGS:
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_LONG(*value, (long)g_value_get_flags(gval));
|
|
break;
|
|
|
|
case G_TYPE_STRING:
|
|
{
|
|
gchar *cp = NULL;
|
|
gsize cp_len = 0;
|
|
zend_bool free_cp = 0;
|
|
const gchar *str = g_value_get_string(gval);
|
|
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
if (str != NULL) {
|
|
if (do_utf8) {
|
|
cp = phpg_from_utf8(str, strlen(str), &cp_len, &free_cp TSRMLS_CC);
|
|
if (cp) {
|
|
str = cp;
|
|
} else {
|
|
php_error(E_WARNING, "Could not convert string from UTF-8");
|
|
}
|
|
}
|
|
ZVAL_STRING(*value, (char *)str, 1);
|
|
if (free_cp) {
|
|
g_free(cp);
|
|
}
|
|
} else
|
|
ZVAL_NULL(*value);
|
|
}
|
|
break;
|
|
|
|
case G_TYPE_PARAM:
|
|
phpg_paramspec_new(value, g_value_get_param(gval) TSRMLS_CC);
|
|
break;
|
|
|
|
case G_TYPE_OBJECT:
|
|
phpg_gobject_new(value, g_value_get_object(gval) TSRMLS_CC);
|
|
break;
|
|
|
|
case G_TYPE_INTERFACE:
|
|
if (g_type_is_a(G_VALUE_TYPE(gval), G_TYPE_OBJECT)) {
|
|
phpg_gobject_new(value, g_value_get_object(gval) TSRMLS_CC);
|
|
} else {
|
|
php_error(E_WARNING, "Could not access interface %s", g_type_name(G_VALUE_TYPE(gval)));
|
|
MAKE_STD_ZVAL(*value);
|
|
ZVAL_NULL(*value);
|
|
return FAILURE;
|
|
}
|
|
break;
|
|
|
|
case G_TYPE_POINTER:
|
|
phpg_gpointer_new(value, G_VALUE_TYPE(gval), g_value_get_pointer(gval) TSRMLS_CC);
|
|
break;
|
|
|
|
case G_TYPE_BOXED:
|
|
{
|
|
phpg_gboxed_marshal_t *gbm;
|
|
|
|
if (G_VALUE_HOLDS(gval, G_TYPE_PHP_VALUE)) {
|
|
zval *object = (zval *) g_value_dup_boxed(gval);
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
ZVAL_NULL(*value);
|
|
if (object) {
|
|
REPLACE_ZVAL_VALUE(value, object, 1);
|
|
zval_ptr_dtor(&object);
|
|
return SUCCESS;
|
|
} else {
|
|
ZVAL_NULL(*value);
|
|
return FAILURE;
|
|
}
|
|
} else if (G_VALUE_HOLDS(gval, G_TYPE_VALUE_ARRAY)) {
|
|
int i;
|
|
zval *item;
|
|
int value_count;
|
|
|
|
GValueArray *array = (GValueArray *) g_value_get_boxed(gval);
|
|
MAKE_ZVAL_IF_NULL(*value);
|
|
array_init(*value);
|
|
value_count = array->n_values;
|
|
|
|
for (i = 0; i < value_count; i++) {
|
|
MAKE_STD_ZVAL(item);
|
|
phpg_gvalue_to_zval(array->values + i, &item, copy_boxed, TRUE TSRMLS_CC);
|
|
add_next_index_zval(*value, item);
|
|
}
|
|
} else if ((gbm = phpg_gboxed_lookup_custom(G_VALUE_TYPE(gval)))) {
|
|
MAKE_STD_ZVAL(*value);
|
|
return gbm->to_zval(gval, value TSRMLS_CC);
|
|
} else {
|
|
if (copy_boxed) {
|
|
phpg_gboxed_new(value, G_VALUE_TYPE(gval), g_value_get_boxed(gval), TRUE, TRUE TSRMLS_CC);
|
|
} else {
|
|
phpg_gboxed_new(value, G_VALUE_TYPE(gval), g_value_get_boxed(gval), FALSE, FALSE TSRMLS_CC);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
php_error(E_WARNING, "PHP-GTK internal error: unsupported type %s", g_type_name(G_VALUE_TYPE(gval)));
|
|
MAKE_STD_ZVAL(*value);
|
|
ZVAL_NULL(*value);
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_GTK_API phpg_gvalue_from_zval() */
|
|
PHP_GTK_API int phpg_gvalue_from_zval(GValue *gval, zval **value, zend_bool do_utf8 TSRMLS_DC)
|
|
{
|
|
switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(gval))) {
|
|
/*
|
|
* For whatever reason, we should apparently respect that the gval may be of these
|
|
* types and they do not need a value.
|
|
*/
|
|
case G_TYPE_INVALID:
|
|
case G_TYPE_NONE:
|
|
break;
|
|
|
|
case G_TYPE_BOOLEAN:
|
|
convert_to_boolean_ex(value);
|
|
g_value_set_boolean(gval, (gboolean)Z_BVAL_PP(value));
|
|
break;
|
|
|
|
case G_TYPE_CHAR:
|
|
convert_to_string_ex(value);
|
|
g_value_set_char(gval, Z_STRVAL_PP(value)[0]);
|
|
break;
|
|
|
|
case G_TYPE_UCHAR:
|
|
convert_to_string_ex(value);
|
|
g_value_set_uchar(gval, (guchar)Z_STRVAL_PP(value)[0]);
|
|
break;
|
|
|
|
case G_TYPE_INT:
|
|
convert_to_long_ex(value);
|
|
g_value_set_int(gval, (gint)Z_LVAL_PP(value));
|
|
break;
|
|
|
|
case G_TYPE_UINT:
|
|
convert_to_long_ex(value);
|
|
g_value_set_uint(gval, (guint)Z_LVAL_PP(value));
|
|
break;
|
|
|
|
case G_TYPE_LONG:
|
|
convert_to_long_ex(value);
|
|
g_value_set_long(gval, (glong)Z_LVAL_PP(value));
|
|
break;
|
|
|
|
case G_TYPE_ULONG:
|
|
convert_to_long_ex(value);
|
|
g_value_set_ulong(gval, (gulong)Z_LVAL_PP(value));
|
|
break;
|
|
|
|
case G_TYPE_FLOAT:
|
|
convert_to_double_ex(value);
|
|
g_value_set_float(gval, (gfloat)Z_DVAL_PP(value));
|
|
break;
|
|
|
|
case G_TYPE_DOUBLE:
|
|
convert_to_double_ex(value);
|
|
g_value_set_double(gval, Z_DVAL_PP(value));
|
|
break;
|
|
|
|
case G_TYPE_ENUM:
|
|
{
|
|
gint val = 0;
|
|
if (phpg_gvalue_get_enum(G_VALUE_TYPE(gval), *value, &val) == FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
g_value_set_enum(gval, val);
|
|
break;
|
|
}
|
|
|
|
case G_TYPE_FLAGS:
|
|
{
|
|
gint val = 0;
|
|
if (phpg_gvalue_get_flags(G_VALUE_TYPE(gval), *value, &val) == FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
g_value_set_flags(gval, val);
|
|
break;
|
|
}
|
|
|
|
case G_TYPE_STRING:
|
|
{
|
|
gchar *utf8 = NULL;
|
|
gsize utf8_len = 0;
|
|
zend_bool free_utf8 = 0;
|
|
gchar *str;
|
|
|
|
convert_to_string_ex(value);
|
|
str = Z_STRVAL_PP(value);
|
|
if (do_utf8) {
|
|
utf8 = phpg_to_utf8(Z_STRVAL_PP(value), Z_STRLEN_PP(value), &utf8_len, &free_utf8 TSRMLS_CC);
|
|
if (utf8) {
|
|
str = utf8;
|
|
} else {
|
|
php_error(E_WARNING, "Could not convert string to UTF-8");
|
|
}
|
|
}
|
|
g_value_set_string(gval, str);
|
|
if (free_utf8) {
|
|
g_free(utf8);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case G_TYPE_POINTER:
|
|
if (Z_TYPE_PP(value) == IS_NULL) {
|
|
g_value_set_pointer(gval, NULL);
|
|
} else if (Z_TYPE_PP(value) == IS_OBJECT
|
|
&& instanceof_function(Z_OBJCE_PP(value), gpointer_ce TSRMLS_CC)
|
|
&& G_VALUE_HOLDS(gval, ((phpg_gpointer_t*)PHPG_GET(*value))->gtype)) {
|
|
g_value_set_pointer(gval, ((phpg_gpointer_t*)PHPG_GET(*value))->pointer);
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
break;
|
|
|
|
case G_TYPE_BOXED:
|
|
{
|
|
phpg_gboxed_marshal_t *gbm;
|
|
|
|
if (Z_TYPE_PP(value) == IS_NULL) {
|
|
g_value_set_boxed(gval, NULL);
|
|
/*
|
|
* We should be safe just setting the zval here, since G_TYPE_PHP_VALUE is
|
|
* supposed to take any zval type.
|
|
*/
|
|
} else if (G_VALUE_HOLDS(gval, G_TYPE_PHP_VALUE)) {
|
|
g_value_set_boxed(gval, *value);
|
|
} else if (Z_TYPE_PP(value) == IS_OBJECT
|
|
&& instanceof_function(Z_OBJCE_PP(value), gboxed_ce TSRMLS_CC)
|
|
&& G_VALUE_HOLDS(gval, ((phpg_gboxed_t*)PHPG_GET(*value))->gtype)) {
|
|
g_value_set_boxed(gval, PHPG_GBOXED(*value));
|
|
} else if ((gbm = phpg_gboxed_lookup_custom(G_VALUE_TYPE(gval)))) {
|
|
return gbm->from_zval(*value, gval TSRMLS_CC);
|
|
} else
|
|
return FAILURE;
|
|
break;
|
|
}
|
|
|
|
case G_TYPE_PARAM:
|
|
if (php_gtk_check_class(*value, gparamspec_ce)) {
|
|
g_value_set_param(gval, PHPG_GPARAMSPEC(*value));
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
break;
|
|
|
|
case G_TYPE_OBJECT:
|
|
if (Z_TYPE_PP(value) == IS_NULL) {
|
|
g_value_set_object(gval, NULL);
|
|
} else if (Z_TYPE_P(*value) == IS_OBJECT
|
|
&& instanceof_function(Z_OBJCE_PP(value), gobject_ce TSRMLS_CC)
|
|
&& G_TYPE_CHECK_INSTANCE_TYPE(PHPG_GOBJECT(*value), G_VALUE_TYPE(gval))) {
|
|
g_value_set_object(gval, PHPG_GOBJECT(*value));
|
|
} else
|
|
return FAILURE;
|
|
break;
|
|
|
|
case G_TYPE_INTERFACE:
|
|
if (g_type_is_a(G_VALUE_TYPE(gval), G_TYPE_OBJECT) &&
|
|
Z_TYPE_PP(value) == IS_OBJECT &&
|
|
G_TYPE_CHECK_INSTANCE_TYPE(PHPG_GOBJECT(*value), G_VALUE_TYPE(gval))) {
|
|
g_value_set_object(gval, PHPG_GOBJECT(*value));
|
|
} else {
|
|
php_error(E_WARNING, "Could not access interface %s", g_type_name(G_VALUE_TYPE(gval)));
|
|
return FAILURE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
php_error(E_WARNING, "PHP-GTK internal error: unsupported type %s", g_type_name(G_VALUE_TYPE(gval)));
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_GTK_API phpg_param_gvalue_to_zval() */
|
|
PHP_GTK_API int phpg_param_gvalue_to_zval(const GValue *gval, zval **value, zend_bool copy_boxed, const GParamSpec *pspec TSRMLS_DC)
|
|
{
|
|
if (G_IS_PARAM_SPEC_UNICHAR(pspec)) {
|
|
/* TODO */
|
|
return FAILURE;
|
|
} else {
|
|
return phpg_gvalue_to_zval(gval, value, copy_boxed, TRUE TSRMLS_CC);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_GTK_API phpg_param_gvalue_from_zval() */
|
|
PHP_GTK_API int phpg_param_gvalue_from_zval(GValue *gval, zval **value, const GParamSpec *pspec TSRMLS_DC)
|
|
{
|
|
if (G_IS_PARAM_SPEC_UNICHAR(pspec)) {
|
|
/* TODO */
|
|
return FAILURE;
|
|
} else {
|
|
return phpg_gvalue_from_zval(gval, value, TRUE TSRMLS_CC);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_GTK_API phpg_gvalues_to_array() */
|
|
PHP_GTK_API zval *phpg_gvalues_to_array(const GValue *values, uint n_values)
|
|
{
|
|
zval *hash;
|
|
zval *item = NULL;
|
|
int i;
|
|
int value_count;
|
|
|
|
MAKE_STD_ZVAL(hash);
|
|
array_init(hash);
|
|
value_count = n_values;
|
|
|
|
for (i = 0; i < value_count; i++) {
|
|
//item = phpg_gvalue_to_zval(&values[i], FALSE);
|
|
if (!item) {
|
|
MAKE_STD_ZVAL(item);
|
|
ZVAL_NULL(item);
|
|
}
|
|
zend_hash_next_index_insert(Z_ARRVAL_P(hash), &item, sizeof(zval *), NULL);
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_GTK_API phpg_gvalue_get_enum() */
|
|
PHP_GTK_API int phpg_gvalue_get_enum(GType enum_type, zval *enum_val, gint *result)
|
|
{
|
|
if (result == NULL)
|
|
return FAILURE;
|
|
|
|
if (enum_val == NULL) {
|
|
*result = 0;
|
|
} else if (Z_TYPE_P(enum_val) == IS_LONG) {
|
|
*result = Z_LVAL_P(enum_val);
|
|
} else if (Z_TYPE_P(enum_val) == IS_STRING) {
|
|
GEnumClass *eclass = NULL;
|
|
GEnumValue *info = NULL;
|
|
|
|
if (enum_type != G_TYPE_NONE) {
|
|
eclass = G_ENUM_CLASS(g_type_class_ref(enum_type));
|
|
} else {
|
|
php_error(E_WARNING, "PHP-GTK internal error: could not obtain the type of enum");
|
|
return FAILURE;
|
|
}
|
|
|
|
info = g_enum_get_value_by_name(eclass, Z_STRVAL_P(enum_val));
|
|
|
|
if (info == NULL) {
|
|
info = g_enum_get_value_by_nick(eclass, Z_STRVAL_P(enum_val));
|
|
}
|
|
g_type_class_unref(eclass);
|
|
|
|
if (info != NULL) {
|
|
*result = info->value;
|
|
} else {
|
|
php_error(E_WARNING, "PHP-GTK internal error: could not convert '%s' to enum", Z_STRVAL_P(enum_val));
|
|
return FAILURE;
|
|
}
|
|
} else {
|
|
php_error(E_WARNING, "PHP-GTK internal error: enums must be strings or integers");
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_GTK_API phpg_gvalue_get_flags() */
|
|
PHP_GTK_API int phpg_gvalue_get_flags(GType flags_type, zval *flags_val, gint *result)
|
|
{
|
|
GFlagsClass *fclass = NULL;
|
|
GFlagsValue *info = NULL;
|
|
|
|
if (result == NULL)
|
|
return FAILURE;
|
|
|
|
if (flags_val == NULL) {
|
|
*result = 0;
|
|
} else if (Z_TYPE_P(flags_val) == IS_LONG) {
|
|
*result = Z_LVAL_P(flags_val);
|
|
} else if (Z_TYPE_P(flags_val) == IS_STRING) {
|
|
if (flags_type != G_TYPE_NONE) {
|
|
fclass = G_FLAGS_CLASS(g_type_class_ref(flags_type));
|
|
} else {
|
|
php_error(E_WARNING, "PHP-GTK internal error: could not obtain the type of flags");
|
|
return FAILURE;
|
|
}
|
|
|
|
info = g_flags_get_value_by_name(fclass, Z_STRVAL_P(flags_val));
|
|
if (info == NULL) {
|
|
info = g_flags_get_value_by_nick(fclass, Z_STRVAL_P(flags_val));
|
|
}
|
|
g_type_class_unref(fclass);
|
|
|
|
if (info != NULL) {
|
|
*result = info->value;
|
|
} else {
|
|
php_error(E_WARNING, "PHP-GTK internal error: could not convert '%s' to flags", Z_STRVAL_P(flags_val));
|
|
return FAILURE;
|
|
}
|
|
} else if (Z_TYPE_P(flags_val) == IS_ARRAY) {
|
|
zval **flag;
|
|
|
|
*result = 0;
|
|
if (flags_type != G_TYPE_NONE) {
|
|
fclass = G_FLAGS_CLASS(g_type_class_ref(flags_type));
|
|
} else {
|
|
php_error(E_WARNING, "PHP-GTK internal error: could not obtain the type of flags");
|
|
return FAILURE;
|
|
}
|
|
|
|
for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(flags_val));
|
|
zend_hash_get_current_data(Z_ARRVAL_P(flags_val), (void **)&flag) == SUCCESS;
|
|
zend_hash_move_forward(Z_ARRVAL_P(flags_val))) {
|
|
|
|
if (Z_TYPE_PP(flag) == IS_LONG) {
|
|
*result |= Z_LVAL_PP(flag);
|
|
} else if (Z_TYPE_PP(flag) == IS_STRING) {
|
|
info = g_flags_get_value_by_name(fclass, Z_STRVAL_PP(flag));
|
|
if (info == NULL) {
|
|
info = g_flags_get_value_by_nick(fclass, Z_STRVAL_PP(flag));
|
|
}
|
|
if (info != NULL) {
|
|
*result |= info->value;
|
|
} else {
|
|
php_error(E_WARNING, "PHP-GTK internal error: could not convert '%s' to flags", Z_STRVAL_PP(flag));
|
|
g_type_class_unref(fclass);
|
|
return FAILURE;
|
|
}
|
|
} else {
|
|
php_error(E_WARNING, "PHP-GTK flag arrays can contain only integers or strings");
|
|
g_type_class_unref(fclass);
|
|
return 0;
|
|
}
|
|
}
|
|
g_type_class_unref(fclass);
|
|
} else {
|
|
php_error(E_WARNING, "PHP-GTK flags must be strings, integers, or arrays of strings or integers");
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
#endif
|
|
|
|
/* vim: set fdm=marker et : */
|