diff options
Diffstat (limited to 'dbus/dbus-object.c')
-rw-r--r-- | dbus/dbus-object.c | 324 |
1 files changed, 321 insertions, 3 deletions
diff --git a/dbus/dbus-object.c b/dbus/dbus-object.c index fdd33dd4..262f75ca 100644 --- a/dbus/dbus-object.c +++ b/dbus/dbus-object.c @@ -1,10 +1,10 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-object.c DBusObject type +/* dbus-object.c Objects * * Copyright (C) 2003 Red Hat Inc. * * Licensed under the Academic Free License version 1.2 - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -14,7 +14,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -25,3 +25,321 @@ #include "dbus-internals.h" #include "dbus-object.h" +/** + * @defgroup DBusCallbackObjectInternals DBusCallbackObject implementation details + * @ingroup DBusInternals + * @brief DBusCallbackObject private implementation details. + * + * The guts of DBusCallbackObject and its methods. + * + * @{ + */ + +_DBUS_DEFINE_GLOBAL_LOCK (callback_object); + +/** + * @brief Internals of DBusCallbackObject + * + * Object that can send and receive messages. + */ +struct DBusCallbackObject +{ + DBusAtomic refcount; /**< reference count */ + DBusObjectMessageFunction function; /**< callback function */ + void *user_data; /**< user data for function */ + DBusFreeFunction free_user_data; /**< free the user data */ +}; + +static void +callback_object_registered (DBusObjectInfo *info) +{ + DBusCallbackObject *callback = info->object_impl; + + dbus_callback_object_ref (callback); +} + +static void +callback_object_unregistered (DBusObjectInfo *info) +{ + DBusCallbackObject *callback = info->object_impl; + + dbus_callback_object_unref (callback); +} + +static void +callback_object_message (DBusObjectInfo *info, + DBusMessage *message) +{ + DBusCallbackObject *callback = info->object_impl; + + if (callback->function) + (* callback->function) (info, message); +} + +/** @} */ + +/** + * @defgroup DBusObject DBusObjectInfo, DBusObjectVTable, DBusCallbackObject + * @ingroup DBus + * @brief support for object instances + * + * Behind each DBusConnection are object instances. An object instance + * may be a GObject (using GLib), a QObject (using Qt), a built-in + * object type called DBusCallbackObject, or any other representation + * of an object; it's even permissible to have an object that's simply + * an integer value or a pointer to a struct. + * + * Objects are registered with one or more DBusConnection. Registered + * objects receive an object ID, represented by the DBusObjectID type. + * Object IDs can be passed over a DBusConnection and used by the + * remote application to refer to objects. Remote applications can + * also refer to objects by dynamically locating objects that support + * a particular interface. + * + * To define an object, you simply provide three callbacks: one to be + * called when the object is registered with a new connection, one + * to be called when the object is unregistered, and one to be called + * when the object receives a message from the peer on the other end + * of the DBusConnection. The three callbacks are specified in a + * DBusObjectVTable struct. + * + * The DBusObjectInfo struct is used to pass the object pointer + * (object_impl), connection, and object ID to each of the callbacks + * in the virtual table. This struct should be treated as read-only. + * + * DBusCallbackObject is provided for convenience as a way to + * implement an object quickly by writing only one callback function, + * the callback that processes messages. To use DBusCallbackObject, + * simply create one, then call dbus_connection_register_object() + * passing in the provided DBusObjectVTable + * dbus_callback_object_vtable. This is the simplest possible object; + * it simply contains a function to be called whenever a message is + * received. + * + * The DBusCallbackObject will be strong-referenced by the + * DBusConnection, so may be unreferenced once it's registered, and + * will go away either on unregistration or when the connection is + * freed. + * + * One DBusCallbackObject may be registered with any number of + * DBusConnection. + * + * @{ + */ + +/** + * @typedef DBusCallbackObject + * + * Opaque data type representing a callback object. + */ + +static const DBusObjectVTable callback_object_vtable = { + callback_object_registered, + callback_object_unregistered, + callback_object_message +}; + +/** + * Virtual table for a DBusCallbackObject, used to register the + * callback object with dbus_connection_register_object(). + */ +const DBusObjectVTable* dbus_callback_object_vtable = &callback_object_vtable; + +/** + * Creates a new callback object. The callback function + * may be #NULL for a no-op callback or a callback to + * be assigned a function later. + * + * Use dbus_connection_register_object() along with + * dbus_callback_object_vtable to register the callback object with + * one or more connections. Each connection will add a reference to + * the callback object, so once it's registered it may be unreferenced + * with dbus_callback_object_unref(). + * + * @param function function to call to handle a message + * @param user_data data to pass to the function + * @param free_user_data function to call to free the user data + * @returns a new DBusCallbackObject or #NULL if no memory. + */ +DBusCallbackObject* +dbus_callback_object_new (DBusObjectMessageFunction function, + void *user_data, + DBusFreeFunction free_user_data) +{ + DBusCallbackObject *callback; + + callback = dbus_new0 (DBusCallbackObject, 1); + if (callback == NULL) + return NULL; + + callback->refcount.value = 1; + callback->function = function; + callback->user_data = user_data; + callback->free_user_data = free_user_data; + + return callback; +} + +/** + * Increments the reference count on a callback object. + * + * @param callback the callback + */ +void +dbus_callback_object_ref (DBusCallbackObject *callback) +{ + _dbus_return_if_fail (callback != NULL); + + _dbus_atomic_inc (&callback->refcount); +} + + +/** + * Decrements the reference count on a callback object, + * freeing the callback if the count reaches 0. + * + * @param callback the callback + */ +void +dbus_callback_object_unref (DBusCallbackObject *callback) +{ + dbus_bool_t last_unref; + + _dbus_return_if_fail (callback != NULL); + + last_unref = (_dbus_atomic_dec (&callback->refcount) == 1); + + if (last_unref) + { + if (callback->free_user_data) + (* callback->free_user_data) (callback->user_data); + + dbus_free (callback); + } +} + +/** + * Gets the user data for the callback. + * + * @param callback the callback + * @returns the user data + */ +void* +dbus_callback_object_get_data (DBusCallbackObject *callback) +{ + void* user_data; + + _dbus_return_val_if_fail (callback != NULL, NULL); + + _DBUS_LOCK (callback_object); + user_data = callback->user_data; + _DBUS_UNLOCK (callback_object); + return user_data; +} + + +/** + * Sets the user data for the callback. Frees any previously-existing + * user data with the previous free_user_data function. + * + * @param callback the callback + * @param user_data the user data + * @param free_user_data free function for the data + */ +void +dbus_callback_object_set_data (DBusCallbackObject *callback, + void *user_data, + DBusFreeFunction free_user_data) +{ + DBusFreeFunction old_free_func; + void *old_user_data; + + _dbus_return_if_fail (callback != NULL); + + _DBUS_LOCK (callback_object); + old_free_func = callback->free_user_data; + old_user_data = callback->user_data; + + callback->user_data = user_data; + callback->free_user_data = free_user_data; + _DBUS_UNLOCK (callback_object); + + if (old_free_func) + (* old_free_func) (old_user_data); +} + +/** + * Sets the function to be used to handle messages to the + * callback object. + * + * @param callback the callback + * @param function the function + */ +void +dbus_callback_object_set_function (DBusCallbackObject *callback, + DBusObjectMessageFunction function) +{ + _dbus_return_if_fail (callback != NULL); + + _DBUS_LOCK (callback_object); + callback->function = function; + _DBUS_UNLOCK (callback_object); +} + + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include <stdio.h> + +static void +test_message_function (DBusObjectInfo *info, + DBusMessage *message) +{ + /* nothing */ +} + +static void +free_test_data (void *data) +{ + /* does nothing */ +} + +/** + * @ingroup DBusCallbackObjectInternals + * Unit test for DBusCallbackObject. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_object_test (void) +{ + DBusCallbackObject *callback; + +#define TEST_DATA ((void*) 0xcafebabe) + + callback = dbus_callback_object_new (test_message_function, + TEST_DATA, + free_test_data); + + _dbus_assert (callback != NULL); + _dbus_assert (callback->function == test_message_function); + + if (dbus_callback_object_get_data (callback) != TEST_DATA) + _dbus_assert_not_reached ("got wrong data"); + + dbus_callback_object_set_data (callback, NULL, NULL); + if (dbus_callback_object_get_data (callback) != NULL) + _dbus_assert_not_reached ("got wrong data after set"); + + dbus_callback_object_set_function (callback, NULL); + _dbus_assert (callback->function == NULL); + + dbus_callback_object_ref (callback); + dbus_callback_object_unref (callback); + dbus_callback_object_unref (callback); + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ |