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