dbus/glib/dbus-gmain.c

775 lines
19 KiB
C
Raw Normal View History

/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gmain.c GLib main loop integration
*
* Copyright (C) 2002, 2003 CodeFactory AB
* Copyright (C) 2005 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.1
*
* 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
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* 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
*
*/
#include <config.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "dbus-gtest.h"
#include "dbus-gutils.h"
2005-06-12 Colin Walters <walters@verbum.org> Async signals and various bugfixes and testing by Ross Burton <ross@burtonini.com>. * glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete. (dbus_gvalue_genmarshal_name_from_type) (dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c. (dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature. (dbus_g_value_types_init, dbus_gtype_from_signature) (dbus_gtype_from_signature_iter, dbus_gtype_to_signature) (dbus_gtypes_from_arg_signature): New function prototypes. (dbus_gvalue_demarshal): Take context and error arguments. (dbus_gvalue_demarshal_variant): New function. (dbus_gvalue_demarshal_message): New function. (dbus_gvalue_store): Delete. * glib/dbus-gvalue.c: File has been almost entirely rewritten; now we special-case more types such as DBUS_TYPE_SIGNATURE, handle arrays and hash tables correctly, etc. Full support for recursive values is not yet complete. * glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last argument of signal to G_TYPE_POINTER since we now pass a structure. (lookup_g_marshaller): Delete in favor of _dbus_gobject_lookup_marshaller. (marshal_dbus_message_to_g_marshaller): Use _dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message to handle remote signal callbacks. (dbus_g_proxy_new_from_proxy): New function; creates a new DBusGProxy by copying an existing one. (dbus_g_proxy_get_interface, dbus_g_proxy_set_interface) (dbus_g_proxy_get_path): New functions. (dbus_g_proxy_marshal_args_to_message): New function; factored out of existing code. (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments from a varargs array. (dbus_g_proxy_begin_call_internal): New function. (dbus_g_proxy_end_call_internal): New function. (dbus_g_proxy_begin_call): Take GTypes instead of DBus types as arguments; simply invoke dbus_g_proxy_begin_call_internal after collecting args into value array. (dbus_g_proxy_end_call): Take GTypes instead of DBus types; invoke dbus_g_proxy_end_call_internal. (dbus_g_proxy_invoke): Simply invoke begin_call_interanl and end_call_internal. (dbus_g_proxy_call_no_reply): Take GTypes instead of DBus types. (array_free_all): New function. (dbus_g_proxy_add_signal): Take GTypes. * glib/dbus-gobject.h: (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller): Prototype. * glib/dbus-gobject.c: Add a global marshal_table hash which stores mappings from type signatures to marshallers. Change lots of invocations of dbus_gtype_to_dbus_type to dbus_gtype_to_signature. (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (introspect_signals): Fix test for query.return_type. (set_object_property): Update invocation of dbus_gvalue_demarshal. (invoke_object_method): Many changes. Handle asynchronous invocations. Convert arguments with dbus_gvalue_demarshal_message. Handle errors. Use DBusSignatureIter instead of strlen on args. Handle all arguments generically. Special-case variants. (dbus_g_method_return, dbus_g_method_return_error): New function. (DBusGSignalClosure): New structure, closes over signal information. (dbus_g_signal_closure_new): New function. (dbus_g_signal_closure_finalize): New function. (signal_emitter_marshaller): New function; is special marshaller which emits signals on bus. (export_signals): New function; introspects object signals and connects to them. (dbus_g_object_type_install_info): Take GType instead of GObjectClass. (dbus_g_connection_register_g_object): Invoke export_signals. (dbus_g_connection_lookup_g_object): New function. (DBusGFuncSignature) New structure; used for mapping type signatures to marshallers. (funcsig_hash): New function; hashes DBusGFuncSignature. (funcsig_equal): New function; compares DBusGFuncSignature. (_dbus_gobject_lookup_marshaller): New function. (dbus_g_object_register_marshaller): New function; used to register a marshaller at runtime for a particular signature. * glib/dbus-gmain.c (_dbus_gmain_test): Add various tests. * glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC which notes a server method implementation should be asynchronous. * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Call dbus_g_value_types_init. (write_formal_parameters): Use dbus_gtype_from_signature. Handle variants specially. (dbus_g_type_get_lookup_function): Turn GType into an invocation of a lookup function. (write_args_for_direction): Use dbus_g_type_get_lookup_function. (write_untyped_out_args): New method; write output arguments. (write_formal_declarations_for_direction): Function for writing prototypes. (write_formal_parameters_for_direction): Function for writing implementations. (write_typed_args_for_direction): Function for writing arguments prefixed with GTypes. (write_async_method_client): Write out async version of method. * glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h. (dbus_g_type_get_marshal_name): Move mapping from GType to marshal name into here. (dbus_g_type_get_c_name): Move into here. (compute_marshaller): Convert signature to type with dbus_gtype_from_signature, use dbus_g_type_get_marshal_name. (compute_marshaller_name): Ditto. (compute_marshaller): Handle async signal annotations. (gather_marshallers): Return if we don't have a known prefix. (generate_glue): Collect introspection blob here, and write all of the blob at the end. This allows an object with multiple interfaces to work. Mark async methods in introspection blob. * glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add dbus-gtype-specialized.c, dbus-gtype-specialized.h, dbus-gvalue-utils.h, dbus-gvalue-utils.c. * dbus/dbus-glib.h: Don't include dbus-protocol.h; this avoids people accidentally using DBUS_TYPE_* which should not be necessary anymore. Do include dbus-gtype-specialized.h, which are utilities for GLib container types. Add various #defines for types such as DBUS_TYPE_G_BOOLEAN_ARRAY. (DBusGValueIterator, DBusGValue): Define, not fully used yet. (dbus_g_value_get_g_type): Type for recursive value. (dbus_g_value_open, dbus_g_value_iterator_get_value) (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) (dbus_g_value_free): Prototypes. (dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype. (dbus_g_proxy_set_interface): Prototype. (dbus_g_proxy_begin_call, dbus_g_proxy_end_call) (dbus_g_proxy_call_no_reply): Take GLib types instead of DBus types. (dbus_g_proxy_get_path, dbus_g_proxy_get_interface): Accessors. (DBusGAsyncData, DBusGMethodInvocation): Structures for doing async invocations. (dbus_g_method_return, dbus_g_method_return_error): Prototypes. * doc/dbus-tutorial.xml: Update GLib section. * tools/dbus-viewer.c (load_child_nodes): Update for new invocation type of dbus_g_proxy_end_call. (load_from_service_thread_func): Ditto. * tools/print-introspect.c (main): Ditto. * tools/dbus-names-model.c (have_names_notify) (names_model_reload, names_model_set_connection) Use GTypes. * python/Makefile.am (INCLUDES): Define DBUS_COMPILATION, needed since Python bindings use GLib bindings. * test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION. Add --prefix argument. * tools/Makefile.am: Define DBUS_COMPILATION. Remove unneeded --ignore-unsupported arg. * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: * test/glib/test-dbus-glib.c: Add many more tests.
2005-06-13 03:01:30 +00:00
#include "dbus-gvalue.h"
#include "dbus-gvalue-utils.h"
#include <string.h>
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-17 03:52:07 +00:00
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
#define N_(x) x
/**
* @defgroup DBusGLib GLib bindings
* @brief API for using D-BUS with GLib
*
* libdbus proper is a low-level API, these GLib bindings wrap libdbus
* with a much higher-level approach. The higher level approach is
* possible because GLib defines a main loop, an object/type system,
* and an out-of-memory handling policy (it exits the program).
* See http://www.gtk.org for GLib information.
*
* To manipulate remote objects, use #DBusGProxy.
*/
/**
* @defgroup DBusGLibInternals GLib bindings implementation details
* @ingroup DBusInternals
* @brief Implementation details of GLib bindings
*
* @{
*/
/**
* A GSource subclass for dispatching DBusConnection messages.
* We need this on top of the IO handlers, because sometimes
* there are messages to dispatch queued up but no IO pending.
*/
typedef struct
{
GSource source; /**< the parent GSource */
DBusConnection *connection; /**< the connection to dispatch */
} DBusGMessageQueue;
static gboolean message_queue_prepare (GSource *source,
gint *timeout);
static gboolean message_queue_check (GSource *source);
static gboolean message_queue_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static GSourceFuncs message_queue_funcs = {
message_queue_prepare,
message_queue_check,
message_queue_dispatch,
NULL
};
static gboolean
message_queue_prepare (GSource *source,
gint *timeout)
{
DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
*timeout = -1;
return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);
}
static gboolean
message_queue_check (GSource *source)
{
return FALSE;
}
static gboolean
message_queue_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
dbus_connection_ref (connection);
/* Only dispatch once - we don't want to starve other GSource */
dbus_connection_dispatch (connection);
dbus_connection_unref (connection);
return TRUE;
}
typedef struct
{
GMainContext *context; /**< the main context */
GSList *ios; /**< all IOHandler */
GSList *timeouts; /**< all TimeoutHandler */
DBusConnection *connection; /**< NULL if this is really for a server not a connection */
GSource *message_queue_source; /**< DBusGMessageQueue */
} ConnectionSetup;
typedef struct
{
ConnectionSetup *cs;
GSource *source;
DBusWatch *watch;
} IOHandler;
typedef struct
{
ConnectionSetup *cs;
GSource *source;
DBusTimeout *timeout;
} TimeoutHandler;
static dbus_int32_t connection_slot = -1;
static dbus_int32_t server_slot = -1;
static ConnectionSetup*
connection_setup_new (GMainContext *context,
DBusConnection *connection)
{
ConnectionSetup *cs;
cs = g_new0 (ConnectionSetup, 1);
g_assert (context != NULL);
cs->context = context;
g_main_context_ref (cs->context);
if (connection)
{
cs->connection = connection;
cs->message_queue_source = g_source_new (&message_queue_funcs,
sizeof (DBusGMessageQueue));
((DBusGMessageQueue*)cs->message_queue_source)->connection = connection;
g_source_attach (cs->message_queue_source, cs->context);
}
return cs;
}
static void
io_handler_source_finalized (gpointer data)
{
IOHandler *handler;
handler = data;
if (handler->watch)
dbus_watch_set_data (handler->watch, NULL, NULL);
g_free (handler);
}
static void
io_handler_destroy_source (void *data)
{
IOHandler *handler;
handler = data;
if (handler->source)
{
GSource *source = handler->source;
handler->source = NULL;
handler->cs->ios = g_slist_remove (handler->cs->ios, handler);
g_source_destroy (source);
g_source_unref (source);
}
}
static void
io_handler_watch_freed (void *data)
{
IOHandler *handler;
handler = data;
handler->watch = NULL;
io_handler_destroy_source (handler);
}
static gboolean
io_handler_dispatch (GIOChannel *source,
GIOCondition condition,
gpointer data)
{
IOHandler *handler;
guint dbus_condition = 0;
DBusConnection *connection;
handler = data;
connection = handler->cs->connection;
if (connection)
dbus_connection_ref (connection);
if (condition & G_IO_IN)
dbus_condition |= DBUS_WATCH_READABLE;
if (condition & G_IO_OUT)
dbus_condition |= DBUS_WATCH_WRITABLE;
if (condition & G_IO_ERR)
dbus_condition |= DBUS_WATCH_ERROR;
if (condition & G_IO_HUP)
dbus_condition |= DBUS_WATCH_HANGUP;
/* Note that we don't touch the handler after this, because
* dbus may have disabled the watch and thus killed the
* handler.
*/
dbus_watch_handle (handler->watch, dbus_condition);
handler = NULL;
if (connection)
dbus_connection_unref (connection);
return TRUE;
}
static void
connection_setup_add_watch (ConnectionSetup *cs,
DBusWatch *watch)
{
guint flags;
GIOCondition condition;
GIOChannel *channel;
IOHandler *handler;
if (!dbus_watch_get_enabled (watch))
return;
g_assert (dbus_watch_get_data (watch) == NULL);
flags = dbus_watch_get_flags (watch);
condition = G_IO_ERR | G_IO_HUP;
if (flags & DBUS_WATCH_READABLE)
condition |= G_IO_IN;
if (flags & DBUS_WATCH_WRITABLE)
condition |= G_IO_OUT;
handler = g_new0 (IOHandler, 1);
handler->cs = cs;
handler->watch = watch;
channel = g_io_channel_unix_new (dbus_watch_get_fd (watch));
handler->source = g_io_create_watch (channel, condition);
g_source_set_callback (handler->source, (GSourceFunc) io_handler_dispatch, handler,
io_handler_source_finalized);
g_source_attach (handler->source, cs->context);
cs->ios = g_slist_prepend (cs->ios, handler);
dbus_watch_set_data (watch, handler, io_handler_watch_freed);
}
static void
connection_setup_remove_watch (ConnectionSetup *cs,
DBusWatch *watch)
{
IOHandler *handler;
handler = dbus_watch_get_data (watch);
if (handler == NULL)
return;
io_handler_destroy_source (handler);
}
static void
timeout_handler_source_finalized (gpointer data)
{
TimeoutHandler *handler;
handler = data;
if (handler->timeout)
dbus_timeout_set_data (handler->timeout, NULL, NULL);
g_free (handler);
}
static void
timeout_handler_destroy_source (void *data)
{
TimeoutHandler *handler;
handler = data;
if (handler->source)
{
GSource *source = handler->source;
handler->source = NULL;
handler->cs->timeouts = g_slist_remove (handler->cs->timeouts, handler);
g_source_destroy (source);
g_source_unref (source);
}
}
static void
timeout_handler_timeout_freed (void *data)
{
TimeoutHandler *handler;
handler = data;
handler->timeout = NULL;
timeout_handler_destroy_source (handler);
}
static gboolean
timeout_handler_dispatch (gpointer data)
{
TimeoutHandler *handler;
handler = data;
dbus_timeout_handle (handler->timeout);
return TRUE;
}
static void
connection_setup_add_timeout (ConnectionSetup *cs,
DBusTimeout *timeout)
{
TimeoutHandler *handler;
if (!dbus_timeout_get_enabled (timeout))
return;
g_assert (dbus_timeout_get_data (timeout) == NULL);
handler = g_new0 (TimeoutHandler, 1);
handler->cs = cs;
handler->timeout = timeout;
handler->source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
g_source_set_callback (handler->source, timeout_handler_dispatch, handler,
timeout_handler_source_finalized);
g_source_attach (handler->source, handler->cs->context);
cs->timeouts = g_slist_prepend (cs->timeouts, handler);
dbus_timeout_set_data (timeout, handler, timeout_handler_timeout_freed);
}
static void
connection_setup_remove_timeout (ConnectionSetup *cs,
DBusTimeout *timeout)
{
TimeoutHandler *handler;
handler = dbus_timeout_get_data (timeout);
if (handler == NULL)
return;
timeout_handler_destroy_source (handler);
}
static void
connection_setup_free (ConnectionSetup *cs)
{
while (cs->ios)
io_handler_destroy_source (cs->ios->data);
while (cs->timeouts)
timeout_handler_destroy_source (cs->timeouts->data);
if (cs->message_queue_source)
{
GSource *source;
source = cs->message_queue_source;
cs->message_queue_source = NULL;
g_source_destroy (source);
g_source_unref (source);
}
g_main_context_unref (cs->context);
g_free (cs);
}
static dbus_bool_t
add_watch (DBusWatch *watch,
gpointer data)
{
ConnectionSetup *cs;
cs = data;
connection_setup_add_watch (cs, watch);
return TRUE;
}
static void
remove_watch (DBusWatch *watch,
gpointer data)
{
ConnectionSetup *cs;
cs = data;
connection_setup_remove_watch (cs, watch);
}
static void
watch_toggled (DBusWatch *watch,
void *data)
{
/* Because we just exit on OOM, enable/disable is
* no different from add/remove
*/
if (dbus_watch_get_enabled (watch))
add_watch (watch, data);
else
remove_watch (watch, data);
}
static dbus_bool_t
add_timeout (DBusTimeout *timeout,
void *data)
{
ConnectionSetup *cs;
cs = data;
if (!dbus_timeout_get_enabled (timeout))
return TRUE;
connection_setup_add_timeout (cs, timeout);
return TRUE;
}
static void
remove_timeout (DBusTimeout *timeout,
void *data)
{
ConnectionSetup *cs;
cs = data;
connection_setup_remove_timeout (cs, timeout);
}
static void
timeout_toggled (DBusTimeout *timeout,
void *data)
{
/* Because we just exit on OOM, enable/disable is
* no different from add/remove
*/
if (dbus_timeout_get_enabled (timeout))
add_timeout (timeout, data);
else
remove_timeout (timeout, data);
}
static void
wakeup_main (void *data)
{
ConnectionSetup *cs = data;
g_main_context_wakeup (cs->context);
}
/* Move to a new context */
static ConnectionSetup*
connection_setup_new_from_old (GMainContext *context,
ConnectionSetup *old)
{
GSList *tmp;
ConnectionSetup *cs;
g_assert (old->context != context);
cs = connection_setup_new (context, old->connection);
tmp = old->ios;
while (tmp != NULL)
{
IOHandler *handler = tmp->data;
connection_setup_add_watch (cs, handler->watch);
tmp = tmp->next;
}
tmp = old->timeouts;
while (tmp != NULL)
{
TimeoutHandler *handler = tmp->data;
connection_setup_add_timeout (cs, handler->timeout);
tmp = tmp->next;
}
return cs;
}
/** @} */ /* End of GLib bindings internals */
/** @addtogroup DBusGLib
* @{
*/
/**
* Sets the watch and timeout functions of a #DBusConnection
* to integrate the connection with the GLib main loop.
* Pass in #NULL for the #GMainContext unless you're
* doing something specialized.
*
* If called twice for the same context, does nothing the second
* time. If called once with context A and once with context B,
* context B replaces context A as the context monitoring the
* connection.
*
* @param connection the connection
* @param context the #GMainContext or #NULL for default context
*/
void
dbus_connection_setup_with_g_main (DBusConnection *connection,
GMainContext *context)
{
ConnectionSetup *old_setup;
ConnectionSetup *cs;
/* FIXME we never free the slot, so its refcount just keeps growing,
* which is kind of broken.
*/
dbus_connection_allocate_data_slot (&connection_slot);
if (connection_slot < 0)
goto nomem;
if (context == NULL)
context = g_main_context_default ();
cs = NULL;
old_setup = dbus_connection_get_data (connection, connection_slot);
if (old_setup != NULL)
{
if (old_setup->context == context)
return; /* nothing to do */
cs = connection_setup_new_from_old (context, old_setup);
/* Nuke the old setup */
dbus_connection_set_data (connection, connection_slot, NULL, NULL);
old_setup = NULL;
}
if (cs == NULL)
cs = connection_setup_new (context, connection);
if (!dbus_connection_set_data (connection, connection_slot, cs,
(DBusFreeFunction)connection_setup_free))
goto nomem;
if (!dbus_connection_set_watch_functions (connection,
add_watch,
remove_watch,
watch_toggled,
cs, NULL))
goto nomem;
if (!dbus_connection_set_timeout_functions (connection,
add_timeout,
remove_timeout,
timeout_toggled,
cs, NULL))
goto nomem;
dbus_connection_set_wakeup_main_function (connection,
wakeup_main,
cs, NULL);
return;
nomem:
g_error ("Not enough memory to set up DBusConnection for use with GLib");
}
/**
* Sets the watch and timeout functions of a #DBusServer
* to integrate the server with the GLib main loop.
* In most cases the context argument should be #NULL.
*
* If called twice for the same context, does nothing the second
* time. If called once with context A and once with context B,
* context B replaces context A as the context monitoring the
* connection.
*
* @param server the server
* @param context the #GMainContext or #NULL for default
*/
void
dbus_server_setup_with_g_main (DBusServer *server,
GMainContext *context)
{
ConnectionSetup *old_setup;
ConnectionSetup *cs;
/* FIXME we never free the slot, so its refcount just keeps growing,
* which is kind of broken.
*/
dbus_server_allocate_data_slot (&server_slot);
if (server_slot < 0)
goto nomem;
if (context == NULL)
context = g_main_context_default ();
cs = NULL;
old_setup = dbus_server_get_data (server, server_slot);
if (old_setup != NULL)
{
if (old_setup->context == context)
return; /* nothing to do */
cs = connection_setup_new_from_old (context, old_setup);
/* Nuke the old setup */
dbus_server_set_data (server, server_slot, NULL, NULL);
old_setup = NULL;
}
if (cs == NULL)
cs = connection_setup_new (context, NULL);
if (!dbus_server_set_data (server, server_slot, cs,
(DBusFreeFunction)connection_setup_free))
goto nomem;
if (!dbus_server_set_watch_functions (server,
add_watch,
remove_watch,
watch_toggled,
cs, NULL))
goto nomem;
if (!dbus_server_set_timeout_functions (server,
add_timeout,
remove_timeout,
timeout_toggled,
cs, NULL))
goto nomem;
return;
nomem:
g_error ("Not enough memory to set up DBusServer for use with GLib");
}
/**
* Returns a connection to the given bus. The connection is a global variable
* shared with other callers of this function.
*
* (Internally, calls dbus_bus_get() then calls
* dbus_connection_setup_with_g_main() on the result.)
*
* @param type bus type
* @param error address where an error can be returned.
* @returns a DBusConnection
*/
DBusGConnection*
dbus_g_bus_get (DBusBusType type,
GError **error)
{
DBusConnection *connection;
DBusError derror;
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2005-06-12 Colin Walters <walters@verbum.org> Async signals and various bugfixes and testing by Ross Burton <ross@burtonini.com>. * glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete. (dbus_gvalue_genmarshal_name_from_type) (dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c. (dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature. (dbus_g_value_types_init, dbus_gtype_from_signature) (dbus_gtype_from_signature_iter, dbus_gtype_to_signature) (dbus_gtypes_from_arg_signature): New function prototypes. (dbus_gvalue_demarshal): Take context and error arguments. (dbus_gvalue_demarshal_variant): New function. (dbus_gvalue_demarshal_message): New function. (dbus_gvalue_store): Delete. * glib/dbus-gvalue.c: File has been almost entirely rewritten; now we special-case more types such as DBUS_TYPE_SIGNATURE, handle arrays and hash tables correctly, etc. Full support for recursive values is not yet complete. * glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last argument of signal to G_TYPE_POINTER since we now pass a structure. (lookup_g_marshaller): Delete in favor of _dbus_gobject_lookup_marshaller. (marshal_dbus_message_to_g_marshaller): Use _dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message to handle remote signal callbacks. (dbus_g_proxy_new_from_proxy): New function; creates a new DBusGProxy by copying an existing one. (dbus_g_proxy_get_interface, dbus_g_proxy_set_interface) (dbus_g_proxy_get_path): New functions. (dbus_g_proxy_marshal_args_to_message): New function; factored out of existing code. (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments from a varargs array. (dbus_g_proxy_begin_call_internal): New function. (dbus_g_proxy_end_call_internal): New function. (dbus_g_proxy_begin_call): Take GTypes instead of DBus types as arguments; simply invoke dbus_g_proxy_begin_call_internal after collecting args into value array. (dbus_g_proxy_end_call): Take GTypes instead of DBus types; invoke dbus_g_proxy_end_call_internal. (dbus_g_proxy_invoke): Simply invoke begin_call_interanl and end_call_internal. (dbus_g_proxy_call_no_reply): Take GTypes instead of DBus types. (array_free_all): New function. (dbus_g_proxy_add_signal): Take GTypes. * glib/dbus-gobject.h: (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller): Prototype. * glib/dbus-gobject.c: Add a global marshal_table hash which stores mappings from type signatures to marshallers. Change lots of invocations of dbus_gtype_to_dbus_type to dbus_gtype_to_signature. (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (introspect_signals): Fix test for query.return_type. (set_object_property): Update invocation of dbus_gvalue_demarshal. (invoke_object_method): Many changes. Handle asynchronous invocations. Convert arguments with dbus_gvalue_demarshal_message. Handle errors. Use DBusSignatureIter instead of strlen on args. Handle all arguments generically. Special-case variants. (dbus_g_method_return, dbus_g_method_return_error): New function. (DBusGSignalClosure): New structure, closes over signal information. (dbus_g_signal_closure_new): New function. (dbus_g_signal_closure_finalize): New function. (signal_emitter_marshaller): New function; is special marshaller which emits signals on bus. (export_signals): New function; introspects object signals and connects to them. (dbus_g_object_type_install_info): Take GType instead of GObjectClass. (dbus_g_connection_register_g_object): Invoke export_signals. (dbus_g_connection_lookup_g_object): New function. (DBusGFuncSignature) New structure; used for mapping type signatures to marshallers. (funcsig_hash): New function; hashes DBusGFuncSignature. (funcsig_equal): New function; compares DBusGFuncSignature. (_dbus_gobject_lookup_marshaller): New function. (dbus_g_object_register_marshaller): New function; used to register a marshaller at runtime for a particular signature. * glib/dbus-gmain.c (_dbus_gmain_test): Add various tests. * glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC which notes a server method implementation should be asynchronous. * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Call dbus_g_value_types_init. (write_formal_parameters): Use dbus_gtype_from_signature. Handle variants specially. (dbus_g_type_get_lookup_function): Turn GType into an invocation of a lookup function. (write_args_for_direction): Use dbus_g_type_get_lookup_function. (write_untyped_out_args): New method; write output arguments. (write_formal_declarations_for_direction): Function for writing prototypes. (write_formal_parameters_for_direction): Function for writing implementations. (write_typed_args_for_direction): Function for writing arguments prefixed with GTypes. (write_async_method_client): Write out async version of method. * glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h. (dbus_g_type_get_marshal_name): Move mapping from GType to marshal name into here. (dbus_g_type_get_c_name): Move into here. (compute_marshaller): Convert signature to type with dbus_gtype_from_signature, use dbus_g_type_get_marshal_name. (compute_marshaller_name): Ditto. (compute_marshaller): Handle async signal annotations. (gather_marshallers): Return if we don't have a known prefix. (generate_glue): Collect introspection blob here, and write all of the blob at the end. This allows an object with multiple interfaces to work. Mark async methods in introspection blob. * glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add dbus-gtype-specialized.c, dbus-gtype-specialized.h, dbus-gvalue-utils.h, dbus-gvalue-utils.c. * dbus/dbus-glib.h: Don't include dbus-protocol.h; this avoids people accidentally using DBUS_TYPE_* which should not be necessary anymore. Do include dbus-gtype-specialized.h, which are utilities for GLib container types. Add various #defines for types such as DBUS_TYPE_G_BOOLEAN_ARRAY. (DBusGValueIterator, DBusGValue): Define, not fully used yet. (dbus_g_value_get_g_type): Type for recursive value. (dbus_g_value_open, dbus_g_value_iterator_get_value) (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) (dbus_g_value_free): Prototypes. (dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype. (dbus_g_proxy_set_interface): Prototype. (dbus_g_proxy_begin_call, dbus_g_proxy_end_call) (dbus_g_proxy_call_no_reply): Take GLib types instead of DBus types. (dbus_g_proxy_get_path, dbus_g_proxy_get_interface): Accessors. (DBusGAsyncData, DBusGMethodInvocation): Structures for doing async invocations. (dbus_g_method_return, dbus_g_method_return_error): Prototypes. * doc/dbus-tutorial.xml: Update GLib section. * tools/dbus-viewer.c (load_child_nodes): Update for new invocation type of dbus_g_proxy_end_call. (load_from_service_thread_func): Ditto. * tools/print-introspect.c (main): Ditto. * tools/dbus-names-model.c (have_names_notify) (names_model_reload, names_model_set_connection) Use GTypes. * python/Makefile.am (INCLUDES): Define DBUS_COMPILATION, needed since Python bindings use GLib bindings. * test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION. Add --prefix argument. * tools/Makefile.am: Define DBUS_COMPILATION. Remove unneeded --ignore-unsupported arg. * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: * test/glib/test-dbus-glib.c: Add many more tests.
2005-06-13 03:01:30 +00:00
dbus_g_value_types_init ();
dbus_error_init (&derror);
connection = dbus_bus_get (type, &derror);
if (connection == NULL)
{
dbus_g_error_set (error, derror.name, derror.message);
dbus_error_free (&derror);
return NULL;
}
/* does nothing if it's already been done */
dbus_connection_setup_with_g_main (connection, NULL);
return DBUS_G_CONNECTION_FROM_CONNECTION (connection);
}
/** @} */ /* end of public API */
#ifdef DBUS_BUILD_TESTS
/**
* @ingroup DBusGLibInternals
* Unit test for GLib main loop integration
* @returns #TRUE on success.
*/
gboolean
_dbus_gmain_test (const char *test_data_dir)
{
2005-06-12 Colin Walters <walters@verbum.org> Async signals and various bugfixes and testing by Ross Burton <ross@burtonini.com>. * glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete. (dbus_gvalue_genmarshal_name_from_type) (dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c. (dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature. (dbus_g_value_types_init, dbus_gtype_from_signature) (dbus_gtype_from_signature_iter, dbus_gtype_to_signature) (dbus_gtypes_from_arg_signature): New function prototypes. (dbus_gvalue_demarshal): Take context and error arguments. (dbus_gvalue_demarshal_variant): New function. (dbus_gvalue_demarshal_message): New function. (dbus_gvalue_store): Delete. * glib/dbus-gvalue.c: File has been almost entirely rewritten; now we special-case more types such as DBUS_TYPE_SIGNATURE, handle arrays and hash tables correctly, etc. Full support for recursive values is not yet complete. * glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last argument of signal to G_TYPE_POINTER since we now pass a structure. (lookup_g_marshaller): Delete in favor of _dbus_gobject_lookup_marshaller. (marshal_dbus_message_to_g_marshaller): Use _dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message to handle remote signal callbacks. (dbus_g_proxy_new_from_proxy): New function; creates a new DBusGProxy by copying an existing one. (dbus_g_proxy_get_interface, dbus_g_proxy_set_interface) (dbus_g_proxy_get_path): New functions. (dbus_g_proxy_marshal_args_to_message): New function; factored out of existing code. (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments from a varargs array. (dbus_g_proxy_begin_call_internal): New function. (dbus_g_proxy_end_call_internal): New function. (dbus_g_proxy_begin_call): Take GTypes instead of DBus types as arguments; simply invoke dbus_g_proxy_begin_call_internal after collecting args into value array. (dbus_g_proxy_end_call): Take GTypes instead of DBus types; invoke dbus_g_proxy_end_call_internal. (dbus_g_proxy_invoke): Simply invoke begin_call_interanl and end_call_internal. (dbus_g_proxy_call_no_reply): Take GTypes instead of DBus types. (array_free_all): New function. (dbus_g_proxy_add_signal): Take GTypes. * glib/dbus-gobject.h: (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller): Prototype. * glib/dbus-gobject.c: Add a global marshal_table hash which stores mappings from type signatures to marshallers. Change lots of invocations of dbus_gtype_to_dbus_type to dbus_gtype_to_signature. (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (introspect_signals): Fix test for query.return_type. (set_object_property): Update invocation of dbus_gvalue_demarshal. (invoke_object_method): Many changes. Handle asynchronous invocations. Convert arguments with dbus_gvalue_demarshal_message. Handle errors. Use DBusSignatureIter instead of strlen on args. Handle all arguments generically. Special-case variants. (dbus_g_method_return, dbus_g_method_return_error): New function. (DBusGSignalClosure): New structure, closes over signal information. (dbus_g_signal_closure_new): New function. (dbus_g_signal_closure_finalize): New function. (signal_emitter_marshaller): New function; is special marshaller which emits signals on bus. (export_signals): New function; introspects object signals and connects to them. (dbus_g_object_type_install_info): Take GType instead of GObjectClass. (dbus_g_connection_register_g_object): Invoke export_signals. (dbus_g_connection_lookup_g_object): New function. (DBusGFuncSignature) New structure; used for mapping type signatures to marshallers. (funcsig_hash): New function; hashes DBusGFuncSignature. (funcsig_equal): New function; compares DBusGFuncSignature. (_dbus_gobject_lookup_marshaller): New function. (dbus_g_object_register_marshaller): New function; used to register a marshaller at runtime for a particular signature. * glib/dbus-gmain.c (_dbus_gmain_test): Add various tests. * glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC which notes a server method implementation should be asynchronous. * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Call dbus_g_value_types_init. (write_formal_parameters): Use dbus_gtype_from_signature. Handle variants specially. (dbus_g_type_get_lookup_function): Turn GType into an invocation of a lookup function. (write_args_for_direction): Use dbus_g_type_get_lookup_function. (write_untyped_out_args): New method; write output arguments. (write_formal_declarations_for_direction): Function for writing prototypes. (write_formal_parameters_for_direction): Function for writing implementations. (write_typed_args_for_direction): Function for writing arguments prefixed with GTypes. (write_async_method_client): Write out async version of method. * glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h. (dbus_g_type_get_marshal_name): Move mapping from GType to marshal name into here. (dbus_g_type_get_c_name): Move into here. (compute_marshaller): Convert signature to type with dbus_gtype_from_signature, use dbus_g_type_get_marshal_name. (compute_marshaller_name): Ditto. (compute_marshaller): Handle async signal annotations. (gather_marshallers): Return if we don't have a known prefix. (generate_glue): Collect introspection blob here, and write all of the blob at the end. This allows an object with multiple interfaces to work. Mark async methods in introspection blob. * glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add dbus-gtype-specialized.c, dbus-gtype-specialized.h, dbus-gvalue-utils.h, dbus-gvalue-utils.c. * dbus/dbus-glib.h: Don't include dbus-protocol.h; this avoids people accidentally using DBUS_TYPE_* which should not be necessary anymore. Do include dbus-gtype-specialized.h, which are utilities for GLib container types. Add various #defines for types such as DBUS_TYPE_G_BOOLEAN_ARRAY. (DBusGValueIterator, DBusGValue): Define, not fully used yet. (dbus_g_value_get_g_type): Type for recursive value. (dbus_g_value_open, dbus_g_value_iterator_get_value) (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) (dbus_g_value_free): Prototypes. (dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype. (dbus_g_proxy_set_interface): Prototype. (dbus_g_proxy_begin_call, dbus_g_proxy_end_call) (dbus_g_proxy_call_no_reply): Take GLib types instead of DBus types. (dbus_g_proxy_get_path, dbus_g_proxy_get_interface): Accessors. (DBusGAsyncData, DBusGMethodInvocation): Structures for doing async invocations. (dbus_g_method_return, dbus_g_method_return_error): Prototypes. * doc/dbus-tutorial.xml: Update GLib section. * tools/dbus-viewer.c (load_child_nodes): Update for new invocation type of dbus_g_proxy_end_call. (load_from_service_thread_func): Ditto. * tools/print-introspect.c (main): Ditto. * tools/dbus-names-model.c (have_names_notify) (names_model_reload, names_model_set_connection) Use GTypes. * python/Makefile.am (INCLUDES): Define DBUS_COMPILATION, needed since Python bindings use GLib bindings. * test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION. Add --prefix argument. * tools/Makefile.am: Define DBUS_COMPILATION. Remove unneeded --ignore-unsupported arg. * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: * test/glib/test-dbus-glib.c: Add many more tests.
2005-06-13 03:01:30 +00:00
GType rectype;
GType gtype;
g_type_init ();
dbus_g_value_types_init ();
rectype = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
g_assert (rectype != G_TYPE_INVALID);
g_assert (!strcmp (g_type_name (rectype), "GArray+guint"));
gtype = dbus_gtype_from_signature ("au", TRUE);
g_assert (gtype == rectype);
rectype = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
g_assert (rectype != G_TYPE_INVALID);
g_assert (!strcmp (g_type_name (rectype), "GHashTable+gchararray+gchararray"));
gtype = dbus_gtype_from_signature ("a{ss}", TRUE);
g_assert (gtype == rectype);
gtype = dbus_gtype_from_signature ("o", FALSE);
g_assert (gtype == G_TYPE_OBJECT);
gtype = dbus_gtype_from_signature ("o", TRUE);
g_assert (gtype == DBUS_TYPE_G_PROXY);
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */