nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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, see <http://www.gnu.org/licenses/>. |
||
17 | * |
||
18 | * Author: David Zeuthen <davidz@redhat.com> |
||
19 | */ |
||
20 | |||
21 | #include "config.h" |
||
22 | |||
23 | #include "gdbusobjectmanager.h" |
||
24 | #include "gdbusobjectmanagerclient.h" |
||
25 | #include "gdbusobject.h" |
||
26 | #include "gdbusprivate.h" |
||
27 | #include "gioenumtypes.h" |
||
28 | #include "ginitable.h" |
||
29 | #include "gasyncresult.h" |
||
30 | #include "gasyncinitable.h" |
||
31 | #include "gdbusconnection.h" |
||
32 | #include "gdbusutils.h" |
||
33 | #include "gdbusobject.h" |
||
34 | #include "gdbusobjectproxy.h" |
||
35 | #include "gdbusproxy.h" |
||
36 | #include "gdbusinterface.h" |
||
37 | |||
38 | #include "glibintl.h" |
||
39 | |||
40 | /** |
||
41 | * SECTION:gdbusobjectmanagerclient |
||
42 | * @short_description: Client-side object manager |
||
43 | * @include: gio/gio.h |
||
44 | * |
||
45 | * #GDBusObjectManagerClient is used to create, monitor and delete object |
||
46 | * proxies for remote objects exported by a #GDBusObjectManagerServer (or any |
||
47 | * code implementing the |
||
48 | * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) |
||
49 | * interface). |
||
50 | * |
||
51 | * Once an instance of this type has been created, you can connect to |
||
52 | * the #GDBusObjectManager::object-added and |
||
53 | * #GDBusObjectManager::object-removed signals and inspect the |
||
54 | * #GDBusObjectProxy objects returned by |
||
55 | * g_dbus_object_manager_get_objects(). |
||
56 | * |
||
57 | * If the name for a #GDBusObjectManagerClient is not owned by anyone at |
||
58 | * object construction time, the default behavior is to request the |
||
59 | * message bus to launch an owner for the name. This behavior can be |
||
60 | * disabled using the %G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START |
||
61 | * flag. It's also worth noting that this only works if the name of |
||
62 | * interest is activatable in the first place. E.g. in some cases it |
||
63 | * is not possible to launch an owner for the requested name. In this |
||
64 | * case, #GDBusObjectManagerClient object construction still succeeds but |
||
65 | * there will be no object proxies |
||
66 | * (e.g. g_dbus_object_manager_get_objects() returns the empty list) and |
||
67 | * the #GDBusObjectManagerClient:name-owner property is %NULL. |
||
68 | * |
||
69 | * The owner of the requested name can come and go (for example |
||
70 | * consider a system service being restarted) – #GDBusObjectManagerClient |
||
71 | * handles this case too; simply connect to the #GObject::notify |
||
72 | * signal to watch for changes on the #GDBusObjectManagerClient:name-owner |
||
73 | * property. When the name owner vanishes, the behavior is that |
||
74 | * #GDBusObjectManagerClient:name-owner is set to %NULL (this includes |
||
75 | * emission of the #GObject::notify signal) and then |
||
76 | * #GDBusObjectManager::object-removed signals are synthesized |
||
77 | * for all currently existing object proxies. Since |
||
78 | * #GDBusObjectManagerClient:name-owner is %NULL when this happens, you can |
||
79 | * use this information to disambiguate a synthesized signal from a |
||
80 | * genuine signal caused by object removal on the remote |
||
81 | * #GDBusObjectManager. Similarly, when a new name owner appears, |
||
82 | * #GDBusObjectManager::object-added signals are synthesized |
||
83 | * while #GDBusObjectManagerClient:name-owner is still %NULL. Only when all |
||
84 | * object proxies have been added, the #GDBusObjectManagerClient:name-owner |
||
85 | * is set to the new name owner (this includes emission of the |
||
86 | * #GObject::notify signal). Furthermore, you are guaranteed that |
||
87 | * #GDBusObjectManagerClient:name-owner will alternate between a name owner |
||
88 | * (e.g. `:1.42`) and %NULL even in the case where |
||
89 | * the name of interest is atomically replaced |
||
90 | * |
||
91 | * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy |
||
92 | * instances. All signals (including the |
||
93 | * org.freedesktop.DBus.Properties::PropertiesChanged signal) |
||
94 | * delivered to #GDBusProxy instances are guaranteed to originate |
||
95 | * from the name owner. This guarantee along with the behavior |
||
96 | * described above, means that certain race conditions including the |
||
97 | * "half the proxy is from the old owner and the other half is from |
||
98 | * the new owner" problem cannot happen. |
||
99 | * |
||
100 | * To avoid having the application connect to signals on the returned |
||
101 | * #GDBusObjectProxy and #GDBusProxy objects, the |
||
102 | * #GDBusObject::interface-added, |
||
103 | * #GDBusObject::interface-removed, |
||
104 | * #GDBusProxy::g-properties-changed and |
||
105 | * #GDBusProxy::g-signal signals |
||
106 | * are also emitted on the #GDBusObjectManagerClient instance managing these |
||
107 | * objects. The signals emitted are |
||
108 | * #GDBusObjectManager::interface-added, |
||
109 | * #GDBusObjectManager::interface-removed, |
||
110 | * #GDBusObjectManagerClient::interface-proxy-properties-changed and |
||
111 | * #GDBusObjectManagerClient::interface-proxy-signal. |
||
112 | * |
||
113 | * Note that all callbacks and signals are emitted in the |
||
114 | * [thread-default main context][g-main-context-push-thread-default] |
||
115 | * that the #GDBusObjectManagerClient object was constructed |
||
116 | * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects |
||
117 | * originating from the #GDBusObjectManagerClient object will be created in |
||
118 | * the same context and, consequently, will deliver signals in the |
||
119 | * same main loop. |
||
120 | */ |
||
121 | |||
122 | struct _GDBusObjectManagerClientPrivate |
||
123 | { |
||
124 | GMutex lock; |
||
125 | |||
126 | GBusType bus_type; |
||
127 | GDBusConnection *connection; |
||
128 | gchar *object_path; |
||
129 | gchar *name; |
||
130 | gchar *name_owner; |
||
131 | GDBusObjectManagerClientFlags flags; |
||
132 | |||
133 | GDBusProxy *control_proxy; |
||
134 | |||
135 | GHashTable *map_object_path_to_object_proxy; |
||
136 | |||
137 | guint signal_subscription_id; |
||
138 | gchar *match_rule; |
||
139 | |||
140 | GDBusProxyTypeFunc get_proxy_type_func; |
||
141 | gpointer get_proxy_type_user_data; |
||
142 | GDestroyNotify get_proxy_type_destroy_notify; |
||
143 | }; |
||
144 | |||
145 | enum |
||
146 | { |
||
147 | PROP_0, |
||
148 | PROP_BUS_TYPE, |
||
149 | PROP_CONNECTION, |
||
150 | PROP_FLAGS, |
||
151 | PROP_OBJECT_PATH, |
||
152 | PROP_NAME, |
||
153 | PROP_NAME_OWNER, |
||
154 | PROP_GET_PROXY_TYPE_FUNC, |
||
155 | PROP_GET_PROXY_TYPE_USER_DATA, |
||
156 | PROP_GET_PROXY_TYPE_DESTROY_NOTIFY |
||
157 | }; |
||
158 | |||
159 | enum |
||
160 | { |
||
161 | INTERFACE_PROXY_SIGNAL_SIGNAL, |
||
162 | INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL, |
||
163 | LAST_SIGNAL |
||
164 | }; |
||
165 | |||
166 | static guint signals[LAST_SIGNAL] = { 0 }; |
||
167 | |||
168 | static void initable_iface_init (GInitableIface *initable_iface); |
||
169 | static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface); |
||
170 | static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface); |
||
171 | |||
172 | G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT, |
||
173 | G_ADD_PRIVATE (GDBusObjectManagerClient) |
||
174 | G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init) |
||
175 | G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init) |
||
176 | G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init)); |
||
177 | |||
178 | static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager); |
||
179 | |||
180 | static void on_control_proxy_g_signal (GDBusProxy *proxy, |
||
181 | const gchar *sender_name, |
||
182 | const gchar *signal_name, |
||
183 | GVariant *parameters, |
||
184 | gpointer user_data); |
||
185 | |||
186 | static void process_get_all_result (GDBusObjectManagerClient *manager, |
||
187 | GVariant *value, |
||
188 | const gchar *name_owner); |
||
189 | |||
190 | static void |
||
191 | g_dbus_object_manager_client_finalize (GObject *object) |
||
192 | { |
||
193 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object); |
||
194 | |||
195 | maybe_unsubscribe_signals (manager); |
||
196 | |||
197 | g_hash_table_unref (manager->priv->map_object_path_to_object_proxy); |
||
198 | |||
199 | if (manager->priv->control_proxy != NULL) |
||
200 | { |
||
201 | g_signal_handlers_disconnect_by_func (manager->priv->control_proxy, |
||
202 | on_control_proxy_g_signal, |
||
203 | manager); |
||
204 | g_object_unref (manager->priv->control_proxy); |
||
205 | } |
||
206 | if (manager->priv->connection != NULL) |
||
207 | g_object_unref (manager->priv->connection); |
||
208 | g_free (manager->priv->object_path); |
||
209 | g_free (manager->priv->name); |
||
210 | g_free (manager->priv->name_owner); |
||
211 | |||
212 | if (manager->priv->get_proxy_type_destroy_notify != NULL) |
||
213 | manager->priv->get_proxy_type_destroy_notify (manager->priv->get_proxy_type_user_data); |
||
214 | |||
215 | g_mutex_clear (&manager->priv->lock); |
||
216 | |||
217 | if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL) |
||
218 | G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object); |
||
219 | } |
||
220 | |||
221 | static void |
||
222 | g_dbus_object_manager_client_get_property (GObject *_object, |
||
223 | guint prop_id, |
||
224 | GValue *value, |
||
225 | GParamSpec *pspec) |
||
226 | { |
||
227 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object); |
||
228 | |||
229 | switch (prop_id) |
||
230 | { |
||
231 | case PROP_CONNECTION: |
||
232 | g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager)); |
||
233 | break; |
||
234 | |||
235 | case PROP_OBJECT_PATH: |
||
236 | g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager))); |
||
237 | break; |
||
238 | |||
239 | case PROP_NAME: |
||
240 | g_value_set_string (value, g_dbus_object_manager_client_get_name (manager)); |
||
241 | break; |
||
242 | |||
243 | case PROP_FLAGS: |
||
244 | g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager)); |
||
245 | break; |
||
246 | |||
247 | case PROP_NAME_OWNER: |
||
248 | g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager)); |
||
249 | break; |
||
250 | |||
251 | default: |
||
252 | G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec); |
||
253 | break; |
||
254 | } |
||
255 | } |
||
256 | |||
257 | static void |
||
258 | g_dbus_object_manager_client_set_property (GObject *_object, |
||
259 | guint prop_id, |
||
260 | const GValue *value, |
||
261 | GParamSpec *pspec) |
||
262 | { |
||
263 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object); |
||
264 | const gchar *name; |
||
265 | |||
266 | switch (prop_id) |
||
267 | { |
||
268 | case PROP_BUS_TYPE: |
||
269 | manager->priv->bus_type = g_value_get_enum (value); |
||
270 | break; |
||
271 | |||
272 | case PROP_CONNECTION: |
||
273 | if (g_value_get_object (value) != NULL) |
||
274 | { |
||
275 | g_assert (manager->priv->connection == NULL); |
||
276 | g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value))); |
||
277 | manager->priv->connection = g_value_dup_object (value); |
||
278 | } |
||
279 | break; |
||
280 | |||
281 | case PROP_OBJECT_PATH: |
||
282 | g_assert (manager->priv->object_path == NULL); |
||
283 | g_assert (g_variant_is_object_path (g_value_get_string (value))); |
||
284 | manager->priv->object_path = g_value_dup_string (value); |
||
285 | break; |
||
286 | |||
287 | case PROP_NAME: |
||
288 | g_assert (manager->priv->name == NULL); |
||
289 | name = g_value_get_string (value); |
||
290 | g_assert (name == NULL || g_dbus_is_name (name)); |
||
291 | manager->priv->name = g_strdup (name); |
||
292 | break; |
||
293 | |||
294 | case PROP_FLAGS: |
||
295 | manager->priv->flags = g_value_get_flags (value); |
||
296 | break; |
||
297 | |||
298 | case PROP_GET_PROXY_TYPE_FUNC: |
||
299 | manager->priv->get_proxy_type_func = g_value_get_pointer (value); |
||
300 | break; |
||
301 | |||
302 | case PROP_GET_PROXY_TYPE_USER_DATA: |
||
303 | manager->priv->get_proxy_type_user_data = g_value_get_pointer (value); |
||
304 | break; |
||
305 | |||
306 | case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY: |
||
307 | manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value); |
||
308 | break; |
||
309 | |||
310 | default: |
||
311 | G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec); |
||
312 | break; |
||
313 | } |
||
314 | } |
||
315 | |||
316 | static void |
||
317 | g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) |
||
318 | { |
||
319 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
||
320 | |||
321 | gobject_class->finalize = g_dbus_object_manager_client_finalize; |
||
322 | gobject_class->set_property = g_dbus_object_manager_client_set_property; |
||
323 | gobject_class->get_property = g_dbus_object_manager_client_get_property; |
||
324 | |||
325 | /** |
||
326 | * GDBusObjectManagerClient:connection: |
||
327 | * |
||
328 | * The #GDBusConnection to use. |
||
329 | * |
||
330 | * Since: 2.30 |
||
331 | */ |
||
332 | g_object_class_install_property (gobject_class, |
||
333 | PROP_CONNECTION, |
||
334 | g_param_spec_object ("connection", |
||
335 | "Connection", |
||
336 | "The connection to use", |
||
337 | G_TYPE_DBUS_CONNECTION, |
||
338 | G_PARAM_READABLE | |
||
339 | G_PARAM_WRITABLE | |
||
340 | G_PARAM_CONSTRUCT_ONLY | |
||
341 | G_PARAM_STATIC_STRINGS)); |
||
342 | |||
343 | /** |
||
344 | * GDBusObjectManagerClient:bus-type: |
||
345 | * |
||
346 | * If this property is not %G_BUS_TYPE_NONE, then |
||
347 | * #GDBusObjectManagerClient:connection must be %NULL and will be set to the |
||
348 | * #GDBusConnection obtained by calling g_bus_get() with the value |
||
349 | * of this property. |
||
350 | * |
||
351 | * Since: 2.30 |
||
352 | */ |
||
353 | g_object_class_install_property (gobject_class, |
||
354 | PROP_BUS_TYPE, |
||
355 | g_param_spec_enum ("bus-type", |
||
356 | "Bus Type", |
||
357 | "The bus to connect to, if any", |
||
358 | G_TYPE_BUS_TYPE, |
||
359 | G_BUS_TYPE_NONE, |
||
360 | G_PARAM_WRITABLE | |
||
361 | G_PARAM_CONSTRUCT_ONLY | |
||
362 | G_PARAM_STATIC_NAME | |
||
363 | G_PARAM_STATIC_BLURB | |
||
364 | G_PARAM_STATIC_NICK)); |
||
365 | |||
366 | /** |
||
367 | * GDBusObjectManagerClient:flags: |
||
368 | * |
||
369 | * Flags from the #GDBusObjectManagerClientFlags enumeration. |
||
370 | * |
||
371 | * Since: 2.30 |
||
372 | */ |
||
373 | g_object_class_install_property (gobject_class, |
||
374 | PROP_FLAGS, |
||
375 | g_param_spec_flags ("flags", |
||
376 | "Flags", |
||
377 | "Flags for the proxy manager", |
||
378 | G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS, |
||
379 | G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, |
||
380 | G_PARAM_READABLE | |
||
381 | G_PARAM_WRITABLE | |
||
382 | G_PARAM_CONSTRUCT_ONLY | |
||
383 | G_PARAM_STATIC_NAME | |
||
384 | G_PARAM_STATIC_BLURB | |
||
385 | G_PARAM_STATIC_NICK)); |
||
386 | |||
387 | /** |
||
388 | * GDBusObjectManagerClient:object-path: |
||
389 | * |
||
390 | * The object path the manager is for. |
||
391 | * |
||
392 | * Since: 2.30 |
||
393 | */ |
||
394 | g_object_class_install_property (gobject_class, |
||
395 | PROP_OBJECT_PATH, |
||
396 | g_param_spec_string ("object-path", |
||
397 | "Object Path", |
||
398 | "The object path of the control object", |
||
399 | NULL, |
||
400 | G_PARAM_READABLE | |
||
401 | G_PARAM_WRITABLE | |
||
402 | G_PARAM_CONSTRUCT_ONLY | |
||
403 | G_PARAM_STATIC_STRINGS)); |
||
404 | |||
405 | /** |
||
406 | * GDBusObjectManagerClient:name: |
||
407 | * |
||
408 | * The well-known name or unique name that the manager is for. |
||
409 | * |
||
410 | * Since: 2.30 |
||
411 | */ |
||
412 | g_object_class_install_property (gobject_class, |
||
413 | PROP_NAME, |
||
414 | g_param_spec_string ("name", |
||
415 | "Name", |
||
416 | "Name that the manager is for", |
||
417 | NULL, |
||
418 | G_PARAM_READABLE | |
||
419 | G_PARAM_WRITABLE | |
||
420 | G_PARAM_CONSTRUCT_ONLY | |
||
421 | G_PARAM_STATIC_STRINGS)); |
||
422 | |||
423 | /** |
||
424 | * GDBusObjectManagerClient:name-owner: |
||
425 | * |
||
426 | * The unique name that owns #GDBusObjectManagerClient:name or %NULL if |
||
427 | * no-one is currently owning the name. Connect to the |
||
428 | * #GObject::notify signal to track changes to this property. |
||
429 | * |
||
430 | * Since: 2.30 |
||
431 | */ |
||
432 | g_object_class_install_property (gobject_class, |
||
433 | PROP_NAME_OWNER, |
||
434 | g_param_spec_string ("name-owner", |
||
435 | "Name Owner", |
||
436 | "The owner of the name we are watching", |
||
437 | NULL, |
||
438 | G_PARAM_READABLE | |
||
439 | G_PARAM_STATIC_STRINGS)); |
||
440 | |||
441 | /** |
||
442 | * GDBusObjectManagerClient:get-proxy-type-func: |
||
443 | * |
||
444 | * The #GDBusProxyTypeFunc to use when determining what #GType to |
||
445 | * use for interface proxies or %NULL. |
||
446 | * |
||
447 | * Since: 2.30 |
||
448 | */ |
||
449 | g_object_class_install_property (gobject_class, |
||
450 | PROP_GET_PROXY_TYPE_FUNC, |
||
451 | g_param_spec_pointer ("get-proxy-type-func", |
||
452 | "GDBusProxyTypeFunc Function Pointer", |
||
453 | "The GDBusProxyTypeFunc pointer to use", |
||
454 | G_PARAM_READABLE | |
||
455 | G_PARAM_WRITABLE | |
||
456 | G_PARAM_CONSTRUCT_ONLY | |
||
457 | G_PARAM_STATIC_STRINGS)); |
||
458 | |||
459 | /** |
||
460 | * GDBusObjectManagerClient:get-proxy-type-user-data: |
||
461 | * |
||
462 | * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func. |
||
463 | * |
||
464 | * Since: 2.30 |
||
465 | */ |
||
466 | g_object_class_install_property (gobject_class, |
||
467 | PROP_GET_PROXY_TYPE_USER_DATA, |
||
468 | g_param_spec_pointer ("get-proxy-type-user-data", |
||
469 | "GDBusProxyTypeFunc User Data", |
||
470 | "The GDBusProxyTypeFunc user_data", |
||
471 | G_PARAM_READABLE | |
||
472 | G_PARAM_WRITABLE | |
||
473 | G_PARAM_CONSTRUCT_ONLY | |
||
474 | G_PARAM_STATIC_STRINGS)); |
||
475 | |||
476 | /** |
||
477 | * GDBusObjectManagerClient:get-proxy-type-destroy-notify: |
||
478 | * |
||
479 | * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data. |
||
480 | * |
||
481 | * Since: 2.30 |
||
482 | */ |
||
483 | g_object_class_install_property (gobject_class, |
||
484 | PROP_GET_PROXY_TYPE_DESTROY_NOTIFY, |
||
485 | g_param_spec_pointer ("get-proxy-type-destroy-notify", |
||
486 | "GDBusProxyTypeFunc user data free function", |
||
487 | "The GDBusProxyTypeFunc user data free function", |
||
488 | G_PARAM_READABLE | |
||
489 | G_PARAM_WRITABLE | |
||
490 | G_PARAM_CONSTRUCT_ONLY | |
||
491 | G_PARAM_STATIC_STRINGS)); |
||
492 | |||
493 | /** |
||
494 | * GDBusObjectManagerClient::interface-proxy-signal: |
||
495 | * @manager: The #GDBusObjectManagerClient emitting the signal. |
||
496 | * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal. |
||
497 | * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal. |
||
498 | * @sender_name: The sender of the signal or NULL if the connection is not a bus connection. |
||
499 | * @signal_name: The signal name. |
||
500 | * @parameters: A #GVariant tuple with parameters for the signal. |
||
501 | * |
||
502 | * Emitted when a D-Bus signal is received on @interface_proxy. |
||
503 | * |
||
504 | * This signal exists purely as a convenience to avoid having to |
||
505 | * connect signals to all interface proxies managed by @manager. |
||
506 | * |
||
507 | * This signal is emitted in the |
||
508 | * [thread-default main context][g-main-context-push-thread-default] |
||
509 | * that @manager was constructed in. |
||
510 | * |
||
511 | * Since: 2.30 |
||
512 | */ |
||
513 | signals[INTERFACE_PROXY_SIGNAL_SIGNAL] = |
||
514 | g_signal_new (I_("interface-proxy-signal"), |
||
515 | G_TYPE_DBUS_OBJECT_MANAGER_CLIENT, |
||
516 | G_SIGNAL_RUN_LAST, |
||
517 | G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal), |
||
518 | NULL, |
||
519 | NULL, |
||
520 | NULL, |
||
521 | G_TYPE_NONE, |
||
522 | 5, |
||
523 | G_TYPE_DBUS_OBJECT_PROXY, |
||
524 | G_TYPE_DBUS_PROXY, |
||
525 | G_TYPE_STRING, |
||
526 | G_TYPE_STRING, |
||
527 | G_TYPE_VARIANT); |
||
528 | |||
529 | /** |
||
530 | * GDBusObjectManagerClient::interface-proxy-properties-changed: |
||
531 | * @manager: The #GDBusObjectManagerClient emitting the signal. |
||
532 | * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing. |
||
533 | * @interface_proxy: The #GDBusProxy that has properties that are changing. |
||
534 | * @changed_properties: A #GVariant containing the properties that changed. |
||
535 | * @invalidated_properties: A %NULL terminated array of properties that was invalidated. |
||
536 | * |
||
537 | * Emitted when one or more D-Bus properties on proxy changes. The |
||
538 | * local cache has already been updated when this signal fires. Note |
||
539 | * that both @changed_properties and @invalidated_properties are |
||
540 | * guaranteed to never be %NULL (either may be empty though). |
||
541 | * |
||
542 | * This signal exists purely as a convenience to avoid having to |
||
543 | * connect signals to all interface proxies managed by @manager. |
||
544 | * |
||
545 | * This signal is emitted in the |
||
546 | * [thread-default main context][g-main-context-push-thread-default] |
||
547 | * that @manager was constructed in. |
||
548 | * |
||
549 | * Since: 2.30 |
||
550 | */ |
||
551 | signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] = |
||
552 | g_signal_new (I_("interface-proxy-properties-changed"), |
||
553 | G_TYPE_DBUS_OBJECT_MANAGER_CLIENT, |
||
554 | G_SIGNAL_RUN_LAST, |
||
555 | G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed), |
||
556 | NULL, |
||
557 | NULL, |
||
558 | NULL, |
||
559 | G_TYPE_NONE, |
||
560 | 4, |
||
561 | G_TYPE_DBUS_OBJECT_PROXY, |
||
562 | G_TYPE_DBUS_PROXY, |
||
563 | G_TYPE_VARIANT, |
||
564 | G_TYPE_STRV); |
||
565 | } |
||
566 | |||
567 | static void |
||
568 | g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager) |
||
569 | { |
||
570 | manager->priv = g_dbus_object_manager_client_get_instance_private (manager); |
||
571 | g_mutex_init (&manager->priv->lock); |
||
572 | manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash, |
||
573 | g_str_equal, |
||
574 | g_free, |
||
575 | (GDestroyNotify) g_object_unref); |
||
576 | } |
||
577 | |||
578 | /* ---------------------------------------------------------------------------------------------------- */ |
||
579 | |||
580 | /** |
||
581 | * g_dbus_object_manager_client_new_sync: |
||
582 | * @connection: A #GDBusConnection. |
||
583 | * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration. |
||
584 | * @name: (allow-none): The owner of the control object (unique or well-known name), or %NULL when not using a message bus connection. |
||
585 | * @object_path: The object path of the control object. |
||
586 | * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies. |
||
587 | * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func. |
||
588 | * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL. |
||
589 | * @cancellable: (allow-none): A #GCancellable or %NULL |
||
590 | * @error: Return location for error or %NULL. |
||
591 | * |
||
592 | * Creates a new #GDBusObjectManagerClient object. |
||
593 | * |
||
594 | * This is a synchronous failable constructor - the calling thread is |
||
595 | * blocked until a reply is received. See g_dbus_object_manager_client_new() |
||
596 | * for the asynchronous version. |
||
597 | * |
||
598 | * Returns: (transfer full) (type GDBusObjectManagerClient): A |
||
599 | * #GDBusObjectManagerClient object or %NULL if @error is set. Free |
||
600 | * with g_object_unref(). |
||
601 | * |
||
602 | * Since: 2.30 |
||
603 | */ |
||
604 | GDBusObjectManager * |
||
605 | g_dbus_object_manager_client_new_sync (GDBusConnection *connection, |
||
606 | GDBusObjectManagerClientFlags flags, |
||
607 | const gchar *name, |
||
608 | const gchar *object_path, |
||
609 | GDBusProxyTypeFunc get_proxy_type_func, |
||
610 | gpointer get_proxy_type_user_data, |
||
611 | GDestroyNotify get_proxy_type_destroy_notify, |
||
612 | GCancellable *cancellable, |
||
613 | GError **error) |
||
614 | { |
||
615 | GInitable *initable; |
||
616 | |||
617 | g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); |
||
618 | g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) || |
||
619 | g_dbus_is_name (name), NULL); |
||
620 | g_return_val_if_fail (g_variant_is_object_path (object_path), NULL); |
||
621 | g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
||
622 | |||
623 | initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT, |
||
624 | cancellable, |
||
625 | error, |
||
626 | "connection", connection, |
||
627 | "flags", flags, |
||
628 | "name", name, |
||
629 | "object-path", object_path, |
||
630 | "get-proxy-type-func", get_proxy_type_func, |
||
631 | "get-proxy-type-user-data", get_proxy_type_user_data, |
||
632 | "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify, |
||
633 | NULL); |
||
634 | if (initable != NULL) |
||
635 | return G_DBUS_OBJECT_MANAGER (initable); |
||
636 | else |
||
637 | return NULL; |
||
638 | } |
||
639 | |||
640 | /** |
||
641 | * g_dbus_object_manager_client_new: |
||
642 | * @connection: A #GDBusConnection. |
||
643 | * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration. |
||
644 | * @name: The owner of the control object (unique or well-known name). |
||
645 | * @object_path: The object path of the control object. |
||
646 | * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies. |
||
647 | * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func. |
||
648 | * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL. |
||
649 | * @cancellable: (allow-none): A #GCancellable or %NULL |
||
650 | * @callback: A #GAsyncReadyCallback to call when the request is satisfied. |
||
651 | * @user_data: The data to pass to @callback. |
||
652 | * |
||
653 | * Asynchronously creates a new #GDBusObjectManagerClient object. |
||
654 | * |
||
655 | * This is an asynchronous failable constructor. When the result is |
||
656 | * ready, @callback will be invoked in the |
||
657 | * [thread-default main context][g-main-context-push-thread-default] |
||
658 | * of the thread you are calling this method from. You can |
||
659 | * then call g_dbus_object_manager_client_new_finish() to get the result. See |
||
660 | * g_dbus_object_manager_client_new_sync() for the synchronous version. |
||
661 | * |
||
662 | * Since: 2.30 |
||
663 | */ |
||
664 | void |
||
665 | g_dbus_object_manager_client_new (GDBusConnection *connection, |
||
666 | GDBusObjectManagerClientFlags flags, |
||
667 | const gchar *name, |
||
668 | const gchar *object_path, |
||
669 | GDBusProxyTypeFunc get_proxy_type_func, |
||
670 | gpointer get_proxy_type_user_data, |
||
671 | GDestroyNotify get_proxy_type_destroy_notify, |
||
672 | GCancellable *cancellable, |
||
673 | GAsyncReadyCallback callback, |
||
674 | gpointer user_data) |
||
675 | { |
||
676 | g_return_if_fail (G_IS_DBUS_CONNECTION (connection)); |
||
677 | g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) || |
||
678 | g_dbus_is_name (name)); |
||
679 | g_return_if_fail (g_variant_is_object_path (object_path)); |
||
680 | |||
681 | g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT, |
||
682 | G_PRIORITY_DEFAULT, |
||
683 | cancellable, |
||
684 | callback, |
||
685 | user_data, |
||
686 | "connection", connection, |
||
687 | "flags", flags, |
||
688 | "name", name, |
||
689 | "object-path", object_path, |
||
690 | "get-proxy-type-func", get_proxy_type_func, |
||
691 | "get-proxy-type-user-data", get_proxy_type_user_data, |
||
692 | "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify, |
||
693 | NULL); |
||
694 | } |
||
695 | |||
696 | /** |
||
697 | * g_dbus_object_manager_client_new_finish: |
||
698 | * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new(). |
||
699 | * @error: Return location for error or %NULL. |
||
700 | * |
||
701 | * Finishes an operation started with g_dbus_object_manager_client_new(). |
||
702 | * |
||
703 | * Returns: (transfer full) (type GDBusObjectManagerClient): A |
||
704 | * #GDBusObjectManagerClient object or %NULL if @error is set. Free |
||
705 | * with g_object_unref(). |
||
706 | * |
||
707 | * Since: 2.30 |
||
708 | */ |
||
709 | GDBusObjectManager * |
||
710 | g_dbus_object_manager_client_new_finish (GAsyncResult *res, |
||
711 | GError **error) |
||
712 | { |
||
713 | GObject *object; |
||
714 | GObject *source_object; |
||
715 | |||
716 | source_object = g_async_result_get_source_object (res); |
||
717 | g_assert (source_object != NULL); |
||
718 | |||
719 | object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), |
||
720 | res, |
||
721 | error); |
||
722 | g_object_unref (source_object); |
||
723 | |||
724 | if (object != NULL) |
||
725 | return G_DBUS_OBJECT_MANAGER (object); |
||
726 | else |
||
727 | return NULL; |
||
728 | } |
||
729 | |||
730 | /* ---------------------------------------------------------------------------------------------------- */ |
||
731 | |||
732 | /** |
||
733 | * g_dbus_object_manager_client_new_for_bus_sync: |
||
734 | * @bus_type: A #GBusType. |
||
735 | * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration. |
||
736 | * @name: The owner of the control object (unique or well-known name). |
||
737 | * @object_path: The object path of the control object. |
||
738 | * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies. |
||
739 | * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func. |
||
740 | * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL. |
||
741 | * @cancellable: (allow-none): A #GCancellable or %NULL |
||
742 | * @error: Return location for error or %NULL. |
||
743 | * |
||
744 | * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead |
||
745 | * of a #GDBusConnection. |
||
746 | * |
||
747 | * This is a synchronous failable constructor - the calling thread is |
||
748 | * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus() |
||
749 | * for the asynchronous version. |
||
750 | * |
||
751 | * Returns: (transfer full) (type GDBusObjectManagerClient): A |
||
752 | * #GDBusObjectManagerClient object or %NULL if @error is set. Free |
||
753 | * with g_object_unref(). |
||
754 | * |
||
755 | * Since: 2.30 |
||
756 | */ |
||
757 | GDBusObjectManager * |
||
758 | g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type, |
||
759 | GDBusObjectManagerClientFlags flags, |
||
760 | const gchar *name, |
||
761 | const gchar *object_path, |
||
762 | GDBusProxyTypeFunc get_proxy_type_func, |
||
763 | gpointer get_proxy_type_user_data, |
||
764 | GDestroyNotify get_proxy_type_destroy_notify, |
||
765 | GCancellable *cancellable, |
||
766 | GError **error) |
||
767 | { |
||
768 | GInitable *initable; |
||
769 | |||
770 | g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL); |
||
771 | g_return_val_if_fail (g_dbus_is_name (name), NULL); |
||
772 | g_return_val_if_fail (g_variant_is_object_path (object_path), NULL); |
||
773 | g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
||
774 | |||
775 | initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT, |
||
776 | cancellable, |
||
777 | error, |
||
778 | "bus-type", bus_type, |
||
779 | "flags", flags, |
||
780 | "name", name, |
||
781 | "object-path", object_path, |
||
782 | "get-proxy-type-func", get_proxy_type_func, |
||
783 | "get-proxy-type-user-data", get_proxy_type_user_data, |
||
784 | "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify, |
||
785 | NULL); |
||
786 | if (initable != NULL) |
||
787 | return G_DBUS_OBJECT_MANAGER (initable); |
||
788 | else |
||
789 | return NULL; |
||
790 | } |
||
791 | |||
792 | /** |
||
793 | * g_dbus_object_manager_client_new_for_bus: |
||
794 | * @bus_type: A #GBusType. |
||
795 | * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration. |
||
796 | * @name: The owner of the control object (unique or well-known name). |
||
797 | * @object_path: The object path of the control object. |
||
798 | * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies. |
||
799 | * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func. |
||
800 | * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL. |
||
801 | * @cancellable: (allow-none): A #GCancellable or %NULL |
||
802 | * @callback: A #GAsyncReadyCallback to call when the request is satisfied. |
||
803 | * @user_data: The data to pass to @callback. |
||
804 | * |
||
805 | * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a |
||
806 | * #GDBusConnection. |
||
807 | * |
||
808 | * This is an asynchronous failable constructor. When the result is |
||
809 | * ready, @callback will be invoked in the |
||
810 | * [thread-default main loop][g-main-context-push-thread-default] |
||
811 | * of the thread you are calling this method from. You can |
||
812 | * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See |
||
813 | * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version. |
||
814 | * |
||
815 | * Since: 2.30 |
||
816 | */ |
||
817 | void |
||
818 | g_dbus_object_manager_client_new_for_bus (GBusType bus_type, |
||
819 | GDBusObjectManagerClientFlags flags, |
||
820 | const gchar *name, |
||
821 | const gchar *object_path, |
||
822 | GDBusProxyTypeFunc get_proxy_type_func, |
||
823 | gpointer get_proxy_type_user_data, |
||
824 | GDestroyNotify get_proxy_type_destroy_notify, |
||
825 | GCancellable *cancellable, |
||
826 | GAsyncReadyCallback callback, |
||
827 | gpointer user_data) |
||
828 | { |
||
829 | g_return_if_fail (bus_type != G_BUS_TYPE_NONE); |
||
830 | g_return_if_fail (g_dbus_is_name (name)); |
||
831 | g_return_if_fail (g_variant_is_object_path (object_path)); |
||
832 | |||
833 | g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT, |
||
834 | G_PRIORITY_DEFAULT, |
||
835 | cancellable, |
||
836 | callback, |
||
837 | user_data, |
||
838 | "bus-type", bus_type, |
||
839 | "flags", flags, |
||
840 | "name", name, |
||
841 | "object-path", object_path, |
||
842 | "get-proxy-type-func", get_proxy_type_func, |
||
843 | "get-proxy-type-user-data", get_proxy_type_user_data, |
||
844 | "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify, |
||
845 | NULL); |
||
846 | } |
||
847 | |||
848 | /** |
||
849 | * g_dbus_object_manager_client_new_for_bus_finish: |
||
850 | * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus(). |
||
851 | * @error: Return location for error or %NULL. |
||
852 | * |
||
853 | * Finishes an operation started with g_dbus_object_manager_client_new_for_bus(). |
||
854 | * |
||
855 | * Returns: (transfer full) (type GDBusObjectManagerClient): A |
||
856 | * #GDBusObjectManagerClient object or %NULL if @error is set. Free |
||
857 | * with g_object_unref(). |
||
858 | * |
||
859 | * Since: 2.30 |
||
860 | */ |
||
861 | GDBusObjectManager * |
||
862 | g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res, |
||
863 | GError **error) |
||
864 | { |
||
865 | GObject *object; |
||
866 | GObject *source_object; |
||
867 | |||
868 | source_object = g_async_result_get_source_object (res); |
||
869 | g_assert (source_object != NULL); |
||
870 | |||
871 | object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), |
||
872 | res, |
||
873 | error); |
||
874 | g_object_unref (source_object); |
||
875 | |||
876 | if (object != NULL) |
||
877 | return G_DBUS_OBJECT_MANAGER (object); |
||
878 | else |
||
879 | return NULL; |
||
880 | } |
||
881 | |||
882 | /* ---------------------------------------------------------------------------------------------------- */ |
||
883 | |||
884 | /** |
||
885 | * g_dbus_object_manager_client_get_connection: |
||
886 | * @manager: A #GDBusObjectManagerClient |
||
887 | * |
||
888 | * Gets the #GDBusConnection used by @manager. |
||
889 | * |
||
890 | * Returns: (transfer none): A #GDBusConnection object. Do not free, |
||
891 | * the object belongs to @manager. |
||
892 | * |
||
893 | * Since: 2.30 |
||
894 | */ |
||
895 | GDBusConnection * |
||
896 | g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager) |
||
897 | { |
||
898 | GDBusConnection *ret; |
||
899 | g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL); |
||
900 | g_mutex_lock (&manager->priv->lock); |
||
901 | ret = manager->priv->connection; |
||
902 | g_mutex_unlock (&manager->priv->lock); |
||
903 | return ret; |
||
904 | } |
||
905 | |||
906 | /** |
||
907 | * g_dbus_object_manager_client_get_name: |
||
908 | * @manager: A #GDBusObjectManagerClient |
||
909 | * |
||
910 | * Gets the name that @manager is for, or %NULL if not a message bus |
||
911 | * connection. |
||
912 | * |
||
913 | * Returns: A unique or well-known name. Do not free, the string |
||
914 | * belongs to @manager. |
||
915 | * |
||
916 | * Since: 2.30 |
||
917 | */ |
||
918 | const gchar * |
||
919 | g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager) |
||
920 | { |
||
921 | const gchar *ret; |
||
922 | g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL); |
||
923 | g_mutex_lock (&manager->priv->lock); |
||
924 | ret = manager->priv->name; |
||
925 | g_mutex_unlock (&manager->priv->lock); |
||
926 | return ret; |
||
927 | } |
||
928 | |||
929 | /** |
||
930 | * g_dbus_object_manager_client_get_flags: |
||
931 | * @manager: A #GDBusObjectManagerClient |
||
932 | * |
||
933 | * Gets the flags that @manager was constructed with. |
||
934 | * |
||
935 | * Returns: Zero of more flags from the #GDBusObjectManagerClientFlags |
||
936 | * enumeration. |
||
937 | * |
||
938 | * Since: 2.30 |
||
939 | */ |
||
940 | GDBusObjectManagerClientFlags |
||
941 | g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager) |
||
942 | { |
||
943 | GDBusObjectManagerClientFlags ret; |
||
944 | g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE); |
||
945 | g_mutex_lock (&manager->priv->lock); |
||
946 | ret = manager->priv->flags; |
||
947 | g_mutex_unlock (&manager->priv->lock); |
||
948 | return ret; |
||
949 | } |
||
950 | |||
951 | /** |
||
952 | * g_dbus_object_manager_client_get_name_owner: |
||
953 | * @manager: A #GDBusObjectManagerClient. |
||
954 | * |
||
955 | * The unique name that owns the name that @manager is for or %NULL if |
||
956 | * no-one currently owns that name. You can connect to the |
||
957 | * #GObject::notify signal to track changes to the |
||
958 | * #GDBusObjectManagerClient:name-owner property. |
||
959 | * |
||
960 | * Returns: (nullable): The name owner or %NULL if no name owner |
||
961 | * exists. Free with g_free(). |
||
962 | * |
||
963 | * Since: 2.30 |
||
964 | */ |
||
965 | gchar * |
||
966 | g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager) |
||
967 | { |
||
968 | gchar *ret; |
||
969 | g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL); |
||
970 | g_mutex_lock (&manager->priv->lock); |
||
971 | ret = g_strdup (manager->priv->name_owner); |
||
972 | g_mutex_unlock (&manager->priv->lock); |
||
973 | return ret; |
||
974 | } |
||
975 | |||
976 | /* ---------------------------------------------------------------------------------------------------- */ |
||
977 | |||
978 | /* signal handler for all objects we manage - we dispatch signals |
||
979 | * from here to the objects |
||
980 | */ |
||
981 | static void |
||
982 | signal_cb (GDBusConnection *connection, |
||
983 | const gchar *sender_name, |
||
984 | const gchar *object_path, |
||
985 | const gchar *interface_name, |
||
986 | const gchar *signal_name, |
||
987 | GVariant *parameters, |
||
988 | gpointer user_data) |
||
989 | { |
||
990 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data); |
||
991 | GDBusObjectProxy *object_proxy; |
||
992 | GDBusInterface *interface; |
||
993 | |||
994 | g_mutex_lock (&manager->priv->lock); |
||
995 | object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path); |
||
996 | if (object_proxy == NULL) |
||
997 | { |
||
998 | g_mutex_unlock (&manager->priv->lock); |
||
999 | goto out; |
||
1000 | } |
||
1001 | g_object_ref (object_proxy); |
||
1002 | g_mutex_unlock (&manager->priv->lock); |
||
1003 | |||
1004 | //g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE)); |
||
1005 | |||
1006 | g_object_ref (manager); |
||
1007 | if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0) |
||
1008 | { |
||
1009 | if (g_strcmp0 (signal_name, "PropertiesChanged") == 0) |
||
1010 | { |
||
1011 | const gchar *interface_name; |
||
1012 | GVariant *changed_properties; |
||
1013 | const gchar **invalidated_properties; |
||
1014 | |||
1015 | g_variant_get (parameters, |
||
1016 | "(&s@a{sv}^a&s)", |
||
1017 | &interface_name, |
||
1018 | &changed_properties, |
||
1019 | &invalidated_properties); |
||
1020 | |||
1021 | interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name); |
||
1022 | if (interface != NULL) |
||
1023 | { |
||
1024 | GVariantIter property_iter; |
||
1025 | const gchar *property_name; |
||
1026 | GVariant *property_value; |
||
1027 | guint n; |
||
1028 | |||
1029 | /* update caches... */ |
||
1030 | g_variant_iter_init (&property_iter, changed_properties); |
||
1031 | while (g_variant_iter_next (&property_iter, |
||
1032 | "{&sv}", |
||
1033 | &property_name, |
||
1034 | &property_value)) |
||
1035 | { |
||
1036 | g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface), |
||
1037 | property_name, |
||
1038 | property_value); |
||
1039 | g_variant_unref (property_value); |
||
1040 | } |
||
1041 | |||
1042 | for (n = 0; invalidated_properties[n] != NULL; n++) |
||
1043 | { |
||
1044 | g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface), |
||
1045 | invalidated_properties[n], |
||
1046 | NULL); |
||
1047 | } |
||
1048 | /* ... and then synthesize the signal */ |
||
1049 | g_signal_emit_by_name (interface, |
||
1050 | "g-properties-changed", |
||
1051 | changed_properties, |
||
1052 | invalidated_properties); |
||
1053 | g_signal_emit (manager, |
||
1054 | signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL], |
||
1055 | 0, |
||
1056 | object_proxy, |
||
1057 | interface, |
||
1058 | changed_properties, |
||
1059 | invalidated_properties); |
||
1060 | g_object_unref (interface); |
||
1061 | } |
||
1062 | g_variant_unref (changed_properties); |
||
1063 | g_free (invalidated_properties); |
||
1064 | } |
||
1065 | } |
||
1066 | else |
||
1067 | { |
||
1068 | /* regular signal - just dispatch it */ |
||
1069 | interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name); |
||
1070 | if (interface != NULL) |
||
1071 | { |
||
1072 | g_signal_emit_by_name (interface, |
||
1073 | "g-signal", |
||
1074 | sender_name, |
||
1075 | signal_name, |
||
1076 | parameters); |
||
1077 | g_signal_emit (manager, |
||
1078 | signals[INTERFACE_PROXY_SIGNAL_SIGNAL], |
||
1079 | 0, |
||
1080 | object_proxy, |
||
1081 | interface, |
||
1082 | sender_name, |
||
1083 | signal_name, |
||
1084 | parameters); |
||
1085 | g_object_unref (interface); |
||
1086 | } |
||
1087 | } |
||
1088 | g_object_unref (manager); |
||
1089 | |||
1090 | out: |
||
1091 | g_clear_object (&object_proxy); |
||
1092 | } |
||
1093 | |||
1094 | static void |
||
1095 | subscribe_signals (GDBusObjectManagerClient *manager, |
||
1096 | const gchar *name_owner) |
||
1097 | { |
||
1098 | GError *error = NULL; |
||
1099 | GVariant *ret; |
||
1100 | |||
1101 | g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager)); |
||
1102 | g_return_if_fail (manager->priv->signal_subscription_id == 0); |
||
1103 | g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner)); |
||
1104 | |||
1105 | if (name_owner != NULL) |
||
1106 | { |
||
1107 | /* Only add path_namespace if it's non-'/'. This removes a no-op key from |
||
1108 | * the match rule, and also works around a D-Bus bug where |
||
1109 | * path_namespace='/' matches nothing in D-Bus versions < 1.6.18. |
||
1110 | * |
||
1111 | * See: https://bugs.freedesktop.org/show_bug.cgi?id=70799 */ |
||
1112 | if (g_str_equal (manager->priv->object_path, "/")) |
||
1113 | { |
||
1114 | manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s'", |
||
1115 | name_owner); |
||
1116 | } |
||
1117 | else |
||
1118 | { |
||
1119 | manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'", |
||
1120 | name_owner, manager->priv->object_path); |
||
1121 | } |
||
1122 | |||
1123 | /* The bus daemon may not implement path_namespace so gracefully |
||
1124 | * handle this by using a fallback triggered if @error is set. */ |
||
1125 | ret = g_dbus_connection_call_sync (manager->priv->connection, |
||
1126 | "org.freedesktop.DBus", |
||
1127 | "/org/freedesktop/DBus", |
||
1128 | "org.freedesktop.DBus", |
||
1129 | "AddMatch", |
||
1130 | g_variant_new ("(s)", |
||
1131 | manager->priv->match_rule), |
||
1132 | NULL, /* reply_type */ |
||
1133 | G_DBUS_CALL_FLAGS_NONE, |
||
1134 | -1, /* default timeout */ |
||
1135 | NULL, /* TODO: Cancellable */ |
||
1136 | &error); |
||
1137 | |||
1138 | /* yay, bus daemon supports path_namespace */ |
||
1139 | if (ret != NULL) |
||
1140 | g_variant_unref (ret); |
||
1141 | } |
||
1142 | |||
1143 | if (error == NULL) |
||
1144 | { |
||
1145 | /* still need to ask GDBusConnection for the callbacks */ |
||
1146 | manager->priv->signal_subscription_id = |
||
1147 | g_dbus_connection_signal_subscribe (manager->priv->connection, |
||
1148 | name_owner, |
||
1149 | NULL, /* interface */ |
||
1150 | NULL, /* member */ |
||
1151 | NULL, /* path - TODO: really want wilcard support here */ |
||
1152 | NULL, /* arg0 */ |
||
1153 | G_DBUS_SIGNAL_FLAGS_NONE | |
||
1154 | G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, |
||
1155 | signal_cb, |
||
1156 | manager, |
||
1157 | NULL); /* user_data_free_func */ |
||
1158 | |||
1159 | } |
||
1160 | else |
||
1161 | { |
||
1162 | /* TODO: we could report this to the user |
||
1163 | g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)", |
||
1164 | error->message, |
||
1165 | g_quark_to_string (error->domain), |
||
1166 | error->code); |
||
1167 | */ |
||
1168 | |||
1169 | g_error_free (error); |
||
1170 | |||
1171 | /* no need to call RemoveMatch when done since it didn't work */ |
||
1172 | g_free (manager->priv->match_rule); |
||
1173 | manager->priv->match_rule = NULL; |
||
1174 | |||
1175 | /* Fallback is to subscribe to *all* signals from the name owner which |
||
1176 | * is rather wasteful. It's probably not a big practical problem because |
||
1177 | * users typically want all objects that the name owner supplies. |
||
1178 | */ |
||
1179 | manager->priv->signal_subscription_id = |
||
1180 | g_dbus_connection_signal_subscribe (manager->priv->connection, |
||
1181 | name_owner, |
||
1182 | NULL, /* interface */ |
||
1183 | NULL, /* member */ |
||
1184 | NULL, /* path - TODO: really want wilcard support here */ |
||
1185 | NULL, /* arg0 */ |
||
1186 | G_DBUS_SIGNAL_FLAGS_NONE, |
||
1187 | signal_cb, |
||
1188 | manager, |
||
1189 | NULL); /* user_data_free_func */ |
||
1190 | } |
||
1191 | } |
||
1192 | |||
1193 | static void |
||
1194 | maybe_unsubscribe_signals (GDBusObjectManagerClient *manager) |
||
1195 | { |
||
1196 | g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager)); |
||
1197 | |||
1198 | if (manager->priv->signal_subscription_id > 0) |
||
1199 | { |
||
1200 | g_dbus_connection_signal_unsubscribe (manager->priv->connection, |
||
1201 | manager->priv->signal_subscription_id); |
||
1202 | manager->priv->signal_subscription_id = 0; |
||
1203 | } |
||
1204 | |||
1205 | if (manager->priv->match_rule != NULL) |
||
1206 | { |
||
1207 | /* Since the AddMatch call succeeded this is guaranteed to not |
||
1208 | * fail - therefore, don't bother checking the return value |
||
1209 | */ |
||
1210 | g_dbus_connection_call (manager->priv->connection, |
||
1211 | "org.freedesktop.DBus", |
||
1212 | "/org/freedesktop/DBus", |
||
1213 | "org.freedesktop.DBus", |
||
1214 | "RemoveMatch", |
||
1215 | g_variant_new ("(s)", |
||
1216 | manager->priv->match_rule), |
||
1217 | NULL, /* reply_type */ |
||
1218 | G_DBUS_CALL_FLAGS_NONE, |
||
1219 | -1, /* default timeout */ |
||
1220 | NULL, /* GCancellable */ |
||
1221 | NULL, /* GAsyncReadyCallback */ |
||
1222 | NULL); /* user data */ |
||
1223 | g_free (manager->priv->match_rule); |
||
1224 | manager->priv->match_rule = NULL; |
||
1225 | } |
||
1226 | |||
1227 | } |
||
1228 | |||
1229 | /* ---------------------------------------------------------------------------------------------------- */ |
||
1230 | |||
1231 | static void |
||
1232 | on_notify_g_name_owner (GObject *object, |
||
1233 | GParamSpec *pspec, |
||
1234 | gpointer user_data) |
||
1235 | { |
||
1236 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data); |
||
1237 | gchar *old_name_owner; |
||
1238 | gchar *new_name_owner; |
||
1239 | |||
1240 | g_mutex_lock (&manager->priv->lock); |
||
1241 | old_name_owner = manager->priv->name_owner; |
||
1242 | new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy); |
||
1243 | manager->priv->name_owner = NULL; |
||
1244 | |||
1245 | g_object_ref (manager); |
||
1246 | if (g_strcmp0 (old_name_owner, new_name_owner) != 0) |
||
1247 | { |
||
1248 | GList *l; |
||
1249 | GList *proxies; |
||
1250 | |||
1251 | /* remote manager changed; nuke all local proxies */ |
||
1252 | proxies = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy); |
||
1253 | g_list_foreach (proxies, (GFunc) g_object_ref, NULL); |
||
1254 | g_hash_table_remove_all (manager->priv->map_object_path_to_object_proxy); |
||
1255 | |||
1256 | g_mutex_unlock (&manager->priv->lock); |
||
1257 | |||
1258 | /* do the :name-owner notify with a NULL name - this way the user knows |
||
1259 | * the ::object-proxy-removed following is because the name owner went |
||
1260 | * away |
||
1261 | */ |
||
1262 | g_object_notify (G_OBJECT (manager), "name-owner"); |
||
1263 | |||
1264 | for (l = proxies; l != NULL; l = l->next) |
||
1265 | { |
||
1266 | GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY (l->data); |
||
1267 | g_signal_emit_by_name (manager, "object-removed", object_proxy); |
||
1268 | } |
||
1269 | g_list_free_full (proxies, g_object_unref); |
||
1270 | |||
1271 | /* nuke local filter */ |
||
1272 | maybe_unsubscribe_signals (manager); |
||
1273 | } |
||
1274 | else |
||
1275 | { |
||
1276 | g_mutex_unlock (&manager->priv->lock); |
||
1277 | } |
||
1278 | |||
1279 | if (new_name_owner != NULL) |
||
1280 | { |
||
1281 | GError *error; |
||
1282 | GVariant *value; |
||
1283 | |||
1284 | //g_debug ("repopulating for %s", new_name_owner); |
||
1285 | |||
1286 | /* TODO: do this async! */ |
||
1287 | subscribe_signals (manager, |
||
1288 | new_name_owner); |
||
1289 | error = NULL; |
||
1290 | value = g_dbus_proxy_call_sync (manager->priv->control_proxy, |
||
1291 | "GetManagedObjects", |
||
1292 | NULL, /* parameters */ |
||
1293 | G_DBUS_CALL_FLAGS_NONE, |
||
1294 | -1, |
||
1295 | NULL, |
||
1296 | &error); |
||
1297 | if (value == NULL) |
||
1298 | { |
||
1299 | maybe_unsubscribe_signals (manager); |
||
1300 | g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s", |
||
1301 | new_name_owner, |
||
1302 | manager->priv->name, |
||
1303 | error->message); |
||
1304 | g_error_free (error); |
||
1305 | } |
||
1306 | else |
||
1307 | { |
||
1308 | process_get_all_result (manager, value, new_name_owner); |
||
1309 | g_variant_unref (value); |
||
1310 | } |
||
1311 | |||
1312 | /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this |
||
1313 | * way the user knows that the signals were emitted because the name owner came back |
||
1314 | */ |
||
1315 | g_mutex_lock (&manager->priv->lock); |
||
1316 | manager->priv->name_owner = new_name_owner; |
||
1317 | g_mutex_unlock (&manager->priv->lock); |
||
1318 | g_object_notify (G_OBJECT (manager), "name-owner"); |
||
1319 | |||
1320 | } |
||
1321 | g_free (old_name_owner); |
||
1322 | g_object_unref (manager); |
||
1323 | } |
||
1324 | |||
1325 | static gboolean |
||
1326 | initable_init (GInitable *initable, |
||
1327 | GCancellable *cancellable, |
||
1328 | GError **error) |
||
1329 | { |
||
1330 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable); |
||
1331 | gboolean ret; |
||
1332 | GVariant *value; |
||
1333 | GDBusProxyFlags proxy_flags; |
||
1334 | |||
1335 | ret = FALSE; |
||
1336 | |||
1337 | if (manager->priv->bus_type != G_BUS_TYPE_NONE) |
||
1338 | { |
||
1339 | g_assert (manager->priv->connection == NULL); |
||
1340 | manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error); |
||
1341 | if (manager->priv->connection == NULL) |
||
1342 | goto out; |
||
1343 | } |
||
1344 | |||
1345 | proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES; |
||
1346 | if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START) |
||
1347 | proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START; |
||
1348 | |||
1349 | manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection, |
||
1350 | proxy_flags, |
||
1351 | NULL, /* GDBusInterfaceInfo* */ |
||
1352 | manager->priv->name, |
||
1353 | manager->priv->object_path, |
||
1354 | "org.freedesktop.DBus.ObjectManager", |
||
1355 | cancellable, |
||
1356 | error); |
||
1357 | if (manager->priv->control_proxy == NULL) |
||
1358 | goto out; |
||
1359 | |||
1360 | g_signal_connect (G_OBJECT (manager->priv->control_proxy), |
||
1361 | "notify::g-name-owner", |
||
1362 | G_CALLBACK (on_notify_g_name_owner), |
||
1363 | manager); |
||
1364 | |||
1365 | g_signal_connect (manager->priv->control_proxy, |
||
1366 | "g-signal", |
||
1367 | G_CALLBACK (on_control_proxy_g_signal), |
||
1368 | manager); |
||
1369 | |||
1370 | manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy); |
||
1371 | if (manager->priv->name_owner == NULL && manager->priv->name != NULL) |
||
1372 | { |
||
1373 | /* it's perfectly fine if there's no name owner.. we're just going to |
||
1374 | * wait until one is ready |
||
1375 | */ |
||
1376 | } |
||
1377 | else |
||
1378 | { |
||
1379 | /* yay, we can get the objects */ |
||
1380 | subscribe_signals (manager, |
||
1381 | manager->priv->name_owner); |
||
1382 | value = g_dbus_proxy_call_sync (manager->priv->control_proxy, |
||
1383 | "GetManagedObjects", |
||
1384 | NULL, /* parameters */ |
||
1385 | G_DBUS_CALL_FLAGS_NONE, |
||
1386 | -1, |
||
1387 | cancellable, |
||
1388 | error); |
||
1389 | if (value == NULL) |
||
1390 | { |
||
1391 | maybe_unsubscribe_signals (manager); |
||
1392 | g_warn_if_fail (g_signal_handlers_disconnect_by_func (manager->priv->control_proxy, |
||
1393 | on_control_proxy_g_signal, |
||
1394 | manager) == 1); |
||
1395 | g_object_unref (manager->priv->control_proxy); |
||
1396 | manager->priv->control_proxy = NULL; |
||
1397 | goto out; |
||
1398 | } |
||
1399 | |||
1400 | process_get_all_result (manager, value, manager->priv->name_owner); |
||
1401 | g_variant_unref (value); |
||
1402 | } |
||
1403 | |||
1404 | ret = TRUE; |
||
1405 | |||
1406 | out: |
||
1407 | return ret; |
||
1408 | } |
||
1409 | |||
1410 | static void |
||
1411 | initable_iface_init (GInitableIface *initable_iface) |
||
1412 | { |
||
1413 | initable_iface->init = initable_init; |
||
1414 | } |
||
1415 | |||
1416 | static void |
||
1417 | async_initable_iface_init (GAsyncInitableIface *async_initable_iface) |
||
1418 | { |
||
1419 | /* for now, just use default: run GInitable code in thread */ |
||
1420 | } |
||
1421 | |||
1422 | /* ---------------------------------------------------------------------------------------------------- */ |
||
1423 | |||
1424 | static void |
||
1425 | add_interfaces (GDBusObjectManagerClient *manager, |
||
1426 | const gchar *object_path, |
||
1427 | GVariant *ifaces_and_properties, |
||
1428 | const gchar *name_owner) |
||
1429 | { |
||
1430 | GDBusObjectProxy *op; |
||
1431 | gboolean added; |
||
1432 | GVariantIter iter; |
||
1433 | const gchar *interface_name; |
||
1434 | GVariant *properties; |
||
1435 | GList *interface_added_signals, *l; |
||
1436 | GDBusProxy *interface_proxy; |
||
1437 | |||
1438 | g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner)); |
||
1439 | |||
1440 | g_mutex_lock (&manager->priv->lock); |
||
1441 | |||
1442 | interface_added_signals = NULL; |
||
1443 | added = FALSE; |
||
1444 | |||
1445 | op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path); |
||
1446 | if (op == NULL) |
||
1447 | { |
||
1448 | GType object_proxy_type; |
||
1449 | if (manager->priv->get_proxy_type_func != NULL) |
||
1450 | { |
||
1451 | object_proxy_type = manager->priv->get_proxy_type_func (manager, |
||
1452 | object_path, |
||
1453 | NULL, |
||
1454 | manager->priv->get_proxy_type_user_data); |
||
1455 | g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY)); |
||
1456 | } |
||
1457 | else |
||
1458 | { |
||
1459 | object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY; |
||
1460 | } |
||
1461 | op = g_object_new (object_proxy_type, |
||
1462 | "g-connection", manager->priv->connection, |
||
1463 | "g-object-path", object_path, |
||
1464 | NULL); |
||
1465 | added = TRUE; |
||
1466 | } |
||
1467 | g_object_ref (op); |
||
1468 | |||
1469 | g_variant_iter_init (&iter, ifaces_and_properties); |
||
1470 | while (g_variant_iter_next (&iter, |
||
1471 | "{&s@a{sv}}", |
||
1472 | &interface_name, |
||
1473 | &properties)) |
||
1474 | { |
||
1475 | GError *error; |
||
1476 | GType interface_proxy_type; |
||
1477 | |||
1478 | if (manager->priv->get_proxy_type_func != NULL) |
||
1479 | { |
||
1480 | interface_proxy_type = manager->priv->get_proxy_type_func (manager, |
||
1481 | object_path, |
||
1482 | interface_name, |
||
1483 | manager->priv->get_proxy_type_user_data); |
||
1484 | g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY)); |
||
1485 | } |
||
1486 | else |
||
1487 | { |
||
1488 | interface_proxy_type = G_TYPE_DBUS_PROXY; |
||
1489 | } |
||
1490 | |||
1491 | /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and |
||
1492 | * DO_NOT_CONNECT_SIGNALS and use a unique name |
||
1493 | */ |
||
1494 | error = NULL; |
||
1495 | interface_proxy = g_initable_new (interface_proxy_type, |
||
1496 | NULL, /* GCancellable */ |
||
1497 | &error, |
||
1498 | "g-connection", manager->priv->connection, |
||
1499 | "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | |
||
1500 | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, |
||
1501 | "g-name", name_owner, |
||
1502 | "g-object-path", object_path, |
||
1503 | "g-interface-name", interface_name, |
||
1504 | NULL); |
||
1505 | if (interface_proxy == NULL) |
||
1506 | { |
||
1507 | g_warning ("%s: Error constructing proxy for path %s and interface %s: %s", |
||
1508 | G_STRLOC, |
||
1509 | object_path, |
||
1510 | interface_name, |
||
1511 | error->message); |
||
1512 | g_error_free (error); |
||
1513 | } |
||
1514 | else |
||
1515 | { |
||
1516 | GVariantIter property_iter; |
||
1517 | const gchar *property_name; |
||
1518 | GVariant *property_value; |
||
1519 | |||
1520 | /* associate the interface proxy with the object */ |
||
1521 | g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy), |
||
1522 | G_DBUS_OBJECT (op)); |
||
1523 | |||
1524 | g_variant_iter_init (&property_iter, properties); |
||
1525 | while (g_variant_iter_next (&property_iter, |
||
1526 | "{&sv}", |
||
1527 | &property_name, |
||
1528 | &property_value)) |
||
1529 | { |
||
1530 | g_dbus_proxy_set_cached_property (interface_proxy, |
||
1531 | property_name, |
||
1532 | property_value); |
||
1533 | g_variant_unref (property_value); |
||
1534 | } |
||
1535 | |||
1536 | _g_dbus_object_proxy_add_interface (op, interface_proxy); |
||
1537 | if (!added) |
||
1538 | interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy)); |
||
1539 | g_object_unref (interface_proxy); |
||
1540 | } |
||
1541 | g_variant_unref (properties); |
||
1542 | } |
||
1543 | |||
1544 | g_mutex_unlock (&manager->priv->lock); |
||
1545 | |||
1546 | /* now that we don't hold the lock any more, emit signals */ |
||
1547 | g_object_ref (manager); |
||
1548 | for (l = interface_added_signals; l != NULL; l = l->next) |
||
1549 | { |
||
1550 | interface_proxy = G_DBUS_PROXY (l->data); |
||
1551 | g_signal_emit_by_name (manager, "interface-added", op, interface_proxy); |
||
1552 | g_object_unref (interface_proxy); |
||
1553 | } |
||
1554 | g_list_free (interface_added_signals); |
||
1555 | |||
1556 | if (added) |
||
1557 | { |
||
1558 | g_hash_table_insert (manager->priv->map_object_path_to_object_proxy, |
||
1559 | g_strdup (object_path), |
||
1560 | op); |
||
1561 | g_signal_emit_by_name (manager, "object-added", op); |
||
1562 | } |
||
1563 | g_object_unref (manager); |
||
1564 | g_object_unref (op); |
||
1565 | } |
||
1566 | |||
1567 | static void |
||
1568 | remove_interfaces (GDBusObjectManagerClient *manager, |
||
1569 | const gchar *object_path, |
||
1570 | const gchar *const *interface_names) |
||
1571 | { |
||
1572 | GDBusObjectProxy *op; |
||
1573 | GList *interfaces; |
||
1574 | guint n; |
||
1575 | guint num_interfaces; |
||
1576 | guint num_interfaces_to_remove; |
||
1577 | |||
1578 | g_mutex_lock (&manager->priv->lock); |
||
1579 | |||
1580 | op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path); |
||
1581 | if (op == NULL) |
||
1582 | { |
||
1583 | g_warning ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists", |
||
1584 | G_STRLOC, |
||
1585 | object_path); |
||
1586 | g_mutex_unlock (&manager->priv->lock); |
||
1587 | goto out; |
||
1588 | } |
||
1589 | |||
1590 | interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op)); |
||
1591 | num_interfaces = g_list_length (interfaces); |
||
1592 | g_list_free_full (interfaces, g_object_unref); |
||
1593 | |||
1594 | num_interfaces_to_remove = g_strv_length ((gchar **) interface_names); |
||
1595 | |||
1596 | /* see if we are going to completety remove the object */ |
||
1597 | g_object_ref (manager); |
||
1598 | if (num_interfaces_to_remove == num_interfaces) |
||
1599 | { |
||
1600 | g_object_ref (op); |
||
1601 | g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path)); |
||
1602 | g_mutex_unlock (&manager->priv->lock); |
||
1603 | g_signal_emit_by_name (manager, "object-removed", op); |
||
1604 | g_object_unref (op); |
||
1605 | } |
||
1606 | else |
||
1607 | { |
||
1608 | g_object_ref (op); |
||
1609 | g_mutex_unlock (&manager->priv->lock); |
||
1610 | for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++) |
||
1611 | { |
||
1612 | GDBusInterface *interface; |
||
1613 | interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]); |
||
1614 | _g_dbus_object_proxy_remove_interface (op, interface_names[n]); |
||
1615 | if (interface != NULL) |
||
1616 | { |
||
1617 | g_signal_emit_by_name (manager, "interface-removed", op, interface); |
||
1618 | g_object_unref (interface); |
||
1619 | } |
||
1620 | } |
||
1621 | g_object_unref (op); |
||
1622 | } |
||
1623 | g_object_unref (manager); |
||
1624 | out: |
||
1625 | ; |
||
1626 | } |
||
1627 | |||
1628 | static void |
||
1629 | process_get_all_result (GDBusObjectManagerClient *manager, |
||
1630 | GVariant *value, |
||
1631 | const gchar *name_owner) |
||
1632 | { |
||
1633 | GVariant *arg0; |
||
1634 | const gchar *object_path; |
||
1635 | GVariant *ifaces_and_properties; |
||
1636 | GVariantIter iter; |
||
1637 | |||
1638 | g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner)); |
||
1639 | |||
1640 | arg0 = g_variant_get_child_value (value, 0); |
||
1641 | g_variant_iter_init (&iter, arg0); |
||
1642 | while (g_variant_iter_next (&iter, |
||
1643 | "{&o@a{sa{sv}}}", |
||
1644 | &object_path, |
||
1645 | &ifaces_and_properties)) |
||
1646 | { |
||
1647 | add_interfaces (manager, object_path, ifaces_and_properties, name_owner); |
||
1648 | g_variant_unref (ifaces_and_properties); |
||
1649 | } |
||
1650 | g_variant_unref (arg0); |
||
1651 | } |
||
1652 | |||
1653 | static void |
||
1654 | on_control_proxy_g_signal (GDBusProxy *proxy, |
||
1655 | const gchar *sender_name, |
||
1656 | const gchar *signal_name, |
||
1657 | GVariant *parameters, |
||
1658 | gpointer user_data) |
||
1659 | { |
||
1660 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data); |
||
1661 | const gchar *object_path; |
||
1662 | |||
1663 | //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE)); |
||
1664 | |||
1665 | if (g_strcmp0 (signal_name, "InterfacesAdded") == 0) |
||
1666 | { |
||
1667 | GVariant *ifaces_and_properties; |
||
1668 | g_variant_get (parameters, |
||
1669 | "(&o@a{sa{sv}})", |
||
1670 | &object_path, |
||
1671 | &ifaces_and_properties); |
||
1672 | add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner); |
||
1673 | g_variant_unref (ifaces_and_properties); |
||
1674 | } |
||
1675 | else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0) |
||
1676 | { |
||
1677 | const gchar **ifaces; |
||
1678 | g_variant_get (parameters, |
||
1679 | "(&o^a&s)", |
||
1680 | &object_path, |
||
1681 | &ifaces); |
||
1682 | remove_interfaces (manager, object_path, ifaces); |
||
1683 | g_free (ifaces); |
||
1684 | } |
||
1685 | } |
||
1686 | |||
1687 | /* ---------------------------------------------------------------------------------------------------- */ |
||
1688 | |||
1689 | static const gchar * |
||
1690 | g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager) |
||
1691 | { |
||
1692 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager); |
||
1693 | return manager->priv->object_path; |
||
1694 | } |
||
1695 | |||
1696 | static GDBusObject * |
||
1697 | g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager, |
||
1698 | const gchar *object_path) |
||
1699 | { |
||
1700 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager); |
||
1701 | GDBusObject *ret; |
||
1702 | |||
1703 | g_mutex_lock (&manager->priv->lock); |
||
1704 | ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path); |
||
1705 | if (ret != NULL) |
||
1706 | g_object_ref (ret); |
||
1707 | g_mutex_unlock (&manager->priv->lock); |
||
1708 | return ret; |
||
1709 | } |
||
1710 | |||
1711 | static GDBusInterface * |
||
1712 | g_dbus_object_manager_client_get_interface (GDBusObjectManager *_manager, |
||
1713 | const gchar *object_path, |
||
1714 | const gchar *interface_name) |
||
1715 | { |
||
1716 | GDBusInterface *ret; |
||
1717 | GDBusObject *object; |
||
1718 | |||
1719 | ret = NULL; |
||
1720 | |||
1721 | object = g_dbus_object_manager_get_object (_manager, object_path); |
||
1722 | if (object == NULL) |
||
1723 | goto out; |
||
1724 | |||
1725 | ret = g_dbus_object_get_interface (object, interface_name); |
||
1726 | g_object_unref (object); |
||
1727 | |||
1728 | out: |
||
1729 | return ret; |
||
1730 | } |
||
1731 | |||
1732 | static GList * |
||
1733 | g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager) |
||
1734 | { |
||
1735 | GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager); |
||
1736 | GList *ret; |
||
1737 | |||
1738 | g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL); |
||
1739 | |||
1740 | g_mutex_lock (&manager->priv->lock); |
||
1741 | ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy); |
||
1742 | g_list_foreach (ret, (GFunc) g_object_ref, NULL); |
||
1743 | g_mutex_unlock (&manager->priv->lock); |
||
1744 | |||
1745 | return ret; |
||
1746 | } |
||
1747 | |||
1748 | |||
1749 | static void |
||
1750 | dbus_object_manager_interface_init (GDBusObjectManagerIface *iface) |
||
1751 | { |
||
1752 | iface->get_object_path = g_dbus_object_manager_client_get_object_path; |
||
1753 | iface->get_objects = g_dbus_object_manager_client_get_objects; |
||
1754 | iface->get_object = g_dbus_object_manager_client_get_object; |
||
1755 | iface->get_interface = g_dbus_object_manager_client_get_interface; |
||
1756 | } |
||
1757 | |||
1758 | /* ---------------------------------------------------------------------------------------------------- */ |