xdgmime: plug a small leak
[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_clear_object (&proxy->priv->connection);
75
76   g_free (proxy->priv->object_path);
77
78   g_mutex_clear (&proxy->priv->lock);
79
80   if (G_OBJECT_CLASS (g_dbus_object_proxy_parent_class)->finalize != NULL)
81     G_OBJECT_CLASS (g_dbus_object_proxy_parent_class)->finalize (object);
82 }
83
84 static void
85 g_dbus_object_proxy_get_property (GObject    *object,
86                                   guint       prop_id,
87                                   GValue     *value,
88                                   GParamSpec *pspec)
89 {
90   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
91
92   switch (prop_id)
93     {
94     case PROP_G_OBJECT_PATH:
95       g_mutex_lock (&proxy->priv->lock);
96       g_value_set_string (value, proxy->priv->object_path);
97       g_mutex_unlock (&proxy->priv->lock);
98       break;
99
100     case PROP_G_CONNECTION:
101       g_value_set_object (value, g_dbus_object_proxy_get_connection (proxy));
102       break;
103
104     default:
105       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
106       break;
107     }
108 }
109
110 static void
111 g_dbus_object_proxy_set_property (GObject       *object,
112                                   guint          prop_id,
113                                   const GValue  *value,
114                                   GParamSpec    *pspec)
115 {
116   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
117
118   switch (prop_id)
119     {
120     case PROP_G_OBJECT_PATH:
121       g_mutex_lock (&proxy->priv->lock);
122       proxy->priv->object_path = g_value_dup_string (value);
123       g_mutex_unlock (&proxy->priv->lock);
124       break;
125
126     case PROP_G_CONNECTION:
127       g_mutex_lock (&proxy->priv->lock);
128       proxy->priv->connection = g_value_dup_object (value);
129       g_mutex_unlock (&proxy->priv->lock);
130       break;
131
132     default:
133       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
134       break;
135     }
136 }
137
138 static void
139 g_dbus_object_proxy_class_init (GDBusObjectProxyClass *klass)
140 {
141   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
142
143   gobject_class->finalize     = g_dbus_object_proxy_finalize;
144   gobject_class->set_property = g_dbus_object_proxy_set_property;
145   gobject_class->get_property = g_dbus_object_proxy_get_property;
146
147   /**
148    * GDBusObjectProxy:g-object-path:
149    *
150    * The object path of the proxy.
151    *
152    * Since: 2.30
153    */
154   g_object_class_install_property (gobject_class,
155                                    PROP_G_OBJECT_PATH,
156                                    g_param_spec_string ("g-object-path",
157                                                         "Object Path",
158                                                         "The object path of the proxy",
159                                                         NULL,
160                                                         G_PARAM_READWRITE |
161                                                         G_PARAM_CONSTRUCT_ONLY |
162                                                         G_PARAM_STATIC_STRINGS));
163
164   /**
165    * GDBusObjectProxy:g-connection:
166    *
167    * The connection of the proxy.
168    *
169    * Since: 2.30
170    */
171   g_object_class_install_property (gobject_class,
172                                    PROP_G_CONNECTION,
173                                    g_param_spec_object ("g-connection",
174                                                         "Connection",
175                                                         "The connection of the proxy",
176                                                         G_TYPE_DBUS_CONNECTION,
177                                                         G_PARAM_READWRITE |
178                                                         G_PARAM_CONSTRUCT_ONLY |
179                                                         G_PARAM_STATIC_STRINGS));
180
181   g_type_class_add_private (klass, sizeof (GDBusObjectProxyPrivate));
182 }
183
184 static void
185 g_dbus_object_proxy_init (GDBusObjectProxy *proxy)
186 {
187   proxy->priv = G_TYPE_INSTANCE_GET_PRIVATE (proxy,
188                                              G_TYPE_DBUS_OBJECT_PROXY,
189                                              GDBusObjectProxyPrivate);
190   g_mutex_init (&proxy->priv->lock);
191   proxy->priv->map_name_to_iface = g_hash_table_new_full (g_str_hash,
192                                                           g_str_equal,
193                                                           g_free,
194                                                           (GDestroyNotify) g_object_unref);
195 }
196
197 static const gchar *
198 g_dbus_object_proxy_get_object_path (GDBusObject *object)
199 {
200   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
201   const gchar *ret;
202   g_mutex_lock (&proxy->priv->lock);
203   ret = proxy->priv->object_path;
204   g_mutex_unlock (&proxy->priv->lock);
205   return ret;
206 }
207
208 /**
209  * g_dbus_object_proxy_get_connection:
210  * @proxy: a #GDBusObjectProxy
211  *
212  * Gets the connection that @proxy is for.
213  *
214  * Returns: (transfer none): A #GDBusConnection. Do not free, the
215  *   object is owned by @proxy.
216  *
217  * Since: 2.30
218  */
219 GDBusConnection *
220 g_dbus_object_proxy_get_connection (GDBusObjectProxy *proxy)
221 {
222   GDBusConnection *ret;
223   g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
224   g_mutex_lock (&proxy->priv->lock);
225   ret = proxy->priv->connection;
226   g_mutex_unlock (&proxy->priv->lock);
227   return ret;
228 }
229
230 static GDBusInterface *
231 g_dbus_object_proxy_get_interface (GDBusObject *object,
232                                    const gchar *interface_name)
233 {
234   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
235   GDBusProxy *ret;
236
237   g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
238   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
239
240   g_mutex_lock (&proxy->priv->lock);
241   ret = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
242   if (ret != NULL)
243     g_object_ref (ret);
244   g_mutex_unlock (&proxy->priv->lock);
245
246   return (GDBusInterface *) ret; /* TODO: proper cast */
247 }
248
249 static GList *
250 g_dbus_object_proxy_get_interfaces (GDBusObject *object)
251 {
252   GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
253   GList *ret;
254
255   g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
256
257   ret = NULL;
258
259   g_mutex_lock (&proxy->priv->lock);
260   ret = g_hash_table_get_values (proxy->priv->map_name_to_iface);
261   g_list_foreach (ret, (GFunc) g_object_ref, NULL);
262   g_mutex_unlock (&proxy->priv->lock);
263
264   return ret;
265 }
266
267 /* ---------------------------------------------------------------------------------------------------- */
268
269 /**
270  * g_dbus_object_proxy_new:
271  * @connection: a #GDBusConnection
272  * @object_path: the object path
273  *
274  * Creates a new #GDBusObjectProxy for the given connection and
275  * object path.
276  *
277  * Returns: a new #GDBusObjectProxy
278  *
279  * Since: 2.30
280  */
281 GDBusObjectProxy *
282 g_dbus_object_proxy_new (GDBusConnection *connection,
283                          const gchar     *object_path)
284 {
285   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
286   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
287   return G_DBUS_OBJECT_PROXY (g_object_new (G_TYPE_DBUS_OBJECT_PROXY,
288                                             "g-object-path", object_path,
289                                             "g-connection", connection,
290                                             NULL));
291 }
292
293 void
294 _g_dbus_object_proxy_add_interface (GDBusObjectProxy *proxy,
295                                     GDBusProxy       *interface_proxy)
296 {
297   const gchar *interface_name;
298   GDBusProxy *interface_proxy_to_remove;
299
300   g_return_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy));
301   g_return_if_fail (G_IS_DBUS_PROXY (interface_proxy));
302
303   g_mutex_lock (&proxy->priv->lock);
304
305   interface_name = g_dbus_proxy_get_interface_name (interface_proxy);
306   interface_proxy_to_remove = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
307   if (interface_proxy_to_remove != NULL)
308     {
309       g_object_ref (interface_proxy_to_remove);
310       g_warn_if_fail (g_hash_table_remove (proxy->priv->map_name_to_iface, interface_name));
311     }
312   g_hash_table_insert (proxy->priv->map_name_to_iface,
313                        g_strdup (interface_name),
314                        g_object_ref (interface_proxy));
315   g_object_ref (interface_proxy);
316
317   g_mutex_unlock (&proxy->priv->lock);
318
319   if (interface_proxy_to_remove != NULL)
320     {
321       g_signal_emit_by_name (proxy, "interface-removed", interface_proxy_to_remove);
322       g_object_unref (interface_proxy_to_remove);
323     }
324
325   g_signal_emit_by_name (proxy, "interface-added", interface_proxy);
326   g_object_unref (interface_proxy);
327 }
328
329 void
330 _g_dbus_object_proxy_remove_interface (GDBusObjectProxy *proxy,
331                                        const gchar      *interface_name)
332 {
333   GDBusProxy *interface_proxy;
334
335   g_return_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy));
336   g_return_if_fail (g_dbus_is_interface_name (interface_name));
337
338   g_mutex_lock (&proxy->priv->lock);
339
340   interface_proxy = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
341   if (interface_proxy != NULL)
342     {
343       g_object_ref (interface_proxy);
344       g_warn_if_fail (g_hash_table_remove (proxy->priv->map_name_to_iface, interface_name));
345       g_mutex_unlock (&proxy->priv->lock);
346       g_signal_emit_by_name (proxy, "interface-removed", interface_proxy);
347       g_object_unref (interface_proxy);
348     }
349   else
350     {
351       g_mutex_unlock (&proxy->priv->lock);
352     }
353 }
354
355 static void
356 dbus_object_interface_init (GDBusObjectIface *iface)
357 {
358   iface->get_object_path       = g_dbus_object_proxy_get_object_path;
359   iface->get_interfaces        = g_dbus_object_proxy_get_interfaces;
360   iface->get_interface         = g_dbus_object_proxy_get_interface;
361 }