summaryrefslogtreecommitdiffstats
path: root/glib
diff options
context:
space:
mode:
Diffstat (limited to 'glib')
-rw-r--r--glib/Makefile.am6
-rw-r--r--glib/dbus-binding-tool-glib.c642
-rw-r--r--glib/dbus-binding-tool-glib.h1
-rw-r--r--glib/dbus-gmain.c29
-rw-r--r--glib/dbus-gobject.c599
-rw-r--r--glib/dbus-gobject.h10
-rw-r--r--glib/dbus-gproxy.c789
-rw-r--r--glib/dbus-gtype-specialized.c441
-rw-r--r--glib/dbus-gtype-specialized.h104
-rw-r--r--glib/dbus-gvalue-utils.c715
-rw-r--r--glib/dbus-gvalue-utils.h70
-rw-r--r--glib/dbus-gvalue.c1508
-rw-r--r--glib/dbus-gvalue.h55
13 files changed, 4185 insertions, 784 deletions
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 6d81e7d1..b9b9a70f 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -15,8 +15,12 @@ libdbus_glib_1_la_SOURCES = \
dbus-gthread.c \
dbus-gutils.c \
dbus-gutils.h \
+ dbus-gtype-specialized.c \
+ dbus-gtype-specialized.h \
dbus-gvalue.c \
- dbus-gvalue.h
+ dbus-gvalue.h \
+ dbus-gvalue-utils.c \
+ dbus-gvalue-utils.h
libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la
## don't export symbols that start with "_" (we use this
diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c
index 3c86d81f..76536aad 100644
--- a/glib/dbus-binding-tool-glib.c
+++ b/glib/dbus-binding-tool-glib.c
@@ -26,6 +26,7 @@
#include "dbus-gparser.h"
#include "dbus-gutils.h"
#include "dbus-gvalue.h"
+#include "dbus-gvalue-utils.h"
#include "dbus-glib-tool.h"
#include "dbus-binding-tool-glib.h"
#include <glib/gi18n.h>
@@ -45,12 +46,67 @@ typedef struct
GError **error;
GHashTable *generated;
+ GString *blob;
+ guint count;
} DBusBindingToolCData;
static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error);
static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
+static const char *
+dbus_g_type_get_marshal_name (GType gtype)
+{
+ switch (G_TYPE_FUNDAMENTAL (gtype))
+ {
+ case G_TYPE_BOOLEAN:
+ return "BOOLEAN";
+ case G_TYPE_UCHAR:
+ return "UCHAR";
+ case G_TYPE_INT:
+ return "INT";
+ case G_TYPE_UINT:
+ return "UINT";
+ case G_TYPE_INT64:
+ return "INT64";
+ case G_TYPE_UINT64:
+ return "UINT64";
+ case G_TYPE_DOUBLE:
+ return "DOUBLE";
+ case G_TYPE_STRING:
+ return "STRING";
+ case G_TYPE_POINTER:
+ return "POINTER";
+ case G_TYPE_BOXED:
+ return "BOXED";
+ case G_TYPE_OBJECT:
+ return "OBJECT";
+ default:
+ return NULL;
+ }
+}
+
+/* This entire function is kind of...ugh. */
+static const char *
+dbus_g_type_get_c_name (GType gtype)
+{
+ if (dbus_g_type_is_collection (gtype))
+ return "GArray";
+ if (dbus_g_type_is_map (gtype))
+ return "GHashTable";
+
+ if (g_type_is_a (gtype, G_TYPE_STRING))
+ return "char *";
+
+ /* This one is even more hacky...we get an extra *
+ * because G_TYPE_STRV is a G_TYPE_BOXED
+ */
+ if (g_type_is_a (gtype, G_TYPE_STRV))
+ return "char *";
+
+ return g_type_name (gtype);
+}
+
static char *
compute_marshaller (MethodInfo *method, GError **error)
{
@@ -71,9 +127,10 @@ compute_marshaller (MethodInfo *method, GError **error)
if (arg_info_get_direction (arg) == ARG_IN)
{
const char *marshal_name;
+ GType gtype;
- marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg));
- if (!marshal_name)
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), FALSE);
+ if (gtype == G_TYPE_INVALID)
{
g_set_error (error,
DBUS_BINDING_TOOL_ERROR,
@@ -83,6 +140,10 @@ compute_marshaller (MethodInfo *method, GError **error)
g_string_free (ret, TRUE);
return NULL;
}
+
+ marshal_name = dbus_g_type_get_marshal_name (gtype);
+ g_assert (marshal_name);
+
if (!first)
g_string_append (ret, ",");
else
@@ -91,6 +152,12 @@ compute_marshaller (MethodInfo *method, GError **error)
}
}
+ if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) {
+ if (!first)
+ g_string_append (ret, ",");
+ g_string_append (ret, "POINTER");
+ first = FALSE;
+ } else {
/* Append pointer for each out arg storage */
for (elt = method_info_get_args (method); elt; elt = elt->next)
{
@@ -105,12 +172,13 @@ compute_marshaller (MethodInfo *method, GError **error)
g_string_append (ret, "POINTER");
}
}
-
/* Final GError parameter */
if (!first)
g_string_append (ret, ",");
g_string_append (ret, "POINTER");
+ }
+
return g_string_free (ret, FALSE);
}
@@ -136,25 +204,31 @@ compute_marshaller_name (MethodInfo *method, const char *prefix, GError **error)
{
const char *marshal_name;
const char *type;
+ GType gtype;
type = arg_info_get_type (arg);
- marshal_name = dbus_gvalue_genmarshal_name_from_type (type);
- if (!marshal_name)
+ gtype = dbus_gtype_from_signature (type, FALSE);
+ if (gtype == G_TYPE_INVALID)
{
g_set_error (error,
DBUS_BINDING_TOOL_ERROR,
DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
- _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"),
+ _("Unsupported conversion from D-BUS type %s to glib type"),
type);
g_string_free (ret, TRUE);
return NULL;
}
+ marshal_name = dbus_g_type_get_marshal_name (gtype);
+ g_assert (marshal_name != NULL);
g_string_append (ret, "_");
- g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (type));
+ g_string_append (ret, marshal_name);
}
}
+ if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) {
+ g_string_append (ret, "_POINTER");
+ } else {
/* Append pointer for each out arg storage */
for (elt = method_info_get_args (method); elt; elt = elt->next)
{
@@ -165,9 +239,9 @@ compute_marshaller_name (MethodInfo *method, const char *prefix, GError **error)
g_string_append (ret, "_POINTER");
}
}
-
/* Final GError parameter */
g_string_append (ret, "_POINTER");
+ }
return g_string_free (ret, FALSE);
}
@@ -210,7 +284,8 @@ gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
if (interface_c_name == NULL)
{
- return TRUE;
+ if (!data->prefix)
+ return TRUE;
}
methods = interface_info_get_methods (interface);
@@ -223,10 +298,6 @@ gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
char *marshaller_name;
method = (MethodInfo *) tmp->data;
- if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL) == NULL)
- {
- continue;
- }
marshaller_name = compute_marshaller (method, error);
if (!marshaller_name)
@@ -291,12 +362,56 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
{
if (base_info_get_type (base) == INFO_TYPE_NODE)
{
+ GString *object_introspection_data_blob;
+ GIOChannel *channel;
+ guint i;
+
+ channel = data->channel;
+
+ object_introspection_data_blob = g_string_new_len ("", 0);
+
+ data->blob = object_introspection_data_blob;
+ data->count = 0;
+
+ if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, data->prefix))
+ goto io_lose;
+
if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base),
data, error))
return FALSE;
if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base),
data, error))
return FALSE;
+
+ WRITE_OR_LOSE ("};\n\n");
+
+ /* Information about the object. */
+
+ if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
+ channel, error, data->prefix))
+ goto io_lose;
+ WRITE_OR_LOSE (" 0,\n");
+ if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, data->prefix))
+ goto io_lose;
+ if (!write_printf_to_iochannel (" %d,\n", channel, error, data->count))
+ goto io_lose;
+ WRITE_OR_LOSE(" \"");
+ for (i = 0; i < object_introspection_data_blob->len; i++)
+ {
+ if (object_introspection_data_blob->str[i] != '\0')
+ {
+ if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
+ return FALSE;
+ }
+ else
+ {
+ if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
+ return FALSE;
+ }
+ }
+ WRITE_OR_LOSE ("\"\n};\n\n");
+
+ g_string_free (object_introspection_data_blob, TRUE);
}
else
{
@@ -304,41 +419,43 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
InterfaceInfo *interface;
GSList *methods;
GSList *tmp;
- gsize i;
- int count;
const char *interface_c_name;
GString *object_introspection_data_blob;
channel = data->channel;
+ object_introspection_data_blob = data->blob;
interface = (InterfaceInfo *) base;
interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
if (interface_c_name == NULL)
{
- return TRUE;
+ if (data->prefix == NULL)
+ return TRUE;
+ interface_c_name = data->prefix;
}
- object_introspection_data_blob = g_string_new_len ("", 0);
-
methods = interface_info_get_methods (interface);
- count = 0;
/* Table of marshalled methods. */
- if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL)))
- goto io_lose;
for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
{
MethodInfo *method;
char *marshaller_name;
- const char *method_c_name;
+ char *method_c_name;
+ gboolean async = FALSE;
GSList *args;
method = (MethodInfo *) tmp->data;
- method_c_name = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL);
+ method_c_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL));
if (method_c_name == NULL)
- {
- continue;
+ {
+ char *method_name_uscored;
+ method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
+ method_c_name = g_strdup_printf ("%s_%s",
+ interface_c_name,
+ method_name_uscored);
+ g_free (method_name_uscored);
}
if (!write_printf_to_iochannel (" { (GCallback) %s, ", channel, error,
@@ -357,6 +474,9 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
goto io_lose;
}
+ if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL)
+ async = TRUE;
+
/* Object method data blob format:
* <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
*/
@@ -367,6 +487,9 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
g_string_append (object_introspection_data_blob, method_info_get_name (method));
g_string_append_c (object_introspection_data_blob, '\0');
+ g_string_append_c (object_introspection_data_blob, async ? 'A' : 'S');
+ g_string_append_c (object_introspection_data_blob, '\0');
+
for (args = method_info_get_args (method); args; args = args->next)
{
ArgInfo *arg;
@@ -400,37 +523,8 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
g_string_append_c (object_introspection_data_blob, '\0');
- count++;
+ data->count++;
}
- WRITE_OR_LOSE ("};\n\n");
-
- /* Information about the object. */
-
- if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
- channel, error, interface_c_name))
- goto io_lose;
- WRITE_OR_LOSE (" 0,\n");
- if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, interface_c_name))
- goto io_lose;
- if (!write_printf_to_iochannel (" %d,\n", channel, error, count))
- goto io_lose;
- WRITE_OR_LOSE(" \"");
- for (i = 0; i < object_introspection_data_blob->len; i++)
- {
- if (object_introspection_data_blob->str[i] != '\0')
- {
- if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
- return FALSE;
- }
- else
- {
- if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
- return FALSE;
- }
- }
- WRITE_OR_LOSE ("\"\n};\n\n");
-
- g_string_free (object_introspection_data_blob, TRUE);
}
return TRUE;
io_lose:
@@ -471,6 +565,8 @@ dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, const
memset (&data, 0, sizeof (data));
+ dbus_g_value_types_init ();
+
data.prefix = prefix;
data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
data.error = error;
@@ -607,6 +703,8 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
{
ArgInfo *arg;
const char *type_str;
+ const char *type_suffix;
+ GType gtype;
int direction;
arg = args->data;
@@ -615,9 +713,8 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
direction = arg_info_get_direction (arg);
- type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN);
-
- if (!type_str)
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ if (gtype == G_TYPE_INVALID)
{
g_set_error (error,
DBUS_BINDING_TOOL_ERROR,
@@ -628,18 +725,37 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
interface_info_get_name (iface));
return FALSE;
}
+ type_str = dbus_g_type_get_c_name (gtype);
+ g_assert (type_str);
+ /* Variants are special...*/
+ if (gtype == G_TYPE_VALUE)
+ {
+ if (direction == ARG_IN)
+ type_suffix = "*";
+ else
+ type_suffix = "";
+ }
+ else if ((g_type_is_a (gtype, G_TYPE_BOXED)
+ || g_type_is_a (gtype, G_TYPE_OBJECT)
+ || g_type_is_a (gtype, G_TYPE_POINTER)))
+ type_suffix = "*";
+ else
+ type_suffix = "";
+
switch (direction)
{
case ARG_IN:
- if (!write_printf_to_iochannel ("%s IN_%s", channel, error,
+ if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
type_str,
+ type_suffix,
arg_info_get_name (arg)))
goto io_lose;
break;
case ARG_OUT:
- if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error,
+ if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
type_str,
+ type_suffix,
arg_info_get_name (arg)))
goto io_lose;
break;
@@ -653,32 +769,71 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
return FALSE;
}
-static gboolean
-write_args_sig_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
+#define MAP_FUNDAMENTAL(NAME) \
+ case G_TYPE_ ## NAME: \
+ return g_strdup ("G_TYPE_" #NAME);
+#define MAP_KNOWN(NAME) \
+ if (gtype == NAME) \
+ return g_strdup (#NAME)
+static char *
+dbus_g_type_get_lookup_function (GType gtype)
{
- GSList *args;
-
- WRITE_OR_LOSE ("\"");
-
- for (args = method_info_get_args (method); args; args = args->next)
+ char *type_lookup;
+ switch (gtype)
{
- ArgInfo *arg;
-
- arg = args->data;
-
- if (direction != arg_info_get_direction (arg))
- continue;
-
- if (!write_printf_to_iochannel ("%s", channel, error, arg_info_get_type (arg)))
- goto io_lose;
+ MAP_FUNDAMENTAL(CHAR);
+ MAP_FUNDAMENTAL(UCHAR);
+ MAP_FUNDAMENTAL(BOOLEAN);
+ MAP_FUNDAMENTAL(LONG);
+ MAP_FUNDAMENTAL(ULONG);
+ MAP_FUNDAMENTAL(INT);
+ MAP_FUNDAMENTAL(UINT);
+ MAP_FUNDAMENTAL(INT64);
+ MAP_FUNDAMENTAL(UINT64);
+ MAP_FUNDAMENTAL(FLOAT);
+ MAP_FUNDAMENTAL(DOUBLE);
+ MAP_FUNDAMENTAL(STRING);
}
-
- WRITE_OR_LOSE ("\", ");
-
- return TRUE;
- io_lose:
- return FALSE;
+ if (dbus_g_type_is_collection (gtype))
+ {
+ GType elt_gtype;
+ char *sublookup;
+
+ elt_gtype = dbus_g_type_get_collection_specialization (gtype);
+ sublookup = dbus_g_type_get_lookup_function (elt_gtype);
+ g_assert (sublookup);
+ type_lookup = g_strdup_printf ("dbus_g_type_get_collection (\"GArray\", %s)",
+ sublookup);
+ g_free (sublookup);
+ return type_lookup;
+ }
+ else if (dbus_g_type_is_map (gtype))
+ {
+ GType key_gtype;
+ char *key_lookup;
+ GType value_gtype;
+ char *value_lookup;
+
+ key_gtype = dbus_g_type_get_map_key_specialization (gtype);
+ value_gtype = dbus_g_type_get_map_value_specialization (gtype);
+ key_lookup = dbus_g_type_get_lookup_function (key_gtype);
+ g_assert (key_lookup);
+ value_lookup = dbus_g_type_get_lookup_function (value_gtype);
+ g_assert (value_lookup);
+ type_lookup = g_strdup_printf ("dbus_g_type_get_map (\"GHashTable\", %s, %s)",
+ key_lookup, value_lookup);
+ g_free (key_lookup);
+ g_free (value_lookup);
+ return type_lookup;
+ }
+ MAP_KNOWN(G_TYPE_VALUE);
+ MAP_KNOWN(G_TYPE_STRV);
+ MAP_KNOWN(DBUS_TYPE_G_PROXY);
+ MAP_KNOWN(DBUS_TYPE_G_PROXY_ARRAY);
+ return NULL;
}
+#undef MAP_FUNDAMENTAL
+#undef MAP_KNOWN
static gboolean
write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
@@ -688,25 +843,38 @@ write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *
for (args = method_info_get_args (method); args; args = args->next)
{
ArgInfo *arg;
+ GType gtype;
+ char *type_lookup;
arg = args->data;
if (direction != arg_info_get_direction (arg))
continue;
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ g_assert (gtype != G_TYPE_INVALID);
+ type_lookup = dbus_g_type_get_lookup_function (gtype);
+ g_assert (type_lookup != NULL);
+
switch (direction)
{
+
case ARG_IN:
- if (!write_printf_to_iochannel ("IN_%s, ", channel, error, arg_info_get_name (arg)))
+ if (!write_printf_to_iochannel ("%s, IN_%s, ", channel, error,
+ type_lookup,
+ arg_info_get_name (arg)))
goto io_lose;
break;
case ARG_OUT:
- if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, arg_info_get_name (arg)))
+ if (!write_printf_to_iochannel ("%s, OUT_%s, ", channel, error,
+ type_lookup,
+ arg_info_get_name (arg)))
goto io_lose;
break;
case ARG_INVALID:
break;
}
+ g_free (type_lookup);
}
return TRUE;
@@ -722,15 +890,303 @@ check_supported_parameters (MethodInfo *method)
for (args = method_info_get_args (method); args; args = args->next)
{
ArgInfo *arg;
+ GType gtype;
+
arg = args->data;
- if (!dbus_gvalue_ctype_from_type (arg_info_get_type (arg),
- arg_info_get_direction (arg)))
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ if (gtype == G_TYPE_INVALID)
return FALSE;
}
return TRUE;
}
static gboolean
+write_untyped_out_args (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
+{
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+
+ arg = args->data;
+ if (arg_info_get_direction (arg) != ARG_OUT)
+ continue;
+
+ if (!write_printf_to_iochannel ("OUT_%s, ", channel, error,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ }
+
+ return TRUE;
+ io_lose:
+ return FALSE;
+}
+
+static gboolean
+write_formal_declarations_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
+ {
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ GType gtype;
+ const char *type_str, *type_suffix;
+ int dir;
+
+ arg = args->data;
+
+ dir = arg_info_get_direction (arg);
+
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ type_str = dbus_g_type_get_c_name (gtype);
+
+ if (!type_str)
+ {
+ g_set_error (error,
+ DBUS_BINDING_TOOL_ERROR,
+ DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+ _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
+ arg_info_get_type (arg),
+ method_info_get_name (method),
+ interface_info_get_name (iface));
+ return FALSE;
+ }
+
+ /* Variants are special...*/
+ if (gtype == G_TYPE_VALUE)
+ {
+ if (direction == ARG_IN)
+ type_suffix = "*";
+ else
+ type_suffix = "";
+ }
+ else if ((g_type_is_a (gtype, G_TYPE_BOXED)
+ || g_type_is_a (gtype, G_TYPE_OBJECT)
+ || g_type_is_a (gtype, G_TYPE_POINTER)))
+ type_suffix = "*";
+ else
+ type_suffix = "";
+
+ if (direction != dir)
+ continue;
+
+ switch (dir)
+ {
+ case ARG_IN:
+ if (!write_printf_to_iochannel (" %s%s IN_%s;\n", channel, error,
+ type_str, type_suffix,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_OUT:
+ if (!write_printf_to_iochannel (" %s%s OUT_%s;\n", channel, error,
+ type_str, type_suffix,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_INVALID:
+ break;
+ }
+ }
+ return TRUE;
+ io_lose:
+ return FALSE;
+ }
+
+static gboolean
+write_formal_parameters_for_direction (InterfaceInfo *iface, MethodInfo *method, int dir, GIOChannel *channel, GError **error)
+{
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ const char *type_str;
+ const char *type_suffix;
+ GType gtype;
+ int direction;
+
+ arg = args->data;
+
+ direction = arg_info_get_direction (arg);
+ if (dir != direction) continue;
+
+ WRITE_OR_LOSE (", ");
+
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ type_str = dbus_g_type_get_c_name (gtype);
+ /* Variants are special...*/
+ if (gtype == G_TYPE_VALUE)
+ {
+ if (direction == ARG_IN)
+ type_suffix = "*";
+ else
+ type_suffix = "";
+ }
+ else if ((g_type_is_a (gtype, G_TYPE_BOXED)
+ || g_type_is_a (gtype, G_TYPE_OBJECT)
+ || g_type_is_a (gtype, G_TYPE_POINTER)))
+ type_suffix = "*";
+ else
+ type_suffix = "";
+
+ if (!type_str)
+ {
+ g_set_error (error,
+ DBUS_BINDING_TOOL_ERROR,
+ DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+ _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
+ arg_info_get_type (arg),
+ method_info_get_name (method),
+ interface_info_get_name (iface));
+ return FALSE;
+ }
+
+ switch (direction)
+ {
+ case ARG_IN:
+ if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
+ type_str,
+ type_suffix,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_OUT:
+ if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
+ type_str,
+ type_suffix,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_INVALID:
+ break;
+ }
+ }
+ return TRUE;
+ io_lose:
+ return FALSE;
+}
+
+static gboolean
+write_typed_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
+ {
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ int dir;
+ GType gtype;
+ const char *type_lookup;
+
+ arg = args->data;
+
+ dir = arg_info_get_direction (arg);
+
+ if (dir != direction)
+ continue;
+
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ type_lookup = dbus_g_type_get_lookup_function (gtype);
+
+ if (!write_printf_to_iochannel ("%s, &%s_%s, ", channel, error, type_lookup, direction == ARG_IN ? "IN" : "OUT", arg_info_get_name (arg)))
+ goto io_lose;
+ }
+ return TRUE;
+ io_lose:
+ return FALSE;
+}
+
+static gboolean
+write_async_method_client (GIOChannel *channel, InterfaceInfo *interface, MethodInfo *method, GError **error)
+{
+ char *method_name, *iface_prefix;
+ iface_prefix = iface_to_c_prefix (interface_info_get_name (interface));
+ method_name = compute_client_method_name (iface_prefix, method);
+
+ /* Write the typedef for the client callback */
+ if (!write_printf_to_iochannel ("typedef void (*%s_reply) (", channel, error, method_name))
+ goto io_lose;
+ {
+ GSList *args;
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ const char *type_suffix, *type_str;
+ GType gtype;
+
+ arg = args->data;
+
+ if (arg_info_get_direction (arg) != ARG_OUT)
+ continue;
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ if (gtype != G_TYPE_VALUE && (g_type_is_a (gtype, G_TYPE_BOXED)
+ || g_type_is_a (gtype, G_TYPE_OBJECT)
+ || g_type_is_a (gtype, G_TYPE_POINTER)))
+ type_suffix = "*";
+ else
+ type_suffix = "";
+ type_str = dbus_g_type_get_c_name (dbus_gtype_from_signature (arg_info_get_type (arg), TRUE));
+ if (!write_printf_to_iochannel ("%s %sOUT_%s, ", channel, error, type_str, type_suffix, arg_info_get_name (arg)))
+ goto io_lose;
+ }
+ }
+ WRITE_OR_LOSE ("GError *error, gpointer userdata);\n\n");
+
+
+ /* Write the callback when the call returns */
+ WRITE_OR_LOSE ("static void\n");
+ if (!write_printf_to_iochannel ("%s_async_callback (DBusGPendingCall *pending, DBusGAsyncData *data)\n", channel, error, method_name))
+ goto io_lose;
+ WRITE_OR_LOSE ("{\n");
+ WRITE_OR_LOSE (" GError *error = NULL;\n");
+ if (!write_formal_declarations_for_direction (interface, method, channel, ARG_OUT, error))
+ goto io_lose;
+ WRITE_OR_LOSE (" dbus_g_proxy_end_call (data->proxy, pending, &error, ");
+ if (!write_typed_args_for_direction (interface, method, channel, ARG_OUT, error))
+ goto io_lose;
+ WRITE_OR_LOSE("G_TYPE_INVALID);\n");
+ if (!write_printf_to_iochannel (" (*(%s_reply)data->cb) (", channel, error, method_name))
+ goto io_lose;
+ if (!write_untyped_out_args (interface, method, channel, error))
+ goto io_lose;
+ WRITE_OR_LOSE ("error, data->userdata);\n");
+ WRITE_OR_LOSE (" return;\n}\n\n");
+
+
+ /* Write the main wrapper function */
+ WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n");
+ if (!write_printf_to_iochannel ("%s_async (DBusGProxy *proxy", channel, error,
+ method_name))
+ goto io_lose;
+ if (!write_formal_parameters_for_direction (interface, method, ARG_IN, channel, error))
+ goto io_lose;
+
+ if (!write_printf_to_iochannel (", %s_reply callback, gpointer userdata)\n\n", channel, error, method_name))
+ goto io_lose;
+
+ WRITE_OR_LOSE ("{\n");
+ WRITE_OR_LOSE (" DBusGPendingCall *pending;\n DBusGAsyncData *stuff;\n stuff = g_new (DBusGAsyncData, 1);\n stuff->proxy = proxy;\n stuff->cb = callback;\n stuff->userdata = userdata;\n");
+ if (!write_printf_to_iochannel (" pending = dbus_g_proxy_begin_call (proxy, \"%s\", ", channel, error, method_info_get_name (method)))
+ goto io_lose;
+ if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
+ goto io_lose;
+ WRITE_OR_LOSE ("G_TYPE_INVALID);\n");
+
+ if (!write_printf_to_iochannel (" dbus_g_pending_call_set_notify(pending, (DBusGPendingCallNotify)%s_async_callback, stuff, g_free);\n", channel, error, method_name))
+ goto io_lose;
+
+ WRITE_OR_LOSE (" return TRUE;\n}\n\n");
+
+ g_free (method_name);
+ return TRUE;
+ io_lose:
+ return FALSE;
+ }
+
+static gboolean
generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
{
GSList *tmp;
@@ -818,21 +1274,19 @@ generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error
method_info_get_name (method)))
goto io_lose;
- if (!write_args_sig_for_direction (interface, method, channel, ARG_IN, error))
- goto io_lose;
-
- if (!write_args_sig_for_direction (interface, method, channel, ARG_OUT, error))
- goto io_lose;
-
WRITE_OR_LOSE ("error, ");
if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
goto io_lose;
+ WRITE_OR_LOSE ("G_TYPE_INVALID, ");
+
if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
goto io_lose;
- WRITE_OR_LOSE ("NULL);\n}\n\n");
+ WRITE_OR_LOSE ("G_TYPE_INVALID);\n}\n\n");
+
+ write_async_method_client (channel, interface, method, error);
}
if (!write_printf_to_iochannel ("#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_%s */\n\n", channel, error, iface_prefix))
@@ -853,6 +1307,8 @@ dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gbool
DBusBindingToolCData data;
gboolean ret;
+ dbus_g_value_types_init ();
+
memset (&data, 0, sizeof (data));
data.channel = channel;
diff --git a/glib/dbus-binding-tool-glib.h b/glib/dbus-binding-tool-glib.h
index 9988df29..257b5347 100644
--- a/glib/dbus-binding-tool-glib.h
+++ b/glib/dbus-binding-tool-glib.h
@@ -26,6 +26,7 @@
G_BEGIN_DECLS
#define DBUS_GLIB_ANNOTATION_C_SYMBOL "org.freedesktop.DBus.GLib.CSymbol"
+#define DBUS_GLIB_ANNOTATION_ASYNC "org.freedesktop.DBus.GLib.Async"
gboolean dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gboolean ignore_unsupported, GError **error);
gboolean dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, const char *prefix, GError **error);
diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c
index 046c493c..08f8aef4 100644
--- a/glib/dbus-gmain.c
+++ b/glib/dbus-gmain.c
@@ -27,6 +27,9 @@
#include <dbus/dbus-glib-lowlevel.h>
#include "dbus-gtest.h"
#include "dbus-gutils.h"
+#include "dbus-gvalue.h"
+#include "dbus-gvalue-utils.h"
+#include <string.h>
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
@@ -709,6 +712,8 @@ dbus_g_bus_get (DBusBusType type,
DBusError derror;
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ dbus_g_value_types_init ();
dbus_error_init (&derror);
@@ -738,6 +743,30 @@ dbus_g_bus_get (DBusBusType type,
gboolean
_dbus_gmain_test (const char *test_data_dir)
{
+ GType rectype;
+ GType gtype;
+
+ g_type_init ();
+ dbus_g_value_types_init ();
+
+ rectype = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
+ g_assert (rectype != G_TYPE_INVALID);
+ g_assert (!strcmp (g_type_name (rectype), "GArray+guint"));
+
+ gtype = dbus_gtype_from_signature ("au", TRUE);
+ g_assert (gtype == rectype);
+
+ rectype = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
+ g_assert (rectype != G_TYPE_INVALID);
+ g_assert (!strcmp (g_type_name (rectype), "GHashTable+gchararray+gchararray"));
+
+ gtype = dbus_gtype_from_signature ("a{ss}", TRUE);
+ g_assert (gtype == rectype);
+
+ gtype = dbus_gtype_from_signature ("o", FALSE);
+ g_assert (gtype == G_TYPE_OBJECT);
+ gtype = dbus_gtype_from_signature ("o", TRUE);
+ g_assert (gtype == DBUS_TYPE_G_PROXY);
return TRUE;
}
diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c
index 09fc97fc..e2645f41 100644
--- a/glib/dbus-gobject.c
+++ b/glib/dbus-gobject.c
@@ -22,12 +22,15 @@
*/
#include <config.h>
+#include <gobject/gvaluecollector.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "dbus-gtest.h"
#include "dbus-gutils.h"
#include "dbus-gobject.h"
#include "dbus-gvalue.h"
+#include "dbus-gmarshal.h"
+#include "dbus-gvalue-utils.h"
#include <string.h>
/**
@@ -35,8 +38,9 @@
* @{
*/
-static GStaticRWLock info_hash_lock = G_STATIC_RW_LOCK_INIT;
+static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
static GHashTable *info_hash = NULL;
+static GHashTable *marshal_table = NULL;
static char*
uscore_to_wincaps (const char *uscore)
@@ -129,7 +133,7 @@ static const char *
method_arg_info_from_object_info (const DBusGObjectInfo *object,
const DBusGMethodInfo *method)
{
- return string_table_lookup (get_method_data (object, method), 2);
+ return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
}
static const char *
@@ -199,42 +203,6 @@ method_output_signature_from_object_info (const DBusGObjectInfo *object,
return method_dir_signature_from_object_info (object, method, FALSE);
}
-/**
- * Converts the args of a message into an array of GValue.
- *
- * @param message the message
- * @returns #NULL if conversion fails, otherwise the values.
- */
-GValueArray *
-_dbus_glib_marshal_dbus_message_to_gvalue_array (DBusMessage *message)
-{
- GValueArray *ret;
- DBusMessageIter iter;
- int dtype;
-
- ret = g_value_array_new (6); /* 6 is a typical maximum for arguments */
- dbus_message_iter_init (message, &iter);
-
- while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
- {
- GValue value = { 0, };
-
- if (!dbus_gvalue_demarshal (&iter, &value))
- {
- g_warning ("Unable to convert arg type %d to GValue", dtype);
- g_value_array_free (ret);
- ret = NULL;
- goto out;
- }
- g_value_array_append (ret, &value);
-
- dbus_message_iter_next (&iter);
- }
-
- out:
- return ret;
-}
-
static void
gobject_unregister_function (DBusConnection *connection,
void *user_data)
@@ -267,7 +235,7 @@ introspect_properties (GObject *object, GString *xml)
gboolean can_get;
GParamSpec *spec = specs[i];
- dbus_type = dbus_gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec));
+ dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
if (dbus_type == NULL)
continue;
@@ -347,7 +315,7 @@ introspect_signals (GType type, GString *xml)
g_signal_query (ids[i], &query);
- if (query.return_type)
+ if (query.return_type != G_TYPE_NONE)
continue; /* FIXME: these could be listed as methods ? */
g_string_append (xml, " <signal name=\"");
@@ -356,8 +324,11 @@ introspect_signals (GType type, GString *xml)
for (arg = 0; arg < query.n_params; arg++)
{
- const char *dbus_type = dbus_gtype_to_dbus_type (query.param_types[arg]);
+ const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]);
+ if (!dbus_type)
+ continue;
+
g_string_append (xml, " <arg type=\"");
g_string_append (xml, dbus_type);
g_string_append (xml, "\"/>\n");
@@ -428,7 +399,7 @@ introspect_interfaces (GObject *object, GString *xml)
{
GType classtype;
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_lock (&globals_lock);
for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
{
@@ -475,7 +446,7 @@ introspect_interfaces (GObject *object, GString *xml)
}
}
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_unlock (&globals_lock);
}
static DBusHandlerResult
@@ -560,15 +531,15 @@ set_object_property (DBusConnection *connection,
GValue value = { 0, };
DBusMessage *ret;
DBusMessageIter sub;
+ DBusGValueMarshalCtx context;
dbus_message_iter_recurse (iter, &sub);
-
- /* The g_object_set_property() will transform some types, e.g. it
- * will let you use a uchar to set an int property etc. Note that
- * any error in value range or value conversion will just
- * g_warning(). These GObject skels are not for secure applications.
- */
- if (dbus_gvalue_demarshal (&sub, &value))
+
+ context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
+ context.proxy = NULL;
+
+ g_value_init (&value, pspec->value_type);
+ if (dbus_gvalue_demarshal (&context, &sub, &value, NULL))
{
g_object_set_property (object,
pspec->name,
@@ -644,7 +615,7 @@ lookup_object_and_method (GObject *object,
signature = dbus_message_get_signature (message);
ret = FALSE;
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_lock (&globals_lock);
if (!info_hash)
goto out;
@@ -674,6 +645,7 @@ lookup_object_and_method (GObject *object,
expected_interface = method_interface_from_object_info (*object_ret, method);
expected_member = method_name_from_object_info (*object_ret, method);
expected_signature = method_input_signature_from_object_info (*object_ret, method);
+
if ((interface == NULL
|| strcmp (expected_interface, interface) == 0)
&& strcmp (expected_member, member) == 0
@@ -689,7 +661,7 @@ lookup_object_and_method (GObject *object,
}
}
out:
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_unlock (&globals_lock);
return ret;
}
@@ -759,74 +731,147 @@ invoke_object_method (GObject *object,
DBusConnection *connection,
DBusMessage *message)
{
- gboolean had_error;
+ gboolean had_error, call_only;
GError *gerror;
GValueArray *value_array;
GValue object_value = {0,};
GValue error_value = {0,};
GValue return_value = {0,};
GClosure closure;
- char *out_signature;
- int out_signature_len;
- GArray *out_param_values;
- int i;
+ char *in_signature;
+ char *out_signature = NULL;
+ int current_type;
+ DBusSignatureIter out_signature_iter;
+ GArray *out_param_values = NULL;
+ GValueArray *out_param_gvalues = NULL;
+ int out_param_count;
+ int out_param_pos, out_param_gvalue_pos;
DBusHandlerResult result;
DBusMessage *reply;
gerror = NULL;
+ if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0) {
+ call_only = TRUE;
+ } else {
+ call_only = FALSE;
+ }
+
/* This is evil. We do this to work around the fact that
* the generated glib marshallers check a flag in the closure object
* which we don't care about. We don't need/want to create
* a new closure for each invocation.
*/
memset (&closure, 0, sizeof (closure));
+
+ in_signature = method_input_signature_from_object_info (object_info, method);
/* Convert method IN parameters to GValueArray */
- value_array = _dbus_glib_marshal_dbus_message_to_gvalue_array (message);
-
- g_return_val_if_fail (value_array != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+ {
+ GArray *types_array;
+ guint n_params;
+ const GType *types;
+ DBusGValueMarshalCtx context;
+
+ context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
+ context.proxy = NULL;
+
+ types_array = dbus_gtypes_from_arg_signature (in_signature, FALSE);
+ n_params = types_array->len;
+ types = (const GType*) types_array->data;
+
+ value_array = dbus_gvalue_demarshal_message (&context, message, n_params, types, NULL);
+ if (value_array == NULL)
+ {
+ g_free (in_signature);
+ g_array_free (types_array, TRUE);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ g_array_free (types_array, TRUE);
+ }
/* Prepend object as first argument */
g_value_init (&object_value, G_TYPE_OBJECT);
g_value_set_object (&object_value, object);
g_value_array_prepend (value_array, &object_value);
+ if (call_only) {
+ GValue context_value = {0,};
+ DBusGMethodInvocation *context;
+ context = g_new (DBusGMethodInvocation, 1);
+ context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
+ context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
+ context->object = object_info;
+ context->method = method;
+ g_value_init (&context_value, G_TYPE_POINTER);
+ g_value_set_pointer (&context_value, context);
+ g_value_array_append (value_array, &context_value);
+ } else {
out_signature = method_output_signature_from_object_info (object_info, method);
- out_signature_len = strlen (out_signature);
+
+ /* Count number of output parameters */
+ dbus_signature_iter_init (&out_signature_iter, out_signature);
+ out_param_count = 0;
+ while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
+ {
+ out_param_count++;
+ dbus_signature_iter_next (&out_signature_iter);
+ }
/* Create an array to store the actual values of OUT
* parameters. Then, create a GValue boxed POINTER
* to each of those values, and append to the invocation,
* so the method can return the OUT parameters.
*/
- out_param_values = g_array_new (FALSE, TRUE, sizeof (DBusBasicGValue));
- for (i = 0; i < out_signature_len; i++)
+ out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
+
+ /* We have a special array of GValues for toplevel GValue return
+ * types.
+ */
+ out_param_gvalues = g_value_array_new (out_param_count);
+ out_param_pos = 0;
+ out_param_gvalue_pos = 0;
+ dbus_signature_iter_init (&out_signature_iter, out_signature);
+ while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
{
GValue value = {0, };
- DBusBasicGValue basic;
+ GTypeCValue storage;
- memset (&basic, 0, sizeof (basic));
-
- /* FIXME - broken for container types */
-
- g_array_append_val (out_param_values, basic);
g_value_init (&value, G_TYPE_POINTER);
- g_value_set_pointer (&value, &(g_array_index (out_param_values, DBusBasicGValue, i)));
+
+ /* We special case variants to make method invocation a bit nicer */
+ if (current_type != DBUS_TYPE_VARIANT)
+ {
+ memset (&storage, 0, sizeof (storage));
+ g_array_append_val (out_param_values, storage);
+ g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
+ out_param_pos++;
+ }
+ else
+ {
+ g_value_array_append (out_param_gvalues, NULL);
+ g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
+ out_param_gvalue_pos++;
+ }
g_value_array_append (value_array, &value);
+ dbus_signature_iter_next (&out_signature_iter);
}
/* Append GError as final argument */
g_value_init (&error_value, G_TYPE_POINTER);
g_value_set_pointer (&error_value, &gerror);
g_value_array_append (value_array, &error_value);
-
+ }
/* Actually invoke method */
g_value_init (&return_value, G_TYPE_BOOLEAN);
method->marshaller (&closure, &return_value,
value_array->n_values,
value_array->values,
NULL, method->function);
+ if (call_only) {
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ goto done;
+ }
had_error = !g_value_get_boolean (&return_value);
if (!had_error)
@@ -839,16 +884,34 @@ invoke_object_method (GObject *object,
/* Append OUT arguments to reply */
dbus_message_iter_init_append (reply, &iter);
- for (i = 0; i < out_signature_len; i++)
+ dbus_signature_iter_init (&out_signature_iter, out_signature);
+ out_param_pos = 0;
+ out_param_gvalue_pos = 0;
+ while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
{
- DBusBasicGValue *value;
-
- /* FIXME - broken for container types */
-
- value = &(g_array_index (out_param_values, DBusBasicGValue, i));
- if (!dbus_message_iter_append_basic (&iter, out_signature[i], value))
- goto nomem;
+ GValue gvalue = {0, };
+ g_value_init (&gvalue, dbus_gtype_from_signature_iter (&out_signature_iter, FALSE));
+ if (current_type != DBUS_TYPE_VARIANT)
+ {
+ if (!dbus_gvalue_take (&gvalue,
+ &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
+ g_assert_not_reached ();
+ out_param_pos++;
+ }
+ else
+ {
+ g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
+ out_param_gvalue_pos++;
+ }
+
+ if (!dbus_gvalue_marshal (&iter, &gvalue))
+ goto nomem;
+ /* Here we actually free the allocated value; we
+ * took ownership of it with dbus_gvalue_take.
+ */
+ g_value_unset (&gvalue);
+ dbus_signature_iter_next (&out_signature_iter);
}
}
else
@@ -860,30 +923,17 @@ invoke_object_method (GObject *object,
dbus_message_unref (reply);
}
- /* Assume that if there was an error, no return values are
- * set */
- if (!had_error)
- {
- /* Be sure to free all returned STRING arguments for now;
- * later this should be specified via method info parameter
- * annotation; probably we want to support custom free funcs too */
- for (i = 0; i < out_signature_len; i++)
- {
- DBusBasicGValue *value;
-
- value = &(g_array_index (out_param_values, DBusBasicGValue, i));
- if (out_signature[i] == DBUS_TYPE_STRING)
- g_free (value->gpointer_val);
- }
- }
-
result = DBUS_HANDLER_RESULT_HANDLED;
done:
+ g_free (in_signature);
g_free (out_signature);
- g_array_free (out_param_values, TRUE);
+ if (!call_only) {
+ g_array_free (out_param_values, TRUE);
+ g_value_array_free (out_param_gvalues);
+ g_value_unset (&object_value);
+ g_value_unset (&error_value);
+ }
g_value_array_free (value_array);
- g_value_unset (&object_value);
- g_value_unset (&error_value);
g_value_unset (&return_value);
return result;
nomem:
@@ -891,6 +941,55 @@ invoke_object_method (GObject *object,
goto done;
}
+void
+dbus_g_method_return (DBusGMethodInvocation *context, ...)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ va_list args;
+ char *out_sig;
+ GArray *argsig;
+ guint i;
+
+ reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
+ out_sig = method_output_signature_from_object_info (context->object, context->method);
+ argsig = dbus_gtypes_from_arg_signature (out_sig, FALSE);
+
+ dbus_message_iter_init_append (reply, &iter);
+
+ va_start (args, context);
+ for (i = 0; i < argsig->len; i++) {
+ GValue value = {0,};
+ char *error;
+ g_value_init (&value, g_array_index (argsig, GType, i));
+ error = NULL;
+ G_VALUE_COLLECT (&value, args, 0, &error);
+ if (error) {
+ g_warning(error);
+ g_free (error);
+ }
+ dbus_gvalue_marshal (&iter, &value);
+ }
+ va_end (args);
+
+ dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
+ dbus_message_unref (reply);
+
+ dbus_g_connection_unref (context->connection);
+ dbus_g_message_unref (context->message);
+ g_free (context);
+}
+
+void
+dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
+{
+ DBusMessage *reply;
+ reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
+ dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
+ dbus_message_unref (reply);
+}
+
+
static DBusHandlerResult
gobject_message_function (DBusConnection *connection,
DBusMessage *message,
@@ -1009,6 +1108,125 @@ static DBusObjectPathVTable gobject_dbus_vtable = {
NULL
};
+typedef struct {
+ GClosure closure;
+ DBusGConnection *connection;
+ GObject *object;
+ char *signame;
+} DBusGSignalClosure;
+
+static GClosure *
+dbus_g_signal_closure_new (DBusGConnection *connection,
+ GObject *object,
+ const char *signame)
+{
+ DBusGSignalClosure *closure;
+
+ closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
+
+ closure->connection = dbus_g_connection_ref (connection);
+ closure->object = object;
+ closure->signame = g_strdup (signame);
+ return (GClosure*) closure;
+}
+
+static void
+dbus_g_signal_closure_finalize (gpointer data,
+ GClosure *closure)
+{
+ DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
+
+ dbus_g_connection_unref (sigclosure->connection);
+ g_free (sigclosure->signame);
+}
+
+static void
+signal_emitter_marshaller (GClosure *closure,
+ GValue *retval,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ DBusGSignalClosure *sigclosure;
+ DBusMessage *signal;
+ DBusMessageIter iter;
+ guint i;
+ const char *path;
+
+ sigclosure = (DBusGSignalClosure *) closure;
+
+ g_assert (retval == NULL);
+
+ path = _dbus_gobject_get_path (sigclosure->object);
+
+ g_assert (path != NULL);
+
+ signal = dbus_message_new_signal (path,
+ "org.gtk.objects",
+ sigclosure->signame);
+ if (!signal)
+ {
+ g_error ("out of memory");
+ return;
+ }
+
+ dbus_message_iter_init_append (signal, &iter);
+
+ /* First argument is the object itself, and we can't marshall that */
+ for (i = 1; i < n_param_values; i++)
+ {
+ if (!dbus_gvalue_marshal (&iter,
+ (GValue *) (&(param_values[i]))))
+ {
+ g_warning ("failed to marshal parameter %d for signal %s",
+ i, sigclosure->signame);
+ goto out;
+ }
+ }
+ dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
+ signal, NULL);
+ out:
+ dbus_message_unref (signal);
+}
+
+static void
+export_signals (DBusGConnection *connection, GObject *object)
+{
+ guint i;
+ guint *ids, n_ids;
+
+ ids = g_signal_list_ids (G_TYPE_FROM_INSTANCE (object), &n_ids);
+ if (!n_ids)
+ return;
+
+ /* FIXME: recurse to parent types ? */
+ for (i = 0; i < n_ids; i++)
+ {
+ GSignalQuery query;
+ GClosure *closure;
+
+ g_signal_query (ids[i], &query);
+
+ if (query.return_type != G_TYPE_NONE) {
+ g_warning("Not exporting signal '%s' as it has a return type %s", query.signal_name, g_type_name (query.return_type));
+ continue; /* FIXME: these could be listed as methods ? */
+ }
+
+ closure = dbus_g_signal_closure_new (connection, object, query.signal_name);
+ g_closure_set_marshal (closure, signal_emitter_marshaller);
+
+ g_signal_connect_closure_by_id (object,
+ ids[i],
+ 0,
+ closure,
+ FALSE);
+
+ g_closure_add_finalize_notifier (closure, NULL,
+ dbus_g_signal_closure_finalize);
+ }
+}
+
/** @} */ /* end of internals */
/**
@@ -1017,7 +1235,7 @@ static DBusObjectPathVTable gobject_dbus_vtable = {
*/
/**
- * Install introspection information about the given object class
+ * Install introspection information about the given object GType
* sufficient to allow methods on the object to be invoked by name.
* The introspection information is normally generated by
* dbus-glib-tool, then this function is called in the
@@ -1027,16 +1245,24 @@ static DBusObjectPathVTable gobject_dbus_vtable = {
* object registered with dbus_g_connection_register_g_object() can have
* their methods invoked remotely.
*
- * @param object_class class struct of the object
+ * @param object_type GType for the object
* @param info introspection data generated by dbus-glib-tool
*/
void
-dbus_g_object_class_install_info (GObjectClass *object_class,
- const DBusGObjectInfo *info)
+dbus_g_object_type_install_info (GType object_type,
+ const DBusGObjectInfo *info)
{
+ GObjectClass *object_class;
+
+ g_return_if_fail (G_TYPE_IS_OBJECT (object_type));
+
+ dbus_g_value_types_init ();
+
+ object_class = g_type_class_peek (object_type);
+
g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
- g_static_rw_lock_writer_lock (&info_hash_lock);
+ g_static_rw_lock_writer_lock (&globals_lock);
if (info_hash == NULL)
{
@@ -1045,7 +1271,7 @@ dbus_g_object_class_install_info (GObjectClass *object_class,
g_hash_table_replace (info_hash, object_class, (void*) info);
- g_static_rw_lock_writer_unlock (&info_hash_lock);
+ g_static_rw_lock_writer_unlock (&globals_lock);
}
static void
@@ -1087,12 +1313,175 @@ dbus_g_connection_register_g_object (DBusGConnection *connection,
return;
}
+ export_signals (connection, object);
+
g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
}
+GObject *
+dbus_g_connection_lookup_g_object (DBusGConnection *connection,
+ const char *at_path)
+{
+ gpointer ret;
+ if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
+ return NULL;
+ return ret;
+}
+
+typedef struct {
+ GType rettype;
+ guint n_params;
+ GType *params;
+} DBusGFuncSignature;
+
+static guint
+funcsig_hash (gconstpointer key)
+{
+ const DBusGFuncSignature *sig = key;
+ GType *types;
+ guint ret;
+
+ ret = sig->rettype;
+ types = sig->params;
+
+ while (*types != G_TYPE_INVALID)
+ {
+ ret += (int) (*types);
+ types++;
+ }
+
+ return ret;
+}
+
+static gboolean
+funcsig_equal (gconstpointer aval,
+ gconstpointer bval)
+{
+ const DBusGFuncSignature *a = aval;
+ const DBusGFuncSignature *b = bval;
+ const GType *atypes;
+ const GType *btypes;
+
+ if (a->rettype != b->rettype)
+ return FALSE;
+
+ atypes = a->params;
+ btypes = b->params;
+
+ while (*atypes != G_TYPE_INVALID)
+ {
+ if (*btypes != *atypes)
+ return FALSE;
+ atypes++;
+ btypes++;
+ }
+ if (*btypes != G_TYPE_INVALID)
+ return FALSE;
+
+ return TRUE;
+}
+
+GClosureMarshal
+_dbus_gobject_lookup_marshaller (GType rettype,
+ guint n_params,
+ const GType *param_types)
+{
+ GClosureMarshal ret;
+ DBusGFuncSignature sig;
+
+ sig.rettype = rettype;
+ sig.n_params = n_params;
+ sig.params = (GType*) param_types;
+
+ g_static_rw_lock_reader_lock (&globals_lock);
+
+ if (marshal_table)
+ ret = g_hash_table_lookup (marshal_table, &sig);
+ else
+ ret = NULL;
+
+ g_static_rw_lock_reader_unlock (&globals_lock);
+
+ if (ret == NULL)
+ {
+ if (rettype == G_TYPE_NONE)
+ {
+ if (n_params == 0)
+ ret = g_cclosure_marshal_VOID__VOID;
+ else if (n_params == 1)
+ {
+ switch (param_types[0])
+ {
+ case G_TYPE_BOOLEAN:
+ ret = g_cclosure_marshal_VOID__BOOLEAN;
+ case G_TYPE_UCHAR:
+ ret = g_cclosure_marshal_VOID__UCHAR;
+ case G_TYPE_INT:
+ ret = g_cclosure_marshal_VOID__INT;
+ case G_TYPE_UINT:
+ ret = g_cclosure_marshal_VOID__UINT;
+ case G_TYPE_DOUBLE:
+ ret = g_cclosure_marshal_VOID__DOUBLE;
+ case G_TYPE_STRING:
+ ret = g_cclosure_marshal_VOID__STRING;
+ }
+ }
+ }
+ else if (n_params == 3
+ && param_types[0] == G_TYPE_STRING
+ && param_types[1] == G_TYPE_STRING
+ && param_types[2] == G_TYPE_STRING)
+ {
+ ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Register a GClosureMarshal to be used for signal invocations.
+ * This function will not be needed once GLib includes libffi.
+ *
+ * @param rettype a GType for the return type of the function
+ * @param n_types number of function parameters
+ * @param param_types a C array of GTypes values
+ * @param marshaller a GClosureMarshal to be used for invocation
+ */
+void
+dbus_g_object_register_marshaller (GType rettype,
+ guint n_types,
+ const GType *param_types,
+ GClosureMarshal marshaller)
+{
+ DBusGFuncSignature *sig;
+
+ g_static_rw_lock_writer_lock (&globals_lock);
+
+ if (marshal_table == NULL)
+ marshal_table = g_hash_table_new_full (funcsig_hash,
+ funcsig_equal,
+ g_free,
+ NULL);
+ sig = g_new0 (DBusGFuncSignature, 1);
+ sig->rettype = rettype;
+ sig->n_params = n_types;
+ sig->params = g_new (GType, n_types);
+ memcpy (sig->params, param_types, n_types * sizeof (GType));
+
+ g_hash_table_insert (marshal_table, sig, marshaller);
+
+ g_static_rw_lock_writer_unlock (&globals_lock);
+}
+
/** @} */ /* end of public API */
+const char * _dbus_gobject_get_path (GObject *obj)
+{
+ return g_object_get_data (obj, "dbus_glib_object_path");
+}
+
#ifdef DBUS_BUILD_TESTS
#include <stdlib.h>
diff --git a/glib/dbus-gobject.h b/glib/dbus-gobject.h
index 6c78546a..fcc38cda 100644
--- a/glib/dbus-gobject.h
+++ b/glib/dbus-gobject.h
@@ -24,11 +24,19 @@
#define DBUS_GLIB_OBJECT_H
#include <dbus/dbus.h>
+#include <dbus/dbus-signature.h>
#include <glib.h>
+#include "dbus/dbus-glib.h"
G_BEGIN_DECLS
-GValueArray* _dbus_glib_marshal_dbus_message_to_gvalue_array (DBusMessage *message);
+const char * _dbus_gobject_get_path (GObject *obj);
+
+GClosureMarshal _dbus_gobject_lookup_marshaller (GType rettype,
+ guint n_params,
+ const GType *param_types);
+
+
G_END_DECLS
diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c
index b5e977a4..42bfca8e 100644
--- a/glib/dbus-gproxy.c
+++ b/glib/dbus-gproxy.c
@@ -24,8 +24,8 @@
#include <dbus/dbus-glib-lowlevel.h>
#include <dbus/dbus-signature.h>
#include "dbus-gutils.h"
-#include "dbus-gmarshal.h"
#include "dbus-gvalue.h"
+#include "dbus-gvalue-utils.h"
#include "dbus-gobject.h"
#include <string.h>
#include <glib/gi18n.h>
@@ -737,7 +737,7 @@ dbus_g_proxy_class_init (DBusGProxyClass *klass)
0,
NULL, NULL,
marshal_dbus_message_to_g_marshaller,
- G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_STRING);
+ G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
}
static void
@@ -816,80 +816,6 @@ create_signal_name (const char *interface,
return g_string_free (str, FALSE);
}
-static GSignalCMarshaller
-lookup_g_marshaller (DBusGProxy *proxy,
- const char *signature)
-{
- /* The "proxy" arg would eventually be used if you could provide
- * a marshaller when adding a signal to the proxy
- */
-
-#define MATCH1(sig, t0) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == '\0')
-#define MATCH2(sig, t0, t1) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == (DBUS_TYPE_##t1) && (sig)[2] == '\0')
-#define MATCH3(sig, t0, t1, t2) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == (DBUS_TYPE_##t1) && (sig)[2] == (DBUS_TYPE_##t2) && (sig)[3] == '\0')
-
- switch (*signature)
- {
- case '\0':
- return g_cclosure_marshal_VOID__VOID;
-
- case DBUS_TYPE_BOOLEAN:
- if (MATCH1 (signature, BOOLEAN))
- return g_cclosure_marshal_VOID__BOOLEAN;
- break;
-
- case DBUS_TYPE_BYTE:
- if (MATCH1 (signature, BYTE))
- return g_cclosure_marshal_VOID__UCHAR;
- break;
-
- case DBUS_TYPE_INT16:
- if (MATCH1 (signature, INT16))
- return g_cclosure_marshal_VOID__INT;
- break;
-
- case DBUS_TYPE_UINT16:
- if (MATCH1 (signature, UINT16))
- return g_cclosure_marshal_VOID__UINT;
- break;
-
- case DBUS_TYPE_INT32:
- if (MATCH1 (signature, INT32))
- return g_cclosure_marshal_VOID__INT;
- break;
-
- case DBUS_TYPE_UINT32:
- if (MATCH1 (signature, UINT32))
- return g_cclosure_marshal_VOID__UINT;
- break;
-
- case DBUS_TYPE_DOUBLE:
- if (MATCH1 (signature, DOUBLE))
- return g_cclosure_marshal_VOID__DOUBLE;
- break;
-
- case DBUS_TYPE_OBJECT_PATH:
- if (MATCH1 (signature, OBJECT_PATH))
- return g_cclosure_marshal_VOID__STRING;
- break;
-
- case DBUS_TYPE_SIGNATURE:
- if (MATCH1 (signature, SIGNATURE))
- return g_cclosure_marshal_VOID__STRING;
- break;
-
- case DBUS_TYPE_STRING:
- if (MATCH1 (signature, STRING))
- return g_cclosure_marshal_VOID__STRING;
- /* This is for NameOwnerChanged */
- else if (MATCH3 (signature, STRING, STRING, STRING))
- return _dbus_g_marshal_NONE__STRING_STRING_STRING;
- break;
- }
-
- return NULL;
-}
-
static void
marshal_dbus_message_to_g_marshaller (GClosure *closure,
GValue *return_value,
@@ -909,25 +835,36 @@ marshal_dbus_message_to_g_marshaller (GClosure *closure,
GSignalCMarshaller c_marshaller;
DBusGProxy *proxy;
DBusMessage *message;
- const char *signature;
+ GArray *gsignature;
+ const GType *types;
g_assert (n_param_values == 3);
proxy = g_value_get_object (&param_values[0]);
message = g_value_get_boxed (&param_values[1]);
- signature = g_value_get_string (&param_values[2]);
+ gsignature = g_value_get_pointer (&param_values[2]);
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (message != NULL);
- g_return_if_fail (signature != NULL);
-
- c_marshaller = lookup_g_marshaller (proxy, signature);
+ g_return_if_fail (gsignature != NULL);
+
+ c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
+ (GType*) gsignature->data);
g_return_if_fail (c_marshaller != NULL);
- value_array = _dbus_glib_marshal_dbus_message_to_gvalue_array (message);
+ {
+ DBusGValueMarshalCtx context;
+ context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
+ context.proxy = proxy;
- g_return_if_fail (value_array != NULL);
+ types = (const GType*) gsignature->data;
+ value_array = dbus_gvalue_demarshal_message (&context, message,
+ gsignature->len, types, NULL);
+ }
+
+ if (value_array == NULL)
+ return;
g_value_init (&value, G_TYPE_FROM_INSTANCE (proxy));
g_value_set_instance (&value, proxy);
@@ -966,37 +903,40 @@ dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
if (q != 0)
{
- const char *signature;
-
- signature = g_datalist_id_get_data (&proxy->signal_signatures, q);
- if (signature == NULL)
- {
-#if 0
- /* this should not trigger a warning, as you shouldn't have to
- * add signals you don't care about
- */
- g_warning ("Signal '%s' has not been added to this proxy object\n",
- name);
-#endif
- }
- else if (!dbus_message_has_signature (message, signature))
- {
- g_warning ("Signature '%s' expected for signal '%s', actual signature '%s'\n",
- signature,
- name,
- dbus_message_get_signature (message));
- }
- else
- {
- g_signal_emit (proxy,
- signals[RECEIVED],
- q,
- message,
- signature);
- }
+ GArray *gsignature;
+ GArray *msg_gsignature;
+ guint i;
+
+ gsignature = g_datalist_id_get_data (&proxy->signal_signatures, q);
+ if (gsignature == NULL)
+ goto out;
+
+ msg_gsignature = dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
+ TRUE);
+ for (i = 0; i < gsignature->len; i++)
+ {
+ if (msg_gsignature->len == i
+ || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
+ goto mismatch;
+ }
+ if (msg_gsignature->len != i)
+ goto mismatch;
+
+ g_signal_emit (proxy,
+ signals[RECEIVED],
+ q,
+ message,
+ msg_gsignature);
}
+ out:
g_free (name);
+ return;
+ mismatch:
+ g_warning ("Unexpected message signature '%s' for signal '%s'\n",
+ dbus_message_get_signature (message),
+ name);
+ goto out;
}
/** @} End of DBusGLibInternals */
@@ -1204,6 +1144,33 @@ dbus_g_proxy_new_for_name_owner (DBusGConnection *connection,
}
/**
+ * Creates a proxy using an existing proxy as a template, substituting
+ * the specified interface and path. Either or both may be NULL.
+ *
+ * @param proxy the proxy to use as a template
+ * @param path of the object inside the peer to call methods on
+ * @param interface name of the interface to call methods on
+ * @returns new proxy object
+ *
+ */
+DBusGProxy*
+dbus_g_proxy_new_from_proxy (DBusGProxy *proxy,
+ const char *interface,
+ const char *path)
+{
+ g_return_val_if_fail (proxy != NULL, NULL);
+
+ if (interface == NULL)
+ interface = proxy->interface;
+ if (path == NULL)
+ path = proxy->path;
+
+ return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection),
+ proxy->name,
+ path, interface);
+}
+
+/**
* Creates a proxy for an object in peer application (one
* we're directly connected to). That is, this function is
* intended for use when there's no message bus involved,
@@ -1255,199 +1222,63 @@ dbus_g_proxy_get_bus_name (DBusGProxy *proxy)
}
/**
- * Invokes a method on a remote interface. This function does not
- * block; instead it returns an opaque #DBusPendingCall object that
- * tracks the pending call. The method call will not be sent over the
- * wire until the application returns to the main loop, or blocks in
- * dbus_connection_flush() to write out pending data. The call will
- * be completed after a timeout, or when a reply is received.
- * To collect the results of the call (which may be an error,
- * or a reply), use dbus_g_proxy_end_call().
- *
- * @todo this particular function shouldn't die on out of memory,
- * since you should be able to do a call with large arguments.
- *
- * @param proxy a proxy for a remote interface
- * @param method the name of the method to invoke
- * @param first_arg_type type of the first argument
+ * Gets the object interface proxy is bound to (may be #NULL in some cases).
*
- * @returns opaque pending call object
- * */
-DBusGPendingCall*
-dbus_g_proxy_begin_call (DBusGProxy *proxy,
- const char *method,
- int first_arg_type,
- ...)
+ * @param proxy the proxy
+ * @returns an object interface
+ */
+const char*
+dbus_g_proxy_get_interface (DBusGProxy *proxy)
{
- DBusPendingCall *pending;
- DBusMessage *message;
- va_list args;
-
g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
- message = dbus_message_new_method_call (proxy->name,
- proxy->path,
- proxy->interface,
- method);
- if (message == NULL)
- goto oom;
-
- va_start (args, first_arg_type);
- if (!dbus_message_append_args_valist (message, first_arg_type,
- args))
- goto oom;
- va_end (args);
-
- if (!dbus_connection_send_with_reply (proxy->manager->connection,
- message,
- &pending,
- -1))
- goto oom;
-
- return DBUS_G_PENDING_CALL_FROM_PENDING_CALL (pending);
-
- oom:
- /* FIXME we should create a pending call that's
- * immediately completed with an error status without
- * ever going on the wire.
- */
-
- g_error ("Out of memory");
- return NULL;
+ return proxy->interface;
}
/**
- * Collects the results of a method call. The method call was normally
- * initiated with dbus_g_proxy_end_call(). This function will block if
- * the results haven't yet been received; use
- * dbus_g_pending_call_set_notify() to be notified asynchronously that a
- * pending call has been completed. If it's completed, it will not block.
- *
- * If the call results in an error, the error is set as normal for
- * GError and the function returns #FALSE.
- *
- * Otherwise, the "out" parameters and return value of the
- * method are stored in the provided varargs list.
- * The list should be terminated with #DBUS_TYPE_INVALID.
+ * Sets the object interface proxy is bound to
*
- * This function doesn't affect the reference count of the
- * #DBusGPendingCall, the caller of dbus_g_proxy_begin_call() still owns
- * a reference.
- *
- * @todo this should be changed to make a g_malloc() copy of the
- * data returned probably; right now the data vanishes
- * when you free the PendingCall which is sort of strange.
- *
- * @param proxy a proxy for a remote interface
- * @param pending the pending call from dbus_g_proxy_begin_call()
- * @param error return location for an error
- * @param first_arg_type type of first "out" argument
- * @returns #FALSE if an error is set
+ * @param proxy the proxy
+ * @param interface_name an object interface
*/
-gboolean
-dbus_g_proxy_end_call (DBusGProxy *proxy,
- DBusGPendingCall *pending,
- GError **error,
- int first_arg_type,
- ...)
+void
+dbus_g_proxy_set_interface (DBusGProxy *proxy,
+ const char *interface_name)
{
- DBusMessage *message;
- va_list args;
- DBusError derror;
-
- g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
- g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
- g_return_val_if_fail (pending != NULL, FALSE);
-
- dbus_pending_call_block (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
- message = dbus_pending_call_steal_reply (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
-
- g_assert (message != NULL);
-
- dbus_error_init (&derror);
-
- switch (dbus_message_get_type (message))
- {
- case DBUS_MESSAGE_TYPE_METHOD_RETURN:
- va_start (args, first_arg_type);
- if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args))
- {
- va_end (args);
- goto error;
- }
- va_end (args);
-
- dbus_message_unref (message);
- return TRUE;
-
- case DBUS_MESSAGE_TYPE_ERROR:
- dbus_set_error_from_message (&derror, message);
- goto error;
-
- default:
- dbus_set_error (&derror, DBUS_ERROR_FAILED,
- "Reply was neither a method return nor an exception");
- goto error;
- }
-
- error:
- dbus_message_unref (message);
-
- dbus_set_g_error (error, &derror);
- dbus_error_free (&derror);
- return FALSE;
+ /* FIXME - need to unregister when we switch interface for now
+ * later should support idea of unset interface
+ */
+ dbus_g_proxy_manager_unregister (proxy->manager, proxy);
+ g_free (proxy->interface);
+ proxy->interface = g_strdup (interface_name);
+ dbus_g_proxy_manager_register (proxy->manager, proxy);
}
/**
- * Function for invoking a method and receiving reply values.
- * Normally this is not used directly - calls to it are generated
- * from client-side wrappers (see dbus-binding-tool).
+ * Gets the path this proxy is bound to
*
- * This function takes two type signatures, one for method arguments,
- * and one for return values. The remaining arguments after the
- * error parameter should be values of the input arguments,
- * followed by pointer values to storage for return values.
- *
- * @param proxy a proxy for a remote interface
- * @param method method to invoke
- * @param insig signature of input values
- * @param outsig signature of output values
- * @param error return location for an error
- * @returns #FALSE if an error is set, TRUE otherwise
+ * @param proxy the proxy
+ * @returns an object path
*/
-gboolean
-dbus_g_proxy_invoke (DBusGProxy *proxy,
- const char *method,
- const char *insig,
- const char *outsig,
- GError **error,
- ...)
+const char*
+dbus_g_proxy_get_path (DBusGProxy *proxy)
+{
+ g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
+ g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
+
+ return proxy->path;
+}
+
+static DBusMessage *
+dbus_g_proxy_marshal_args_to_message (DBusGProxy *proxy,
+ const char *method,
+ GValueArray *args)
{
- DBusPendingCall *pending;
DBusMessage *message;
- DBusMessage *reply;
- va_list args;
- va_list args_unwind;
- int n_retvals_processed;
DBusMessageIter msgiter;
- DBusSignatureIter sigiter;
- int expected_type;
- gboolean ret;
- DBusError derror;
-
- g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
- g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
-
- va_start (args, error);
- /* Keep around a copy of output arguments so we
- * can free on error. */
- G_VA_COPY (args_unwind, args);
+ guint i;
- ret = FALSE;
- pending = NULL;
- reply = NULL;
- n_retvals_processed = 0;
message = dbus_message_new_method_call (proxy->name,
proxy->path,
proxy->interface,
@@ -1455,47 +1286,91 @@ dbus_g_proxy_invoke (DBusGProxy *proxy,
if (message == NULL)
goto oom;
- dbus_signature_iter_init (&sigiter, insig);
dbus_message_iter_init_append (message, &msgiter);
- while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+ for (i = 0; i < args->n_values; i++)
{
- GValue gvalue = {0, };
- char *collect_err;
+ GValue *gvalue;
- if (!dbus_gvalue_init (expected_type, &gvalue))
- {
- g_set_error (error, DBUS_GERROR,
- DBUS_GERROR_INVALID_ARGS,
- _("Unsupported type '%c'"), expected_type);
- goto out;
- }
-
- G_VALUE_COLLECT (&gvalue, args, G_VALUE_NOCOPY_CONTENTS, &collect_err);
+ gvalue = g_value_array_get_nth (args, i);
- if (collect_err)
- {
- g_set_error (error, DBUS_GERROR,
- DBUS_GERROR_INVALID_ARGS,
- collect_err);
- goto out;
- }
-
- /* Anything we can init must be marshallable */
- if (!dbus_gvalue_marshal (&msgiter, &gvalue))
+ if (!dbus_gvalue_marshal (&msgiter, gvalue))
g_assert_not_reached ();
- g_value_unset (&gvalue);
-
- dbus_signature_iter_next (&sigiter);
}
+ return message;
+ oom:
+ return NULL;
+}
+
+#define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
+do { \
+ GType valtype; \
+ int i = 0; \
+ VALARRAY = g_value_array_new (6); \
+ valtype = FIRST_ARG_TYPE; \
+ while (valtype != G_TYPE_INVALID) \
+ { \
+ const char *collect_err; \
+ GValue *val; \
+ g_value_array_append (VALARRAY, NULL); \
+ val = g_value_array_get_nth (VALARRAY, i); \
+ g_value_init (val, valtype); \
+ collect_err = NULL; \
+ G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
+ valtype = va_arg (ARGS, GType); \
+ i++; \
+ } \
+} while (0)
+
+static DBusGPendingCall *
+dbus_g_proxy_begin_call_internal (DBusGProxy *proxy,
+ const char *method,
+ GValueArray *args)
+{
+ DBusMessage *message;
+ DBusPendingCall *pending;
+
+ g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
+ g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
+
+ pending = NULL;
+ message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
+ if (!message)
+ goto oom;
+
if (!dbus_connection_send_with_reply (proxy->manager->connection,
message,
&pending,
-1))
goto oom;
+ g_assert (pending != NULL);
- dbus_pending_call_block (pending);
- reply = dbus_pending_call_steal_reply (pending);
+ return DBUS_G_PENDING_CALL_FROM_PENDING_CALL (pending);
+ oom:
+ g_error ("Out of memory");
+ return NULL;
+}
+
+static gboolean
+dbus_g_proxy_end_call_internal (DBusGProxy *proxy,
+ DBusGPendingCall *pending,
+ GError **error,
+ GType first_arg_type,
+ va_list args)
+{
+ DBusMessage *reply;
+ DBusMessageIter msgiter;
+ DBusError derror;
+ va_list args_unwind;
+ int n_retvals_processed;
+ gboolean ret;
+ GType valtype;
+
+ reply = NULL;
+ ret = FALSE;
+ n_retvals_processed = 0;
+ dbus_pending_call_block (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
+ reply = dbus_pending_call_steal_reply (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
g_assert (reply != NULL);
@@ -1505,53 +1380,86 @@ dbus_g_proxy_invoke (DBusGProxy *proxy,
{
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
- dbus_signature_iter_init (&sigiter, outsig);
dbus_message_iter_init (reply, &msgiter);
- while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+ valtype = first_arg_type;
+ while (valtype != G_TYPE_INVALID)
{
int arg_type;
- gpointer *value_ret;
+ gpointer return_storage;
GValue gvalue = { 0, };
+ DBusGValueMarshalCtx context;
+
+ context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
+ context.proxy = proxy;
- value_ret = va_arg (args, gpointer *);
arg_type = dbus_message_iter_get_arg_type (&msgiter);
- if (expected_type != arg_type)
+ if (arg_type == DBUS_TYPE_INVALID)
+ g_set_error (error, DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Too few arguments in reply"));
+
+ return_storage = va_arg (args, gpointer);
+ if (return_storage == NULL)
+ goto next;
+
+ /* We handle variants specially; the caller is expected
+ * to have already allocated storage for them.
+ */
+ if (arg_type == DBUS_TYPE_VARIANT
+ && g_type_is_a (valtype, G_TYPE_VALUE))
{
- if (arg_type == DBUS_TYPE_INVALID)
- g_set_error (error, DBUS_GERROR,
- DBUS_GERROR_INVALID_ARGS,
- _("Too few arguments in reply"));
- else
- g_set_error (error, DBUS_GERROR,
+ if (!dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
+ {
+ g_set_error (error,
+ DBUS_GERROR,
DBUS_GERROR_INVALID_ARGS,
- _("Reply argument was \"%c\", expected \"%c\""),
- arg_type, expected_type);
- goto out;
+ _("Couldn't convert argument, expected \"%s\""),
+ g_type_name (valtype));
+ goto out;
+ }
}
-
- if (!dbus_gvalue_demarshal (&msgiter, &gvalue))
+ else
{
- g_set_error (error,
- DBUS_GERROR,
- DBUS_GERROR_INVALID_ARGS,
- _("Couldn't convert argument type \"%c\""), expected_type);
- goto out;
+ g_value_init (&gvalue, valtype);
+
+ /* FIXME, should use error here instead of NULL */
+ if (!dbus_gvalue_demarshal (&context, &msgiter, &gvalue, NULL))
+ {
+ g_set_error (error,
+ DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Couldn't convert argument, expected \"%s\""),
+ g_type_name (valtype));
+ goto out;
+ }
+
+ if (G_VALUE_TYPE (&gvalue) != valtype)
+ {
+ g_set_error (error, DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Reply argument was \"%s\", expected \"%s\""),
+ g_type_name (G_VALUE_TYPE (&gvalue)),
+ g_type_name (valtype));
+ goto out;
+ }
+
+ /* Anything that can be demarshaled must be storable */
+ if (!dbus_gvalue_store (&gvalue, (gpointer*) return_storage))
+ g_assert_not_reached ();
+ /* Ownership of the value passes to the client, don't unset */
}
- /* Anything that can be demarshaled must be storable */
- if (!dbus_gvalue_store (&gvalue, value_ret))
- g_assert_not_reached ();
- g_value_unset (&gvalue);
+ next:
n_retvals_processed++;
- dbus_signature_iter_next (&sigiter);
dbus_message_iter_next (&msgiter);
+ valtype = va_arg (args, GType);
}
if (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
{
g_set_error (error, DBUS_GERROR,
DBUS_GERROR_INVALID_ARGS,
- _("Too many arguments"));
+ _("Too many arguments in reply"));
goto out;
}
break;
@@ -1589,16 +1497,132 @@ dbus_g_proxy_invoke (DBusGProxy *proxy,
va_end (args_unwind);
if (pending)
- dbus_pending_call_unref (pending);
- if (message)
- dbus_message_unref (message);
+ dbus_g_pending_call_unref (pending);
if (reply)
dbus_message_unref (reply);
return ret;
- oom:
- g_error ("Out of memory");
- ret = FALSE;
- goto out;
+}
+
+
+/**
+ * Invokes a method on a remote interface. This function does not
+ * block; instead it returns an opaque #DBusPendingCall object that
+ * tracks the pending call. The method call will not be sent over the
+ * wire until the application returns to the main loop, or blocks in
+ * dbus_connection_flush() to write out pending data. The call will
+ * be completed after a timeout, or when a reply is received.
+ * To collect the results of the call (which may be an error,
+ * or a reply), use dbus_g_proxy_end_call().
+ *
+ * @todo this particular function shouldn't die on out of memory,
+ * since you should be able to do a call with large arguments.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param method the name of the method to invoke
+ * @param first_arg_type type of the first argument
+ *
+ * @returns opaque pending call object
+ * */
+DBusGPendingCall*
+dbus_g_proxy_begin_call (DBusGProxy *proxy,
+ const char *method,
+ GType first_arg_type,
+ ...)
+{
+ DBusGPendingCall *pending;
+ va_list args;
+ GValueArray *arg_values;
+
+ va_start (args, first_arg_type);
+
+ DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
+
+ pending = dbus_g_proxy_begin_call_internal (proxy, method, arg_values);
+
+ g_value_array_free (arg_values);
+
+ va_end (args);
+
+ return pending;
+}
+
+/**
+ * Collects the results of a method call. The method call was normally
+ * initiated with dbus_g_proxy_end_call(). This function will block if
+ * the results haven't yet been received; use
+ * dbus_g_pending_call_set_notify() to be notified asynchronously that a
+ * pending call has been completed. If it's completed, it will not block.
+ *
+ * If the call results in an error, the error is set as normal for
+ * GError and the function returns #FALSE.
+ *
+ * Otherwise, the "out" parameters and return value of the
+ * method are stored in the provided varargs list.
+ * The list should be terminated with G_TYPE_INVALID.
+ *
+ * This function unrefs the pending call.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param pending the pending call from dbus_g_proxy_begin_call()
+ * @param error return location for an error
+ * @param first_arg_type type of first "out" argument
+ * @returns #FALSE if an error is set
+ */
+gboolean
+dbus_g_proxy_end_call (DBusGProxy *proxy,
+ DBusGPendingCall *pending,
+ GError **error,
+ GType first_arg_type,
+ ...)
+{
+ gboolean ret;
+ va_list args;
+
+ va_start (args, first_arg_type);
+
+ ret = dbus_g_proxy_end_call_internal (proxy, pending, error, first_arg_type, args);
+
+ va_end (args);
+
+ return ret;
+}
+
+/**
+ * Function for invoking a method and receiving reply values.
+ * Normally this is not used directly - calls to it are generated
+ * from client-side wrappers (see dbus-binding-tool).
+ *
+ * @param proxy a proxy for a remote interface
+ * @param method method to invoke
+ * @param error return location for an error
+ * @returns #FALSE if an error is set, TRUE otherwise
+ */
+gboolean
+dbus_g_proxy_invoke (DBusGProxy *proxy,
+ const char *method,
+ GError **error,
+ GType first_arg_type,
+ ...)
+{
+ gboolean ret;
+ DBusGPendingCall *pending;
+ va_list args;
+ GValueArray *in_args;
+
+ va_start (args, first_arg_type);
+
+ DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
+
+ pending = dbus_g_proxy_begin_call_internal (proxy, method, in_args);
+
+ g_value_array_free (in_args);
+
+ first_arg_type = va_arg (args, GType);
+ ret = dbus_g_proxy_end_call_internal (proxy, pending, error, first_arg_type, args);
+
+ va_end (args);
+
+ return ret;
}
/**
@@ -1614,30 +1638,29 @@ dbus_g_proxy_invoke (DBusGProxy *proxy,
*/
void
dbus_g_proxy_call_no_reply (DBusGProxy *proxy,
- const char *method,
- int first_arg_type,
- ...)
+ const char *method,
+ GType first_arg_type,
+ ...)
{
DBusMessage *message;
va_list args;
+ GValueArray *in_args;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
- message = dbus_message_new_method_call (proxy->name,
- proxy->path,
- proxy->interface,
- method);
- if (message == NULL)
+ va_start (args, first_arg_type);
+ DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
+
+ message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
+
+ g_value_array_free (in_args);
+ va_end (args);
+
+ if (!message)
goto oom;
dbus_message_set_no_reply (message, TRUE);
-
- va_start (args, first_arg_type);
- if (!dbus_message_append_args_valist (message, first_arg_type,
- args))
- goto oom;
- va_end (args);
if (!dbus_connection_send (proxy->manager->connection,
message,
@@ -1696,41 +1719,63 @@ dbus_g_proxy_send (DBusGProxy *proxy,
g_error ("Out of memory\n");
}
+static void
+array_free_all (gpointer array)
+{
+ g_array_free (array, TRUE);
+}
+
/**
- * Specifies the signature of a signal, such that it's possible to
- * connect to the signal on this proxy.
+ * Specifies the argument signature of a signal;.only necessary
+ * if the remote object does not support introspection. The arguments
+ * specified are the GLib types expected.
*
* @param proxy the proxy for a remote interface
* @param signal_name the name of the signal
- * @param signature D-BUS signature of the signal
+ * @param first_type the first argument type, or G_TYPE_INVALID if none
*/
void
dbus_g_proxy_add_signal (DBusGProxy *proxy,
const char *signal_name,
- const char *signature)
+ GType first_type,
+ ...)
{
GQuark q;
char *name;
+ GArray *gtypesig;
+ GType gtype;
+ va_list args;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
g_return_if_fail (signal_name != NULL);
- g_return_if_fail (signature != NULL);
-#ifndef G_DISABLE_CHECKS
- if (lookup_g_marshaller (proxy, signature) == NULL)
- g_warning ("No marshaller for signature '%s', we need to add API for providing your own",
- signature);
-#endif
name = create_signal_name (proxy->interface, signal_name);
q = g_quark_from_string (name);
g_return_if_fail (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL);
+
+ gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
+
+ va_start (args, first_type);
+ gtype = first_type;
+ while (gtype != G_TYPE_INVALID)
+ {
+ g_array_append_val (gtypesig, gtype);
+ gtype = va_arg (args, GType);
+ }
+ va_end (args);
+
+#ifndef G_DISABLE_CHECKS
+ if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
+ g_warning ("No marshaller for signature of signal '%s'", signal_name);
+#endif
+
g_datalist_id_set_data_full (&proxy->signal_signatures,
- q, g_strdup (signature),
- g_free);
+ q, gtypesig,
+ array_free_all);
g_free (name);
}
diff --git a/glib/dbus-gtype-specialized.c b/glib/dbus-gtype-specialized.c
new file mode 100644
index 00000000..b331fcc5
--- /dev/null
+++ b/glib/dbus-gtype-specialized.c
@@ -0,0 +1,441 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gtype-specialized.c: Non-DBus-specific functions for specialized GTypes
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "dbus-gtype-specialized.h"
+#include <glib.h>
+#include <string.h>
+#include <gobject/gvaluecollector.h>
+
+typedef enum {
+ DBUS_G_SPECTYPE_COLLECTION,
+ DBUS_G_SPECTYPE_MAP
+} DBusGTypeSpecializedType;
+
+typedef struct {
+ DBusGTypeSpecializedType type;
+ const DBusGTypeSpecializedVtable *vtable;
+} DBusGTypeSpecializedContainer;
+
+typedef struct {
+ GType types[6];
+ const DBusGTypeSpecializedContainer *klass;
+} DBusGTypeSpecializedData;
+
+static GHashTable /* char * -> data* */ *specialized_containers;
+
+static GQuark
+specialized_type_data_quark ()
+{
+ static GQuark quark;
+ if (!quark)
+ quark = g_quark_from_static_string ("DBusGTypeSpecializedData");
+
+ return quark;
+}
+
+void
+dbus_g_type_specialized_init (void)
+{
+ specialized_containers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+}
+
+static gboolean
+specialized_types_is_initialized (void)
+{
+ return specialized_containers != NULL;
+}
+
+static DBusGTypeSpecializedData *
+lookup_specialization_data (GType type)
+{
+ return g_type_get_qdata (type, specialized_type_data_quark ());
+}
+
+/* Copied from gboxed.c */
+static void
+proxy_value_init (GValue *value)
+{
+ value->data[0].v_pointer = NULL;
+}
+
+/* Adapted from gboxed.c */
+static void
+proxy_value_free (GValue *value)
+{
+ if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
+ {
+ DBusGTypeSpecializedData *data;
+ GType type;
+
+ type = G_VALUE_TYPE (value);
+ data = lookup_specialization_data (type);
+ g_assert (data != NULL);
+
+ data->klass->vtable->free_func (type, value->data[0].v_pointer);
+ }
+}
+
+/* Adapted from gboxed.c */
+static void
+proxy_value_copy (const GValue *src_value,
+ GValue *dest_value)
+{
+ if (src_value->data[0].v_pointer)
+ {
+ DBusGTypeSpecializedData *data;
+ GType type;
+ type = G_VALUE_TYPE (src_value);
+ data = lookup_specialization_data (type);
+ g_assert (data != NULL);
+ dest_value->data[0].v_pointer = data->klass->vtable->copy_func (type, src_value->data[0].v_pointer);
+ }
+ else
+ dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
+}
+
+/* Copied from gboxed.c */
+static gpointer
+proxy_value_peek_pointer (const GValue *value)
+{
+ return value->data[0].v_pointer;
+}
+
+/* Adapted from gboxed.c */
+static gchar*
+proxy_collect_value (GValue *value,
+ guint n_collect_values,
+ GTypeCValue *collect_values,
+ guint collect_flags)
+{
+ DBusGTypeSpecializedData *data;
+ GType type;
+
+ type = G_VALUE_TYPE (value);
+ data = lookup_specialization_data (type);
+
+ if (!collect_values[0].v_pointer)
+ value->data[0].v_pointer = NULL;
+ else
+ {
+ if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
+ {
+ value->data[0].v_pointer = collect_values[0].v_pointer;
+ value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
+ }
+ else
+ value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer);
+ }
+
+ return NULL;
+}
+
+/* Adapted from gboxed.c */
+static gchar*
+proxy_lcopy_value (const GValue *value,
+ guint n_collect_values,
+ GTypeCValue *collect_values,
+ guint collect_flags)
+{
+ gpointer *boxed_p = collect_values[0].v_pointer;
+
+ if (!boxed_p)
+ return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
+
+ if (!value->data[0].v_pointer)
+ *boxed_p = NULL;
+ else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
+ *boxed_p = value->data[0].v_pointer;
+ else
+ {
+ DBusGTypeSpecializedData *data;
+ GType type;
+
+ type = G_VALUE_TYPE (value);
+ data = lookup_specialization_data (type);
+
+ *boxed_p = data->klass->vtable->copy_func (type, value->data[0].v_pointer);
+ }
+
+ return NULL;
+}
+
+static char *
+build_specialization_name (const char *prefix, GType first_type, GType second_type)
+{
+ GString *fullname;
+
+ fullname = g_string_new (prefix);
+ g_string_append_c (fullname, '+');
+ g_string_append (fullname, g_type_name (first_type));
+ if (second_type != G_TYPE_INVALID)
+ {
+ g_string_append_c (fullname, '+');
+ g_string_append (fullname, g_type_name (second_type));
+ }
+ return g_string_free (fullname, FALSE);
+}
+
+static void
+register_container (const char *name,
+ DBusGTypeSpecializedType type,
+ const DBusGTypeSpecializedVtable *vtable)
+{
+ DBusGTypeSpecializedContainer *klass;
+
+ klass = g_new0 (DBusGTypeSpecializedContainer, 1);
+ klass->type = type;
+ klass->vtable = vtable;
+
+ g_hash_table_insert (specialized_containers, g_strdup (name), klass);
+}
+
+void
+dbus_g_type_register_collection (const char *name,
+ const DBusGTypeSpecializedCollectionVtable *vtable,
+ guint flags)
+{
+ g_return_if_fail (specialized_types_is_initialized ());
+ register_container (name, DBUS_G_SPECTYPE_COLLECTION, (const DBusGTypeSpecializedVtable*) vtable);
+}
+
+void
+dbus_g_type_register_map (const char *name,
+ const DBusGTypeSpecializedMapVtable *vtable,
+ guint flags)
+{
+ g_return_if_fail (specialized_types_is_initialized ());
+ register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable);
+}
+
+static GType
+register_specialized_instance (const DBusGTypeSpecializedContainer *klass,
+ char *name,
+ GType first_type,
+ GType second_type)
+{
+ GType ret;
+
+ static const GTypeValueTable vtable =
+ {
+ proxy_value_init,
+ proxy_value_free,
+ proxy_value_copy,
+ proxy_value_peek_pointer,
+ "p",
+ proxy_collect_value,
+ "p",
+ proxy_lcopy_value,
+ };
+ static const GTypeInfo derived_info =
+ {
+ 0, /* class_size */
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ NULL, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0, /* instance_size */
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ &vtable, /* value_table */
+ };
+
+ ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0);
+ /* install proxy functions upon successfull registration */
+ if (ret != G_TYPE_INVALID)
+ {
+ DBusGTypeSpecializedData *data;
+ data = g_new0 (DBusGTypeSpecializedData, 1);
+ data->types[0] = first_type;
+ data->types[1] = second_type;
+ data->klass = klass;
+ g_type_set_qdata (ret, specialized_type_data_quark (), data);
+ }
+
+ return ret;
+}
+
+static GType
+lookup_or_register_specialized (const char *container,
+ GType first_type,
+ GType second_type)
+{
+ GType ret;
+ char *name;
+ const DBusGTypeSpecializedContainer *klass;
+
+ g_return_val_if_fail (specialized_types_is_initialized (), G_TYPE_INVALID);
+
+ klass = g_hash_table_lookup (specialized_containers, container);
+ g_return_val_if_fail (klass != NULL, G_TYPE_INVALID);
+
+ name = build_specialization_name (container, first_type, second_type);
+ ret = g_type_from_name (name);
+ if (ret == G_TYPE_INVALID)
+ {
+ /* Take ownership of name */
+ ret = register_specialized_instance (klass, name,
+ first_type,
+ second_type);
+ }
+ else
+ g_free (name);
+ return ret;
+}
+
+GType
+dbus_g_type_get_collection (const char *container,
+ GType specialization)
+{
+ return lookup_or_register_specialized (container, specialization, G_TYPE_INVALID);
+}
+
+GType
+dbus_g_type_get_map (const char *container,
+ GType key_specialization,
+ GType value_specialization)
+{
+ return lookup_or_register_specialized (container, key_specialization, value_specialization);
+}
+
+gboolean
+dbus_g_type_is_collection (GType gtype)
+{
+ DBusGTypeSpecializedData *data;
+ data = lookup_specialization_data (gtype);
+ if (data == NULL)
+ return FALSE;
+ return data->klass->type == DBUS_G_SPECTYPE_COLLECTION;
+}
+
+gboolean
+dbus_g_type_is_map (GType gtype)
+{
+ DBusGTypeSpecializedData *data;
+ data = lookup_specialization_data (gtype);
+ if (data == NULL)
+ return FALSE;
+ return data->klass->type == DBUS_G_SPECTYPE_MAP;
+}
+
+static GType
+get_specialization_index (GType gtype, guint i)
+{
+ DBusGTypeSpecializedData *data;
+
+ data = lookup_specialization_data (gtype);
+ return data->types[i];
+}
+
+GType
+dbus_g_type_get_collection_specialization (GType gtype)
+{
+ g_return_val_if_fail (dbus_g_type_is_collection (gtype), G_TYPE_INVALID);
+ return get_specialization_index (gtype, 0);
+}
+
+GType
+dbus_g_type_get_map_key_specialization (GType gtype)
+{
+ g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
+ return get_specialization_index (gtype, 0);
+}
+
+GType
+dbus_g_type_get_map_value_specialization (GType gtype)
+{
+ g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
+ return get_specialization_index (gtype, 1);
+}
+
+gpointer
+dbus_g_type_specialized_construct (GType type)
+{
+ DBusGTypeSpecializedData *data;
+ g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
+
+ data = lookup_specialization_data (type);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ return data->klass->vtable->constructor (type);
+}
+
+gboolean
+dbus_g_type_collection_get_fixed (GValue *value,
+ gpointer *data_ret,
+ guint *len_ret)
+{
+ DBusGTypeSpecializedData *data;
+ GType gtype;
+
+ g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
+ g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
+
+ gtype = G_VALUE_TYPE (value);
+ data = lookup_specialization_data (gtype);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ return ((DBusGTypeSpecializedCollectionVtable *) (data->klass->vtable))->fixed_accessor (gtype,
+ g_value_get_boxed (value),
+ data_ret, len_ret);
+}
+
+void
+dbus_g_type_collection_value_iterate (GValue *value,
+ DBusGTypeSpecializedCollectionIterator iterator,
+ gpointer user_data)
+{
+ DBusGTypeSpecializedData *data;
+ GType gtype;
+
+ g_return_if_fail (specialized_types_is_initialized ());
+ g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
+
+ gtype = G_VALUE_TYPE (value);
+ data = lookup_specialization_data (gtype);
+ g_return_if_fail (data != NULL);
+
+ ((DBusGTypeSpecializedCollectionVtable *) data->klass->vtable)->iterator (gtype,
+ g_value_get_boxed (value),
+ iterator, user_data);
+}
+
+void
+dbus_g_type_map_value_iterate (GValue *value,
+ DBusGTypeSpecializedMapIterator iterator,
+ gpointer user_data)
+{
+ DBusGTypeSpecializedData *data;
+ GType gtype;
+
+ g_return_if_fail (specialized_types_is_initialized ());
+ g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
+
+ gtype = G_VALUE_TYPE (value);
+ data = lookup_specialization_data (gtype);
+ g_return_if_fail (data != NULL);
+
+ ((DBusGTypeSpecializedMapVtable *) data->klass->vtable)->iterator (gtype,
+ g_value_get_boxed (value),
+ iterator, user_data);
+}
diff --git a/glib/dbus-gtype-specialized.h b/glib/dbus-gtype-specialized.h
new file mode 100644
index 00000000..5157f33f
--- /dev/null
+++ b/glib/dbus-gtype-specialized.h
@@ -0,0 +1,104 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gtype-specialized.h: Non-DBus-specific functions for specialized GTypes
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef DBUS_GOBJECT_TYPE_SPECIALIZED_H
+#define DBUS_GOBJECT_TYPE_SPECIALIZED_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+GType dbus_g_type_get_collection (const char *container,
+ GType specialization);
+GType dbus_g_type_get_map (const char *container,
+ GType key_specialization,
+ GType value_specialization);
+gboolean dbus_g_type_is_collection (GType gtype);
+gboolean dbus_g_type_is_map (GType gtype);
+GType dbus_g_type_get_collection_specialization (GType gtype);
+GType dbus_g_type_get_map_key_specialization (GType gtype);
+GType dbus_g_type_get_map_value_specialization (GType gtype);
+
+typedef void (*DBusGTypeSpecializedCollectionIterator) (const GValue *val,
+ gpointer user_data);
+typedef void (*DBusGTypeSpecializedMapIterator) (const GValue *key_val,
+ const GValue *value_val,
+ gpointer user_data);
+
+gpointer dbus_g_type_specialized_construct (GType type);
+
+gboolean dbus_g_type_collection_get_fixed (GValue *value,
+ gpointer *data,
+ guint *len);
+
+void dbus_g_type_collection_value_iterate (GValue *value,
+ DBusGTypeSpecializedCollectionIterator iterator,
+ gpointer user_data);
+
+void dbus_g_type_map_value_iterate (GValue *value,
+ DBusGTypeSpecializedMapIterator iterator,
+ gpointer user_data);
+
+typedef gpointer (*DBusGTypeSpecializedConstructor) (GType type);
+typedef void (*DBusGTypeSpecializedFreeFunc) (GType type, gpointer val);
+typedef gpointer (*DBusGTypeSpecializedCopyFunc) (GType type, gpointer src);
+
+typedef struct {
+ DBusGTypeSpecializedConstructor constructor;
+ DBusGTypeSpecializedFreeFunc free_func;
+ DBusGTypeSpecializedCopyFunc copy_func;
+ gpointer padding1;
+ gpointer padding2;
+ gpointer padding3;
+} DBusGTypeSpecializedVtable;
+
+typedef gboolean (*DBusGTypeSpecializedCollectionFixedAccessorFunc) (GType type, gpointer instance, gpointer *values, guint *len);
+typedef void (*DBusGTypeSpecializedCollectionIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data);
+
+typedef struct {
+ DBusGTypeSpecializedVtable base_vtable;
+ DBusGTypeSpecializedCollectionFixedAccessorFunc fixed_accessor;
+ DBusGTypeSpecializedCollectionIteratorFunc iterator;
+} DBusGTypeSpecializedCollectionVtable;
+
+typedef void (*DBusGTypeSpecializedMapIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedMapIterator iterator, gpointer user_data);
+
+typedef struct {
+ DBusGTypeSpecializedVtable base_vtable;
+ DBusGTypeSpecializedMapIteratorFunc iterator;
+} DBusGTypeSpecializedMapVtable;
+
+void dbus_g_type_specialized_init (void);
+
+void dbus_g_type_register_collection (const char *name,
+ const DBusGTypeSpecializedCollectionVtable *vtable,
+ guint flags);
+
+void dbus_g_type_register_map (const char *name,
+ const DBusGTypeSpecializedMapVtable *vtable,
+ guint flags);
+
+G_END_DECLS
+
+#endif
diff --git a/glib/dbus-gvalue-utils.c b/glib/dbus-gvalue-utils.c
new file mode 100644
index 00000000..9eea4bf0
--- /dev/null
+++ b/glib/dbus-gvalue-utils.c
@@ -0,0 +1,715 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gvalue-utils.c: Non-DBus-specific functions related to GType/GValue
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "dbus/dbus-glib.h"
+#include "dbus-gvalue-utils.h"
+#include <glib.h>
+#include <string.h>
+#include <gobject/gvaluecollector.h>
+
+
+static guint
+fixed_type_get_size (GType type)
+{
+ switch (type)
+ {
+ case G_TYPE_CHAR:
+ case G_TYPE_UCHAR:
+ return sizeof (gchar);
+ case G_TYPE_BOOLEAN:
+ return sizeof (gboolean);
+ case G_TYPE_LONG:
+ case G_TYPE_ULONG:
+ return sizeof (glong);
+ case G_TYPE_INT:
+ case G_TYPE_UINT:
+ return sizeof (gint);
+ case G_TYPE_INT64:
+ case G_TYPE_UINT64:
+ return sizeof (gint64);
+ case G_TYPE_FLOAT:
+ return sizeof (gfloat);
+ case G_TYPE_DOUBLE:
+ return sizeof (gdouble);
+ default:
+ return 0;
+ }
+}
+
+gboolean
+dbus_g_type_is_fixed (GType type)
+{
+ return fixed_type_get_size (type) > 0;
+}
+
+guint
+dbus_g_type_fixed_get_size (GType type)
+{
+ g_assert (dbus_g_type_is_fixed (type));
+ return fixed_type_get_size (type);
+}
+
+gboolean
+dbus_gvalue_store (GValue *value,
+ gpointer storage)
+{
+ /* FIXME - can we use the GValue lcopy_value method
+ * to do this in a cleaner way?
+ */
+ switch (g_type_fundamental (G_VALUE_TYPE (value)))
+ {
+ case G_TYPE_CHAR:
+ *((gchar *) storage) = g_value_get_char (value);
+ return TRUE;
+ case G_TYPE_UCHAR:
+ *((guchar *) storage) = g_value_get_uchar (value);
+ return TRUE;
+ case G_TYPE_BOOLEAN:
+ *((gboolean *) storage) = g_value_get_boolean (value);
+ return TRUE;
+ case G_TYPE_LONG:
+ *((glong *) storage) = g_value_get_long (value);
+ return TRUE;
+ case G_TYPE_ULONG:
+ *((gulong *) storage) = g_value_get_ulong (value);
+ return TRUE;
+ case G_TYPE_INT:
+ *((gint *) storage) = g_value_get_int (value);
+ return TRUE;
+ case G_TYPE_UINT:
+ *((guint *) storage) = g_value_get_uint (value);
+ return TRUE;
+ case G_TYPE_INT64:
+ *((gint64 *) storage) = g_value_get_int64 (value);
+ return TRUE;
+ case G_TYPE_UINT64:
+ *((guint64 *) storage) = g_value_get_uint64 (value);
+ return TRUE;
+ case G_TYPE_DOUBLE:
+ *((gdouble *) storage) = g_value_get_double (value);
+ return TRUE;
+ case G_TYPE_STRING:
+ *((gchar **) storage) = (char*) g_value_get_string (value);
+ return TRUE;
+ case G_TYPE_POINTER:
+ *((gpointer *) storage) = g_value_get_pointer (value);
+ return TRUE;
+ case G_TYPE_OBJECT:
+ *((gpointer *) storage) = g_value_get_object (value);
+ return TRUE;
+ case G_TYPE_BOXED:
+ *((gpointer *) storage) = g_value_get_boxed (value);
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+gboolean
+dbus_gvalue_set_from_pointer (GValue *value,
+ gconstpointer storage)
+{
+ /* FIXME - is there a better way to do this? */
+ switch (g_type_fundamental (G_VALUE_TYPE (value)))
+ {
+ case G_TYPE_CHAR:
+ g_value_set_char (value, *((gchar *) storage));
+ return TRUE;
+ case G_TYPE_UCHAR:
+ g_value_set_uchar (value, *((guchar *) storage));
+ return TRUE;
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean (value, *((gboolean *) storage));
+ return TRUE;
+ case G_TYPE_LONG:
+ g_value_set_long (value, *((glong *) storage));
+ return TRUE;
+ case G_TYPE_ULONG:
+ g_value_set_ulong (value, *((gulong *) storage));
+ return TRUE;
+ case G_TYPE_INT:
+ g_value_set_int (value, *((gint *) storage));
+ return TRUE;
+ case G_TYPE_UINT:
+ g_value_set_uint (value, *((guint *) storage));
+ return TRUE;
+ case G_TYPE_INT64:
+ g_value_set_int64 (value, *((gint64 *) storage));
+ return TRUE;
+ case G_TYPE_UINT64:
+ g_value_set_uint64 (value, *((guint64 *) storage));
+ return TRUE;
+ case G_TYPE_DOUBLE:
+ g_value_set_double (value, *((gdouble *) storage));
+ return TRUE;
+ case G_TYPE_STRING:
+ g_value_set_string (value, *((gchar **) storage));
+ return TRUE;
+ case G_TYPE_POINTER:
+ g_value_set_pointer (value, *((gpointer *) storage));
+ return TRUE;
+ case G_TYPE_OBJECT:
+ g_value_set_object (value, *((gpointer *) storage));
+ return TRUE;
+ case G_TYPE_BOXED:
+ g_value_set_boxed (value, *((gpointer *) storage));
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+gboolean
+dbus_gvalue_take (GValue *value,
+ GTypeCValue *cvalue)
+{
+ GType g_type;
+ GTypeValueTable *value_table;
+ char *error_msg;
+
+ g_type = G_VALUE_TYPE (value);
+ value_table = g_type_value_table_peek (g_type);
+
+ error_msg = value_table->collect_value (value, 1, cvalue, G_VALUE_NOCOPY_CONTENTS);
+ if (error_msg)
+ {
+ g_warning ("%s: %s", G_STRLOC, error_msg);
+ g_free (error_msg);
+ return FALSE;
+ }
+ /* Clear the NOCOPY_CONTENTS flag; we want to take ownership
+ * of the value.
+ */
+ value->data[1].v_uint &= ~(G_VALUE_NOCOPY_CONTENTS);
+ return TRUE;
+}
+
+static gboolean
+hash_func_from_gtype (GType gtype, GHashFunc *func)
+{
+ switch (gtype)
+ {
+ case G_TYPE_CHAR:
+ case G_TYPE_UCHAR:
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_INT:
+ case G_TYPE_UINT:
+ *func = NULL;
+ return TRUE;
+ case G_TYPE_STRING:
+ *func = g_str_hash;
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static gboolean
+hash_free_from_gtype (GType gtype, GDestroyNotify *func)
+{
+ switch (gtype)
+ {
+ case G_TYPE_CHAR:
+ case G_TYPE_UCHAR:
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_INT:
+ case G_TYPE_UINT:
+ *func = NULL;
+ return TRUE;
+ case G_TYPE_STRING:
+ *func = g_free;
+ return TRUE;
+ default:
+ if (gtype == G_TYPE_VALUE)
+ {
+ *func = (GDestroyNotify) g_value_unset;
+ return TRUE;
+ }
+ return FALSE;
+ }
+}
+
+gboolean
+dbus_gtype_is_valid_hash_key (GType type)
+{
+ GHashFunc func;
+ return hash_func_from_gtype (type, &func);
+}
+
+gboolean
+dbus_gtype_is_valid_hash_value (GType type)
+{
+ GDestroyNotify func;
+ return hash_free_from_gtype (type, &func);
+}
+
+GHashFunc
+dbus_g_hash_func_from_gtype (GType gtype)
+{
+ GHashFunc func;
+ gboolean ret;
+ ret = hash_func_from_gtype (gtype, &func);
+ g_assert (ret != FALSE);
+ return func;
+}
+
+GEqualFunc
+dbus_g_hash_equal_from_gtype (GType gtype)
+{
+ g_assert (dbus_gtype_is_valid_hash_key (gtype));
+
+ switch (gtype)
+ {
+ case G_TYPE_CHAR:
+ case G_TYPE_UCHAR:
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_INT:
+ case G_TYPE_UINT:
+ return NULL;
+ case G_TYPE_STRING:
+ return g_str_equal;
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
+}
+
+GDestroyNotify
+dbus_g_hash_free_from_gtype (GType gtype)
+{
+ GDestroyNotify func;
+ gboolean ret;
+ ret = hash_free_from_gtype (gtype, &func);
+ g_assert (ret != FALSE);
+ return func;
+}
+
+static void
+gvalue_from_hash_value (GValue *value, gpointer instance)
+{
+ switch (g_type_fundamental (G_VALUE_TYPE (value)))
+ {
+ case G_TYPE_CHAR:
+ g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance));
+ break;
+ case G_TYPE_UCHAR:
+ g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance));
+ break;
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance));
+ break;
+ case G_TYPE_INT:
+ g_value_set_int (value, GPOINTER_TO_INT (instance));
+ break;
+ case G_TYPE_UINT:
+ g_value_set_uint (value, GPOINTER_TO_UINT (instance));
+ break;
+ case G_TYPE_STRING:
+ g_value_set_static_string (value, instance);
+ break;
+ case G_TYPE_POINTER:
+ g_value_set_pointer (value, instance);
+ break;
+ case G_TYPE_BOXED:
+ g_value_set_static_boxed (value, instance);
+ break;
+ case G_TYPE_OBJECT:
+ g_value_set_object (value, instance);
+ g_object_unref (g_value_get_object (value));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static gpointer
+hash_value_from_gvalue (GValue *value)
+{
+ switch (g_type_fundamental (G_VALUE_TYPE (value)))
+ {
+ case G_TYPE_CHAR:
+ return GINT_TO_POINTER ((int) g_value_get_char (value));
+ break;
+ case G_TYPE_UCHAR:
+ return GUINT_TO_POINTER ((guint) g_value_get_uchar (value));
+ break;
+ case G_TYPE_BOOLEAN:
+ return GUINT_TO_POINTER ((guint) g_value_get_boolean (value));
+ break;
+ case G_TYPE_INT:
+ return GINT_TO_POINTER (g_value_get_int (value));
+ break;
+ case G_TYPE_UINT:
+ return GUINT_TO_POINTER (g_value_get_uint (value));
+ break;
+ case G_TYPE_STRING:
+ return (gpointer) g_value_get_string (value);
+ break;
+ case G_TYPE_POINTER:
+ return g_value_get_pointer (value);
+ break;
+ case G_TYPE_BOXED:
+ return g_value_get_boxed (value);
+ break;
+ case G_TYPE_OBJECT:
+ return g_value_get_object (value);
+ break;
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
+}
+
+struct DBusGHashTableValueForeachData
+{
+ DBusGTypeSpecializedMapIterator func;
+ GType key_type;
+ GType value_type;
+ gpointer data;
+};
+
+static void
+hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data)
+{
+ GValue key_val = {0, };
+ GValue value_val = {0, };
+ struct DBusGHashTableValueForeachData *data = user_data;
+
+ g_value_init (&key_val, data->key_type);
+ g_value_init (&value_val, data->value_type);
+ gvalue_from_hash_value (&key_val, key);
+ gvalue_from_hash_value (&value_val, value);
+
+ data->func (&key_val, &value_val, data->data);
+}
+
+
+static void
+hashtable_iterator (GType hash_type,
+ gpointer instance,
+ DBusGTypeSpecializedMapIterator iterator,
+ gpointer user_data)
+{
+ struct DBusGHashTableValueForeachData data;
+ GType key_gtype;
+ GType value_gtype;
+
+ key_gtype = dbus_g_type_get_map_key_specialization (hash_type);
+ value_gtype = dbus_g_type_get_map_value_specialization (hash_type);
+
+ data.func = iterator;
+ data.key_type = key_gtype;
+ data.value_type = value_gtype;
+ data.data = user_data;
+
+ g_hash_table_foreach (instance, hashtable_foreach_with_values, &data);
+}
+
+void
+dbus_g_hash_table_insert_steal_values (GHashTable *table,
+ GValue *key_val,
+ GValue *value_val)
+{
+ gpointer key, val;
+
+ key = hash_value_from_gvalue (key_val);
+ val = hash_value_from_gvalue (value_val);
+
+ g_hash_table_insert (table, key, val);
+}
+
+static gpointer
+hashtable_constructor (GType type)
+{
+ GHashTable *ret;
+ GType key_gtype;
+ GType value_gtype;
+
+ key_gtype = dbus_g_type_get_map_key_specialization (type);
+ value_gtype = dbus_g_type_get_map_value_specialization (type);
+
+ ret = g_hash_table_new_full (dbus_g_hash_func_from_gtype (key_gtype),
+ dbus_g_hash_equal_from_gtype (key_gtype),
+ dbus_g_hash_free_from_gtype (key_gtype),
+ dbus_g_hash_free_from_gtype (value_gtype));
+ return ret;
+}
+
+static void
+hashtable_insert_values (GHashTable *table,
+ const GValue *key_val,
+ const GValue *value_val)
+{
+ GValue key_copy = {0, };
+ GValue value_copy = {0, };
+
+ g_value_init (&key_copy, G_VALUE_TYPE (key_val));
+ g_value_copy (key_val, &key_copy);
+ g_value_init (&value_copy, G_VALUE_TYPE (value_val));
+ g_value_copy (value_val, &value_copy);
+
+ dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy);
+}
+
+static void
+hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data)
+{
+ hashtable_insert_values ((GHashTable *) data, key, val);
+}
+
+static gpointer
+hashtable_copy (GType type, gpointer src)
+{
+ GHashTable *ghash;
+ GHashTable *ret;
+ GValue hashval = {0,};
+
+ ghash = src;
+
+ ret = hashtable_constructor (type);
+
+ g_value_init (&hashval, type);
+ g_value_set_static_boxed (&hashval, ghash);
+ dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret);
+ return ret;
+}
+
+static void
+hashtable_free (GType type, gpointer val)
+{
+ g_hash_table_destroy (val);
+}
+
+static gpointer
+array_constructor (GType type)
+{
+ GArray *array;
+ guint elt_size;
+ GType elt_type;
+ gboolean zero_terminated;
+ gboolean clear;
+
+ elt_type = dbus_g_type_get_collection_specialization (type);
+ g_assert (elt_type != G_TYPE_INVALID);
+
+ elt_size = dbus_g_type_fixed_get_size (elt_type);
+
+ /* These are "safe" defaults */
+ zero_terminated = TRUE; /* ((struct _DBusGRealArray*) garray)->zero_terminated; */
+ clear = TRUE; /* ((struct _DBusGRealArray*) garray)->clear; */
+
+ array = g_array_new (zero_terminated, clear, elt_size);
+ return array;
+}
+
+static gpointer
+array_copy (GType type, gpointer src)
+{
+ GArray *garray;
+ GArray *new;
+
+ garray = src;
+
+ new = array_constructor (type);
+ g_array_append_vals (new, garray->data, garray->len);
+
+ return new;
+}
+
+static void
+array_free (GType type, gpointer val)
+{
+ GArray *array;
+ array = val;
+ g_array_free (array, TRUE);
+}
+
+static gboolean
+array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len)
+{
+ GType elt_type;
+ GArray *array = instance;
+
+ elt_type = dbus_g_type_get_collection_specialization (type);
+ if (!dbus_g_type_is_fixed (elt_type))
+ return FALSE;
+
+ *values = array->data;
+ *len = array->len;
+ return TRUE;
+}
+
+static gpointer
+ptrarray_constructor (GType type)
+{
+ /* Later we should determine a destructor, need g_ptr_array_destroy */
+ return g_ptr_array_new ();
+}
+
+static void
+gvalue_from_ptrarray_value (GValue *value, gpointer instance)
+{
+ switch (g_type_fundamental (G_VALUE_TYPE (value)))
+ {
+ case G_TYPE_POINTER:
+ g_value_set_pointer (value, instance);
+ break;
+ case G_TYPE_BOXED:
+ g_value_set_static_boxed (value, instance);
+ break;
+ case G_TYPE_OBJECT:
+ g_value_set_object (value, instance);
+ g_object_unref (g_value_get_object (value));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static gpointer
+ptrarray_value_from_gvalue (const GValue *value)
+{
+ switch (g_type_fundamental (G_VALUE_TYPE (value)))
+ {
+ case G_TYPE_POINTER:
+ return g_value_get_pointer (value);
+ break;
+ case G_TYPE_BOXED:
+ return g_value_get_boxed (value);
+ break;
+ case G_TYPE_OBJECT:
+ return g_value_get_object (value);
+ break;
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
+}
+
+static void
+ptrarray_iterator (GType hash_type,
+ gpointer instance,
+ DBusGTypeSpecializedCollectionIterator iterator,
+ gpointer user_data)
+{
+ GPtrArray *ptrarray;
+ GType elt_gtype;
+ guint i;
+
+ ptrarray = instance;
+
+ elt_gtype = dbus_g_type_get_collection_specialization (hash_type);
+
+ for (i = 0; i < ptrarray->len; i++)
+ {
+ GValue val = {0, };
+ g_value_init (&val, elt_gtype);
+ gvalue_from_ptrarray_value (&val, g_ptr_array_index (ptrarray, i));
+ iterator (&val, user_data);
+ }
+}
+
+static void
+ptrarray_copy_elt (const GValue *val, gpointer user_data)
+{
+ GPtrArray *dest = user_data;
+ GValue val_copy = {0, };
+
+ g_value_init (&val_copy, G_VALUE_TYPE (val));
+ g_value_copy (val, &val_copy);
+
+ g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy));
+}
+
+static gpointer
+ptrarray_copy (GType type, gpointer src)
+{
+ GPtrArray *new;
+ GValue array_val = {0, };
+
+ g_value_init (&array_val, type);
+ g_value_set_static_boxed (&array_val, src);
+
+ new = ptrarray_constructor (type);
+ dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new);
+
+ return new;
+}
+
+static void
+ptrarray_free (GType type, gpointer val)
+{
+ GArray *array;
+ array = val;
+ g_array_free (array, TRUE);
+}
+
+void
+dbus_g_type_specialized_builtins_init (void)
+{
+ static const DBusGTypeSpecializedCollectionVtable array_vtable = {
+ {
+ array_constructor,
+ array_free,
+ array_copy,
+ NULL,
+ NULL,
+ NULL
+ },
+ array_fixed_accessor,
+ NULL
+ };
+
+ dbus_g_type_register_collection ("GArray", &array_vtable, 0);
+
+ static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = {
+ {
+ ptrarray_constructor,
+ ptrarray_free,
+ ptrarray_copy,
+ NULL,
+ NULL,
+ NULL
+ },
+ NULL,
+ ptrarray_iterator
+ };
+
+ dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);
+
+ static const DBusGTypeSpecializedMapVtable hashtable_vtable = {
+ {
+ hashtable_constructor,
+ hashtable_free,
+ hashtable_copy,
+ NULL,
+ NULL,
+ NULL
+ },
+ hashtable_iterator
+ };
+
+ dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
+}
diff --git a/glib/dbus-gvalue-utils.h b/glib/dbus-gvalue-utils.h
new file mode 100644
index 00000000..781569ff
--- /dev/null
+++ b/glib/dbus-gvalue-utils.h
@@ -0,0 +1,70 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gvalue-utils.h: Non-DBus-specific functions related to GType/GValue
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef DBUS_GOBJECT_VALUE_UTILS_H
+#define DBUS_GOBJECT_VALUE_UTILS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void dbus_g_type_specialized_builtins_init (void);
+
+gboolean dbus_g_type_is_fixed (GType gtype);
+guint dbus_g_type_fixed_get_size (GType gtype);
+
+gboolean dbus_gvalue_set_from_pointer (GValue *value,
+ gconstpointer storage);
+
+typedef void (*DBusGHashValueForeachFunc) (GValue * key, GValue *val, gpointer data);
+
+void dbus_g_hash_table_value_foreach (GHashTable *table,
+ GType hash_type,
+ DBusGHashValueForeachFunc func,
+ gpointer data);
+
+void dbus_g_hash_table_insert_values (GHashTable *table,
+ GValue *key_val,
+ GValue *value_val);
+void dbus_g_hash_table_insert_steal_values (GHashTable *table,
+ GValue *key_val,
+ GValue *value_val);
+
+gboolean dbus_gtype_is_valid_hash_key (GType type);
+gboolean dbus_gtype_is_valid_hash_value (GType type);
+
+GHashFunc dbus_g_hash_func_from_gtype (GType gtype);
+GEqualFunc dbus_g_hash_equal_from_gtype (GType gtype);
+GDestroyNotify dbus_g_hash_free_from_gtype (GType gtype);
+
+gboolean dbus_gvalue_store (GValue *value,
+ gpointer storage);
+
+gboolean dbus_gvalue_take (GValue *value,
+ GTypeCValue *cvalue);
+
+
+G_END_DECLS
+
+#endif
diff --git a/glib/dbus-gvalue.c b/glib/dbus-gvalue.c
index eae5a458..8506330d 100644
--- a/glib/dbus-gvalue.c
+++ b/glib/dbus-gvalue.c
@@ -22,202 +22,680 @@
*
*/
-#include <dbus-gvalue.h>
+#include "dbus-gvalue.h"
+#include "dbus-gobject.h"
+#include "dbus-gvalue-utils.h"
+#include "dbus/dbus-glib.h"
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
#include "dbus/dbus-signature.h"
-/* This is slightly evil, we don't use g_value_set_foo() functions */
+static gboolean demarshal_static_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gpointer dbus_g_value_copy (gpointer value);
+
+
+struct DBusGValue
+{
+ enum {
+ DBUS_G_VALUE_TYPE_TOPLEVEL,
+ DBUS_G_VALUE_TYPE_ITERATOR
+ } type;
+ union {
+ struct {
+ DBusGConnection *connection;
+ DBusGProxy *proxy;
+ DBusMessage *message;
+ char *signature;
+ } toplevel;
+ struct {
+ DBusGValue *toplevel;
+ DBusMessageIter iterator;
+ } recurse;
+ } value;
+};
+
+static gboolean marshal_basic (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_basic (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_strv (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_strv (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_variant (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_garray_basic (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_garray_basic (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_proxy (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_proxy (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_object (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_object (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_proxy_array (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_proxy_array (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_map (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_ghashtable (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+
+typedef gboolean (*DBusGValueMarshalFunc) (DBusMessageIter *iter,
+ GValue *value);
+typedef gboolean (*DBusGValueDemarshalFunc) (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+
+typedef struct {
+ DBusGValueMarshalFunc marshaller;
+ DBusGValueDemarshalFunc demarshaller;
+} DBusGTypeMarshalVtable;
+
+typedef struct {
+ const char *sig;
+ const DBusGTypeMarshalVtable *vtable;
+} DBusGTypeMarshalData;
+
+static GQuark
+dbus_g_type_metadata_data_quark ()
+{
+ static GQuark quark;
+ if (!quark)
+ quark = g_quark_from_static_string ("DBusGTypeMetaData");
+
+ return quark;
+}
+
+static void
+set_type_metadata (GType type, const DBusGTypeMarshalData *data)
+{
+ g_type_set_qdata (type, dbus_g_type_metadata_data_quark (), (gpointer) data);
+}
+
#define MAP_BASIC(d_t, g_t) \
case DBUS_TYPE_##d_t: \
return G_TYPE_##g_t;
-
static GType
-dbus_dbus_type_to_gtype (int type)
+typecode_to_gtype (int type)
{
switch (type)
{
MAP_BASIC (BOOLEAN, BOOLEAN);
MAP_BASIC (BYTE, UCHAR);
+ MAP_BASIC (INT16, INT);
MAP_BASIC (INT32, INT);
+ MAP_BASIC (UINT16, UINT);
MAP_BASIC (UINT32, UINT);
MAP_BASIC (INT64, INT64);
MAP_BASIC (UINT64, UINT64);
MAP_BASIC (DOUBLE, DOUBLE);
- case DBUS_TYPE_INT16:
- return G_TYPE_INT;
- case DBUS_TYPE_UINT16:
- return G_TYPE_UINT;
- case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- case DBUS_TYPE_SIGNATURE:
- return G_TYPE_STRING;
- case DBUS_TYPE_STRUCT:
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
+ MAP_BASIC (STRING, STRING);
default:
return G_TYPE_INVALID;
}
}
-
#undef MAP_BASIC
-gboolean
-dbus_gvalue_init (int type,
- GValue *value)
+static gboolean
+dbus_typecode_maps_to_basic (int typecode)
+{
+ return typecode_to_gtype (typecode) != G_TYPE_INVALID;
+}
+
+static gboolean
+basic_typecode_to_gtype (int typecode)
+{
+ g_assert (dbus_type_is_basic (typecode));
+ g_assert (dbus_typecode_maps_to_basic (typecode));
+ return typecode_to_gtype (typecode);
+}
+
+static void
+register_basic (int typecode, const DBusGTypeMarshalData *typedata)
{
+ set_type_metadata (basic_typecode_to_gtype (typecode), typedata);
+}
+
+static void
+register_array (int typecode, const DBusGTypeMarshalData *typedata)
+{
+ GType elt_gtype;
GType gtype;
- gtype = dbus_dbus_type_to_gtype (type);
- if (gtype == G_TYPE_INVALID)
- return FALSE;
- g_value_init (value, gtype);
- return TRUE;
+ elt_gtype = basic_typecode_to_gtype (typecode);
+ gtype = dbus_g_type_get_collection ("GArray", elt_gtype);
+ set_type_metadata (gtype, typedata);
+}
+
+static void
+register_dict (int key_type, int value_type, const DBusGTypeMarshalData *typedata)
+{
+ GType key_gtype;
+ GType value_gtype;
+ GType gtype;
+
+ key_gtype = basic_typecode_to_gtype (key_type);
+ value_gtype = basic_typecode_to_gtype (value_type);
+ gtype = dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype);
+ set_type_metadata (gtype, typedata);
+}
+
+void
+dbus_g_value_types_init (void)
+{
+ static gboolean types_initialized;
+
+
+ if (types_initialized)
+ return;
+
+ g_assert (sizeof (DBusGValueIterator) >= sizeof (DBusMessageIter));
+
+ dbus_g_type_specialized_init ();
+ dbus_g_type_specialized_builtins_init ();
+
+ static const DBusGTypeMarshalVtable basic_vtable = {
+ marshal_basic,
+ demarshal_basic
+ };
+ static const DBusGTypeMarshalVtable garray_basic_vtable = {
+ marshal_garray_basic,
+ demarshal_garray_basic
+ };
+ static const DBusGTypeMarshalVtable ghashtable_vtable = {
+ marshal_map,
+ demarshal_ghashtable
+ };
+
+ /* Register basic types */
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_BOOLEAN_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_BOOLEAN, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_BYTE_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_BYTE, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_INT16_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_INT16, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_UINT16_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_UINT16, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_UINT32_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_UINT32, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_INT32_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_INT32, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_UINT64_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_UINT64, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_INT64_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_INT64, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_DOUBLE_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_DOUBLE, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_STRING_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_STRING, &typedata);
+ }
+
+ /* Register complex types with builtin GType mappings */
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_variant,
+ demarshal_variant
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_VARIANT_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (G_TYPE_VALUE, &typedata);
+ };
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_strv,
+ demarshal_strv
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (G_TYPE_STRV, &typedata);
+ };
+
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_BOOLEAN, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_BYTE, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_UINT32, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_INT32, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT64_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_UINT64, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT64_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_INT64, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &ghashtable_vtable,
+ };
+ register_dict (DBUS_TYPE_STRING, DBUS_TYPE_STRING, &typedata);
+ }
+
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_proxy,
+ demarshal_proxy
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (DBUS_TYPE_G_PROXY, &typedata);
+ }
+
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_object,
+ demarshal_object
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (G_TYPE_OBJECT, &typedata);
+ }
+
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_proxy_array,
+ demarshal_proxy_array
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (DBUS_TYPE_G_PROXY_ARRAY, &typedata);
+ }
+
+ types_initialized = TRUE;
}
-/* FIXME - broken for containers
+/**
+ * Get the GLib type ID for a DBusGValue boxed type.
+ *
+ * @returns GLib type
*/
-static int
-base_type_from_signature (const char *signature)
+GType
+dbus_g_value_get_g_type (void)
{
- DBusSignatureIter iter;
+ static GType type_id = 0;
- dbus_signature_iter_init (&iter, signature);
+ if (!type_id)
+ type_id = g_boxed_type_register_static ("DBusGValue",
+ dbus_g_value_copy,
+ (GBoxedFreeFunc) dbus_g_value_free);
+ return type_id;
+}
+
+void
+dbus_g_value_open (DBusGValue *value,
+ DBusGValueIterator *iter)
+{
+ DBusGValue *real;
+
+ g_return_if_fail (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL);
+
+ real = (DBusGValue*) iter;
+ real->type = DBUS_G_VALUE_TYPE_ITERATOR;
+ real->value.recurse.toplevel = value;
- return dbus_signature_iter_get_current_type (&iter);
+ dbus_message_iter_init (value->value.toplevel.message,
+ &(real->value.recurse.iterator));
+ value->value.recurse.toplevel = value;
}
-const char *
-dbus_gvalue_genmarshal_name_from_type (const char *signature)
+gboolean
+dbus_g_value_iterator_get_values (DBusGValueIterator *iter,
+ GError **error,
+ GValue *first_val,
+ ...)
{
- int type;
+ GValue *value;
+ va_list args;
+ DBusGValue *iterval;
- type = base_type_from_signature (signature);
- switch (type)
+ va_start (args, first_val);
+
+ iterval = (DBusGValue *) iter;
+
+ value = first_val;
+ do
{
- case DBUS_TYPE_BOOLEAN:
- return "BOOLEAN";
- case DBUS_TYPE_BYTE:
- return "UCHAR";
- case DBUS_TYPE_INT32:
- return "INT";
- case DBUS_TYPE_UINT32:
- return "UINT";
- case DBUS_TYPE_INT64:
- return "INT64";
- case DBUS_TYPE_UINT64:
- return "UINT64";
- case DBUS_TYPE_DOUBLE:
- return "DOUBLE";
- case DBUS_TYPE_INT16:
- return "INT";
- break;
- case DBUS_TYPE_UINT16:
- return "UINT";
- case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- case DBUS_TYPE_SIGNATURE:
- return "STRING";
-
- case DBUS_TYPE_STRUCT:
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
- return NULL;
- }
+ DBusGValueMarshalCtx context;
+
+ context.gconnection = (iterval->value.recurse.toplevel)->value.toplevel.connection;
+ context.proxy = (iterval->value.recurse.toplevel)->value.toplevel.proxy;
+ if (!dbus_gvalue_demarshal (&context,
+ &(iterval->value.recurse.iterator),
+ value,
+ error))
+ return FALSE;
+ } while ((value = va_arg (args, GValue *)) != NULL);
+
+ return TRUE;
+}
+
+static char *
+dbus_g_value_get_signature (DBusGValue *value)
+{
+ return value->value.toplevel.signature;
+}
+
+static gpointer
+dbus_g_value_copy (gpointer value)
+{
+ /* FIXME */
return NULL;
}
-const char *
-dbus_gvalue_ctype_from_type (const char *signature, gboolean in)
+void
+dbus_g_value_free (DBusGValue *value)
+{
+ if (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL)
+ {
+ dbus_message_unref (value->value.toplevel.message);
+ g_free (value->value.toplevel.signature);
+ }
+}
+
+static GType
+signature_iter_to_g_type_dict (const DBusSignatureIter *subiter, gboolean is_client)
{
- int type;
+ DBusSignatureIter iter;
+ GType key_gtype;
+ GType value_gtype;
- type = base_type_from_signature (signature);
+ g_assert (dbus_signature_iter_get_current_type (subiter) == DBUS_TYPE_DICT_ENTRY);
- switch (type)
+ dbus_signature_iter_recurse (subiter, &iter);
+
+ key_gtype = dbus_gtype_from_signature_iter (&iter, is_client);
+ if (key_gtype == G_TYPE_INVALID)
+ return G_TYPE_INVALID;
+
+ dbus_signature_iter_next (&iter);
+ value_gtype = dbus_gtype_from_signature_iter (&iter, is_client);
+ if (value_gtype == G_TYPE_INVALID)
+ return G_TYPE_INVALID;
+
+ if (!dbus_gtype_is_valid_hash_key (key_gtype)
+ || !dbus_gtype_is_valid_hash_value (value_gtype))
+ /* Later we need to return DBUS_TYPE_G_VALUE */
+ return G_TYPE_INVALID;
+
+ return dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype);
+}
+
+static GType
+signature_iter_to_g_type_array (DBusSignatureIter *iter, gboolean is_client)
+{
+ GType elt_gtype;
+ DBusGTypeMarshalData *typedata;
+
+ elt_gtype = dbus_gtype_from_signature_iter (iter, is_client);
+ if (elt_gtype == G_TYPE_INVALID)
+ return G_TYPE_INVALID;
+
+ typedata = g_type_get_qdata (elt_gtype, dbus_g_type_metadata_data_quark ());
+ if (typedata == NULL)
+ return G_TYPE_INVALID;
+
+ if (elt_gtype == G_TYPE_OBJECT)
+ return DBUS_TYPE_G_OBJECT_ARRAY;
+ if (elt_gtype == G_TYPE_STRING)
+ return G_TYPE_STRV;
+ if (dbus_g_type_is_fixed (elt_gtype))
+ return dbus_g_type_get_collection ("GArray", elt_gtype);
+
+ /* Later we need to return DBUS_TYPE_G_VALUE */
+ return G_TYPE_INVALID;
+}
+
+static gboolean
+signature_iter_to_g_type_struct (DBusSignatureIter *origiter, gboolean is_client)
+{
+ /* FIXME allow structures */
+ return G_TYPE_INVALID;
+#if 0
+ DBusSignatureIter iter;
+ int current_type;
+
+ iter = *origiter;
+
+ while ((current_type = dbus_signature_iter_get_current_type (&iter)) != DBUS_TYPE_INVALID) {
+ subtype = dbus_gtype_from_signature_iter (&iter, is_client);
+ if (subtype == G_TYPE_INVALID)
+ return G_TYPE_INVALID;
+ }
+ return DBUS_TYPE_G_VALUE ();
+#endif
+}
+
+GType
+dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client)
+{
+ int current_type;
+
+ current_type = dbus_signature_iter_get_current_type (iter);
+ /* TODO: handle type 0? */
+ if (dbus_typecode_maps_to_basic (current_type))
+ return basic_typecode_to_gtype (current_type);
+ else if (current_type == DBUS_TYPE_OBJECT_PATH)
+ return is_client ? DBUS_TYPE_G_PROXY : G_TYPE_OBJECT;
+ else
{
- case DBUS_TYPE_BOOLEAN:
- return "gboolean";
- case DBUS_TYPE_BYTE:
- return "guchar";
- case DBUS_TYPE_INT32:
- return "gint32";
- case DBUS_TYPE_UINT32:
- return "guint32";
- case DBUS_TYPE_INT64:
- return "gint64";
- case DBUS_TYPE_UINT64:
- return "guint64";
- case DBUS_TYPE_DOUBLE:
- return "gdouble";
- case DBUS_TYPE_INT16:
- return "gint";
- break;
- case DBUS_TYPE_UINT16:
- return "guint";
- case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- case DBUS_TYPE_SIGNATURE:
- /* FIXME - kind of a hack */
- if (in)
- return "const char *";
+ DBusSignatureIter subiter;
+
+ g_assert (dbus_type_is_container (current_type));
+ dbus_signature_iter_recurse (iter, &subiter);
+
+ if (current_type == DBUS_TYPE_ARRAY)
+ {
+ int elt_type = dbus_signature_iter_get_current_type (&subiter);
+ if (elt_type == DBUS_TYPE_DICT_ENTRY)
+ return signature_iter_to_g_type_dict (&subiter, is_client);
+ else
+ return signature_iter_to_g_type_array (&subiter, is_client);
+ }
+ else if (current_type == DBUS_TYPE_STRUCT)
+ return signature_iter_to_g_type_struct (&subiter, is_client);
+ else if (current_type == DBUS_TYPE_VARIANT)
+ return g_value_get_type ();
+ else if (current_type == DBUS_TYPE_DICT_ENTRY)
+ return G_TYPE_INVALID;
else
- return "char *";
- case DBUS_TYPE_STRUCT:
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
- return NULL;
+ {
+ g_assert_not_reached ();
+ return G_TYPE_INVALID;
+ }
}
- return NULL;
}
-const char *
-dbus_gtype_to_dbus_type (GType type)
+GType
+dbus_gtype_from_signature (const char *signature, gboolean is_client)
{
- switch (type)
+ DBusSignatureIter iter;
+
+ dbus_signature_iter_init (&iter, signature);
+
+ return dbus_gtype_from_signature_iter (&iter, is_client);
+}
+
+static char *
+dbus_gvalue_to_signature (GValue *value)
+{
+ const char *ret;
+
+ ret = dbus_gtype_to_signature (G_VALUE_TYPE (value));
+ if (ret)
+ return g_strdup (ret);
+ else
{
- case G_TYPE_CHAR:
- case G_TYPE_UCHAR:
- return DBUS_TYPE_BYTE_AS_STRING;
+ DBusGValue *val;
- case G_TYPE_BOOLEAN:
- return DBUS_TYPE_BOOLEAN_AS_STRING;
+ g_assert (G_VALUE_TYPE (value) == DBUS_TYPE_G_VALUE);
- /* long gets cut to 32 bits so the remote API is consistent
- * on all architectures
- */
+ val = g_value_get_boxed (value);
- case G_TYPE_LONG:
- case G_TYPE_INT:
- return DBUS_TYPE_INT32_AS_STRING;
- case G_TYPE_ULONG:
- case G_TYPE_UINT:
- return DBUS_TYPE_UINT32_AS_STRING;
+ return dbus_g_value_get_signature (val);
+ }
+}
- case G_TYPE_INT64:
- return DBUS_TYPE_INT64_AS_STRING;
+const char *
+dbus_gtype_to_signature (GType gtype)
+{
+ DBusGTypeMarshalData *typedata;
- case G_TYPE_UINT64:
- return DBUS_TYPE_UINT64_AS_STRING;
-
- case G_TYPE_FLOAT:
- case G_TYPE_DOUBLE:
- return DBUS_TYPE_DOUBLE_AS_STRING;
+ typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
+ if (typedata == NULL)
+ return NULL;
+ return typedata->sig;
+}
- case G_TYPE_STRING:
- return DBUS_TYPE_STRING_AS_STRING;
+GArray *
+dbus_gtypes_from_arg_signature (const char *argsig, gboolean is_client)
+{
+ GArray *ret;
+ int current_type;
+ DBusSignatureIter sigiter;
- default:
- return NULL;
+ ret = g_array_new (FALSE, FALSE, sizeof (GType));
+
+ dbus_signature_iter_init (&sigiter, argsig);
+ while ((current_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+ {
+ GType curtype;
+
+ curtype = dbus_gtype_from_signature_iter (&sigiter, is_client);
+ g_array_append_val (ret, curtype);
+ dbus_signature_iter_next (&sigiter);
}
+ return ret;
}
-gboolean
-dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
-{
- g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int));
- dbus_gvalue_init (dbus_message_iter_get_arg_type (iter), value);
+static gboolean
+demarshal_basic (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ int current_type;
- switch (dbus_message_iter_get_arg_type (iter))
+ current_type = dbus_message_iter_get_arg_type (iter);
+ g_assert (dbus_type_is_basic (current_type));
+
+ switch (current_type)
{
case DBUS_TYPE_BOOLEAN:
{
@@ -283,24 +761,407 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
return TRUE;
}
case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- case DBUS_TYPE_SIGNATURE:
{
const char *s;
dbus_message_iter_get_basic (iter, &s);
- g_value_set_string (value, s);
+ g_value_set_string (value, s);
return TRUE;
}
- case DBUS_TYPE_STRUCT:
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
+}
+
+static gboolean
+demarshal_static_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ char *sig;
+ int current_type;
+ DBusMessageIter subiter;
+ GType variant_type;
+
+ current_type = dbus_message_iter_get_arg_type (iter);
+ dbus_message_iter_recurse (iter, &subiter);
+ sig = dbus_message_iter_get_signature (&subiter);
+
+ variant_type = dbus_gtype_from_signature (sig, context->proxy != NULL);
+ if (variant_type != G_TYPE_INVALID)
+ {
+ g_value_init (value, variant_type);
+
+ if (!dbus_gvalue_demarshal (context, &subiter, value, error))
+ {
+ dbus_free (sig);
+ return FALSE;
+ }
+ }
+ dbus_free (sig);
+ return TRUE;
+}
+
+static gboolean
+demarshal_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+
+{
+ GValue *variant_val;
+ variant_val = g_new0 (GValue, 1);
+
+ if (!demarshal_static_variant (context, iter, variant_val, error))
+ return FALSE;
+
+ g_value_set_boxed_take_ownership (value, variant_val);
+ return TRUE;
+}
+
+static gboolean
+demarshal_proxy (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ const char *name;
+ DBusGProxy *new_proxy;
+ const char *objpath;
+ int current_type;
+
+ current_type = dbus_message_iter_get_arg_type (iter);
+ g_assert (current_type == DBUS_TYPE_OBJECT_PATH);
+
+ g_assert (context->proxy != NULL);
+
+ name = dbus_g_proxy_get_bus_name (context->proxy);
+
+ dbus_message_iter_get_basic (iter, &objpath);
+
+ new_proxy = dbus_g_proxy_new_from_proxy (context->proxy, NULL, objpath);
+ g_value_set_object_take_ownership (value, new_proxy);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_object (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ const char *objpath;
+ int current_type;
+ GObject *obj;
+
+ current_type = dbus_message_iter_get_arg_type (iter);
+ g_assert (current_type == DBUS_TYPE_OBJECT_PATH);
+ g_assert (context->proxy == NULL);
+
+ dbus_message_iter_get_basic (iter, &objpath);
+
+ obj = dbus_g_connection_lookup_g_object (context->gconnection, objpath);
+ if (obj == NULL)
+ {
+ g_set_error (error,
+ DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Unregistered object at path '%s'"),
+ objpath);
return FALSE;
}
+ g_value_set_object (value, obj);
+
+ return TRUE;
}
-
+
+static gboolean
+demarshal_strv (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ DBusMessageIter subiter;
+ int current_type;
+ char **ret;
+ int len;
+ int i;
+
+ dbus_message_iter_recurse (iter, &subiter);
+
+ len = dbus_message_iter_get_array_len (&subiter);
+ g_assert (len >= 0);
+ ret = g_malloc (sizeof (char *) * (len + 1));
+
+ i = 0;
+ while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID)
+ {
+ g_assert (i < len);
+ g_assert (current_type == DBUS_TYPE_STRING);
+
+ dbus_message_iter_get_basic (&subiter, &(ret[i]));
+ ret[i] = g_strdup (ret[i]);
+
+ dbus_message_iter_next (&subiter);
+ i++;
+ }
+ ret[i] = NULL;
+ g_value_set_boxed_take_ownership (value, ret);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_garray_basic (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ DBusMessageIter subiter;
+ GArray *ret;
+ GType elt_gtype;
+ int elt_size;
+ void *msgarray;
+ int msgarray_len;
+
+ dbus_message_iter_recurse (iter, &subiter);
+
+ elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value));
+ g_assert (elt_gtype != G_TYPE_INVALID);
+ g_assert (dbus_g_type_is_fixed (elt_gtype));
+
+ elt_size = dbus_g_type_fixed_get_size (elt_gtype);
+
+ ret = g_array_new (FALSE, TRUE, elt_size);
+
+ msgarray = NULL;
+ dbus_message_iter_get_fixed_array (&subiter,
+ &msgarray,
+ &msgarray_len);
+ g_assert (msgarray != NULL);
+ g_assert (msgarray_len >= 0);
+ g_array_append_vals (ret, msgarray, (guint) msgarray_len);
+
+ g_value_set_boxed_take_ownership (value, ret);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_proxy_array (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ DBusMessageIter subiter;
+ GPtrArray *ret;
+ guint len;
+ guint i;
+ int current_type;
+
+ g_assert (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY);
+
+ dbus_message_iter_recurse (iter, &subiter);
+
+ len = dbus_message_iter_get_array_len (&subiter);
+ g_assert (len >= 0);
+ ret = g_ptr_array_sized_new (len);
+
+ i = 0;
+ while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID)
+ {
+ GValue subval = {0, };
+ g_assert (i < len);
+
+ if (!demarshal_proxy (context, &subiter, &subval, error))
+ {
+ for (i = 0; i < ret->len; i++)
+ g_object_unref (g_ptr_array_index (ret, i));
+ g_ptr_array_free (ret, TRUE);
+ return FALSE;
+ }
+
+ g_ptr_array_index (ret, i) = g_value_get_boxed (&subval);
+ /* Don't unset value, now owned by ret */
+
+ i++;
+ }
+ g_value_set_boxed_take_ownership (value, ret);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_ghashtable (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ GType gtype;
+ DBusMessageIter subiter;
+ int current_type;
+ GHashTable *ret;
+ GType key_gtype;
+ GType value_gtype;
+
+ current_type = dbus_message_iter_get_arg_type (iter);
+ g_assert (current_type == DBUS_TYPE_ARRAY);
+
+ gtype = G_VALUE_TYPE (value);
+
+ dbus_message_iter_recurse (iter, &subiter);
+
+ g_assert (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_DICT_ENTRY);
+
+ key_gtype = dbus_g_type_get_map_key_specialization (gtype);
+ g_assert (dbus_gtype_is_valid_hash_key (key_gtype));
+ value_gtype = dbus_g_type_get_map_value_specialization (gtype);
+ g_assert (dbus_gtype_is_valid_hash_value (value_gtype));
+
+ ret = g_hash_table_new_full (dbus_g_hash_func_from_gtype (key_gtype),
+ dbus_g_hash_equal_from_gtype (key_gtype),
+ dbus_g_hash_free_from_gtype (key_gtype),
+ dbus_g_hash_free_from_gtype (value_gtype));
+
+ while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID)
+ {
+ DBusMessageIter entry_iter;
+ GValue key_value = {0,};
+ GValue value_value = {0,};
+
+ current_type = dbus_message_iter_get_arg_type (&subiter);
+ g_assert (current_type == DBUS_TYPE_DICT_ENTRY);
+
+ dbus_message_iter_recurse (&subiter, &entry_iter);
+
+ g_value_init (&key_value, key_gtype);
+ if (!dbus_gvalue_demarshal (context,
+ &entry_iter,
+ &key_value,
+ error))
+ return FALSE;
+
+ dbus_message_iter_next (&entry_iter);
+
+ g_value_init (&value_value, value_gtype);
+ if (!dbus_gvalue_demarshal (context,
+ &entry_iter,
+ &value_value,
+ error))
+ return FALSE;
+
+ dbus_g_hash_table_insert_steal_values (ret,
+ &key_value,
+ &value_value);
+ /* Ownership of values passes to hash table, don't unset */
+
+ dbus_message_iter_next (&subiter);
+ }
+ g_value_set_boxed_take_ownership (value, ret);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_recurse (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ return FALSE;
+}
+
+gboolean
+dbus_gvalue_demarshal (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ GType gtype;
+ DBusGTypeMarshalData *typedata;
+
+ gtype = G_VALUE_TYPE (value);
+
+ typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
+ g_return_val_if_fail (typedata != NULL || g_type_is_a (gtype, DBUS_TYPE_G_VALUE), FALSE);
+
+ if (typedata == NULL)
+ {
+ if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE))
+ return demarshal_recurse (context, iter, value, error);
+ g_assert_not_reached ();
+ }
+ g_assert (typedata->vtable);
+ return typedata->vtable->demarshaller (context, iter, value, error);
+}
+
gboolean
-dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
+dbus_gvalue_demarshal_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ return demarshal_static_variant (context, iter, value, error);
+}
+
+GValueArray *
+dbus_gvalue_demarshal_message (DBusGValueMarshalCtx *context,
+ DBusMessage *message,
+ guint n_types,
+ const GType *types,
+ GError **error)
+{
+ GValueArray *ret;
+ DBusMessageIter iter;
+ int current_type;
+ guint index;
+
+ ret = g_value_array_new (6); /* 6 is a typical maximum for arguments */
+
+ dbus_message_iter_init (message, &iter);
+ index = 0;
+ while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
+ {
+ GValue *value;
+ GType gtype;
+
+ if (index >= n_types)
+ {
+ g_set_error (error, DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Too many arguments in message"));
+ goto lose;
+ }
+
+ g_value_array_append (ret, NULL);
+ value = g_value_array_get_nth (ret, index);
+
+ gtype = types[index];
+ g_value_init (value, gtype);
+
+ if (!dbus_gvalue_demarshal (context, &iter, value, error))
+ goto lose;
+ dbus_message_iter_next (&iter);
+ index++;
+ }
+ if (index < n_types)
+ {
+ g_set_error (error, DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Too few arguments in message"));
+ goto lose;
+ }
+
+ return ret;
+ lose:
+ g_value_array_free (ret);
+ return NULL;
+}
+
+static gboolean
+marshal_basic (DBusMessageIter *iter, GValue *value)
{
GType value_type;
@@ -353,9 +1214,6 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
goto nomem;
}
return TRUE;
- /* long gets cut to 32 bits so the remote API is consistent
- * on all architectures
- */
case G_TYPE_LONG:
{
dbus_int32_t v = g_value_get_long (value);
@@ -424,9 +1282,10 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
return TRUE;
default:
- /* FIXME: we need to define custom boxed types for arrays
- etc. so we can map them transparently / pleasantly */
- return FALSE;
+ {
+ g_assert_not_reached ();
+ return FALSE;
+ }
}
nomem:
@@ -434,49 +1293,320 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
return FALSE;
}
-/* FIXME is there a better way to do this? */
+static gboolean
+marshal_strv (DBusMessageIter *iter,
+ GValue *value)
+{
+ DBusMessageIter subiter;
+ char **array;
+ char **elt;
+ gboolean ret;
+
+ g_assert (G_VALUE_TYPE (value) == g_strv_get_type ());
+
+ array = g_value_get_boxed (value);
+
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_ARRAY,
+ "s",
+ &subiter))
+ goto out;
+
+ for (elt = array; *elt; elt++)
+ {
+ if (!dbus_message_iter_append_basic (&subiter,
+ DBUS_TYPE_STRING,
+ elt))
+ goto out;
+ }
+
+ if (!dbus_message_iter_close_container (iter, &subiter))
+ goto out;
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+marshal_garray_basic (DBusMessageIter *iter,
+ GValue *value)
+{
+ GType elt_gtype;
+ DBusMessageIter subiter;
+ GArray *array;
+ guint elt_size;
+ const char *subsignature_str;
+ gboolean ret;
+
+ elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value));
+ /* FIXME - this means we can't send an array of DBusGValue right now... */
+ subsignature_str = dbus_gtype_to_signature (elt_gtype);
+ g_assert (subsignature_str != NULL);
+
+ elt_size = dbus_g_type_fixed_get_size (elt_gtype);
+
+ array = g_value_get_boxed (value);
+
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_ARRAY,
+ subsignature_str,
+ &subiter))
+ goto out;
+
+ /* TODO - This assumes that basic values are the same size
+ * is this always true? If it is we can probably avoid
+ * a lot of the overhead in _marshal_basic_instance...
+ */
+ if (!dbus_message_iter_append_fixed_array (&subiter,
+ subsignature_str[0],
+ &(array->data),
+ array->len))
+ goto out;
+
+ if (!dbus_message_iter_close_container (iter, &subiter))
+ goto out;
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+marshal_proxy (DBusMessageIter *iter,
+ GValue *value)
+{
+ const char *path;
+ DBusGProxy *proxy;
+
+ g_assert (G_VALUE_TYPE (value) == dbus_g_proxy_get_type ());
+
+ proxy = g_value_get_object (value);
+ path = dbus_g_proxy_get_path (proxy);
+
+ if (!dbus_message_iter_append_basic (iter,
+ DBUS_TYPE_OBJECT_PATH,
+ &path))
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean
+marshal_object (DBusMessageIter *iter,
+ GValue *value)
+{
+ const char *path;
+ GObject *obj;
+
+ obj = g_value_get_object (value);
+ path = _dbus_gobject_get_path (obj);
+
+ if (path == NULL)
+ /* FIXME should throw error */
+ return FALSE;
+
+ if (!dbus_message_iter_append_basic (iter,
+ DBUS_TYPE_OBJECT_PATH,
+ &path))
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean
+marshal_proxy_array (DBusMessageIter *iter,
+ GValue *value)
+{
+ DBusMessageIter subiter;
+ GPtrArray *array;
+ const char *subsignature_str;
+ gboolean ret;
+ guint i;
+
+ subsignature_str = dbus_gtype_to_signature (DBUS_TYPE_G_PROXY);
+ g_assert (subsignature_str != NULL);
+
+ array = g_value_get_boxed (value);
+
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_ARRAY,
+ subsignature_str,
+ &subiter))
+ goto out;
+
+ for (i = 0; i < array->len; i++)
+ {
+ GValue val = {0, };
+
+ g_value_init (&val, DBUS_TYPE_G_PROXY);
+ g_value_set_static_boxed (&val, g_ptr_array_index (array, i));
+
+ marshal_proxy (&subiter, &val);
+
+ g_value_unset (&val);
+ }
+
+ if (!dbus_message_iter_close_container (iter, &subiter))
+ goto out;
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+struct DBusGLibHashMarshalData
+{
+ const char *entry_sig;
+ DBusMessageIter *iter;
+ gboolean err;
+};
+
+static void
+marshal_map_entry (const GValue *key,
+ const GValue *value,
+ gpointer data)
+{
+ struct DBusGLibHashMarshalData *hashdata = data;
+ DBusMessageIter subiter;
+
+ if (hashdata->err)
+ return;
+
+ if (!dbus_message_iter_open_container (hashdata->iter,
+ DBUS_TYPE_DICT_ENTRY,
+ NULL,
+ &subiter))
+ goto lose;
+
+ if (!dbus_gvalue_marshal (&subiter, (GValue*) key))
+ goto lose;
+
+ if (!dbus_gvalue_marshal (&subiter, (GValue*) value))
+ goto lose;
+
+ if (!dbus_message_iter_close_container (hashdata->iter, &subiter))
+ goto lose;
+
+ return;
+ lose:
+ hashdata->err = TRUE;
+}
+
+static gboolean
+marshal_map (DBusMessageIter *iter,
+ GValue *value)
+{
+ GType gtype;
+ DBusMessageIter arr_iter;
+ gboolean ret;
+ struct DBusGLibHashMarshalData hashdata;
+ GType key_type;
+ GType value_type;
+ const char *key_sig;
+ const char *value_sig;
+ char *entry_sig;
+ char *array_sig;
+
+ gtype = G_VALUE_TYPE (value);
+
+ ret = FALSE;
+
+ key_type = dbus_g_type_get_map_key_specialization (gtype);
+ g_assert (dbus_gtype_is_valid_hash_key (key_type));
+ value_type = dbus_g_type_get_map_value_specialization (gtype);
+ g_assert (dbus_gtype_is_valid_hash_value (value_type));
+
+ key_sig = dbus_gtype_to_signature (key_type);
+ value_sig = dbus_gtype_to_signature (value_type);
+ entry_sig = g_strdup_printf ("%s%s", key_sig, value_sig);
+ array_sig = g_strdup_printf ("%c%s%c",
+ DBUS_DICT_ENTRY_BEGIN_CHAR,
+ entry_sig,
+ DBUS_DICT_ENTRY_END_CHAR);
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_ARRAY,
+ array_sig,
+ &arr_iter))
+ goto lose;
+
+ hashdata.iter = &arr_iter;
+ hashdata.err = FALSE;
+ hashdata.entry_sig = entry_sig;
+
+ dbus_g_type_map_value_iterate (value,
+ marshal_map_entry,
+ &hashdata);
+
+ if (!dbus_message_iter_close_container (iter, &arr_iter))
+ goto lose;
+
+ out:
+ g_free (entry_sig);
+ g_free (array_sig);
+ return !hashdata.err;
+ lose:
+ hashdata.err = TRUE;
+ goto out;
+}
+
+static gboolean
+marshal_variant (DBusMessageIter *iter,
+ GValue *value)
+{
+ GType value_gtype;
+ DBusMessageIter subiter;
+ char *variant_sig;
+ GValue *real_value;
+ gboolean ret;
+
+ real_value = g_value_get_boxed (value);
+ value_gtype = G_VALUE_TYPE (real_value);
+
+ variant_sig = dbus_gvalue_to_signature (real_value);
+ if (variant_sig == NULL)
+ {
+ g_warning ("Unsupported value type \"%s\"",
+ g_type_name (value_gtype));
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_VARIANT,
+ variant_sig,
+ &subiter))
+ goto out;
+
+ if (!marshal_basic (&subiter, real_value))
+ goto out;
+
+ if (!dbus_message_iter_close_container (iter, &subiter))
+ goto out;
+
+ ret = TRUE;
+ out:
+ g_free (variant_sig);
+ return ret;
+}
+
+static gboolean
+marshal_recurse (DBusMessageIter *iter,
+ GValue *value)
+{
+ return FALSE;
+}
+
gboolean
-dbus_gvalue_store (GValue *value,
- gpointer storage)
+dbus_gvalue_marshal (DBusMessageIter *iter,
+ GValue *value)
{
- switch (G_VALUE_TYPE (value))
+ GType gtype;
+ DBusGTypeMarshalData *typedata;
+
+ gtype = G_VALUE_TYPE (value);
+
+ typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
+ if (typedata == NULL)
{
- case G_TYPE_CHAR:
- *((gchar *) storage) = g_value_get_char (value);
- return TRUE;
- case G_TYPE_UCHAR:
- *((guchar *) storage) = g_value_get_uchar (value);
- return TRUE;
- case G_TYPE_BOOLEAN:
- *((gboolean *) storage) = g_value_get_boolean (value);
- return TRUE;
- case G_TYPE_LONG:
- *((glong *) storage) = g_value_get_long (value);
- return TRUE;
- case G_TYPE_ULONG:
- *((gulong *) storage) = g_value_get_ulong (value);
- return TRUE;
- case G_TYPE_INT:
- *((gint *) storage) = g_value_get_int (value);
- return TRUE;
- case G_TYPE_UINT:
- *((guint *) storage) = g_value_get_uint (value);
- return TRUE;
- case G_TYPE_INT64:
- *((gint64 *) storage) = g_value_get_int64 (value);
- return TRUE;
- case G_TYPE_UINT64:
- *((guint64 *) storage) = g_value_get_uint64 (value);
- return TRUE;
- case G_TYPE_FLOAT:
- case G_TYPE_DOUBLE:
- *((gdouble *) storage) = g_value_get_double (value);
- return TRUE;
- case G_TYPE_STRING:
- /* FIXME - should optimize by not duping string twice */
- *((gchar **) storage) = g_value_dup_string (value);
- return TRUE;
- default:
+ if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE))
+ return marshal_recurse (iter, value);
return FALSE;
}
+ g_assert (typedata->vtable);
+ return typedata->vtable->marshaller (iter, value);
}
diff --git a/glib/dbus-gvalue.h b/glib/dbus-gvalue.h
index 4caa6880..54ef780b 100644
--- a/glib/dbus-gvalue.h
+++ b/glib/dbus-gvalue.h
@@ -2,40 +2,49 @@
#define DBUS_GOBJECT_VALUE_H
#include <dbus/dbus.h>
+#include <dbus/dbus-signature.h>
#include <glib.h>
#include <glib-object.h>
+#include "dbus/dbus-glib.h"
G_BEGIN_DECLS
-/* Used for return value storage */
-typedef union
-{
- gboolean gboolean_val;
- guchar guchar_val;
- gint int_val;
- gint64 gint64_val;
- guint64 guint64_val;
- double double_val;
- gpointer gpointer_val;
- char * chararray_val;
-} DBusBasicGValue;
+typedef struct {
+ DBusGConnection *gconnection;
+ DBusGProxy *proxy;
+} DBusGValueMarshalCtx;
-const char * dbus_gvalue_genmarshal_name_from_type (const char *type);
+void dbus_g_value_types_init (void);
-const char * dbus_gvalue_ctype_from_type (const char *type, gboolean in);
+GType dbus_gtype_from_signature (const char *signature,
+ gboolean is_client);
-const char * dbus_gtype_to_dbus_type (GType type);
+GType dbus_gtype_from_signature_iter (DBusSignatureIter *sigiter,
+ gboolean is_client);
-gboolean dbus_gvalue_init (int type,
- GValue *value);
+const char * dbus_gtype_to_signature (GType type);
-gboolean dbus_gvalue_demarshal (DBusMessageIter *iter,
- GValue *value);
-gboolean dbus_gvalue_marshal (DBusMessageIter *iter,
- GValue *value);
+GArray * dbus_gtypes_from_arg_signature (const char *signature,
+ gboolean is_client);
-gboolean dbus_gvalue_store (GValue *value,
- gpointer storage);
+gboolean dbus_gvalue_demarshal (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+
+gboolean dbus_gvalue_demarshal_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+
+GValueArray * dbus_gvalue_demarshal_message (DBusGValueMarshalCtx *context,
+ DBusMessage *message,
+ guint n_params,
+ const GType *types,
+ GError **error);
+
+gboolean dbus_gvalue_marshal (DBusMessageIter *iter,
+ GValue *value);
G_END_DECLS