dbus/glib dbus-gvalue.h, 1.4, 1.5 dbus-gvalue.c, 1.8,
1.9 dbus-gvalue-utils.h, NONE, 1.1 dbus-gvalue-utils.c, NONE,
1.1 dbus-gtype-specialized.h, NONE,
1.1 dbus-gtype-specialized.c, NONE, 1.1 dbus-gproxy.c, 1.24,
1.25 dbus-gobject.h, 1.2, 1.3 dbus-gobject.c, 1.22,
1.23 dbus-gmain.c, 1.41, 1.42 dbus-binding-tool-glib.h, 1.4,
1.5 dbus-binding-tool-glib.c, 1.8, 1.9 Makefile.am, 1.17, 1.18
Colin Walters
walters at freedesktop.org
Sun Jun 12 20:01:26 PDT 2005
Update of /cvs/dbus/dbus/glib
In directory gabe:/tmp/cvs-serv11651/glib
Modified Files:
dbus-gvalue.h dbus-gvalue.c dbus-gproxy.c dbus-gobject.h
dbus-gobject.c dbus-gmain.c dbus-binding-tool-glib.h
dbus-binding-tool-glib.c Makefile.am
Added Files:
dbus-gvalue-utils.h dbus-gvalue-utils.c
dbus-gtype-specialized.h dbus-gtype-specialized.c
Log Message:
2005-06-12 Colin Walters <walters at verbum.org>
Async signals and various bugfixes and testing by
Ross Burton <ross at 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.
Index: dbus-gvalue.h
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gvalue.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbus-gvalue.h 9 Mar 2005 17:09:11 -0000 1.4
+++ dbus-gvalue.h 13 Jun 2005 03:01:24 -0000 1.5
@@ -2,40 +2,49 @@
#define DBUS_GOBJECT_VALUE_H
#include <dbus/dbus.h>
+#include <dbus/dbus-signature.h>
#include <glib.h>
#include <glib-object.h>
+#include "dbus/dbus-glib.h"
G_BEGIN_DECLS
-/* Used for return value storage */
-typedef union
-{
- gboolean gboolean_val;
- guchar guchar_val;
- gint int_val;
- gint64 gint64_val;
- guint64 guint64_val;
- double double_val;
- gpointer gpointer_val;
- char * chararray_val;
-} DBusBasicGValue;
+typedef struct {
+ DBusGConnection *gconnection;
+ DBusGProxy *proxy;
+} DBusGValueMarshalCtx;
-const char * dbus_gvalue_genmarshal_name_from_type (const char *type);
+void dbus_g_value_types_init (void);
-const char * dbus_gvalue_ctype_from_type (const char *type, gboolean in);
+GType dbus_gtype_from_signature (const char *signature,
+ gboolean is_client);
-const char * dbus_gtype_to_dbus_type (GType type);
+GType dbus_gtype_from_signature_iter (DBusSignatureIter *sigiter,
+ gboolean is_client);
-gboolean dbus_gvalue_init (int type,
- GValue *value);
+const char * dbus_gtype_to_signature (GType type);
-gboolean dbus_gvalue_demarshal (DBusMessageIter *iter,
- GValue *value);
-gboolean dbus_gvalue_marshal (DBusMessageIter *iter,
- GValue *value);
+GArray * dbus_gtypes_from_arg_signature (const char *signature,
+ gboolean is_client);
-gboolean dbus_gvalue_store (GValue *value,
- gpointer storage);
+gboolean dbus_gvalue_demarshal (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+
+gboolean dbus_gvalue_demarshal_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+
+GValueArray * dbus_gvalue_demarshal_message (DBusGValueMarshalCtx *context,
+ DBusMessage *message,
+ guint n_params,
+ const GType *types,
+ GError **error);
+
+gboolean dbus_gvalue_marshal (DBusMessageIter *iter,
+ GValue *value);
G_END_DECLS
Index: dbus-gvalue.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gvalue.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- dbus-gvalue.c 9 Mar 2005 17:09:11 -0000 1.8
+++ dbus-gvalue.c 13 Jun 2005 03:01:24 -0000 1.9
@@ -22,202 +22,680 @@
*
*/
-#include <dbus-gvalue.h>
+#include "dbus-gvalue.h"
+#include "dbus-gobject.h"
+#include "dbus-gvalue-utils.h"
+#include "dbus/dbus-glib.h"
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
#include "dbus/dbus-signature.h"
-/* This is slightly evil, we don't use g_value_set_foo() functions */
+static gboolean demarshal_static_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gpointer dbus_g_value_copy (gpointer value);
+
+
+struct DBusGValue
+{
+ enum {
+ DBUS_G_VALUE_TYPE_TOPLEVEL,
+ DBUS_G_VALUE_TYPE_ITERATOR
+ } type;
+ union {
+ struct {
+ DBusGConnection *connection;
+ DBusGProxy *proxy;
+ DBusMessage *message;
+ char *signature;
+ } toplevel;
+ struct {
+ DBusGValue *toplevel;
+ DBusMessageIter iterator;
+ } recurse;
+ } value;
+};
+
+static gboolean marshal_basic (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_basic (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_strv (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_strv (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_variant (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_garray_basic (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_garray_basic (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_proxy (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_proxy (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_object (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_object (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_proxy_array (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_proxy_array (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+static gboolean marshal_map (DBusMessageIter *iter,
+ GValue *value);
+static gboolean demarshal_ghashtable (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+
+typedef gboolean (*DBusGValueMarshalFunc) (DBusMessageIter *iter,
+ GValue *value);
+typedef gboolean (*DBusGValueDemarshalFunc) (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error);
+
+typedef struct {
+ DBusGValueMarshalFunc marshaller;
+ DBusGValueDemarshalFunc demarshaller;
+} DBusGTypeMarshalVtable;
+
+typedef struct {
+ const char *sig;
+ const DBusGTypeMarshalVtable *vtable;
+} DBusGTypeMarshalData;
+
+static GQuark
+dbus_g_type_metadata_data_quark ()
+{
+ static GQuark quark;
+ if (!quark)
+ quark = g_quark_from_static_string ("DBusGTypeMetaData");
+
+ return quark;
+}
+
+static void
+set_type_metadata (GType type, const DBusGTypeMarshalData *data)
+{
+ g_type_set_qdata (type, dbus_g_type_metadata_data_quark (), (gpointer) data);
+}
+
#define MAP_BASIC(d_t, g_t) \
case DBUS_TYPE_##d_t: \
return G_TYPE_##g_t;
-
static GType
-dbus_dbus_type_to_gtype (int type)
+typecode_to_gtype (int type)
{
switch (type)
{
MAP_BASIC (BOOLEAN, BOOLEAN);
MAP_BASIC (BYTE, UCHAR);
+ MAP_BASIC (INT16, INT);
MAP_BASIC (INT32, INT);
+ MAP_BASIC (UINT16, UINT);
MAP_BASIC (UINT32, UINT);
MAP_BASIC (INT64, INT64);
MAP_BASIC (UINT64, UINT64);
MAP_BASIC (DOUBLE, DOUBLE);
- case DBUS_TYPE_INT16:
- return G_TYPE_INT;
- case DBUS_TYPE_UINT16:
- return G_TYPE_UINT;
- case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- case DBUS_TYPE_SIGNATURE:
- return G_TYPE_STRING;
- case DBUS_TYPE_STRUCT:
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
+ MAP_BASIC (STRING, STRING);
default:
return G_TYPE_INVALID;
}
}
-
#undef MAP_BASIC
-gboolean
-dbus_gvalue_init (int type,
- GValue *value)
+static gboolean
+dbus_typecode_maps_to_basic (int typecode)
+{
+ return typecode_to_gtype (typecode) != G_TYPE_INVALID;
+}
+
+static gboolean
+basic_typecode_to_gtype (int typecode)
+{
+ g_assert (dbus_type_is_basic (typecode));
+ g_assert (dbus_typecode_maps_to_basic (typecode));
+ return typecode_to_gtype (typecode);
+}
+
+static void
+register_basic (int typecode, const DBusGTypeMarshalData *typedata)
+{
+ set_type_metadata (basic_typecode_to_gtype (typecode), typedata);
+}
+
+static void
+register_array (int typecode, const DBusGTypeMarshalData *typedata)
{
+ GType elt_gtype;
GType gtype;
- gtype = dbus_dbus_type_to_gtype (type);
- if (gtype == G_TYPE_INVALID)
- return FALSE;
- g_value_init (value, gtype);
- return TRUE;
+ elt_gtype = basic_typecode_to_gtype (typecode);
+ gtype = dbus_g_type_get_collection ("GArray", elt_gtype);
+ set_type_metadata (gtype, typedata);
}
-/* FIXME - broken for containers
+static void
+register_dict (int key_type, int value_type, const DBusGTypeMarshalData *typedata)
+{
+ GType key_gtype;
+ GType value_gtype;
+ GType gtype;
+
+ key_gtype = basic_typecode_to_gtype (key_type);
+ value_gtype = basic_typecode_to_gtype (value_type);
+ gtype = dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype);
+ set_type_metadata (gtype, typedata);
+}
+
+void
+dbus_g_value_types_init (void)
+{
+ static gboolean types_initialized;
+
+
+ if (types_initialized)
+ return;
+
+ g_assert (sizeof (DBusGValueIterator) >= sizeof (DBusMessageIter));
+
+ dbus_g_type_specialized_init ();
+ dbus_g_type_specialized_builtins_init ();
+
+ static const DBusGTypeMarshalVtable basic_vtable = {
+ marshal_basic,
+ demarshal_basic
+ };
+ static const DBusGTypeMarshalVtable garray_basic_vtable = {
+ marshal_garray_basic,
+ demarshal_garray_basic
+ };
+ static const DBusGTypeMarshalVtable ghashtable_vtable = {
+ marshal_map,
+ demarshal_ghashtable
+ };
+
+ /* Register basic types */
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_BOOLEAN_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_BOOLEAN, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_BYTE_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_BYTE, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_INT16_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_INT16, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_UINT16_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_UINT16, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_UINT32_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_UINT32, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_INT32_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_INT32, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_UINT64_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_UINT64, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_INT64_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_INT64, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_DOUBLE_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_DOUBLE, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_STRING_AS_STRING,
+ &basic_vtable,
+ };
+ register_basic (DBUS_TYPE_STRING, &typedata);
+ }
+
+ /* Register complex types with builtin GType mappings */
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_variant,
+ demarshal_variant
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_VARIANT_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (G_TYPE_VALUE, &typedata);
+ };
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_strv,
+ demarshal_strv
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (G_TYPE_STRV, &typedata);
+ };
+
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_BOOLEAN, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_BYTE, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_UINT32, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_INT32, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT64_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_UINT64, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT64_AS_STRING,
+ &garray_basic_vtable
+ };
+ register_array (DBUS_TYPE_INT64, &typedata);
+ }
+ {
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &ghashtable_vtable,
+ };
+ register_dict (DBUS_TYPE_STRING, DBUS_TYPE_STRING, &typedata);
+ }
+
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_proxy,
+ demarshal_proxy
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (DBUS_TYPE_G_PROXY, &typedata);
+ }
+
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_object,
+ demarshal_object
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (G_TYPE_OBJECT, &typedata);
+ }
+
+ {
+ static const DBusGTypeMarshalVtable vtable = {
+ marshal_proxy_array,
+ demarshal_proxy_array
+ };
+ static const DBusGTypeMarshalData typedata = {
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &vtable
+ };
+ set_type_metadata (DBUS_TYPE_G_PROXY_ARRAY, &typedata);
+ }
+
+ types_initialized = TRUE;
+}
+
+/**
+ * Get the GLib type ID for a DBusGValue boxed type.
+ *
+ * @returns GLib type
*/
-static int
-base_type_from_signature (const char *signature)
+GType
+dbus_g_value_get_g_type (void)
{
- DBusSignatureIter iter;
+ static GType type_id = 0;
- dbus_signature_iter_init (&iter, signature);
+ if (!type_id)
+ type_id = g_boxed_type_register_static ("DBusGValue",
+ dbus_g_value_copy,
+ (GBoxedFreeFunc) dbus_g_value_free);
+ return type_id;
+}
- return dbus_signature_iter_get_current_type (&iter);
+void
+dbus_g_value_open (DBusGValue *value,
+ DBusGValueIterator *iter)
+{
+ DBusGValue *real;
+
+ g_return_if_fail (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL);
+
+ real = (DBusGValue*) iter;
+ real->type = DBUS_G_VALUE_TYPE_ITERATOR;
+ real->value.recurse.toplevel = value;
+
+ dbus_message_iter_init (value->value.toplevel.message,
+ &(real->value.recurse.iterator));
+ value->value.recurse.toplevel = value;
}
-const char *
-dbus_gvalue_genmarshal_name_from_type (const char *signature)
+gboolean
+dbus_g_value_iterator_get_values (DBusGValueIterator *iter,
+ GError **error,
+ GValue *first_val,
+ ...)
{
- int type;
+ GValue *value;
+ va_list args;
+ DBusGValue *iterval;
- type = base_type_from_signature (signature);
- switch (type)
+ va_start (args, first_val);
+
+ iterval = (DBusGValue *) iter;
+
+ value = first_val;
+ do
{
- case DBUS_TYPE_BOOLEAN:
- return "BOOLEAN";
- case DBUS_TYPE_BYTE:
- return "UCHAR";
- case DBUS_TYPE_INT32:
- return "INT";
- case DBUS_TYPE_UINT32:
- return "UINT";
- case DBUS_TYPE_INT64:
- return "INT64";
- case DBUS_TYPE_UINT64:
- return "UINT64";
- case DBUS_TYPE_DOUBLE:
- return "DOUBLE";
- case DBUS_TYPE_INT16:
- return "INT";
- break;
- case DBUS_TYPE_UINT16:
- return "UINT";
- case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- case DBUS_TYPE_SIGNATURE:
- return "STRING";
-
- case DBUS_TYPE_STRUCT:
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
- return NULL;
- }
+ DBusGValueMarshalCtx context;
+
+ context.gconnection = (iterval->value.recurse.toplevel)->value.toplevel.connection;
+ context.proxy = (iterval->value.recurse.toplevel)->value.toplevel.proxy;
+ if (!dbus_gvalue_demarshal (&context,
+ &(iterval->value.recurse.iterator),
+ value,
+ error))
+ return FALSE;
+ } while ((value = va_arg (args, GValue *)) != NULL);
+
+ return TRUE;
+}
+
+static char *
+dbus_g_value_get_signature (DBusGValue *value)
+{
+ return value->value.toplevel.signature;
+}
+
+static gpointer
+dbus_g_value_copy (gpointer value)
+{
+ /* FIXME */
return NULL;
}
-const char *
-dbus_gvalue_ctype_from_type (const char *signature, gboolean in)
+void
+dbus_g_value_free (DBusGValue *value)
{
- int type;
+ if (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL)
+ {
+ dbus_message_unref (value->value.toplevel.message);
+ g_free (value->value.toplevel.signature);
+ }
+}
- type = base_type_from_signature (signature);
+static GType
+signature_iter_to_g_type_dict (const DBusSignatureIter *subiter, gboolean is_client)
+{
+ DBusSignatureIter iter;
+ GType key_gtype;
+ GType value_gtype;
- switch (type)
+ g_assert (dbus_signature_iter_get_current_type (subiter) == DBUS_TYPE_DICT_ENTRY);
+
+ dbus_signature_iter_recurse (subiter, &iter);
+
+ key_gtype = dbus_gtype_from_signature_iter (&iter, is_client);
+ if (key_gtype == G_TYPE_INVALID)
+ return G_TYPE_INVALID;
+
+ dbus_signature_iter_next (&iter);
+ value_gtype = dbus_gtype_from_signature_iter (&iter, is_client);
+ if (value_gtype == G_TYPE_INVALID)
+ return G_TYPE_INVALID;
+
+ if (!dbus_gtype_is_valid_hash_key (key_gtype)
+ || !dbus_gtype_is_valid_hash_value (value_gtype))
+ /* Later we need to return DBUS_TYPE_G_VALUE */
+ return G_TYPE_INVALID;
+
+ return dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype);
+}
+
+static GType
+signature_iter_to_g_type_array (DBusSignatureIter *iter, gboolean is_client)
+{
+ GType elt_gtype;
+ DBusGTypeMarshalData *typedata;
+
+ elt_gtype = dbus_gtype_from_signature_iter (iter, is_client);
+ if (elt_gtype == G_TYPE_INVALID)
+ return G_TYPE_INVALID;
+
+ typedata = g_type_get_qdata (elt_gtype, dbus_g_type_metadata_data_quark ());
+ if (typedata == NULL)
+ return G_TYPE_INVALID;
+
+ if (elt_gtype == G_TYPE_OBJECT)
+ return DBUS_TYPE_G_OBJECT_ARRAY;
+ if (elt_gtype == G_TYPE_STRING)
+ return G_TYPE_STRV;
+ if (dbus_g_type_is_fixed (elt_gtype))
+ return dbus_g_type_get_collection ("GArray", elt_gtype);
+
+ /* Later we need to return DBUS_TYPE_G_VALUE */
+ return G_TYPE_INVALID;
+}
+
+static gboolean
+signature_iter_to_g_type_struct (DBusSignatureIter *origiter, gboolean is_client)
+{
+ /* FIXME allow structures */
+ return G_TYPE_INVALID;
+#if 0
+ DBusSignatureIter iter;
+ int current_type;
+
+ iter = *origiter;
+
+ while ((current_type = dbus_signature_iter_get_current_type (&iter)) != DBUS_TYPE_INVALID) {
+ subtype = dbus_gtype_from_signature_iter (&iter, is_client);
+ if (subtype == G_TYPE_INVALID)
+ return G_TYPE_INVALID;
+ }
+ return DBUS_TYPE_G_VALUE ();
+#endif
+}
+
+GType
+dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client)
+{
+ int current_type;
+
+ current_type = dbus_signature_iter_get_current_type (iter);
+ /* TODO: handle type 0? */
+ if (dbus_typecode_maps_to_basic (current_type))
+ return basic_typecode_to_gtype (current_type);
+ else if (current_type == DBUS_TYPE_OBJECT_PATH)
+ return is_client ? DBUS_TYPE_G_PROXY : G_TYPE_OBJECT;
+ else
{
- case DBUS_TYPE_BOOLEAN:
- return "gboolean";
- case DBUS_TYPE_BYTE:
- return "guchar";
- case DBUS_TYPE_INT32:
- return "gint32";
- case DBUS_TYPE_UINT32:
- return "guint32";
- case DBUS_TYPE_INT64:
- return "gint64";
- case DBUS_TYPE_UINT64:
- return "guint64";
- case DBUS_TYPE_DOUBLE:
- return "gdouble";
- case DBUS_TYPE_INT16:
- return "gint";
- break;
- case DBUS_TYPE_UINT16:
- return "guint";
- case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- case DBUS_TYPE_SIGNATURE:
- /* FIXME - kind of a hack */
- if (in)
- return "const char *";
+ DBusSignatureIter subiter;
+
+ g_assert (dbus_type_is_container (current_type));
+ dbus_signature_iter_recurse (iter, &subiter);
+
+ if (current_type == DBUS_TYPE_ARRAY)
+ {
+ int elt_type = dbus_signature_iter_get_current_type (&subiter);
+ if (elt_type == DBUS_TYPE_DICT_ENTRY)
+ return signature_iter_to_g_type_dict (&subiter, is_client);
+ else
+ return signature_iter_to_g_type_array (&subiter, is_client);
+ }
+ else if (current_type == DBUS_TYPE_STRUCT)
+ return signature_iter_to_g_type_struct (&subiter, is_client);
+ else if (current_type == DBUS_TYPE_VARIANT)
+ return g_value_get_type ();
+ else if (current_type == DBUS_TYPE_DICT_ENTRY)
+ return G_TYPE_INVALID;
else
- return "char *";
- case DBUS_TYPE_STRUCT:
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
- return NULL;
+ {
+ g_assert_not_reached ();
+ return G_TYPE_INVALID;
+ }
}
- return NULL;
}
-const char *
-dbus_gtype_to_dbus_type (GType type)
+GType
+dbus_gtype_from_signature (const char *signature, gboolean is_client)
{
- switch (type)
+ DBusSignatureIter iter;
+
+ dbus_signature_iter_init (&iter, signature);
+
+ return dbus_gtype_from_signature_iter (&iter, is_client);
+}
+
+static char *
+dbus_gvalue_to_signature (GValue *value)
+{
+ const char *ret;
+
+ ret = dbus_gtype_to_signature (G_VALUE_TYPE (value));
+ if (ret)
+ return g_strdup (ret);
+ else
{
- case G_TYPE_CHAR:
- case G_TYPE_UCHAR:
- return DBUS_TYPE_BYTE_AS_STRING;
+ DBusGValue *val;
- case G_TYPE_BOOLEAN:
- return DBUS_TYPE_BOOLEAN_AS_STRING;
+ g_assert (G_VALUE_TYPE (value) == DBUS_TYPE_G_VALUE);
- /* long gets cut to 32 bits so the remote API is consistent
- * on all architectures
- */
+ val = g_value_get_boxed (value);
- case G_TYPE_LONG:
- case G_TYPE_INT:
- return DBUS_TYPE_INT32_AS_STRING;
- case G_TYPE_ULONG:
- case G_TYPE_UINT:
- return DBUS_TYPE_UINT32_AS_STRING;
+ return dbus_g_value_get_signature (val);
+ }
+}
- case G_TYPE_INT64:
- return DBUS_TYPE_INT64_AS_STRING;
+const char *
+dbus_gtype_to_signature (GType gtype)
+{
+ DBusGTypeMarshalData *typedata;
- case G_TYPE_UINT64:
- return DBUS_TYPE_UINT64_AS_STRING;
-
- case G_TYPE_FLOAT:
- case G_TYPE_DOUBLE:
- return DBUS_TYPE_DOUBLE_AS_STRING;
+ typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
+ if (typedata == NULL)
+ return NULL;
+ return typedata->sig;
+}
- case G_TYPE_STRING:
- return DBUS_TYPE_STRING_AS_STRING;
+GArray *
+dbus_gtypes_from_arg_signature (const char *argsig, gboolean is_client)
+{
+ GArray *ret;
+ int current_type;
+ DBusSignatureIter sigiter;
- default:
- return NULL;
+ ret = g_array_new (FALSE, FALSE, sizeof (GType));
+
+ dbus_signature_iter_init (&sigiter, argsig);
+ while ((current_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+ {
+ GType curtype;
+
+ curtype = dbus_gtype_from_signature_iter (&sigiter, is_client);
+ g_array_append_val (ret, curtype);
+ dbus_signature_iter_next (&sigiter);
}
+ return ret;
}
-gboolean
-dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
-{
- g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int));
- dbus_gvalue_init (dbus_message_iter_get_arg_type (iter), value);
+static gboolean
+demarshal_basic (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ int current_type;
- switch (dbus_message_iter_get_arg_type (iter))
+ current_type = dbus_message_iter_get_arg_type (iter);
+ g_assert (dbus_type_is_basic (current_type));
+
+ switch (current_type)
{
case DBUS_TYPE_BOOLEAN:
{
@@ -283,24 +761,407 @@
return TRUE;
}
case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- case DBUS_TYPE_SIGNATURE:
{
const char *s;
dbus_message_iter_get_basic (iter, &s);
- g_value_set_string (value, s);
+ g_value_set_string (value, s);
return TRUE;
}
- case DBUS_TYPE_STRUCT:
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
default:
+ g_assert_not_reached ();
return FALSE;
}
}
-
+
+static gboolean
+demarshal_static_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ char *sig;
+ int current_type;
+ DBusMessageIter subiter;
+ GType variant_type;
+
+ current_type = dbus_message_iter_get_arg_type (iter);
+ dbus_message_iter_recurse (iter, &subiter);
+ sig = dbus_message_iter_get_signature (&subiter);
+
+ variant_type = dbus_gtype_from_signature (sig, context->proxy != NULL);
+ if (variant_type != G_TYPE_INVALID)
+ {
+ g_value_init (value, variant_type);
+
+ if (!dbus_gvalue_demarshal (context, &subiter, value, error))
+ {
+ dbus_free (sig);
+ return FALSE;
+ }
+ }
+ dbus_free (sig);
+ return TRUE;
+}
+
+static gboolean
+demarshal_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+
+{
+ GValue *variant_val;
+ variant_val = g_new0 (GValue, 1);
+
+ if (!demarshal_static_variant (context, iter, variant_val, error))
+ return FALSE;
+
+ g_value_set_boxed_take_ownership (value, variant_val);
+ return TRUE;
+}
+
+static gboolean
+demarshal_proxy (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ const char *name;
+ DBusGProxy *new_proxy;
+ const char *objpath;
+ int current_type;
+
+ current_type = dbus_message_iter_get_arg_type (iter);
+ g_assert (current_type == DBUS_TYPE_OBJECT_PATH);
+
+ g_assert (context->proxy != NULL);
+
+ name = dbus_g_proxy_get_bus_name (context->proxy);
+
+ dbus_message_iter_get_basic (iter, &objpath);
+
+ new_proxy = dbus_g_proxy_new_from_proxy (context->proxy, NULL, objpath);
+ g_value_set_object_take_ownership (value, new_proxy);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_object (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ const char *objpath;
+ int current_type;
+ GObject *obj;
+
+ current_type = dbus_message_iter_get_arg_type (iter);
+ g_assert (current_type == DBUS_TYPE_OBJECT_PATH);
+ g_assert (context->proxy == NULL);
+
+ dbus_message_iter_get_basic (iter, &objpath);
+
+ obj = dbus_g_connection_lookup_g_object (context->gconnection, objpath);
+ if (obj == NULL)
+ {
+ g_set_error (error,
+ DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Unregistered object at path '%s'"),
+ objpath);
+ return FALSE;
+ }
+ g_value_set_object (value, obj);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_strv (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ DBusMessageIter subiter;
+ int current_type;
+ char **ret;
+ int len;
+ int i;
+
+ dbus_message_iter_recurse (iter, &subiter);
+
+ len = dbus_message_iter_get_array_len (&subiter);
+ g_assert (len >= 0);
+ ret = g_malloc (sizeof (char *) * (len + 1));
+
+ i = 0;
+ while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID)
+ {
+ g_assert (i < len);
+ g_assert (current_type == DBUS_TYPE_STRING);
+
+ dbus_message_iter_get_basic (&subiter, &(ret[i]));
+ ret[i] = g_strdup (ret[i]);
+
+ dbus_message_iter_next (&subiter);
+ i++;
+ }
+ ret[i] = NULL;
+ g_value_set_boxed_take_ownership (value, ret);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_garray_basic (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ DBusMessageIter subiter;
+ GArray *ret;
+ GType elt_gtype;
+ int elt_size;
+ void *msgarray;
+ int msgarray_len;
+
+ dbus_message_iter_recurse (iter, &subiter);
+
+ elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value));
+ g_assert (elt_gtype != G_TYPE_INVALID);
+ g_assert (dbus_g_type_is_fixed (elt_gtype));
+
+ elt_size = dbus_g_type_fixed_get_size (elt_gtype);
+
+ ret = g_array_new (FALSE, TRUE, elt_size);
+
+ msgarray = NULL;
+ dbus_message_iter_get_fixed_array (&subiter,
+ &msgarray,
+ &msgarray_len);
+ g_assert (msgarray != NULL);
+ g_assert (msgarray_len >= 0);
+ g_array_append_vals (ret, msgarray, (guint) msgarray_len);
+
+ g_value_set_boxed_take_ownership (value, ret);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_proxy_array (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ DBusMessageIter subiter;
+ GPtrArray *ret;
+ guint len;
+ guint i;
+ int current_type;
+
+ g_assert (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY);
+
+ dbus_message_iter_recurse (iter, &subiter);
+
+ len = dbus_message_iter_get_array_len (&subiter);
+ g_assert (len >= 0);
+ ret = g_ptr_array_sized_new (len);
+
+ i = 0;
+ while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID)
+ {
+ GValue subval = {0, };
+ g_assert (i < len);
+
+ if (!demarshal_proxy (context, &subiter, &subval, error))
+ {
+ for (i = 0; i < ret->len; i++)
+ g_object_unref (g_ptr_array_index (ret, i));
+ g_ptr_array_free (ret, TRUE);
+ return FALSE;
+ }
+
+ g_ptr_array_index (ret, i) = g_value_get_boxed (&subval);
+ /* Don't unset value, now owned by ret */
+
+ i++;
+ }
+ g_value_set_boxed_take_ownership (value, ret);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_ghashtable (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ GType gtype;
+ DBusMessageIter subiter;
+ int current_type;
+ GHashTable *ret;
+ GType key_gtype;
+ GType value_gtype;
+
+ current_type = dbus_message_iter_get_arg_type (iter);
+ g_assert (current_type == DBUS_TYPE_ARRAY);
+
+ gtype = G_VALUE_TYPE (value);
+
+ dbus_message_iter_recurse (iter, &subiter);
+
+ g_assert (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_DICT_ENTRY);
+
+ key_gtype = dbus_g_type_get_map_key_specialization (gtype);
+ g_assert (dbus_gtype_is_valid_hash_key (key_gtype));
+ value_gtype = dbus_g_type_get_map_value_specialization (gtype);
+ g_assert (dbus_gtype_is_valid_hash_value (value_gtype));
+
+ ret = g_hash_table_new_full (dbus_g_hash_func_from_gtype (key_gtype),
+ dbus_g_hash_equal_from_gtype (key_gtype),
+ dbus_g_hash_free_from_gtype (key_gtype),
+ dbus_g_hash_free_from_gtype (value_gtype));
+
+ while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID)
+ {
+ DBusMessageIter entry_iter;
+ GValue key_value = {0,};
+ GValue value_value = {0,};
+
+ current_type = dbus_message_iter_get_arg_type (&subiter);
+ g_assert (current_type == DBUS_TYPE_DICT_ENTRY);
+
+ dbus_message_iter_recurse (&subiter, &entry_iter);
+
+ g_value_init (&key_value, key_gtype);
+ if (!dbus_gvalue_demarshal (context,
+ &entry_iter,
+ &key_value,
+ error))
+ return FALSE;
+
+ dbus_message_iter_next (&entry_iter);
+
+ g_value_init (&value_value, value_gtype);
+ if (!dbus_gvalue_demarshal (context,
+ &entry_iter,
+ &value_value,
+ error))
+ return FALSE;
+
+ dbus_g_hash_table_insert_steal_values (ret,
+ &key_value,
+ &value_value);
+ /* Ownership of values passes to hash table, don't unset */
+
+ dbus_message_iter_next (&subiter);
+ }
+ g_value_set_boxed_take_ownership (value, ret);
+
+ return TRUE;
+}
+
+static gboolean
+demarshal_recurse (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ return FALSE;
+}
+
gboolean
-dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
+dbus_gvalue_demarshal (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ GType gtype;
+ DBusGTypeMarshalData *typedata;
+
+ gtype = G_VALUE_TYPE (value);
+
+ typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
+ g_return_val_if_fail (typedata != NULL || g_type_is_a (gtype, DBUS_TYPE_G_VALUE), FALSE);
+
+ if (typedata == NULL)
+ {
+ if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE))
+ return demarshal_recurse (context, iter, value, error);
+ g_assert_not_reached ();
+ }
+ g_assert (typedata->vtable);
+ return typedata->vtable->demarshaller (context, iter, value, error);
+}
+
+gboolean
+dbus_gvalue_demarshal_variant (DBusGValueMarshalCtx *context,
+ DBusMessageIter *iter,
+ GValue *value,
+ GError **error)
+{
+ return demarshal_static_variant (context, iter, value, error);
+}
+
+GValueArray *
+dbus_gvalue_demarshal_message (DBusGValueMarshalCtx *context,
+ DBusMessage *message,
+ guint n_types,
+ const GType *types,
+ GError **error)
+{
+ GValueArray *ret;
+ DBusMessageIter iter;
+ int current_type;
+ guint index;
+
+ ret = g_value_array_new (6); /* 6 is a typical maximum for arguments */
+
+ dbus_message_iter_init (message, &iter);
+ index = 0;
+ while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
+ {
+ GValue *value;
+ GType gtype;
+
+ if (index >= n_types)
+ {
+ g_set_error (error, DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Too many arguments in message"));
+ goto lose;
+ }
+
+ g_value_array_append (ret, NULL);
+ value = g_value_array_get_nth (ret, index);
+
+ gtype = types[index];
+ g_value_init (value, gtype);
+
+ if (!dbus_gvalue_demarshal (context, &iter, value, error))
+ goto lose;
+ dbus_message_iter_next (&iter);
+ index++;
+ }
+ if (index < n_types)
+ {
+ g_set_error (error, DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Too few arguments in message"));
+ goto lose;
+ }
+
+ return ret;
+ lose:
+ g_value_array_free (ret);
+ return NULL;
+}
+
+static gboolean
+marshal_basic (DBusMessageIter *iter, GValue *value)
{
GType value_type;
@@ -353,9 +1214,6 @@
goto nomem;
}
return TRUE;
- /* long gets cut to 32 bits so the remote API is consistent
- * on all architectures
- */
case G_TYPE_LONG:
{
dbus_int32_t v = g_value_get_long (value);
@@ -424,9 +1282,10 @@
return TRUE;
default:
- /* FIXME: we need to define custom boxed types for arrays
- etc. so we can map them transparently / pleasantly */
- return FALSE;
+ {
+ g_assert_not_reached ();
+ return FALSE;
+ }
}
nomem:
@@ -434,49 +1293,320 @@
return FALSE;
}
-/* FIXME is there a better way to do this? */
+static gboolean
+marshal_strv (DBusMessageIter *iter,
+ GValue *value)
+{
+ DBusMessageIter subiter;
+ char **array;
+ char **elt;
+ gboolean ret;
+
+ g_assert (G_VALUE_TYPE (value) == g_strv_get_type ());
+
+ array = g_value_get_boxed (value);
+
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_ARRAY,
+ "s",
+ &subiter))
+ goto out;
+
+ for (elt = array; *elt; elt++)
+ {
+ if (!dbus_message_iter_append_basic (&subiter,
+ DBUS_TYPE_STRING,
+ elt))
+ goto out;
+ }
+
+ if (!dbus_message_iter_close_container (iter, &subiter))
+ goto out;
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+marshal_garray_basic (DBusMessageIter *iter,
+ GValue *value)
+{
+ GType elt_gtype;
+ DBusMessageIter subiter;
+ GArray *array;
+ guint elt_size;
+ const char *subsignature_str;
+ gboolean ret;
+
+ elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value));
+ /* FIXME - this means we can't send an array of DBusGValue right now... */
+ subsignature_str = dbus_gtype_to_signature (elt_gtype);
+ g_assert (subsignature_str != NULL);
+
+ elt_size = dbus_g_type_fixed_get_size (elt_gtype);
+
+ array = g_value_get_boxed (value);
+
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_ARRAY,
+ subsignature_str,
+ &subiter))
+ goto out;
+
+ /* TODO - This assumes that basic values are the same size
+ * is this always true? If it is we can probably avoid
+ * a lot of the overhead in _marshal_basic_instance...
+ */
+ if (!dbus_message_iter_append_fixed_array (&subiter,
+ subsignature_str[0],
+ &(array->data),
+ array->len))
+ goto out;
+
+ if (!dbus_message_iter_close_container (iter, &subiter))
+ goto out;
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+marshal_proxy (DBusMessageIter *iter,
+ GValue *value)
+{
+ const char *path;
+ DBusGProxy *proxy;
+
+ g_assert (G_VALUE_TYPE (value) == dbus_g_proxy_get_type ());
+
+ proxy = g_value_get_object (value);
+ path = dbus_g_proxy_get_path (proxy);
+
+ if (!dbus_message_iter_append_basic (iter,
+ DBUS_TYPE_OBJECT_PATH,
+ &path))
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean
+marshal_object (DBusMessageIter *iter,
+ GValue *value)
+{
+ const char *path;
+ GObject *obj;
+
+ obj = g_value_get_object (value);
+ path = _dbus_gobject_get_path (obj);
+
+ if (path == NULL)
+ /* FIXME should throw error */
+ return FALSE;
+
+ if (!dbus_message_iter_append_basic (iter,
+ DBUS_TYPE_OBJECT_PATH,
+ &path))
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean
+marshal_proxy_array (DBusMessageIter *iter,
+ GValue *value)
+{
+ DBusMessageIter subiter;
+ GPtrArray *array;
+ const char *subsignature_str;
+ gboolean ret;
+ guint i;
+
+ subsignature_str = dbus_gtype_to_signature (DBUS_TYPE_G_PROXY);
+ g_assert (subsignature_str != NULL);
+
+ array = g_value_get_boxed (value);
+
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_ARRAY,
+ subsignature_str,
+ &subiter))
+ goto out;
+
+ for (i = 0; i < array->len; i++)
+ {
+ GValue val = {0, };
+
+ g_value_init (&val, DBUS_TYPE_G_PROXY);
+ g_value_set_static_boxed (&val, g_ptr_array_index (array, i));
+
+ marshal_proxy (&subiter, &val);
+
+ g_value_unset (&val);
+ }
+
+ if (!dbus_message_iter_close_container (iter, &subiter))
+ goto out;
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+struct DBusGLibHashMarshalData
+{
+ const char *entry_sig;
+ DBusMessageIter *iter;
+ gboolean err;
+};
+
+static void
+marshal_map_entry (const GValue *key,
+ const GValue *value,
+ gpointer data)
+{
+ struct DBusGLibHashMarshalData *hashdata = data;
+ DBusMessageIter subiter;
+
+ if (hashdata->err)
+ return;
+
+ if (!dbus_message_iter_open_container (hashdata->iter,
+ DBUS_TYPE_DICT_ENTRY,
+ NULL,
+ &subiter))
+ goto lose;
+
+ if (!dbus_gvalue_marshal (&subiter, (GValue*) key))
+ goto lose;
+
+ if (!dbus_gvalue_marshal (&subiter, (GValue*) value))
+ goto lose;
+
+ if (!dbus_message_iter_close_container (hashdata->iter, &subiter))
+ goto lose;
+
+ return;
+ lose:
+ hashdata->err = TRUE;
+}
+
+static gboolean
+marshal_map (DBusMessageIter *iter,
+ GValue *value)
+{
+ GType gtype;
+ DBusMessageIter arr_iter;
+ gboolean ret;
+ struct DBusGLibHashMarshalData hashdata;
+ GType key_type;
+ GType value_type;
+ const char *key_sig;
+ const char *value_sig;
+ char *entry_sig;
+ char *array_sig;
+
+ gtype = G_VALUE_TYPE (value);
+
+ ret = FALSE;
+
+ key_type = dbus_g_type_get_map_key_specialization (gtype);
+ g_assert (dbus_gtype_is_valid_hash_key (key_type));
+ value_type = dbus_g_type_get_map_value_specialization (gtype);
+ g_assert (dbus_gtype_is_valid_hash_value (value_type));
+
+ key_sig = dbus_gtype_to_signature (key_type);
+ value_sig = dbus_gtype_to_signature (value_type);
+ entry_sig = g_strdup_printf ("%s%s", key_sig, value_sig);
+ array_sig = g_strdup_printf ("%c%s%c",
+ DBUS_DICT_ENTRY_BEGIN_CHAR,
+ entry_sig,
+ DBUS_DICT_ENTRY_END_CHAR);
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_ARRAY,
+ array_sig,
+ &arr_iter))
+ goto lose;
+
+ hashdata.iter = &arr_iter;
+ hashdata.err = FALSE;
+ hashdata.entry_sig = entry_sig;
+
+ dbus_g_type_map_value_iterate (value,
+ marshal_map_entry,
+ &hashdata);
+
+ if (!dbus_message_iter_close_container (iter, &arr_iter))
+ goto lose;
+
+ out:
+ g_free (entry_sig);
+ g_free (array_sig);
+ return !hashdata.err;
+ lose:
+ hashdata.err = TRUE;
+ goto out;
+}
+
+static gboolean
+marshal_variant (DBusMessageIter *iter,
+ GValue *value)
+{
+ GType value_gtype;
+ DBusMessageIter subiter;
+ char *variant_sig;
+ GValue *real_value;
+ gboolean ret;
+
+ real_value = g_value_get_boxed (value);
+ value_gtype = G_VALUE_TYPE (real_value);
+
+ variant_sig = dbus_gvalue_to_signature (real_value);
+ if (variant_sig == NULL)
+ {
+ g_warning ("Unsupported value type \"%s\"",
+ g_type_name (value_gtype));
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_open_container (iter,
+ DBUS_TYPE_VARIANT,
+ variant_sig,
+ &subiter))
+ goto out;
+
+ if (!marshal_basic (&subiter, real_value))
+ goto out;
+
+ if (!dbus_message_iter_close_container (iter, &subiter))
+ goto out;
+
+ ret = TRUE;
+ out:
+ g_free (variant_sig);
+ return ret;
+}
+
+static gboolean
+marshal_recurse (DBusMessageIter *iter,
+ GValue *value)
+{
+ return FALSE;
+}
+
gboolean
-dbus_gvalue_store (GValue *value,
- gpointer storage)
+dbus_gvalue_marshal (DBusMessageIter *iter,
+ GValue *value)
{
- switch (G_VALUE_TYPE (value))
+ GType gtype;
+ DBusGTypeMarshalData *typedata;
+
+ gtype = G_VALUE_TYPE (value);
+
+ typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
+ if (typedata == NULL)
{
- case G_TYPE_CHAR:
- *((gchar *) storage) = g_value_get_char (value);
- return TRUE;
- case G_TYPE_UCHAR:
- *((guchar *) storage) = g_value_get_uchar (value);
- return TRUE;
- case G_TYPE_BOOLEAN:
- *((gboolean *) storage) = g_value_get_boolean (value);
- return TRUE;
- case G_TYPE_LONG:
- *((glong *) storage) = g_value_get_long (value);
- return TRUE;
- case G_TYPE_ULONG:
- *((gulong *) storage) = g_value_get_ulong (value);
- return TRUE;
- case G_TYPE_INT:
- *((gint *) storage) = g_value_get_int (value);
- return TRUE;
- case G_TYPE_UINT:
- *((guint *) storage) = g_value_get_uint (value);
- return TRUE;
- case G_TYPE_INT64:
- *((gint64 *) storage) = g_value_get_int64 (value);
- return TRUE;
- case G_TYPE_UINT64:
- *((guint64 *) storage) = g_value_get_uint64 (value);
- return TRUE;
- case G_TYPE_FLOAT:
- case G_TYPE_DOUBLE:
- *((gdouble *) storage) = g_value_get_double (value);
- return TRUE;
- case G_TYPE_STRING:
- /* FIXME - should optimize by not duping string twice */
- *((gchar **) storage) = g_value_dup_string (value);
- return TRUE;
- default:
+ if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE))
+ return marshal_recurse (iter, value);
return FALSE;
}
+ g_assert (typedata->vtable);
+ return typedata->vtable->marshaller (iter, value);
}
--- NEW FILE: dbus-gvalue-utils.h ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gvalue-utils.h: Non-DBus-specific functions related to GType/GValue
*
* 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
*
*/
#ifndef DBUS_GOBJECT_VALUE_UTILS_H
#define DBUS_GOBJECT_VALUE_UTILS_H
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
void dbus_g_type_specialized_builtins_init (void);
gboolean dbus_g_type_is_fixed (GType gtype);
guint dbus_g_type_fixed_get_size (GType gtype);
gboolean dbus_gvalue_set_from_pointer (GValue *value,
gconstpointer storage);
typedef void (*DBusGHashValueForeachFunc) (GValue * key, GValue *val, gpointer data);
void dbus_g_hash_table_value_foreach (GHashTable *table,
GType hash_type,
DBusGHashValueForeachFunc func,
gpointer data);
void dbus_g_hash_table_insert_values (GHashTable *table,
GValue *key_val,
GValue *value_val);
void dbus_g_hash_table_insert_steal_values (GHashTable *table,
GValue *key_val,
GValue *value_val);
gboolean dbus_gtype_is_valid_hash_key (GType type);
gboolean dbus_gtype_is_valid_hash_value (GType type);
GHashFunc dbus_g_hash_func_from_gtype (GType gtype);
GEqualFunc dbus_g_hash_equal_from_gtype (GType gtype);
GDestroyNotify dbus_g_hash_free_from_gtype (GType gtype);
gboolean dbus_gvalue_store (GValue *value,
gpointer storage);
gboolean dbus_gvalue_take (GValue *value,
GTypeCValue *cvalue);
G_END_DECLS
#endif
--- NEW FILE: dbus-gvalue-utils.c ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gvalue-utils.c: Non-DBus-specific functions related to GType/GValue
*
* 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 "dbus/dbus-glib.h"
#include "dbus-gvalue-utils.h"
#include <glib.h>
#include <string.h>
#include <gobject/gvaluecollector.h>
static guint
fixed_type_get_size (GType type)
{
switch (type)
{
case G_TYPE_CHAR:
case G_TYPE_UCHAR:
return sizeof (gchar);
case G_TYPE_BOOLEAN:
return sizeof (gboolean);
case G_TYPE_LONG:
case G_TYPE_ULONG:
return sizeof (glong);
case G_TYPE_INT:
case G_TYPE_UINT:
return sizeof (gint);
case G_TYPE_INT64:
case G_TYPE_UINT64:
return sizeof (gint64);
case G_TYPE_FLOAT:
return sizeof (gfloat);
case G_TYPE_DOUBLE:
return sizeof (gdouble);
default:
return 0;
}
}
gboolean
dbus_g_type_is_fixed (GType type)
{
return fixed_type_get_size (type) > 0;
}
guint
dbus_g_type_fixed_get_size (GType type)
{
g_assert (dbus_g_type_is_fixed (type));
return fixed_type_get_size (type);
}
gboolean
dbus_gvalue_store (GValue *value,
gpointer storage)
{
/* FIXME - can we use the GValue lcopy_value method
* to do this in a cleaner way?
*/
switch (g_type_fundamental (G_VALUE_TYPE (value)))
{
case G_TYPE_CHAR:
*((gchar *) storage) = g_value_get_char (value);
return TRUE;
case G_TYPE_UCHAR:
*((guchar *) storage) = g_value_get_uchar (value);
return TRUE;
case G_TYPE_BOOLEAN:
*((gboolean *) storage) = g_value_get_boolean (value);
return TRUE;
case G_TYPE_LONG:
*((glong *) storage) = g_value_get_long (value);
return TRUE;
case G_TYPE_ULONG:
*((gulong *) storage) = g_value_get_ulong (value);
return TRUE;
case G_TYPE_INT:
*((gint *) storage) = g_value_get_int (value);
return TRUE;
case G_TYPE_UINT:
*((guint *) storage) = g_value_get_uint (value);
return TRUE;
case G_TYPE_INT64:
*((gint64 *) storage) = g_value_get_int64 (value);
return TRUE;
case G_TYPE_UINT64:
*((guint64 *) storage) = g_value_get_uint64 (value);
return TRUE;
case G_TYPE_DOUBLE:
*((gdouble *) storage) = g_value_get_double (value);
return TRUE;
case G_TYPE_STRING:
*((gchar **) storage) = (char*) g_value_get_string (value);
return TRUE;
case G_TYPE_POINTER:
*((gpointer *) storage) = g_value_get_pointer (value);
return TRUE;
case G_TYPE_OBJECT:
*((gpointer *) storage) = g_value_get_object (value);
return TRUE;
case G_TYPE_BOXED:
*((gpointer *) storage) = g_value_get_boxed (value);
return TRUE;
default:
return FALSE;
}
}
gboolean
dbus_gvalue_set_from_pointer (GValue *value,
gconstpointer storage)
{
/* FIXME - is there a better way to do this? */
switch (g_type_fundamental (G_VALUE_TYPE (value)))
{
case G_TYPE_CHAR:
g_value_set_char (value, *((gchar *) storage));
return TRUE;
case G_TYPE_UCHAR:
g_value_set_uchar (value, *((guchar *) storage));
return TRUE;
case G_TYPE_BOOLEAN:
g_value_set_boolean (value, *((gboolean *) storage));
return TRUE;
case G_TYPE_LONG:
g_value_set_long (value, *((glong *) storage));
return TRUE;
case G_TYPE_ULONG:
g_value_set_ulong (value, *((gulong *) storage));
return TRUE;
case G_TYPE_INT:
g_value_set_int (value, *((gint *) storage));
return TRUE;
case G_TYPE_UINT:
g_value_set_uint (value, *((guint *) storage));
return TRUE;
case G_TYPE_INT64:
g_value_set_int64 (value, *((gint64 *) storage));
return TRUE;
case G_TYPE_UINT64:
g_value_set_uint64 (value, *((guint64 *) storage));
return TRUE;
case G_TYPE_DOUBLE:
g_value_set_double (value, *((gdouble *) storage));
return TRUE;
case G_TYPE_STRING:
g_value_set_string (value, *((gchar **) storage));
return TRUE;
case G_TYPE_POINTER:
g_value_set_pointer (value, *((gpointer *) storage));
return TRUE;
case G_TYPE_OBJECT:
g_value_set_object (value, *((gpointer *) storage));
return TRUE;
case G_TYPE_BOXED:
g_value_set_boxed (value, *((gpointer *) storage));
return TRUE;
default:
return FALSE;
}
}
gboolean
dbus_gvalue_take (GValue *value,
GTypeCValue *cvalue)
{
GType g_type;
GTypeValueTable *value_table;
char *error_msg;
g_type = G_VALUE_TYPE (value);
value_table = g_type_value_table_peek (g_type);
error_msg = value_table->collect_value (value, 1, cvalue, G_VALUE_NOCOPY_CONTENTS);
if (error_msg)
{
g_warning ("%s: %s", G_STRLOC, error_msg);
g_free (error_msg);
return FALSE;
}
/* Clear the NOCOPY_CONTENTS flag; we want to take ownership
* of the value.
*/
value->data[1].v_uint &= ~(G_VALUE_NOCOPY_CONTENTS);
return TRUE;
}
static gboolean
hash_func_from_gtype (GType gtype, GHashFunc *func)
{
switch (gtype)
{
case G_TYPE_CHAR:
case G_TYPE_UCHAR:
case G_TYPE_BOOLEAN:
case G_TYPE_INT:
case G_TYPE_UINT:
*func = NULL;
return TRUE;
case G_TYPE_STRING:
*func = g_str_hash;
return TRUE;
default:
return FALSE;
}
}
static gboolean
hash_free_from_gtype (GType gtype, GDestroyNotify *func)
{
switch (gtype)
{
case G_TYPE_CHAR:
case G_TYPE_UCHAR:
case G_TYPE_BOOLEAN:
case G_TYPE_INT:
case G_TYPE_UINT:
*func = NULL;
return TRUE;
case G_TYPE_STRING:
*func = g_free;
return TRUE;
default:
if (gtype == G_TYPE_VALUE)
{
*func = (GDestroyNotify) g_value_unset;
return TRUE;
}
return FALSE;
}
}
gboolean
dbus_gtype_is_valid_hash_key (GType type)
{
GHashFunc func;
return hash_func_from_gtype (type, &func);
}
gboolean
dbus_gtype_is_valid_hash_value (GType type)
{
GDestroyNotify func;
return hash_free_from_gtype (type, &func);
}
GHashFunc
dbus_g_hash_func_from_gtype (GType gtype)
{
GHashFunc func;
gboolean ret;
ret = hash_func_from_gtype (gtype, &func);
g_assert (ret != FALSE);
return func;
}
GEqualFunc
dbus_g_hash_equal_from_gtype (GType gtype)
{
g_assert (dbus_gtype_is_valid_hash_key (gtype));
switch (gtype)
{
case G_TYPE_CHAR:
case G_TYPE_UCHAR:
case G_TYPE_BOOLEAN:
case G_TYPE_INT:
case G_TYPE_UINT:
return NULL;
case G_TYPE_STRING:
return g_str_equal;
default:
g_assert_not_reached ();
return NULL;
}
}
GDestroyNotify
dbus_g_hash_free_from_gtype (GType gtype)
{
GDestroyNotify func;
gboolean ret;
ret = hash_free_from_gtype (gtype, &func);
g_assert (ret != FALSE);
return func;
}
static void
gvalue_from_hash_value (GValue *value, gpointer instance)
{
switch (g_type_fundamental (G_VALUE_TYPE (value)))
{
case G_TYPE_CHAR:
g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance));
break;
case G_TYPE_UCHAR:
g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance));
break;
case G_TYPE_BOOLEAN:
g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance));
break;
case G_TYPE_INT:
g_value_set_int (value, GPOINTER_TO_INT (instance));
break;
case G_TYPE_UINT:
g_value_set_uint (value, GPOINTER_TO_UINT (instance));
break;
case G_TYPE_STRING:
g_value_set_static_string (value, instance);
break;
case G_TYPE_POINTER:
g_value_set_pointer (value, instance);
break;
case G_TYPE_BOXED:
g_value_set_static_boxed (value, instance);
break;
case G_TYPE_OBJECT:
g_value_set_object (value, instance);
g_object_unref (g_value_get_object (value));
break;
default:
g_assert_not_reached ();
break;
}
}
static gpointer
hash_value_from_gvalue (GValue *value)
{
switch (g_type_fundamental (G_VALUE_TYPE (value)))
{
case G_TYPE_CHAR:
return GINT_TO_POINTER ((int) g_value_get_char (value));
break;
case G_TYPE_UCHAR:
return GUINT_TO_POINTER ((guint) g_value_get_uchar (value));
break;
case G_TYPE_BOOLEAN:
return GUINT_TO_POINTER ((guint) g_value_get_boolean (value));
break;
case G_TYPE_INT:
return GINT_TO_POINTER (g_value_get_int (value));
break;
case G_TYPE_UINT:
return GUINT_TO_POINTER (g_value_get_uint (value));
break;
case G_TYPE_STRING:
return (gpointer) g_value_get_string (value);
break;
case G_TYPE_POINTER:
return g_value_get_pointer (value);
break;
case G_TYPE_BOXED:
return g_value_get_boxed (value);
break;
case G_TYPE_OBJECT:
return g_value_get_object (value);
break;
default:
g_assert_not_reached ();
return NULL;
}
}
struct DBusGHashTableValueForeachData
{
DBusGTypeSpecializedMapIterator func;
GType key_type;
GType value_type;
gpointer data;
};
static void
hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data)
{
GValue key_val = {0, };
GValue value_val = {0, };
struct DBusGHashTableValueForeachData *data = user_data;
g_value_init (&key_val, data->key_type);
g_value_init (&value_val, data->value_type);
gvalue_from_hash_value (&key_val, key);
gvalue_from_hash_value (&value_val, value);
data->func (&key_val, &value_val, data->data);
}
static void
hashtable_iterator (GType hash_type,
gpointer instance,
DBusGTypeSpecializedMapIterator iterator,
gpointer user_data)
{
struct DBusGHashTableValueForeachData data;
GType key_gtype;
GType value_gtype;
key_gtype = dbus_g_type_get_map_key_specialization (hash_type);
value_gtype = dbus_g_type_get_map_value_specialization (hash_type);
data.func = iterator;
data.key_type = key_gtype;
data.value_type = value_gtype;
data.data = user_data;
g_hash_table_foreach (instance, hashtable_foreach_with_values, &data);
}
void
dbus_g_hash_table_insert_steal_values (GHashTable *table,
GValue *key_val,
GValue *value_val)
{
gpointer key, val;
key = hash_value_from_gvalue (key_val);
val = hash_value_from_gvalue (value_val);
g_hash_table_insert (table, key, val);
}
static gpointer
hashtable_constructor (GType type)
{
GHashTable *ret;
GType key_gtype;
GType value_gtype;
key_gtype = dbus_g_type_get_map_key_specialization (type);
value_gtype = dbus_g_type_get_map_value_specialization (type);
ret = g_hash_table_new_full (dbus_g_hash_func_from_gtype (key_gtype),
dbus_g_hash_equal_from_gtype (key_gtype),
dbus_g_hash_free_from_gtype (key_gtype),
dbus_g_hash_free_from_gtype (value_gtype));
return ret;
}
static void
hashtable_insert_values (GHashTable *table,
const GValue *key_val,
const GValue *value_val)
{
GValue key_copy = {0, };
GValue value_copy = {0, };
g_value_init (&key_copy, G_VALUE_TYPE (key_val));
g_value_copy (key_val, &key_copy);
g_value_init (&value_copy, G_VALUE_TYPE (value_val));
g_value_copy (value_val, &value_copy);
dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy);
}
static void
hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data)
{
hashtable_insert_values ((GHashTable *) data, key, val);
}
static gpointer
hashtable_copy (GType type, gpointer src)
{
GHashTable *ghash;
GHashTable *ret;
GValue hashval = {0,};
ghash = src;
ret = hashtable_constructor (type);
g_value_init (&hashval, type);
g_value_set_static_boxed (&hashval, ghash);
dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret);
return ret;
}
static void
hashtable_free (GType type, gpointer val)
{
g_hash_table_destroy (val);
}
static gpointer
array_constructor (GType type)
{
GArray *array;
guint elt_size;
GType elt_type;
gboolean zero_terminated;
gboolean clear;
elt_type = dbus_g_type_get_collection_specialization (type);
g_assert (elt_type != G_TYPE_INVALID);
elt_size = dbus_g_type_fixed_get_size (elt_type);
/* These are "safe" defaults */
zero_terminated = TRUE; /* ((struct _DBusGRealArray*) garray)->zero_terminated; */
clear = TRUE; /* ((struct _DBusGRealArray*) garray)->clear; */
array = g_array_new (zero_terminated, clear, elt_size);
return array;
}
static gpointer
array_copy (GType type, gpointer src)
{
GArray *garray;
GArray *new;
garray = src;
new = array_constructor (type);
g_array_append_vals (new, garray->data, garray->len);
return new;
}
static void
array_free (GType type, gpointer val)
{
GArray *array;
array = val;
g_array_free (array, TRUE);
}
static gboolean
array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len)
{
GType elt_type;
GArray *array = instance;
elt_type = dbus_g_type_get_collection_specialization (type);
if (!dbus_g_type_is_fixed (elt_type))
return FALSE;
*values = array->data;
*len = array->len;
return TRUE;
}
static gpointer
ptrarray_constructor (GType type)
{
/* Later we should determine a destructor, need g_ptr_array_destroy */
return g_ptr_array_new ();
}
static void
gvalue_from_ptrarray_value (GValue *value, gpointer instance)
{
switch (g_type_fundamental (G_VALUE_TYPE (value)))
{
case G_TYPE_POINTER:
g_value_set_pointer (value, instance);
break;
case G_TYPE_BOXED:
g_value_set_static_boxed (value, instance);
break;
case G_TYPE_OBJECT:
g_value_set_object (value, instance);
g_object_unref (g_value_get_object (value));
break;
default:
g_assert_not_reached ();
break;
}
}
static gpointer
ptrarray_value_from_gvalue (const GValue *value)
{
switch (g_type_fundamental (G_VALUE_TYPE (value)))
{
case G_TYPE_POINTER:
return g_value_get_pointer (value);
break;
case G_TYPE_BOXED:
return g_value_get_boxed (value);
break;
case G_TYPE_OBJECT:
return g_value_get_object (value);
break;
default:
g_assert_not_reached ();
return NULL;
}
}
static void
ptrarray_iterator (GType hash_type,
gpointer instance,
DBusGTypeSpecializedCollectionIterator iterator,
gpointer user_data)
{
GPtrArray *ptrarray;
GType elt_gtype;
guint i;
ptrarray = instance;
elt_gtype = dbus_g_type_get_collection_specialization (hash_type);
for (i = 0; i < ptrarray->len; i++)
{
GValue val = {0, };
g_value_init (&val, elt_gtype);
gvalue_from_ptrarray_value (&val, g_ptr_array_index (ptrarray, i));
iterator (&val, user_data);
}
}
static void
ptrarray_copy_elt (const GValue *val, gpointer user_data)
{
GPtrArray *dest = user_data;
GValue val_copy = {0, };
g_value_init (&val_copy, G_VALUE_TYPE (val));
g_value_copy (val, &val_copy);
g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy));
}
static gpointer
ptrarray_copy (GType type, gpointer src)
{
GPtrArray *new;
GValue array_val = {0, };
g_value_init (&array_val, type);
g_value_set_static_boxed (&array_val, src);
new = ptrarray_constructor (type);
dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new);
return new;
}
static void
ptrarray_free (GType type, gpointer val)
{
GArray *array;
array = val;
g_array_free (array, TRUE);
}
void
dbus_g_type_specialized_builtins_init (void)
{
static const DBusGTypeSpecializedCollectionVtable array_vtable = {
{
array_constructor,
array_free,
array_copy,
NULL,
NULL,
NULL
},
array_fixed_accessor,
NULL
};
dbus_g_type_register_collection ("GArray", &array_vtable, 0);
static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = {
{
ptrarray_constructor,
ptrarray_free,
ptrarray_copy,
NULL,
NULL,
NULL
},
NULL,
ptrarray_iterator
};
dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);
static const DBusGTypeSpecializedMapVtable hashtable_vtable = {
{
hashtable_constructor,
hashtable_free,
hashtable_copy,
NULL,
NULL,
NULL
},
hashtable_iterator
};
dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
}
--- NEW FILE: dbus-gtype-specialized.h ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gtype-specialized.h: Non-DBus-specific functions for specialized GTypes
*
* 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
*
*/
#ifndef DBUS_GOBJECT_TYPE_SPECIALIZED_H
#define DBUS_GOBJECT_TYPE_SPECIALIZED_H
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
GType dbus_g_type_get_collection (const char *container,
GType specialization);
GType dbus_g_type_get_map (const char *container,
GType key_specialization,
GType value_specialization);
gboolean dbus_g_type_is_collection (GType gtype);
gboolean dbus_g_type_is_map (GType gtype);
GType dbus_g_type_get_collection_specialization (GType gtype);
GType dbus_g_type_get_map_key_specialization (GType gtype);
GType dbus_g_type_get_map_value_specialization (GType gtype);
typedef void (*DBusGTypeSpecializedCollectionIterator) (const GValue *val,
gpointer user_data);
typedef void (*DBusGTypeSpecializedMapIterator) (const GValue *key_val,
const GValue *value_val,
gpointer user_data);
gpointer dbus_g_type_specialized_construct (GType type);
gboolean dbus_g_type_collection_get_fixed (GValue *value,
gpointer *data,
guint *len);
void dbus_g_type_collection_value_iterate (GValue *value,
DBusGTypeSpecializedCollectionIterator iterator,
gpointer user_data);
void dbus_g_type_map_value_iterate (GValue *value,
DBusGTypeSpecializedMapIterator iterator,
gpointer user_data);
typedef gpointer (*DBusGTypeSpecializedConstructor) (GType type);
typedef void (*DBusGTypeSpecializedFreeFunc) (GType type, gpointer val);
typedef gpointer (*DBusGTypeSpecializedCopyFunc) (GType type, gpointer src);
typedef struct {
DBusGTypeSpecializedConstructor constructor;
DBusGTypeSpecializedFreeFunc free_func;
DBusGTypeSpecializedCopyFunc copy_func;
gpointer padding1;
gpointer padding2;
gpointer padding3;
} DBusGTypeSpecializedVtable;
typedef gboolean (*DBusGTypeSpecializedCollectionFixedAccessorFunc) (GType type, gpointer instance, gpointer *values, guint *len);
typedef void (*DBusGTypeSpecializedCollectionIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data);
typedef struct {
DBusGTypeSpecializedVtable base_vtable;
DBusGTypeSpecializedCollectionFixedAccessorFunc fixed_accessor;
DBusGTypeSpecializedCollectionIteratorFunc iterator;
} DBusGTypeSpecializedCollectionVtable;
typedef void (*DBusGTypeSpecializedMapIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedMapIterator iterator, gpointer user_data);
typedef struct {
DBusGTypeSpecializedVtable base_vtable;
DBusGTypeSpecializedMapIteratorFunc iterator;
} DBusGTypeSpecializedMapVtable;
void dbus_g_type_specialized_init (void);
void dbus_g_type_register_collection (const char *name,
const DBusGTypeSpecializedCollectionVtable *vtable,
guint flags);
void dbus_g_type_register_map (const char *name,
const DBusGTypeSpecializedMapVtable *vtable,
guint flags);
G_END_DECLS
#endif
--- NEW FILE: dbus-gtype-specialized.c ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gtype-specialized.c: Non-DBus-specific functions for specialized GTypes
*
* 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 "dbus-gtype-specialized.h"
#include <glib.h>
#include <string.h>
#include <gobject/gvaluecollector.h>
typedef enum {
DBUS_G_SPECTYPE_COLLECTION,
DBUS_G_SPECTYPE_MAP
} DBusGTypeSpecializedType;
typedef struct {
DBusGTypeSpecializedType type;
const DBusGTypeSpecializedVtable *vtable;
} DBusGTypeSpecializedContainer;
typedef struct {
GType types[6];
const DBusGTypeSpecializedContainer *klass;
} DBusGTypeSpecializedData;
static GHashTable /* char * -> data* */ *specialized_containers;
static GQuark
specialized_type_data_quark ()
{
static GQuark quark;
if (!quark)
quark = g_quark_from_static_string ("DBusGTypeSpecializedData");
return quark;
}
void
dbus_g_type_specialized_init (void)
{
specialized_containers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
static gboolean
specialized_types_is_initialized (void)
{
return specialized_containers != NULL;
}
static DBusGTypeSpecializedData *
lookup_specialization_data (GType type)
{
return g_type_get_qdata (type, specialized_type_data_quark ());
}
/* Copied from gboxed.c */
static void
proxy_value_init (GValue *value)
{
value->data[0].v_pointer = NULL;
}
/* Adapted from gboxed.c */
static void
proxy_value_free (GValue *value)
{
if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
{
DBusGTypeSpecializedData *data;
GType type;
type = G_VALUE_TYPE (value);
data = lookup_specialization_data (type);
g_assert (data != NULL);
data->klass->vtable->free_func (type, value->data[0].v_pointer);
}
}
/* Adapted from gboxed.c */
static void
proxy_value_copy (const GValue *src_value,
GValue *dest_value)
{
if (src_value->data[0].v_pointer)
{
DBusGTypeSpecializedData *data;
GType type;
type = G_VALUE_TYPE (src_value);
data = lookup_specialization_data (type);
g_assert (data != NULL);
dest_value->data[0].v_pointer = data->klass->vtable->copy_func (type, src_value->data[0].v_pointer);
}
else
dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
}
/* Copied from gboxed.c */
static gpointer
proxy_value_peek_pointer (const GValue *value)
{
return value->data[0].v_pointer;
}
/* Adapted from gboxed.c */
static gchar*
proxy_collect_value (GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags)
{
DBusGTypeSpecializedData *data;
GType type;
type = G_VALUE_TYPE (value);
data = lookup_specialization_data (type);
if (!collect_values[0].v_pointer)
value->data[0].v_pointer = NULL;
else
{
if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
{
value->data[0].v_pointer = collect_values[0].v_pointer;
value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
}
else
value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer);
}
return NULL;
}
/* Adapted from gboxed.c */
static gchar*
proxy_lcopy_value (const GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags)
{
gpointer *boxed_p = collect_values[0].v_pointer;
if (!boxed_p)
return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
if (!value->data[0].v_pointer)
*boxed_p = NULL;
else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
*boxed_p = value->data[0].v_pointer;
else
{
DBusGTypeSpecializedData *data;
GType type;
type = G_VALUE_TYPE (value);
data = lookup_specialization_data (type);
*boxed_p = data->klass->vtable->copy_func (type, value->data[0].v_pointer);
}
return NULL;
}
static char *
build_specialization_name (const char *prefix, GType first_type, GType second_type)
{
GString *fullname;
fullname = g_string_new (prefix);
g_string_append_c (fullname, '+');
g_string_append (fullname, g_type_name (first_type));
if (second_type != G_TYPE_INVALID)
{
g_string_append_c (fullname, '+');
g_string_append (fullname, g_type_name (second_type));
}
return g_string_free (fullname, FALSE);
}
static void
register_container (const char *name,
DBusGTypeSpecializedType type,
const DBusGTypeSpecializedVtable *vtable)
{
DBusGTypeSpecializedContainer *klass;
klass = g_new0 (DBusGTypeSpecializedContainer, 1);
klass->type = type;
klass->vtable = vtable;
g_hash_table_insert (specialized_containers, g_strdup (name), klass);
}
void
dbus_g_type_register_collection (const char *name,
const DBusGTypeSpecializedCollectionVtable *vtable,
guint flags)
{
g_return_if_fail (specialized_types_is_initialized ());
register_container (name, DBUS_G_SPECTYPE_COLLECTION, (const DBusGTypeSpecializedVtable*) vtable);
}
void
dbus_g_type_register_map (const char *name,
const DBusGTypeSpecializedMapVtable *vtable,
guint flags)
{
g_return_if_fail (specialized_types_is_initialized ());
register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable);
}
static GType
register_specialized_instance (const DBusGTypeSpecializedContainer *klass,
char *name,
GType first_type,
GType second_type)
{
GType ret;
static const GTypeValueTable vtable =
{
proxy_value_init,
proxy_value_free,
proxy_value_copy,
proxy_value_peek_pointer,
"p",
proxy_collect_value,
"p",
proxy_lcopy_value,
};
static const GTypeInfo derived_info =
{
0, /* class_size */
NULL, /* base_init */
NULL, /* base_finalize */
NULL, /* class_init */
NULL, /* class_finalize */
NULL, /* class_data */
0, /* instance_size */
0, /* n_preallocs */
NULL, /* instance_init */
&vtable, /* value_table */
};
ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0);
/* install proxy functions upon successfull registration */
if (ret != G_TYPE_INVALID)
{
DBusGTypeSpecializedData *data;
data = g_new0 (DBusGTypeSpecializedData, 1);
data->types[0] = first_type;
data->types[1] = second_type;
data->klass = klass;
g_type_set_qdata (ret, specialized_type_data_quark (), data);
}
return ret;
}
static GType
lookup_or_register_specialized (const char *container,
GType first_type,
GType second_type)
{
GType ret;
char *name;
const DBusGTypeSpecializedContainer *klass;
g_return_val_if_fail (specialized_types_is_initialized (), G_TYPE_INVALID);
klass = g_hash_table_lookup (specialized_containers, container);
g_return_val_if_fail (klass != NULL, G_TYPE_INVALID);
name = build_specialization_name (container, first_type, second_type);
ret = g_type_from_name (name);
if (ret == G_TYPE_INVALID)
{
/* Take ownership of name */
ret = register_specialized_instance (klass, name,
first_type,
second_type);
}
else
g_free (name);
return ret;
}
GType
dbus_g_type_get_collection (const char *container,
GType specialization)
{
return lookup_or_register_specialized (container, specialization, G_TYPE_INVALID);
}
GType
dbus_g_type_get_map (const char *container,
GType key_specialization,
GType value_specialization)
{
return lookup_or_register_specialized (container, key_specialization, value_specialization);
}
gboolean
dbus_g_type_is_collection (GType gtype)
{
DBusGTypeSpecializedData *data;
data = lookup_specialization_data (gtype);
if (data == NULL)
return FALSE;
return data->klass->type == DBUS_G_SPECTYPE_COLLECTION;
}
gboolean
dbus_g_type_is_map (GType gtype)
{
DBusGTypeSpecializedData *data;
data = lookup_specialization_data (gtype);
if (data == NULL)
return FALSE;
return data->klass->type == DBUS_G_SPECTYPE_MAP;
}
static GType
get_specialization_index (GType gtype, guint i)
{
DBusGTypeSpecializedData *data;
data = lookup_specialization_data (gtype);
return data->types[i];
}
GType
dbus_g_type_get_collection_specialization (GType gtype)
{
g_return_val_if_fail (dbus_g_type_is_collection (gtype), G_TYPE_INVALID);
return get_specialization_index (gtype, 0);
}
GType
dbus_g_type_get_map_key_specialization (GType gtype)
{
g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
return get_specialization_index (gtype, 0);
}
GType
dbus_g_type_get_map_value_specialization (GType gtype)
{
g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
return get_specialization_index (gtype, 1);
}
gpointer
dbus_g_type_specialized_construct (GType type)
{
DBusGTypeSpecializedData *data;
g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
data = lookup_specialization_data (type);
g_return_val_if_fail (data != NULL, FALSE);
return data->klass->vtable->constructor (type);
}
gboolean
dbus_g_type_collection_get_fixed (GValue *value,
gpointer *data_ret,
guint *len_ret)
{
DBusGTypeSpecializedData *data;
GType gtype;
g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
gtype = G_VALUE_TYPE (value);
data = lookup_specialization_data (gtype);
g_return_val_if_fail (data != NULL, FALSE);
return ((DBusGTypeSpecializedCollectionVtable *) (data->klass->vtable))->fixed_accessor (gtype,
g_value_get_boxed (value),
data_ret, len_ret);
}
void
dbus_g_type_collection_value_iterate (GValue *value,
DBusGTypeSpecializedCollectionIterator iterator,
gpointer user_data)
{
DBusGTypeSpecializedData *data;
GType gtype;
g_return_if_fail (specialized_types_is_initialized ());
g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
gtype = G_VALUE_TYPE (value);
data = lookup_specialization_data (gtype);
g_return_if_fail (data != NULL);
((DBusGTypeSpecializedCollectionVtable *) data->klass->vtable)->iterator (gtype,
g_value_get_boxed (value),
iterator, user_data);
}
void
dbus_g_type_map_value_iterate (GValue *value,
DBusGTypeSpecializedMapIterator iterator,
gpointer user_data)
{
DBusGTypeSpecializedData *data;
GType gtype;
g_return_if_fail (specialized_types_is_initialized ());
g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
gtype = G_VALUE_TYPE (value);
data = lookup_specialization_data (gtype);
g_return_if_fail (data != NULL);
((DBusGTypeSpecializedMapVtable *) data->klass->vtable)->iterator (gtype,
g_value_get_boxed (value),
iterator, user_data);
}
Index: dbus-gproxy.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gproxy.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- dbus-gproxy.c 9 Mar 2005 17:09:11 -0000 1.24
+++ dbus-gproxy.c 13 Jun 2005 03:01:24 -0000 1.25
@@ -24,8 +24,8 @@
#include <dbus/dbus-glib-lowlevel.h>
#include <dbus/dbus-signature.h>
#include "dbus-gutils.h"
-#include "dbus-gmarshal.h"
#include "dbus-gvalue.h"
+#include "dbus-gvalue-utils.h"
#include "dbus-gobject.h"
#include <string.h>
#include <glib/gi18n.h>
@@ -737,7 +737,7 @@
0,
NULL, NULL,
marshal_dbus_message_to_g_marshaller,
- G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_STRING);
+ G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
}
static void
@@ -816,80 +816,6 @@
return g_string_free (str, FALSE);
}
-static GSignalCMarshaller
-lookup_g_marshaller (DBusGProxy *proxy,
- const char *signature)
-{
- /* The "proxy" arg would eventually be used if you could provide
- * a marshaller when adding a signal to the proxy
- */
-
-#define MATCH1(sig, t0) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == '\0')
-#define MATCH2(sig, t0, t1) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == (DBUS_TYPE_##t1) && (sig)[2] == '\0')
-#define MATCH3(sig, t0, t1, t2) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == (DBUS_TYPE_##t1) && (sig)[2] == (DBUS_TYPE_##t2) && (sig)[3] == '\0')
-
- switch (*signature)
- {
- case '\0':
- return g_cclosure_marshal_VOID__VOID;
-
- case DBUS_TYPE_BOOLEAN:
- if (MATCH1 (signature, BOOLEAN))
- return g_cclosure_marshal_VOID__BOOLEAN;
- break;
-
- case DBUS_TYPE_BYTE:
- if (MATCH1 (signature, BYTE))
- return g_cclosure_marshal_VOID__UCHAR;
- break;
-
- case DBUS_TYPE_INT16:
- if (MATCH1 (signature, INT16))
- return g_cclosure_marshal_VOID__INT;
- break;
-
- case DBUS_TYPE_UINT16:
- if (MATCH1 (signature, UINT16))
- return g_cclosure_marshal_VOID__UINT;
- break;
-
- case DBUS_TYPE_INT32:
- if (MATCH1 (signature, INT32))
- return g_cclosure_marshal_VOID__INT;
- break;
-
- case DBUS_TYPE_UINT32:
- if (MATCH1 (signature, UINT32))
- return g_cclosure_marshal_VOID__UINT;
- break;
-
- case DBUS_TYPE_DOUBLE:
- if (MATCH1 (signature, DOUBLE))
- return g_cclosure_marshal_VOID__DOUBLE;
- break;
-
- case DBUS_TYPE_OBJECT_PATH:
- if (MATCH1 (signature, OBJECT_PATH))
- return g_cclosure_marshal_VOID__STRING;
- break;
-
- case DBUS_TYPE_SIGNATURE:
- if (MATCH1 (signature, SIGNATURE))
- return g_cclosure_marshal_VOID__STRING;
- break;
-
- case DBUS_TYPE_STRING:
- if (MATCH1 (signature, STRING))
- return g_cclosure_marshal_VOID__STRING;
- /* This is for NameOwnerChanged */
- else if (MATCH3 (signature, STRING, STRING, STRING))
- return _dbus_g_marshal_NONE__STRING_STRING_STRING;
- break;
- }
-
- return NULL;
-}
-
static void
marshal_dbus_message_to_g_marshaller (GClosure *closure,
GValue *return_value,
@@ -909,25 +835,36 @@
GSignalCMarshaller c_marshaller;
DBusGProxy *proxy;
DBusMessage *message;
- const char *signature;
+ GArray *gsignature;
+ const GType *types;
g_assert (n_param_values == 3);
proxy = g_value_get_object (¶m_values[0]);
message = g_value_get_boxed (¶m_values[1]);
- signature = g_value_get_string (¶m_values[2]);
+ gsignature = g_value_get_pointer (¶m_values[2]);
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (message != NULL);
- g_return_if_fail (signature != NULL);
-
- c_marshaller = lookup_g_marshaller (proxy, signature);
+ g_return_if_fail (gsignature != NULL);
+
+ c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
+ (GType*) gsignature->data);
g_return_if_fail (c_marshaller != NULL);
- value_array = _dbus_glib_marshal_dbus_message_to_gvalue_array (message);
+ {
+ DBusGValueMarshalCtx context;
+ context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
+ context.proxy = proxy;
- g_return_if_fail (value_array != NULL);
+ types = (const GType*) gsignature->data;
+ value_array = dbus_gvalue_demarshal_message (&context, message,
+ gsignature->len, types, NULL);
+ }
+
+ if (value_array == NULL)
+ return;
g_value_init (&value, G_TYPE_FROM_INSTANCE (proxy));
g_value_set_instance (&value, proxy);
@@ -966,37 +903,40 @@
if (q != 0)
{
- const char *signature;
-
- signature = g_datalist_id_get_data (&proxy->signal_signatures, q);
- if (signature == NULL)
- {
-#if 0
- /* this should not trigger a warning, as you shouldn't have to
- * add signals you don't care about
- */
- g_warning ("Signal '%s' has not been added to this proxy object\n",
- name);
-#endif
- }
- else if (!dbus_message_has_signature (message, signature))
- {
- g_warning ("Signature '%s' expected for signal '%s', actual signature '%s'\n",
- signature,
- name,
- dbus_message_get_signature (message));
- }
- else
- {
- g_signal_emit (proxy,
- signals[RECEIVED],
- q,
- message,
- signature);
- }
+ GArray *gsignature;
+ GArray *msg_gsignature;
+ guint i;
+
+ gsignature = g_datalist_id_get_data (&proxy->signal_signatures, q);
+ if (gsignature == NULL)
+ goto out;
+
+ msg_gsignature = dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
+ TRUE);
+ for (i = 0; i < gsignature->len; i++)
+ {
+ if (msg_gsignature->len == i
+ || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
+ goto mismatch;
+ }
+ if (msg_gsignature->len != i)
+ goto mismatch;
+
+ g_signal_emit (proxy,
+ signals[RECEIVED],
+ q,
+ message,
+ msg_gsignature);
}
+ out:
g_free (name);
+ return;
+ mismatch:
+ g_warning ("Unexpected message signature '%s' for signal '%s'\n",
+ dbus_message_get_signature (message),
+ name);
+ goto out;
}
/** @} End of DBusGLibInternals */
@@ -1204,6 +1144,33 @@
}
/**
+ * Creates a proxy using an existing proxy as a template, substituting
+ * the specified interface and path. Either or both may be NULL.
+ *
+ * @param proxy the proxy to use as a template
+ * @param path of the object inside the peer to call methods on
+ * @param interface name of the interface to call methods on
+ * @returns new proxy object
+ *
+ */
+DBusGProxy*
+dbus_g_proxy_new_from_proxy (DBusGProxy *proxy,
+ const char *interface,
+ const char *path)
+{
+ g_return_val_if_fail (proxy != NULL, NULL);
+
+ if (interface == NULL)
+ interface = proxy->interface;
+ if (path == NULL)
+ path = proxy->path;
+
+ return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection),
+ proxy->name,
+ path, interface);
+}
+
+/**
* Creates a proxy for an object in peer application (one
* we're directly connected to). That is, this function is
* intended for use when there's no message bus involved,
@@ -1255,199 +1222,63 @@
}
/**
- * Invokes a method on a remote interface. This function does not
- * block; instead it returns an opaque #DBusPendingCall object that
- * tracks the pending call. The method call will not be sent over the
- * wire until the application returns to the main loop, or blocks in
- * dbus_connection_flush() to write out pending data. The call will
- * be completed after a timeout, or when a reply is received.
- * To collect the results of the call (which may be an error,
- * or a reply), use dbus_g_proxy_end_call().
- *
- * @todo this particular function shouldn't die on out of memory,
- * since you should be able to do a call with large arguments.
- *
- * @param proxy a proxy for a remote interface
- * @param method the name of the method to invoke
- * @param first_arg_type type of the first argument
+ * Gets the object interface proxy is bound to (may be #NULL in some cases).
*
- * @returns opaque pending call object
- * */
-DBusGPendingCall*
-dbus_g_proxy_begin_call (DBusGProxy *proxy,
- const char *method,
- int first_arg_type,
- ...)
+ * @param proxy the proxy
+ * @returns an object interface
+ */
+const char*
+dbus_g_proxy_get_interface (DBusGProxy *proxy)
{
- DBusPendingCall *pending;
- DBusMessage *message;
- va_list args;
-
g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
- message = dbus_message_new_method_call (proxy->name,
- proxy->path,
- proxy->interface,
- method);
- if (message == NULL)
- goto oom;
-
- va_start (args, first_arg_type);
- if (!dbus_message_append_args_valist (message, first_arg_type,
- args))
- goto oom;
- va_end (args);
-
- if (!dbus_connection_send_with_reply (proxy->manager->connection,
- message,
- &pending,
- -1))
- goto oom;
-
- return DBUS_G_PENDING_CALL_FROM_PENDING_CALL (pending);
-
- oom:
- /* FIXME we should create a pending call that's
- * immediately completed with an error status without
- * ever going on the wire.
- */
-
- g_error ("Out of memory");
- return NULL;
+ return proxy->interface;
}
/**
- * Collects the results of a method call. The method call was normally
- * initiated with dbus_g_proxy_end_call(). This function will block if
- * the results haven't yet been received; use
- * dbus_g_pending_call_set_notify() to be notified asynchronously that a
- * pending call has been completed. If it's completed, it will not block.
- *
- * If the call results in an error, the error is set as normal for
- * GError and the function returns #FALSE.
- *
- * Otherwise, the "out" parameters and return value of the
- * method are stored in the provided varargs list.
- * The list should be terminated with #DBUS_TYPE_INVALID.
- *
- * This function doesn't affect the reference count of the
- * #DBusGPendingCall, the caller of dbus_g_proxy_begin_call() still owns
- * a reference.
- *
- * @todo this should be changed to make a g_malloc() copy of the
- * data returned probably; right now the data vanishes
- * when you free the PendingCall which is sort of strange.
+ * Sets the object interface proxy is bound to
*
- * @param proxy a proxy for a remote interface
- * @param pending the pending call from dbus_g_proxy_begin_call()
- * @param error return location for an error
- * @param first_arg_type type of first "out" argument
- * @returns #FALSE if an error is set
+ * @param proxy the proxy
+ * @param interface_name an object interface
*/
-gboolean
-dbus_g_proxy_end_call (DBusGProxy *proxy,
- DBusGPendingCall *pending,
- GError **error,
- int first_arg_type,
- ...)
+void
+dbus_g_proxy_set_interface (DBusGProxy *proxy,
+ const char *interface_name)
{
- DBusMessage *message;
- va_list args;
- DBusError derror;
-
- g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
- g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
- g_return_val_if_fail (pending != NULL, FALSE);
-
- dbus_pending_call_block (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
- message = dbus_pending_call_steal_reply (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
-
- g_assert (message != NULL);
-
- dbus_error_init (&derror);
-
- switch (dbus_message_get_type (message))
- {
- case DBUS_MESSAGE_TYPE_METHOD_RETURN:
- va_start (args, first_arg_type);
- if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args))
- {
- va_end (args);
- goto error;
- }
- va_end (args);
-
- dbus_message_unref (message);
- return TRUE;
-
- case DBUS_MESSAGE_TYPE_ERROR:
- dbus_set_error_from_message (&derror, message);
- goto error;
-
- default:
- dbus_set_error (&derror, DBUS_ERROR_FAILED,
- "Reply was neither a method return nor an exception");
- goto error;
- }
-
- error:
- dbus_message_unref (message);
-
- dbus_set_g_error (error, &derror);
- dbus_error_free (&derror);
- return FALSE;
+ /* FIXME - need to unregister when we switch interface for now
+ * later should support idea of unset interface
+ */
+ dbus_g_proxy_manager_unregister (proxy->manager, proxy);
+ g_free (proxy->interface);
+ proxy->interface = g_strdup (interface_name);
+ dbus_g_proxy_manager_register (proxy->manager, proxy);
}
/**
- * Function for invoking a method and receiving reply values.
- * Normally this is not used directly - calls to it are generated
- * from client-side wrappers (see dbus-binding-tool).
- *
- * This function takes two type signatures, one for method arguments,
- * and one for return values. The remaining arguments after the
- * error parameter should be values of the input arguments,
- * followed by pointer values to storage for return values.
+ * Gets the path this proxy is bound to
*
- * @param proxy a proxy for a remote interface
- * @param method method to invoke
- * @param insig signature of input values
- * @param outsig signature of output values
- * @param error return location for an error
- * @returns #FALSE if an error is set, TRUE otherwise
+ * @param proxy the proxy
+ * @returns an object path
*/
-gboolean
-dbus_g_proxy_invoke (DBusGProxy *proxy,
- const char *method,
- const char *insig,
- const char *outsig,
- GError **error,
- ...)
+const char*
+dbus_g_proxy_get_path (DBusGProxy *proxy)
+{
+ g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
+ g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
+
+ return proxy->path;
+}
+
+static DBusMessage *
+dbus_g_proxy_marshal_args_to_message (DBusGProxy *proxy,
+ const char *method,
+ GValueArray *args)
{
- DBusPendingCall *pending;
DBusMessage *message;
- DBusMessage *reply;
- va_list args;
- va_list args_unwind;
- int n_retvals_processed;
DBusMessageIter msgiter;
- DBusSignatureIter sigiter;
- int expected_type;
- gboolean ret;
- DBusError derror;
-
- g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
- g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
-
- va_start (args, error);
- /* Keep around a copy of output arguments so we
- * can free on error. */
- G_VA_COPY (args_unwind, args);
+ guint i;
- ret = FALSE;
- pending = NULL;
- reply = NULL;
- n_retvals_processed = 0;
message = dbus_message_new_method_call (proxy->name,
proxy->path,
proxy->interface,
@@ -1455,47 +1286,91 @@
if (message == NULL)
goto oom;
- dbus_signature_iter_init (&sigiter, insig);
dbus_message_iter_init_append (message, &msgiter);
- while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+ for (i = 0; i < args->n_values; i++)
{
- GValue gvalue = {0, };
- char *collect_err;
-
- if (!dbus_gvalue_init (expected_type, &gvalue))
- {
- g_set_error (error, DBUS_GERROR,
- DBUS_GERROR_INVALID_ARGS,
- _("Unsupported type '%c'"), expected_type);
- goto out;
- }
-
- G_VALUE_COLLECT (&gvalue, args, G_VALUE_NOCOPY_CONTENTS, &collect_err);
+ GValue *gvalue;
- if (collect_err)
- {
- g_set_error (error, DBUS_GERROR,
- DBUS_GERROR_INVALID_ARGS,
- collect_err);
- goto out;
- }
+ gvalue = g_value_array_get_nth (args, i);
- /* Anything we can init must be marshallable */
- if (!dbus_gvalue_marshal (&msgiter, &gvalue))
+ if (!dbus_gvalue_marshal (&msgiter, gvalue))
g_assert_not_reached ();
- g_value_unset (&gvalue);
-
- dbus_signature_iter_next (&sigiter);
}
+ return message;
+ oom:
+ return NULL;
+}
+#define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
+do { \
+ GType valtype; \
+ int i = 0; \
+ VALARRAY = g_value_array_new (6); \
+ valtype = FIRST_ARG_TYPE; \
+ while (valtype != G_TYPE_INVALID) \
+ { \
+ const char *collect_err; \
+ GValue *val; \
+ g_value_array_append (VALARRAY, NULL); \
+ val = g_value_array_get_nth (VALARRAY, i); \
+ g_value_init (val, valtype); \
+ collect_err = NULL; \
+ G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
+ valtype = va_arg (ARGS, GType); \
+ i++; \
+ } \
+} while (0)
+
+static DBusGPendingCall *
+dbus_g_proxy_begin_call_internal (DBusGProxy *proxy,
+ const char *method,
+ GValueArray *args)
+{
+ DBusMessage *message;
+ DBusPendingCall *pending;
+
+ g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
+ g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
+
+ pending = NULL;
+
+ message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
+ if (!message)
+ goto oom;
+
if (!dbus_connection_send_with_reply (proxy->manager->connection,
message,
&pending,
-1))
goto oom;
+ g_assert (pending != NULL);
- dbus_pending_call_block (pending);
- reply = dbus_pending_call_steal_reply (pending);
+ return DBUS_G_PENDING_CALL_FROM_PENDING_CALL (pending);
+ oom:
+ g_error ("Out of memory");
+ return NULL;
+}
+
+static gboolean
+dbus_g_proxy_end_call_internal (DBusGProxy *proxy,
+ DBusGPendingCall *pending,
+ GError **error,
+ GType first_arg_type,
+ va_list args)
+{
+ DBusMessage *reply;
+ DBusMessageIter msgiter;
+ DBusError derror;
+ va_list args_unwind;
+ int n_retvals_processed;
+ gboolean ret;
+ GType valtype;
+
+ reply = NULL;
+ ret = FALSE;
+ n_retvals_processed = 0;
+ dbus_pending_call_block (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
+ reply = dbus_pending_call_steal_reply (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
g_assert (reply != NULL);
@@ -1505,53 +1380,86 @@
{
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
- dbus_signature_iter_init (&sigiter, outsig);
dbus_message_iter_init (reply, &msgiter);
- while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+ valtype = first_arg_type;
+ while (valtype != G_TYPE_INVALID)
{
int arg_type;
- gpointer *value_ret;
+ gpointer return_storage;
GValue gvalue = { 0, };
+ DBusGValueMarshalCtx context;
+
+ context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
+ context.proxy = proxy;
- value_ret = va_arg (args, gpointer *);
arg_type = dbus_message_iter_get_arg_type (&msgiter);
- if (expected_type != arg_type)
+ if (arg_type == DBUS_TYPE_INVALID)
+ g_set_error (error, DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Too few arguments in reply"));
+
+ return_storage = va_arg (args, gpointer);
+ if (return_storage == NULL)
+ goto next;
+
+ /* We handle variants specially; the caller is expected
+ * to have already allocated storage for them.
+ */
+ if (arg_type == DBUS_TYPE_VARIANT
+ && g_type_is_a (valtype, G_TYPE_VALUE))
{
- if (arg_type == DBUS_TYPE_INVALID)
- g_set_error (error, DBUS_GERROR,
- DBUS_GERROR_INVALID_ARGS,
- _("Too few arguments in reply"));
- else
- g_set_error (error, DBUS_GERROR,
+ if (!dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
+ {
+ g_set_error (error,
+ DBUS_GERROR,
DBUS_GERROR_INVALID_ARGS,
- _("Reply argument was \"%c\", expected \"%c\""),
- arg_type, expected_type);
- goto out;
+ _("Couldn't convert argument, expected \"%s\""),
+ g_type_name (valtype));
+ goto out;
+ }
}
-
- if (!dbus_gvalue_demarshal (&msgiter, &gvalue))
+ else
{
- g_set_error (error,
- DBUS_GERROR,
- DBUS_GERROR_INVALID_ARGS,
- _("Couldn't convert argument type \"%c\""), expected_type);
- goto out;
+ g_value_init (&gvalue, valtype);
+
+ /* FIXME, should use error here instead of NULL */
+ if (!dbus_gvalue_demarshal (&context, &msgiter, &gvalue, NULL))
+ {
+ g_set_error (error,
+ DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Couldn't convert argument, expected \"%s\""),
+ g_type_name (valtype));
+ goto out;
+ }
+
+ if (G_VALUE_TYPE (&gvalue) != valtype)
+ {
+ g_set_error (error, DBUS_GERROR,
+ DBUS_GERROR_INVALID_ARGS,
+ _("Reply argument was \"%s\", expected \"%s\""),
+ g_type_name (G_VALUE_TYPE (&gvalue)),
+ g_type_name (valtype));
+ goto out;
+ }
+
+ /* Anything that can be demarshaled must be storable */
+ if (!dbus_gvalue_store (&gvalue, (gpointer*) return_storage))
+ g_assert_not_reached ();
+ /* Ownership of the value passes to the client, don't unset */
}
- /* Anything that can be demarshaled must be storable */
- if (!dbus_gvalue_store (&gvalue, value_ret))
- g_assert_not_reached ();
- g_value_unset (&gvalue);
+ next:
n_retvals_processed++;
- dbus_signature_iter_next (&sigiter);
dbus_message_iter_next (&msgiter);
+ valtype = va_arg (args, GType);
}
if (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
{
g_set_error (error, DBUS_GERROR,
DBUS_GERROR_INVALID_ARGS,
- _("Too many arguments"));
+ _("Too many arguments in reply"));
goto out;
}
break;
@@ -1589,16 +1497,132 @@
va_end (args_unwind);
if (pending)
- dbus_pending_call_unref (pending);
- if (message)
- dbus_message_unref (message);
+ dbus_g_pending_call_unref (pending);
if (reply)
dbus_message_unref (reply);
return ret;
- oom:
- g_error ("Out of memory");
- ret = FALSE;
- goto out;
+}
+
+
+/**
+ * Invokes a method on a remote interface. This function does not
+ * block; instead it returns an opaque #DBusPendingCall object that
+ * tracks the pending call. The method call will not be sent over the
+ * wire until the application returns to the main loop, or blocks in
+ * dbus_connection_flush() to write out pending data. The call will
+ * be completed after a timeout, or when a reply is received.
+ * To collect the results of the call (which may be an error,
+ * or a reply), use dbus_g_proxy_end_call().
+ *
+ * @todo this particular function shouldn't die on out of memory,
+ * since you should be able to do a call with large arguments.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param method the name of the method to invoke
+ * @param first_arg_type type of the first argument
+ *
+ * @returns opaque pending call object
+ * */
+DBusGPendingCall*
+dbus_g_proxy_begin_call (DBusGProxy *proxy,
+ const char *method,
+ GType first_arg_type,
+ ...)
+{
+ DBusGPendingCall *pending;
+ va_list args;
+ GValueArray *arg_values;
+
+ va_start (args, first_arg_type);
+
+ DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
+
+ pending = dbus_g_proxy_begin_call_internal (proxy, method, arg_values);
+
+ g_value_array_free (arg_values);
+
+ va_end (args);
+
+ return pending;
+}
+
+/**
+ * Collects the results of a method call. The method call was normally
+ * initiated with dbus_g_proxy_end_call(). This function will block if
+ * the results haven't yet been received; use
+ * dbus_g_pending_call_set_notify() to be notified asynchronously that a
+ * pending call has been completed. If it's completed, it will not block.
+ *
+ * If the call results in an error, the error is set as normal for
+ * GError and the function returns #FALSE.
+ *
+ * Otherwise, the "out" parameters and return value of the
+ * method are stored in the provided varargs list.
+ * The list should be terminated with G_TYPE_INVALID.
+ *
+ * This function unrefs the pending call.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param pending the pending call from dbus_g_proxy_begin_call()
+ * @param error return location for an error
+ * @param first_arg_type type of first "out" argument
+ * @returns #FALSE if an error is set
+ */
+gboolean
+dbus_g_proxy_end_call (DBusGProxy *proxy,
+ DBusGPendingCall *pending,
+ GError **error,
+ GType first_arg_type,
+ ...)
+{
+ gboolean ret;
+ va_list args;
+
+ va_start (args, first_arg_type);
+
+ ret = dbus_g_proxy_end_call_internal (proxy, pending, error, first_arg_type, args);
+
+ va_end (args);
+
+ return ret;
+}
+
+/**
+ * Function for invoking a method and receiving reply values.
+ * Normally this is not used directly - calls to it are generated
+ * from client-side wrappers (see dbus-binding-tool).
+ *
+ * @param proxy a proxy for a remote interface
+ * @param method method to invoke
+ * @param error return location for an error
+ * @returns #FALSE if an error is set, TRUE otherwise
+ */
+gboolean
+dbus_g_proxy_invoke (DBusGProxy *proxy,
+ const char *method,
+ GError **error,
+ GType first_arg_type,
+ ...)
+{
+ gboolean ret;
+ DBusGPendingCall *pending;
+ va_list args;
+ GValueArray *in_args;
+
+ va_start (args, first_arg_type);
+
+ DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
+
+ pending = dbus_g_proxy_begin_call_internal (proxy, method, in_args);
+
+ g_value_array_free (in_args);
+
+ first_arg_type = va_arg (args, GType);
+ ret = dbus_g_proxy_end_call_internal (proxy, pending, error, first_arg_type, args);
+
+ va_end (args);
+
+ return ret;
}
/**
@@ -1614,30 +1638,29 @@
*/
void
dbus_g_proxy_call_no_reply (DBusGProxy *proxy,
- const char *method,
- int first_arg_type,
- ...)
+ const char *method,
+ GType first_arg_type,
+ ...)
{
DBusMessage *message;
va_list args;
+ GValueArray *in_args;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
- message = dbus_message_new_method_call (proxy->name,
- proxy->path,
- proxy->interface,
- method);
- if (message == NULL)
+ va_start (args, first_arg_type);
+ DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
+
+ message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
+
+ g_value_array_free (in_args);
+ va_end (args);
+
+ if (!message)
goto oom;
dbus_message_set_no_reply (message, TRUE);
-
- va_start (args, first_arg_type);
- if (!dbus_message_append_args_valist (message, first_arg_type,
- args))
- goto oom;
- va_end (args);
if (!dbus_connection_send (proxy->manager->connection,
message,
@@ -1696,41 +1719,63 @@
g_error ("Out of memory\n");
}
+static void
+array_free_all (gpointer array)
+{
+ g_array_free (array, TRUE);
+}
+
/**
- * Specifies the signature of a signal, such that it's possible to
- * connect to the signal on this proxy.
+ * Specifies the argument signature of a signal;.only necessary
+ * if the remote object does not support introspection. The arguments
+ * specified are the GLib types expected.
*
* @param proxy the proxy for a remote interface
* @param signal_name the name of the signal
- * @param signature D-BUS signature of the signal
+ * @param first_type the first argument type, or G_TYPE_INVALID if none
*/
void
dbus_g_proxy_add_signal (DBusGProxy *proxy,
const char *signal_name,
- const char *signature)
+ GType first_type,
+ ...)
{
GQuark q;
char *name;
+ GArray *gtypesig;
+ GType gtype;
+ va_list args;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
g_return_if_fail (signal_name != NULL);
- g_return_if_fail (signature != NULL);
-#ifndef G_DISABLE_CHECKS
- if (lookup_g_marshaller (proxy, signature) == NULL)
- g_warning ("No marshaller for signature '%s', we need to add API for providing your own",
- signature);
-#endif
name = create_signal_name (proxy->interface, signal_name);
q = g_quark_from_string (name);
g_return_if_fail (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL);
+
+ gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
+
+ va_start (args, first_type);
+ gtype = first_type;
+ while (gtype != G_TYPE_INVALID)
+ {
+ g_array_append_val (gtypesig, gtype);
+ gtype = va_arg (args, GType);
+ }
+ va_end (args);
+
+#ifndef G_DISABLE_CHECKS
+ if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
+ g_warning ("No marshaller for signature of signal '%s'", signal_name);
+#endif
+
g_datalist_id_set_data_full (&proxy->signal_signatures,
- q, g_strdup (signature),
- g_free);
+ q, gtypesig,
+ array_free_all);
g_free (name);
}
Index: dbus-gobject.h
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gobject.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- dbus-gobject.h 18 Feb 2005 03:14:33 -0000 1.2
+++ dbus-gobject.h 13 Jun 2005 03:01:24 -0000 1.3
@@ -24,11 +24,19 @@
#define DBUS_GLIB_OBJECT_H
#include <dbus/dbus.h>
+#include <dbus/dbus-signature.h>
#include <glib.h>
+#include "dbus/dbus-glib.h"
G_BEGIN_DECLS
-GValueArray* _dbus_glib_marshal_dbus_message_to_gvalue_array (DBusMessage *message);
+const char * _dbus_gobject_get_path (GObject *obj);
+
+GClosureMarshal _dbus_gobject_lookup_marshaller (GType rettype,
+ guint n_params,
+ const GType *param_types);
+
+
G_END_DECLS
Index: dbus-gobject.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gobject.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- dbus-gobject.c 3 May 2005 17:45:29 -0000 1.22
+++ dbus-gobject.c 13 Jun 2005 03:01:24 -0000 1.23
@@ -22,12 +22,15 @@
*/
#include <config.h>
+#include <gobject/gvaluecollector.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "dbus-gtest.h"
#include "dbus-gutils.h"
#include "dbus-gobject.h"
#include "dbus-gvalue.h"
+#include "dbus-gmarshal.h"
+#include "dbus-gvalue-utils.h"
#include <string.h>
/**
@@ -35,8 +38,9 @@
* @{
*/
-static GStaticRWLock info_hash_lock = G_STATIC_RW_LOCK_INIT;
+static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
static GHashTable *info_hash = NULL;
+static GHashTable *marshal_table = NULL;
static char*
uscore_to_wincaps (const char *uscore)
@@ -129,7 +133,7 @@
method_arg_info_from_object_info (const DBusGObjectInfo *object,
const DBusGMethodInfo *method)
{
- return string_table_lookup (get_method_data (object, method), 2);
+ return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
}
static const char *
@@ -199,42 +203,6 @@
return method_dir_signature_from_object_info (object, method, FALSE);
}
-/**
- * Converts the args of a message into an array of GValue.
- *
- * @param message the message
- * @returns #NULL if conversion fails, otherwise the values.
- */
-GValueArray *
-_dbus_glib_marshal_dbus_message_to_gvalue_array (DBusMessage *message)
-{
- GValueArray *ret;
- DBusMessageIter iter;
- int dtype;
-
- ret = g_value_array_new (6); /* 6 is a typical maximum for arguments */
- dbus_message_iter_init (message, &iter);
-
- while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
- {
- GValue value = { 0, };
-
- if (!dbus_gvalue_demarshal (&iter, &value))
- {
- g_warning ("Unable to convert arg type %d to GValue", dtype);
- g_value_array_free (ret);
- ret = NULL;
- goto out;
- }
- g_value_array_append (ret, &value);
-
- dbus_message_iter_next (&iter);
- }
-
- out:
- return ret;
-}
-
static void
gobject_unregister_function (DBusConnection *connection,
void *user_data)
@@ -267,7 +235,7 @@
gboolean can_get;
GParamSpec *spec = specs[i];
- dbus_type = dbus_gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec));
+ dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
if (dbus_type == NULL)
continue;
@@ -347,7 +315,7 @@
g_signal_query (ids[i], &query);
- if (query.return_type)
+ if (query.return_type != G_TYPE_NONE)
continue; /* FIXME: these could be listed as methods ? */
g_string_append (xml, " <signal name=\"");
@@ -356,8 +324,11 @@
for (arg = 0; arg < query.n_params; arg++)
{
- const char *dbus_type = dbus_gtype_to_dbus_type (query.param_types[arg]);
+ const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]);
+ if (!dbus_type)
+ continue;
+
g_string_append (xml, " <arg type=\"");
g_string_append (xml, dbus_type);
g_string_append (xml, "\"/>\n");
@@ -428,7 +399,7 @@
{
GType classtype;
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_lock (&globals_lock);
for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
{
@@ -475,7 +446,7 @@
}
}
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_unlock (&globals_lock);
}
static DBusHandlerResult
@@ -560,15 +531,15 @@
GValue value = { 0, };
DBusMessage *ret;
DBusMessageIter sub;
+ DBusGValueMarshalCtx context;
dbus_message_iter_recurse (iter, &sub);
-
- /* The g_object_set_property() will transform some types, e.g. it
- * will let you use a uchar to set an int property etc. Note that
- * any error in value range or value conversion will just
- * g_warning(). These GObject skels are not for secure applications.
- */
- if (dbus_gvalue_demarshal (&sub, &value))
+
+ context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
+ context.proxy = NULL;
+
+ g_value_init (&value, pspec->value_type);
+ if (dbus_gvalue_demarshal (&context, &sub, &value, NULL))
{
g_object_set_property (object,
pspec->name,
@@ -644,7 +615,7 @@
signature = dbus_message_get_signature (message);
ret = FALSE;
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_lock (&globals_lock);
if (!info_hash)
goto out;
@@ -674,6 +645,7 @@
expected_interface = method_interface_from_object_info (*object_ret, method);
expected_member = method_name_from_object_info (*object_ret, method);
expected_signature = method_input_signature_from_object_info (*object_ret, method);
+
if ((interface == NULL
|| strcmp (expected_interface, interface) == 0)
&& strcmp (expected_member, member) == 0
@@ -689,7 +661,7 @@
}
}
out:
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_unlock (&globals_lock);
return ret;
}
@@ -759,74 +731,147 @@
DBusConnection *connection,
DBusMessage *message)
{
- gboolean had_error;
+ gboolean had_error, call_only;
GError *gerror;
GValueArray *value_array;
GValue object_value = {0,};
GValue error_value = {0,};
GValue return_value = {0,};
GClosure closure;
- char *out_signature;
- int out_signature_len;
- GArray *out_param_values;
- int i;
+ char *in_signature;
+ char *out_signature = NULL;
+ int current_type;
+ DBusSignatureIter out_signature_iter;
+ GArray *out_param_values = NULL;
+ GValueArray *out_param_gvalues = NULL;
+ int out_param_count;
+ int out_param_pos, out_param_gvalue_pos;
DBusHandlerResult result;
DBusMessage *reply;
gerror = NULL;
+ if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0) {
+ call_only = TRUE;
+ } else {
+ call_only = FALSE;
+ }
+
/* This is evil. We do this to work around the fact that
* the generated glib marshallers check a flag in the closure object
* which we don't care about. We don't need/want to create
* a new closure for each invocation.
*/
memset (&closure, 0, sizeof (closure));
+
+ in_signature = method_input_signature_from_object_info (object_info, method);
/* Convert method IN parameters to GValueArray */
- value_array = _dbus_glib_marshal_dbus_message_to_gvalue_array (message);
+ {
+ GArray *types_array;
+ guint n_params;
+ const GType *types;
+ DBusGValueMarshalCtx context;
- g_return_val_if_fail (value_array != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+ context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
+ context.proxy = NULL;
+
+ types_array = dbus_gtypes_from_arg_signature (in_signature, FALSE);
+ n_params = types_array->len;
+ types = (const GType*) types_array->data;
+
+ value_array = dbus_gvalue_demarshal_message (&context, message, n_params, types, NULL);
+ if (value_array == NULL)
+ {
+ g_free (in_signature);
+ g_array_free (types_array, TRUE);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ g_array_free (types_array, TRUE);
+ }
/* Prepend object as first argument */
g_value_init (&object_value, G_TYPE_OBJECT);
g_value_set_object (&object_value, object);
g_value_array_prepend (value_array, &object_value);
+ if (call_only) {
+ GValue context_value = {0,};
+ DBusGMethodInvocation *context;
+ context = g_new (DBusGMethodInvocation, 1);
+ context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
+ context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
+ context->object = object_info;
+ context->method = method;
+ g_value_init (&context_value, G_TYPE_POINTER);
+ g_value_set_pointer (&context_value, context);
+ g_value_array_append (value_array, &context_value);
+ } else {
out_signature = method_output_signature_from_object_info (object_info, method);
- out_signature_len = strlen (out_signature);
+
+ /* Count number of output parameters */
+ dbus_signature_iter_init (&out_signature_iter, out_signature);
+ out_param_count = 0;
+ while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
+ {
+ out_param_count++;
+ dbus_signature_iter_next (&out_signature_iter);
+ }
/* Create an array to store the actual values of OUT
* parameters. Then, create a GValue boxed POINTER
* to each of those values, and append to the invocation,
* so the method can return the OUT parameters.
*/
- out_param_values = g_array_new (FALSE, TRUE, sizeof (DBusBasicGValue));
- for (i = 0; i < out_signature_len; i++)
+ out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
+
+ /* We have a special array of GValues for toplevel GValue return
+ * types.
+ */
+ out_param_gvalues = g_value_array_new (out_param_count);
+ out_param_pos = 0;
+ out_param_gvalue_pos = 0;
+ dbus_signature_iter_init (&out_signature_iter, out_signature);
+ while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
{
GValue value = {0, };
- DBusBasicGValue basic;
-
- memset (&basic, 0, sizeof (basic));
-
- /* FIXME - broken for container types */
+ GTypeCValue storage;
- g_array_append_val (out_param_values, basic);
g_value_init (&value, G_TYPE_POINTER);
- g_value_set_pointer (&value, &(g_array_index (out_param_values, DBusBasicGValue, i)));
+
+ /* We special case variants to make method invocation a bit nicer */
+ if (current_type != DBUS_TYPE_VARIANT)
+ {
+ memset (&storage, 0, sizeof (storage));
+ g_array_append_val (out_param_values, storage);
+ g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
+ out_param_pos++;
+ }
+ else
+ {
+ g_value_array_append (out_param_gvalues, NULL);
+ g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
+ out_param_gvalue_pos++;
+ }
g_value_array_append (value_array, &value);
+ dbus_signature_iter_next (&out_signature_iter);
}
/* Append GError as final argument */
g_value_init (&error_value, G_TYPE_POINTER);
g_value_set_pointer (&error_value, &gerror);
g_value_array_append (value_array, &error_value);
-
+ }
/* Actually invoke method */
g_value_init (&return_value, G_TYPE_BOOLEAN);
method->marshaller (&closure, &return_value,
value_array->n_values,
value_array->values,
NULL, method->function);
+ if (call_only) {
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ goto done;
+ }
had_error = !g_value_get_boolean (&return_value);
if (!had_error)
@@ -839,16 +884,34 @@
/* Append OUT arguments to reply */
dbus_message_iter_init_append (reply, &iter);
- for (i = 0; i < out_signature_len; i++)
+ dbus_signature_iter_init (&out_signature_iter, out_signature);
+ out_param_pos = 0;
+ out_param_gvalue_pos = 0;
+ while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
{
- DBusBasicGValue *value;
-
- /* FIXME - broken for container types */
-
- value = &(g_array_index (out_param_values, DBusBasicGValue, i));
- if (!dbus_message_iter_append_basic (&iter, out_signature[i], value))
- goto nomem;
+ GValue gvalue = {0, };
+ g_value_init (&gvalue, dbus_gtype_from_signature_iter (&out_signature_iter, FALSE));
+ if (current_type != DBUS_TYPE_VARIANT)
+ {
+ if (!dbus_gvalue_take (&gvalue,
+ &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
+ g_assert_not_reached ();
+ out_param_pos++;
+ }
+ else
+ {
+ g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
+ out_param_gvalue_pos++;
+ }
+
+ if (!dbus_gvalue_marshal (&iter, &gvalue))
+ goto nomem;
+ /* Here we actually free the allocated value; we
+ * took ownership of it with dbus_gvalue_take.
+ */
+ g_value_unset (&gvalue);
+ dbus_signature_iter_next (&out_signature_iter);
}
}
else
@@ -860,30 +923,17 @@
dbus_message_unref (reply);
}
- /* Assume that if there was an error, no return values are
- * set */
- if (!had_error)
- {
- /* Be sure to free all returned STRING arguments for now;
- * later this should be specified via method info parameter
- * annotation; probably we want to support custom free funcs too */
- for (i = 0; i < out_signature_len; i++)
- {
- DBusBasicGValue *value;
-
- value = &(g_array_index (out_param_values, DBusBasicGValue, i));
- if (out_signature[i] == DBUS_TYPE_STRING)
- g_free (value->gpointer_val);
- }
- }
-
result = DBUS_HANDLER_RESULT_HANDLED;
done:
+ g_free (in_signature);
g_free (out_signature);
- g_array_free (out_param_values, TRUE);
+ if (!call_only) {
+ g_array_free (out_param_values, TRUE);
+ g_value_array_free (out_param_gvalues);
+ g_value_unset (&object_value);
+ g_value_unset (&error_value);
+ }
g_value_array_free (value_array);
- g_value_unset (&object_value);
- g_value_unset (&error_value);
g_value_unset (&return_value);
return result;
nomem:
@@ -891,6 +941,55 @@
goto done;
}
+void
+dbus_g_method_return (DBusGMethodInvocation *context, ...)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ va_list args;
+ char *out_sig;
+ GArray *argsig;
+ guint i;
+
+ reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
+ out_sig = method_output_signature_from_object_info (context->object, context->method);
+ argsig = dbus_gtypes_from_arg_signature (out_sig, FALSE);
+
+ dbus_message_iter_init_append (reply, &iter);
+
+ va_start (args, context);
+ for (i = 0; i < argsig->len; i++) {
+ GValue value = {0,};
+ char *error;
+ g_value_init (&value, g_array_index (argsig, GType, i));
+ error = NULL;
+ G_VALUE_COLLECT (&value, args, 0, &error);
+ if (error) {
+ g_warning(error);
+ g_free (error);
+ }
+ dbus_gvalue_marshal (&iter, &value);
+ }
+ va_end (args);
+
+ dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
+ dbus_message_unref (reply);
+
+ dbus_g_connection_unref (context->connection);
+ dbus_g_message_unref (context->message);
+ g_free (context);
+}
+
+void
+dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
+{
+ DBusMessage *reply;
+ reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
+ dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
+ dbus_message_unref (reply);
+}
+
+
static DBusHandlerResult
gobject_message_function (DBusConnection *connection,
DBusMessage *message,
@@ -1009,6 +1108,125 @@
NULL
};
+typedef struct {
+ GClosure closure;
+ DBusGConnection *connection;
+ GObject *object;
+ char *signame;
+} DBusGSignalClosure;
+
+static GClosure *
+dbus_g_signal_closure_new (DBusGConnection *connection,
+ GObject *object,
+ const char *signame)
+{
+ DBusGSignalClosure *closure;
+
+ closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
+
+ closure->connection = dbus_g_connection_ref (connection);
+ closure->object = object;
+ closure->signame = g_strdup (signame);
+ return (GClosure*) closure;
+}
+
+static void
+dbus_g_signal_closure_finalize (gpointer data,
+ GClosure *closure)
+{
+ DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
+
+ dbus_g_connection_unref (sigclosure->connection);
+ g_free (sigclosure->signame);
+}
+
+static void
+signal_emitter_marshaller (GClosure *closure,
+ GValue *retval,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ DBusGSignalClosure *sigclosure;
+ DBusMessage *signal;
+ DBusMessageIter iter;
+ guint i;
+ const char *path;
+
+ sigclosure = (DBusGSignalClosure *) closure;
+
+ g_assert (retval == NULL);
+
+ path = _dbus_gobject_get_path (sigclosure->object);
+
+ g_assert (path != NULL);
+
+ signal = dbus_message_new_signal (path,
+ "org.gtk.objects",
+ sigclosure->signame);
+ if (!signal)
+ {
+ g_error ("out of memory");
+ return;
+ }
+
+ dbus_message_iter_init_append (signal, &iter);
+
+ /* First argument is the object itself, and we can't marshall that */
+ for (i = 1; i < n_param_values; i++)
+ {
+ if (!dbus_gvalue_marshal (&iter,
+ (GValue *) (&(param_values[i]))))
+ {
+ g_warning ("failed to marshal parameter %d for signal %s",
+ i, sigclosure->signame);
+ goto out;
+ }
+ }
+ dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
+ signal, NULL);
+ out:
+ dbus_message_unref (signal);
+}
+
+static void
+export_signals (DBusGConnection *connection, GObject *object)
+{
+ guint i;
+ guint *ids, n_ids;
+
+ ids = g_signal_list_ids (G_TYPE_FROM_INSTANCE (object), &n_ids);
+ if (!n_ids)
+ return;
+
+ /* FIXME: recurse to parent types ? */
+ for (i = 0; i < n_ids; i++)
+ {
+ GSignalQuery query;
+ GClosure *closure;
+
+ g_signal_query (ids[i], &query);
+
+ if (query.return_type != G_TYPE_NONE) {
+ g_warning("Not exporting signal '%s' as it has a return type %s", query.signal_name, g_type_name (query.return_type));
+ continue; /* FIXME: these could be listed as methods ? */
+ }
+
+ closure = dbus_g_signal_closure_new (connection, object, query.signal_name);
+ g_closure_set_marshal (closure, signal_emitter_marshaller);
+
+ g_signal_connect_closure_by_id (object,
+ ids[i],
+ 0,
+ closure,
+ FALSE);
+
+ g_closure_add_finalize_notifier (closure, NULL,
+ dbus_g_signal_closure_finalize);
+ }
+}
+
/** @} */ /* end of internals */
/**
@@ -1017,7 +1235,7 @@
*/
/**
- * Install introspection information about the given object class
+ * Install introspection information about the given object GType
* sufficient to allow methods on the object to be invoked by name.
* The introspection information is normally generated by
* dbus-glib-tool, then this function is called in the
@@ -1027,16 +1245,24 @@
* object registered with dbus_g_connection_register_g_object() can have
* their methods invoked remotely.
*
- * @param object_class class struct of the object
+ * @param object_type GType for the object
* @param info introspection data generated by dbus-glib-tool
*/
void
-dbus_g_object_class_install_info (GObjectClass *object_class,
- const DBusGObjectInfo *info)
+dbus_g_object_type_install_info (GType object_type,
+ const DBusGObjectInfo *info)
{
+ GObjectClass *object_class;
+
+ g_return_if_fail (G_TYPE_IS_OBJECT (object_type));
+
+ dbus_g_value_types_init ();
+
+ object_class = g_type_class_peek (object_type);
+
g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
- g_static_rw_lock_writer_lock (&info_hash_lock);
+ g_static_rw_lock_writer_lock (&globals_lock);
if (info_hash == NULL)
{
@@ -1045,7 +1271,7 @@
g_hash_table_replace (info_hash, object_class, (void*) info);
- g_static_rw_lock_writer_unlock (&info_hash_lock);
+ g_static_rw_lock_writer_unlock (&globals_lock);
}
static void
@@ -1087,12 +1313,175 @@
return;
}
+ export_signals (connection, object);
+
g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
}
+GObject *
+dbus_g_connection_lookup_g_object (DBusGConnection *connection,
+ const char *at_path)
+{
+ gpointer ret;
+ if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
+ return NULL;
+ return ret;
+}
+
+typedef struct {
+ GType rettype;
+ guint n_params;
+ GType *params;
+} DBusGFuncSignature;
+
+static guint
+funcsig_hash (gconstpointer key)
+{
+ const DBusGFuncSignature *sig = key;
+ GType *types;
+ guint ret;
+
+ ret = sig->rettype;
+ types = sig->params;
+
+ while (*types != G_TYPE_INVALID)
+ {
+ ret += (int) (*types);
+ types++;
+ }
+
+ return ret;
+}
+
+static gboolean
+funcsig_equal (gconstpointer aval,
+ gconstpointer bval)
+{
+ const DBusGFuncSignature *a = aval;
+ const DBusGFuncSignature *b = bval;
+ const GType *atypes;
+ const GType *btypes;
+
+ if (a->rettype != b->rettype)
+ return FALSE;
+
+ atypes = a->params;
+ btypes = b->params;
+
+ while (*atypes != G_TYPE_INVALID)
+ {
+ if (*btypes != *atypes)
+ return FALSE;
+ atypes++;
+ btypes++;
+ }
+ if (*btypes != G_TYPE_INVALID)
+ return FALSE;
+
+ return TRUE;
+}
+
+GClosureMarshal
+_dbus_gobject_lookup_marshaller (GType rettype,
+ guint n_params,
+ const GType *param_types)
+{
+ GClosureMarshal ret;
+ DBusGFuncSignature sig;
+
+ sig.rettype = rettype;
+ sig.n_params = n_params;
+ sig.params = (GType*) param_types;
+
+ g_static_rw_lock_reader_lock (&globals_lock);
+
+ if (marshal_table)
+ ret = g_hash_table_lookup (marshal_table, &sig);
+ else
+ ret = NULL;
+
+ g_static_rw_lock_reader_unlock (&globals_lock);
+
+ if (ret == NULL)
+ {
+ if (rettype == G_TYPE_NONE)
+ {
+ if (n_params == 0)
+ ret = g_cclosure_marshal_VOID__VOID;
+ else if (n_params == 1)
+ {
+ switch (param_types[0])
+ {
+ case G_TYPE_BOOLEAN:
+ ret = g_cclosure_marshal_VOID__BOOLEAN;
+ case G_TYPE_UCHAR:
+ ret = g_cclosure_marshal_VOID__UCHAR;
+ case G_TYPE_INT:
+ ret = g_cclosure_marshal_VOID__INT;
+ case G_TYPE_UINT:
+ ret = g_cclosure_marshal_VOID__UINT;
+ case G_TYPE_DOUBLE:
+ ret = g_cclosure_marshal_VOID__DOUBLE;
+ case G_TYPE_STRING:
+ ret = g_cclosure_marshal_VOID__STRING;
+ }
+ }
+ }
+ else if (n_params == 3
+ && param_types[0] == G_TYPE_STRING
+ && param_types[1] == G_TYPE_STRING
+ && param_types[2] == G_TYPE_STRING)
+ {
+ ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Register a GClosureMarshal to be used for signal invocations.
+ * This function will not be needed once GLib includes libffi.
+ *
+ * @param rettype a GType for the return type of the function
+ * @param n_types number of function parameters
+ * @param param_types a C array of GTypes values
+ * @param marshaller a GClosureMarshal to be used for invocation
+ */
+void
+dbus_g_object_register_marshaller (GType rettype,
+ guint n_types,
+ const GType *param_types,
+ GClosureMarshal marshaller)
+{
+ DBusGFuncSignature *sig;
+
+ g_static_rw_lock_writer_lock (&globals_lock);
+
+ if (marshal_table == NULL)
+ marshal_table = g_hash_table_new_full (funcsig_hash,
+ funcsig_equal,
+ g_free,
+ NULL);
+ sig = g_new0 (DBusGFuncSignature, 1);
+ sig->rettype = rettype;
+ sig->n_params = n_types;
+ sig->params = g_new (GType, n_types);
+ memcpy (sig->params, param_types, n_types * sizeof (GType));
+
+ g_hash_table_insert (marshal_table, sig, marshaller);
+
+ g_static_rw_lock_writer_unlock (&globals_lock);
+}
+
/** @} */ /* end of public API */
+const char * _dbus_gobject_get_path (GObject *obj)
+{
+ return g_object_get_data (obj, "dbus_glib_object_path");
+}
+
#ifdef DBUS_BUILD_TESTS
#include <stdlib.h>
Index: dbus-gmain.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gmain.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -d -r1.41 -r1.42
--- dbus-gmain.c 16 May 2005 21:27:03 -0000 1.41
+++ dbus-gmain.c 13 Jun 2005 03:01:24 -0000 1.42
@@ -27,6 +27,9 @@
#include <dbus/dbus-glib-lowlevel.h>
#include "dbus-gtest.h"
#include "dbus-gutils.h"
+#include "dbus-gvalue.h"
+#include "dbus-gvalue-utils.h"
+#include <string.h>
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
@@ -709,6 +712,8 @@
DBusError derror;
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ dbus_g_value_types_init ();
dbus_error_init (&derror);
@@ -738,6 +743,30 @@
gboolean
_dbus_gmain_test (const char *test_data_dir)
{
+ 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;
}
Index: dbus-binding-tool-glib.h
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-binding-tool-glib.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbus-binding-tool-glib.h 11 May 2005 19:02:31 -0000 1.4
+++ dbus-binding-tool-glib.h 13 Jun 2005 03:01:24 -0000 1.5
@@ -26,6 +26,7 @@
G_BEGIN_DECLS
#define DBUS_GLIB_ANNOTATION_C_SYMBOL "org.freedesktop.DBus.GLib.CSymbol"
+#define DBUS_GLIB_ANNOTATION_ASYNC "org.freedesktop.DBus.GLib.Async"
gboolean dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gboolean ignore_unsupported, GError **error);
gboolean dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, const char *prefix, GError **error);
Index: dbus-binding-tool-glib.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-binding-tool-glib.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- dbus-binding-tool-glib.c 11 May 2005 19:02:31 -0000 1.8
+++ dbus-binding-tool-glib.c 13 Jun 2005 03:01:24 -0000 1.9
@@ -26,6 +26,7 @@
#include "dbus-gparser.h"
#include "dbus-gutils.h"
#include "dbus-gvalue.h"
+#include "dbus-gvalue-utils.h"
#include "dbus-glib-tool.h"
#include "dbus-binding-tool-glib.h"
#include <glib/gi18n.h>
@@ -45,12 +46,67 @@
GError **error;
GHashTable *generated;
+ GString *blob;
+ guint count;
} DBusBindingToolCData;
static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error);
static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
+static const char *
+dbus_g_type_get_marshal_name (GType gtype)
+{
+ switch (G_TYPE_FUNDAMENTAL (gtype))
+ {
+ case G_TYPE_BOOLEAN:
+ return "BOOLEAN";
+ case G_TYPE_UCHAR:
+ return "UCHAR";
+ case G_TYPE_INT:
+ return "INT";
+ case G_TYPE_UINT:
+ return "UINT";
+ case G_TYPE_INT64:
+ return "INT64";
+ case G_TYPE_UINT64:
+ return "UINT64";
+ case G_TYPE_DOUBLE:
+ return "DOUBLE";
+ case G_TYPE_STRING:
+ return "STRING";
+ case G_TYPE_POINTER:
+ return "POINTER";
+ case G_TYPE_BOXED:
+ return "BOXED";
+ case G_TYPE_OBJECT:
+ return "OBJECT";
+ default:
+ return NULL;
+ }
+}
+
+/* This entire function is kind of...ugh. */
+static const char *
+dbus_g_type_get_c_name (GType gtype)
+{
+ if (dbus_g_type_is_collection (gtype))
+ return "GArray";
+ if (dbus_g_type_is_map (gtype))
+ return "GHashTable";
+
+ if (g_type_is_a (gtype, G_TYPE_STRING))
+ return "char *";
+
+ /* This one is even more hacky...we get an extra *
+ * because G_TYPE_STRV is a G_TYPE_BOXED
+ */
+ if (g_type_is_a (gtype, G_TYPE_STRV))
+ return "char *";
+
+ return g_type_name (gtype);
+}
+
static char *
compute_marshaller (MethodInfo *method, GError **error)
{
@@ -71,9 +127,10 @@
if (arg_info_get_direction (arg) == ARG_IN)
{
const char *marshal_name;
+ GType gtype;
- marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg));
- if (!marshal_name)
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), FALSE);
+ if (gtype == G_TYPE_INVALID)
{
g_set_error (error,
DBUS_BINDING_TOOL_ERROR,
@@ -83,6 +140,10 @@
g_string_free (ret, TRUE);
return NULL;
}
+
+ marshal_name = dbus_g_type_get_marshal_name (gtype);
+ g_assert (marshal_name);
+
if (!first)
g_string_append (ret, ",");
else
@@ -91,6 +152,12 @@
}
}
+ if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) {
+ if (!first)
+ g_string_append (ret, ",");
+ g_string_append (ret, "POINTER");
+ first = FALSE;
+ } else {
/* Append pointer for each out arg storage */
for (elt = method_info_get_args (method); elt; elt = elt->next)
{
@@ -105,12 +172,13 @@
g_string_append (ret, "POINTER");
}
}
-
/* Final GError parameter */
if (!first)
g_string_append (ret, ",");
g_string_append (ret, "POINTER");
+ }
+
return g_string_free (ret, FALSE);
}
@@ -136,25 +204,31 @@
{
const char *marshal_name;
const char *type;
+ GType gtype;
type = arg_info_get_type (arg);
- marshal_name = dbus_gvalue_genmarshal_name_from_type (type);
- if (!marshal_name)
+ gtype = dbus_gtype_from_signature (type, FALSE);
+ if (gtype == G_TYPE_INVALID)
{
g_set_error (error,
DBUS_BINDING_TOOL_ERROR,
DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
- _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"),
+ _("Unsupported conversion from D-BUS type %s to glib type"),
type);
g_string_free (ret, TRUE);
return NULL;
}
+ marshal_name = dbus_g_type_get_marshal_name (gtype);
+ g_assert (marshal_name != NULL);
g_string_append (ret, "_");
- g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (type));
+ g_string_append (ret, marshal_name);
}
}
+ if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) {
+ g_string_append (ret, "_POINTER");
+ } else {
/* Append pointer for each out arg storage */
for (elt = method_info_get_args (method); elt; elt = elt->next)
{
@@ -165,9 +239,9 @@
g_string_append (ret, "_POINTER");
}
}
-
/* Final GError parameter */
g_string_append (ret, "_POINTER");
+ }
return g_string_free (ret, FALSE);
}
@@ -210,7 +284,8 @@
interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
if (interface_c_name == NULL)
{
- return TRUE;
+ if (!data->prefix)
+ return TRUE;
}
methods = interface_info_get_methods (interface);
@@ -223,10 +298,6 @@
char *marshaller_name;
method = (MethodInfo *) tmp->data;
- if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL) == NULL)
- {
- continue;
- }
marshaller_name = compute_marshaller (method, error);
if (!marshaller_name)
@@ -291,12 +362,56 @@
{
if (base_info_get_type (base) == INFO_TYPE_NODE)
{
+ GString *object_introspection_data_blob;
+ GIOChannel *channel;
+ guint i;
+
+ channel = data->channel;
+
+ object_introspection_data_blob = g_string_new_len ("", 0);
+
+ data->blob = object_introspection_data_blob;
+ data->count = 0;
+
+ if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, data->prefix))
+ goto io_lose;
+
if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base),
data, error))
return FALSE;
if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base),
data, error))
return FALSE;
+
+ WRITE_OR_LOSE ("};\n\n");
+
+ /* Information about the object. */
+
+ if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
+ channel, error, data->prefix))
+ goto io_lose;
+ WRITE_OR_LOSE (" 0,\n");
+ if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, data->prefix))
+ goto io_lose;
+ if (!write_printf_to_iochannel (" %d,\n", channel, error, data->count))
+ goto io_lose;
+ WRITE_OR_LOSE(" \"");
+ for (i = 0; i < object_introspection_data_blob->len; i++)
+ {
+ if (object_introspection_data_blob->str[i] != '\0')
+ {
+ if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
+ return FALSE;
+ }
+ else
+ {
+ if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
+ return FALSE;
+ }
+ }
+ WRITE_OR_LOSE ("\"\n};\n\n");
+
+ g_string_free (object_introspection_data_blob, TRUE);
}
else
{
@@ -304,41 +419,43 @@
InterfaceInfo *interface;
GSList *methods;
GSList *tmp;
- gsize i;
- int count;
const char *interface_c_name;
GString *object_introspection_data_blob;
channel = data->channel;
+ object_introspection_data_blob = data->blob;
interface = (InterfaceInfo *) base;
interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
if (interface_c_name == NULL)
{
- return TRUE;
+ if (data->prefix == NULL)
+ return TRUE;
+ interface_c_name = data->prefix;
}
- object_introspection_data_blob = g_string_new_len ("", 0);
-
methods = interface_info_get_methods (interface);
- count = 0;
/* Table of marshalled methods. */
- if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL)))
- goto io_lose;
for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
{
MethodInfo *method;
char *marshaller_name;
- const char *method_c_name;
+ char *method_c_name;
+ gboolean async = FALSE;
GSList *args;
method = (MethodInfo *) tmp->data;
- method_c_name = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL);
+ method_c_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL));
if (method_c_name == NULL)
- {
- continue;
+ {
+ char *method_name_uscored;
+ method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
+ method_c_name = g_strdup_printf ("%s_%s",
+ interface_c_name,
+ method_name_uscored);
+ g_free (method_name_uscored);
}
if (!write_printf_to_iochannel (" { (GCallback) %s, ", channel, error,
@@ -357,6 +474,9 @@
goto io_lose;
}
+ if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL)
+ async = TRUE;
+
/* Object method data blob format:
* <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
*/
@@ -367,6 +487,9 @@
g_string_append (object_introspection_data_blob, method_info_get_name (method));
g_string_append_c (object_introspection_data_blob, '\0');
+ g_string_append_c (object_introspection_data_blob, async ? 'A' : 'S');
+ g_string_append_c (object_introspection_data_blob, '\0');
+
for (args = method_info_get_args (method); args; args = args->next)
{
ArgInfo *arg;
@@ -400,37 +523,8 @@
g_string_append_c (object_introspection_data_blob, '\0');
- count++;
+ data->count++;
}
- WRITE_OR_LOSE ("};\n\n");
-
- /* Information about the object. */
-
- if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
- channel, error, interface_c_name))
- goto io_lose;
- WRITE_OR_LOSE (" 0,\n");
- if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, interface_c_name))
- goto io_lose;
- if (!write_printf_to_iochannel (" %d,\n", channel, error, count))
- goto io_lose;
- WRITE_OR_LOSE(" \"");
- for (i = 0; i < object_introspection_data_blob->len; i++)
- {
- if (object_introspection_data_blob->str[i] != '\0')
- {
- if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
- return FALSE;
- }
- else
- {
- if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
- return FALSE;
- }
- }
- WRITE_OR_LOSE ("\"\n};\n\n");
-
- g_string_free (object_introspection_data_blob, TRUE);
}
return TRUE;
io_lose:
@@ -471,6 +565,8 @@
memset (&data, 0, sizeof (data));
+ dbus_g_value_types_init ();
+
data.prefix = prefix;
data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
data.error = error;
@@ -607,6 +703,8 @@
{
ArgInfo *arg;
const char *type_str;
+ const char *type_suffix;
+ GType gtype;
int direction;
arg = args->data;
@@ -615,9 +713,8 @@
direction = arg_info_get_direction (arg);
- type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN);
-
- if (!type_str)
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ if (gtype == G_TYPE_INVALID)
{
g_set_error (error,
DBUS_BINDING_TOOL_ERROR,
@@ -628,18 +725,37 @@
interface_info_get_name (iface));
return FALSE;
}
+ type_str = dbus_g_type_get_c_name (gtype);
+ g_assert (type_str);
+ /* Variants are special...*/
+ if (gtype == G_TYPE_VALUE)
+ {
+ if (direction == ARG_IN)
+ type_suffix = "*";
+ else
+ type_suffix = "";
+ }
+ else if ((g_type_is_a (gtype, G_TYPE_BOXED)
+ || g_type_is_a (gtype, G_TYPE_OBJECT)
+ || g_type_is_a (gtype, G_TYPE_POINTER)))
+ type_suffix = "*";
+ else
+ type_suffix = "";
+
switch (direction)
{
case ARG_IN:
- if (!write_printf_to_iochannel ("%s IN_%s", channel, error,
+ if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
type_str,
+ type_suffix,
arg_info_get_name (arg)))
goto io_lose;
break;
case ARG_OUT:
- if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error,
+ if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
type_str,
+ type_suffix,
arg_info_get_name (arg)))
goto io_lose;
break;
@@ -653,32 +769,71 @@
return FALSE;
}
-static gboolean
-write_args_sig_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
+#define MAP_FUNDAMENTAL(NAME) \
+ case G_TYPE_ ## NAME: \
+ return g_strdup ("G_TYPE_" #NAME);
+#define MAP_KNOWN(NAME) \
+ if (gtype == NAME) \
+ return g_strdup (#NAME)
+static char *
+dbus_g_type_get_lookup_function (GType gtype)
{
- GSList *args;
-
- WRITE_OR_LOSE ("\"");
-
- for (args = method_info_get_args (method); args; args = args->next)
+ char *type_lookup;
+ switch (gtype)
{
- ArgInfo *arg;
-
- arg = args->data;
-
- if (direction != arg_info_get_direction (arg))
- continue;
-
- if (!write_printf_to_iochannel ("%s", channel, error, arg_info_get_type (arg)))
- goto io_lose;
+ MAP_FUNDAMENTAL(CHAR);
+ MAP_FUNDAMENTAL(UCHAR);
+ MAP_FUNDAMENTAL(BOOLEAN);
+ MAP_FUNDAMENTAL(LONG);
+ MAP_FUNDAMENTAL(ULONG);
+ MAP_FUNDAMENTAL(INT);
+ MAP_FUNDAMENTAL(UINT);
+ MAP_FUNDAMENTAL(INT64);
+ MAP_FUNDAMENTAL(UINT64);
+ MAP_FUNDAMENTAL(FLOAT);
+ MAP_FUNDAMENTAL(DOUBLE);
+ MAP_FUNDAMENTAL(STRING);
}
-
- WRITE_OR_LOSE ("\", ");
-
- return TRUE;
- io_lose:
- return FALSE;
+ if (dbus_g_type_is_collection (gtype))
+ {
+ GType elt_gtype;
+ char *sublookup;
+
+ elt_gtype = dbus_g_type_get_collection_specialization (gtype);
+ sublookup = dbus_g_type_get_lookup_function (elt_gtype);
+ g_assert (sublookup);
+ type_lookup = g_strdup_printf ("dbus_g_type_get_collection (\"GArray\", %s)",
+ sublookup);
+ g_free (sublookup);
+ return type_lookup;
+ }
+ else if (dbus_g_type_is_map (gtype))
+ {
+ GType key_gtype;
+ char *key_lookup;
+ GType value_gtype;
+ char *value_lookup;
+
+ key_gtype = dbus_g_type_get_map_key_specialization (gtype);
+ value_gtype = dbus_g_type_get_map_value_specialization (gtype);
+ key_lookup = dbus_g_type_get_lookup_function (key_gtype);
+ g_assert (key_lookup);
+ value_lookup = dbus_g_type_get_lookup_function (value_gtype);
+ g_assert (value_lookup);
+ type_lookup = g_strdup_printf ("dbus_g_type_get_map (\"GHashTable\", %s, %s)",
+ key_lookup, value_lookup);
+ g_free (key_lookup);
+ g_free (value_lookup);
+ return type_lookup;
+ }
+ MAP_KNOWN(G_TYPE_VALUE);
+ MAP_KNOWN(G_TYPE_STRV);
+ MAP_KNOWN(DBUS_TYPE_G_PROXY);
+ MAP_KNOWN(DBUS_TYPE_G_PROXY_ARRAY);
+ return NULL;
}
+#undef MAP_FUNDAMENTAL
+#undef MAP_KNOWN
static gboolean
write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
@@ -688,25 +843,38 @@
for (args = method_info_get_args (method); args; args = args->next)
{
ArgInfo *arg;
+ GType gtype;
+ char *type_lookup;
arg = args->data;
if (direction != arg_info_get_direction (arg))
continue;
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ g_assert (gtype != G_TYPE_INVALID);
+ type_lookup = dbus_g_type_get_lookup_function (gtype);
+ g_assert (type_lookup != NULL);
+
switch (direction)
{
+
case ARG_IN:
- if (!write_printf_to_iochannel ("IN_%s, ", channel, error, arg_info_get_name (arg)))
+ if (!write_printf_to_iochannel ("%s, IN_%s, ", channel, error,
+ type_lookup,
+ arg_info_get_name (arg)))
goto io_lose;
break;
case ARG_OUT:
- if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, arg_info_get_name (arg)))
+ if (!write_printf_to_iochannel ("%s, OUT_%s, ", channel, error,
+ type_lookup,
+ arg_info_get_name (arg)))
goto io_lose;
break;
case ARG_INVALID:
break;
}
+ g_free (type_lookup);
}
return TRUE;
@@ -722,15 +890,303 @@
for (args = method_info_get_args (method); args; args = args->next)
{
ArgInfo *arg;
+ GType gtype;
+
arg = args->data;
- if (!dbus_gvalue_ctype_from_type (arg_info_get_type (arg),
- arg_info_get_direction (arg)))
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ if (gtype == G_TYPE_INVALID)
return FALSE;
}
return TRUE;
}
static gboolean
+write_untyped_out_args (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
+{
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+
+ arg = args->data;
+ if (arg_info_get_direction (arg) != ARG_OUT)
+ continue;
+
+ if (!write_printf_to_iochannel ("OUT_%s, ", channel, error,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ }
+
+ return TRUE;
+ io_lose:
+ return FALSE;
+}
+
+static gboolean
+write_formal_declarations_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
+ {
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ GType gtype;
+ const char *type_str, *type_suffix;
+ int dir;
+
+ arg = args->data;
+
+ dir = arg_info_get_direction (arg);
+
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ type_str = dbus_g_type_get_c_name (gtype);
+
+ if (!type_str)
+ {
+ g_set_error (error,
+ DBUS_BINDING_TOOL_ERROR,
+ DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+ _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
+ arg_info_get_type (arg),
+ method_info_get_name (method),
+ interface_info_get_name (iface));
+ return FALSE;
+ }
+
+ /* Variants are special...*/
+ if (gtype == G_TYPE_VALUE)
+ {
+ if (direction == ARG_IN)
+ type_suffix = "*";
+ else
+ type_suffix = "";
+ }
+ else if ((g_type_is_a (gtype, G_TYPE_BOXED)
+ || g_type_is_a (gtype, G_TYPE_OBJECT)
+ || g_type_is_a (gtype, G_TYPE_POINTER)))
+ type_suffix = "*";
+ else
+ type_suffix = "";
+
+ if (direction != dir)
+ continue;
+
+ switch (dir)
+ {
+ case ARG_IN:
+ if (!write_printf_to_iochannel (" %s%s IN_%s;\n", channel, error,
+ type_str, type_suffix,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_OUT:
+ if (!write_printf_to_iochannel (" %s%s OUT_%s;\n", channel, error,
+ type_str, type_suffix,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_INVALID:
+ break;
+ }
+ }
+ return TRUE;
+ io_lose:
+ return FALSE;
+ }
+
+static gboolean
+write_formal_parameters_for_direction (InterfaceInfo *iface, MethodInfo *method, int dir, GIOChannel *channel, GError **error)
+{
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ const char *type_str;
+ const char *type_suffix;
+ GType gtype;
+ int direction;
+
+ arg = args->data;
+
+ direction = arg_info_get_direction (arg);
+ if (dir != direction) continue;
+
+ WRITE_OR_LOSE (", ");
+
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ type_str = dbus_g_type_get_c_name (gtype);
+ /* Variants are special...*/
+ if (gtype == G_TYPE_VALUE)
+ {
+ if (direction == ARG_IN)
+ type_suffix = "*";
+ else
+ type_suffix = "";
+ }
+ else if ((g_type_is_a (gtype, G_TYPE_BOXED)
+ || g_type_is_a (gtype, G_TYPE_OBJECT)
+ || g_type_is_a (gtype, G_TYPE_POINTER)))
+ type_suffix = "*";
+ else
+ type_suffix = "";
+
+ if (!type_str)
+ {
+ g_set_error (error,
+ DBUS_BINDING_TOOL_ERROR,
+ DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+ _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
+ arg_info_get_type (arg),
+ method_info_get_name (method),
+ interface_info_get_name (iface));
+ return FALSE;
+ }
+
+ switch (direction)
+ {
+ case ARG_IN:
+ if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
+ type_str,
+ type_suffix,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_OUT:
+ if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
+ type_str,
+ type_suffix,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_INVALID:
+ break;
+ }
+ }
+ return TRUE;
+ io_lose:
+ return FALSE;
+}
+
+static gboolean
+write_typed_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
+ {
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ int dir;
+ GType gtype;
+ const char *type_lookup;
+
+ arg = args->data;
+
+ dir = arg_info_get_direction (arg);
+
+ if (dir != direction)
+ continue;
+
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ type_lookup = dbus_g_type_get_lookup_function (gtype);
+
+ if (!write_printf_to_iochannel ("%s, &%s_%s, ", channel, error, type_lookup, direction == ARG_IN ? "IN" : "OUT", arg_info_get_name (arg)))
+ goto io_lose;
+ }
+ return TRUE;
+ io_lose:
+ return FALSE;
+}
+
+static gboolean
+write_async_method_client (GIOChannel *channel, InterfaceInfo *interface, MethodInfo *method, GError **error)
+{
+ char *method_name, *iface_prefix;
+ iface_prefix = iface_to_c_prefix (interface_info_get_name (interface));
+ method_name = compute_client_method_name (iface_prefix, method);
+
+ /* Write the typedef for the client callback */
+ if (!write_printf_to_iochannel ("typedef void (*%s_reply) (", channel, error, method_name))
+ goto io_lose;
+ {
+ GSList *args;
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ const char *type_suffix, *type_str;
+ GType gtype;
+
+ arg = args->data;
+
+ if (arg_info_get_direction (arg) != ARG_OUT)
+ continue;
+ gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+ if (gtype != G_TYPE_VALUE && (g_type_is_a (gtype, G_TYPE_BOXED)
+ || g_type_is_a (gtype, G_TYPE_OBJECT)
+ || g_type_is_a (gtype, G_TYPE_POINTER)))
+ type_suffix = "*";
+ else
+ type_suffix = "";
+ type_str = dbus_g_type_get_c_name (dbus_gtype_from_signature (arg_info_get_type (arg), TRUE));
+ if (!write_printf_to_iochannel ("%s %sOUT_%s, ", channel, error, type_str, type_suffix, arg_info_get_name (arg)))
+ goto io_lose;
+ }
+ }
+ WRITE_OR_LOSE ("GError *error, gpointer userdata);\n\n");
+
+
+ /* Write the callback when the call returns */
+ WRITE_OR_LOSE ("static void\n");
+ if (!write_printf_to_iochannel ("%s_async_callback (DBusGPendingCall *pending, DBusGAsyncData *data)\n", channel, error, method_name))
+ goto io_lose;
+ WRITE_OR_LOSE ("{\n");
+ WRITE_OR_LOSE (" GError *error = NULL;\n");
+ if (!write_formal_declarations_for_direction (interface, method, channel, ARG_OUT, error))
+ goto io_lose;
+ WRITE_OR_LOSE (" dbus_g_proxy_end_call (data->proxy, pending, &error, ");
+ if (!write_typed_args_for_direction (interface, method, channel, ARG_OUT, error))
+ goto io_lose;
+ WRITE_OR_LOSE("G_TYPE_INVALID);\n");
+ if (!write_printf_to_iochannel (" (*(%s_reply)data->cb) (", channel, error, method_name))
+ goto io_lose;
+ if (!write_untyped_out_args (interface, method, channel, error))
+ goto io_lose;
+ WRITE_OR_LOSE ("error, data->userdata);\n");
+ WRITE_OR_LOSE (" return;\n}\n\n");
+
+
+ /* Write the main wrapper function */
+ WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n");
+ if (!write_printf_to_iochannel ("%s_async (DBusGProxy *proxy", channel, error,
+ method_name))
+ goto io_lose;
+ if (!write_formal_parameters_for_direction (interface, method, ARG_IN, channel, error))
+ goto io_lose;
+
+ if (!write_printf_to_iochannel (", %s_reply callback, gpointer userdata)\n\n", channel, error, method_name))
+ goto io_lose;
+
+ WRITE_OR_LOSE ("{\n");
+ WRITE_OR_LOSE (" DBusGPendingCall *pending;\n DBusGAsyncData *stuff;\n stuff = g_new (DBusGAsyncData, 1);\n stuff->proxy = proxy;\n stuff->cb = callback;\n stuff->userdata = userdata;\n");
+ if (!write_printf_to_iochannel (" pending = dbus_g_proxy_begin_call (proxy, \"%s\", ", channel, error, method_info_get_name (method)))
+ goto io_lose;
+ if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
+ goto io_lose;
+ WRITE_OR_LOSE ("G_TYPE_INVALID);\n");
+
+ if (!write_printf_to_iochannel (" dbus_g_pending_call_set_notify(pending, (DBusGPendingCallNotify)%s_async_callback, stuff, g_free);\n", channel, error, method_name))
+ goto io_lose;
+
+ WRITE_OR_LOSE (" return TRUE;\n}\n\n");
+
+ g_free (method_name);
+ return TRUE;
+ io_lose:
+ return FALSE;
+ }
+
+static gboolean
generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
{
GSList *tmp;
@@ -818,21 +1274,19 @@
method_info_get_name (method)))
goto io_lose;
- if (!write_args_sig_for_direction (interface, method, channel, ARG_IN, error))
- goto io_lose;
-
- if (!write_args_sig_for_direction (interface, method, channel, ARG_OUT, error))
- goto io_lose;
-
WRITE_OR_LOSE ("error, ");
if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
goto io_lose;
+ WRITE_OR_LOSE ("G_TYPE_INVALID, ");
+
if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
goto io_lose;
- WRITE_OR_LOSE ("NULL);\n}\n\n");
+ WRITE_OR_LOSE ("G_TYPE_INVALID);\n}\n\n");
+
+ write_async_method_client (channel, interface, method, error);
}
if (!write_printf_to_iochannel ("#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_%s */\n\n", channel, error, iface_prefix))
@@ -853,6 +1307,8 @@
DBusBindingToolCData data;
gboolean ret;
+ dbus_g_value_types_init ();
+
memset (&data, 0, sizeof (data));
data.channel = channel;
Index: Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/glib/Makefile.am,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- Makefile.am 17 Mar 2005 17:48:29 -0000 1.17
+++ Makefile.am 13 Jun 2005 03:01:24 -0000 1.18
@@ -15,8 +15,12 @@
dbus-gthread.c \
dbus-gutils.c \
dbus-gutils.h \
+ dbus-gtype-specialized.c \
+ dbus-gtype-specialized.h \
dbus-gvalue.c \
- dbus-gvalue.h
+ dbus-gvalue.h \
+ dbus-gvalue-utils.c \
+ dbus-gvalue-utils.h
libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la
## don't export symbols that start with "_" (we use this
More information about the dbus-commit
mailing list