cleanup
[platform/upstream/glib.git] / gio / gdbusobjectmanagerserver.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, 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 "gdbusobjectmanagerserver.h"
25 #include "gdbusobject.h"
26 #include "gdbusobjectskeleton.h"
27 #include "gdbusinterfaceskeleton.h"
28 #include "gdbusconnection.h"
29 #include "gdbusintrospection.h"
30 #include "gdbusmethodinvocation.h"
31 #include "gdbuserror.h"
32
33 #include "glibintl.h"
34
35 /**
36  * SECTION:gdbusobjectmanagerserver
37  * @short_description: Service-side object manager
38  * @include: gio/gio.h
39  *
40  * #GDBusObjectManagerServer is used to export #GDBusObject instances using
41  * the standardized
42  * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
43  * interface. For example, remote D-Bus clients can get all objects
44  * and properties in a single call. Additionally, any change in the
45  * object hierarchy is broadcast using signals. This means that D-Bus
46  * clients can keep caches up to date by only listening to D-Bus
47  * signals.
48  *
49  * See #GDBusObjectManagerClient for the client-side code that is
50  * intended to be used with #GDBusObjectManagerServer or any D-Bus
51  * object implementing the org.freedesktop.DBus.ObjectManager
52  * interface.
53  */
54
55 typedef struct
56 {
57   GDBusObjectSkeleton *object;
58   GDBusObjectManagerServer *manager;
59   GHashTable *map_iface_name_to_iface;
60   gboolean exported;
61 } RegistrationData;
62
63 static void registration_data_free (RegistrationData *data);
64
65 static void export_all (GDBusObjectManagerServer *manager);
66 static void unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager);
67
68 static void g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
69                                                          RegistrationData   *data,
70                                                          const gchar *const *interfaces,
71                                                          const gchar *object_path);
72
73 static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
74                                                            RegistrationData   *data,
75                                                            const gchar *const *interfaces);
76
77 static gboolean g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer  *manager,
78                                                                 const gchar               *object_path);
79
80 struct _GDBusObjectManagerServerPrivate
81 {
82   GMutex lock;
83   GDBusConnection *connection;
84   gchar *object_path;
85   gchar *object_path_ending_in_slash;
86   GHashTable *map_object_path_to_data;
87   guint manager_reg_id;
88 };
89
90 enum
91 {
92   PROP_0,
93   PROP_CONNECTION,
94   PROP_OBJECT_PATH
95 };
96
97 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
98
99 G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerServer, g_dbus_object_manager_server, G_TYPE_OBJECT,
100                          G_ADD_PRIVATE (GDBusObjectManagerServer)
101                          G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
102
103 static void g_dbus_object_manager_server_constructed (GObject *object);
104
105 static void
106 g_dbus_object_manager_server_finalize (GObject *object)
107 {
108   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
109
110   if (manager->priv->connection != NULL)
111     {
112       unexport_all (manager, TRUE);
113       g_object_unref (manager->priv->connection);
114     }
115   g_hash_table_unref (manager->priv->map_object_path_to_data);
116   g_free (manager->priv->object_path);
117   g_free (manager->priv->object_path_ending_in_slash);
118
119   g_mutex_clear (&manager->priv->lock);
120
121   if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize != NULL)
122     G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize (object);
123 }
124
125 static void
126 g_dbus_object_manager_server_get_property (GObject    *object,
127                                            guint       prop_id,
128                                            GValue     *value,
129                                            GParamSpec *pspec)
130 {
131   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
132
133   switch (prop_id)
134     {
135     case PROP_CONNECTION:
136       g_mutex_lock (&manager->priv->lock);
137       g_value_set_object (value, manager->priv->connection);
138       g_mutex_unlock (&manager->priv->lock);
139       break;
140
141     case PROP_OBJECT_PATH:
142       g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
143       break;
144
145     default:
146       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
147       break;
148     }
149 }
150
151 static void
152 g_dbus_object_manager_server_set_property (GObject       *object,
153                                            guint          prop_id,
154                                            const GValue  *value,
155                                            GParamSpec    *pspec)
156 {
157   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
158
159   switch (prop_id)
160     {
161     case PROP_CONNECTION:
162       g_dbus_object_manager_server_set_connection (manager, g_value_get_object (value));
163       break;
164
165     case PROP_OBJECT_PATH:
166       g_assert (manager->priv->object_path == NULL);
167       g_assert (g_variant_is_object_path (g_value_get_string (value)));
168       manager->priv->object_path = g_value_dup_string (value);
169       manager->priv->object_path_ending_in_slash = g_strdup_printf ("%s/", manager->priv->object_path);
170       break;
171
172     default:
173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174       break;
175     }
176 }
177
178 static void
179 g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass)
180 {
181   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
182
183   gobject_class->finalize     = g_dbus_object_manager_server_finalize;
184   gobject_class->constructed  = g_dbus_object_manager_server_constructed;
185   gobject_class->set_property = g_dbus_object_manager_server_set_property;
186   gobject_class->get_property = g_dbus_object_manager_server_get_property;
187
188   /**
189    * GDBusObjectManagerServer:connection:
190    *
191    * The #GDBusConnection to export objects on.
192    *
193    * Since: 2.30
194    */
195   g_object_class_install_property (gobject_class,
196                                    PROP_CONNECTION,
197                                    g_param_spec_object ("connection",
198                                                         "Connection",
199                                                         "The connection to export objects on",
200                                                         G_TYPE_DBUS_CONNECTION,
201                                                         G_PARAM_READABLE |
202                                                         G_PARAM_WRITABLE |
203                                                         G_PARAM_STATIC_STRINGS));
204
205   /**
206    * GDBusObjectManagerServer:object-path:
207    *
208    * The object path to register the manager object at.
209    *
210    * Since: 2.30
211    */
212   g_object_class_install_property (gobject_class,
213                                    PROP_OBJECT_PATH,
214                                    g_param_spec_string ("object-path",
215                                                         "Object Path",
216                                                         "The object path to register the manager object at",
217                                                         NULL,
218                                                         G_PARAM_READABLE |
219                                                         G_PARAM_WRITABLE |
220                                                         G_PARAM_CONSTRUCT_ONLY |
221                                                         G_PARAM_STATIC_STRINGS));
222 }
223
224 static void
225 g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager)
226 {
227   manager->priv = g_dbus_object_manager_server_get_instance_private (manager);
228   g_mutex_init (&manager->priv->lock);
229   manager->priv->map_object_path_to_data = g_hash_table_new_full (g_str_hash,
230                                                                   g_str_equal,
231                                                                   g_free,
232                                                                   (GDestroyNotify) registration_data_free);
233 }
234
235 /**
236  * g_dbus_object_manager_server_new:
237  * @object_path: The object path to export the manager object at.
238  *
239  * Creates a new #GDBusObjectManagerServer object.
240  *
241  * The returned server isn't yet exported on any connection. To do so,
242  * use g_dbus_object_manager_server_set_connection(). Normally you
243  * want to export all of your objects before doing so to avoid <ulink
244  * url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">InterfacesAdded</ulink>
245  * signals being emitted.
246  *
247  * Returns: A #GDBusObjectManagerServer object. Free with g_object_unref().
248  *
249  * Since: 2.30
250  */
251 GDBusObjectManagerServer *
252 g_dbus_object_manager_server_new (const gchar     *object_path)
253 {
254   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
255   return G_DBUS_OBJECT_MANAGER_SERVER (g_object_new (G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
256                                                      "object-path", object_path,
257                                                      NULL));
258 }
259
260 /**
261  * g_dbus_object_manager_server_set_connection:
262  * @manager: A #GDBusObjectManagerServer.
263  * @connection: (allow-none): A #GDBusConnection or %NULL.
264  *
265  * Exports all objects managed by @manager on @connection. If
266  * @connection is %NULL, stops exporting objects.
267  */
268 void
269 g_dbus_object_manager_server_set_connection (GDBusObjectManagerServer  *manager,
270                                              GDBusConnection           *connection)
271 {
272   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
273   g_return_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection));
274
275   g_mutex_lock (&manager->priv->lock);
276
277   if (manager->priv->connection == connection)
278     {
279       g_mutex_unlock (&manager->priv->lock);
280       goto out;
281     }
282
283   if (manager->priv->connection != NULL)
284     {
285       unexport_all (manager, FALSE);
286       g_object_unref (manager->priv->connection);
287       manager->priv->connection = NULL;
288     }
289
290   manager->priv->connection = connection != NULL ? g_object_ref (connection) : NULL;
291   if (manager->priv->connection != NULL)
292     export_all (manager);
293
294   g_mutex_unlock (&manager->priv->lock);
295
296   g_object_notify (G_OBJECT (manager), "connection");
297  out:
298   ;
299 }
300
301 /**
302  * g_dbus_object_manager_server_get_connection:
303  * @manager: A #GDBusObjectManagerServer
304  *
305  * Gets the #GDBusConnection used by @manager.
306  *
307  * Returns: (transfer full): A #GDBusConnection object or %NULL if
308  *   @manager isn't exported on a connection. The returned object should
309  *   be freed with g_object_unref().
310  *
311  * Since: 2.30
312  */
313 GDBusConnection *
314 g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager)
315 {
316   GDBusConnection *ret;
317   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), NULL);
318   g_mutex_lock (&manager->priv->lock);
319   ret = manager->priv->connection != NULL ? g_object_ref (manager->priv->connection) : NULL;
320   g_mutex_unlock (&manager->priv->lock);
321   return ret;
322 }
323
324 /* ---------------------------------------------------------------------------------------------------- */
325
326 static void
327 registration_data_export_interface (RegistrationData        *data,
328                                     GDBusInterfaceSkeleton  *interface_skeleton,
329                                     const gchar             *object_path)
330 {
331   GDBusInterfaceInfo *info;
332   GError *error;
333
334   info = g_dbus_interface_skeleton_get_info (interface_skeleton);
335   error = NULL;
336   if (data->manager->priv->connection != NULL)
337     {
338       if (!g_dbus_interface_skeleton_export (interface_skeleton,
339                                              data->manager->priv->connection,
340                                              object_path,
341                                              &error))
342         {
343           g_warning ("%s: Error registering object at %s with interface %s: %s",
344                      G_STRLOC,
345                      object_path,
346                      info->name,
347                      error->message);
348           g_error_free (error);
349         }
350     }
351
352   g_assert (g_hash_table_lookup (data->map_iface_name_to_iface, info->name) == NULL);
353   g_hash_table_insert (data->map_iface_name_to_iface,
354                        info->name,
355                        g_object_ref (interface_skeleton));
356
357   /* if we are already exported, then... */
358   if (data->exported)
359     {
360       const gchar *interfaces[2];
361       /* emit InterfacesAdded on the ObjectManager object */
362       interfaces[0] = info->name;
363       interfaces[1] = NULL;
364       g_dbus_object_manager_server_emit_interfaces_added (data->manager, data, interfaces, object_path);
365     }
366 }
367
368 static void
369 registration_data_unexport_interface (RegistrationData       *data,
370                                       GDBusInterfaceSkeleton *interface_skeleton)
371 {
372   GDBusInterfaceInfo *info;
373   GDBusInterfaceSkeleton *iface;
374
375   info = g_dbus_interface_skeleton_get_info (interface_skeleton);
376   iface = g_hash_table_lookup (data->map_iface_name_to_iface, info->name);
377   g_assert (iface != NULL);
378
379   if (data->manager->priv->connection != NULL)
380     g_dbus_interface_skeleton_unexport (iface);
381
382   g_warn_if_fail (g_hash_table_remove (data->map_iface_name_to_iface, info->name));
383
384   /* if we are already exported, then... */
385   if (data->exported)
386     {
387       const gchar *interfaces[2];
388       /* emit InterfacesRemoved on the ObjectManager object */
389       interfaces[0] = info->name;
390       interfaces[1] = NULL;
391       g_dbus_object_manager_server_emit_interfaces_removed (data->manager, data, interfaces);
392     }
393 }
394
395 /* ---------------------------------------------------------------------------------------------------- */
396
397 static void
398 on_interface_added (GDBusObject    *object,
399                     GDBusInterface *interface,
400                     gpointer        user_data)
401 {
402   RegistrationData *data = user_data;
403   const gchar *object_path;
404   g_mutex_lock (&data->manager->priv->lock);
405   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
406   registration_data_export_interface (data, G_DBUS_INTERFACE_SKELETON (interface), object_path);
407   g_mutex_unlock (&data->manager->priv->lock);
408 }
409
410 static void
411 on_interface_removed (GDBusObject    *object,
412                       GDBusInterface *interface,
413                       gpointer        user_data)
414 {
415   RegistrationData *data = user_data;
416   g_mutex_lock (&data->manager->priv->lock);
417   registration_data_unexport_interface (data, G_DBUS_INTERFACE_SKELETON (interface));
418   g_mutex_unlock (&data->manager->priv->lock);
419 }
420
421 /* ---------------------------------------------------------------------------------------------------- */
422
423
424 static void
425 registration_data_free (RegistrationData *data)
426 {
427   GHashTableIter iter;
428   GDBusInterfaceSkeleton *iface;
429
430   data->exported = FALSE;
431
432   g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
433   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &iface))
434     {
435       if (data->manager->priv->connection != NULL)
436         g_dbus_interface_skeleton_unexport (iface);
437     }
438
439   g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_added), data);
440   g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_removed), data);
441   g_object_unref (data->object);
442   g_hash_table_destroy (data->map_iface_name_to_iface);
443   g_free (data);
444 }
445
446 /* ---------------------------------------------------------------------------------------------------- */
447
448 static void
449 g_dbus_object_manager_server_export_unlocked (GDBusObjectManagerServer  *manager,
450                                               GDBusObjectSkeleton       *object,
451                                               const gchar               *object_path)
452 {
453   RegistrationData *data;
454   GList *existing_interfaces;
455   GList *l;
456   GPtrArray *interface_names;
457
458   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
459   g_return_if_fail (G_IS_DBUS_OBJECT (object));
460   g_return_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash));
461
462   interface_names = g_ptr_array_new ();
463
464   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
465   if (data != NULL)
466     g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
467
468   data = g_new0 (RegistrationData, 1);
469   data->object = g_object_ref (object);
470   data->manager = manager;
471   data->map_iface_name_to_iface = g_hash_table_new_full (g_str_hash,
472                                                          g_str_equal,
473                                                          NULL,
474                                                          (GDestroyNotify) g_object_unref);
475
476   g_signal_connect (object,
477                     "interface-added",
478                     G_CALLBACK (on_interface_added),
479                     data);
480   g_signal_connect (object,
481                     "interface-removed",
482                     G_CALLBACK (on_interface_removed),
483                     data);
484
485   /* Register all known interfaces - note that data->exported is FALSE so
486    * we don't emit any InterfacesAdded signals.
487    */
488   existing_interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object));
489   for (l = existing_interfaces; l != NULL; l = l->next)
490     {
491       GDBusInterfaceSkeleton *interface_skeleton = G_DBUS_INTERFACE_SKELETON (l->data);
492       registration_data_export_interface (data, interface_skeleton, object_path);
493       g_ptr_array_add (interface_names, g_dbus_interface_skeleton_get_info (interface_skeleton)->name);
494     }
495   g_list_free_full (existing_interfaces, g_object_unref);
496   g_ptr_array_add (interface_names, NULL);
497
498   data->exported = TRUE;
499
500   /* now emit InterfacesAdded() for all the interfaces */
501   g_dbus_object_manager_server_emit_interfaces_added (manager, data, (const gchar *const *) interface_names->pdata, object_path);
502   g_ptr_array_unref (interface_names);
503
504   g_hash_table_insert (manager->priv->map_object_path_to_data,
505                        g_strdup (object_path),
506                        data);
507 }
508
509 /**
510  * g_dbus_object_manager_server_export:
511  * @manager: A #GDBusObjectManagerServer.
512  * @object: A #GDBusObjectSkeleton.
513  *
514  * Exports @object on @manager.
515  *
516  * If there is already a #GDBusObject exported at the object path,
517  * then the old object is removed.
518  *
519  * The object path for @object must be in the hierarchy rooted by the
520  * object path for @manager.
521  *
522  * Note that @manager will take a reference on @object for as long as
523  * it is exported.
524  *
525  * Since: 2.30
526  */
527 void
528 g_dbus_object_manager_server_export (GDBusObjectManagerServer  *manager,
529                                      GDBusObjectSkeleton       *object)
530 {
531   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
532   g_mutex_lock (&manager->priv->lock);
533   g_dbus_object_manager_server_export_unlocked (manager, object,
534                                                 g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
535   g_mutex_unlock (&manager->priv->lock);
536 }
537
538 /**
539  * g_dbus_object_manager_server_export_uniquely:
540  * @manager: A #GDBusObjectManagerServer.
541  * @object: An object.
542  *
543  * Like g_dbus_object_manager_server_export() but appends a string of
544  * the form _N (with N being a natural number) to @object's object path
545  * if an object with the given path already exists. As such, the
546  * #GDBusObjectProxy:g-object-path property of @object may be modified.
547  *
548  * Since: 2.30
549  */
550 void
551 g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager,
552                                               GDBusObjectSkeleton      *object)
553 {
554   gchar *orig_object_path;
555   gchar *object_path;
556   guint count;
557   gboolean modified;
558
559   orig_object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
560
561   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
562   g_return_if_fail (G_IS_DBUS_OBJECT (object));
563   g_return_if_fail (g_str_has_prefix (orig_object_path, manager->priv->object_path_ending_in_slash));
564
565   g_mutex_lock (&manager->priv->lock);
566
567   object_path = g_strdup (orig_object_path);
568   count = 1;
569   modified = FALSE;
570   while (TRUE)
571     {
572       RegistrationData *data;
573       data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
574       if (data == NULL)
575         {
576           break;
577         }
578       g_free (object_path);
579       object_path = g_strdup_printf ("%s_%d", orig_object_path, count++);
580       modified = TRUE;
581     }
582
583   g_dbus_object_manager_server_export_unlocked (manager, object, object_path);
584
585   g_mutex_unlock (&manager->priv->lock);
586
587   if (modified)
588     g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), object_path);
589
590   g_free (object_path);
591   g_free (orig_object_path);
592
593 }
594
595 /**
596  * g_dbus_object_manager_server_is_exported:
597  * @manager: A #GDBusObjectManagerServer.
598  * @object: An object.
599  *
600  * Returns whether @object is currently exported on @manager.
601  *
602  * Returns: %TRUE if @object is exported
603  *
604  * Since: 2.34
605  **/
606 gboolean
607 g_dbus_object_manager_server_is_exported (GDBusObjectManagerServer *manager,
608                                           GDBusObjectSkeleton      *object)
609 {
610   RegistrationData *data = NULL;
611   const gchar *object_path;
612   gboolean object_is_exported;
613
614   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
615   g_return_val_if_fail (G_IS_DBUS_OBJECT (object), FALSE);
616
617   g_mutex_lock (&manager->priv->lock);
618
619   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
620   if (object_path != NULL)
621     data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
622   object_is_exported = (data != NULL);
623
624   g_mutex_unlock (&manager->priv->lock);
625
626   return object_is_exported;
627 }
628
629 /* ---------------------------------------------------------------------------------------------------- */
630
631 static gboolean
632 g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer  *manager,
633                                                 const gchar               *object_path)
634 {
635   RegistrationData *data;
636   gboolean ret;
637
638   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
639   g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE);
640   g_return_val_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash), FALSE);
641
642   ret = FALSE;
643
644   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
645   if (data != NULL)
646     {
647       GPtrArray *interface_names;
648       GHashTableIter iter;
649       const gchar *iface_name;
650
651       interface_names = g_ptr_array_new ();
652       g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
653       while (g_hash_table_iter_next (&iter, (gpointer) &iface_name, NULL))
654         g_ptr_array_add (interface_names, (gpointer) iface_name);
655       g_ptr_array_add (interface_names, NULL);
656       /* now emit InterfacesRemoved() for all the interfaces */
657       g_dbus_object_manager_server_emit_interfaces_removed (manager, data, (const gchar *const *) interface_names->pdata);
658       g_ptr_array_unref (interface_names);
659
660       g_hash_table_remove (manager->priv->map_object_path_to_data, object_path);
661       ret = TRUE;
662     }
663
664   return ret;
665 }
666
667 /**
668  * g_dbus_object_manager_server_unexport:
669  * @manager: A #GDBusObjectManagerServer.
670  * @object_path: An object path.
671  *
672  * If @manager has an object at @path, removes the object. Otherwise
673  * does nothing.
674  *
675  * Note that @object_path must be in the hierarchy rooted by the
676  * object path for @manager.
677  *
678  * Returns: %TRUE if object at @object_path was removed, %FALSE otherwise.
679  *
680  * Since: 2.30
681  */
682 gboolean
683 g_dbus_object_manager_server_unexport (GDBusObjectManagerServer  *manager,
684                                        const gchar         *object_path)
685 {
686   gboolean ret;
687   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
688   g_mutex_lock (&manager->priv->lock);
689   ret = g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
690   g_mutex_unlock (&manager->priv->lock);
691   return ret;
692 }
693
694
695 /* ---------------------------------------------------------------------------------------------------- */
696
697 static const GDBusArgInfo manager_interfaces_added_signal_info_arg0 =
698 {
699   -1,
700   "object_path",
701   "o",
702   (GDBusAnnotationInfo**) NULL,
703 };
704
705 static const GDBusArgInfo manager_interfaces_added_signal_info_arg1 =
706 {
707   -1,
708   "interfaces_and_properties",
709   "a{sa{sv}}",
710   (GDBusAnnotationInfo**) NULL,
711 };
712
713 static const GDBusArgInfo * const manager_interfaces_added_signal_info_arg_pointers[] =
714 {
715   &manager_interfaces_added_signal_info_arg0,
716   &manager_interfaces_added_signal_info_arg1,
717   NULL
718 };
719
720 static const GDBusSignalInfo manager_interfaces_added_signal_info =
721 {
722   -1,
723   "InterfacesAdded",
724   (GDBusArgInfo**) &manager_interfaces_added_signal_info_arg_pointers,
725   (GDBusAnnotationInfo**) NULL
726 };
727
728 /* ---------- */
729
730 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg0 =
731 {
732   -1,
733   "object_path",
734   "o",
735   (GDBusAnnotationInfo**) NULL,
736 };
737
738 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg1 =
739 {
740   -1,
741   "interfaces",
742   "as",
743   (GDBusAnnotationInfo**) NULL,
744 };
745
746 static const GDBusArgInfo * const manager_interfaces_removed_signal_info_arg_pointers[] =
747 {
748   &manager_interfaces_removed_signal_info_arg0,
749   &manager_interfaces_removed_signal_info_arg1,
750   NULL
751 };
752
753 static const GDBusSignalInfo manager_interfaces_removed_signal_info =
754 {
755   -1,
756   "InterfacesRemoved",
757   (GDBusArgInfo**) &manager_interfaces_removed_signal_info_arg_pointers,
758   (GDBusAnnotationInfo**) NULL
759 };
760
761 /* ---------- */
762
763 static const GDBusSignalInfo * const manager_signal_info_pointers[] =
764 {
765   &manager_interfaces_added_signal_info,
766   &manager_interfaces_removed_signal_info,
767   NULL
768 };
769
770 /* ---------- */
771
772 static const GDBusArgInfo manager_get_all_method_info_out_arg0 =
773 {
774   -1,
775   "object_paths_interfaces_and_properties",
776   "a{oa{sa{sv}}}",
777   (GDBusAnnotationInfo**) NULL,
778 };
779
780 static const GDBusArgInfo * const manager_get_all_method_info_out_arg_pointers[] =
781 {
782   &manager_get_all_method_info_out_arg0,
783   NULL
784 };
785
786 static const GDBusMethodInfo manager_get_all_method_info =
787 {
788   -1,
789   "GetManagedObjects",
790   (GDBusArgInfo**) NULL,
791   (GDBusArgInfo**) &manager_get_all_method_info_out_arg_pointers,
792   (GDBusAnnotationInfo**) NULL
793 };
794
795 static const GDBusMethodInfo * const manager_method_info_pointers[] =
796 {
797   &manager_get_all_method_info,
798   NULL
799 };
800
801 /* ---------- */
802
803 static const GDBusInterfaceInfo manager_interface_info =
804 {
805   -1,
806   "org.freedesktop.DBus.ObjectManager",
807   (GDBusMethodInfo **) manager_method_info_pointers,
808   (GDBusSignalInfo **) manager_signal_info_pointers,
809   (GDBusPropertyInfo **) NULL,
810   (GDBusAnnotationInfo **) NULL
811 };
812
813 static void
814 manager_method_call (GDBusConnection       *connection,
815                      const gchar           *sender,
816                      const gchar           *object_path,
817                      const gchar           *interface_name,
818                      const gchar           *method_name,
819                      GVariant              *parameters,
820                      GDBusMethodInvocation *invocation,
821                      gpointer               user_data)
822 {
823   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (user_data);
824   GVariantBuilder array_builder;
825   GHashTableIter object_iter;
826   RegistrationData *data;
827
828   g_mutex_lock (&manager->priv->lock);
829
830   if (g_strcmp0 (method_name, "GetManagedObjects") == 0)
831     {
832       g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}"));
833       g_hash_table_iter_init (&object_iter, manager->priv->map_object_path_to_data);
834       while (g_hash_table_iter_next (&object_iter, NULL, (gpointer) &data))
835         {
836           GVariantBuilder interfaces_builder;
837           GHashTableIter interface_iter;
838           GDBusInterfaceSkeleton *iface;
839           const gchar *iter_object_path;
840
841           g_variant_builder_init (&interfaces_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
842           g_hash_table_iter_init (&interface_iter, data->map_iface_name_to_iface);
843           while (g_hash_table_iter_next (&interface_iter, NULL, (gpointer) &iface))
844             {
845               GVariant *properties = g_dbus_interface_skeleton_get_properties (iface);
846               g_variant_builder_add (&interfaces_builder, "{s@a{sv}}",
847                                      g_dbus_interface_skeleton_get_info (iface)->name,
848                                      properties);
849               g_variant_unref (properties);
850             }
851           iter_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
852           g_variant_builder_add (&array_builder,
853                                  "{oa{sa{sv}}}",
854                                  iter_object_path,
855                                  &interfaces_builder);
856         }
857
858       g_dbus_method_invocation_return_value (invocation,
859                                              g_variant_new ("(a{oa{sa{sv}}})",
860                                                             &array_builder));
861     }
862   else
863     {
864       g_dbus_method_invocation_return_error (invocation,
865                                              G_DBUS_ERROR,
866                                              G_DBUS_ERROR_UNKNOWN_METHOD,
867                                              "Unknown method %s - only GetManagedObjects() is supported",
868                                              method_name);
869     }
870   g_mutex_unlock (&manager->priv->lock);
871 }
872
873 static const GDBusInterfaceVTable manager_interface_vtable =
874 {
875   manager_method_call, /* handle_method_call */
876   NULL, /* get_property */
877   NULL  /* set_property */
878 };
879
880 /* ---------------------------------------------------------------------------------------------------- */
881
882 static void
883 g_dbus_object_manager_server_constructed (GObject *object)
884 {
885   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
886
887   if (manager->priv->connection != NULL)
888     export_all (manager);
889
890   if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed != NULL)
891     G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed (object);
892 }
893
894 static void
895 g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
896                                                     RegistrationData   *data,
897                                                     const gchar *const *interfaces,
898                                                     const gchar *object_path)
899 {
900   GVariantBuilder array_builder;
901   GError *error;
902   guint n;
903
904   if (data->manager->priv->connection == NULL)
905     goto out;
906
907   g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
908   for (n = 0; interfaces[n] != NULL; n++)
909     {
910       GDBusInterfaceSkeleton *iface;
911       GVariant *properties;
912
913       iface = g_hash_table_lookup (data->map_iface_name_to_iface, interfaces[n]);
914       g_assert (iface != NULL);
915       properties = g_dbus_interface_skeleton_get_properties (iface);
916       g_variant_builder_add (&array_builder, "{s@a{sv}}", interfaces[n], properties);
917       g_variant_unref (properties);
918     }
919
920   error = NULL;
921   g_dbus_connection_emit_signal (data->manager->priv->connection,
922                                  NULL, /* destination_bus_name */
923                                  manager->priv->object_path,
924                                  manager_interface_info.name,
925                                  "InterfacesAdded",
926                                  g_variant_new ("(oa{sa{sv}})",
927                                                 object_path,
928                                                 &array_builder),
929                                  &error);
930   g_assert_no_error (error);
931  out:
932   ;
933 }
934
935 static void
936 g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
937                                                       RegistrationData   *data,
938                                                       const gchar *const *interfaces)
939 {
940   GVariantBuilder array_builder;
941   GError *error;
942   guint n;
943   const gchar *object_path;
944
945   if (data->manager->priv->connection == NULL)
946     goto out;
947
948   g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
949   for (n = 0; interfaces[n] != NULL; n++)
950     g_variant_builder_add (&array_builder, "s", interfaces[n]);
951
952   error = NULL;
953   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
954   g_dbus_connection_emit_signal (data->manager->priv->connection,
955                                  NULL, /* destination_bus_name */
956                                  manager->priv->object_path,
957                                  manager_interface_info.name,
958                                  "InterfacesRemoved",
959                                  g_variant_new ("(oas)",
960                                                 object_path,
961                                                 &array_builder),
962                                  &error);
963   g_assert_no_error (error);
964  out:
965   ;
966 }
967
968 /* ---------------------------------------------------------------------------------------------------- */
969
970 static GList *
971 g_dbus_object_manager_server_get_objects (GDBusObjectManager  *_manager)
972 {
973   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
974   GList *ret;
975   GHashTableIter iter;
976   RegistrationData *data;
977
978   g_mutex_lock (&manager->priv->lock);
979
980   ret = NULL;
981   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
982   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
983     {
984       ret = g_list_prepend (ret, g_object_ref (data->object));
985     }
986
987   g_mutex_unlock (&manager->priv->lock);
988
989   return ret;
990 }
991
992 static const gchar *
993 g_dbus_object_manager_server_get_object_path (GDBusObjectManager *_manager)
994 {
995   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
996   return manager->priv->object_path;
997 }
998
999 static GDBusObject *
1000 g_dbus_object_manager_server_get_object (GDBusObjectManager *_manager,
1001                                          const gchar        *object_path)
1002 {
1003   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
1004   GDBusObject *ret;
1005   RegistrationData *data;
1006
1007   ret = NULL;
1008
1009   g_mutex_lock (&manager->priv->lock);
1010   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
1011   if (data != NULL)
1012     ret = g_object_ref (data->object);
1013   g_mutex_unlock (&manager->priv->lock);
1014
1015   return ret;
1016 }
1017
1018 static GDBusInterface *
1019 g_dbus_object_manager_server_get_interface  (GDBusObjectManager  *_manager,
1020                                              const gchar         *object_path,
1021                                              const gchar         *interface_name)
1022 {
1023   GDBusInterface *ret;
1024   GDBusObject *object;
1025
1026   ret = NULL;
1027
1028   object = g_dbus_object_manager_get_object (_manager, object_path);
1029   if (object == NULL)
1030     goto out;
1031
1032   ret = g_dbus_object_get_interface (object, interface_name);
1033   g_object_unref (object);
1034
1035  out:
1036   return ret;
1037 }
1038
1039 static void
1040 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1041 {
1042   iface->get_object_path = g_dbus_object_manager_server_get_object_path;
1043   iface->get_objects     = g_dbus_object_manager_server_get_objects;
1044   iface->get_object      = g_dbus_object_manager_server_get_object;
1045   iface->get_interface   = g_dbus_object_manager_server_get_interface;
1046 }
1047
1048 /* ---------------------------------------------------------------------------------------------------- */
1049
1050 static void
1051 export_all (GDBusObjectManagerServer *manager)
1052 {
1053   GHashTableIter iter;
1054   const gchar *object_path;
1055   RegistrationData *data;
1056   GHashTableIter iface_iter;
1057   GDBusInterfaceSkeleton *iface;
1058   GError *error;
1059
1060   g_return_if_fail (manager->priv->connection != NULL);
1061
1062   error = NULL;
1063   g_warn_if_fail (manager->priv->manager_reg_id == 0);
1064   manager->priv->manager_reg_id = g_dbus_connection_register_object (manager->priv->connection,
1065                                                                      manager->priv->object_path,
1066                                                                      (GDBusInterfaceInfo *) &manager_interface_info,
1067                                                                      &manager_interface_vtable,
1068                                                                      manager,
1069                                                                      NULL, /* user_data_free_func */
1070                                                                      &error);
1071   if (manager->priv->manager_reg_id == 0)
1072     {
1073       g_warning ("%s: Error registering manager at %s: %s",
1074                  G_STRLOC,
1075                  manager->priv->object_path,
1076                  error->message);
1077       g_error_free (error);
1078     }
1079
1080   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
1081   while (g_hash_table_iter_next (&iter, (gpointer) &object_path, (gpointer) &data))
1082     {
1083       g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
1084       while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
1085         {
1086           g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) == NULL);
1087           error = NULL;
1088           if (!g_dbus_interface_skeleton_export (iface,
1089                                                  manager->priv->connection,
1090                                                  object_path,
1091                                                  &error))
1092             {
1093               g_warning ("%s: Error registering object at %s with interface %s: %s",
1094                          G_STRLOC,
1095                          object_path,
1096                          g_dbus_interface_skeleton_get_info (iface)->name,
1097                          error->message);
1098               g_error_free (error);
1099             }
1100         }
1101     }
1102 }
1103
1104 static void
1105 unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager)
1106 {
1107   GHashTableIter iter;
1108   RegistrationData *data;
1109   GHashTableIter iface_iter;
1110   GDBusInterfaceSkeleton *iface;
1111
1112   g_return_if_fail (manager->priv->connection != NULL);
1113
1114   g_warn_if_fail (manager->priv->manager_reg_id > 0);
1115   if (manager->priv->manager_reg_id > 0)
1116     {
1117       g_warn_if_fail (g_dbus_connection_unregister_object (manager->priv->connection,
1118                                                            manager->priv->manager_reg_id));
1119       manager->priv->manager_reg_id = 0;
1120     }
1121   if (only_manager)
1122     goto out;
1123
1124   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
1125   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
1126     {
1127       g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
1128       while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
1129         {
1130           g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) != NULL);
1131           g_dbus_interface_skeleton_unexport (iface);
1132         }
1133     }
1134  out:
1135   ;
1136 }
1137
1138 /* ---------------------------------------------------------------------------------------------------- */