summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--girepository/ginvoke.c171
-rw-r--r--girepository/girepository.h9
-rw-r--r--tests/invoke/Makefile.am9
-rw-r--r--tests/invoke/genericmarshaller.c204
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;
+}
+