* name is tracked and can be read from
* #GDBusProxy:g-name-owner. Connect to the #GObject::notify signal to
* get notified of changes. Additionally, only signals and property
- * changes emitted from the current name owner are considered. This
- * avoids a number of race conditions when the name is lost by one
- * owner and claimed by another.
+ * changes emitted from the current name owner are considered and
+ * calls are always sent to the current name owner. This avoids a
+ * number of race conditions when the name is lost by one owner and
+ * claimed by another. However, if no name owner currently exists,
+ * then calls will be sent to the well-known name which may result in
+ * the message bus launching an owner (unless
+ * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START is set).
*
* The generic #GDBusProxy::g-properties-changed and #GDBusProxy::g-signal
* signals are not very convenient to work with. Therefore, the recommended
g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
proxy->priv->signals_subscriber_id);
- g_object_unref (proxy->priv->connection);
+ if (proxy->priv->connection != NULL)
+ g_object_unref (proxy->priv->connection);
g_free (proxy->priv->name);
g_free (proxy->priv->name_owner);
g_free (proxy->priv->object_path);
/* ---------------------------------------------------------------------------------------------------- */
+static gint
+property_name_sort_func (const gchar **a,
+ const gchar **b)
+{
+ return g_strcmp0 (*a, *b);
+}
+
/**
* g_dbus_proxy_get_cached_property_names:
* @proxy: A #GDBusProxy.
g_hash_table_iter_init (&iter, proxy->priv->properties);
while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL))
g_ptr_array_add (p, g_strdup (key));
- g_ptr_array_sort (p, (GCompareFunc) g_strcmp0);
+ g_ptr_array_sort (p, (GCompareFunc) property_name_sort_func);
g_ptr_array_add (p, NULL);
names = (gchar **) g_ptr_array_free (p, FALSE);
}
else
{
- g_simple_async_result_set_from_error (data->simple, error);
- g_error_free (error);
+ g_simple_async_result_take_error (data->simple, error);
g_simple_async_result_complete_in_idle (data->simple);
async_init_data_free (data);
goto out;
failed:
g_warn_if_fail (error != NULL);
- g_simple_async_result_set_from_error (data->simple, error);
- g_error_free (error);
+ g_simple_async_result_take_error (data->simple, error);
g_simple_async_result_complete_in_idle (data->simple);
async_init_data_free (data);
}
data->callback,
data->user_data,
NULL);
- g_simple_async_result_set_from_error (simple, error);
- g_error_free (error);
+ g_simple_async_result_take_error (simple, error);
g_simple_async_result_complete_in_idle (simple);
g_object_unref (simple);
}
* Creates a proxy for accessing @interface_name on the remote object
* at @object_path owned by @name at @connection and asynchronously
* loads D-Bus properties unless the
- * #G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used. Connect to
+ * %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used. Connect to
* the #GDBusProxy::g-properties-changed signal to get notified about
* property changes.
*
- * If the #G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
+ * If the %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
* match rules for signals. Connect to the #GDBusProxy::g-signal signal
* to handle signals from the remote object.
*
* If @name is a well-known name and the
- * #G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn't set and no name
+ * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn't set and no name
* owner currently exists, the message bus will be requested to launch
* a name owner for the name.
*
* Creates a proxy for accessing @interface_name on the remote object
* at @object_path owned by @name at @connection and synchronously
* loads D-Bus properties unless the
- * #G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used.
+ * %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used.
*
- * If the #G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
+ * If the %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
* match rules for signals. Connect to the #GDBusProxy::g-signal signal
* to handle signals from the remote object.
*
* If @name is a well-known name and the
- * #G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn't set and no name
+ * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn't set and no name
* owner currently exists, the message bus will be requested to launch
* a name owner for the name.
*
*
* Gets the connection @proxy is for.
*
- * Returns: A #GDBusConnection owned by @proxy. Do not free.
+ * Returns: (transfer none): A #GDBusConnection owned by @proxy. Do not free.
*
* Since: 2.26
*/
&error);
if (error != NULL)
{
- g_simple_async_result_set_from_error (simple,
- error);
- g_error_free (error);
+ g_simple_async_result_take_error (simple, error);
}
else
{
/* no need to complete in idle since the method GDBusConnection already does */
g_simple_async_result_complete (simple);
+ g_object_unref (simple);
}
static const GDBusMethodInfo *
return info;
}
+static const gchar *
+get_destination_for_call (GDBusProxy *proxy)
+{
+ const gchar *ret;
+
+ ret = NULL;
+
+ /* If proxy->priv->name is a unique name, then proxy->priv->name_owner
+ * is never NULL and always the same as proxy->priv->name. We use this
+ * knowledge to avoid checking if proxy->priv->name is a unique or
+ * well-known name.
+ */
+ ret = proxy->priv->name_owner;
+ if (ret != NULL)
+ goto out;
+
+ if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
+ goto out;
+
+ ret = proxy->priv->name;
+
+ out:
+ return ret;
+}
+
/**
* g_dbus_proxy_call:
* @proxy: A #GDBusProxy.
* @method_name: Name of method to invoke.
* @parameters: 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 or -1 to use the proxy default timeout.
+ * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
+ * "infinite") or -1 to use the proxy default timeout.
* @cancellable: A #GCancellable or %NULL.
* @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
* care about the result of the method invocation.
gboolean was_split;
gchar *split_interface_name;
const gchar *split_method_name;
- const GDBusMethodInfo *expected_method_info;
const gchar *target_method_name;
const gchar *target_interface_name;
+ const gchar *destination;
GVariantType *reply_type;
g_return_if_fail (G_IS_DBUS_PROXY (proxy));
g_return_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
+ reply_type = NULL;
+ split_interface_name = NULL;
+
simple = g_simple_async_result_new (G_OBJECT (proxy),
callback,
user_data,
target_method_name = was_split ? split_method_name : method_name;
target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
- g_object_set_data_full (G_OBJECT (simple), "-gdbus-proxy-method-name", g_strdup (target_method_name), g_free);
-
/* Warn if method is unexpected (cf. :g-interface-info) */
- expected_method_info = NULL;
if (!was_split)
- expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
+ {
+ const GDBusMethodInfo *expected_method_info;
+ expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
+ if (expected_method_info != NULL)
+ reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
+ }
- if (expected_method_info)
- reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
- else
- reply_type = NULL;
+ destination = NULL;
+ if (proxy->priv->name != NULL)
+ {
+ destination = get_destination_for_call (proxy);
+ if (destination == NULL)
+ {
+ g_simple_async_result_set_error (simple,
+ 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"));
+ goto out;
+ }
+ }
g_dbus_connection_call (proxy->priv->connection,
- proxy->priv->name_owner,
+ destination,
proxy->priv->object_path,
target_interface_name,
target_method_name,
(GAsyncReadyCallback) reply_cb,
simple);
+ out:
if (reply_type != NULL)
g_variant_type_free (reply_type);
{
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
GVariant *value;
- const char *method_name;
g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
if (g_simple_async_result_propagate_error (simple, error))
goto out;
- value = g_simple_async_result_get_op_res_gpointer (simple);
- method_name = g_object_get_data (G_OBJECT (simple), "-gdbus-proxy-method-name");
+ value = g_variant_ref (g_simple_async_result_get_op_res_gpointer (simple));
out:
return value;
* @method_name: Name of method to invoke.
* @parameters: 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 or -1 to use the proxy default timeout.
+ * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
+ * "infinite") or -1 to use the proxy default timeout.
* @cancellable: A #GCancellable or %NULL.
* @error: Return location for error or %NULL.
*
gboolean was_split;
gchar *split_interface_name;
const gchar *split_method_name;
- const GDBusMethodInfo *expected_method_info;
const gchar *target_method_name;
const gchar *target_interface_name;
+ const gchar *destination;
GVariantType *reply_type;
g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
g_return_val_if_fail (timeout_msec == -1 || timeout_msec >= 0, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ reply_type = NULL;
+
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;
- if (proxy->priv->expected_interface)
+ /* Warn if method is unexpected (cf. :g-interface-info) */
+ if (!was_split)
{
- expected_method_info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, target_method_name);
- if (expected_method_info == NULL)
- {
- g_warning ("Trying to invoke method `%s' which isn't in expected interface `%s'",
- target_method_name,
- target_interface_name);
- }
+ const GDBusMethodInfo *expected_method_info;
+ expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
+ if (expected_method_info != NULL)
+ reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
}
- else
+
+ destination = NULL;
+ if (proxy->priv->name != NULL)
{
- expected_method_info = NULL;
+ destination = 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;
+ goto out;
+ }
}
- if (expected_method_info)
- reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
- else
- reply_type = NULL;
-
ret = g_dbus_connection_call_sync (proxy->priv->connection,
- proxy->priv->name_owner,
+ destination,
proxy->priv->object_path,
target_interface_name,
target_method_name,
cancellable,
error);
+ out:
if (reply_type != NULL)
g_variant_type_free (reply_type);