nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
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 /* ---------------------------------------------------------------------------------------------------- */