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