g_unix_set_fd_nonblocking: New API to control file descriptor blocking state
[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 g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
68                                                          RegistrationData   *data,
69                                                          const gchar *const *interfaces);
70
71 static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
72                                                            RegistrationData   *data,
73                                                            const gchar *const *interfaces);
74
75 struct _GDBusObjectManagerServerPrivate
76 {
77   GDBusConnection *connection;
78   gchar *object_path;
79   gchar *object_path_ending_in_slash;
80   GHashTable *map_object_path_to_data;
81   guint manager_reg_id;
82 };
83
84 enum
85 {
86   PROP_0,
87   PROP_CONNECTION,
88   PROP_OBJECT_PATH
89 };
90
91 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
92
93 G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerServer, g_dbus_object_manager_server, G_TYPE_OBJECT,
94                          G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init));
95
96 static void g_dbus_object_manager_server_constructed (GObject *object);
97
98 static void
99 g_dbus_object_manager_server_finalize (GObject *object)
100 {
101   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
102
103   g_hash_table_unref (manager->priv->map_object_path_to_data);
104   if (manager->priv->manager_reg_id > 0)
105     g_warn_if_fail (g_dbus_connection_unregister_object (manager->priv->connection, manager->priv->manager_reg_id));
106   g_object_unref (manager->priv->connection);
107   g_free (manager->priv->object_path);
108   g_free (manager->priv->object_path_ending_in_slash);
109
110   if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize != NULL)
111     G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize (object);
112 }
113
114 static void
115 g_dbus_object_manager_server_get_property (GObject    *_object,
116                                     guint       prop_id,
117                                     GValue     *value,
118                                     GParamSpec *pspec)
119 {
120   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_object);
121
122   switch (prop_id)
123     {
124     case PROP_CONNECTION:
125       g_value_set_object (value, g_dbus_object_manager_server_get_connection (manager));
126       break;
127
128     case PROP_OBJECT_PATH:
129       g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
130       break;
131
132     default:
133       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
134       break;
135     }
136 }
137
138 static void
139 g_dbus_object_manager_server_set_property (GObject       *_object,
140                                     guint          prop_id,
141                                     const GValue  *value,
142                                     GParamSpec    *pspec)
143 {
144   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_object);
145
146   switch (prop_id)
147     {
148     case PROP_CONNECTION:
149       g_assert (manager->priv->connection == NULL);
150       g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
151       manager->priv->connection = g_value_dup_object (value);
152       break;
153
154     case PROP_OBJECT_PATH:
155       g_assert (manager->priv->object_path == NULL);
156       g_assert (g_variant_is_object_path (g_value_get_string (value)));
157       manager->priv->object_path = g_value_dup_string (value);
158       manager->priv->object_path_ending_in_slash = g_strdup_printf ("%s/", manager->priv->object_path);
159       break;
160
161     default:
162       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
163       break;
164     }
165 }
166
167 static void
168 g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass)
169 {
170   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
171
172   gobject_class->finalize     = g_dbus_object_manager_server_finalize;
173   gobject_class->constructed  = g_dbus_object_manager_server_constructed;
174   gobject_class->set_property = g_dbus_object_manager_server_set_property;
175   gobject_class->get_property = g_dbus_object_manager_server_get_property;
176
177   /**
178    * GDBusObjectManagerServer:connection:
179    *
180    * The #GDBusConnection to export objects on.
181    *
182    * Since: 2.30
183    */
184   g_object_class_install_property (gobject_class,
185                                    PROP_CONNECTION,
186                                    g_param_spec_object ("connection",
187                                                         "Connection",
188                                                         "The connection to export objects on",
189                                                         G_TYPE_DBUS_CONNECTION,
190                                                         G_PARAM_READABLE |
191                                                         G_PARAM_WRITABLE |
192                                                         G_PARAM_CONSTRUCT_ONLY |
193                                                         G_PARAM_STATIC_STRINGS));
194
195   /**
196    * GDBusObjectManagerServer:object-path:
197    *
198    * The object path to register the manager object at.
199    *
200    * Since: 2.30
201    */
202   g_object_class_install_property (gobject_class,
203                                    PROP_OBJECT_PATH,
204                                    g_param_spec_string ("object-path",
205                                                         "Object Path",
206                                                         "The object path to register the manager object at",
207                                                         NULL,
208                                                         G_PARAM_READABLE |
209                                                         G_PARAM_WRITABLE |
210                                                         G_PARAM_CONSTRUCT_ONLY |
211                                                         G_PARAM_STATIC_STRINGS));
212
213   g_type_class_add_private (klass, sizeof (GDBusObjectManagerServerPrivate));
214 }
215
216 static void
217 g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager)
218 {
219   manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
220                                                G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
221                                                GDBusObjectManagerServerPrivate);
222   manager->priv->map_object_path_to_data = g_hash_table_new_full (g_str_hash,
223                                                                   g_str_equal,
224                                                                   g_free,
225                                                                   (GDestroyNotify) registration_data_free);
226 }
227
228 /**
229  * g_dbus_object_manager_server_new:
230  * @connection: A #GDBusConnection.
231  * @object_path: The object path to export the manager object at.
232  *
233  * Creates a new #GDBusObjectManagerServer object.
234  *
235  * TODO: make it so that the objects are not exported yet -
236  * e.g. start()/stop() semantics.
237  *
238  * Returns: A #GDBusObjectManagerServer object. Free with g_object_unref().
239  *
240  * Since: 2.30
241  */
242 GDBusObjectManagerServer *
243 g_dbus_object_manager_server_new (GDBusConnection *connection,
244                            const gchar     *object_path)
245 {
246   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
247   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
248   return G_DBUS_OBJECT_MANAGER_SERVER (g_object_new (G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
249                                               "connection", connection,
250                                               "object-path", object_path,
251                                               NULL));
252 }
253
254 /**
255  * g_dbus_object_manager_server_get_connection:
256  * @manager: A #GDBusObjectManagerServer
257  *
258  * Gets the #GDBusConnection used by @manager.
259  *
260  * Returns: (transfer none): A #GDBusConnection object. Do not free,
261  *   the object belongs to @manager.
262  *
263  * Since: 2.30
264  */
265 GDBusConnection *
266 g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager)
267 {
268   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), NULL);
269   return manager->priv->connection;
270 }
271
272 /* ---------------------------------------------------------------------------------------------------- */
273
274 static void
275 registration_data_export_interface (RegistrationData        *data,
276                                     GDBusInterfaceSkeleton  *interface_skeleton)
277 {
278   GDBusInterfaceInfo *info;
279   GError *error;
280   const gchar *object_path;
281
282   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
283
284   info = g_dbus_interface_skeleton_get_info (interface_skeleton);
285   error = NULL;
286   if (!g_dbus_interface_skeleton_export (interface_skeleton,
287                                          data->manager->priv->connection,
288                                          object_path,
289                                          &error))
290     {
291       /* TODO: probably wrong to complain on stderr */
292       g_warning ("%s: Error registering object at %s with interface %s: %s",
293                  G_STRLOC,
294                  object_path,
295                  info->name,
296                  error->message);
297       g_error_free (error);
298       goto out;
299     }
300
301   g_assert (g_hash_table_lookup (data->map_iface_name_to_iface, info->name) == NULL);
302   g_hash_table_insert (data->map_iface_name_to_iface,
303                        info->name,
304                        g_object_ref (interface_skeleton));
305
306   /* if we are already exported, then... */
307   if (data->exported)
308     {
309       const gchar *interfaces[2];
310       /* emit InterfacesAdded on the ObjectManager object */
311       interfaces[0] = info->name;
312       interfaces[1] = NULL;
313       g_dbus_object_manager_server_emit_interfaces_added (data->manager, data, interfaces);
314     }
315
316  out:
317   ;
318 }
319
320 static void
321 registration_data_unexport_interface (RegistrationData       *data,
322                                       GDBusInterfaceSkeleton *interface_skeleton)
323 {
324   GDBusInterfaceInfo *info;
325   GDBusInterfaceSkeleton *iface;
326
327   info = g_dbus_interface_skeleton_get_info (interface_skeleton);
328   iface = g_hash_table_lookup (data->map_iface_name_to_iface, info->name);
329   g_assert (iface != NULL);
330
331   g_dbus_interface_skeleton_unexport (iface);
332
333   g_warn_if_fail (g_hash_table_remove (data->map_iface_name_to_iface, info->name));
334
335   /* if we are already exported, then... */
336   if (data->exported)
337     {
338       const gchar *interfaces[2];
339       /* emit InterfacesRemoved on the ObjectManager object */
340       interfaces[0] = info->name;
341       interfaces[1] = NULL;
342       g_dbus_object_manager_server_emit_interfaces_removed (data->manager, data, interfaces);
343     }
344 }
345
346 /* ---------------------------------------------------------------------------------------------------- */
347
348 static void
349 on_interface_added (GDBusObject    *object,
350                     GDBusInterface *interface,
351                     gpointer        user_data)
352 {
353   RegistrationData *data = user_data;
354   registration_data_export_interface (data, G_DBUS_INTERFACE_SKELETON (interface));
355 }
356
357 static void
358 on_interface_removed (GDBusObject    *object,
359                       GDBusInterface *interface,
360                       gpointer        user_data)
361 {
362   RegistrationData *data = user_data;
363   registration_data_unexport_interface (data, G_DBUS_INTERFACE_SKELETON (interface));
364 }
365
366 /* ---------------------------------------------------------------------------------------------------- */
367
368
369 static void
370 registration_data_free (RegistrationData *data)
371 {
372   GHashTableIter iter;
373   GDBusInterfaceSkeleton *iface;
374
375   data->exported = FALSE;
376
377   g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
378   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &iface))
379     g_dbus_interface_skeleton_unexport (iface);
380
381   g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_added), data);
382   g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_removed), data);
383   g_object_unref (data->object);
384   g_hash_table_destroy (data->map_iface_name_to_iface);
385   g_free (data);
386 }
387
388 /* ---------------------------------------------------------------------------------------------------- */
389
390 /**
391  * g_dbus_object_manager_server_export:
392  * @manager: A #GDBusObjectManagerServer.
393  * @object: A #GDBusObjectSkeleton.
394  *
395  * Exports @object on @manager.
396  *
397  * If there is already a #GDBusObject exported at the object path,
398  * then the old object is removed.
399  *
400  * The object path for @object must be in the hierarchy rooted by the
401  * object path for @manager.
402  *
403  * Note that @manager will take a reference on @object for as long as
404  * it is exported.
405  *
406  * Since: 2.30
407  */
408 void
409 g_dbus_object_manager_server_export (GDBusObjectManagerServer  *manager,
410                                      GDBusObjectSkeleton       *object)
411 {
412   RegistrationData *data;
413   GList *existing_interfaces;
414   GList *l;
415   GPtrArray *interface_names;
416   const gchar *object_path;
417
418   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
419
420   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
421   g_return_if_fail (G_IS_DBUS_OBJECT (object));
422   g_return_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash));
423
424   interface_names = g_ptr_array_new ();
425
426   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
427   if (data != NULL)
428     g_dbus_object_manager_server_unexport (manager, object_path);
429
430   data = g_new0 (RegistrationData, 1);
431   data->object = g_object_ref (object);
432   data->manager = manager;
433   data->map_iface_name_to_iface = g_hash_table_new_full (g_str_hash,
434                                                          g_str_equal,
435                                                          NULL,
436                                                          (GDestroyNotify) g_object_unref);
437
438   g_signal_connect (object,
439                     "interface-added",
440                     G_CALLBACK (on_interface_added),
441                     data);
442   g_signal_connect (object,
443                     "interface-removed",
444                     G_CALLBACK (on_interface_removed),
445                     data);
446
447   /* Register all known interfaces - note that data->exported is FALSE so
448    * we don't emit any InterfacesAdded signals.
449    */
450   existing_interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object));
451   for (l = existing_interfaces; l != NULL; l = l->next)
452     {
453       GDBusInterfaceSkeleton *interface_skeleton = G_DBUS_INTERFACE_SKELETON (l->data);
454       registration_data_export_interface (data, interface_skeleton);
455       g_ptr_array_add (interface_names, g_dbus_interface_skeleton_get_info (interface_skeleton)->name);
456     }
457   g_list_foreach (existing_interfaces, (GFunc) g_object_unref, NULL);
458   g_list_free (existing_interfaces);
459   g_ptr_array_add (interface_names, NULL);
460
461   data->exported = TRUE;
462
463   /* now emit InterfacesAdded() for all the interfaces */
464   g_dbus_object_manager_server_emit_interfaces_added (manager, data, (const gchar *const *) interface_names->pdata);
465   g_ptr_array_unref (interface_names);
466
467   g_hash_table_insert (manager->priv->map_object_path_to_data,
468                        g_strdup (object_path),
469                        data);
470 }
471
472 /**
473  * g_dbus_object_manager_server_export_uniquely:
474  * @manager: A #GDBusObjectManagerServer.
475  * @object: An object.
476  *
477  * Like g_dbus_object_manager_server_export() but appends a string of
478  * the form <literal>_N</literal> (with N being a natural number) to
479  * @object<!-- -->'s object path if an object with the given path
480  * already exists. As such, the #GDBusObjectProxy:object-path property
481  * of @object may be modified.
482  *
483  * Since: 2.30
484  */
485 void
486 g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager,
487                                               GDBusObjectSkeleton      *object)
488 {
489   gchar *orig_object_path;
490   gchar *object_path;
491   guint count;
492   gboolean modified;
493
494   orig_object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
495
496   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
497   g_return_if_fail (G_IS_DBUS_OBJECT (object));
498   g_return_if_fail (g_str_has_prefix (orig_object_path, manager->priv->object_path_ending_in_slash));
499
500   object_path = g_strdup (orig_object_path);
501   count = 1;
502   modified = FALSE;
503   while (TRUE)
504     {
505       RegistrationData *data;
506       data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
507       if (data == NULL)
508         {
509           break;
510         }
511       g_free (object_path);
512       object_path = g_strdup_printf ("%s_%d", orig_object_path, count++);
513       modified = TRUE;
514     }
515
516   if (modified)
517     g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), object_path);
518
519   g_dbus_object_manager_server_export (manager, object);
520
521   g_free (object_path);
522   g_free (orig_object_path);
523 }
524
525 /**
526  * g_dbus_object_manager_server_unexport:
527  * @manager: A #GDBusObjectManagerServer.
528  * @object_path: An object path.
529  *
530  * If @manager has an object at @path, removes the object. Otherwise
531  * does nothing.
532  *
533  * Note that @object_path must be in the hierarchy rooted by the
534  * object path for @manager.
535  *
536  * Returns: %TRUE if object at @object_path was removed, %FALSE otherwise.
537  *
538  * Since: 2.30
539  */
540 gboolean
541 g_dbus_object_manager_server_unexport (GDBusObjectManagerServer  *manager,
542                                        const gchar         *object_path)
543 {
544   RegistrationData *data;
545   gboolean ret;
546
547   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
548   g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE);
549   g_return_val_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash), FALSE);
550
551   ret = FALSE;
552
553   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
554   if (data != NULL)
555     {
556       GPtrArray *interface_names;
557       GHashTableIter iter;
558       const gchar *iface_name;
559
560       interface_names = g_ptr_array_new ();
561       g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
562       while (g_hash_table_iter_next (&iter, (gpointer) &iface_name, NULL))
563         g_ptr_array_add (interface_names, (gpointer) iface_name);
564       g_ptr_array_add (interface_names, NULL);
565       /* now emit InterfacesRemoved() for all the interfaces */
566       g_dbus_object_manager_server_emit_interfaces_removed (manager, data, (const gchar *const *) interface_names->pdata);
567       g_ptr_array_unref (interface_names);
568
569       g_hash_table_remove (manager->priv->map_object_path_to_data, object_path);
570       ret = TRUE;
571     }
572
573   return ret;
574 }
575
576
577 /* ---------------------------------------------------------------------------------------------------- */
578
579 static const GDBusArgInfo manager_interfaces_added_signal_info_arg0 =
580 {
581   -1,
582   "object_path",
583   "o",
584   (GDBusAnnotationInfo**) NULL,
585 };
586
587 static const GDBusArgInfo manager_interfaces_added_signal_info_arg1 =
588 {
589   -1,
590   "interfaces_and_properties",
591   "a{sa{sv}}",
592   (GDBusAnnotationInfo**) NULL,
593 };
594
595 static const GDBusArgInfo * const manager_interfaces_added_signal_info_arg_pointers[] =
596 {
597   &manager_interfaces_added_signal_info_arg0,
598   &manager_interfaces_added_signal_info_arg1,
599   NULL
600 };
601
602 static const GDBusSignalInfo manager_interfaces_added_signal_info =
603 {
604   -1,
605   "InterfacesAdded",
606   (GDBusArgInfo**) &manager_interfaces_added_signal_info_arg_pointers,
607   (GDBusAnnotationInfo**) NULL
608 };
609
610 /* ---------- */
611
612 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg0 =
613 {
614   -1,
615   "object_path",
616   "o",
617   (GDBusAnnotationInfo**) NULL,
618 };
619
620 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg1 =
621 {
622   -1,
623   "interfaces",
624   "as",
625   (GDBusAnnotationInfo**) NULL,
626 };
627
628 static const GDBusArgInfo * const manager_interfaces_removed_signal_info_arg_pointers[] =
629 {
630   &manager_interfaces_removed_signal_info_arg0,
631   &manager_interfaces_removed_signal_info_arg1,
632   NULL
633 };
634
635 static const GDBusSignalInfo manager_interfaces_removed_signal_info =
636 {
637   -1,
638   "InterfacesRemoved",
639   (GDBusArgInfo**) &manager_interfaces_removed_signal_info_arg_pointers,
640   (GDBusAnnotationInfo**) NULL
641 };
642
643 /* ---------- */
644
645 static const GDBusSignalInfo * const manager_signal_info_pointers[] =
646 {
647   &manager_interfaces_added_signal_info,
648   &manager_interfaces_removed_signal_info,
649   NULL
650 };
651
652 /* ---------- */
653
654 static const GDBusArgInfo manager_get_all_method_info_out_arg0 =
655 {
656   -1,
657   "object_paths_interfaces_and_properties",
658   "a{oa{sa{sv}}}",
659   (GDBusAnnotationInfo**) NULL,
660 };
661
662 static const GDBusArgInfo * const manager_get_all_method_info_out_arg_pointers[] =
663 {
664   &manager_get_all_method_info_out_arg0,
665   NULL
666 };
667
668 static const GDBusMethodInfo manager_get_all_method_info =
669 {
670   -1,
671   "GetManagedObjects",
672   (GDBusArgInfo**) NULL,
673   (GDBusArgInfo**) &manager_get_all_method_info_out_arg_pointers,
674   (GDBusAnnotationInfo**) NULL
675 };
676
677 static const GDBusMethodInfo * const manager_method_info_pointers[] =
678 {
679   &manager_get_all_method_info,
680   NULL
681 };
682
683 /* ---------- */
684
685 static const GDBusInterfaceInfo manager_interface_info =
686 {
687   -1,
688   "org.freedesktop.DBus.ObjectManager",
689   (GDBusMethodInfo **) manager_method_info_pointers,
690   (GDBusSignalInfo **) manager_signal_info_pointers,
691   (GDBusPropertyInfo **) NULL,
692   (GDBusAnnotationInfo **) NULL
693 };
694
695 static void
696 manager_method_call (GDBusConnection       *connection,
697                      const gchar           *sender,
698                      const gchar           *object_path,
699                      const gchar           *interface_name,
700                      const gchar           *method_name,
701                      GVariant              *parameters,
702                      GDBusMethodInvocation *invocation,
703                      gpointer               user_data)
704 {
705   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (user_data);
706   GVariantBuilder array_builder;
707   GHashTableIter object_iter;
708   RegistrationData *data;
709
710   if (g_strcmp0 (method_name, "GetManagedObjects") == 0)
711     {
712       g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}"));
713       g_hash_table_iter_init (&object_iter, manager->priv->map_object_path_to_data);
714       while (g_hash_table_iter_next (&object_iter, NULL, (gpointer) &data))
715         {
716           GVariantBuilder interfaces_builder;
717           GHashTableIter interface_iter;
718           GDBusInterfaceSkeleton *iface;
719           const gchar *iter_object_path;
720
721           g_variant_builder_init (&interfaces_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
722           g_hash_table_iter_init (&interface_iter, data->map_iface_name_to_iface);
723           while (g_hash_table_iter_next (&interface_iter, NULL, (gpointer) &iface))
724             {
725               g_variant_builder_add_value (&interfaces_builder,
726                                            g_variant_new ("{s@a{sv}}",
727                                                           g_dbus_interface_skeleton_get_info (iface)->name,
728                                                           g_dbus_interface_skeleton_get_properties (iface)));
729             }
730           iter_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
731           g_variant_builder_add (&array_builder,
732                                  "{oa{sa{sv}}}",
733                                  iter_object_path,
734                                  &interfaces_builder);
735         }
736
737       g_dbus_method_invocation_return_value (invocation,
738                                              g_variant_new ("(a{oa{sa{sv}}})",
739                                                             &array_builder));
740     }
741   else
742     {
743       g_dbus_method_invocation_return_error (invocation,
744                                              G_DBUS_ERROR,
745                                              G_DBUS_ERROR_UNKNOWN_METHOD,
746                                              "Unknown method %s - only GetManagedObjects() is supported",
747                                              method_name);
748     }
749 }
750
751 static const GDBusInterfaceVTable manager_interface_vtable =
752 {
753   manager_method_call, /* handle_method_call */
754   NULL, /* get_property */
755   NULL  /* set_property */
756 };
757
758 /* ---------------------------------------------------------------------------------------------------- */
759
760 static void
761 g_dbus_object_manager_server_constructed (GObject *object)
762 {
763   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
764   GError *error;
765
766   error = NULL;
767   manager->priv->manager_reg_id = g_dbus_connection_register_object (manager->priv->connection,
768                                                                      manager->priv->object_path,
769                                                                      (GDBusInterfaceInfo *) &manager_interface_info,
770                                                                      &manager_interface_vtable,
771                                                                      manager,
772                                                                      NULL, /* user_data_free_func */
773                                                                      &error);
774   if (manager->priv->manager_reg_id == 0)
775     {
776       /* TODO: probably wrong to complain on stderr */
777       g_warning ("%s: Error registering manager at %s: %s",
778                  G_STRLOC,
779                  manager->priv->object_path,
780                  error->message);
781       g_error_free (error);
782     }
783
784   if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed != NULL)
785     G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed (object);
786 }
787
788 static void
789 g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
790                                              RegistrationData   *data,
791                                              const gchar *const *interfaces)
792 {
793   GVariantBuilder array_builder;
794   GError *error;
795   guint n;
796   const gchar *object_path;
797
798   g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
799   for (n = 0; interfaces[n] != NULL; n++)
800     {
801       GDBusInterfaceSkeleton *iface;
802       iface = g_hash_table_lookup (data->map_iface_name_to_iface, interfaces[n]);
803       g_assert (iface != NULL);
804       g_variant_builder_add_value (&array_builder,
805                                    g_variant_new ("{s@a{sv}}",
806                                                   interfaces[n],
807                                                   g_dbus_interface_skeleton_get_properties (iface)));
808     }
809
810   error = NULL;
811   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
812   g_dbus_connection_emit_signal (data->manager->priv->connection,
813                                  NULL, /* destination_bus_name */
814                                  manager->priv->object_path,
815                                  manager_interface_info.name,
816                                  "InterfacesAdded",
817                                  g_variant_new ("(oa{sa{sv}})",
818                                                 object_path,
819                                                 &array_builder),
820                                  &error);
821   g_assert_no_error (error);
822 }
823
824 static void
825 g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
826                                                RegistrationData   *data,
827                                                const gchar *const *interfaces)
828 {
829   GVariantBuilder array_builder;
830   GError *error;
831   guint n;
832   const gchar *object_path;
833
834   g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
835   for (n = 0; interfaces[n] != NULL; n++)
836     g_variant_builder_add (&array_builder, "s", interfaces[n]);
837
838   error = NULL;
839   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
840   g_dbus_connection_emit_signal (data->manager->priv->connection,
841                                  NULL, /* destination_bus_name */
842                                  manager->priv->object_path,
843                                  manager_interface_info.name,
844                                  "InterfacesRemoved",
845                                  g_variant_new ("(oas)",
846                                                 object_path,
847                                                 &array_builder),
848                                  &error);
849   g_assert_no_error (error);
850 }
851
852 /* ---------------------------------------------------------------------------------------------------- */
853
854 static GList *
855 g_dbus_object_manager_server_get_objects (GDBusObjectManager  *_manager)
856 {
857   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
858   GList *ret;
859   GHashTableIter iter;
860   RegistrationData *data;
861
862   ret = NULL;
863   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
864   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
865     {
866       ret = g_list_prepend (ret, g_object_ref (data->object));
867     }
868
869   return ret;
870 }
871
872 static const gchar *
873 g_dbus_object_manager_server_get_object_path (GDBusObjectManager *_manager)
874 {
875   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
876   return manager->priv->object_path;
877 }
878
879 static GDBusObject *
880 g_dbus_object_manager_server_get_object (GDBusObjectManager *_manager,
881                                          const gchar        *object_path)
882 {
883   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
884   GDBusObject *ret;
885   RegistrationData *data;
886
887   ret = NULL;
888   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
889   if (data != NULL)
890     ret = g_object_ref (data->object);
891   return ret;
892 }
893
894 static GDBusInterface *
895 g_dbus_object_manager_server_get_interface  (GDBusObjectManager  *_manager,
896                                              const gchar         *object_path,
897                                              const gchar         *interface_name)
898 {
899   GDBusInterface *ret;
900   GDBusObject *object;
901
902   ret = NULL;
903
904   object = g_dbus_object_manager_get_object (_manager, object_path);
905   if (object == NULL)
906     goto out;
907
908   ret = g_dbus_object_get_interface (object, interface_name);
909   g_object_unref (object);
910
911  out:
912   return ret;
913 }
914
915 static void
916 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
917 {
918   iface->get_object_path = g_dbus_object_manager_server_get_object_path;
919   iface->get_objects     = g_dbus_object_manager_server_get_objects;
920   iface->get_object      = g_dbus_object_manager_server_get_object;
921   iface->get_interface   = g_dbus_object_manager_server_get_interface;
922 }