* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: David Zeuthen <davidz@redhat.com>
*/
#include "gdbusobjectmanagerclient.h"
#include "gdbusobject.h"
#include "gdbusprivate.h"
-#include "gio-marshal.h"
#include "gioenumtypes.h"
#include "ginitable.h"
#include "gasyncresult.h"
*
* #GDBusObjectManagerClient is used to create, monitor and delete object
* proxies for remote objects exported by a #GDBusObjectManagerServer (or any
- * code implementing the <ulink
- * url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">org.freedesktop.DBus.ObjectManager</ulink>
+ * code implementing the
+ * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
* interface).
*
* Once an instance of this type has been created, you can connect to
*
* Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy
* instances. All signals (including the
- * <literal>org.freedesktop.DBus.Properties::PropertiesChanged</literal>
- * signal) delivered to #GDBusProxy instances are guaranteed to
- * originate from the name owner. This guarantee along with the
- * behavior described above, means that certain race conditions
- * including the <emphasis><quote>half the proxy is from the old owner
- * and the other half is from the new owner</quote></emphasis> problem
- * cannot happen.
+ * org.freedesktop.DBus.Properties::PropertiesChanged signal)
+ * delivered to #GDBusProxy instances are guaranteed to originate
+ * from the name owner. This guarantee along with the behavior
+ * described above, means that certain race conditions including the
+ * "half the proxy is from the old owner and the other half is from
+ * the new owner" problem cannot happen.
*
* To avoid having the application connect to signals on the returned
* #GDBusObjectProxy and #GDBusProxy objects, the
struct _GDBusObjectManagerClientPrivate
{
+ GMutex lock;
+
GBusType bus_type;
GDBusConnection *connection;
gchar *object_path;
GDBusProxyTypeFunc get_proxy_type_func;
gpointer get_proxy_type_user_data;
+ GDestroyNotify get_proxy_type_destroy_notify;
};
enum
PROP_NAME,
PROP_NAME_OWNER,
PROP_GET_PROXY_TYPE_FUNC,
- PROP_GET_PROXY_TYPE_USER_DATA
+ PROP_GET_PROXY_TYPE_USER_DATA,
+ PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
};
enum
static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT,
+ G_ADD_PRIVATE (GDBusObjectManagerClient)
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init));
if (manager->priv->control_proxy != NULL)
{
- g_warn_if_fail (g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
- on_control_proxy_g_signal,
- manager) == 1);
+ g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
+ on_control_proxy_g_signal,
+ manager);
g_object_unref (manager->priv->control_proxy);
}
g_object_unref (manager->priv->connection);
g_free (manager->priv->name);
g_free (manager->priv->name_owner);
+ if (manager->priv->get_proxy_type_destroy_notify != NULL)
+ manager->priv->get_proxy_type_destroy_notify (manager->priv->get_proxy_type_user_data);
+
+ g_mutex_clear (&manager->priv->lock);
+
if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
}
static void
g_dbus_object_manager_client_get_property (GObject *_object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
break;
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
break;
}
}
static void
g_dbus_object_manager_client_set_property (GObject *_object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
+ const gchar *name;
switch (prop_id)
{
case PROP_NAME:
g_assert (manager->priv->name == NULL);
- g_assert (g_dbus_is_name (g_value_get_string (value)));
- manager->priv->name = g_value_dup_string (value);
+ name = g_value_get_string (value);
+ g_assert (name == NULL || g_dbus_is_name (name));
+ manager->priv->name = g_strdup (name);
break;
case PROP_FLAGS:
manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
break;
+ case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY:
+ manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value);
+ break;
+
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
break;
}
}
* GDBusObjectManagerClient:connection:
*
* The #GDBusConnection to use.
+ *
+ * Since: 2.30
*/
g_object_class_install_property (gobject_class,
PROP_CONNECTION,
* #GDBusObjectManagerClient:connection must be %NULL and will be set to the
* #GDBusConnection obtained by calling g_bus_get() with the value
* of this property.
+ *
+ * Since: 2.30
*/
g_object_class_install_property (gobject_class,
PROP_BUS_TYPE,
* GDBusObjectManagerClient:flags:
*
* Flags from the #GDBusObjectManagerClientFlags enumeration.
+ *
+ * Since: 2.30
*/
g_object_class_install_property (gobject_class,
PROP_FLAGS,
* GDBusObjectManagerClient:object-path:
*
* The object path the manager is for.
+ *
+ * Since: 2.30
*/
g_object_class_install_property (gobject_class,
PROP_OBJECT_PATH,
* GDBusObjectManagerClient:name:
*
* The well-known name or unique name that the manager is for.
+ *
+ * Since: 2.30
*/
g_object_class_install_property (gobject_class,
PROP_NAME,
* The unique name that owns #GDBusObjectManagerClient:name or %NULL if
* no-one is currently owning the name. Connect to the
* #GObject::notify signal to track changes to this property.
+ *
+ * Since: 2.30
*/
g_object_class_install_property (gobject_class,
PROP_NAME_OWNER,
*
* The #GDBusProxyTypeFunc to use when determining what #GType to
* use for interface proxies or %NULL.
+ *
+ * Since: 2.30
*/
g_object_class_install_property (gobject_class,
PROP_GET_PROXY_TYPE_FUNC,
* GDBusObjectManagerClient:get-proxy-type-user-data:
*
* The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
+ *
+ * Since: 2.30
*/
g_object_class_install_property (gobject_class,
PROP_GET_PROXY_TYPE_USER_DATA,
G_PARAM_STATIC_STRINGS));
/**
+ * GDBusObjectManagerClient:get-proxy-type-destroy-notify:
+ *
+ * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data.
+ *
+ * Since: 2.30
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_GET_PROXY_TYPE_DESTROY_NOTIFY,
+ g_param_spec_pointer ("get-proxy-type-destroy-notify",
+ "GDBusProxyTypeFunc user data free function",
+ "The GDBusProxyTypeFunc user data free function",
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
* GDBusObjectManagerClient::interface-proxy-signal:
* @manager: The #GDBusObjectManagerClient emitting the signal.
* @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
* This signal is emitted in the
* <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
* that @manager was constructed in.
+ *
+ * Since: 2.30
*/
signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
g_signal_new ("interface-proxy-signal",
G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
NULL,
NULL,
- _gio_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANT,
+ NULL,
G_TYPE_NONE,
5,
G_TYPE_DBUS_OBJECT_PROXY,
* This signal is emitted in the
* <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
* that @manager was constructed in.
+ *
+ * Since: 2.30
*/
signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
g_signal_new ("interface-proxy-properties-changed",
G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
NULL,
NULL,
- _gio_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXED,
+ NULL,
G_TYPE_NONE,
4,
G_TYPE_DBUS_OBJECT_PROXY,
G_TYPE_DBUS_PROXY,
G_TYPE_VARIANT,
G_TYPE_STRV);
-
- g_type_class_add_private (klass, sizeof (GDBusObjectManagerClientPrivate));
}
static void
g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
{
- manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
- G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
- GDBusObjectManagerClientPrivate);
+ manager->priv = g_dbus_object_manager_client_get_instance_private (manager);
+ g_mutex_init (&manager->priv->lock);
manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
* g_dbus_object_manager_client_new_sync:
* @connection: A #GDBusConnection.
* @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
- * @name: The owner of the control object (unique or well-known name).
+ * @name: (allow-none): The owner of the control object (unique or well-known name), or %NULL when not using a message bus connection.
* @object_path: The object path of the control object.
- * @get_proxy_type_func: A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
+ * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
* @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
- * @cancellable: A #GCancellable or %NULL
+ * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
+ * @cancellable: (allow-none): A #GCancellable or %NULL
* @error: Return location for error or %NULL.
*
* Creates a new #GDBusObjectManagerClient object.
* blocked until a reply is received. See g_dbus_object_manager_client_new()
* for the asynchronous version.
*
- * Returns: A #GDBusObjectManagerClient object or %NULL if @error is
- * set. Free with g_object_unref().
+ * Returns: (transfer full) (type GDBusObjectManagerClient): A
+ * #GDBusObjectManagerClient object or %NULL if @error is set. Free
+ * with g_object_unref().
+ *
+ * Since: 2.30
*/
GDBusObjectManager *
g_dbus_object_manager_client_new_sync (GDBusConnection *connection,
const gchar *object_path,
GDBusProxyTypeFunc get_proxy_type_func,
gpointer get_proxy_type_user_data,
+ GDestroyNotify get_proxy_type_destroy_notify,
GCancellable *cancellable,
GError **error)
{
"object-path", object_path,
"get-proxy-type-func", get_proxy_type_func,
"get-proxy-type-user-data", get_proxy_type_user_data,
+ "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
NULL);
if (initable != NULL)
return G_DBUS_OBJECT_MANAGER (initable);
* @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
* @name: The owner of the control object (unique or well-known name).
* @object_path: The object path of the control object.
- * @get_proxy_type_func: A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
+ * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
* @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
- * @cancellable: A #GCancellable or %NULL
+ * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
+ * @cancellable: (allow-none): A #GCancellable or %NULL
* @callback: A #GAsyncReadyCallback to call when the request is satisfied.
* @user_data: The data to pass to @callback.
*
* of the thread you are calling this method from. You can
* then call g_dbus_object_manager_client_new_finish() to get the result. See
* g_dbus_object_manager_client_new_sync() for the synchronous version.
+ *
+ * Since: 2.30
*/
void
g_dbus_object_manager_client_new (GDBusConnection *connection,
const gchar *object_path,
GDBusProxyTypeFunc get_proxy_type_func,
gpointer get_proxy_type_user_data,
+ GDestroyNotify get_proxy_type_destroy_notify,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
"object-path", object_path,
"get-proxy-type-func", get_proxy_type_func,
"get-proxy-type-user-data", get_proxy_type_user_data,
+ "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
NULL);
}
*
* Finishes an operation started with g_dbus_object_manager_client_new().
*
- * Returns: A #GDBusObjectManagerClient object or %NULL if @error is
- * set. Free with g_object_unref().
+ * Returns: (transfer full) (type GDBusObjectManagerClient): A
+ * #GDBusObjectManagerClient object or %NULL if @error is set. Free
+ * with g_object_unref().
+ *
+ * Since: 2.30
*/
GDBusObjectManager *
g_dbus_object_manager_client_new_finish (GAsyncResult *res,
- GError **error)
+ GError **error)
{
GObject *object;
GObject *source_object;
* @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
* @name: The owner of the control object (unique or well-known name).
* @object_path: The object path of the control object.
- * @get_proxy_type_func: A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
+ * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
* @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
- * @cancellable: A #GCancellable or %NULL
+ * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
+ * @cancellable: (allow-none): A #GCancellable or %NULL
* @error: Return location for error or %NULL.
*
* Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
* blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
* for the asynchronous version.
*
- * Returns: A #GDBusObjectManagerClient object or %NULL if @error is
- * set. Free with g_object_unref().
+ * Returns: (transfer full) (type GDBusObjectManagerClient): A
+ * #GDBusObjectManagerClient object or %NULL if @error is set. Free
+ * with g_object_unref().
+ *
+ * Since: 2.30
*/
GDBusObjectManager *
g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type,
const gchar *object_path,
GDBusProxyTypeFunc get_proxy_type_func,
gpointer get_proxy_type_user_data,
+ GDestroyNotify get_proxy_type_destroy_notify,
GCancellable *cancellable,
GError **error)
{
"object-path", object_path,
"get-proxy-type-func", get_proxy_type_func,
"get-proxy-type-user-data", get_proxy_type_user_data,
+ "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
NULL);
if (initable != NULL)
return G_DBUS_OBJECT_MANAGER (initable);
* @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
* @name: The owner of the control object (unique or well-known name).
* @object_path: The object path of the control object.
- * @get_proxy_type_func: A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
+ * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
* @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
- * @cancellable: A #GCancellable or %NULL
+ * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
+ * @cancellable: (allow-none): A #GCancellable or %NULL
* @callback: A #GAsyncReadyCallback to call when the request is satisfied.
* @user_data: The data to pass to @callback.
*
* of the thread you are calling this method from. You can
* then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
* g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
+ *
+ * Since: 2.30
*/
void
g_dbus_object_manager_client_new_for_bus (GBusType bus_type,
const gchar *object_path,
GDBusProxyTypeFunc get_proxy_type_func,
gpointer get_proxy_type_user_data,
+ GDestroyNotify get_proxy_type_destroy_notify,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
"object-path", object_path,
"get-proxy-type-func", get_proxy_type_func,
"get-proxy-type-user-data", get_proxy_type_user_data,
+ "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
NULL);
}
*
* Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
*
- * Returns: A #GDBusObjectManagerClient object or %NULL if @error is
- * set. Free with g_object_unref().
+ * Returns: (transfer full) (type GDBusObjectManagerClient): A
+ * #GDBusObjectManagerClient object or %NULL if @error is set. Free
+ * with g_object_unref().
+ *
+ * Since: 2.30
*/
GDBusObjectManager *
g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
*
* Gets the #GDBusConnection used by @manager.
*
- * Returns: A #GDBusConnection object. Do not free, the object belongs
- * to @manager.
+ * Returns: (transfer none): A #GDBusConnection object. Do not free,
+ * the object belongs to @manager.
+ *
+ * Since: 2.30
*/
GDBusConnection *
g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
{
+ GDBusConnection *ret;
g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
- return manager->priv->connection;
+ g_mutex_lock (&manager->priv->lock);
+ ret = manager->priv->connection;
+ g_mutex_unlock (&manager->priv->lock);
+ return ret;
}
/**
* g_dbus_object_manager_client_get_name:
* @manager: A #GDBusObjectManagerClient
*
- * Gets the name that @manager is for.
+ * Gets the name that @manager is for, or %NULL if not a message bus
+ * connection.
*
* Returns: A unique or well-known name. Do not free, the string
* belongs to @manager.
+ *
+ * Since: 2.30
*/
const gchar *
g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager)
{
+ const gchar *ret;
g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
- return manager->priv->name;
+ g_mutex_lock (&manager->priv->lock);
+ ret = manager->priv->name;
+ g_mutex_unlock (&manager->priv->lock);
+ return ret;
}
/**
*
* Returns: Zero of more flags from the #GDBusObjectManagerClientFlags
* enumeration.
+ *
+ * Since: 2.30
*/
GDBusObjectManagerClientFlags
g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager)
{
+ GDBusObjectManagerClientFlags ret;
g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
- return manager->priv->flags;
+ g_mutex_lock (&manager->priv->lock);
+ ret = manager->priv->flags;
+ g_mutex_unlock (&manager->priv->lock);
+ return ret;
}
/**
*
* Returns: The name owner or %NULL if no name owner exists. Free with
* g_free().
+ *
+ * Since: 2.30
*/
gchar *
g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager)
{
+ gchar *ret;
g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
- return g_strdup (manager->priv->name_owner);
+ g_mutex_lock (&manager->priv->lock);
+ ret = g_strdup (manager->priv->name_owner);
+ g_mutex_unlock (&manager->priv->lock);
+ return ret;
}
/* ---------------------------------------------------------------------------------------------------- */
GDBusObjectProxy *object_proxy;
GDBusInterface *interface;
+ g_mutex_lock (&manager->priv->lock);
object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
if (object_proxy == NULL)
- goto out;
+ {
+ g_mutex_unlock (&manager->priv->lock);
+ goto out;
+ }
+ g_object_ref (object_proxy);
+ g_mutex_unlock (&manager->priv->lock);
//g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE));
+ g_object_ref (manager);
if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
{
if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
NULL);
}
/* ... and then synthesize the signal */
+ g_signal_emit_by_name (interface,
+ "g-properties-changed",
+ changed_properties,
+ invalidated_properties);
g_signal_emit (manager,
signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
0,
interface,
changed_properties,
invalidated_properties);
- g_signal_emit_by_name (interface,
- "g-properties-changed",
- changed_properties,
- invalidated_properties);
g_object_unref (interface);
}
g_variant_unref (changed_properties);
interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
if (interface != NULL)
{
+ g_signal_emit_by_name (interface,
+ "g-signal",
+ sender_name,
+ signal_name,
+ parameters);
g_signal_emit (manager,
signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
0,
sender_name,
signal_name,
parameters);
- g_signal_emit_by_name (interface,
- "g-signal",
- sender_name,
- signal_name,
- parameters);
g_object_unref (interface);
}
}
+ g_object_unref (manager);
out:
- ;
+ g_clear_object (&object_proxy);
}
static void
subscribe_signals (GDBusObjectManagerClient *manager,
const gchar *name_owner)
{
- GError *error;
+ GError *error = NULL;
GVariant *ret;
g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
g_return_if_fail (manager->priv->signal_subscription_id == 0);
- g_return_if_fail (g_dbus_is_unique_name (name_owner));
+ g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
- /* the bus daemon may not implement path_prefix so gracefully
- * handle this by using a fallback
- */
- manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
- name_owner,
- manager->priv->object_path);
-
- error = NULL;
- ret = g_dbus_connection_call_sync (manager->priv->connection,
- "org.freedesktop.DBus",
- "/org/freedeskop/DBus",
- "org.freedesktop.DBus",
- "AddMatch",
- g_variant_new ("(s)",
- manager->priv->match_rule),
- NULL, /* reply_type */
- G_DBUS_CALL_FLAGS_NONE,
- -1, /* default timeout */
- NULL, /* TODO: Cancellable */
- &error);
- if (ret != NULL)
+ if (name_owner != NULL)
{
+ /* Only add path_namespace if it's non-'/'. This removes a no-op key from
+ * the match rule, and also works around a D-Bus bug where
+ * path_namespace='/' matches nothing in D-Bus versions < 1.6.18.
+ *
+ * See: https://bugs.freedesktop.org/show_bug.cgi?id=70799 */
+ if (g_str_equal (manager->priv->object_path, "/"))
+ {
+ manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s'",
+ name_owner);
+ }
+ else
+ {
+ manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
+ name_owner, manager->priv->object_path);
+ }
+
+ /* The bus daemon may not implement path_namespace so gracefully
+ * handle this by using a fallback triggered if @error is set. */
+ ret = g_dbus_connection_call_sync (manager->priv->connection,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "AddMatch",
+ g_variant_new ("(s)",
+ manager->priv->match_rule),
+ NULL, /* reply_type */
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, /* default timeout */
+ NULL, /* TODO: Cancellable */
+ &error);
+
/* yay, bus daemon supports path_namespace */
- g_variant_unref (ret);
+ if (ret != NULL)
+ g_variant_unref (ret);
+ }
+ if (error == NULL)
+ {
/* still need to ask GDBusConnection for the callbacks */
manager->priv->signal_subscription_id =
g_dbus_connection_signal_subscribe (manager->priv->connection,
*/
g_dbus_connection_call (manager->priv->connection,
"org.freedesktop.DBus",
- "/org/freedeskop/DBus",
+ "/org/freedesktop/DBus",
"org.freedesktop.DBus",
"RemoveMatch",
g_variant_new ("(s)",
gchar *old_name_owner;
gchar *new_name_owner;
+ g_mutex_lock (&manager->priv->lock);
old_name_owner = manager->priv->name_owner;
new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
manager->priv->name_owner = NULL;
+ g_object_ref (manager);
if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
{
GList *l;
GList *proxies;
+ /* remote manager changed; nuke all local proxies */
+ proxies = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
+ g_list_foreach (proxies, (GFunc) g_object_ref, NULL);
+ g_hash_table_remove_all (manager->priv->map_object_path_to_object_proxy);
+
+ g_mutex_unlock (&manager->priv->lock);
+
/* do the :name-owner notify with a NULL name - this way the user knows
* the ::object-proxy-removed following is because the name owner went
* away
*/
g_object_notify (G_OBJECT (manager), "name-owner");
- /* remote manager changed; nuke all local proxies */
- proxies = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
- g_list_foreach (proxies, (GFunc) g_object_ref, NULL);
- g_hash_table_remove_all (manager->priv->map_object_path_to_object_proxy);
for (l = proxies; l != NULL; l = l->next)
{
GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY (l->data);
g_signal_emit_by_name (manager, "object-removed", object_proxy);
}
- g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
- g_list_free (proxies);
+ g_list_free_full (proxies, g_object_unref);
/* nuke local filter */
maybe_unsubscribe_signals (manager);
}
+ else
+ {
+ g_mutex_unlock (&manager->priv->lock);
+ }
if (new_name_owner != NULL)
{
/* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
* way the user knows that the signals were emitted because the name owner came back
*/
+ g_mutex_lock (&manager->priv->lock);
manager->priv->name_owner = new_name_owner;
+ g_mutex_unlock (&manager->priv->lock);
g_object_notify (G_OBJECT (manager), "name-owner");
}
g_free (old_name_owner);
+ g_object_unref (manager);
}
static gboolean
proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
- proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;;
+ proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
proxy_flags,
G_CALLBACK (on_notify_g_name_owner),
manager);
+ g_signal_connect (manager->priv->control_proxy,
+ "g-signal",
+ G_CALLBACK (on_control_proxy_g_signal),
+ manager);
+
manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
- if (manager->priv->name_owner == NULL)
+ if (manager->priv->name_owner == NULL && manager->priv->name != NULL)
{
/* it's perfectly fine if there's no name owner.. we're just going to
* wait until one is ready
}
else
{
- /* yay, we have a name owner */
- g_signal_connect (manager->priv->control_proxy,
- "g-signal",
- G_CALLBACK (on_control_proxy_g_signal),
- manager);
+ /* yay, we can get the objects */
subscribe_signals (manager,
manager->priv->name_owner);
value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
GVariantIter iter;
const gchar *interface_name;
GVariant *properties;
+ GList *interface_added_signals, *l;
+ GDBusProxy *interface_proxy;
- g_return_if_fail (g_dbus_is_unique_name (name_owner));
+ g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
+ g_mutex_lock (&manager->priv->lock);
+
+ interface_added_signals = NULL;
added = FALSE;
+
op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
if (op == NULL)
{
- op = _g_dbus_object_proxy_new (manager->priv->connection, object_path);
+ GType object_proxy_type;
+ if (manager->priv->get_proxy_type_func != NULL)
+ {
+ object_proxy_type = manager->priv->get_proxy_type_func (manager,
+ object_path,
+ NULL,
+ manager->priv->get_proxy_type_user_data);
+ g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
+ }
+ else
+ {
+ object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
+ }
+ op = g_object_new (object_proxy_type,
+ "g-connection", manager->priv->connection,
+ "g-object-path", object_path,
+ NULL);
added = TRUE;
}
+ g_object_ref (op);
g_variant_iter_init (&iter, ifaces_and_properties);
while (g_variant_iter_next (&iter,
&interface_name,
&properties))
{
- GDBusProxy *interface_proxy;
GError *error;
GType interface_proxy_type;
_g_dbus_object_proxy_add_interface (op, interface_proxy);
if (!added)
- g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
+ interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
g_object_unref (interface_proxy);
}
g_variant_unref (properties);
}
+ g_mutex_unlock (&manager->priv->lock);
+
+ /* now that we don't hold the lock any more, emit signals */
+ g_object_ref (manager);
+ for (l = interface_added_signals; l != NULL; l = l->next)
+ {
+ interface_proxy = G_DBUS_PROXY (l->data);
+ g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
+ g_object_unref (interface_proxy);
+ }
+ g_list_free (interface_added_signals);
+
if (added)
{
g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
op);
g_signal_emit_by_name (manager, "object-added", op);
}
+ g_object_unref (manager);
+ g_object_unref (op);
}
static void
guint num_interfaces;
guint num_interfaces_to_remove;
+ g_mutex_lock (&manager->priv->lock);
+
op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
if (op == NULL)
{
g_warning ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
G_STRLOC,
object_path);
+ g_mutex_unlock (&manager->priv->lock);
goto out;
}
interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
num_interfaces = g_list_length (interfaces);
- g_list_foreach (interfaces, (GFunc) g_object_unref, NULL);
- g_list_free (interfaces);
+ g_list_free_full (interfaces, g_object_unref);
num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
/* see if we are going to completety remove the object */
+ g_object_ref (manager);
if (num_interfaces_to_remove == num_interfaces)
{
g_object_ref (op);
g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
+ g_mutex_unlock (&manager->priv->lock);
g_signal_emit_by_name (manager, "object-removed", op);
g_object_unref (op);
}
else
{
+ g_object_ref (op);
+ g_mutex_unlock (&manager->priv->lock);
for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
{
GDBusInterface *interface;
g_object_unref (interface);
}
}
+ g_object_unref (op);
}
+ g_object_unref (manager);
out:
;
}
GVariant *ifaces_and_properties;
GVariantIter iter;
- g_return_if_fail (g_dbus_is_unique_name (name_owner));
+ g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
arg0 = g_variant_get_child_value (value, 0);
g_variant_iter_init (&iter, arg0);
GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
GDBusObject *ret;
+ g_mutex_lock (&manager->priv->lock);
ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
if (ret != NULL)
g_object_ref (ret);
+ g_mutex_unlock (&manager->priv->lock);
return ret;
}
g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
+ g_mutex_lock (&manager->priv->lock);
ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+ g_mutex_unlock (&manager->priv->lock);
+
return ret;
}