+static GVariant *
+decode_method_reply (GDBusMessage *reply,
+ const gchar *method_name,
+ const GVariantType *reply_type,
+ GError **error)
+{
+ GVariant *result;
+
+ result = NULL;
+ switch (g_dbus_message_get_message_type (reply))
+ {
+ case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ result = g_dbus_message_get_body (reply);
+ if (result == NULL)
+ {
+ result = g_variant_new ("()");
+ g_variant_ref_sink (result);
+ }
+ else
+ {
+ g_variant_ref (result);
+ }
+
+ if (!g_variant_is_of_type (result, reply_type))
+ {
+ gchar *type_string = g_variant_type_dup_string (reply_type);
+
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Method `%s' returned type `%s', but expected `%s'"),
+ method_name, g_variant_get_type_string (result), type_string);
+
+ g_variant_unref (result);
+ g_free (type_string);
+ result = NULL;
+ }
+ break;
+
+ case G_DBUS_MESSAGE_TYPE_ERROR:
+ g_dbus_message_to_gerror (reply, error);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return result;
+}
+
+
+typedef struct
+{
+ GSimpleAsyncResult *simple;
+ GVariantType *reply_type;
+ gchar *method_name; /* for error message */
+ guint32 serial;
+} CallState;
+
+static void
+g_dbus_connection_call_done (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (source);
+ CallState *state = user_data;
+ GError *error;
+ GDBusMessage *reply;
+ GVariant *value;
+
+ error = NULL;
+ reply = g_dbus_connection_send_message_with_reply_finish (connection,
+ result,
+ &error);
+
+ if (G_UNLIKELY (_g_dbus_debug_call ()))
+ {
+ _g_dbus_debug_print_lock ();
+ g_print ("========================================================================\n"
+ "GDBus-debug:Call:\n"
+ " <<<< ASYNC COMPLETE %s() (serial %d)\n"
+ " ",
+ state->method_name,
+ state->serial);
+ if (reply != NULL)
+ {
+ g_print ("SUCCESS\n");
+ }
+ else
+ {
+ g_print ("FAILED: %s\n",
+ error->message);
+ }
+ _g_dbus_debug_print_unlock ();
+ }
+
+
+ if (reply != NULL)
+ {
+ value = decode_method_reply (reply, state->method_name,
+ state->reply_type, &error);
+ g_object_unref (reply);
+ }
+ else
+ value = NULL;
+
+ if (value == NULL)
+ {
+ g_simple_async_result_set_from_error (state->simple, error);
+ g_error_free (error);
+ }
+ else
+ g_simple_async_result_set_op_res_gpointer (state->simple, value,
+ (GDestroyNotify) g_variant_unref);
+
+ g_simple_async_result_complete (state->simple);
+ g_variant_type_free (state->reply_type);
+ g_object_unref (state->simple);
+ g_free (state->method_name);
+
+ g_slice_free (CallState, state);
+}
+