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