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