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