1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
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.
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.
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.
20 * Author: David Zeuthen <davidz@redhat.com>
25 #include "gdbusobject.h"
26 #include "gdbusobjectskeleton.h"
27 #include "gdbusinterfaceskeleton.h"
28 #include "gio-marshal.h"
29 #include "gdbusprivate.h"
30 #include "gdbusmethodinvocation.h"
31 #include "gdbusintrospection.h"
32 #include "gdbusinterface.h"
33 #include "gdbusutils.h"
38 * SECTION:gdbusobjectskeleton
39 * @short_description: Service-side D-Bus object
42 * A #GDBusObjectSkeleton instance is essentially a group of D-Bus
43 * interfaces. The set of exported interfaces on the object may be
44 * dynamic and change at runtime.
46 * This type is intended to be used with #GDBusObjectManager.
49 struct _GDBusObjectSkeletonPrivate
52 GHashTable *map_name_to_iface;
63 AUTHORIZE_METHOD_SIGNAL,
67 static guint signals[LAST_SIGNAL] = {0};
69 static void dbus_object_interface_init (GDBusObjectIface *iface);
71 G_DEFINE_TYPE_WITH_CODE (GDBusObjectSkeleton, g_dbus_object_skeleton, G_TYPE_OBJECT,
72 G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT, dbus_object_interface_init));
76 g_dbus_object_skeleton_finalize (GObject *_object)
78 GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
80 g_free (object->priv->object_path);
81 g_hash_table_unref (object->priv->map_name_to_iface);
83 if (G_OBJECT_CLASS (g_dbus_object_skeleton_parent_class)->finalize != NULL)
84 G_OBJECT_CLASS (g_dbus_object_skeleton_parent_class)->finalize (_object);
88 g_dbus_object_skeleton_get_property (GObject *_object,
93 GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
97 case PROP_OBJECT_PATH:
98 g_value_take_string (value, object->priv->object_path);
102 G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
108 g_dbus_object_skeleton_set_property (GObject *_object,
113 GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
117 case PROP_OBJECT_PATH:
118 g_dbus_object_skeleton_set_object_path (object, g_value_get_string (value));
122 G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
128 g_dbus_object_skeleton_authorize_method_default (GDBusObjectSkeleton *object,
129 GDBusInterfaceSkeleton *interface,
130 GDBusMethodInvocation *invocation)
136 g_dbus_object_skeleton_class_init (GDBusObjectSkeletonClass *klass)
138 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
140 gobject_class->finalize = g_dbus_object_skeleton_finalize;
141 gobject_class->set_property = g_dbus_object_skeleton_set_property;
142 gobject_class->get_property = g_dbus_object_skeleton_get_property;
144 klass->authorize_method = g_dbus_object_skeleton_authorize_method_default;
147 * GDBusObjectSkeleton:object-path:
149 * The object path where the object is exported.
153 g_object_class_install_property (gobject_class,
155 g_param_spec_string ("object-path",
157 "The object path where the object is exported",
162 G_PARAM_STATIC_STRINGS));
165 * GDBusObjectSkeleton::authorize-method:
166 * @object: The #GDBusObjectSkeleton emitting the signal.
167 * @interface: The #GDBusInterfaceSkeleton that @invocation is for.
168 * @invocation: A #GDBusMethodInvocation.
170 * Emitted when a method is invoked by a remote caller and used to
171 * determine if the method call is authorized.
173 * This signal is like #GDBusInterfaceSkeleton<!-- -->'s
174 * #GDBusInterfaceSkeleton::g-authorize-method signal, except that it is
175 * for the enclosing object.
177 * The default class handler just returns %TRUE.
179 * Returns: %TRUE if the call is authorized, %FALSE otherwise.
183 signals[AUTHORIZE_METHOD_SIGNAL] =
184 g_signal_new ("authorize-method",
185 G_TYPE_DBUS_OBJECT_SKELETON,
187 G_STRUCT_OFFSET (GDBusObjectSkeletonClass, authorize_method),
188 _g_signal_accumulator_false_handled,
190 _gio_marshal_BOOLEAN__OBJECT_OBJECT,
193 G_TYPE_DBUS_INTERFACE_SKELETON,
194 G_TYPE_DBUS_METHOD_INVOCATION);
196 g_type_class_add_private (klass, sizeof (GDBusObjectSkeletonPrivate));
200 g_dbus_object_skeleton_init (GDBusObjectSkeleton *object)
202 object->priv = G_TYPE_INSTANCE_GET_PRIVATE (object, G_TYPE_DBUS_OBJECT_SKELETON, GDBusObjectSkeletonPrivate);
203 object->priv->map_name_to_iface = g_hash_table_new_full (g_str_hash,
206 (GDestroyNotify) g_object_unref);
210 * g_dbus_object_skeleton_new:
211 * @object_path: An object path.
213 * Creates a new #GDBusObjectSkeleton.
215 * Returns: A #GDBusObjectSkeleton. Free with g_object_unref().
219 GDBusObjectSkeleton *
220 g_dbus_object_skeleton_new (const gchar *object_path)
222 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
223 return G_DBUS_OBJECT_SKELETON (g_object_new (G_TYPE_DBUS_OBJECT_SKELETON,
224 "object-path", object_path,
229 * g_dbus_object_skeleton_set_object_path:
230 * @object: A #GDBusObjectSkeleton.
231 * @object_path: A valid D-Bus object path.
233 * Sets the object path for @object.
238 g_dbus_object_skeleton_set_object_path (GDBusObjectSkeleton *object,
239 const gchar *object_path)
241 g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
242 g_return_if_fail (object_path == NULL || g_variant_is_object_path (object_path));
243 /* TODO: fail if object is currently exported */
244 if (g_strcmp0 (object->priv->object_path, object_path) != 0)
246 g_free (object->priv->object_path);
247 object->priv->object_path = g_strdup (object_path);
248 g_object_notify (G_OBJECT (object), "object-path");
253 g_dbus_object_skeleton_get_object_path (GDBusObject *_object)
255 GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
256 return object->priv->object_path;
260 * g_dbus_object_skeleton_add_interface:
261 * @object: A #GDBusObjectSkeleton.
262 * @interface_: A #GDBusInterfaceSkeleton.
264 * Adds @interface_ to @object.
266 * If @object already contains a #GDBusInterfaceSkeleton with the same
267 * interface name, it is removed before @interface_ is added.
269 * Note that @object takes its own reference on @interface_ and holds
275 g_dbus_object_skeleton_add_interface (GDBusObjectSkeleton *object,
276 GDBusInterfaceSkeleton *interface_)
278 GDBusInterfaceInfo *info;
280 g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
281 g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
283 info = g_dbus_interface_skeleton_get_info (interface_);
284 g_object_ref (interface_);
285 g_dbus_object_skeleton_remove_interface_by_name (object, info->name);
286 g_hash_table_insert (object->priv->map_name_to_iface,
287 g_strdup (info->name),
289 g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_), G_DBUS_OBJECT (object));
290 g_signal_emit_by_name (object,
296 * g_dbus_object_skeleton_remove_interface:
297 * @object: A #GDBusObjectSkeleton.
298 * @interface_: A #GDBusInterfaceSkeleton.
300 * Removes @interface_ from @object.
305 g_dbus_object_skeleton_remove_interface (GDBusObjectSkeleton *object,
306 GDBusInterfaceSkeleton *interface_)
308 GDBusInterfaceSkeleton *other_interface;
309 GDBusInterfaceInfo *info;
311 g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
312 g_return_if_fail (G_IS_DBUS_INTERFACE (interface_));
314 info = g_dbus_interface_skeleton_get_info (interface_);
316 other_interface = g_hash_table_lookup (object->priv->map_name_to_iface, info->name);
317 if (other_interface == NULL)
319 g_warning ("Tried to remove interface with name %s from object "
320 "at path %s but no such interface exists",
322 object->priv->object_path);
324 else if (other_interface != interface_)
326 g_warning ("Tried to remove interface %p with name %s from object "
327 "at path %s but the object has the interface %p",
330 object->priv->object_path,
335 g_object_ref (interface_);
336 g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, info->name));
337 g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_), NULL);
338 g_signal_emit_by_name (object,
341 g_object_unref (interface_);
347 * g_dbus_object_skeleton_remove_interface_by_name:
348 * @object: A #GDBusObjectSkeleton.
349 * @interface_name: A D-Bus interface name.
351 * Removes the #GDBusInterface with @interface_name from @object.
353 * If no D-Bus interface of the given interface exists, this function
359 g_dbus_object_skeleton_remove_interface_by_name (GDBusObjectSkeleton *object,
360 const gchar *interface_name)
362 GDBusInterface *interface;
364 g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
365 g_return_if_fail (g_dbus_is_interface_name (interface_name));
367 interface = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
368 if (interface != NULL)
370 g_object_ref (interface);
371 g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, interface_name));
372 g_dbus_interface_set_object (interface, NULL);
373 g_signal_emit_by_name (object,
376 g_object_unref (interface);
380 static GDBusInterface *
381 g_dbus_object_skeleton_get_interface (GDBusObject *_object,
382 const gchar *interface_name)
384 GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
387 g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), NULL);
388 g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
390 ret = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
397 g_dbus_object_skeleton_get_interfaces (GDBusObject *_object)
399 GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
402 GDBusInterface *interface;
404 g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), NULL);
408 g_hash_table_iter_init (&iter, object->priv->map_name_to_iface);
409 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &interface))
410 ret = g_list_prepend (ret, g_object_ref (interface));
416 * g_dbus_object_skeleton_flush:
417 * @object: A #GDBusObjectSkeleton.
419 * This method simply calls g_dbus_interface_skeleton_flush() on all
420 * interfaces belonging to @object. See that method for when flushing
426 g_dbus_object_skeleton_flush (GDBusObjectSkeleton *object)
429 GDBusInterfaceSkeleton *interface_skeleton;
431 g_hash_table_iter_init (&iter, object->priv->map_name_to_iface);
432 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &interface_skeleton))
434 g_dbus_interface_skeleton_flush (interface_skeleton);
439 g_dbus_object_skeleton_lookup_with_typecheck (GDBusObject *object,
440 const gchar *interface_name,
443 GDBusObjectSkeleton *skeleton = G_DBUS_OBJECT_SKELETON (object);
446 ret = g_hash_table_lookup (skeleton->priv->map_name_to_iface, interface_name);
449 g_warn_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (ret, type));
456 g_dbus_object_skeleton_peek_with_typecheck (GDBusObject *object,
457 const gchar *interface_name,
460 GDBusInterfaceSkeleton *ret;
461 ret = g_dbus_object_skeleton_lookup_with_typecheck (object, interface_name, type);
463 g_object_unref (ret);
468 dbus_object_interface_init (GDBusObjectIface *iface)
470 iface->get_object_path = g_dbus_object_skeleton_get_object_path;
471 iface->get_interfaces = g_dbus_object_skeleton_get_interfaces;
472 iface->get_interface = g_dbus_object_skeleton_get_interface;
473 iface->lookup_with_typecheck = g_dbus_object_skeleton_lookup_with_typecheck;
474 iface->peek_with_typecheck = g_dbus_object_skeleton_peek_with_typecheck;
478 _g_dbus_object_skeleton_has_authorize_method_handlers (GDBusObjectSkeleton *object)
480 gboolean has_handlers;
481 gboolean has_default_class_handler;
483 has_handlers = g_signal_has_handler_pending (object,
484 signals[AUTHORIZE_METHOD_SIGNAL],
487 has_default_class_handler = (G_DBUS_OBJECT_SKELETON_GET_CLASS (object)->authorize_method ==
488 g_dbus_object_skeleton_authorize_method_default);
490 return has_handlers || !has_default_class_handler;