Hi, Attached is a patch that adds a generic cclosure marshaller using libffi to gobject. The reason for this is to allow signals of GObjects written in a language binding to call signal callbacks in C. It's not just a theoretical case, Edward Hervey recently ran into this problem while trying to prototype a GStreamer element in Python.
It has conditional support, perhaps it would be better to required a copy of libffi, but since there are no official releases since 1998 so you'd have to use the CVS version. Tom, do you have any plans to release a standalone version of libffi in the near future? Comments and suggestions on the patch are welcome. -- Johan Dahlin
Mudanças de propriedades em: tests/gobject ___________________________________________________________________ Nome: svn:ignore - Makefile Makefile.in accumulator defaultiface gvalue-test ifacecheck ifaceinherit ifaceinit ifaceproperties override references testmarshal.c testmarshal.h stamp-testmarshal.h paramspec-test .libs .deps + Makefile Makefile.in accumulator defaultiface gvalue-test ifacecheck ifaceinherit ifaceinit ifaceproperties override references testgenericmarshaller testmarshal.c testmarshal.h stamp-testmarshal.h paramspec-test .libs .deps Index: tests/gobject/testgenericmarshaller.c =================================================================== --- tests/gobject/testgenericmarshaller.c (revisão 0) +++ tests/gobject/testgenericmarshaller.c (revisão 0) @@ -0,0 +1,199 @@ +/* GObject - GLib Type, Object, Parameter and Signal Library + * testmarshallergeneric.c: Generic CClosure marshaller + * Copyright (C) 2007 Johan Dahlin + * + * 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 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 <string.h> +#include <glib-object.h> + +typedef struct { + GObject parent; +} TestObject; + +typedef struct { + GObjectClass parent_class; + void (* test1) (TestObject *object); + void (* test2) (TestObject *object, char *str); + int (* test3) (TestObject *object, int i); + void (* test4) (TestObject *object, + gboolean b, long l, float f, double d, + guint uint, gulong ulong); +} TestObjectClass; + +#define TEST_TYPE_OBJECT (test_object_get_type()) +#define TEST_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_OBJECT, TestObject)) +#define TEST_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OBJECT, TestObjectClass)) +#define TEST_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_OBJECT)) +#define TEST_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TEST_TYPE_OBJECT)) +#define TEST_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_OBJECT, TestObjectClass)) + +GType test_object_get_type (void); + +enum { + TEST1, + TEST2, + TEST3, + TEST4, + LAST_SIGNAL +}; + +static guint object_signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT); + +static void test_object_init (TestObject *self) +{ +} + +static void test_object_class_init (TestObjectClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass*) klass; + + object_signals[TEST1] = + g_signal_new ("test1", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (TestObjectClass, test1), + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, 0); + object_signals[TEST2] = + g_signal_new ("test2", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (TestObjectClass, test2), + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, 1, + G_TYPE_STRING); + object_signals[TEST3] = + g_signal_new ("test3", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TestObjectClass, test3), + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_INT, 1, + G_TYPE_DOUBLE); + object_signals[TEST4] = + g_signal_new ("test4", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TestObjectClass, test3), + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, 6, + G_TYPE_BOOLEAN, + G_TYPE_LONG, + G_TYPE_FLOAT, + G_TYPE_DOUBLE, + G_TYPE_UINT, + G_TYPE_ULONG); +} + +static void +test1_callback (TestObject *object, char *data) +{ + g_return_if_fail (TEST_IS_OBJECT (object)); + g_return_if_fail (!strcmp (data, "user-data")); +} + +static void +test1_callback_swapped (char *data, TestObject *object) +{ + g_return_if_fail (TEST_IS_OBJECT (object)); + g_return_if_fail (!strcmp (data, "user-data")); +} + +static void +test2_callback (TestObject *object, char *string) +{ + g_return_if_fail (TEST_IS_OBJECT (object)); + g_return_if_fail (!strcmp (string, "string")); +} + +static int +test3_callback (TestObject *object, double f) +{ + g_return_val_if_fail (TEST_IS_OBJECT (object), -1); + g_return_val_if_fail (f == 42.0, -1); + + return 20; +} + +static void +test4_callback (TestObject *object, + gboolean b, long l, float f, double d, guint uint, gulong ulong, + gpointer user_data) +{ + g_return_if_fail (b == TRUE); + g_return_if_fail (l == 10L); + g_return_if_fail (f <= 3.14001 && f >= 3.13999); + g_return_if_fail (d == 1.78); + g_return_if_fail (uint == 20); + g_return_if_fail (ulong == 30L); +} + +void +test_cclosure_marshal (void) +{ + TestObject *object; + gchar *data = "user-data"; + int i; + + g_type_init (); + + object = g_object_new (TEST_TYPE_OBJECT, NULL); + g_signal_connect (G_OBJECT (object), + "test1", + G_CALLBACK (test1_callback), + data); + g_signal_connect_swapped (G_OBJECT (object), + "test1", + G_CALLBACK (test1_callback_swapped), + data); + g_signal_connect (G_OBJECT (object), + "test2", + G_CALLBACK (test2_callback), + NULL); + g_signal_connect (G_OBJECT (object), + "test3", + G_CALLBACK (test3_callback), + NULL); + g_signal_connect (G_OBJECT (object), + "test4", + G_CALLBACK (test4_callback), + NULL); + + g_signal_emit (G_OBJECT (object), object_signals[TEST1], 0); + g_signal_emit (G_OBJECT (object), object_signals[TEST2], 0, "string"); + g_signal_emit (G_OBJECT (object), object_signals[TEST3], 0, 42.0, &i); + g_signal_emit (G_OBJECT (object), object_signals[TEST4], 0, + TRUE, 10L, 3.14, 1.78, 20, 30L); + g_assert (i == 20); + + g_object_unref (object); +} + +int main(void) +{ + test_cclosure_marshal (); + + return 0; +} + Index: tests/gobject/Makefile.am =================================================================== --- tests/gobject/Makefile.am (revisão 5317) +++ tests/gobject/Makefile.am (cópia de trabalho) @@ -60,6 +60,10 @@ singleton \ references +if HAVE_LIBFFI +test_programs += testgenericmarshaller +endif + check_PROGRAMS = $(test_programs) TESTS = $(test_programs) Index: gobject/ChangeLog =================================================================== --- gobject/ChangeLog (revisão 5317) +++ gobject/ChangeLog (cópia de trabalho) @@ -1,3 +1,11 @@ +2007-01-30 Johan Dahlin <[EMAIL PROTECTED]> + + * Makefile.am: + * gclosure.c: (g_value_to_ffi_type), (g_cclosure_marshal_generic): + * gclosure.h: + * gobject.symbols: + Add a generic signal cclosure marshaller using libffi. (#408010) + 2007-01-02 Tor Lillqvist <[EMAIL PROTECTED]> * glib-genmarshal.c (main): Handle "/dev/stdin" by dup()ing fd 0 Index: gobject/gobject.symbols =================================================================== --- gobject/gobject.symbols (revisão 5317) +++ gobject/gobject.symbols (cópia de trabalho) @@ -77,6 +77,7 @@ g_closure_sink g_closure_unref g_signal_type_cclosure_new +g_cclosure_marshal_generic #endif #endif Index: gobject/gclosure.c =================================================================== --- gobject/gclosure.c (revisão 5317) +++ gobject/gclosure.c (cópia de trabalho) @@ -1,6 +1,7 @@ /* GObject - GLib Type, Object, Parameter and Signal Library * Copyright (C) 2000-2001 Red Hat, Inc. * Copyright (C) 2005 Imendio AB + * Copyright (C) 2007 Johan Dahlin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,6 +18,9 @@ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. */ + +#include <config.h> + #include "gclosure.h" /* @@ -26,7 +30,9 @@ #include "gvalue.h" #include "gobjectalias.h" #include <string.h> - +#ifdef HAVE_FFI_H +#include <ffi.h> +#endif #define CLOSURE_MAX_REF_COUNT ((1 << 15) - 1) #define CLOSURE_MAX_N_GUARDS ((1 << 1) - 1) @@ -612,5 +618,139 @@ g_signal_type_cclosure_new (GType ity return closure; } +#ifdef HAVE_FFI_H +static ffi_type * +g_value_to_ffi_type (const GValue *gvalue, gpointer *value) +{ + ffi_type *rettype = NULL; + GType type = g_type_fundamental (G_VALUE_TYPE (gvalue)); + + switch (type) { + case G_TYPE_BOOLEAN: + case G_TYPE_CHAR: + case G_TYPE_INT: + rettype = &ffi_type_sint; + *value = (gpointer)&(gvalue->data[0].v_int); + break; + case G_TYPE_UCHAR: + case G_TYPE_UINT: + rettype = &ffi_type_uint; + *value = (gpointer)&(gvalue->data[0].v_uint); + break; + case G_TYPE_OBJECT: + case G_TYPE_STRING: + case G_TYPE_POINTER: + rettype = &ffi_type_pointer; + *value = (gpointer)&(gvalue->data[0].v_pointer); + break; + case G_TYPE_FLOAT: + rettype = &ffi_type_float; + *value = (gpointer)&(gvalue->data[0].v_float); + break; + case G_TYPE_DOUBLE: + rettype = &ffi_type_double; + *value = (gpointer)&(gvalue->data[0].v_double); + break; + case G_TYPE_LONG: + rettype = &ffi_type_slong; + *value = (gpointer)&(gvalue->data[0].v_long); + break; + case G_TYPE_ULONG: + rettype = &ffi_type_ulong; + *value = (gpointer)&(gvalue->data[0].v_ulong); + break; + case G_TYPE_INT64: + rettype = &ffi_type_sint64; + *value = (gpointer)&(gvalue->data[0].v_int64); + break; + case G_TYPE_UINT64: + rettype = &ffi_type_uint64; + *value = (gpointer)&(gvalue->data[0].v_uint64); + break; + default: + rettype = &ffi_type_pointer; + *value = NULL; + g_warning ("Unsupported fundamental type: %s", g_type_name (type)); + break; + } + return rettype; +} + +void +g_cclosure_marshal_generic (GClosure *closure, + GValue *return_gvalue, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + ffi_cif cif; + ffi_type *rtype, **atypes; + guint i, n_args; + gpointer instance, user_data, rvalue, *args; + GCClosure *cc = (GCClosure*) closure; + + /* If using connect_swapped, swap instance and user_data */ + if (G_CCLOSURE_SWAP_DATA (closure)) + { + instance = &closure->data; + user_data = (gpointer)&((param_values + 0)->data[0].v_pointer); + } + else + { + instance = (gpointer)&((param_values + 0)->data[0].v_pointer); + user_data = &closure->data; + } + + /* Add an extra argument for user_data */ + n_args = n_param_values + 1; + + atypes = g_new (ffi_type *, n_args); + args = g_new (gpointer, n_args); + + /* Normal Arguments: + * shortcut the first and the last argument, they'll always be pointers. + */ + atypes[0] = &ffi_type_pointer; + args[0] = instance; + for (i = 1; i < n_args - 1; i++) + atypes[i] = g_value_to_ffi_type (param_values + i, &args[i]); + atypes[n_args-1] = &ffi_type_pointer; + args[n_args-1] = user_data; + + /* Return value */ + if (return_gvalue) + { + rtype = g_value_to_ffi_type (return_gvalue, &rvalue); + } + else + { + rtype = &ffi_type_void; + rvalue = NULL; + } + + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK) + goto out; + + ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args); + + out: + g_free (atypes); + g_free (args); +} +#else +void +g_cclosure_marshal_generic (GClosure *closure, + GValue *return_gvalue, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + g_warning ("Glib was compiled without ffi support, " + "g_cclosure_marshal_generic is disabled."); +} +#endif + #define __G_CLOSURE_C__ #include "gobjectaliasdef.c" Index: gobject/Makefile.am =================================================================== --- gobject/Makefile.am (revisão 5317) +++ gobject/Makefile.am (cópia de trabalho) @@ -79,6 +79,10 @@ libgobject_2_0_la_LIBADD = $(libglib) +if HAVE_LIBFFI +libgobject_2_0_la_LIBADD += -lffi +endif + libgobject_2_0_la_DEPENDENCIES = $(gobject_win32_res) $(GOBJECT_DEF) # Index: gobject/gclosure.h =================================================================== --- gobject/gclosure.h (revisão 5317) +++ gobject/gclosure.h (cópia de trabalho) @@ -150,6 +150,12 @@ const GValue *param_values, gpointer invocation_hint); +void g_cclosure_marshal_generic (GClosure *closure, + GValue *return_gvalue, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); /* FIXME: OK: data_object::destroy -> closure_invalidate(); MIS: closure_invalidate() -> disconnect(closure); Index: configure.in =================================================================== --- configure.in (revisão 5317) +++ configure.in (cópia de trabalho) @@ -1376,6 +1376,18 @@ AC_MSG_RESULT($GIO) AC_SUBST(GIO) +dnl ********************* +dnl *** libffi checks *** +dnl ********************* + +AC_MSG_CHECKING(for ffi.h) +AC_TRY_CPP([#include <ffi.h>], gobject_ffi_h=yes, gobject_ffi_h=no) +if test $gobject_ffi_h = yes; then + AC_DEFINE(HAVE_FFI_H,1,[Have ffi.h include file]) +fi +AC_MSG_RESULT([$gobject_ffi_h]) +AM_CONDITIONAL(HAVE_LIBFFI, test "$gobject_ffi_h" = "yes") + dnl **************************************** dnl *** platform dependent source checks *** dnl **************************************** Index: ChangeLog =================================================================== --- ChangeLog (revisão 5317) +++ ChangeLog (cópia de trabalho) @@ -1,3 +1,10 @@ +2007-01-30 Johan Dahlin <[EMAIL PROTECTED]> + + * configure.in: + * tests/gobject/Makefile.am: + * tests/gobject/testgenericmarshaller.c: + Add a generic CClosure marshaller using libffi, (#401080) + 2007-01-26 Matthias Clasen <[EMAIL PROTECTED]> * configure.in: Define G_GNUC_INTERNAL for Sun Studio
_______________________________________________ gtk-devel-list mailing list gtk-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-devel-list