[Xfce4-commits] <glib-objc:no-foundation-dep> add GOCClosure... sorta like NSInvocation. untested
Brian J. Tarricone
noreply at xfce.org
Sun Nov 22 04:02:17 CET 2009
Updating branch refs/heads/no-foundation-dep
to 33329ae709dc907d02c613a4514f1fc16c41b00f (commit)
from 85cca33b1b3827211dd1d4cbd9fb2ef2f863efac (commit)
commit 33329ae709dc907d02c613a4514f1fc16c41b00f
Author: Brian J. Tarricone <brian at tarricone.org>
Date: Fri Jul 10 13:34:46 2009 -0700
add GOCClosure... sorta like NSInvocation. untested
also add a platform-dependent header in $(libdir) to support this
.gitignore | 2 +
Makefile.am | 15 ++
common/goc-private.h | 24 +++
configure.ac.in | 132 +++++++++++--
gobject-objc/GOCClosure.h | 99 +++++++++
gobject-objc/GOCClosure.m | 502 +++++++++++++++++++++++++++++++++++++++++++++
gobject-objc/Makefile.am | 8 +-
7 files changed, 763 insertions(+), 19 deletions(-)
diff --git a/.gitignore b/.gitignore
index 2141f62..c4d3d28 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,8 +23,10 @@ config.sub
configure
configure.ac
depcomp
+glib-objc-config.h
install-sh
libtool
ltmain.sh
missing
+stamp-goc-h
stamp-h1
diff --git a/Makefile.am b/Makefile.am
index 02714f1..a16667b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,3 +3,18 @@ SUBDIRS = \
glib-objc \
gobject-objc \
tests
+
+archdepdir = $(libdir)/glib-objc-$(GLIB_OBJC_API_VERSION)/include
+archdep_HEADERS = \
+ glib-objc-config.h
+
+BUILT_SOURCES = stamp-goc-h
+glib-objc-config.h: stamp-goc-h
+ @if test -f glib-objc-config.h; then :; \
+ else rm -f stamp-goc-h; $(MAKE) stamp-goc-h; fi
+stamp-goc-h: config.status
+ cd $(top_builddir) && $(SHELL) ./config.status glib-objc-config.h
+ echo timestamp > stamp-goc-h
+
+DISTCLEANFILES = \
+ glib-objc-config.h
diff --git a/common/goc-private.h b/common/goc-private.h
index ba15d56..2afc758 100644
--- a/common/goc-private.h
+++ b/common/goc-private.h
@@ -58,4 +58,28 @@
return (val); \
} G_STMT_END
+
+#define _goc_collect_varargs(arrayp, countp, first_param, var_args, do_strdup) G_STMT_START{ \
+ void *__cur; \
+ int __max_params = 6; \
+ \
+ *(countp) = 0; \
+ *(arrayp) = g_malloc(sizeof(void *) * (__max_params + 1)); \
+ __cur = (void *)first_param; \
+ while(__cur) { \
+ if(*(countp) == __max_params) { \
+ __max_params *= 2; \
+ *(arrayp) = g_realloc(*(arrayp), sizeof(void *) * (__max_params + 1)); \
+ } \
+ \
+ if(do_strdup) \
+ (*(arrayp))[(*(countp))++] = (void *)g_strdup(__cur); \
+ else \
+ (*(arrayp))[(*(countp))++] = __cur; \
+ __cur = va_arg(var_args, void *); \
+ } \
+ (*(arrayp))[*(countp)] = NULL; \
+}G_STMT_END
+
+
#endif /* __GOC_PRIVATE_H__ */
diff --git a/configure.ac.in b/configure.ac.in
index bcf053c..72e3819 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -50,23 +50,89 @@ AC_SUBST(GOC_API_VERSION)
dnl required
-PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.12.0], , [AC_MSG_ERROR([
-*** Glib version 2.12.0 or greater is required.
-*** YOu can download it from http://gtk.org/
-])])
-AC_MSG_CHECKING([GLIB_CFLAGS])
-AC_MSG_RESULT([$GLIB_CFLAGS])
-AC_MSG_CHECKING([GLIB_LIBS])
-AC_MSG_RESULT([$GLIB_LIBS])
-
-PKG_CHECK_MODULES([GOBJECT], [gobject-2.0 >= 2.12.0], , [AC_MSG_ERROR([
-*** GObject (a part of the Glib library) version 2.12.0 or greater is required.
-*** You can download it from http://gtk.org/
-])])
-AC_MSG_CHECKING([GOBJECT_CFLAGS])
-AC_MSG_RESULT([$GOBJECT_CFLAGS])
-AC_MSG_CHECKING([GOBJECT_LIBS])
-AC_MSG_RESULT([$GOBJECT_LIBS])
+#
+# BT_CHECK_PACKAGE(VAR, MODULE, MIN_VERSION, [WEBSITE])
+#
+AC_DEFUN([BT_CHECK_PACKAGE],
+[
+ PKG_CHECK_MODULES([$1], [$2 >= $3], ,
+ [
+ echo '***'" $2 version $3 is required."
+ if test "x$4" != "x"; then
+ echo '***'" You can download it from $4"
+ fi
+ exit 1
+ ])
+ AC_MSG_CHECKING([$1_CFLAGS])
+ AC_MSG_RESULT([$$1_CFLAGS])
+ AC_MSG_CHECKING([$1_LIBS])
+ AC_MSG_RESULT([$$1_LIBS])
+])
+
+BT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.12.0], [http://gtk.org/])
+BT_CHECK_PACKAGE([GOBJECT], [gobject-2.0], [2.12.0], [http://gtk.org/])
+BT_CHECK_PACKAGE([LIBFFI], [libffi], [3.0.0], [http://sourceware.org/libffi])
+
+dnl figure out some semi-custom types
+
+# BT_CHECK_OBJC_SIG(VAR, TYPE_MACRO, FRIENDLY_NAME)
+AC_DEFUN([BT_CHECK_OBJC_SIG],
+[
+ AC_LANG_PUSH([Objective C])
+
+ AC_MSG_CHECKING([the type signature of $3])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [
+ #include <stdio.h>
+ #if defined(HAVE_OBJC_OBJC_RUNTIME_H)
+ # include <objc/objc-runtime.h>
+ #elif defined(HAVE_OBJC_OBJC_API_H)
+ # include <objc/objc-api.h>
+ #endif
+ ],
+ [
+ FILE *fp = fopen("bt-conftest.out", "w");
+ if(!fp)
+ return 1;
+ fprintf(fp, "%c\n", $2);
+ fclose(fp);
+ ])
+ ], ,
+ [
+ AC_MSG_RESULT([failed])
+ echo <<__EOERR
+*** Failed to figure out the type signature of $3. Your Objective C runtime
+*** may not be supported.
+__EOERR
+ rm -f bt-conftest.out
+ exit 1
+ ])
+
+ AC_LANG_POP()
+
+ val=`cat bt-conftest.out`
+ rm -f bt-conftest.out
+ if test -z "$val"; then
+ AC_MSG_RESULT([failed])
+ echo <<__EOERR
+*** Type signature of $3 appears to be empty. Your Objective C runtime may
+*** not be supported.
+__EOERR
+ exit 1
+ fi
+
+ AC_MSG_RESULT([$val])
+ $1="$val"
+])
+
+BT_CHECK_OBJC_SIG([GOC_ARGTYPE_BOOL], [_C_BOOL], [BOOL])
+BT_CHECK_OBJC_SIG([GOC_ARGTYPE_FLAGS], [_C_BFLD], [bitfields/flags])
+# this next one shouldn't be hard-coded. instead should make sure there are
+# no conflicts with the system signatures
+AC_MSG_CHECKING([the type signature of enums])
+GOC_ARGTYPE_ENUM='e'
+AC_MSG_RESULT([$GOC_ARGTYPE_ENUM])
dnl check for debugging support
AC_ARG_ENABLE([debug],
@@ -93,6 +159,38 @@ if test "x$enable_debug" != "xno"; then
fi
AC_MSG_RESULT([$enable_debug])
+AC_CONFIG_COMMANDS([glib-objc-config.h],
+[
+ outfile=glib-objc-config.h-tmp
+ cat > $outfile <<__EOF
+/*
+ * glib-objc-config.h
+ *
+ * This is a generated file. Please modifiy 'configure.ac.in'.
+ */
+
+#ifndef __GLIB_OBJC_CONFIG_H__
+#define __GLIB_OBJC_CONFIG_H__
+
+#define __GOC_ARGTYPE_BOOL "$argtype_bool"
+#define __GOC_ARGTYPE_FLAGS "$argtype_flags"
+#define __GOC_ARGTYPE_ENUM "$argtype_enum"
+
+#endif /* __GLIB_OBJC_CONFIG_H__ */
+__EOF
+ if cmp -s $outfile glib-objc-config.h; then
+ AC_MSG_NOTICE([glib-objc-config.h is unchanged])
+ rm -f $outfile
+ else
+ mv $outfile glib-objc-config.h
+ fi
+],
+[
+ argtype_bool=$GOC_ARGTYPE_BOOL
+ argtype_flags=$GOC_ARGTYPE_FLAGS
+ argtype_enum=$GOC_ARGTYPE_ENUM
+])
+
AC_OUTPUT([
Makefile
common/Makefile
diff --git a/gobject-objc/GOCClosure.h b/gobject-objc/GOCClosure.h
new file mode 100644
index 0000000..da4f015
--- /dev/null
+++ b/gobject-objc/GOCClosure.h
@@ -0,0 +1,99 @@
+/*
+ * glib-objc - objective-c bindings for glib/gobject
+ *
+ * Copyright (c) 2009 Brian Tarricone <brian at tarricone.org>
+ *
+ * This program 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; version 2 of the License ONLY.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GOC_CLOSURE_H__
+#define __GOC_CLOSURE_H__
+
+#include <glib-objc-config.h>
+
+#import <glib-objc/GOCObjectBase.h>
+#import <gobject-objc/GOCValue.h>
+
+#define GOC_ARGTYPE_INVALID NULL
+#define GOC_ARGTYPE_NONE @encode(void)
+#define GOC_ARGTYPE_BOOL __GOC_ARGTYPE_BOOL
+#define GOC_ARGTYPE_UCHAR @encode(unsigned char)
+#define GOC_ARGTYPE_CHAR @encode(char)
+#define GOC_ARGTYPE_USHORT @encode(unsigned short)
+#define GOC_ARGTYPE_SHORT @encode(short)
+#define GOC_ARGTYPE_UINT @encode(unsigned int)
+#define GOC_ARGTYPE_INT @encode(int)
+#define GOC_ARGTYPE_ULONG @encode(unsigned long)
+#define GOC_ARGTYPE_LONG @encode(long)
+#define GOC_ARGTYPE_UINT64 @encode(unsigned long long)
+#define GOC_ARGTYPE_INT64 @encode(long long)
+#define GOC_ARGTYPE_FLOAT @encode(float)
+#define GOC_ARGTYPE_DOUBLE @encode(double)
+#define GOC_ARGTYPE_FLAGS __GOC_ARGTYPE_FLAGS
+#define GOC_ARGTYPE_ENUM __GOC_ARGTYPE_ENUM
+#define GOC_ARGTYPE_OBJECT @encode(id)
+#define GOC_ARGTYPE_POINTER @encode(void *)
+#define GOC_ARGTYPE_STRING @encode(char *)
+#define GOC_ARGTYPE_STRV @encode(char **)
+
+typedef struct _GOCClosurePriv GOCClosurePriv;
+
+ at interface GOCClosure : GOCObjectBase
+{
+ @private
+ GOCClosurePriv *priv;
+}
+
+/* designated initializer */
+- (id)initWithSelector:(SEL)aSelector
+ onTarget:(id)target
+ withUserData:(id <GOCObject>)userData
+ withReturnType:(const char *)returnType
+ andArgTypeV:(char **)argTypes;
+
+/* argument varargs lists should be terminated with NULL or nil */
+- (id)initWithSelector:(SEL)aSelector
+ onTarget:(id)target
+ withUserData:(id <GOCObject>)userData
+ withReturnType:(const char *)returnType
+ andArgTypes:(const char *)firstArgType,...;
+- (id)initWithSelector:(SEL)aSelector
+ withUserData:(id <GOCObject>)userData
+ withReturnType:(const char *)returnType
+ andArgTypes:(const char *)firstArgType,...;
+/* return type is assumed to be void */
+- (id)initWithSelector:(SEL)aSelector
+ andArgTypes:(const char *)firstArgType,...;
+
+- (void)setTarget:(id)aTarget;
+- (id)target;
+
+- (void)setSelector:(SEL)aSelector;
+- (SEL)selector;
+
+/* return value is the return value from the closure's callback. it will be nil
+ * if the return type is void. arguments in the varargs array should be terminated
+ * with nil. to pass a nil/NULL value, use [GOCValue valueWithVoid] or similar. */
+- (GOCValue *)invokeWithInvocationHint:(void *)invocationHint
+ andArgs:(GOCValue *)firstArg,...;
+- (GOCValue *)invokeWithArgs:(GOCValue *)firstArg,...;
+
+/* non-varargs versions. array should be terminated with nil */
+- (GOCValue *)invokeWithInvocationHint:(void *)invocationHint
+ andArgV:(GOCValue **)argv;
+- (GOCValue *)invokeWithArgV:(GOCValue **)argv;
+
+ at end
+
+#endif /* __GOC_CLOSURE_H__ */
diff --git a/gobject-objc/GOCClosure.m b/gobject-objc/GOCClosure.m
new file mode 100644
index 0000000..7e4c21c
--- /dev/null
+++ b/gobject-objc/GOCClosure.m
@@ -0,0 +1,502 @@
+/*
+ * glib-objc - objective-c bindings for glib/gobject
+ *
+ * Copyright (c) 2009 Brian Tarricone <brian at tarricone.org>
+ *
+ * This program 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; version 2 of the License ONLY.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+
+#if defined(HAVE_OBJC_OBJC_RUNTIME_H)
+#include <objc/objc-runtime.h>
+#elif defined(HAVE_OBJC_OBJC_API_H)
+#include <objc/objc-api.h>
+#endif
+
+#include <ffi.h>
+#include <glib.h>
+
+#include <goc-private.h>
+#import "GOCClosure.h"
+#import "GOCValue+GOCPrivate.h"
+#import "GOCNumber+GOCPrivate.h"
+
+ at implementation GOCClosure
+
+struct _GOCClosurePriv
+{
+ SEL selector;
+ id target;
+ IMP msgImp;
+ char *returnType;
+ unsigned int argCount;
+ char **argTypes;
+ id <GOCObject> userData;
+};
+
+
+/* designated initializer */
+- (id)initWithSelector:(SEL)aSelector
+ onTarget:(id)target
+ withUserData:(id <GOCObject>)userData
+ withReturnType:(const char *)returnType
+ andArgTypeV:(char **)argTypes
+{
+ self = [super init];
+ if(self) {
+ priv = g_slice_new0(GOCClosurePriv);
+
+ priv->selector = aSelector;
+ priv->target = target; /* FIXME: ref? */
+ if(priv->selector && priv->target)
+ priv->msgImp = [priv->target methodFor:priv->selector];
+ priv->returnType = g_strdup(returnType);
+ priv->argTypes = g_strdupv(argTypes); /* FIXME: avoid copy for internal calls? */
+ priv->argCount = g_strv_length(priv->argTypes);
+ priv->userData = userData; /* FIXME: ref? */
+ }
+ return self;
+}
+
+- (id)_initWithSelector:(SEL)aSelector
+ onTarget:(id)target
+ withUserData:(id <GOCObject>)userData
+ withReturnType:(const char *)returnType
+ andFirstArgType:(const char *)firstArgType
+ andArgTypeValist:(va_list)argTypes
+{
+ char **argtv = NULL;
+ unsigned int argt_count = 0;
+ id ret = nil;
+
+ _goc_collect_varargs(&argtv, &argt_count, firstArgType, argTypes, YES);
+
+ ret = [self initWithSelector:aSelector
+ onTarget:target
+ withUserData:userData
+ withReturnType:returnType
+ andArgTypeV:argtv];
+
+ g_strfreev(argtv);
+
+ return ret;
+}
+
+- (id)initWithSelector:(SEL)aSelector
+ onTarget:(id)target
+ withUserData:(id <GOCObject>)userData
+ withReturnType:(const char *)returnType
+ andArgTypes:(const char *)firstArgType,...
+{
+ va_list var_args;
+ id ret;
+
+ va_start(var_args, firstArgType);
+
+ ret = [self _initWithSelector:aSelector
+ onTarget:target
+ withUserData:userData
+ withReturnType:returnType
+ andFirstArgType:firstArgType
+ andArgTypeValist:var_args];
+
+ va_end(var_args);
+
+ return ret;
+
+}
+
+- (id)initWithSelector:(SEL)aSelector
+ withUserData:(id <GOCObject>)userData
+ withReturnType:(const char *)returnType
+ andArgTypes:(const char *)firstArgType,...
+{
+ va_list var_args;
+ id ret;
+
+ va_start(var_args, firstArgType);
+
+ ret = [self _initWithSelector:aSelector
+ onTarget:nil
+ withUserData:userData
+ withReturnType:returnType
+ andFirstArgType:firstArgType
+ andArgTypeValist:var_args];
+
+ va_end(var_args);
+
+ return ret;
+
+}
+
+- (id)initWithSelector:(SEL)aSelector
+ andArgTypes:(const char *)firstArgType,...
+{
+ va_list var_args;
+ id ret;
+
+ va_start(var_args, firstArgType);
+
+ ret = [self _initWithSelector:aSelector
+ onTarget:nil
+ withUserData:nil
+ withReturnType:NULL
+ andFirstArgType:firstArgType
+ andArgTypeValist:var_args];
+
+ va_end(var_args);
+
+ return ret;
+}
+
+- (void)setTarget:(id)aTarget
+{
+ if(priv->target == aTarget)
+ return;
+
+ priv->target = aTarget;
+
+ if(priv->selector && priv->target)
+ priv->msgImp = [priv->target methodFor:priv->selector];
+ else
+ priv->msgImp = NULL;
+}
+
+- (id)target
+{
+ return priv->target;
+}
+
+- (void)setSelector:(SEL)aSelector
+{
+ if(priv->selector == aSelector)
+ return;
+
+ priv->selector = aSelector;
+
+ if(priv->selector && priv->target)
+ priv->msgImp = [priv->target methodFor:priv->selector];
+ else
+ priv->msgImp = NULL;
+}
+
+- (SEL)selector
+{
+ return priv->selector;
+}
+
+- (GOCValue *)invokeWithInvocationHint:(void *)invocationHint
+ andArgs:(GOCValue *)firstArg,...
+{
+ GOCValue **argv = NULL, *ret = nil;
+ unsigned int arg_count = 0;
+ va_list var_args;
+
+ va_start(var_args, firstArg);
+ _goc_collect_varargs(&argv, &arg_count, firstArg, var_args, NO);
+ va_end(var_args);
+
+ if(arg_count != priv->argCount) {
+ g_critical("Expected %u args, but got %u", priv->argCount, arg_count);
+ return nil;
+ }
+
+ ret = [self invokeWithInvocationHint:invocationHint andArgV:argv];
+
+ g_free(argv);
+
+ return ret;
+}
+
+- (GOCValue *)invokeWithArgs:(GOCValue *)firstArg,...
+{
+ GOCValue **argv = NULL, *ret = nil;
+ unsigned int arg_count = 0;
+ va_list var_args;
+
+ va_start(var_args, firstArg);
+ _goc_collect_varargs(&argv, &arg_count, firstArg, var_args, NO);
+ va_end(var_args);
+
+ if(arg_count != priv->argCount) {
+ g_critical("Expected %u args, but got %u", priv->argCount, arg_count);
+ return nil;
+ }
+
+ ret = [self invokeWithInvocationHint:NULL andArgV:argv];
+
+ g_free(argv);
+
+ return ret;
+}
+
+static ffi_type *
+libffi_type_from_objc_signature(const char *sig)
+{
+ if(!sig)
+ return NULL;
+
+ switch(*sig) {
+ case _C_ID:
+ case _C_PTR:
+ case _C_CLASS:
+ case _C_SEL:
+ case _C_CHARPTR:
+ return &ffi_type_pointer;
+ case _C_CHR:
+ return &ffi_type_schar;
+ case _C_UCHR:
+ return &ffi_type_uchar;
+ case _C_SHT:
+ return &ffi_type_sshort;
+ case _C_USHT:
+ return &ffi_type_ushort;
+ case _C_INT:
+ return &ffi_type_sint;
+ case _C_UINT:
+ return &ffi_type_uint;
+ case _C_LNG:
+ return &ffi_type_slong;
+ case _C_ULNG:
+ return &ffi_type_ulong;
+ case _C_LNG_LNG:
+ return &ffi_type_sint64;
+ case _C_ULNG_LNG:
+ return &ffi_type_uint64;
+ case _C_FLT:
+ return &ffi_type_float;
+ case _C_DBL:
+ return &ffi_type_double;
+ case _C_BFLD:
+ return &ffi_type_uint;
+ case _C_BOOL:
+ if(sizeof(BOOL) == sizeof(unsigned char))
+ return &ffi_type_uchar;
+ else if(sizeof(BOOL) == sizeof(int))
+ return &ffi_type_sint;
+
+ g_critical("Unhandled type for ObjC BOOL type (sizeof(BOOL) is %d)", (int)sizeof(BOOL));
+ return NULL;
+ case _C_VOID:
+ return &ffi_type_void;
+ default:
+ if(*sig == GOC_ARGTYPE_ENUM[0])
+ return &ffi_type_sint;
+ }
+
+ g_critical("Unhandled/unsupported ObjC signature type '%s'", sig);
+ return NULL;
+}
+
+static BOOL
+libffi_value_from_gocvalue(void **ffival,
+ const GOCValue *gocval)
+{
+ if(!ffival || !gocval)
+ return NO;
+
+ *ffival = NULL;
+
+ if([gocval holdsObject])
+ *(id *)ffival = [gocval objectValue];
+ else if([gocval holdsPointer])
+ *ffival = [gocval pointerValue];
+ else if([gocval holdsVoid])
+ return YES; /* we're returning a NULL value in *ffival */
+ else if([gocval isKindOf:[GOCNumber class]]) {
+ GOCNumber *gocn = (GOCNumber *)gocval;
+
+ if([gocn holdsBool])
+ *(BOOL **)ffival = (BOOL *)[gocn storage];
+ else if([gocn holdsUChar])
+ *(unsigned char **)ffival = (unsigned char *)[gocn storage];
+ else if([gocn holdsChar])
+ *(char **)ffival = (char *)[gocn storage];
+ else if([gocn holdsUShort])
+ *(unsigned short **)ffival = (unsigned short *)[gocn storage];
+ else if([gocn holdsShort])
+ *(short **)ffival = (short *)[gocn storage];
+ else if([gocn holdsUInt])
+ *(unsigned int **)ffival = (unsigned int *)[gocn storage];
+ else if([gocn holdsInt])
+ *(int **)ffival = (int *)[gocn storage];
+ else if([gocn holdsULong])
+ *(unsigned long **)ffival = (unsigned long *)[gocn storage];
+ else if([gocn holdsLong])
+ *(long **)ffival = (long *)[gocn storage];
+ else if([gocn holdsUInt64])
+ *(unsigned long long **)ffival = (unsigned long long *)[gocn storage];
+ else if([gocn holdsInt64])
+ *(long long **)ffival = (long long *)[gocn storage];
+ else if([gocn holdsFloat])
+ *(float **)ffival = (float *)[gocn storage];
+ else if([gocn holdsDouble])
+ *(double **)ffival = (double *)[gocn storage];
+ else if([gocn holdsEnum])
+ *(int **)ffival = (int *)[gocn storage];
+ else if([gocn holdsFlags])
+ *(unsigned int **)ffival = (unsigned int *)[gocn storage];
+ }
+
+ if(!*ffival)
+ return NO;
+
+ return YES;
+}
+
+static GOCValue *
+gocvalue_from_libffi_retval(void *retval,
+ const char *type_sig)
+{
+ if(!retval || !type_sig)
+ return nil;
+
+ switch(*type_sig) {
+ case _C_ID:
+ return [GOCValue valueWithObject:*(id *)retval];
+ case _C_PTR:
+ case _C_CLASS:
+ case _C_SEL:
+ case _C_CHARPTR:
+ return [GOCValue valueWithPointer:*(void **)retval];
+ case _C_CHR:
+ return [GOCNumber numberWithChar:*(char *)retval];
+ case _C_UCHR:
+ return [GOCNumber numberWithUChar:*(unsigned char *)retval];
+ case _C_SHT:
+ return [GOCNumber numberWithShort:*(short *)retval];
+ case _C_USHT:
+ return [GOCNumber numberWithUShort:*(unsigned short *)retval];
+ case _C_INT:
+ return [GOCNumber numberWithInt:*(int *)retval];
+ case _C_UINT:
+ return [GOCNumber numberWithUInt:*(unsigned int *)retval];
+ case _C_LNG:
+ return [GOCNumber numberWithLong:*(long *)retval];
+ case _C_ULNG:
+ return [GOCNumber numberWithULong:*(unsigned long *)retval];
+ case _C_LNG_LNG:
+ return [GOCNumber numberWithInt64:*(long long *)retval];
+ case _C_ULNG_LNG:
+ return [GOCNumber numberWithUInt64:*(unsigned long long *)retval];
+ case _C_FLT:
+ return [GOCNumber numberWithFloat:*(float *)retval];
+ case _C_DBL:
+ return [GOCNumber numberWithDouble:*(double *)retval];
+ case _C_BFLD:
+ return [GOCNumber numberWithFlags:*(unsigned int *)retval];
+ case _C_BOOL:
+ return [GOCNumber numberWithBool:*(BOOL *)retval];
+ case _C_VOID:
+ return [GOCValue valueWithVoid];
+ default:
+ if(*type_sig == GOC_ARGTYPE_ENUM[0])
+ return [GOCNumber numberWithEnum:*(int *)retval];
+ }
+
+ g_critical("Unhandled/unsupported ObjC signature type '%s'", type_sig);
+ return nil;
+}
+
+/* non-varargs versions. array should be terminated with nil */
+- (GOCValue *)invokeWithInvocationHint:(void *)invocationHint
+ andArgV:(GOCValue **)argv
+{
+ GOCValue *ret = nil;
+ unsigned int arg_count = 0, i;
+ ffi_status status;
+ ffi_cif fcif;
+ ffi_type *ret_type = NULL;
+ ffi_type **arg_types = NULL;
+ char retval[32] = { 0, }; /* should be more than enough */
+ void **args = NULL;
+
+ if(!priv->msgImp) {
+ g_critical("Unable to invoke closure without a valid IMP pointer "
+ "(either the target or selector are unset, or the selector "
+ "is not a valid message for the target)");
+ return nil;
+ }
+
+ while(argv[arg_count])
+ ++arg_count;
+
+ if(arg_count != priv->argCount) {
+ g_critical("Expected %u args, but got %u", priv->argCount, arg_count);
+ goto out;
+ }
+
+ ret_type = libffi_type_from_objc_signature(priv->returnType);
+ if(!ret_type) {
+ g_critical("Couldn't determine FFI return type for ObjC type '%s'", priv->returnType);
+ goto out;
+ }
+
+ arg_types = g_malloc(sizeof(ffi_type *) * (arg_count + 2));
+ arg_types[0] = &ffi_type_pointer; /* self */
+ arg_types[1] = &ffi_type_pointer; /* _cmd */
+ for(i = 0; i < arg_count; ++i) {
+ arg_types[i+2] = libffi_type_from_objc_signature(priv->argTypes[i]);
+ if(!arg_types[i]) {
+ g_critical("Couldn't determine FFI arg type for ObjC type '%s' at index %u",
+ priv->argTypes[i], i);
+ goto out;
+ }
+ }
+
+ status = ffi_prep_cif(&fcif, FFI_DEFAULT_ABI, arg_count, ret_type, arg_types);
+ if(status != FFI_OK) {
+ g_critical("ffi_prep_cif() failed with exit code %d", (int)status);
+ goto out;
+ }
+
+ args = g_malloc(sizeof(void *) * (arg_count + 2));
+ args[0] = priv->target;
+ args[1] = (void *)priv->selector;
+ for(i = 0; i < arg_count; ++i) {
+ if(!libffi_value_from_gocvalue(&args[i+2], argv[i])) {
+ g_critical("Unable to convert GOCValue to FFI value at index %d", i);
+ goto out;
+ }
+ }
+
+ ffi_call(&fcif, FFI_FN(priv->msgImp), retval, args);
+ ret = gocvalue_from_libffi_retval(retval, priv->returnType);
+
+out:
+ if(arg_types)
+ g_free(arg_types);
+ if(args)
+ g_free(args);
+
+ return ret;
+}
+
+- (GOCValue *)invokeWithArgV:(GOCValue **)argv
+{
+ return [self invokeWithInvocationHint:NULL andArgV:argv];
+}
+
+- (void)free
+{
+ g_slice_free(GOCClosurePriv, priv);
+ [super free];
+}
+
+ at end
diff --git a/gobject-objc/Makefile.am b/gobject-objc/Makefile.am
index e214396..70694a9 100644
--- a/gobject-objc/Makefile.am
+++ b/gobject-objc/Makefile.am
@@ -6,6 +6,7 @@ glibobjcmaininclude_HEADERS = \
gobjectobjcincludedir = $(glibobjcmainincludedir)/gobject-objc
gobjectobjcinclude_HEADERS = \
GOCBoxedValue.h \
+ GOCClosure.h \
GOCObject.h \
GOCNumber.h \
GOCValue.h
@@ -14,6 +15,7 @@ libgobject_objc_2_0_la_SOURCES = \
$(gobjectobjcmaininclude_HEADERS) \
$(gobjectobjcinclude_HEADERS) \
GOCBoxedValue.m \
+ GOCClosure.m \
GOCObject.m \
GOCNumber.m \
GOCValue.m \
@@ -22,7 +24,8 @@ libgobject_objc_2_0_la_SOURCES = \
libgobject_objc_2_0_la_CFLAGS = \
-DGLIB_OBJC_COMPILATION \
- $(GOBJECT_CFLAGS)
+ $(GOBJECT_CFLAGS) \
+ $(LIBFFI_CFLAGS)
libgobject_objc_2_0_la_OBJCFLAGS = $(libgobject_objc_2_0_la_CFLAGS)
@@ -30,7 +33,8 @@ libgobject_objc_2_0_la_LDFLAGS = \
-version-info $(GOC_VERINFO)
libgobject_objc_2_0_la_LIBADD = \
- $(GOBJECT_LIBS)
+ $(GOBJECT_LIBS) \
+ $(LIBFFI_LIBS)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_in_files = gobject-objc-$(GOC_API_VERSION).pc.in
More information about the Xfce4-commits
mailing list