GDBus: switch to struct-embedded GMutex and GCond
[platform/upstream/glib.git] / gio / gdbusobjectproxy.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include "gdbusobject.h"
26 #include "gdbusobjectproxy.h"
27 #include "gdbusconnection.h"
28 #include "gdbusprivate.h"
29 #include "gdbusutils.h"
30 #include "gdbusproxy.h"
31
32 #include "glibintl.h"
33
34 /**
35  * SECTION:gdbusobjectproxy
36  * @short_description: Client-side D-Bus object
37  * @include: gio/gio.h
38  *
39  * A #GDBusObjectProxy is an object used to represent a remote object
40  * with one or more D-Bus interfaces. Normally, you don't instantiate
41  * a #GDBusObjectProxy yourself - typically #GDBusObjectManagerClient
42  * is used to obtain it.
43  *
44  * Since: 2.30
45  */
46
47 struct _GDBusObjectProxyPrivate
48 {
49   GMutex lock;
50   GHashTable *map_name_to_iface;
51   gchar *object_path;
52   GDBusConnection *connection;
53 };
54
55 enum
56 {
57   PROP_0,
58   PROP_G_OBJECT_PATH,
59   PROP_G_CONNECTION
60 };
61
62 static void dbus_object_interface_init (GDBusObjectIface *iface);
63
64 G_DEFINE_TYPE_WITH_CODE (GDBusObjectProxy, g_dbus_object_proxy, G_TYPE_OBJECT,
65                          G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT, dbus_object_interface_init));
66
67 static void
68 g_dbus_object_proxy_finalize (GObject *object)
69 {
70   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
71
72   g_hash_table_unref (proxy->priv->map_name_to_iface);
73
74   g_mutex_clear (&proxy->priv->lock);
75
76   if (G_OBJECT_CLASS (g_dbus_object_proxy_parent_class)->finalize != NULL)
77     G_OBJECT_CLASS (g_dbus_object_proxy_parent_class)->finalize (object);
78 }
79
80 static void
81 g_dbus_object_proxy_get_property (GObject    *object,
82                                   guint       prop_id,
83                                   GValue     *value,
84                                   GParamSpec *pspec)
85 {
86   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
87
88   switch (prop_id)
89     {
90     case PROP_G_OBJECT_PATH:
91       g_mutex_lock (&proxy->priv->lock);
92       g_value_set_string (value, proxy->priv->object_path);
93       g_mutex_unlock (&proxy->priv->lock);
94       break;
95
96     case PROP_G_CONNECTION:
97       g_value_set_object (value, g_dbus_object_proxy_get_connection (proxy));
98       break;
99
100     default:
101       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
102       break;
103     }
104 }
105
106 static void
107 g_dbus_object_proxy_set_property (GObject       *object,
108                                   guint          prop_id,
109                                   const GValue  *value,
110                                   GParamSpec    *pspec)
111 {
112   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
113
114   switch (prop_id)
115     {
116     case PROP_G_OBJECT_PATH:
117       g_mutex_lock (&proxy->priv->lock);
118       proxy->priv->object_path = g_value_dup_string (value);
119       g_mutex_unlock (&proxy->priv->lock);
120       break;
121
122     case PROP_G_CONNECTION:
123       g_mutex_lock (&proxy->priv->lock);
124       proxy->priv->connection = g_value_dup_object (value);
125       g_mutex_unlock (&proxy->priv->lock);
126       break;
127
128     default:
129       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
130       break;
131     }
132 }
133
134 static void
135 g_dbus_object_proxy_class_init (GDBusObjectProxyClass *klass)
136 {
137   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
138
139   gobject_class->finalize     = g_dbus_object_proxy_finalize;
140   gobject_class->set_property = g_dbus_object_proxy_set_property;
141   gobject_class->get_property = g_dbus_object_proxy_get_property;
142
143   /**
144    * GDBusObjectProxy:g-object-path:
145    *
146    * The object path of the proxy.
147    *
148    * Since: 2.30
149    */
150   g_object_class_install_property (gobject_class,
151                                    PROP_G_OBJECT_PATH,
152                                    g_param_spec_string ("g-object-path",
153                                                         "Object Path",
154                                                         "The object path of the proxy",
155                                                         NULL,
156                                                         G_PARAM_READWRITE |
157                                                         G_PARAM_CONSTRUCT_ONLY |
158                                                         G_PARAM_STATIC_STRINGS));
159
160   /**
161    * GDBusObjectProxy:g-connection:
162    *
163    * The connection of the proxy.
164    *
165    * Since: 2.30
166    */
167   g_object_class_install_property (gobject_class,
168                                    PROP_G_CONNECTION,
169                                    g_param_spec_object ("g-connection",
170                                                         "Connection",
171                                                         "The connection of the proxy",
172                                                         G_TYPE_DBUS_CONNECTION,
173                                                         G_PARAM_READWRITE |
174                                                         G_PARAM_CONSTRUCT_ONLY |
175                                                         G_PARAM_STATIC_STRINGS));
176
177   g_type_class_add_private (klass, sizeof (GDBusObjectProxyPrivate));
178 }
179
180 static void
181 g_dbus_object_proxy_init (GDBusObjectProxy *proxy)
182 {
183   proxy->priv = G_TYPE_INSTANCE_GET_PRIVATE (proxy,
184                                              G_TYPE_DBUS_OBJECT_PROXY,
185                                              GDBusObjectProxyPrivate);
186   g_mutex_init (&proxy->priv->lock);
187   proxy->priv->map_name_to_iface = g_hash_table_new_full (g_str_hash,
188                                                           g_str_equal,
189                                                           g_free,
190                                                           (GDestroyNotify) g_object_unref);
191 }
192
193 static const gchar *
194 g_dbus_object_proxy_get_object_path (GDBusObject *object)
195 {
196   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
197   const gchar *ret;
198   g_mutex_lock (&proxy->priv->lock);
199   ret = proxy->priv->object_path;
200   g_mutex_unlock (&proxy->priv->lock);
201   return ret;
202 }
203
204 /**
205  * g_dbus_object_proxy_get_connection:
206  * @proxy: a #GDBusObjectProxy
207  *
208  * Gets the connection that @proxy is for.
209  *
210  * Returns: (transfer none): A #GDBusConnection. Do not free, the
211  *   object is owned by @proxy.
212  *
213  * Since: 2.30
214  */
215 GDBusConnection *
216 g_dbus_object_proxy_get_connection (GDBusObjectProxy *proxy)
217 {
218   GDBusConnection *ret;
219   g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
220   g_mutex_lock (&proxy->priv->lock);
221   ret = proxy->priv->connection;
222   g_mutex_unlock (&proxy->priv->lock);
223   return ret;
224 }
225
226 static GDBusInterface *
227 g_dbus_object_proxy_get_interface (GDBusObject *object,
228                                    const gchar *interface_name)
229 {
230   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
231   GDBusProxy *ret;
232
233   g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
234   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
235
236   g_mutex_lock (&proxy->priv->lock);
237   ret = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
238   if (ret != NULL)
239     g_object_ref (ret);
240   g_mutex_unlock (&proxy->priv->lock);
241
242   return (GDBusInterface *) ret; /* TODO: proper cast */
243 }
244
245 static GList *
246 g_dbus_object_proxy_get_interfaces (GDBusObject *object)
247 {
248   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
249   GList *ret;
250
251   g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
252
253   ret = NULL;
254
255   g_mutex_lock (&proxy->priv->lock);
256   ret = g_hash_table_get_values (proxy->priv->map_name_to_iface);
257   g_list_foreach (ret, (GFunc) g_object_ref, NULL);
258   g_mutex_unlock (&proxy->priv->lock);
259
260   return ret;
261 }
262
263 /* ---------------------------------------------------------------------------------------------------- */
264
265 /**
266  * g_dbus_object_proxy_new:
267  * @connection: a #GDBusConnection
268  * @object_path: the object path
269  *
270  * Creates a new #GDBusObjectProxy for the given connection and
271  * object path.
272  *
273  * Returns: a new #GDBusObjectProxy
274  *
275  * Since: 2.30
276  */
277 GDBusObjectProxy *
278 g_dbus_object_proxy_new (GDBusConnection *connection,
279                          const gchar     *object_path)
280 {
281   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
282   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
283   return G_DBUS_OBJECT_PROXY (g_object_new (G_TYPE_DBUS_OBJECT_PROXY,
284                                             "g-object-path", object_path,
285                                             "g-connection", connection,
286                                             NULL));
287 }
288
289 void
290 _g_dbus_object_proxy_add_interface (GDBusObjectProxy *proxy,
291                                     GDBusProxy       *interface_proxy)
292 {
293   const gchar *interface_name;
294   GDBusProxy *interface_proxy_to_remove;
295
296   g_return_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy));
297   g_return_if_fail (G_IS_DBUS_PROXY (interface_proxy));
298
299   g_mutex_lock (&proxy->priv->lock);
300
301   interface_name = g_dbus_proxy_get_interface_name (interface_proxy);
302   interface_proxy_to_remove = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
303   if (interface_proxy_to_remove != NULL)
304     {
305       g_object_ref (interface_proxy_to_remove);
306       g_warn_if_fail (g_hash_table_remove (proxy->priv->map_name_to_iface, interface_name));
307     }
308   g_hash_table_insert (proxy->priv->map_name_to_iface,
309                        g_strdup (interface_name),
310                        g_object_ref (interface_proxy));
311   g_object_ref (interface_proxy);
312
313   g_mutex_unlock (&proxy->priv->lock);
314
315   if (interface_proxy_to_remove != NULL)
316     {
317       g_signal_emit_by_name (proxy, "interface-removed", interface_proxy_to_remove);
318       g_object_unref (interface_proxy_to_remove);
319     }
320
321   g_signal_emit_by_name (proxy, "interface-added", interface_proxy);
322   g_object_unref (interface_proxy);
323 }
324
325 void
326 _g_dbus_object_proxy_remove_interface (GDBusObjectProxy *proxy,
327                                        const gchar      *interface_name)
328 {
329   GDBusProxy *interface_proxy;
330
331   g_return_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy));
332   g_return_if_fail (g_dbus_is_interface_name (interface_name));
333
334   g_mutex_lock (&proxy->priv->lock);
335
336   interface_proxy = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
337   if (interface_proxy != NULL)
338     {
339       g_object_ref (interface_proxy);
340       g_warn_if_fail (g_hash_table_remove (proxy->priv->map_name_to_iface, interface_name));
341       g_mutex_unlock (&proxy->priv->lock);
342       g_signal_emit_by_name (proxy, "interface-removed", interface_proxy);
343       g_object_unref (interface_proxy);
344     }
345   else
346     {
347       g_mutex_unlock (&proxy->priv->lock);
348     }
349 }
350
351 static void
352 dbus_object_interface_init (GDBusObjectIface *iface)
353 {
354   iface->get_object_path       = g_dbus_object_proxy_get_object_path;
355   iface->get_interfaces        = g_dbus_object_proxy_get_interfaces;
356   iface->get_interface         = g_dbus_object_proxy_get_interface;
357 }