diff options
-rw-r--r-- | girepository/ginvoke.c | 171 | ||||
-rw-r--r-- | girepository/girepository.h | 9 | ||||
-rw-r--r-- | tests/invoke/Makefile.am | 9 | ||||
-rw-r--r-- | tests/invoke/genericmarshaller.c | 204 |
4 files changed, 390 insertions, 3 deletions
diff --git a/girepository/ginvoke.c b/girepository/ginvoke.c index 89419e56..e83a8200 100644 --- a/girepository/ginvoke.c +++ b/girepository/ginvoke.c @@ -261,3 +261,174 @@ g_function_info_invoke (GIFunctionInfo *info, out: return success; } + +static ffi_type * +value_to_ffi_type (const GValue *gvalue, gpointer *value) +{ + ffi_type *rettype = NULL; + GType type = g_type_fundamental (G_VALUE_TYPE (gvalue)); + g_assert (type != G_TYPE_INVALID); + + 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_STRING: + case G_TYPE_OBJECT: + case G_TYPE_BOXED: + 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; +} + +static void +value_from_ffi_type (GValue *gvalue, gpointer *value) +{ + switch (g_type_fundamental (G_VALUE_TYPE (gvalue))) + { + case G_TYPE_INT: + g_value_set_int (gvalue, *(gint*)value); + break; + case G_TYPE_FLOAT: + g_value_set_float (gvalue, *(gfloat*)value); + break; + case G_TYPE_DOUBLE: + g_value_set_double (gvalue, *(gdouble*)value); + break; + case G_TYPE_BOOLEAN: + g_value_set_boolean (gvalue, *(gboolean*)value); + break; + case G_TYPE_STRING: + g_value_set_string (gvalue, *(gchar**)value); + break; + case G_TYPE_CHAR: + g_value_set_char (gvalue, *(gchar*)value); + break; + case G_TYPE_UCHAR: + g_value_set_uchar (gvalue, *(guchar*)value); + break; + case G_TYPE_UINT: + g_value_set_uint (gvalue, *(guint*)value); + break; + case G_TYPE_POINTER: + g_value_set_pointer (gvalue, *(gpointer*)value); + break; + case G_TYPE_LONG: + g_value_set_long (gvalue, *(glong*)value); + break; + case G_TYPE_ULONG: + g_value_set_ulong (gvalue, *(gulong*)value); + break; + case G_TYPE_INT64: + g_value_set_int64 (gvalue, *(gint64*)value); + break; + case G_TYPE_UINT64: + g_value_set_uint64 (gvalue, *(guint64*)value); + break; + case G_TYPE_BOXED: + g_value_set_boxed (gvalue, *(gpointer*)value); + break; + default: + g_warning ("Unsupported fundamental type: %s", + g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue)))); + } +} + +void +gi_cclosure_marshal_generic (GClosure *closure, + GValue *return_gvalue, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + ffi_type *rtype; + void *rvalue; + int n_args; + ffi_type **atypes; + void **args; + int i; + ffi_cif cif; + GCClosure *cc = (GCClosure*) closure; + + if (return_gvalue && G_VALUE_TYPE (return_gvalue)) + { + rtype = value_to_ffi_type (return_gvalue, &rvalue); + } + else + { + rtype = &ffi_type_void; + } + + rvalue = g_alloca (MAX (rtype->size, sizeof (ffi_arg))); + + n_args = n_param_values + 1; + atypes = g_alloca (sizeof (ffi_type *) * n_args); + args = g_alloca (sizeof (gpointer) * n_args); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + atypes[n_args-1] = value_to_ffi_type (param_values + 0, + &args[n_args-1]); + atypes[0] = &ffi_type_pointer; + args[0] = &closure->data; + } + else + { + atypes[0] = value_to_ffi_type (param_values + 0, &args[0]); + atypes[n_args-1] = &ffi_type_pointer; + args[n_args-1] = &closure->data; + } + + for (i = 1; i < n_args - 1; i++) + atypes[i] = value_to_ffi_type (param_values + i, &args[i]); + + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK) + return; + + ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args); + + if (return_gvalue && G_VALUE_TYPE (return_gvalue)) + value_from_ffi_type (return_gvalue, rvalue); +} diff --git a/girepository/girepository.h b/girepository/girepository.h index 38697c69..340c7fa4 100644 --- a/girepository/girepository.h +++ b/girepository/girepository.h @@ -141,6 +141,15 @@ typedef enum GQuark g_irepository_error_quark (void); +/* Global utility functions */ + +void gi_cclosure_marshal_generic (GClosure *closure, + GValue *return_gvalue, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + /* Types of objects registered in the repository */ typedef enum diff --git a/tests/invoke/Makefile.am b/tests/invoke/Makefile.am index 92158eb2..2177bd79 100644 --- a/tests/invoke/Makefile.am +++ b/tests/invoke/Makefile.am @@ -1,11 +1,10 @@ ## Process this file with automake to produce Makefile.in -check_PROGRAMS = invoke +check_PROGRAMS = invoke genericmarshaller testlib_LTLIBRARIES = testfns.la testlibdir = /tmp install-testlibLTLIBRARIES: # prevent it from being installed - testfns_la_SOURCES = \ testfns.c \ testfns-metadata.c @@ -27,7 +26,11 @@ invoke_SOURCES = invoke.c invoke_CFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository invoke_LDADD = $(top_builddir)/girepository/libgirepository.la $(GIREPO_LIBS) -TESTS = invoke invoke-namespace-find.sh +genericmarshaller_SOURCES = genericmarshaller.c +genericmarshaller_CFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository +genericmarshaller_LDADD = $(top_builddir)/girepository/libgirepository.la $(GIREPO_LIBS) + +TESTS = invoke genericmarshaller invoke-namespace-find.sh EXTRA_DIST = invoke-namespace-find.sh testfns-1.0.gir diff --git a/tests/invoke/genericmarshaller.c b/tests/invoke/genericmarshaller.c new file mode 100644 index 00000000..9ee0c204 --- /dev/null +++ b/tests/invoke/genericmarshaller.c @@ -0,0 +1,204 @@ +/* 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> +#include "girepository.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, + gi_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, + gi_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, + gi_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, + gi_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_printerr ("running genericmarshaller tests\n"); + + 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); + + g_printerr ("genericmarshaller succeeded\n"); +} + +int main(void) +{ + test_cclosure_marshal (); + + return 0; +} + |