X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdbusobjectmanagerclient.c;h=5755e74fb9616f00f9a391a6a5d900258617fc48;hb=51fac05d73f8363de821eb0d6940dedca13a8c0f;hp=74062e69c515e1068d55657b1a9aadd7eaff1661;hpb=ea742e88e30fc398b8f86cc017161e6dcbb61e08;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdbusobjectmanagerclient.c b/gio/gdbusobjectmanagerclient.c index 74062e6..5755e74 100644 --- a/gio/gdbusobjectmanagerclient.c +++ b/gio/gdbusobjectmanagerclient.c @@ -13,9 +13,7 @@ * 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 . * * Author: David Zeuthen */ @@ -26,7 +24,6 @@ #include "gdbusobjectmanagerclient.h" #include "gdbusobject.h" #include "gdbusprivate.h" -#include "gio-marshal.h" #include "gioenumtypes.h" #include "ginitable.h" #include "gasyncresult.h" @@ -48,8 +45,8 @@ * * #GDBusObjectManagerClient is used to create, monitor and delete object * proxies for remote objects exported by a #GDBusObjectManagerServer (or any - * code implementing the org.freedesktop.DBus.ObjectManager + * 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 @@ -89,18 +86,17 @@ * is set to the new name owner (this includes emission of the * #GObject::notify signal). Furthermore, you are guaranteed that * #GDBusObjectManagerClient:name-owner will alternate between a name owner - * (e.g. :1.42) and %NULL even in the case where + * (e.g. `:1.42`) and %NULL even in the case where * the name of interest is atomically replaced * * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy * instances. All signals (including the - * 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. + * 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 @@ -116,7 +112,7 @@ * #GDBusObjectManagerClient::interface-proxy-signal. * * Note that all callbacks and signals are emitted in the - * thread-default main loop + * [thread-default main context][g-main-context-push-thread-default] * that the #GDBusObjectManagerClient object was constructed * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects * originating from the #GDBusObjectManagerClient object will be created in @@ -126,6 +122,8 @@ struct _GDBusObjectManagerClientPrivate { + GMutex lock; + GBusType bus_type; GDBusConnection *connection; gchar *object_path; @@ -142,6 +140,7 @@ struct _GDBusObjectManagerClientPrivate GDBusProxyTypeFunc get_proxy_type_func; gpointer get_proxy_type_user_data; + GDestroyNotify get_proxy_type_destroy_notify; }; enum @@ -154,7 +153,8 @@ 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 @@ -171,6 +171,7 @@ static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface 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)); @@ -198,25 +199,31 @@ g_dbus_object_manager_client_finalize (GObject *object) 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); + if (manager->priv->connection != NULL) + g_object_unref (manager->priv->connection); g_free (manager->priv->object_path); 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); @@ -243,18 +250,19 @@ g_dbus_object_manager_client_get_property (GObject *_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) { @@ -279,8 +287,9 @@ g_dbus_object_manager_client_set_property (GObject *_object, 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: @@ -295,8 +304,12 @@ g_dbus_object_manager_client_set_property (GObject *_object, 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; } } @@ -462,6 +475,23 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) 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. @@ -476,7 +506,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) * connect signals to all interface proxies managed by @manager. * * This signal is emitted in the - * thread-default main loop + * [thread-default main context][g-main-context-push-thread-default] * that @manager was constructed in. * * Since: 2.30 @@ -488,7 +518,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) 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, @@ -514,7 +544,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) * connect signals to all interface proxies managed by @manager. * * This signal is emitted in the - * thread-default main loop + * [thread-default main context][g-main-context-push-thread-default] * that @manager was constructed in. * * Since: 2.30 @@ -526,23 +556,20 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) 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, @@ -555,11 +582,12 @@ g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager) * 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. @@ -581,6 +609,7 @@ 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) { @@ -601,6 +630,7 @@ g_dbus_object_manager_client_new_sync (GDBusConnection *connection "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); @@ -614,9 +644,10 @@ g_dbus_object_manager_client_new_sync (GDBusConnection *connection * @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. * @@ -624,7 +655,7 @@ g_dbus_object_manager_client_new_sync (GDBusConnection *connection * * This is an asynchronous failable constructor. When the result is * ready, @callback will be invoked in the - * thread-default main loop + * [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_object_manager_client_new_finish() to get the result. See * g_dbus_object_manager_client_new_sync() for the synchronous version. @@ -638,6 +669,7 @@ 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) @@ -658,6 +690,7 @@ g_dbus_object_manager_client_new (GDBusConnection *connection, "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); } @@ -676,7 +709,7 @@ g_dbus_object_manager_client_new (GDBusConnection *connection, */ GDBusObjectManager * g_dbus_object_manager_client_new_finish (GAsyncResult *res, - GError **error) + GError **error) { GObject *object; GObject *source_object; @@ -703,9 +736,10 @@ g_dbus_object_manager_client_new_finish (GAsyncResult *res, * @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 @@ -728,6 +762,7 @@ g_dbus_object_manager_client_new_for_bus_sync (GBusType bu 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) { @@ -747,6 +782,7 @@ g_dbus_object_manager_client_new_for_bus_sync (GBusType bu "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); @@ -760,9 +796,10 @@ g_dbus_object_manager_client_new_for_bus_sync (GBusType bu * @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. * @@ -771,7 +808,7 @@ g_dbus_object_manager_client_new_for_bus_sync (GBusType bu * * This is an asynchronous failable constructor. When the result is * ready, @callback will be invoked in the - * thread-default main loop + * [thread-default main loop][g-main-context-push-thread-default] * 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. @@ -785,6 +822,7 @@ g_dbus_object_manager_client_new_for_bus (GBusType bus_typ 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) @@ -804,6 +842,7 @@ g_dbus_object_manager_client_new_for_bus (GBusType bus_typ "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); } @@ -857,15 +896,20 @@ g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res, 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. @@ -875,8 +919,12 @@ g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager) 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; } /** @@ -893,8 +941,12 @@ g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager) 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; } /** @@ -906,16 +958,20 @@ g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager) * #GObject::notify signal to track changes to the * #GDBusObjectManagerClient:name-owner property. * - * Returns: The name owner or %NULL if no name owner exists. Free with - * g_free(). + * Returns: (nullable): 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; } /* ---------------------------------------------------------------------------------------------------- */ @@ -936,12 +992,19 @@ signal_cb (GDBusConnection *connection, 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) @@ -984,6 +1047,10 @@ signal_cb (GDBusConnection *connection, 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, @@ -991,10 +1058,6 @@ signal_cb (GDBusConnection *connection, 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); @@ -1007,6 +1070,11 @@ signal_cb (GDBusConnection *connection, 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, @@ -1015,55 +1083,66 @@ signal_cb (GDBusConnection *connection, 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, @@ -1131,7 +1210,7 @@ maybe_unsubscribe_signals (GDBusObjectManagerClient *manager) */ g_dbus_connection_call (manager->priv->connection, "org.freedesktop.DBus", - "/org/freedeskop/DBus", + "/org/freedesktop/DBus", "org.freedesktop.DBus", "RemoveMatch", g_variant_new ("(s)", @@ -1159,36 +1238,44 @@ on_notify_g_name_owner (GObject *object, 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) { @@ -1226,11 +1313,14 @@ on_notify_g_name_owner (GObject *object, /* 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 @@ -1255,7 +1345,7 @@ initable_init (GInitable *initable, 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, @@ -1273,8 +1363,13 @@ initable_init (GInitable *initable, 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 @@ -1282,11 +1377,7 @@ initable_init (GInitable *initable, } 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, @@ -1342,16 +1433,39 @@ add_interfaces (GDBusObjectManagerClient *manager, 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, @@ -1359,7 +1473,6 @@ add_interfaces (GDBusObjectManagerClient *manager, &interface_name, &properties)) { - GDBusProxy *interface_proxy; GError *error; GType interface_proxy_type; @@ -1423,12 +1536,24 @@ add_interfaces (GDBusObjectManagerClient *manager, _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, @@ -1436,6 +1561,8 @@ add_interfaces (GDBusObjectManagerClient *manager, op); g_signal_emit_by_name (manager, "object-added", op); } + g_object_unref (manager); + g_object_unref (op); } static void @@ -1449,32 +1576,38 @@ remove_interfaces (GDBusObjectManagerClient *manager, 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; @@ -1486,7 +1619,9 @@ remove_interfaces (GDBusObjectManagerClient *manager, g_object_unref (interface); } } + g_object_unref (op); } + g_object_unref (manager); out: ; } @@ -1501,7 +1636,7 @@ process_get_all_result (GDBusObjectManagerClient *manager, 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); @@ -1566,9 +1701,11 @@ g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager, 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; } @@ -1601,8 +1738,11 @@ g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager) 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; }