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