summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2010-06-15 14:37:47 -0400
committerDavid Zeuthen <davidz@redhat.com>2010-06-15 14:37:47 -0400
commit917e0632cb4e8a4508112075b48a608ac36f8c33 (patch)
tree1b1bd0684538364f528339e87bf3c4b3db01cb7b
Initial commit
-rw-r--r--Makefile.am2
-rwxr-xr-xautogen.sh90
-rw-r--r--configure.ac117
-rw-r--r--src/Makefile.am67
-rw-r--r--src/gdbusgi.c1012
-rw-r--r--src/gdbusgi.h41
-rw-r--r--src/myfrobnicator.c274
-rw-r--r--src/myfrobnicator.h112
-rw-r--r--src/test.c347
9 files changed, 2062 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..2cad62a
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,2 @@
+
+SUBDIRS = src
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..29cfc2b
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+set -e
+set -x
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+DIE=0
+
+(test -f $srcdir/configure.ac) || {
+ echo -n "**Error**: Directory $srcdir does not look like the"
+ echo " top-level package directory"
+ exit 1
+}
+
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have autoconf installed."
+ echo "Download the appropriate package for your distribution,"
+ echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+ DIE=1
+}
+
+(grep "^AM_PROG_LIBTOOL" $srcdir/configure.ac >/dev/null) && {
+ (libtool --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have libtool installed."
+ echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/"
+ DIE=1
+ }
+}
+
+(automake --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have automake installed."
+ echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/"
+ DIE=1
+ NO_AUTOMAKE=yes
+}
+
+
+# if no automake, don't bother testing for aclocal
+test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: Missing aclocal. The version of automake"
+ echo "installed doesn't appear recent enough."
+ echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/"
+ DIE=1
+}
+
+if test "$DIE" -eq 1; then
+ exit 1
+fi
+
+if test -z "$*"; then
+ echo "**Warning**: I am going to run configure with no arguments."
+ echo "If you wish to pass any to it, please specify them on the"
+ echo $0 " command line."
+ echo
+fi
+
+case $CC in
+xlc )
+ am_opt=--include-deps;;
+esac
+
+aclocalinclude="$ACLOCAL_FLAGS"
+
+echo "Running libtoolize..."
+libtoolize --force --copy
+echo "Running aclocal $aclocalinclude ..."
+aclocal $aclocalinclude
+echo "Running autoheader..."
+autoheader
+echo "Running automake --foreign -Wno-portability $am_opt ..."
+automake --add-missing --foreign -Wno-portability $am_opt
+echo "Running autoconf ..."
+autoconf
+
+conf_flags="--enable-maintainer-mode --enable-gtk-doc"
+
+if test x$NOCONFIGURE = x; then
+ echo "Running $srcdir/configure $conf_flags $@ ..."
+ $srcdir/configure $conf_flags "$@" \
+ && echo "Now type make to compile." || exit 1
+else
+ echo "Skipping configure process."
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..cddd86a
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,117 @@
+
+AC_INIT([GDBus for GObject Introspection],[0.1],[mailto:zeuthen@gmail.com],[gdbus-gi])
+AM_INIT_AUTOMAKE([1.9 foreign dist-bzip2 no-dist-gzip])
+AC_CONFIG_HEADERS([config.h])
+AM_MAINTAINER_MODE
+
+AC_PROG_CC
+AC_ISC_POSIX
+AC_HEADER_STDC
+AM_PROG_LIBTOOL
+
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+#### gcc warning flags
+
+if test "x$GCC" = "xyes"; then
+ changequote(,)dnl
+ case " $CFLAGS " in
+ *[\ \ ]-Wall[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wall" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-Wchar-subscripts[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wchar-subscripts" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-Wmissing-declarations[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wmissing-declarations" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-Wnested-externs[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wnested-externs" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-Wpointer-arith[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wpointer-arith" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-Wcast-align[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wcast-align" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-Wsign-compare[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wsign-compare" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-Wformat[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wformat" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-Wformat-security[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wformat-security" ;;
+ esac
+
+ if test "x$enable_ansi" = "xyes"; then
+ case " $CFLAGS " in
+ *[\ \ ]-ansi[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -ansi" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-D_POSIX_C_SOURCE*) ;;
+ *) CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=199309L" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-D_BSD_SOURCE[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -D_BSD_SOURCE" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-pedantic[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -pedantic" ;;
+ esac
+ fi
+ changequote([,])dnl
+fi
+
+PKG_CHECK_MODULES(GLIB2, glib-2.0 gio-2.0)
+AC_SUBST(GLIB2_CFLAGS)
+AC_SUBST(GLIB2_LIBS)
+
+PKG_CHECK_MODULES([INTROSPECTION], [gobject-introspection-1.0 >= 0.6.2])
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+])
+
+echo "
+ gdbus-gi $VERSION
+ ===============
+
+ prefix: ${prefix}
+ libdir: ${libdir}
+ libexecdir: ${libexecdir}
+ bindir: ${bindir}
+ sbindir: ${sbindir}
+ datadir: ${datadir}
+ sysconfdir: ${sysconfdir}
+ localstatedir: ${localstatedir}
+ docdir: ${docdir}
+
+ compiler: ${CC}
+ cflags: ${CFLAGS}
+ cppflags: ${CPPFLAGS}
+
+ Maintainer mode: ${USE_MAINTAINER_MODE}
+"
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..0cc9721
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,67 @@
+
+NULL =
+
+noinst_PROGRAMS = test
+
+test_SOURCES = \
+ test.c \
+ gdbusgi.h gdbusgi.c \
+ $(NULL)
+
+test_CFLAGS = \
+ $(GLIB2_CFLAGS) \
+ $(INTROSPECTION_CFLAGS) \
+ $(NULL)
+
+test_LDADD = \
+ $(GLIB2_LIBS) \
+ $(INTROSPECTION_LIBS) \
+ libmy.la \
+ $(NULL)
+
+# ----------------------------------------------------------------------------------------------------
+
+noinst_LTLIBRARIES = libmy.la
+
+libmy_la_SOURCES = \
+ myfrobnicator.h myfrobnicator.c \
+ gdbusgi.h gdbusgi.c \
+ $(NULL)
+
+libmy_la_CFLAGS = \
+ $(GLIB2_CFLAGS) \
+ $(INTROSPECTION_CFLAGS) \
+ $(NULL)
+
+libmy_la_LIBADD = \
+ $(GLIB2_LIBS) \
+ $(INTROSPECTION_LIBS) \
+ $(NULL)
+
+# ----------------------------------------------------------------------------------------------------
+
+My-1.0.gir: libmy.la Makefile.am
+ g-ir-scanner -v -v \
+ --namespace My \
+ --nsversion=1.0 \
+ --include=Gio-2.0 \
+ --library=libmy.la \
+ --libtool ../libtool \
+ --output $@ \
+ --pkg=glib-2.0 \
+ --pkg=gobject-2.0 \
+ --pkg=gio-2.0 \
+ -I$(top_builddir)/src \
+ -I$(top_srcdir)/src \
+ $(top_srcdir)/src/myfrobnicator.h \
+ $(top_srcdir)/src/myfrobnicator.c \
+ $(NULL)
+
+My-1.0.typelib: My-1.0.gir
+ g-ir-compiler $< -o $@
+
+# ----------------------------------------------------------------------------------------------------
+
+clean-local:
+ rm -f *~ My*
+
diff --git a/src/gdbusgi.c b/src/gdbusgi.c
new file mode 100644
index 0000000..1578d6d
--- /dev/null
+++ b/src/gdbusgi.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#include "gdbusgi.h"
+
+#include <girepository.h>
+
+typedef struct
+{
+ GObject *object;
+ GDBusInterfaceInfo *info;
+ gpointer user_data;
+ GDestroyNotify user_data_free_func;
+
+ GHashTable *dbus_method_name_to_method_data;
+} ExportData;
+
+static void
+export_data_free (ExportData *data)
+{
+ g_hash_table_unref (data->dbus_method_name_to_method_data);
+ if (data->object != NULL)
+ g_object_unref (data->object);
+ if (data->info != NULL)
+ g_dbus_interface_info_unref (data->info);
+ if (data->user_data_free_func != NULL)
+ data->user_data_free_func (data->user_data);
+ g_free (data);
+}
+
+typedef struct
+{
+ GIFunctionInfo *method;
+ GDBusMethodInfo *dbus_method;
+ guint num_gi_in_args;
+ guint num_gi_out_args;
+} MethodData;
+
+static void
+method_data_free (MethodData *data)
+{
+ g_base_info_unref (data->method);
+ g_dbus_method_info_unref (data->dbus_method);
+ g_free (data);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+set_in_arg (GVariant *value,
+ GArgument *arg_to_set,
+ GIArgInfo *arg_info)
+{
+ const GVariantType *variant_type;
+
+ variant_type = g_variant_get_type (value);
+
+ if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN))
+ arg_to_set->v_boolean = g_variant_get_boolean (value);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTE))
+ arg_to_set->v_int8 = g_variant_get_byte (value);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT16))
+ arg_to_set->v_int16 = g_variant_get_int16 (value);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT16))
+ arg_to_set->v_uint16 = g_variant_get_uint16 (value);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32))
+ arg_to_set->v_int32 = g_variant_get_int32 (value);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32))
+ arg_to_set->v_uint32 = g_variant_get_uint32 (value);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64))
+ arg_to_set->v_int64 = g_variant_get_int64 (value);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT64))
+ arg_to_set->v_uint64 = g_variant_get_uint64 (value);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_DOUBLE))
+ arg_to_set->v_double = g_variant_get_double (value);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE))
+ {
+ switch (g_arg_info_get_ownership_transfer (arg_info))
+ {
+ case GI_TRANSFER_NOTHING:
+ arg_to_set->v_string = (gchar *) g_variant_get_string (value, NULL);
+ break;
+ case GI_TRANSFER_CONTAINER:
+ g_assert_not_reached ();
+ break;
+ case GI_TRANSFER_EVERYTHING:
+ arg_to_set->v_string = g_variant_dup_string (value, NULL);
+ break;
+ }
+ }
+ else
+ {
+ g_error ("Don't know how to set GVariant with type-string %s on a GArgument",
+ g_variant_get_type_string (value));
+ }
+}
+
+
+static void
+prepare_in_args (GVariant *parameters,
+ GArgument *in_args,
+ guint num_in_args,
+ GIFunctionInfo *method)
+{
+ GVariantIter iter;
+ GICallableInfo *callable;
+ guint count_in_args;
+ guint count_out_args;
+ guint n;
+
+ g_assert_cmpint (g_variant_n_children (parameters), ==, num_in_args);
+
+ callable = (GICallableInfo *) method;
+
+ count_in_args = 0;
+ count_out_args = 0;
+ g_variant_iter_init (&iter, parameters);
+ for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++)
+ {
+ GArgument *arg_to_set;
+ GIArgInfo *arg;
+ GIDirection direction;
+
+ arg = g_callable_info_get_arg (callable, n);
+ direction = g_arg_info_get_direction (arg);
+ arg_to_set = NULL;
+ switch (direction)
+ {
+ case GI_DIRECTION_IN:
+ arg_to_set = &in_args[count_in_args++];
+ break;
+
+ case GI_DIRECTION_OUT:
+ /* do nothing */
+ count_out_args++;
+ break;
+
+ case GI_DIRECTION_INOUT:
+ count_out_args++;
+ arg_to_set = &in_args[count_in_args++];
+ break;
+ }
+
+ if (arg_to_set != NULL)
+ {
+ GVariant *item;
+
+ item = g_variant_iter_next_value (&iter);
+ g_assert (item != NULL);
+ set_in_arg (item, arg_to_set, arg);
+ }
+ }
+ g_assert_cmpint (count_in_args, ==, num_in_args);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+add_out_arg (GVariantBuilder *builder,
+ GITypeInfo *type,
+ GArgument *value,
+ GDBusArgInfo *arg_info)
+{
+ const GVariantType *variant_type;
+ GVariant *variant;
+
+ variant_type = G_VARIANT_TYPE (arg_info->signature);
+
+ if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN))
+ variant = g_variant_new_boolean (value->v_boolean);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTE))
+ variant = g_variant_new_byte (value->v_uint8);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT16))
+ variant = g_variant_new_int16 (value->v_int16);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT16))
+ variant = g_variant_new_uint16 (value->v_uint16);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32))
+ variant = g_variant_new_int32 (value->v_int32);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32))
+ variant = g_variant_new_uint32 (value->v_uint32);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64))
+ variant = g_variant_new_int64 (value->v_int64);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT64))
+ variant = g_variant_new_uint64 (value->v_uint64);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_DOUBLE))
+ variant = g_variant_new_double (value->v_double);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING))
+ variant = g_variant_new_string (value->v_string);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH))
+ variant = g_variant_new_object_path (value->v_string);
+ else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE))
+ variant = g_variant_new_signature (value->v_string);
+ else
+ g_assert_not_reached ();
+
+ g_variant_builder_add_value (builder, variant);
+}
+
+static void
+prepare_out_args (GArgument *return_value,
+ GArgument *args,
+ GArgument *arg_values,
+ guint num_args,
+ GIFunctionInfo *method,
+ GDBusMethodInfo *dbus_method)
+{
+ GICallableInfo *callable;
+ guint n;
+ guint count_out_args;
+
+ callable = (GICallableInfo *) method;
+
+ count_out_args = 0;
+ for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++)
+ {
+ GIArgInfo *arg;
+ GIDirection direction;
+
+ arg = g_callable_info_get_arg (callable, n);
+ direction = g_arg_info_get_direction (arg);
+
+ switch (direction)
+ {
+ case GI_DIRECTION_IN:
+ /* do nothing */
+ break;
+
+ case GI_DIRECTION_OUT:
+ args[count_out_args].v_pointer = &arg_values[count_out_args];
+ count_out_args++;
+ break;
+
+ case GI_DIRECTION_INOUT:
+ /* won't be used but needs to be present */
+ args[count_out_args].v_pointer = NULL;
+ count_out_args++;
+ break;
+ }
+ g_base_info_unref ((GIBaseInfo *) arg);
+ }
+ g_assert_cmpint (num_args, ==, count_out_args);
+}
+
+static GVariant *
+process_out_args (GArgument *return_value,
+ GArgument *in_args,
+ GArgument *args,
+ guint num_args,
+ GIFunctionInfo *method,
+ GDBusMethodInfo *dbus_method)
+{
+ GVariant *ret;
+ GVariantBuilder builder;
+ GICallableInfo *callable;
+ GITypeInfo *return_type;
+ guint dbus_arg_num;
+ guint n;
+ guint count_in_args;
+ guint count_out_args;
+
+ callable = (GICallableInfo *) method;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
+
+ dbus_arg_num = 0;
+ return_type = g_callable_info_get_return_type (callable);
+ if (g_type_info_get_tag (return_type) != GI_TYPE_TAG_VOID)
+ {
+ add_out_arg (&builder,
+ return_type,
+ return_value,
+ dbus_method->out_args[dbus_arg_num++]);
+ }
+ //g_base_info_unref ((GIBaseInfo *) return_type);
+
+ count_in_args = 0;
+ count_out_args = 0;
+ for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++)
+ {
+ GIArgInfo *arg;
+ GIDirection direction;
+ GArgument *arg_with_value;
+
+ arg = g_callable_info_get_arg (callable, n);
+ direction = g_arg_info_get_direction (arg);
+
+ arg_with_value = NULL;
+ switch (direction)
+ {
+ case GI_DIRECTION_IN:
+ /* do nothing */
+ count_in_args++;
+ break;
+
+ case GI_DIRECTION_OUT:
+ arg_with_value = args[count_out_args].v_pointer;
+ count_out_args++;
+ break;
+
+ case GI_DIRECTION_INOUT:
+ /* return value is in the in GArgument, not the out one (that needs to be present) */
+ arg_with_value = &in_args[count_in_args];
+ count_out_args++;
+ count_in_args++;
+ break;
+ }
+
+ if (arg_with_value != NULL)
+ {
+ add_out_arg (&builder,
+ return_type,
+ arg_with_value,
+ dbus_method->out_args[dbus_arg_num++]);
+ }
+
+ g_base_info_unref ((GIBaseInfo *) arg);
+ }
+ g_assert_cmpint (num_args, ==, count_out_args);
+
+ ret = g_variant_builder_end (&builder);
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+free_one_arg (GArgument *arg,
+ GITypeInfo *type,
+ GITransfer transfer)
+{
+ GITypeTag tag;
+
+ tag = g_type_info_get_tag (type);
+ switch (tag)
+ {
+ case GI_TYPE_TAG_UTF8:
+ switch (transfer)
+ {
+ case GI_TRANSFER_NOTHING:
+ /* do nothing */
+ break;
+ case GI_TRANSFER_CONTAINER:
+ g_assert_not_reached ();
+ break;
+ case GI_TRANSFER_EVERYTHING:
+ g_free (arg->v_string);
+ break;
+ }
+ break;
+
+ default:
+ /* Do nothing */
+ break;
+ }
+}
+
+static void
+free_args (GArgument *return_value,
+ GArgument *in_args,
+ guint num_in_args,
+ GArgument *out_args,
+ GArgument *out_arg_values,
+ guint num_out_args,
+ GIFunctionInfo *method)
+{
+ GICallableInfo *callable;
+ guint count_in_args;
+ guint count_out_args;
+ guint n;
+ GITypeInfo *return_type;
+
+ callable = (GICallableInfo *) method;
+
+ return_type = g_callable_info_get_return_type (callable);
+ if (g_type_info_get_tag (return_type) != GI_TYPE_TAG_VOID)
+ {
+ free_one_arg (return_value,
+ return_type,
+ g_callable_info_get_caller_owns (callable));
+ }
+ //g_base_info_unref ((GIBaseInfo *) return_type);
+
+ count_in_args = 0;
+ count_out_args = 0;
+ for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++)
+ {
+ GIArgInfo *arg;
+ GITypeInfo *type;
+ GIDirection direction;
+ GITransfer transfer;
+ GArgument *arg_to_free;
+
+ arg = g_callable_info_get_arg (callable, n);
+ type = g_arg_info_get_type (arg);
+ direction = g_arg_info_get_direction (arg);
+ transfer = g_arg_info_get_ownership_transfer (arg);
+
+ switch (direction)
+ {
+ case GI_DIRECTION_IN:
+ /* do nothing */
+ arg_to_free = &in_args[count_in_args++];
+ break;
+
+ case GI_DIRECTION_OUT:
+ arg_to_free = &out_arg_values[count_out_args++];
+ break;
+
+ case GI_DIRECTION_INOUT:
+ /* should be unused */
+ g_assert (out_args[count_out_args].v_pointer == NULL);
+ count_out_args++;
+ arg_to_free = &in_args[count_in_args++];
+ break;
+ }
+
+ free_one_arg (arg_to_free,
+ type,
+ transfer);
+
+ g_base_info_unref ((GIBaseInfo *) type);
+ g_base_info_unref ((GIBaseInfo *) arg);
+ }
+ g_assert_cmpint (num_in_args, ==, count_in_args);
+ g_assert_cmpint (num_out_args, ==, count_out_args);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GStaticPrivate gobject_invocation = G_STATIC_PRIVATE_INIT;
+static GStaticPrivate gobject_invocation_object = G_STATIC_PRIVATE_INIT;
+static GStaticPrivate gobject_invocation_deferred = G_STATIC_PRIVATE_INIT;
+
+static void
+on_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ ExportData *data = user_data;
+ MethodData *method_data;
+ GError *error;
+ GArgument return_value;
+ GArgument *in_args;
+ GArgument *out_args;
+ GArgument *out_arg_values;
+ guint n;
+ gboolean deferred;
+ gboolean invocation_result;
+
+ in_args = NULL;
+ out_args = NULL;
+
+ /* The GDBus core guarantees that only methods matching the given
+ * introspection data is dispatched.
+ */
+ method_data = g_hash_table_lookup (data->dbus_method_name_to_method_data, method_name);
+ g_assert (method_data != NULL);
+
+ /* First argument is the object (e.g. this/self) and not included in the arg count */
+ in_args = g_new0 (GArgument, method_data->num_gi_in_args + 1);
+ out_args = g_new0 (GArgument, method_data->num_gi_out_args);
+ out_arg_values = g_new0 (GArgument, method_data->num_gi_out_args);
+ n = 0;
+ in_args[n++].v_pointer = data->object;
+
+ prepare_in_args (parameters,
+ in_args + 1,
+ method_data->num_gi_in_args,
+ method_data->method);
+ prepare_out_args (&return_value,
+ out_args,
+ out_arg_values,
+ method_data->num_gi_out_args,
+ method_data->method,
+ method_data->dbus_method);
+
+ g_static_private_set (&gobject_invocation, invocation, NULL);
+ g_static_private_set (&gobject_invocation_object, g_object_ref (data->object), g_object_unref);
+ g_static_private_set (&gobject_invocation_deferred, GINT_TO_POINTER (FALSE), NULL);
+
+ error = NULL;
+ invocation_result = g_function_info_invoke (method_data->method,
+ in_args,
+ method_data->num_gi_in_args + 1,
+ out_args,
+ method_data->num_gi_out_args,
+ &return_value,
+ &error);
+ g_static_private_set (&gobject_invocation, NULL, NULL);
+ g_static_private_set (&gobject_invocation_object, NULL, NULL);
+ if (!invocation_result)
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ deferred = GPOINTER_TO_INT (g_static_private_get (&gobject_invocation_deferred));
+ if (!deferred)
+ {
+ GVariant *return_gvariant;
+ return_gvariant = process_out_args (&return_value,
+ in_args + 1, /* skip this/self */
+ out_args,
+ method_data->num_gi_out_args,
+ method_data->method,
+ method_data->dbus_method);
+ g_dbus_method_invocation_return_value (invocation, return_gvariant);
+ g_variant_unref (return_gvariant);
+ }
+
+ out:
+ if (in_args != NULL)
+ {
+ free_args (&return_value,
+ in_args + 1, /* skip this/self */
+ method_data->num_gi_in_args,
+ out_args,
+ out_arg_values,
+ method_data->num_gi_out_args,
+ method_data->method);
+ g_free (in_args);
+ g_free (out_args);
+ g_free (out_arg_values);
+ }
+}
+
+/**
+ * g_dbus_method_invocation_get_for_gobject:
+ * @object: A #GObject registered with g_dbus_connection_register_gobject().
+ * @takeover_invocation: Whether the invocation should be taken over.
+ *
+ * Gets the #GDBusMethodInvocation representing the remote call being
+ * dispatched on the thread, if any. This can be used to get
+ * information about the remote end via
+ * e.g. g_dbus_method_invocation_get_sender().
+ *
+ * It is safe to call this multiple times.
+ *
+ * Returns: A #GDBusMethodInvocation object for the method call
+ * currently being dispatced or %NULL if the invocation of the
+ * method isn't for handling a remote D-Bus call. Do not free
+ * the reference.
+ */
+GDBusMethodInvocation *
+g_dbus_method_invocation_get_for_gobject (GObject *object)
+{
+ GDBusMethodInvocation *ret;
+ GObject *object_for_invocation;
+
+ ret = G_DBUS_METHOD_INVOCATION (g_static_private_get (&gobject_invocation));
+ if (ret == NULL)
+ goto out;
+
+ object_for_invocation = G_OBJECT (g_static_private_get (&gobject_invocation_object));
+ g_warn_if_fail (object == object_for_invocation);
+
+ out:
+ return ret;
+}
+
+/**
+ * g_dbus_method_invocation_takeover_for_gobject:
+ * @object: A #GObject registered with g_dbus_connection_register_gobject().
+ *
+ * Gets the #GDBusMethodInvocation representing the remote D-Bus call
+ * currently being dispatched on the running thread, if any. By doing
+ * this, the caller assumes the responsibility of finishing the remote
+ * D-Bus call. This means that all handling of return values and
+ * errors from the calling method is ignored and handling of the D-Bus
+ * call must be finished using
+ * e.g. g_dbus_method_invocation_return_value() or
+ * g_dbus_method_invocation_return_error() or g_object_unref().
+ *
+ * It is a programming error to call this more than once.
+ *
+ * Returns: A #GDBusMethodInvocation object for the method call
+ * currently being dispatced or %NULL if the invocation of the method
+ * isn't for handling a remote D-Bus call. Caller owns the returned
+ * reference.
+ */
+GDBusMethodInvocation *
+g_dbus_method_invocation_takeover_for_gobject (GObject *object)
+{
+ GDBusMethodInvocation *ret;
+ gboolean already_deferred;
+
+ ret = g_dbus_method_invocation_get_for_gobject (object);
+ if (ret == NULL)
+ goto out;
+
+ already_deferred = GPOINTER_TO_INT (g_static_private_get (&gobject_invocation_deferred));
+ g_warn_if_fail (!already_deferred);
+ g_static_private_set (&gobject_invocation_deferred, GINT_TO_POINTER (TRUE), NULL);
+
+ out:
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GVariant *
+on_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+on_set_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static const GDBusInterfaceVTable export_vtable =
+{
+ on_method_call,
+ on_get_property,
+ on_set_property
+};
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GDBusArgInfo *
+get_arg_info (GICallableInfo *callable,
+ GIArgInfo *arg,
+ GError **error)
+{
+ GITypeTag tag;
+ GITypeInfo *type;
+ GDBusArgInfo *ret;
+ GVariantType *variant_type;
+ const gchar *type_from_annotation;
+ const gchar *name;
+
+ ret = NULL;
+
+ type_from_annotation = NULL;
+ if (arg != NULL)
+ {
+ type = g_arg_info_get_type (arg);
+ name = g_base_info_get_name ((GIBaseInfo *) arg);
+ type_from_annotation = g_base_info_get_attribute ((GIBaseInfo *) arg, "gdbus.signature");
+ }
+ else
+ {
+ type = g_callable_info_get_return_type (callable);
+ name = "return_value";
+ type_from_annotation = g_callable_info_get_return_attribute (callable, "gdbus.signature");
+ }
+
+ if (type_from_annotation != NULL)
+ {
+ variant_type = g_variant_type_new (type_from_annotation);
+ /* TODO: check that @type is actually compatible with @type_from_annotation */
+ }
+ else
+ {
+ tag = g_type_info_get_tag (type);
+ switch (tag)
+ {
+ case GI_TYPE_TAG_BOOLEAN:
+ variant_type = g_variant_type_new ("b");
+ break;
+ case GI_TYPE_TAG_INT8:
+ variant_type = g_variant_type_new ("y");
+ break;
+ case GI_TYPE_TAG_UINT8:
+ variant_type = g_variant_type_new ("y");
+ break;
+ case GI_TYPE_TAG_INT16:
+ variant_type = g_variant_type_new ("n");
+ break;
+ case GI_TYPE_TAG_UINT16:
+ variant_type = g_variant_type_new ("q");
+ break;
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_INT32:
+ variant_type = g_variant_type_new ("i");
+ break;
+ case GI_TYPE_TAG_UINT:
+ case GI_TYPE_TAG_UINT32:
+ variant_type = g_variant_type_new ("u");
+ break;
+ case GI_TYPE_TAG_INT64:
+ variant_type = g_variant_type_new ("x");
+ break;
+ case GI_TYPE_TAG_UINT64:
+ variant_type = g_variant_type_new ("t");
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ variant_type = g_variant_type_new ("d");
+ break;
+ case GI_TYPE_TAG_UTF8:
+ variant_type = g_variant_type_new ("s");
+ break;
+ case GI_TYPE_TAG_FILENAME:
+ variant_type = g_variant_type_new ("ay");
+ break;
+ default:
+ variant_type = NULL;
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Type tag `%s' not supported",
+ g_type_tag_to_string (tag));
+ goto out;
+ }
+ }
+
+ ret = g_new0 (GDBusArgInfo, 1);
+ ret->ref_count = 1;
+ ret->name = g_strdup (name);
+ ret->signature = g_variant_type_dup_string (variant_type);
+
+ out:
+ g_base_info_unref ((GIBaseInfo *) type);
+ return ret;
+}
+
+static GDBusMethodInfo *
+get_method_info (GIFunctionInfo *method,
+ const gchar *dbus_name,
+ gint *num_gi_in_args,
+ gint *num_gi_out_args,
+ GError **error)
+{
+ GDBusMethodInfo *ret;
+ GICallableInfo *callable;
+ GITypeInfo *return_type;
+ GPtrArray *in_args;
+ GPtrArray *out_args;
+ guint n;
+
+ ret = NULL;
+ in_args = g_ptr_array_new ();
+ out_args = g_ptr_array_new ();
+
+ *num_gi_in_args = 0;
+ *num_gi_out_args = 0;
+
+ callable = (GICallableInfo *) method;
+
+ /* Handle return value, if any */
+ return_type = g_callable_info_get_return_type (callable);
+ if (g_type_info_get_tag (return_type) != GI_TYPE_TAG_VOID)
+ {
+ GDBusArgInfo *arg_info;
+ arg_info = get_arg_info (callable, NULL, error);
+ if (arg_info == NULL)
+ {
+ g_prefix_error (error,
+ "Error processing return value of symbol `%s': ",
+ g_function_info_get_symbol (method));
+ g_base_info_unref ((GIBaseInfo *) return_type);
+ goto out;
+ }
+ g_ptr_array_add (out_args, arg_info);
+ }
+ //g_base_info_unref ((GIBaseInfo *) return_type);
+
+ /* Go through all parameters */
+ for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++)
+ {
+ GIArgInfo *arg;
+ GIDirection direction;
+ GDBusArgInfo *arg_info;
+
+ arg = g_callable_info_get_arg (callable, n);
+
+ arg_info = get_arg_info (callable, arg, error);
+ if (arg_info == NULL)
+ {
+ g_prefix_error (error,
+ "Error processing argument `%s' of symbol `%s': ",
+ g_base_info_get_name ((GIBaseInfo *) arg),
+ g_function_info_get_symbol (method));
+ g_base_info_unref ((GIBaseInfo *) arg);
+ goto out;
+ }
+
+ direction = g_arg_info_get_direction (arg);
+ switch (direction)
+ {
+ case GI_DIRECTION_IN:
+ g_ptr_array_add (in_args, arg_info);
+ *num_gi_in_args += 1;
+ break;
+ case GI_DIRECTION_OUT:
+ g_ptr_array_add (out_args, arg_info);
+ *num_gi_out_args += 1;
+ break;
+ case GI_DIRECTION_INOUT:
+ {
+ gchar *s;
+ s = g_strdup_printf ("in_%s", arg_info->name);
+ g_free (arg_info->name);
+ arg_info->name = s;
+ g_ptr_array_add (in_args, arg_info);
+ *num_gi_in_args += 1;
+
+ arg_info = get_arg_info (callable, arg, NULL);
+ g_assert (arg_info != NULL);
+ s = g_strdup_printf ("out_%s", arg_info->name);
+ g_free (arg_info->name);
+ arg_info->name = s;
+ g_ptr_array_add (out_args, arg_info);
+ *num_gi_out_args += 1;
+ break;
+ }
+ }
+ g_base_info_unref ((GIBaseInfo *) arg);
+ }
+
+ g_ptr_array_add (in_args, NULL);
+ g_ptr_array_add (out_args, NULL);
+
+ ret = g_new0 (GDBusMethodInfo, 1);
+ ret->ref_count = 1;
+ ret->name = g_strdup (dbus_name);
+ g_ptr_array_ref (in_args);
+ g_ptr_array_ref (out_args);
+ ret->in_args = (GDBusArgInfo **) g_ptr_array_free (in_args, FALSE);
+ ret->out_args = (GDBusArgInfo **) g_ptr_array_free (out_args, FALSE);
+
+ out:
+ g_ptr_array_foreach (in_args, (GFunc) g_dbus_arg_info_unref, NULL);
+ g_ptr_array_foreach (out_args, (GFunc) g_dbus_arg_info_unref, NULL);
+ g_ptr_array_unref (in_args);
+ g_ptr_array_unref (out_args);
+ return ret;
+}
+
+static GDBusInterfaceInfo *
+compute_introspection_data (GObject *object,
+ ExportData *data,
+ GError **error)
+{
+ GPtrArray *method_infos;
+ GDBusInterfaceInfo *ret;
+ GIRepository *repo;
+ GIBaseInfo *info;
+ guint n;
+
+ ret = NULL;
+ info = NULL;
+
+ repo = g_irepository_get_default ();
+ info = g_irepository_find_by_gtype (repo, G_OBJECT_TYPE (object));
+ if (info == NULL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Error looking up GIBaseInfo for object of type %s",
+ g_type_name (G_OBJECT_TYPE (object)));
+ goto out;
+ }
+
+ ret = g_new0 (GDBusInterfaceInfo, 1);
+ ret->ref_count = 1;
+ ret->name = g_strdup (g_base_info_get_attribute (info, "gdbus.interface"));
+ if (ret->name == NULL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "No gdbus.interface attribute on type %s",
+ g_type_name (G_OBJECT_TYPE (object)));
+ g_dbus_interface_info_unref (ret);
+ ret = NULL;
+ goto out;
+ }
+
+ g_assert (GI_IS_OBJECT_INFO (info));
+
+ method_infos = g_ptr_array_new ();
+ for (n = 0; n < (guint) g_object_info_get_n_methods ((GIObjectInfo *) info); n++)
+ {
+ GIFunctionInfo *method;
+ const gchar *dbus_name;
+
+ method = g_object_info_get_method ((GIObjectInfo *) info, n);
+ dbus_name = g_base_info_get_attribute ((GIBaseInfo *) method, "gdbus.method");
+ if (dbus_name != NULL)
+ {
+ GDBusMethodInfo *method_info;
+ MethodData *method_data;
+ gint num_gi_in_args;
+ gint num_gi_out_args;
+
+ method_info = get_method_info (method,
+ dbus_name,
+ &num_gi_in_args,
+ &num_gi_out_args,
+ error);
+ if (method_info == NULL)
+ {
+ g_ptr_array_foreach (method_infos, (GFunc) g_dbus_method_info_unref, NULL);
+ g_ptr_array_unref (method_infos);
+ g_dbus_interface_info_unref (ret);
+ ret = NULL;
+ goto out;
+ }
+ g_ptr_array_add (method_infos, method_info);
+
+ method_data = g_new0 (MethodData, 1);
+ method_data->method = g_base_info_ref ((GIBaseInfo *) method);
+ method_data->dbus_method = g_dbus_method_info_ref (method_info);
+ method_data->num_gi_in_args = num_gi_in_args;
+ method_data->num_gi_out_args = num_gi_out_args;
+
+ g_hash_table_insert (data->dbus_method_name_to_method_data,
+ g_strdup (dbus_name),
+ method_data);
+ }
+ }
+ g_ptr_array_add (method_infos, NULL);
+ ret->methods = (GDBusMethodInfo **) g_ptr_array_free (method_infos, FALSE);
+
+ out:
+ if (info != NULL)
+ g_base_info_unref (info);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+guint
+g_dbus_connection_register_gobject (GDBusConnection *connection,
+ GObject *object,
+ const gchar *object_path,
+ gpointer user_data,
+ GDestroyNotify user_data_free_func,
+ GError **error)
+{
+ ExportData *data;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
+ g_return_val_if_fail (G_IS_OBJECT (object), 0);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
+ g_return_val_if_fail (error == NULL || *error == NULL, 0);
+
+ data = g_new0 (ExportData, 1);
+ data->object = g_object_ref (object);
+ data->user_data = user_data;
+ data->user_data_free_func = user_data_free_func;
+
+ data->dbus_method_name_to_method_data = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) method_data_free);
+
+ data->info = compute_introspection_data (object,
+ data,
+ error);
+ if (data->info == NULL)
+ goto fail;
+
+ return g_dbus_connection_register_object (connection,
+ object_path,
+ data->info,
+ &export_vtable,
+ data,
+ (GDestroyNotify) export_data_free,
+ error);
+ fail:
+ export_data_free (data);
+ return 0;
+}
diff --git a/src/gdbusgi.h b/src/gdbusgi.h
new file mode 100644
index 0000000..86444ad
--- /dev/null
+++ b/src/gdbusgi.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#ifndef __G_DBUS_GI_H__
+#define __G_DBUS_GI_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+guint g_dbus_connection_register_gobject (GDBusConnection *connection,
+ GObject *object,
+ const gchar *object_path,
+ gpointer user_data,
+ GDestroyNotify user_data_free_func,
+ GError **error);
+
+GDBusMethodInvocation *g_dbus_method_invocation_get_for_gobject (GObject *object);
+GDBusMethodInvocation *g_dbus_method_invocation_takeover_for_gobject (GObject *object);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_GI_H__ */
diff --git a/src/myfrobnicator.c b/src/myfrobnicator.c
new file mode 100644
index 0000000..fc78fde
--- /dev/null
+++ b/src/myfrobnicator.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#include "config.h"
+
+#include "gdbusgi.h"
+
+#include "myfrobnicator.h"
+
+struct _MyFrobnicatorPrivate
+{
+ guint foo;
+};
+
+G_DEFINE_TYPE (MyFrobnicator, my_frobnicator, G_TYPE_OBJECT);
+
+static void
+my_frobnicator_init (MyFrobnicator *frobnicator)
+{
+}
+
+static void
+my_frobnicator_class_init (MyFrobnicatorClass *klass)
+{
+}
+
+MyFrobnicator *
+my_frobnicator_new (void)
+{
+ return MY_FROBNICATOR (g_object_new (MY_TYPE_FROBNICATOR, NULL));
+}
+
+/**
+ * my_frobnicator_hello_world:
+ * @frobnicator: A #MyFrobnicator.
+ * @greeting: A greeting!
+ *
+ * Computes a response to @greeting.
+ *
+ * Returns: The response. Free with g_free().
+ *
+ * Attributes: (gdbus.method HelloWorld) (foo.bar baz)
+ */
+gchar *
+my_frobnicator_hello_world (MyFrobnicator *frobnicator,
+ const gchar *greeting)
+{
+ gchar *response;
+
+ g_return_val_if_fail (MY_IS_FROBNICATOR (frobnicator), NULL);
+ g_return_val_if_fail (greeting != NULL, NULL);
+
+ response = NULL;
+
+ if (g_strcmp0 (greeting, "fail") == 0)
+ {
+ GDBusMethodInvocation *invocation;
+ invocation = g_dbus_method_invocation_takeover_for_gobject (G_OBJECT (frobnicator));
+ g_dbus_method_invocation_return_error (invocation,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "fail boat!");
+ }
+ else
+ {
+ response = g_strdup_printf ("Hey %s - you greeted me `%s'",
+ g_dbus_method_invocation_get_sender (g_dbus_method_invocation_get_for_gobject (G_OBJECT (frobnicator))),
+ greeting);
+ }
+ return response;
+}
+
+/**
+ * my_frobnicator_hello_world_with_gerror:
+ *
+ * Like my_frobnicator_hello_world() but takes a #GError.
+ *
+ * Attributes: (gdbus.method HelloWorldWithGError)
+ */
+gchar *
+my_frobnicator_hello_world_with_gerror (MyFrobnicator *frobnicator,
+ const gchar *greeting,
+ GError **error)
+{
+ gchar *response;
+
+ g_return_val_if_fail (MY_IS_FROBNICATOR (frobnicator), NULL);
+ g_return_val_if_fail (greeting != NULL, NULL);
+
+ response = NULL;
+
+ if (g_strcmp0 (greeting, "fail") == 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FILE_NOT_FOUND,
+ "fail boat with GError!");
+ }
+ else
+ {
+ response = g_strdup_printf ("Hey ya'll with GError - you greeted me `%s'",
+ greeting);
+ }
+
+ return response;
+}
+
+/**
+ * my_frobnicator_simple_types:
+ * @frobnicator: A #MyFrobnicator.
+ * @v_boolean: Value.
+ * @v_int16: Value.
+ * @v_uint16: Value.
+ * @v_int32: Value.
+ * @v_uint32: Value.
+ * @v_int64: Value.
+ * @v_uint64: Value.
+ * @v_int: Value.
+ * @v_uint: Value.
+ * @v_double: Value.
+ * @v_string: Value.
+ * @v_object_path: (gdbus.signature o) (foo.bar baz): Value.
+ * @v_signature: (gdbus.signature g): Value.
+ * @out_boolean: (out): Return location for value.
+ * @out_int16: (out): Return location for value.
+ * @out_uint16: (out): Return location for value.
+ * @out_int32: (out): Return location for value.
+ * @out_uint32: (out): Return location for value.
+ * @out_int64: (out): Return location for value.
+ * @out_uint64: (out): Return location for value.
+ * @out_int: (out): Return location for value.
+ * @out_uint: (out): Return location for value.
+ * @out_double: (out): Return location for value.
+ * @out_string: (out): Return location for value.
+ * @out_object_path: (out) (gdbus.signature o): Return location for value.
+ * @out_signature: (out) (gdbus.signature g): Return location for value.
+ *
+ * Method demonstrating simple types.
+ *
+ * Attributes: (gdbus.method SimpleTypes)
+ */
+void
+my_frobnicator_simple_types (MyFrobnicator *frobnicator,
+ gboolean v_boolean,
+ gint16 v_int16,
+ guint16 v_uint16,
+ gint32 v_int32,
+ guint32 v_uint32,
+ gint64 v_int64,
+ guint64 v_uint64,
+ gint v_int,
+ guint v_uint,
+ gdouble v_double,
+ const gchar *v_string,
+ const gchar *v_object_path,
+ const gchar *v_signature,
+ gboolean *out_boolean,
+ gint16 *out_int16,
+ guint16 *out_uint16,
+ gint32 *out_int32,
+ guint32 *out_uint32,
+ gint64 *out_int64,
+ guint64 *out_uint64,
+ gint *out_int,
+ guint *out_uint,
+ gdouble *out_double,
+ gchar **out_string,
+ gchar **out_object_path,
+ gchar **out_signature)
+{
+ g_return_if_fail (MY_IS_FROBNICATOR (frobnicator));
+ *out_boolean = !v_boolean;
+ *out_int16 = v_int16 + 100;
+ *out_uint16 = v_uint16 + 101;
+ *out_int32 = v_int32 + 102;
+ *out_uint32 = v_uint32 + 103;
+ *out_int64 = v_int64 + 104;
+ *out_uint64 = v_uint64 + 105;
+ *out_int = v_int + 106;
+ *out_uint = v_uint + 107;
+ *out_double = v_double + 108;
+ *out_string = g_strdup_printf ("You passed `%s'", v_string);
+ *out_object_path = g_strdup_printf ("/you/passed%s", v_object_path);
+ *out_signature = g_strdup_printf ("assgit%s", v_signature);
+}
+
+/**
+ * my_frobnicator_strip:
+ * @frobnicator: A #MyFrobnicator.
+ * @str: (inout): A string that will be stripped using g_strstrip().
+ *
+ * An example of a method with an inout parameter.
+ *
+ * Attributes: (gdbus.method Strip)
+ */
+void
+my_frobnicator_strip (MyFrobnicator *frobnicator,
+ gchar *str)
+{
+ g_return_if_fail (MY_IS_FROBNICATOR (frobnicator));
+ g_return_if_fail (str != NULL);
+ g_strstrip (str);
+}
+
+/**
+ * my_frobnicator_return_const_str:
+ * @frobnicator: A #MyFrobnicator.
+ * @num: A number.
+ *
+ * An method that returns a const object.
+ *
+ * Returns: A constant string that should not be freed.
+ *
+ * Attributes: (gdbus.method ReturnConstStr)
+ */
+const gchar *
+my_frobnicator_return_const_str (MyFrobnicator *frobnicator,
+ guint num)
+{
+ const gchar *ret;
+ switch (num)
+ {
+ case 0:
+ ret = "zero";
+ break;
+ case 1:
+ ret = "one";
+ break;
+ case 2:
+ ret = "two";
+ break;
+ default:
+ ret = "bigger than two!";
+ break;
+ }
+ return ret;
+}
+
+/**
+ * my_frobnicator_poke_path:
+ * @frobnicator: A #MyFrobnicator
+ * @object_path: (gdbus.signature o) (foo.bar bat): An object path.
+ *
+ * Manipulate an object path.
+ *
+ * Returns: (gdbus.signature o): A new object path. Free with g_free().
+ *
+ * Attributes: (gdbus.method PokePath)
+ */
+gchar *
+my_frobnicator_poke_path (MyFrobnicator *frobnicator,
+ const gchar *object_path)
+{
+ return g_strdup_printf ("/another/object/path/here%s", object_path);
+}
+
diff --git a/src/myfrobnicator.h b/src/myfrobnicator.h
new file mode 100644
index 0000000..92686b8
--- /dev/null
+++ b/src/myfrobnicator.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#ifndef __MY_FROBNICATOR_H__
+#define __MY_FROBNICATOR_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define MY_TYPE_FROBNICATOR (my_frobnicator_get_type ())
+#define MY_FROBNICATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MY_TYPE_FROBNICATOR, MyFrobnicator))
+#define MY_FROBNICATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MY_TYPE_FROBNICATOR, MyFrobnicatorClass))
+#define MY_FROBNICATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MY_TYPE_FROBNICATOR, MyFrobnicatorClass))
+#define MY_IS_FROBNICATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MY_TYPE_FROBNICATOR))
+#define MY_IS_FROBNICATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MY_TYPE_FROBNICATOR))
+
+typedef struct _MyFrobnicator MyFrobnicator;
+typedef struct _MyFrobnicatorClass MyFrobnicatorClass;
+typedef struct _MyFrobnicatorPrivate MyFrobnicatorPrivate;
+
+/**
+ * MyFrobnicator:
+ *
+ * The #MyFrobnicator structure contains only private data and
+ * should only be accessed using the provided API.
+ *
+ * Attributes: (gdbus.interface org.MyProject.Frobnicator)
+ */
+struct _MyFrobnicator
+{
+ /*< private >*/
+ GObject parent_instance;
+ MyFrobnicatorPrivate *priv;
+};
+
+/**
+ * MyFrobnicatorClass:
+ * @closed: Signal class handler for the #MyFrobnicator::closed signal.
+ *
+ * Class structure for #MyFrobnicator.
+ */
+struct _MyFrobnicatorClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+GType my_frobnicator_get_type (void) G_GNUC_CONST;
+MyFrobnicator *my_frobnicator_new (void);
+gchar *my_frobnicator_hello_world (MyFrobnicator *frobnicator,
+ const gchar *greeting);
+gchar *my_frobnicator_hello_world_with_gerror (MyFrobnicator *frobnicator,
+ const gchar *greeting,
+ GError **error);
+void my_frobnicator_simple_types (MyFrobnicator *frobnicator,
+ gboolean v_boolean,
+ gint16 v_int16,
+ guint16 v_uint16,
+ gint32 v_int32,
+ guint32 v_uint32,
+ gint64 v_int64,
+ guint64 v_uint64,
+ gint v_int,
+ guint v_uint,
+ gdouble v_double,
+ const gchar *v_string,
+ const gchar *v_object_path,
+ const gchar *v_signature,
+ gboolean *out_boolean,
+ gint16 *out_int16,
+ guint16 *out_uint16,
+ gint32 *out_int32,
+ guint32 *out_uint32,
+ gint64 *out_int64,
+ guint64 *out_uint64,
+ gint *out_int,
+ guint *out_uint,
+ gdouble *out_double,
+ gchar **out_string,
+ gchar **out_object_path,
+ gchar **out_signature);
+void my_frobnicator_strip (MyFrobnicator *frobnicator,
+ gchar *str);
+const gchar *my_frobnicator_return_const_str (MyFrobnicator *frobnicator,
+ guint num);
+
+gchar *my_frobnicator_poke_path (MyFrobnicator *frobnicator,
+ const gchar *object_path);
+
+
+G_END_DECLS
+
+#endif /* __MY_FROBNICATOR_H__ */
diff --git a/src/test.c b/src/test.c
new file mode 100644
index 0000000..1bdec4b
--- /dev/null
+++ b/src/test.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+#include "gdbusgi.h"
+
+#include <girepository.h>
+
+#include "myfrobnicator.h"
+
+static GMainLoop *loop;
+static MyFrobnicator *obj;
+
+static gboolean just_serve = FALSE;
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GError *error;
+
+ error = NULL;
+ g_dbus_connection_register_gobject (connection,
+ G_OBJECT (obj),
+ "/org/My/Frobnicator",
+ NULL, /* user_data */
+ NULL, /* GDestroynotify */
+ &error);
+ g_assert_no_error (error);
+}
+
+static void
+run_test (GDBusConnection *connection)
+{
+ GError *error;
+ GVariant *ret;
+ gchar *s;
+ gchar *s2;
+ guint n;
+
+ error = NULL;
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "HelloWorld",
+ g_variant_new ("(s)", "hey"),
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_no_error (error);
+ g_variant_get (ret, "(&s)", &s);
+ s2 = g_strdup_printf ("Hey %s - you greeted me `hey'",
+ g_dbus_connection_get_unique_name (connection));
+ g_assert_cmpstr (s, ==, s2);
+ g_free (s2);
+ g_variant_unref (ret);
+
+ error = NULL;
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "HelloWorld",
+ g_variant_new ("(s)", "fail"),
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+ g_assert_cmpstr (error->message, ==, "GDBus.Error:org.gtk.GDBus.UnmappedGError.Quark._g_2dio_2derror_2dquark.Code0: fail boat!");
+ g_error_free (error);
+ g_assert (ret == NULL);
+
+ error = NULL;
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "HelloWorldWithGError",
+ g_variant_new ("(s)", "hejsa"),
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_no_error (error);
+ g_variant_get (ret, "(&s)", &s);
+ g_assert_cmpstr (s, ==, "Hey ya'll with GError - you greeted me `hejsa'");
+ g_variant_unref (ret);
+
+ error = NULL;
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "HelloWorldWithGError",
+ g_variant_new ("(s)", "fail"),
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FILE_NOT_FOUND);
+ g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.FileNotFound: fail boat with GError!");
+ g_error_free (error);
+ g_assert (ret == NULL);
+
+ for (n = 0; n < 4; n++)
+ {
+ error = NULL;
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "ReturnConstStr",
+ g_variant_new ("(u)", n),
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_no_error (error);
+ g_variant_get (ret, "(&s)", &s);
+ switch (n)
+ {
+ case 0:
+ g_assert_cmpstr (s, ==, "zero");
+ break;
+ case 1:
+ g_assert_cmpstr (s, ==, "one");
+ break;
+ case 2:
+ g_assert_cmpstr (s, ==, "two");
+ break;
+ case 3:
+ g_assert_cmpstr (s, ==, "bigger than two!");
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ g_variant_unref (ret);
+ }
+
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "Strip",
+ g_variant_new ("(s)", " foobar "),
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_no_error (error);
+ g_variant_get (ret, "(&s)", &s);
+ g_assert_cmpstr (s, ==, "foobar");
+ g_variant_unref (ret);
+
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "PokePath",
+ g_variant_new ("(o)", "/hells/yeahs"),
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_no_error (error);
+ g_variant_get (ret, "(&o)", &s);
+ g_assert_cmpstr (s, ==, "/another/object/path/here/hells/yeahs");
+ g_variant_unref (ret);
+
+
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "SimpleTypes",
+ g_variant_new ("(bnqiuxtiudsog)",
+ TRUE, 10, 11, 12, 13, G_GINT64_CONSTANT (14), G_GUINT64_CONSTANT (15), 16, 17, 18.5,
+ "a string", "/the/path", "assgit"),
+ G_VARIANT_TYPE ("(bnqiuxtiudsog)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_no_error (error);
+ {
+ gboolean v_boolean;
+ gint16 v_int16;
+ guint16 v_uint16;
+ gint32 v_int32;
+ guint32 v_uint32;
+ gint64 v_int64;
+ guint64 v_uint64;
+ gint v_int;
+ guint v_uint;
+ gdouble v_double;
+ const gchar *v_string;
+ const gchar *v_object_path;
+ const gchar *v_signature;
+ g_variant_get (ret,
+ "(bnqiuxtiud&s&o&g)",
+ &v_boolean, &v_int16, &v_uint16, &v_int32, &v_uint32,
+ &v_int64, &v_uint64, &v_int, &v_uint, &v_double,
+ &v_string, &v_object_path, &v_signature);
+ g_assert (!!v_boolean == !TRUE);
+ g_assert_cmpint (v_int16, ==, 10 + 100);
+ g_assert_cmpint (v_uint16, ==, 11 + 101);
+ g_assert_cmpint (v_int32, ==, 12 + 102);
+ g_assert_cmpint (v_uint32, ==, 13 + 103);
+ g_assert_cmpint (v_int64, ==, 14 + 104);
+ g_assert_cmpint (v_uint64, ==, 15 + 105);
+ g_assert_cmpint (v_int, ==, 16 + 106);
+ g_assert_cmpint (v_uint, ==, 17 + 107);
+ g_assert_cmpint (v_double, ==, 18.5 + 108);
+ }
+ g_variant_unref (ret);
+
+}
+
+static gpointer
+run_test_thread_func (gpointer user_data)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
+ GMainContext *thread_context;
+ GMainLoop *thread_loop;
+
+ thread_context = g_main_context_new ();
+ thread_loop = g_main_loop_new (thread_context, FALSE);
+ g_main_context_push_thread_default (thread_context);
+
+ run_test (connection);
+
+ g_main_loop_unref (thread_loop);
+ g_main_context_unref (thread_context);
+
+ g_main_loop_quit (loop);
+ return NULL;
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ if (just_serve)
+ return;
+
+ /* Run test in thread to avoid deadlock */
+ g_thread_create (run_test_thread_func,
+ connection,
+ TRUE,
+ NULL); /* GError** */
+ g_main_loop_run (loop);
+ g_main_loop_quit (loop);
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+static void
+load_typelib (void)
+{
+ GMappedFile *mfile;
+ GTypelib *lib;
+ GError *error;
+
+ error = NULL;
+ mfile = g_mapped_file_new ("My-1.0.typelib",
+ FALSE,
+ &error);
+ g_assert_no_error (error);
+
+ lib = g_typelib_new_from_mapped_file (mfile);
+ g_irepository_load_typelib (g_irepository_get_default (),
+ lib,
+ 0, /* GIRepositoryLoadFlags */
+ &error);
+ g_assert_no_error (error);
+}
+
+gint
+main (gint argc, gchar *argv[])
+{
+ guint owner_id;
+
+ g_type_init ();
+
+ load_typelib ();
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ obj = my_frobnicator_new ();
+
+ owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ "org.My.Service",
+ G_BUS_NAME_OWNER_FLAGS_REPLACE | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
+ on_bus_acquired,
+ on_name_acquired,
+ on_name_lost,
+ NULL,
+ NULL);
+
+ if (argc > 1)
+ just_serve = TRUE;
+
+ g_main_loop_run (loop);
+
+ g_main_loop_unref (loop);
+ g_object_unref (obj);
+
+ return 0;
+}