summaryrefslogtreecommitdiffstats
path: root/glib/dbus-gobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'glib/dbus-gobject.c')
-rw-r--r--glib/dbus-gobject.c242
1 files changed, 187 insertions, 55 deletions
diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c
index 58291573..1dcf4bb9 100644
--- a/glib/dbus-gobject.c
+++ b/glib/dbus-gobject.c
@@ -143,45 +143,91 @@ method_arg_info_from_object_info (const DBusGObjectInfo *object,
return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
}
+typedef enum
+{
+ RETVAL_NONE,
+ RETVAL_NOERROR,
+ RETVAL_ERROR
+} RetvalType;
+
static const char *
arg_iterate (const char *data,
const char **name,
gboolean *in,
gboolean *constval,
+ RetvalType *retval,
const char **type)
{
- *name = data;
+ gboolean inarg;
+
+ if (name)
+ *name = data;
data = string_table_next (data);
switch (*data)
{
case 'I':
- *in = TRUE;
+ inarg = TRUE;
break;
case 'O':
- *in = FALSE;
+ inarg = FALSE;
break;
default:
g_warning ("invalid arg direction '%c'", *data);
+ inarg = FALSE;
break;
}
+ if (in)
+ *in = inarg;
- data = string_table_next (data);
- switch (*data)
+ if (!inarg)
{
- case 'F':
- *constval = FALSE;
- break;
- case 'C':
- *constval = TRUE;
- break;
- default:
- g_warning ("invalid arg const value '%c'", *data);
- break;
+ data = string_table_next (data);
+ switch (*data)
+ {
+ case 'F':
+ if (constval)
+ *constval = FALSE;
+ break;
+ case 'C':
+ if (constval)
+ *constval = TRUE;
+ break;
+ default:
+ g_warning ("invalid arg const value '%c'", *data);
+ break;
+ }
+ data = string_table_next (data);
+ switch (*data)
+ {
+ case 'N':
+ if (retval)
+ *retval = RETVAL_NONE;
+ break;
+ case 'E':
+ if (retval)
+ *retval = RETVAL_ERROR;
+ break;
+ case 'R':
+ if (retval)
+ *retval = RETVAL_NOERROR;
+ break;
+ default:
+ g_warning ("invalid arg ret value '%c'", *data);
+ break;
+ }
+ }
+ else
+ {
+ if (constval)
+ *constval = FALSE;
+ if (retval)
+ *retval = FALSE;
}
data = string_table_next (data);
- *type = data;
+ if (type)
+ *type = data;
return string_table_next (data);
}
@@ -202,10 +248,9 @@ method_dir_signature_from_object_info (const DBusGObjectInfo *object,
{
const char *name;
gboolean arg_in;
- gboolean constval;
const char *type;
- arg = arg_iterate (arg, &name, &arg_in, &constval, &type);
+ arg = arg_iterate (arg, &name, &arg_in, NULL, NULL, &type);
if (arg_in == in)
g_string_append (ret, type);
@@ -340,10 +385,9 @@ write_interface (gpointer key, gpointer val, gpointer user_data)
{
const char *name;
gboolean arg_in;
- gboolean constval;
const char *type;
- args = arg_iterate (args, &name, &arg_in, &constval, &type);
+ args = arg_iterate (args, &name, &arg_in, NULL, NULL, &type);
/* FIXME - handle container types */
g_string_append_printf (xml, " <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
@@ -846,15 +890,17 @@ invoke_object_method (GObject *object,
GValue return_value = {0,};
GClosure closure;
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;
+ gboolean have_retval;
+ gboolean retval_signals_error;
+ gboolean retval_is_synthetic;
+ gboolean retval_is_constant;
+ const char *arg_metadata;
gerror = NULL;
@@ -866,6 +912,11 @@ invoke_object_method (GObject *object,
else
call_only = FALSE;
+ have_retval = FALSE;
+ retval_signals_error = FALSE;
+ retval_is_synthetic = FALSE;
+ retval_is_constant = 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
@@ -924,21 +975,72 @@ invoke_object_method (GObject *object,
}
else
{
- out_signature = method_output_signature_from_object_info (object_info, method);
+ RetvalType retval;
+ gboolean arg_in;
+ gboolean arg_const;
+ const char *argsig;
- /* Count number of output parameters */
- dbus_signature_iter_init (&out_signature_iter, out_signature);
+ arg_metadata = method_arg_info_from_object_info (object_info, method);
+
+ /* Count number of output parameters, and look for a return value */
out_param_count = 0;
- while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
+ while (*arg_metadata)
+ {
+ arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
+ if (arg_in)
+ continue;
+ if (retval != RETVAL_NONE)
+ {
+ DBusSignatureIter tmp_sigiter;
+ /* This is the function return value */
+ g_assert (!have_retval);
+ have_retval = TRUE;
+ retval_is_synthetic = FALSE;
+
+ switch (retval)
+ {
+ case RETVAL_NONE:
+ g_assert_not_reached ();
+ break;
+ case RETVAL_NOERROR:
+ retval_signals_error = FALSE;
+ break;
+ case RETVAL_ERROR:
+ retval_signals_error = TRUE;
+ break;
+ }
+
+ retval_is_constant = arg_const;
+
+ /* Initialize our return GValue with the specified type */
+ dbus_signature_iter_init (&tmp_sigiter, argsig);
+ g_value_init (&return_value, dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
+ }
+ else
+ {
+ /* It's a regular output value */
+ out_param_count++;
+ }
+ }
+
+ /* For compatibility, if we haven't found a return value, we assume
+ * the function returns a gboolean for signalling an error
+ * (and therefore also takes a GError). We also note that it
+ * is a "synthetic" return value; i.e. we aren't going to be
+ * sending it over the bus, it's just to signal an error.
+ */
+ if (!have_retval)
{
- out_param_count++;
- dbus_signature_iter_next (&out_signature_iter);
+ have_retval = TRUE;
+ retval_is_synthetic = TRUE;
+ retval_signals_error = TRUE;
+ g_value_init (&return_value, G_TYPE_BOOLEAN);
}
- /* 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.
+ /* Create an array to store the actual values of OUT parameters
+ * (other than the real function return, if any). 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_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
@@ -948,16 +1050,32 @@ invoke_object_method (GObject *object,
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)
+
+ /* Reset argument metadata pointer */
+ arg_metadata = method_arg_info_from_object_info (object_info, method);
+
+ /* Iterate over output arguments again, this time allocating space for
+ * them as appopriate.
+ */
+ while (*arg_metadata)
{
GValue value = {0, };
GTypeCValue storage;
+ DBusSignatureIter tmp_sigiter;
+ GType current_gtype;
+
+ arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
+ /* Skip over input arguments and the return value, if any */
+ if (arg_in || retval != RETVAL_NONE)
+ continue;
+
+ dbus_signature_iter_init (&tmp_sigiter, argsig);
+ current_gtype = dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
g_value_init (&value, G_TYPE_POINTER);
/* We special case variants to make method invocation a bit nicer */
- if (current_type != DBUS_TYPE_VARIANT)
+ if (current_gtype != G_TYPE_VALUE)
{
memset (&storage, 0, sizeof (storage));
g_array_append_val (out_param_values, storage);
@@ -971,17 +1089,20 @@ invoke_object_method (GObject *object,
out_param_gvalue_pos++;
}
g_value_array_append (value_array, &value);
- dbus_signature_iter_next (&out_signature_iter);
}
+ }
- /* Append GError as final argument */
+ /* Append GError as final argument if necessary */
+ if (retval_signals_error)
+ {
+ g_assert (have_retval);
g_value_array_append (value_array, NULL);
g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
}
+
/* Actually invoke method */
- g_value_init (&return_value, G_TYPE_BOOLEAN);
- method->marshaller (&closure, &return_value,
+ method->marshaller (&closure, have_retval ? &return_value : NULL,
value_array->n_values,
value_array->values,
NULL, method->function);
@@ -990,22 +1111,35 @@ invoke_object_method (GObject *object,
result = DBUS_HANDLER_RESULT_HANDLED;
goto done;
}
- had_error = !g_value_get_boolean (&return_value);
+ if (retval_signals_error)
+ had_error = _dbus_gvalue_signals_error (&return_value);
+ else
+ had_error = FALSE;
if (!had_error)
{
DBusMessageIter iter;
- const char *arg_metadata;
-
- /* Grab the argument metadata and iterate over it */
- arg_metadata = method_arg_info_from_object_info (object_info, method);
reply = dbus_message_new_method_return (message);
if (reply == NULL)
goto nomem;
- /* Append OUT arguments to reply */
+ /* Append output arguments to reply */
dbus_message_iter_init_append (reply, &iter);
+
+ /* First, append the return value, unless it's synthetic */
+ if (have_retval && !retval_is_synthetic)
+ {
+ if (!dbus_gvalue_marshal (&iter, &return_value))
+ goto nomem;
+ if (!retval_is_constant)
+ g_value_unset (&return_value);
+ }
+
+ /* Grab the argument metadata and iterate over it */
+ arg_metadata = method_arg_info_from_object_info (object_info, method);
+
+ /* Now append any remaining return values */
out_param_pos = 0;
out_param_gvalue_pos = 0;
while (*arg_metadata)
@@ -1014,26 +1148,26 @@ invoke_object_method (GObject *object,
const char *arg_name;
gboolean arg_in;
gboolean constval;
+ RetvalType retval;
const char *arg_signature;
DBusSignatureIter argsigiter;
do
{
- /* Look for constness; skip over input arguments */
- arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &arg_signature);
+ /* Iterate over only output values; skip over input
+ arguments and the return value */
+ arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
}
- while (arg_in && *arg_metadata);
+ while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
- /* If the last argument we saw was input, we must be done iterating over
- * output arguments.
+ /* If the last argument we saw was input or the return
+ * value, we must be done iterating over output arguments.
*/
- if (arg_in)
+ if (arg_in || retval != RETVAL_NONE)
break;
dbus_signature_iter_init (&argsigiter, arg_signature);
- g_print ("looking at arg %s (%s)\n", arg_name, constval ? "TRUE" : "FALSE");
-
g_value_init (&gvalue, dbus_gtype_from_signature_iter (&argsigiter, FALSE));
if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
{
@@ -1070,14 +1204,12 @@ invoke_object_method (GObject *object,
result = DBUS_HANDLER_RESULT_HANDLED;
done:
g_free (in_signature);
- g_free (out_signature);
if (!call_only)
{
g_array_free (out_param_values, TRUE);
g_value_array_free (out_param_gvalues);
}
g_value_array_free (value_array);
- g_value_unset (&return_value);
return result;
nomem:
result = DBUS_HANDLER_RESULT_NEED_MEMORY;