Commit 583994cb authored by Havoc Pennington's avatar Havoc Pennington

2003-09-15 Havoc Pennington <hp@pobox.com>

	* dbus/dbus-pending-call.c: add the get/set object data
	boilerplate as for DBusConnection, etc. Use generic object data
	for the notify callback.

	* glib/dbus-gparser.c (parse_node): parse child nodes

	* tools/dbus-viewer.c: more hacking on the dbus-viewer

	* glib/dbus-gutils.c (_dbus_gutils_split_path): add a file to
	contain functions shared between the convenience lib and the
	installed lib

	* glib/Makefile.am (libdbus_glib_1_la_LDFLAGS): add
	-export-symbols-regex to the GLib library

	* dbus/dbus-object-tree.c (_dbus_object_tree_dispatch_and_unlock):
	fix the locking in here, and add a default handler for
	Introspect() that just returns sub-nodes.

2003-09-14  Havoc Pennington  <hp@pobox.com>

	* glib/dbus-gthread.c (dbus_g_thread_init): rename to make g_foo
	rather than gfoo consistent

	* glib/dbus-gproxy.h: delete for now, move contents to
	dbus-glib.h, because the include files don't work right since we
	aren't in the dbus/ subdir.

	* glib/dbus-gproxy.c (dbus_gproxy_send): finish implementing
	(dbus_gproxy_end_call): finish
	(dbus_gproxy_begin_call): finish

	* glib/dbus-gmain.c (dbus_set_g_error): new

	* glib/dbus-gobject.c (handle_introspect): include information
	about child nodes in the introspection

	* dbus/dbus-connection.c (dbus_connection_list_registered): new
	function to help in implementation of introspection

	* dbus/dbus-object-tree.c
	(_dbus_object_tree_list_registered_and_unlock): new function

2003-09-12  Havoc Pennington  <hp@pobox.com>

	* glib/dbus-gidl.h: add common base class for all the foo_info
	types

        * tools/dbus-viewer.c: add GTK-based introspection UI thingy
	similar to kdcop

	* test/Makefile.am: try test srcdir -ef . in addition to test
	srcdir = ., one of them should work (yeah lame)

        * glib/Makefile.am: build the "idl" parser stuff as a convenience
	library

	* glib/dbus-gparser.h: make description_load routines return
	NodeInfo* not Parser*

	* Makefile.am (SUBDIRS): build test dir after all library dirs

	* configure.in: add GTK+ detection
parent 85ab0327
2003-09-15 Havoc Pennington <hp@pobox.com>
* dbus/dbus-pending-call.c: add the get/set object data
boilerplate as for DBusConnection, etc. Use generic object data
for the notify callback.
* glib/dbus-gparser.c (parse_node): parse child nodes
* tools/dbus-viewer.c: more hacking on the dbus-viewer
* glib/dbus-gutils.c (_dbus_gutils_split_path): add a file to
contain functions shared between the convenience lib and the
installed lib
* glib/Makefile.am (libdbus_glib_1_la_LDFLAGS): add
-export-symbols-regex to the GLib library
* dbus/dbus-object-tree.c (_dbus_object_tree_dispatch_and_unlock):
fix the locking in here, and add a default handler for
Introspect() that just returns sub-nodes.
2003-09-14 Havoc Pennington <hp@pobox.com>
* glib/dbus-gthread.c (dbus_g_thread_init): rename to make g_foo
rather than gfoo consistent
* glib/dbus-gproxy.h: delete for now, move contents to
dbus-glib.h, because the include files don't work right since we
aren't in the dbus/ subdir.
* glib/dbus-gproxy.c (dbus_gproxy_send): finish implementing
(dbus_gproxy_end_call): finish
(dbus_gproxy_begin_call): finish
* glib/dbus-gmain.c (dbus_set_g_error): new
* glib/dbus-gobject.c (handle_introspect): include information
about child nodes in the introspection
* dbus/dbus-connection.c (dbus_connection_list_registered): new
function to help in implementation of introspection
* dbus/dbus-object-tree.c
(_dbus_object_tree_list_registered_and_unlock): new function
2003-09-12 Havoc Pennington <hp@pobox.com>
* glib/dbus-gidl.h: add common base class for all the foo_info
types
* tools/dbus-viewer.c: add GTK-based introspection UI thingy
similar to kdcop
* test/Makefile.am: try test srcdir -ef . in addition to test
srcdir = ., one of them should work (yeah lame)
* glib/Makefile.am: build the "idl" parser stuff as a convenience
library
* glib/dbus-gparser.h: make description_load routines return
NodeInfo* not Parser*
* Makefile.am (SUBDIRS): build test dir after all library dirs
* configure.in: add GTK+ detection
2003-09-07 Havoc Pennington <hp@pobox.com>
* Make Doxygen contented.
......
......@@ -17,7 +17,7 @@ if DBUS_USE_MCS
endif
SUBDIRS=dbus bus test doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) tools
SUBDIRS=dbus bus doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) test tools
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = dbus-1.pc $(GLIB_PC)
......
......@@ -24,6 +24,7 @@ AC_HEADER_STDC
AC_ARG_ENABLE(qt, [ --enable-qt enable Qt-friendly client library],enable_qt=$enableval,enable_qt=auto)
AC_ARG_ENABLE(glib, [ --enable-glib enable GLib-friendly client library],enable_glib=$enableval,enable_glib=auto)
AC_ARG_ENABLE(gtk, [ --enable-gtk enable GTK-requiring executables],enable_gtk=$enableval,enable_gtk=auto)
AC_ARG_ENABLE(tests, [ --enable-tests enable unit test code],enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE)
AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no)
AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
......@@ -577,6 +578,34 @@ DBUS_GLIB_TOOL_LIBS=$XML_LIBS
AC_SUBST(DBUS_GLIB_TOOL_CFLAGS)
AC_SUBST(DBUS_GLIB_TOOL_LIBS)
# GTK detection
if test x$have_glib = xno ; then
AC_MSG_WARN([Can't use GTK+ since GLib not enabled])
have_gtk=no
else
PKG_CHECK_MODULES(DBUS_GTK, gtk+-2.0, have_gtk=yes, have_gtk=no)
fi
if test x$have_gtk = xno ; then
AC_MSG_WARN([GTK+ development libraries not found])
fi
if test x$enable_gtk = xyes; then
if test x$have_gtk = xno; then
AC_MSG_ERROR([GTK+ explicitly required, and GTK+ development libraries not found])
fi
fi
if test x$enable_gtk = xno; then
have_gtk=no;
fi
AM_CONDITIONAL(HAVE_GTK, test x$have_gtk = xyes)
dnl Gtk flags
AC_SUBST(DBUS_GTK_CFLAGS)
AC_SUBST(DBUS_GTK_LIBS)
# Qt detection
have_qt=no
AC_MSG_CHECKING([for qglobal.h])
......@@ -885,6 +914,7 @@ echo "
Building checks: ${enable_checks}
Building Qt bindings: ${have_qt}
Building GLib bindings: ${have_glib}
Building GTK+ tools: ${have_gtk}
Building X11 code: ${enable_x11}
Building documentation: ${enable_docs}
Using XML parser: ${with_xml}
......
......@@ -30,6 +30,7 @@
#include <dbus/dbus-resources.h>
#include <dbus/dbus-list.h>
#include <dbus/dbus-timeout.h>
#include <dbus/dbus-dataslot.h>
DBUS_BEGIN_DECLS;
......@@ -104,9 +105,9 @@ struct DBusPendingCall
{
DBusAtomic refcount; /**< reference count */
DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */
DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */
void *user_data; /**< user data for function */
DBusFreeFunction free_user_data; /**< free the user data */
DBusConnection *connection; /**< Connections we're associated with */
DBusMessage *reply; /**< Reply (after we've received it) */
......
......@@ -3101,7 +3101,6 @@ dbus_connection_register_object_path (DBusConnection *connection,
* path. You can use this to establish a default message handling
* policy for a whole "subdirectory."
*
*
* @param connection the connection
* @param path #NULL-terminated array of path elements
* @param vtable the virtual table
......@@ -3136,6 +3135,7 @@ dbus_connection_register_fallback (DBusConnection *connection,
/**
* Unregisters the handler registered with exactly the given path.
* It's a bug to call this function for a path that isn't registered.
* Can unregister both fallback paths and object paths.
*
* @param connection the connection
* @param path the #NULL-terminated array of path elements
......@@ -3154,6 +3154,32 @@ dbus_connection_unregister_object_path (DBusConnection *connection,
path);
}
/**
* Lists the registered fallback handlers and object path handlers at
* the given parent_path. The returned array should be freed with
* dbus_free_string_array().
*
* @param connection the connection
* @param parent_path the path to list the child handlers of
* @param child_entries returns #NULL-terminated array of children
* @returns #FALSE if no memory to allocate the child entries
*/
dbus_bool_t
dbus_connection_list_registered (DBusConnection *connection,
const char **parent_path,
char ***child_entries)
{
_dbus_return_val_if_fail (connection != NULL, FALSE);
_dbus_return_val_if_fail (parent_path != NULL, FALSE);
_dbus_return_val_if_fail (child_entries != NULL, FALSE);
CONNECTION_LOCK (connection);
return _dbus_object_tree_list_registered_and_unlock (connection->objects,
parent_path,
child_entries);
}
static DBusDataSlotAllocator slot_allocator;
_DBUS_DEFINE_GLOBAL_LOCK (connection_slots);
......
......@@ -240,6 +240,9 @@ dbus_bool_t dbus_connection_register_fallback (DBusConnection
void dbus_connection_unregister_object_path (DBusConnection *connection,
const char **path);
dbus_bool_t dbus_connection_list_registered (DBusConnection *connection,
const char **parent_path,
char ***child_entries);
DBUS_END_DECLS;
......
......@@ -230,13 +230,14 @@ extern int _dbus_current_generation;
_DBUS_DECLARE_GLOBAL_LOCK (list);
_DBUS_DECLARE_GLOBAL_LOCK (connection_slots);
_DBUS_DECLARE_GLOBAL_LOCK (pending_call_slots);
_DBUS_DECLARE_GLOBAL_LOCK (server_slots);
_DBUS_DECLARE_GLOBAL_LOCK (message_slots);
_DBUS_DECLARE_GLOBAL_LOCK (atomic);
_DBUS_DECLARE_GLOBAL_LOCK (bus);
_DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
_DBUS_DECLARE_GLOBAL_LOCK (system_users);
#define _DBUS_N_GLOBAL_LOCKS (8)
#define _DBUS_N_GLOBAL_LOCKS (9)
dbus_bool_t _dbus_threads_init_debug (void);
......
......@@ -25,6 +25,7 @@
#include "dbus-internals.h"
#include "dbus-hash.h"
#include "dbus-protocol.h"
#include "dbus-string.h"
#include <string.h>
#include <stdlib.h>
......@@ -34,13 +35,7 @@
* @brief DBusObjectTree is used by DBusConnection to track the object tree
*
* Types and functions related to DBusObjectTree. These
* are all internal.
*
* @todo this is totally broken, because of the following case:
* /foo, /foo/bar, /foo/baz
* if we then receive a message to /foo/baz we need to hand it
* to /foo/baz and /foo but not /foo/bar. So we should be
* using a real tree structure as with GConfListeners.
* are all library-internal.
*
* @{
*/
......@@ -542,6 +537,101 @@ _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
tree->root = NULL;
}
static dbus_bool_t
_dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
const char **parent_path,
char ***child_entries)
{
DBusObjectSubtree *subtree;
char **retval;
_dbus_assert (parent_path != NULL);
_dbus_assert (child_entries != NULL);
*child_entries = NULL;
subtree = find_subtree (tree, parent_path, NULL);
if (subtree == NULL)
{
retval = dbus_new0 (char *, 1);
if (retval == NULL)
goto out;
}
else
{
int i;
retval = dbus_new0 (char*, subtree->n_subtrees + 1);
if (retval == NULL)
goto out;
i = 0;
while (i < subtree->n_subtrees)
{
retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
if (retval[i] == NULL)
{
dbus_free_string_array (retval);
retval = NULL;
goto out;
}
++i;
}
}
out:
*child_entries = retval;
return retval != NULL;
}
static DBusHandlerResult
handle_default_introspect_unlocked (DBusObjectTree *tree,
DBusMessage *message,
const char **path)
{
DBusString xml;
DBusHandlerResult result;
char **children;
int i;
if (!dbus_message_is_method_call (message,
DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
"Introspect"))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (!_dbus_string_init (&xml))
return DBUS_HANDLER_RESULT_NEED_MEMORY;
result = DBUS_HANDLER_RESULT_NEED_MEMORY;
children = NULL;
if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
goto out;
if (!_dbus_string_append (&xml, "<node>\n"))
goto out;
i = 0;
while (children[i] != NULL)
{
if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n",
children[i]))
goto out;
++i;
}
if (!_dbus_string_append (&xml, "</node>\n"))
goto out;
result = DBUS_HANDLER_RESULT_HANDLED;
out:
_dbus_string_free (&xml);
dbus_free_string_array (children);
return result;
}
/**
* Tries to dispatch a message by directing it to handler for the
* object path listed in the message header, if any. Messages are
......@@ -572,12 +662,23 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree,
path = NULL;
if (!dbus_message_get_path_decomposed (message, &path))
{
#ifdef DBUS_BUILD_TESTS
if (tree->connection)
#endif
_dbus_connection_unlock (tree->connection);
_dbus_verbose ("No memory to get decomposed path\n");
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
if (path == NULL)
{
#ifdef DBUS_BUILD_TESTS
if (tree->connection)
#endif
_dbus_connection_unlock (tree->connection);
_dbus_verbose ("No path field in message\n");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
......@@ -649,30 +750,40 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree,
message,
user_data);
if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
goto free_and_return;
#ifdef DBUS_BUILD_TESTS
if (tree->connection)
#endif
_dbus_connection_lock (tree->connection);
if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
goto free_and_return;
}
link = next;
}
free_and_return:
if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
{
/* This hardcoded default handler does a minimal Introspect()
*/
result = handle_default_introspect_unlocked (tree, message,
(const char**) path);
}
#ifdef DBUS_BUILD_TESTS
if (tree->connection)
#endif
_dbus_connection_unlock (tree->connection);
free_and_return:
while (list != NULL)
{
link = _dbus_list_get_first_link (&list);
_dbus_object_subtree_unref (link->data);
_dbus_list_remove_link (&list, link);
}
dbus_free_string_array (path);
return result;
......@@ -770,6 +881,35 @@ _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
}
}
/**
* Lists the registered fallback handlers and object path handlers at
* the given parent_path. The returned array should be freed with
* dbus_free_string_array().
*
* @param connection the connection
* @param parent_path the path to list the child handlers of
* @param child_entries returns #NULL-terminated array of children
* @returns #FALSE if no memory to allocate the child entries
*/
dbus_bool_t
_dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
const char **parent_path,
char ***child_entries)
{
dbus_bool_t result;
result = _dbus_object_tree_list_registered_unlocked (tree,
parent_path,
child_entries);
#ifdef DBUS_BUILD_TESTS
if (tree->connection)
#endif
_dbus_connection_unlock (tree->connection);
return result;
}
/** @} */
#ifdef DBUS_BUILD_TESTS
......
......@@ -44,7 +44,9 @@ DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree
DBusMessage *message);
void _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree);
dbus_bool_t _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
const char **parent_path,
char ***child_entries);
DBUS_END_DECLS;
#endif /* DBUS_OBJECT_TREE_H */
......@@ -38,6 +38,8 @@
* @{
*/
static dbus_int32_t notify_user_data_slot = -1;
/**
* Creates a new pending reply object.
*
......@@ -58,11 +60,17 @@ _dbus_pending_call_new (DBusConnection *connection,
if (timeout_milliseconds == -1)
timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
if (!dbus_pending_call_allocate_data_slot (&notify_user_data_slot))
return NULL;
pending = dbus_new (DBusPendingCall, 1);
if (pending == NULL)
return NULL;
{
dbus_pending_call_free_data_slot (&notify_user_data_slot);
return NULL;
}
timeout = _dbus_timeout_new (timeout_milliseconds,
timeout_handler,
......@@ -70,6 +78,7 @@ _dbus_pending_call_new (DBusConnection *connection,
if (timeout == NULL)
{
dbus_pending_call_free_data_slot (&notify_user_data_slot);
dbus_free (pending);
return NULL;
}
......@@ -77,6 +86,8 @@ _dbus_pending_call_new (DBusConnection *connection,
pending->refcount.value = 1;
pending->connection = connection;
pending->timeout = timeout;
_dbus_data_slot_list_init (&pending->slot_list);
return pending;
}
......@@ -94,7 +105,13 @@ _dbus_pending_call_notify (DBusPendingCall *pending)
pending->completed = TRUE;
if (pending->function)
(* pending->function) (pending, pending->user_data);
{
void *user_data;
user_data = dbus_pending_call_get_data (pending,
notify_user_data_slot);
(* pending->function) (pending, user_data);
}
}
/** @} */
......@@ -154,9 +171,8 @@ dbus_pending_call_unref (DBusPendingCall *pending)
_dbus_assert (!pending->timeout_added);
/* this assumes we aren't holding connection lock... */
if (pending->free_user_data)
(* pending->free_user_data) (pending->user_data);
_dbus_data_slot_list_free (&pending->slot_list);
if (pending->timeout != NULL)
_dbus_timeout_unref (pending->timeout);
......@@ -174,6 +190,8 @@ dbus_pending_call_unref (DBusPendingCall *pending)
}
dbus_free (pending);
dbus_pending_call_free_data_slot (&notify_user_data_slot);
}
}
......@@ -185,28 +203,24 @@ dbus_pending_call_unref (DBusPendingCall *pending)
* @param function notifier function
* @param user_data data to pass to notifier function
* @param free_user_data function to free the user data
*
* @returns #FALSE if not enough memory
*/
void
dbus_bool_t
dbus_pending_call_set_notify (DBusPendingCall *pending,
DBusPendingCallNotifyFunction function,
void *user_data,
DBusFreeFunction free_user_data)
{
DBusFreeFunction old_free_func;
void *old_user_data;
_dbus_return_if_fail (pending != NULL);
_dbus_return_val_if_fail (pending != NULL, FALSE);
old_free_func = pending->free_user_data;
old_user_data = pending->user_data;
pending->user_data = user_data;
pending->free_user_data = free_user_data;
/* could invoke application code! */
if (!dbus_pending_call_set_data (pending, notify_user_data_slot,
user_data, free_user_data))
return FALSE;
pending->function = function;
if (old_free_func)
(* old_free_func) (old_user_data);
return TRUE;
}
/**
......@@ -230,9 +244,10 @@ dbus_pending_call_cancel (DBusPendingCall *pending)
* Checks whether the pending call has received a reply
* yet, or not.
*
* @todo not thread safe? I guess it has to lock though it sucks
*
* @param pending the pending call
* @returns #TRUE if a reply has been received
*/
* @returns #TRUE if a reply has been received */
dbus_bool_t
dbus_pending_call_get_completed (DBusPendingCall *pending)
{
......@@ -245,6 +260,9 @@ dbus_pending_call_get_completed (DBusPendingCall *pending)
* have to keep a reference count on the pending call (or add one
* to the message).
*
* @todo not thread safe? I guess it has to lock though it sucks
* @todo maybe to make this threadsafe, it should be steal_reply(), i.e. only one thread can ever get the message
*
* @param pending the pending call
* @returns the reply message or #NULL.
*/
......@@ -260,6 +278,9 @@ dbus_pending_call_get_reply (DBusPendingCall *pending)
* main loop or process other messages, it simply waits for the reply
* in question.
*
* If the pending call is already completed, this function returns
* immediately.
*
* @todo when you start blocking, the timeout is reset, but it should
* really only use time remaining since the pending call was created.
*
......@@ -269,6 +290,9 @@ void
dbus_pending_call_block (DBusPendingCall *pending)
{
DBusMessage *message;
if (dbus_pending_call_get_completed (pending))
return;
message = _dbus_connection_block_for_reply (pending->connection,
pending->reply_serial,
......@@ -279,6 +303,113 @@ dbus_pending_call_block (DBusPendingCall *pending)
dbus_message_unref (message);
}
static DBusDataSlotAllocator slot_allocator;
_DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
/**
* Allocates an integer ID to be used for storing application-specific
* data on any DBusPendingCall. The allocated ID may then be used
* with dbus_pending_call_set_data() and dbus_pending_call_get_data().
* The passed-in slot must be initialized to -1, and is filled in
* with the slot ID. If the passed-in slot is not -1, it's assumed
* to be already allocated, and its refcount is incremented.
*
* The allocated slot is global, i.e. all DBusPendingCall objects will
* have a slot with the given integer ID reserved.
*
* @param slot_p address of a global variable storing the slot
* @returns #FALSE on failure (no memory)
*/
dbus_bool_t
dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
{
return _dbus_data_slot_allocator_alloc (&slot_allocator,
_DBUS_LOCK_NAME (pending_call_slots),
slot_p);
}
/**
* Deallocates a global ID for #DBusPendingCall data slots.
* dbus_pending_call_get_data() and dbus_pending_call_set_data() may
* no longer be used with this slot. Existing data stored on existing
* DBusPendingCall objects will be freed when the #DBusPendingCall is
* finalized, but may not be retrieved (and may only be replaced if