+static GVariant *
+g_dbus_proxy_call_finish_internal (GDBusProxy *proxy,
+ GUnixFDList **out_fd_list,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GVariant *value;
+ ReplyData *data;
+
+ g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_proxy_call_internal);
+
+ value = NULL;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+ value = g_variant_ref (data->value);
+#ifdef G_OS_UNIX
+ if (out_fd_list != NULL)
+ *out_fd_list = data->fd_list != NULL ? g_object_ref (data->fd_list) : NULL;
+#endif
+
+ out:
+ return value;
+}
+
+static GVariant *
+g_dbus_proxy_call_sync_internal (GDBusProxy *proxy,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusCallFlags flags,
+ gint timeout_msec,
+ GUnixFDList *fd_list,
+ GUnixFDList **out_fd_list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVariant *ret;
+ gboolean was_split;
+ gchar *split_interface_name;
+ const gchar *split_method_name;
+ const gchar *target_method_name;
+ const gchar *target_interface_name;
+ gchar *destination;
+ GVariantType *reply_type;
+
+ g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
+ g_return_val_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name), NULL);
+ g_return_val_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
+ g_return_val_if_fail (timeout_msec == -1 || timeout_msec >= 0, NULL);
+#ifdef G_OS_UNIX
+ g_return_val_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list), NULL);
+#else
+ g_return_val_if_fail (fd_list == NULL, NULL);
+#endif
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ reply_type = NULL;
+
+ G_LOCK (properties_lock);
+
+ was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
+ target_method_name = was_split ? split_method_name : method_name;
+ target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
+
+ /* Warn if method is unexpected (cf. :g-interface-info) */
+ if (!was_split)
+ {
+ const GDBusMethodInfo *expected_method_info;
+ expected_method_info = lookup_method_info (proxy, target_method_name);
+ if (expected_method_info != NULL)
+ reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
+ }
+
+ destination = NULL;
+ if (proxy->priv->name != NULL)
+ {
+ destination = g_strdup (get_destination_for_call (proxy));
+ if (destination == NULL)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Cannot invoke method; proxy is for a well-known name without an owner and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag"));
+ ret = NULL;
+ G_UNLOCK (properties_lock);
+ goto out;
+ }
+ }
+
+ G_UNLOCK (properties_lock);
+
+#ifdef G_OS_UNIX
+ ret = g_dbus_connection_call_with_unix_fd_list_sync (proxy->priv->connection,
+ destination,
+ proxy->priv->object_path,
+ target_interface_name,
+ target_method_name,
+ parameters,
+ reply_type,
+ flags,
+ timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
+ fd_list,
+ out_fd_list,
+ cancellable,
+ error);
+#else
+ ret = g_dbus_connection_call_sync (proxy->priv->connection,
+ destination,
+ proxy->priv->object_path,
+ target_interface_name,
+ target_method_name,
+ parameters,
+ reply_type,
+ flags,
+ timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
+ cancellable,
+ error);
+#endif
+
+ out:
+ if (reply_type != NULL)
+ g_variant_type_free (reply_type);
+
+ g_free (destination);
+ g_free (split_interface_name);
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_proxy_call:
+ * @proxy: A #GDBusProxy.
+ * @method_name: Name of method to invoke.
+ * @parameters: (allow-none): A #GVariant tuple with parameters for the signal or %NULL if not passing parameters.
+ * @flags: Flags from the #GDBusCallFlags enumeration.
+ * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
+ * "infinite") or -1 to use the proxy default timeout.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: (allow-none): A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
+ * care about the result of the method invocation.
+ * @user_data: The data to pass to @callback.
+ *
+ * Asynchronously invokes the @method_name method on @proxy.
+ *
+ * If @method_name contains any dots, then @name is split into interface and
+ * method name parts. This allows using @proxy for invoking methods on
+ * other interfaces.
+ *
+ * If the #GDBusConnection associated with @proxy is closed then
+ * the operation will fail with %G_IO_ERROR_CLOSED. If
+ * @cancellable is canceled, the operation will fail with
+ * %G_IO_ERROR_CANCELLED. If @parameters contains a value not
+ * compatible with the D-Bus protocol, the operation fails with
+ * %G_IO_ERROR_INVALID_ARGUMENT.
+ *
+ * If the @parameters #GVariant is floating, it is consumed. This allows
+ * convenient 'inline' use of g_variant_new(), e.g.:
+ * |[<!-- language="C" -->
+ * g_dbus_proxy_call (proxy,
+ * "TwoStrings",
+ * g_variant_new ("(ss)",
+ * "Thing One",
+ * "Thing Two"),
+ * G_DBUS_CALL_FLAGS_NONE,
+ * -1,
+ * NULL,
+ * (GAsyncReadyCallback) two_strings_done,
+ * &data);
+ * ]|
+ *
+ * If @proxy has an expected interface (see
+ * #GDBusProxy:g-interface-info) and @method_name is referenced by it,
+ * then the return value is checked against the return type.
+ *
+ * This is an asynchronous method. When the operation is finished,
+ * @callback will be invoked in the
+ * [thread-default main context][g-main-context-push-thread-default]
+ * of the thread you are calling this method from.
+ * You can then call g_dbus_proxy_call_finish() to get the result of
+ * the operation. See g_dbus_proxy_call_sync() for the synchronous
+ * version of this method.
+ *
+ * If @callback is %NULL then the D-Bus method call message will be sent with
+ * the %G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED flag set.
+ *
+ * Since: 2.26
+ */
+void
+g_dbus_proxy_call (GDBusProxy *proxy,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusCallFlags flags,
+ gint timeout_msec,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_dbus_proxy_call_internal (proxy, method_name, parameters, flags, timeout_msec, NULL, cancellable, callback, user_data);
+}
+