summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog184
-rw-r--r--dbus/dbus-glib.h126
-rw-r--r--doc/TODO9
-rw-r--r--doc/dbus-tutorial.xml680
-rw-r--r--glib/Makefile.am6
-rw-r--r--glib/dbus-binding-tool-glib.c642
-rw-r--r--glib/dbus-binding-tool-glib.h1
-rw-r--r--glib/dbus-gmain.c29
-rw-r--r--glib/dbus-gobject.c599
-rw-r--r--glib/dbus-gobject.h10
-rw-r--r--glib/dbus-gproxy.c789
-rw-r--r--glib/dbus-gtype-specialized.c441
-rw-r--r--glib/dbus-gtype-specialized.h104
-rw-r--r--glib/dbus-gvalue-utils.c715
-rw-r--r--glib/dbus-gvalue-utils.h70
-rw-r--r--glib/dbus-gvalue.c1508
-rw-r--r--glib/dbus-gvalue.h55
-rw-r--r--python/Makefile.am2
-rw-r--r--test/glib/Makefile.am6
-rw-r--r--test/glib/test-dbus-glib.c487
-rw-r--r--test/glib/test-service-glib.c231
-rw-r--r--test/glib/test-service-glib.xml73
-rw-r--r--tools/Makefile.am4
-rw-r--r--tools/dbus-names-model.c14
-rw-r--r--tools/dbus-viewer.c23
-rw-r--r--tools/print-introspect.c10
26 files changed, 5825 insertions, 993 deletions
diff --git a/ChangeLog b/ChangeLog
index bf71a3b8..305d7673 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,187 @@
+2005-06-12 Colin Walters <walters@verbum.org>
+
+ Async signals and various bugfixes and testing by
+ Ross Burton <ross@burtonini.com>.
+
+ * glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete.
+ (dbus_gvalue_genmarshal_name_from_type)
+ (dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c.
+ (dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature.
+ (dbus_g_value_types_init, dbus_gtype_from_signature)
+ (dbus_gtype_from_signature_iter, dbus_gtype_to_signature)
+ (dbus_gtypes_from_arg_signature): New function prototypes.
+ (dbus_gvalue_demarshal): Take context and error arguments.
+ (dbus_gvalue_demarshal_variant): New function.
+ (dbus_gvalue_demarshal_message): New function.
+ (dbus_gvalue_store): Delete.
+
+ * glib/dbus-gvalue.c:
+
+ File has been almost entirely rewritten; now we special-case
+ more types such as DBUS_TYPE_SIGNATURE, handle arrays and
+ hash tables correctly, etc. Full support for recursive values
+ is not yet complete.
+
+ * glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last
+ argument of signal to G_TYPE_POINTER since we now pass a
+ structure.
+ (lookup_g_marshaller): Delete in favor of
+ _dbus_gobject_lookup_marshaller.
+ (marshal_dbus_message_to_g_marshaller): Use
+ _dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message
+ to handle remote signal callbacks.
+ (dbus_g_proxy_new_from_proxy): New function; creates a new
+ DBusGProxy by copying an existing one.
+ (dbus_g_proxy_get_interface, dbus_g_proxy_set_interface)
+ (dbus_g_proxy_get_path): New functions.
+ (dbus_g_proxy_marshal_args_to_message): New function;
+ factored out of existing code.
+ (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments
+ from a varargs array.
+ (dbus_g_proxy_begin_call_internal): New function.
+ (dbus_g_proxy_end_call_internal): New function.
+ (dbus_g_proxy_begin_call): Take GTypes instead of DBus types
+ as arguments; simply invoke dbus_g_proxy_begin_call_internal
+ after collecting args into value array.
+ (dbus_g_proxy_end_call): Take GTypes instead of DBus types;
+ invoke dbus_g_proxy_end_call_internal.
+ (dbus_g_proxy_invoke): Simply invoke begin_call_interanl and
+ end_call_internal.
+ (dbus_g_proxy_call_no_reply): Take GTypes instead of DBus
+ types.
+ (array_free_all): New function.
+ (dbus_g_proxy_add_signal): Take GTypes.
+
+ * glib/dbus-gobject.h:
+ (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete.
+ (_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller):
+ Prototype.
+
+ * glib/dbus-gobject.c: Add a global marshal_table hash which
+ stores mappings from type signatures to marshallers. Change lots
+ of invocations of dbus_gtype_to_dbus_type to
+ dbus_gtype_to_signature.
+ (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete.
+ (introspect_signals): Fix test for query.return_type.
+ (set_object_property): Update invocation of dbus_gvalue_demarshal.
+ (invoke_object_method): Many changes. Handle asynchronous
+ invocations. Convert arguments with
+ dbus_gvalue_demarshal_message. Handle errors. Use
+ DBusSignatureIter instead of strlen on args. Handle all arguments
+ generically. Special-case variants.
+ (dbus_g_method_return, dbus_g_method_return_error): New function.
+ (DBusGSignalClosure): New structure, closes over signal
+ information.
+ (dbus_g_signal_closure_new): New function.
+ (dbus_g_signal_closure_finalize): New function.
+ (signal_emitter_marshaller): New function; is special marshaller
+ which emits signals on bus.
+ (export_signals): New function; introspects object signals and
+ connects to them.
+ (dbus_g_object_type_install_info): Take GType instead of
+ GObjectClass.
+ (dbus_g_connection_register_g_object): Invoke export_signals.
+ (dbus_g_connection_lookup_g_object): New function.
+ (DBusGFuncSignature) New structure; used for mapping type
+ signatures to marshallers.
+ (funcsig_hash): New function; hashes DBusGFuncSignature.
+ (funcsig_equal): New function; compares DBusGFuncSignature.
+ (_dbus_gobject_lookup_marshaller): New function.
+ (dbus_g_object_register_marshaller): New function; used to
+ register a marshaller at runtime for a particular signature.
+
+ * glib/dbus-gmain.c (_dbus_gmain_test): Add various tests.
+
+ * glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC
+ which notes a server method implementation should be
+ asynchronous.
+
+ * glib/dbus-binding-tool-glib.c
+ (dbus_binding_tool_output_glib_server): Call
+ dbus_g_value_types_init.
+ (write_formal_parameters): Use dbus_gtype_from_signature. Handle
+ variants specially.
+ (dbus_g_type_get_lookup_function): Turn GType into an invocation
+ of a lookup function.
+ (write_args_for_direction): Use dbus_g_type_get_lookup_function.
+ (write_untyped_out_args): New method; write output arguments.
+ (write_formal_declarations_for_direction): Function for
+ writing prototypes.
+ (write_formal_parameters_for_direction): Function for
+ writing implementations.
+ (write_typed_args_for_direction): Function for writing
+ arguments prefixed with GTypes.
+ (write_async_method_client): Write out async version
+ of method.
+
+ * glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h.
+ (dbus_g_type_get_marshal_name): Move mapping from GType
+ to marshal name into here.
+ (dbus_g_type_get_c_name): Move into here.
+ (compute_marshaller): Convert signature to type with
+ dbus_gtype_from_signature, use dbus_g_type_get_marshal_name.
+ (compute_marshaller_name): Ditto.
+ (compute_marshaller): Handle async signal annotations.
+ (gather_marshallers): Return if we don't have a known
+ prefix.
+ (generate_glue): Collect introspection blob here, and
+ write all of the blob at the end. This allows an object
+ with multiple interfaces to work.
+ Mark async methods in introspection blob.
+
+ * glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add
+ dbus-gtype-specialized.c, dbus-gtype-specialized.h,
+ dbus-gvalue-utils.h, dbus-gvalue-utils.c.
+
+ * dbus/dbus-glib.h: Don't include dbus-protocol.h; this
+ avoids people accidentally using DBUS_TYPE_* which should
+ not be necessary anymore.
+ Do include dbus-gtype-specialized.h, which are utilities
+ for GLib container types.
+ Add various #defines for types such as
+ DBUS_TYPE_G_BOOLEAN_ARRAY.
+ (DBusGValueIterator, DBusGValue): Define, not fully used
+ yet.
+ (dbus_g_value_get_g_type): Type for recursive value.
+ (dbus_g_value_open, dbus_g_value_iterator_get_value)
+ (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse)
+ (dbus_g_value_free): Prototypes.
+ (dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype.
+ (dbus_g_proxy_set_interface): Prototype.
+ (dbus_g_proxy_begin_call, dbus_g_proxy_end_call)
+ (dbus_g_proxy_call_no_reply): Take GLib types instead of DBus
+ types.
+ (dbus_g_proxy_get_path, dbus_g_proxy_get_interface):
+ Accessors.
+ (DBusGAsyncData, DBusGMethodInvocation): Structures for
+ doing async invocations.
+ (dbus_g_method_return, dbus_g_method_return_error):
+ Prototypes.
+ * doc/dbus-tutorial.xml: Update GLib section.
+
+ * tools/dbus-viewer.c (load_child_nodes): Update
+ for new invocation type of dbus_g_proxy_end_call.
+ (load_from_service_thread_func): Ditto.
+
+ * tools/print-introspect.c (main): Ditto.
+
+ * tools/dbus-names-model.c (have_names_notify)
+ (names_model_reload, names_model_set_connection)
+ Use GTypes.
+
+ * python/Makefile.am (INCLUDES): Define DBUS_COMPILATION,
+ needed since Python bindings use GLib bindings.
+
+ * test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION.
+ Add --prefix argument.
+
+ * tools/Makefile.am: Define DBUS_COMPILATION. Remove
+ unneeded --ignore-unsupported arg.
+
+ * test/glib/test-service-glib.c:
+ * test/glib/test-service-glib.xml:
+ * test/glib/test-dbus-glib.c: Add many more tests.
+
2005-06-06 David Zeuthen <davidz@redhat.com>
* doc/TODO: Add item about need to remove deprecated functions.
diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h
index e1b4a704..7921c917 100644
--- a/dbus/dbus-glib.h
+++ b/dbus/dbus-glib.h
@@ -25,7 +25,6 @@
#define DBUS_GLIB_H
#include <glib-object.h>
-#include <dbus/dbus-protocol.h>
#include <dbus/dbus-shared.h>
G_BEGIN_DECLS
@@ -115,12 +114,88 @@ struct DBusGObjectInfo
const char *data; /**< Introspection data */
};
-void dbus_g_object_class_install_info (GObjectClass *object_class,
+void dbus_g_object_type_install_info (GType object_type,
const DBusGObjectInfo *info);
-void dbus_g_connection_register_g_object (DBusGConnection *connection,
- const char *at_path,
- GObject *object);
+void dbus_g_connection_register_g_object (DBusGConnection *connection,
+ const char *at_path,
+ GObject *object);
+GObject * dbus_g_connection_lookup_g_object (DBusGConnection *connection,
+ const char *at_path);
+
+
+/**
+ * Generic recursive value
+ */
+
+typedef struct DBusGValueIterator DBusGValueIterator;
+struct DBusGValueIterator
+{
+ void *dummy1; /**< Don't use this */
+ void *dummy2; /**< Don't use this */
+ guint32 dummy3; /**< Don't use this */
+ int dummy4; /**< Don't use this */
+ int dummy5; /**< Don't use this */
+ int dummy6; /**< Don't use this */
+ int dummy7; /**< Don't use this */
+ int dummy8; /**< Don't use this */
+ int dummy9; /**< Don't use this */
+ int dummy10; /**< Don't use this */
+ int dummy11; /**< Don't use this */
+ int pad1; /**< Don't use this */
+ int pad2; /**< Don't use this */
+ void *pad3; /**< Don't use this */
+ void *pad4; /**< Don't use this */
+ void *pad5; /**< Don't use this */
+};
+
+typedef struct DBusGValue DBusGValue;
+
+#ifdef DBUS_COMPILATION
+#include "glib/dbus-gtype-specialized.h"
+#else
+#include <dbus/dbus-gtype-specialized.h>
+#endif
+
+/* definitions for some basic array types */
+#define DBUS_TYPE_G_BOOLEAN_ARRAY (dbus_g_type_get_collection ("GArray", G_TYPE_BOOLEAN))
+#define DBUS_TYPE_G_UCHAR_ARRAY (dbus_g_type_get_collection ("GArray", G_TYPE_UCHAR))
+#define DBUS_TYPE_G_UINT_ARRAY (dbus_g_type_get_collection ("GArray", G_TYPE_UINT))
+#define DBUS_TYPE_G_INT_ARRAY (dbus_g_type_get_collection ("GArray", G_TYPE_INT))
+#define DBUS_TYPE_G_UINT64_ARRAY (dbus_g_type_get_collection ("GArray", G_TYPE_UINT64))
+#define DBUS_TYPE_G_INT64_ARRAY (dbus_g_type_get_collection ("GArray", G_TYPE_INT64))
+#define DBUS_TYPE_G_OBJECT_ARRAY (dbus_g_type_get_collection ("GPtrArray", G_TYPE_OBJECT))
+
+#define DBUS_TYPE_G_STRING_STRING_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING))
+
+/* D-BUS-specific types */
+#define DBUS_TYPE_G_PROXY_ARRAY (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_PROXY))
+
+/* Generic recursive value */
+GType dbus_g_value_get_g_type (void) G_GNUC_CONST;
+#define DBUS_TYPE_G_VALUE (dbus_g_value_get_g_type ())
+
+void dbus_g_value_open (DBusGValue *value,
+ DBusGValueIterator *iter);
+
+GType dbus_g_value_iterator_get_value (DBusGValueIterator *iter,
+ GValue *value);
+
+gboolean dbus_g_value_iterator_get_values (DBusGValueIterator *iter,
+ GError **error,
+ GValue *first_val,
+ ...);
+
+void dbus_g_value_iterator_recurse (DBusGValueIterator *iter,
+ DBusGValueIterator *sub);
+
+void dbus_g_value_free (DBusGValue *value);
+
+
+void dbus_g_object_register_marshaller (GType rettype,
+ guint n_types,
+ const GType *param_types,
+ GClosureMarshal marshaller);
typedef struct DBusGProxy DBusGProxy;
typedef struct DBusGProxyClass DBusGProxyClass;
@@ -143,12 +218,20 @@ DBusGProxy* dbus_g_proxy_new_for_name_owner (DBusGConnection *connect
const char *path,
const char *interface,
GError **error);
+DBusGProxy* dbus_g_proxy_new_from_proxy (DBusGProxy *proxy,
+ const char *interface,
+ const char *path_name);
DBusGProxy* dbus_g_proxy_new_for_peer (DBusGConnection *connection,
const char *path_name,
const char *interface_name);
+
+void dbus_g_proxy_set_interface (DBusGProxy *proxy,
+ const char *interface_name);
void dbus_g_proxy_add_signal (DBusGProxy *proxy,
- const char *signal_name,
- const char *signature);
+ const char *signal_name,
+ GType first_type,
+ ...);
+
void dbus_g_proxy_connect_signal (DBusGProxy *proxy,
const char *signal_name,
GCallback handler,
@@ -160,27 +243,46 @@ void dbus_g_proxy_disconnect_signal (DBusGProxy *proxy,
void *data);
DBusGPendingCall* dbus_g_proxy_begin_call (DBusGProxy *proxy,
const char *method,
- int first_arg_type,
+ GType first_arg_type,
...);
gboolean dbus_g_proxy_end_call (DBusGProxy *proxy,
DBusGPendingCall *pending,
GError **error,
- int first_arg_type,
+ GType first_arg_type,
...);
void dbus_g_proxy_call_no_reply (DBusGProxy *proxy,
const char *method,
- int first_arg_type,
+ GType first_arg_type,
...);
+const char* dbus_g_proxy_get_path (DBusGProxy *proxy);
+
const char* dbus_g_proxy_get_bus_name (DBusGProxy *proxy);
+const char* dbus_g_proxy_get_interface (DBusGProxy *proxy);
+
gboolean dbus_g_proxy_invoke (DBusGProxy *proxy,
const char *method,
- const char *insig,
- const char *outsig,
GError **error,
+ GType first_arg_type,
...);
+typedef struct {
+ DBusGProxy *proxy;
+ gpointer cb;
+ gpointer userdata;
+} DBusGAsyncData;
+
+typedef struct {
+ DBusGConnection *connection;
+ DBusGMessage *message;
+ const DBusGObjectInfo *object;
+ const DBusGMethodInfo *method;
+} DBusGMethodInvocation;
+
+void dbus_g_method_return (DBusGMethodInvocation *context, ...);
+void dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error);
+
#undef DBUS_INSIDE_DBUS_GLIB_H
G_END_DECLS
diff --git a/doc/TODO b/doc/TODO
index 28a772d5..659dde15 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -39,12 +39,11 @@ Important for 1.0
Important for 1.0 GLib Bindings
===
- - finish dbus-glib-tool support for adding introspection
- data to GObject and autoexporting GObject using same
+ - Annotations for "do not take ownership of this return value" on server
- - Need to make sure that dbus-glib.h never returns any
- dbus_malloc() memory, only g_malloc().
- dbus_g_proxy_end_call() is the major offender.
+ - Fix signals
+
+ - Fix errors - need to get specific error back, not UnmappedError crap
- DBusGProxy doesn't emit "destroy" when it should
diff --git a/doc/dbus-tutorial.xml b/doc/dbus-tutorial.xml
index 22906ac9..6ee32927 100644
--- a/doc/dbus-tutorial.xml
+++ b/doc/dbus-tutorial.xml
@@ -449,20 +449,294 @@
<title>GLib API: Using Remote Objects</title>
<para>
-
The GLib binding is defined in the header file
- &lt;dbus/dbus-glib.h&gt;. The API is very small, in sharp contrast to the
- low-level &lt;dbus/dbus.h&gt;.
-
+ &lt;dbus/dbus-glib.h&gt;.
</para>
- <para>
- The GLib bindings are incomplete, see the TODO file and comments in the
- source code.
- </para>
-
- <para>
-Here is a D-BUS program using the GLib bindings.
+ <sect2 id="glib-typemappings">
+ <title>D-BUS - GLib type mappings</title>
+ <para>
+ The heart of the GLib bindings for D-BUS is the mapping it
+ provides between D-BUS "type signatures" and GLib types
+ (<literal>GType</literal>). The D-BUS type system is composed of
+ a number of "basic" types, along with several "container" types.
+ </para>
+ <sect3 id="glib-basic-typemappings">
+ <title>Basic type mappings</title>
+ <para>
+ Below is a list of the basic types, along with their associated
+ mapping to a <literal>GType</literal>.
+ <informaltable>
+ <tgroup cols="4">
+ <thead>
+ <row>
+ <entry>D-BUS basic type</entry>
+ <entry>GType</entry>
+ <entry>Free function</entry>
+ <entry>Notes</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>BYTE</literal></entry>
+ <entry><literal>G_TYPE_UCHAR</literal></entry>
+ <entry></entry>
+ <entry></entry>
+ </row><row>
+ <entry><literal>BOOLEAN</literal></entry>
+ <entry><literal>G_TYPE_BOOLEAN</literal></entry>
+ <entry></entry>
+ <entry></entry>
+ </row><row>
+ <entry><literal>INT16</literal></entry>
+ <entry><literal>G_TYPE_INT</literal></entry>
+ <entry></entry>
+ <entry>Will be changed to a G_TYPE_INT16 once GLib has it</entry>
+ </row><row>
+ <entry><literal>UINT16</literal></entry>
+ <entry><literal>G_TYPE_UINT</literal></entry>
+ <entry></entry>
+ <entry>Will be changed to a G_TYPE_UINT16 once GLib has it</entry>
+ </row><row>
+ <entry><literal>INT32</literal></entry>
+ <entry><literal>G_TYPE_INT</literal></entry>
+ <entry></entry>
+ <entry>Will be changed to a G_TYPE_INT32 once GLib has it</entry>
+ </row><row>
+ <entry><literal>UINT32</literal></entry>
+ <entry><literal>G_TYPE_UINT</literal></entry>
+ <entry></entry>
+ <entry>Will be changed to a G_TYPE_UINT32 once GLib has it</entry>
+ </row><row>
+ <entry><literal>INT64</literal></entry>
+ <entry><literal>G_TYPE_GINT64</literal></entry>
+ <entry></entry>
+ <entry></entry>
+ </row><row>
+ <entry><literal>UINT64</literal></entry>
+ <entry><literal>G_TYPE_GUINT64</literal></entry>
+ <entry></entry>
+ <entry></entry>
+ </row><row>
+ <entry><literal>DOUBLE</literal></entry>
+ <entry><literal>G_TYPE_DOUBLE</literal></entry>
+ <entry></entry>
+ <entry></entry>
+ </row><row>
+ <entry><literal>STRING</literal></entry>
+ <entry><literal>G_TYPE_STRING</literal></entry>
+ <entry>g_free</entry>
+ <entry></entry>
+ </row><row>
+ <entry><literal>OBJECT_PATH</literal></entry>
+ <entry><literal>DBUS_TYPE_G_PROXY</literal></entry>
+ <entry>g_object_unref</entry>
+ <entry>The returned proxy does not have an interface set; use <literal>dbus_g_proxy_set_interface</literal> to invoke methods</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ As you can see, the basic mapping is fairly straightforward.
+ </para>
+ </sect3>
+ <sect3 id="glib-container-typemappings">
+ <title>Container type mappings</title>
+ <para>
+ The D-BUS type system also has a number of "container"
+ types, such as <literal>DBUS_TYPE_ARRAY</literal> and
+ <literal>DBUS_TYPE_STRUCT</literal>. The D-BUS type system
+ is fully recursive, so one can for example have an array of
+ array of strings (i.e. type signature
+ <literal>aas</literal>).
+ </para>
+ <para>
+ However, not all of these types are in common use; for
+ example, at the time of this writing the author knows of no
+ one using <literal>DBUS_TYPE_STRUCT</literal>, or a
+ <literal>DBUS_TYPE_ARRAY</literal> containing any non-basic
+ type. The approach the GLib bindings take is pragmatic; try
+ to map the most common types in the most obvious way, and
+ let using less common and more complex types be less
+ "natural".
+ </para>
+ <para>
+ First, D-BUS type signatures which have an "obvious"
+ corresponding builtin GLib type are mapped using that type:
+ <informaltable>
+ <tgroup cols="6">
+ <thead>
+ <row>
+ <entry>D-BUS type signature</entry>
+ <entry>Description</entry>
+ <entry>GType</entry>
+ <entry>C typedef</entry>
+ <entry>Free function</entry>
+ <entry>Notes</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>as</literal></entry>
+ <entry>Array of strings</entry>
+ <entry><literal>G_TYPE_STRV</literal></entry>
+ <entry><literal>char **</literal></entry>
+ <entry>g_strfreev</entry>
+ <entry></entry>
+ </row><row>
+ <entry><literal>v</literal></entry>
+ <entry>Generic value container</entry>
+ <entry><literal>G_TYPE_VALUE</literal></entry>
+ <entry><literal>GValue *</literal></entry>
+ <entry>g_value_unset</entry>
+ <entry>The calling conventions for values expect that method callers have allocated return values; see below.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ <para>
+ The next most common recursive type signatures are arrays of
+ basic values. The most obvious mapping for arrays of basic
+ types is a <literal>GArray</literal>. Now, GLib does not
+ provide a builtin <literal>GType</literal> for
+ <literal>GArray</literal>. However, we actually need more than
+ that - we need a "parameterized" type which includes the
+ contained type. Why we need this we will see below.
+ </para>
+ <para>
+ The approach taken is to create these types in the D-BUS GLib
+ bindings; however, there is nothing D-BUS specific about them.
+ In the future, we hope to include such "fundamental" types in GLib
+ itself.
+ <informaltable>
+ <tgroup cols="6">
+ <thead>
+ <row>
+ <entry>D-BUS type signature</entry>
+ <entry>Description</entry>
+ <entry>GType</entry>
+ <entry>C typedef</entry>
+ <entry>Free function</entry>
+ <entry>Notes</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>ay</literal></entry>
+ <entry>Array of bytes</entry>
+ <entry><literal>DBUS_TYPE_G_BYTE_ARRAY</literal></entry>
+ <entry><literal>GArray *</literal></entry>
+ <entry>g_array_free</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry><literal>au</literal></entry>
+ <entry>Array of uint</entry>
+ <entry><literal>DBUS_TYPE_G_UINT_ARRAY</literal></entry>
+ <entry><literal>GArray *</literal></entry>
+ <entry>g_array_free</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry><literal>ai</literal></entry>
+ <entry>Array of int</entry>
+ <entry><literal>DBUS_TYPE_G_INT_ARRAY</literal></entry>
+ <entry><literal>GArray *</literal></entry>
+ <entry>g_array_free</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry><literal>ax</literal></entry>
+ <entry>Array of int64</entry>
+ <entry><literal>DBUS_TYPE_G_INT64_ARRAY</literal></entry>
+ <entry><literal>GArray *</literal></entry>
+ <entry>g_array_free</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry><literal>at</literal></entry>
+ <entry>Array of uint64</entry>
+ <entry><literal>DBUS_TYPE_G_UINT64_ARRAY</literal></entry>
+ <entry><literal>GArray *</literal></entry>
+ <entry>g_array_free</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry><literal>ad</literal></entry>
+ <entry>Array of double</entry>
+ <entry><literal>DBUS_TYPE_G_DOUBLE_ARRAY</literal></entry>
+ <entry><literal>GArray *</literal></entry>
+ <entry>g_array_free</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry><literal>ab</literal></entry>
+ <entry>Array of boolean</entry>
+ <entry><literal>DBUS_TYPE_G_BOOLEAN_ARRAY</literal></entry>
+ <entry><literal>GArray *</literal></entry>
+ <entry>g_array_free</entry>
+ <entry></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ <para>
+ D-BUS also includes a special type DBUS_TYPE_DICT_ENTRY which
+ is only valid in arrays. It's intended to be mapped to a "dictionary"
+ type by bindings. The obvious GLib mapping here is GHashTable. Again,
+ however, there is no builtin <literal>GType</literal> for a GHashTable.
+ Moreover, just like for arrays, we need a parameterized type so that
+ the bindings can communiate which types are contained in the hash table.
+ </para>
+ <para>
+ At present, only strings are supported. Work is in progress to
+ include more types.
+ <informaltable>
+ <tgroup cols="6">
+ <thead>
+ <row>
+ <entry>D-BUS type signature</entry>
+ <entry>Description</entry>
+ <entry>GType</entry>
+ <entry>C typedef</entry>
+ <entry>Free function</entry>
+ <entry>Notes</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>a{ss}</literal></entry>
+ <entry>Dictionary mapping strings to strings</entry>
+ <entry><literal>DBUS_TYPE_G_STRING_STRING_HASHTABLE</literal></entry>
+ <entry><literal>GHashTable *</literal></entry>
+ <entry>g_hash_table_destroy</entry>
+ <entry></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </sect3>
+ <sect3 id="glib-generic-typemappings">
+ <title>Arbitrarily recursive type mappings</title>
+ <para>
+ Finally, it is possible users will want to write or invoke D-BUS
+ methods which have arbitrarily complex type signatures not
+ directly supported by these bindings. For this case, we have a
+ <literal>DBusGValue</literal> which acts as a kind of special
+ variant value which may be iterated over manually. The
+ <literal>GType</literal> associated is
+ <literal>DBUS_TYPE_G_VALUE</literal>.
+ </para>
+ <para>
+ TODO insert usage of <literal>DBUS_TYPE_G_VALUE</literal> here.
+ </para>
+ </sect3>
+ </sect2>
+ <sect2 id="sample-program-1">
+ <title>A sample program</title>
+ <para>Here is a D-BUS program using the GLib bindings.
<programlisting>
int
main (int argc, char **argv)
@@ -470,10 +744,8 @@ main (int argc, char **argv)
DBusGConnection *connection;
GError *error;
DBusGProxy *proxy;
- DBusGPendingCall *call;
char **name_list;
- int name_list_len;
- int i;
+ char **name_list_ptr;
g_type_init ();
@@ -495,15 +767,10 @@ main (int argc, char **argv)
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS);
- /* Call ListNames method */
-
- call = dbus_g_proxy_begin_call (proxy, "ListNames", DBUS_TYPE_INVALID);
-
+ /* Call ListNames method, wait for reply */
error = NULL;
- if (!dbus_g_proxy_end_call (proxy, call, &amp;error,
- DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
- &amp;name_list, &amp;name_list_len,
- DBUS_TYPE_INVALID))
+ if (!dbus_g_proxy_invoke (proxy, "ListNames", &amp;error, G_TYPE_INVALID,
+ G_TYPE_STRV, &amp;name_list, G_TYPE_INVALID))
{
g_printerr ("Failed to complete ListNames call: %s\n",
error-&gt;message);
@@ -514,77 +781,348 @@ main (int argc, char **argv)
/* Print the results */
g_print ("Names on the message bus:\n");
- i = 0;
- while (i &lt; name_list_len)
+
+ for (name_list_ptr = name_list; *name_list_ptr; name_list_ptr++)
{
- g_assert (name_list[i] != NULL);
- g_print (" %s\n", name_list[i]);
- ++i;
+ g_print (" %s\n", *name_list_ptr);
}
- g_assert (name_list[i] == NULL);
-
g_strfreev (name_list);
+ g_object_unref (proxy);
+
return 0;
}
</programlisting>
</para>
+ </sect2>
+ <sect2 id="glib-program-setup">
+ <title>Program initalization</title>
+ <para>
+ A connection to the bus is acquired using
+ <literal>dbus_g_bus_get</literal>. Next, a proxy
+ is created for the object "/org/freedesktop/DBus" with
+ interface <literal>org.freedesktop.DBus</literal>
+ on the service <literal>org.freedesktop.DBus</literal>.
+ This is a proxy for the message bus itself.
+ </para>
+ </sect2>
+ <sect2 id="glib-method-invocation">
+ <title>Understanding method invocation</title>
+ <para>
+ You have a number of choices for method invocation. First, as
+ used above, <literal>dbus_g_proxy_invoke</literal> sends a
+ method call to the remote object, and blocks until reply is
+ recieved. The outgoing arguments are specified in the varargs
+ array, terminated with <literal>G_TYPE_INVALID</literal>.
+ Next, pointers to return values are specified, followed again
+ by <literal>G_TYPE_INVALID</literal>.
+ </para>
+ <para>
+ To invoke a method asynchronously, use
+ <literal>dbus_g_proxy_begin_call</literal>. This returns a
+ <literal>DBusGPendingCall</literal> object; you may then set a
+ notification function using
+ <literal>dbus_g_pending_call_set_notify</literal>.
+ </para>
+ </sect2>
+ <sect2 id="glib-signal-connection">
+ <title>Connecting to object signals</title>
+ <para>
+ You may connect to signals using
+ <literal>dbus_g_proxy_add_signal</literal> and
+ <literal>dbus_g_proxy_connect_signal</literal>. At the
+ moment, <literal>dbus_g_proxy_add_signal</literal> requires
+ the D-BUS types of the remote object; this will likely be
+ changed later.
+ </para>
+ </sect2>
+ <sect2 id="glib-more-examples">
+ <title>More examples of method invocation</title>
+ <sect3 id="glib-sending-stuff">
+ <title>Sending an integer and string, receiving an array of bytes</title>
+ <para>
+<programlisting>
+ GArray *arr;
+
+ error = NULL;
+ if (!dbus_g_proxy_invoke (proxy, "Foobar", &amp;error,
+ G_TYPE_INT, 42, G_TYPE_STRING, "hello",
+ G_TYPE_INVALID,
+ DBUS_TYPE_G_UCHAR_ARRAY, &amp;arr, G_TYPE_INVALID))
+ {
+ g_printerr ("Failed to complete Foobar: %s\n",
+ error-&gt;message);
+ g_error_free (error);
+ exit (1);
+ }
+ g_assert (arr != NULL);
+ printf ("got back %u values", arr->len);
+</programlisting>
+ </para>
+ </sect3>
+ <sect3 id="glib-sending-hash">
+ <title>Sending a GHashTable</title>
+ <para>
+<programlisting>
+ GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
+ guint32 ret;
+
+ g_hash_table_insert (hash, "foo", "bar");
+ g_hash_table_insert (hash, "baz", "whee");
- <para>
-
- DBusGProxy represents a remote object. dbus_g_proxy_begin_call() sends
- a method call to the remote object, and dbus_g_proxy_end_call() retrieves
- any return values or exceptions resulting from the method call.
- There are also DBusGProxy functions to connect and disconnect signals,
- not shown in the code example.
-
- </para>
-
- <para>
-
- dbus_g_bus_get() assumes that the application will use GMainLoop. The
- created connection will be associated with the main loop such that
- messages will be sent and received when the main loop runs. However, in
- the above code example the main loop never runs; D-BUS will not run the
- loop implicitly. Instead, dbus_g_proxy_end_call() will block until the
- method call has been sent and the reply received. A more complex GUI
- application might run the main loop while waiting for the method call
- reply. (DBusGPendingCall is currently missing the "notify me when the
- call is complete" functionality found in DBusPendingCall, but it should be
- added.)
+ error = NULL;
+ if (!dbus_g_proxy_invoke (proxy, "HashSize", &amp;error,
+ DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID,
+ G_TYPE_UINT, &amp;ret, G_TYPE_INVALID))
+ {
+ g_printerr ("Failed to complete HashSize: %s\n",
+ error-&gt;message);
+ g_error_free (error);
+ exit (1);
+ }
+ g_assert (ret == 2);
+ g_hash_table_destroy (hash);
+</programlisting>
+ </para>
+ </sect3>
+ <sect3 id="glib-receiving-bool-int">
+ <title>Receiving a boolean and a string</title>
+ <para>
+<programlisting>
+ gboolean boolret;
+ char *strret;
+
+ error = NULL;
+ if (!dbus_g_proxy_invoke (proxy, "GetStuff", &amp;error,
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &amp;boolret,
+ G_TYPE_STRING, &amp;strret,
+ G_TYPE_INVALID))
+ {
+ g_printerr ("Failed to complete GetStuff: %s\n",
+ error-&gt;message);
+ g_error_free (error);
+ exit (1);
+ }
+ printf ("%s %s", boolret ? "TRUE" : "FALSE", strret);
+ g_free (strret);
+</programlisting>
+ </para>
+ </sect3>
+ <sect3 id="glib-sending-str-arrays">
+ <title>Sending two arrays of strings</title>
+ <para>
+<programlisting>
+ /* NULL terminate */
+ char *strs_static[] = {"foo", "bar", "baz", NULL};
+ /* Take pointer to array; cannot pass array directly */
+ char **strs_static_p = strs_static;
+ char **strs_dynamic;
- </para>
+ strs_dynamic = g_new (char *, 4);
+ strs_dynamic[0] = g_strdup ("hello");
+ strs_dynamic[1] = g_strdup ("world");
+ strs_dynamic[2] = g_strdup ("!");
+ /* NULL terminate */
+ strs_dynamic[3] = NULL;
+
+ error = NULL;
+ if (!dbus_g_proxy_invoke (proxy, "TwoStrArrays", &amp;error,
+ G_TYPE_STRV, strs_static_p,
+ G_TYPE_STRV, strs_dynamic,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID))
+ {
+ g_printerr ("Failed to complete TwoStrArrays: %s\n",
+ error-&gt;message);
+ g_error_free (error);
+ exit (1);
+ }
+ g_strfreev (strs_dynamic);
+</programlisting>
+ </para>
+ </sect3>
+ <sect3 id="glib-getting-str-array">
+ <title>Sending a boolean, receiving an array of strings</title>
+ <para>
+<programlisting>
+ char **strs;
+ char **strs_p;
+ gboolean blah;
- <para>
-
- Future plans (see doc/TODO) are to use G_TYPE_STRING in place of
- DBUS_TYPE_STRING and so forth. In fact the above code is slightly
- incorrect at the moment, since it uses g_strfreev() to free a string array
- that was not allocated with g_malloc(). dbus_free_string_array() should
- really be used. However, once the GLib bindings are complete the returned
- data from dbus_g_proxy_end_call() will be allocated with g_malloc().
+ error = NULL;
+ blah = TRUE;
+ if (!dbus_g_proxy_invoke (proxy, "GetStrs", &amp;error,
+ G_TYPE_BOOLEAN, blah,
+ G_TYPE_INVALID,
+ G_TYPE_STRV, &amp;strs,
+ G_TYPE_INVALID))
+ {
+ g_printerr ("Failed to complete GetStrs: %s\n",
+ error-&gt;message);
+ g_error_free (error);
+ exit (1);
+ }
+ for (strs_p = strs; *strs_p; strs_p++)
+ printf ("got string: \"%s\"", *strs_p);
+ g_strfreev (strs);
+</programlisting>
+ </para>
+ </sect3>
+ <sect3 id="glib-sending-variant">
+ <title>Sending a variant</title>
+ <para>
+<programlisting>
+ GValue val = {0, };
- </para>
+ g_value_init (&amp;val, G_TYPE_STRING);
+ g_value_set_string (&amp;val, "hello world");
+
+ error = NULL;
+ if (!dbus_g_proxy_invoke (proxy, "SendVariant", &amp;error,
+ G_TYPE_VALUE, &amp;val, G_TYPE_INVALID,
+ G_TYPE_INVALID))
+ {
+ g_printerr ("Failed to complete SendVariant: %s\n",
+ error-&gt;message);
+ g_error_free (error);
+ exit (1);
+ }
+ g_assert (ret == 2);
+ g_value_unset (&amp;val);
+</programlisting>
+ </para>
+ </sect3>
+ <sect3 id="glib-receiving-variant">
+ <title>Receiving a variant</title>
+ <para>
+<programlisting>
+ GValue val = {0, };
+ error = NULL;
+ if (!dbus_g_proxy_invoke (proxy, "GetVariant", &amp;error, G_TYPE_INVALID,
+ G_TYPE_VALUE, &amp;val, G_TYPE_INVALID))
+ {
+ g_printerr ("Failed to complete GetVariant: %s\n",
+ error-&gt;message);
+ g_error_free (error);
+ exit (1);
+ }
+ if (G_VALUE_TYPE (&amp;val) == G_TYPE_STRING)
+ printf ("%s\n", g_value_get_string (&amp;val));
+ else if (G_VALUE_TYPE (&amp;val) == G_TYPE_INT)
+ printf ("%d\n", g_value_get_int (&amp;val));
+ else
+ ...
+ g_value_unset (&amp;val);
+</programlisting>
+ </para>
+ </sect3>
+ </sect2>
</sect1>
<sect1 id="glib-server">
<title>GLib API: Implementing Objects</title>
-
<para>
-
- The GLib binding is defined in the header file
- &lt;dbus/dbus-glib.h&gt;. To implement an object, it's also necessary
- to use the dbus-glib-tool command line tool.
-
+ At the moment, to expose a GObject via D-BUS, you must
+ write XML by hand which describes the methods exported
+ by the object. In the future, this manual step will
+ be obviated by the upcoming GLib introspection support.
</para>
+ <para>
+ Here is a sample XML file which describes an object that exposes
+ one method, named <literal>ManyArgs</literal>.
+<programlisting>
+&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
+
+&lt;node name="/com/example/MyObject"&gt;
+ &lt;interface name="com.example.MyObject"&gt;
+ &lt;annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/&gt;
+ &lt;method name="ManyArgs"&gt;
+ &lt;!-- This is optional, and in this case is redunundant --&gt;
+ &lt;annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/&gt;
+ &lt;arg type="u" name="x" direction="in" /&gt;
+ &lt;arg type="s" name="str" direction="in" /&gt;
+ &lt;arg type="d" name="trouble" direction="in" /&gt;
+ &lt;arg type="d" name="d_ret" direction="out" /&gt;
+ &lt;arg type="s" name="str_ret" direction="out" /&gt;
+ &lt;/method&gt;
+ &lt;/interface&gt;
+&lt;/node&gt;
+</programlisting>
+ </para>
<para>
- The GLib bindings are incomplete. Implementing an object is not yet
- possible, see the TODO file and comments in the source code for details
- on what work needs doing.
+ This XML is in the same format as the D-BUS introspection XML
+ format. Except we must include an "annotation" which give the C
+ symbols corresponding to the object implementation prefix
+ (<literal>my_object</literal>). In addition, if particular
+ methods symbol names deviate from C convention
+ (i.e. <literal>ManyArgs</literal> -&gt;
+ <literal>many_args</literal>), you may specify an annotation
+ giving the C symbol.
+ </para>
+ <para>
+ Once you have written this XML, run <literal>dbus-binding-tool --mode=glib-server <replaceable>FILENAME</replaceable> &gt; <replaceable>HEADER_NAME</replaceable>.</literal> to
+ generate a header file. For example: <command>dbus-binding-tool --mode=glib-server my-objet.xml &gt; my-object-glue.h</command>.
+ </para>
+ <para>
+ Next, include the generated header in your program, and invoke
+ <literal>dbus_g_object_class_install_info</literal>, passing the
+ object class and "object info" included in the header. For
+ example:
+ <programlisting>
+ dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &amp;com_foo_my_object_info);
+ </programlisting>
+ This should be done exactly once per object class.
+ </para>
+ <para>
+ To actually implement the method, just define a C function named e.g.
+ <literal>my_object_many_args</literal> in the same file as the info
+ header is included. At the moment, it is required that this function
+ conform to the following rules:
+ <itemizedlist>
+ <listitem>
+ <para>
+ The function must return a value of type <literal>gboolean</literal>;
+ <literal>TRUE</literal> on success, and <literal>FALSE</literal>
+ otherwise.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The first parameter is a pointer to an instance of the object.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Following the object instance pointer are the method
+ input values.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Following the input values are pointers to return values.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The final parameter must be a <literal>GError **</literal>.
+ If the function returns <literal>FALSE</literal> for an
+ error, the error parameter must be initalized with
+ <literal>g_set_error</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Finally, you can export an object using <literal>dbus_g_connection_register_g_object</literal>. For example:
+ <programlisting>
+ dbus_g_connection_register_g_object (connection,
+ "/com/foo/MyObject",
+ obj);
+ </programlisting>
</para>
-
</sect1>
<sect1 id="qt-client">
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 6d81e7d1..b9b9a70f 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -15,8 +15,12 @@ libdbus_glib_1_la_SOURCES = \
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
diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c
index 3c86d81f..76536aad 100644
--- a/glib/dbus-binding-tool-glib.c
+++ b/glib/dbus-binding-tool-glib.c
@@ -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 @@ typedef struct
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 @@ compute_marshaller (MethodInfo *method, GError **error)
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 @@ compute_marshaller (MethodInfo *method, GError **error)
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 @@ compute_marshaller (MethodInfo *method, GError **error)
}
}
+ 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 @@ compute_marshaller (MethodInfo *method, GError **error)
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 @@ compute_marshaller_name (MethodInfo *method, const char *prefix, GError **error)
{
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 @@ compute_marshaller_name (MethodInfo *method, const char *prefix, GError **error)
g_string_append (ret, "_POINTER");
}
}
-
/* Final GError parameter */
g_string_append (ret, "_POINTER");
+ }
return g_string_free (ret, FALSE);
}
@@ -210,7 +284,8 @@ gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
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 @@ gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
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 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
{
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 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
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 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
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 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
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 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
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 @@ dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, const
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 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
{
ArgInfo *arg;
const char *type_str;
+ const char *type_suffix;
+ GType gtype;
int direction;
arg = args->data;
@@ -615,9 +713,8 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
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 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
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 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
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 @@ write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *
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 @@ check_supported_parameters (MethodInfo *method)
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 @@ generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error
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 @@ dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gbool
DBusBindingToolCData data;
gboolean ret;
+ dbus_g_value_types_init ();
+
memset (&data, 0, sizeof (data));
data.channel = channel;
diff --git a/glib/dbus-binding-tool-glib.h b/glib/dbus-binding-tool-glib.h
index 9988df29..257b5347 100644
--- a/glib/dbus-binding-tool-glib.h
+++ b/glib/dbus-binding-tool-glib.h
@@ -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);
diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c
index 046c493c..08f8aef4 100644
--- a/glib/dbus-gmain.c
+++ b/glib/dbus-gmain.c
@@ -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 @@ dbus_g_bus_get (DBusBusType type,
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 @@ dbus_g_bus_get (DBusBusType type,
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;
}
diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c
index 09fc97fc..e2645f41 100644
--- a/glib/dbus-gobject.c
+++ b/glib/dbus-gobject.c
@@ -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 @@ static const char *
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 @@ method_output_signature_from_object_info (const DBusGObjectInfo *object,
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 @@ introspect_properties (GObject *object, GString *xml)
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 @@ introspect_signals (GType type, GString *xml)
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 @@ introspect_signals (GType type, GString *xml)
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 @@ introspect_interfaces (GObject *object, GString *xml)
{
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 @@ introspect_interfaces (GObject *object, GString *xml)
}
}
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_unlock (&globals_lock);
}
static DBusHandlerResult
@@ -560,15 +531,15 @@ set_object_property (DBusConnection *connection,
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 @@ lookup_object_and_method (GObject *object,
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 @@ lookup_object_and_method (GObject *object,
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 @@ lookup_object_and_method (GObject *object,
}
}
out:
- g_static_rw_lock_reader_lock (&info_hash_lock);
+ g_static_rw_lock_reader_unlock (&globals_lock);
return ret;
}
@@ -759,74 +731,147 @@ invoke_object_method (GObject *object,
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);
-
- g_return_val_if_fail (value_array != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+ {
+ GArray *types_array;
+ guint n_params;
+ const GType *types;
+ DBusGValueMarshalCtx context;
+
+ 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;
+ GTypeCValue storage;
- memset (&basic, 0, sizeof (basic));
-
- /* FIXME - broken for container types */
-
- 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 @@ invoke_object_method (GObject *object,
/* 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 @@ invoke_object_method (GObject *object,
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 @@ invoke_object_method (GObject *object,
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 @@ static DBusObjectPathVTable gobject_dbus_vtable = {
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 @@ static DBusObjectPathVTable gobject_dbus_vtable = {
*/
/**
- * 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 @@ static DBusObjectPathVTable gobject_dbus_vtable = {
* 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 @@ dbus_g_object_class_install_info (GObjectClass *object_class,
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 @@ dbus_g_connection_register_g_object (DBusGConnection *connection,
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>
diff --git a/glib/dbus-gobject.h b/glib/dbus-gobject.h
index 6c78546a..fcc38cda 100644
--- a/glib/dbus-gobject.h
+++ b/glib/dbus-gobject.h
@@ -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
diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c
index b5e977a4..42bfca8e 100644
--- a/glib/dbus-gproxy.c
+++ b/glib/dbus-gproxy.c
@@ -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 @@ dbus_g_proxy_class_init (DBusGProxyClass *klass)
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 @@ create_signal_name (const char *interface,
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 @@ marshal_dbus_message_to_g_marshaller (GClosure *closure,
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 (&param_values[0]);
message = g_value_get_boxed (&param_values[1]);
- signature = g_value_get_string (&param_values[2]);
+ gsignature = g_value_get_pointer (&param_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 @@ dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
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 @@ dbus_g_proxy_new_for_name_owner (DBusGConnection *connection,
}
/**
+ * 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 @@ dbus_g_proxy_get_bus_name (DBusGProxy *proxy)
}
/**
- * 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.
+ * Sets the object interface proxy is bound to
*
- * 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.
- *
- * @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).
+ * Gets the path this proxy is bound to
*
- * 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.
- *
- * @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 @@ dbus_g_proxy_invoke (DBusGProxy *proxy,
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;
+ GValue *gvalue;
- 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 = g_value_array_get_nth (args, i);
- if (collect_err)
- {
- g_set_error (error, DBUS_GERROR,
- DBUS_GERROR_INVALID_ARGS,
- collect_err);
- goto out;
- }
-
- /* 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 @@ dbus_g_proxy_invoke (DBusGProxy *proxy,
{
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 @@ dbus_g_proxy_invoke (DBusGProxy *proxy,
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 @@ dbus_g_proxy_invoke (DBusGProxy *proxy,
*/
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 @@ dbus_g_proxy_send (DBusGProxy *proxy,
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);
}
diff --git a/glib/dbus-gtype-specialized.c b/glib/dbus-gtype-specialized.c
new file mode 100644
index 00000000..b331fcc5
--- /dev/null
+++ b/glib/dbus-gtype-specialized.c
@@ -0,0 +1,441 @@
+/* -*- 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);
+}
diff --git a/glib/dbus-gtype-specialized.h b/glib/dbus-gtype-specialized.h
new file mode 100644
index 00000000..5157f33f
--- /dev/null
+++ b/glib/dbus-gtype-specialized.h
@@ -0,0 +1,104 @@
+/* -*- 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
diff --git a/glib/dbus-gvalue-utils.c b/glib/dbus-gvalue-utils.c
new file mode 100644
index 00000000..9eea4bf0
--- /dev/null
+++ b/glib/dbus-gvalue-utils.c
@@ -0,0 +1,715 @@
+/* -*- 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);
+}
diff --git a/glib/dbus-gvalue-utils.h b/glib/dbus-gvalue-utils.h
new file mode 100644
index 00000000..781569ff
--- /dev/null
+++ b/glib/dbus-gvalue-utils.h
@@ -0,0 +1,70 @@
+/* -*- 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
diff --git a/glib/dbus-gvalue.c b/glib/dbus-gvalue.c
index eae5a458..8506330d 100644
--- a/glib/dbus-gvalue.c
+++ b/glib/dbus-gvalue.c
@@ -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);
+}
+
+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;
}
-/* FIXME - broken for containers
+/**
+ * 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;
+}
+
+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;
- return dbus_signature_iter_get_current_type (&iter);
+ 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)
+{
+ if (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL)
+ {
+ dbus_message_unref (value->value.toplevel.message);
+ g_free (value->value.toplevel.signature);
+ }
+}
+
+static GType
+signature_iter_to_g_type_dict (const DBusSignatureIter *subiter, gboolean is_client)
{
- int type;
+ DBusSignatureIter iter;
+ GType key_gtype;
+ GType value_gtype;
- type = base_type_from_signature (signature);
+ g_assert (dbus_signature_iter_get_current_type (subiter) == DBUS_TYPE_DICT_ENTRY);
- switch (type)
+ 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 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
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_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_marshal (DBusMessageIter *iter, GValue *value)
+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 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
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 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
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 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
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);
}
diff --git a/glib/dbus-gvalue.h b/glib/dbus-gvalue.h
index 4caa6880..54ef780b 100644
--- a/glib/dbus-gvalue.h
+++ b/glib/dbus-gvalue.h
@@ -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
diff --git a/python/Makefile.am b/python/Makefile.am
index 23e9cea4..b5ee4243 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -1,6 +1,6 @@
SUBDIRS=examples
-INCLUDES=-I$(top_builddir) -I$(top_builddir)/dbus $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) $(PYTHON_INCLUDES)
+INCLUDES=-I$(top_builddir) -I$(top_builddir)/dbus $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) $(PYTHON_INCLUDES) -DDBUS_COMPILATION=1
dbusdir = $(pythondir)/dbus
dbus_PYTHON = __init__.py _dbus.py decorators.py exceptions.py services.py proxies.py _util.py types.py matchrules.py
diff --git a/test/glib/Makefile.am b/test/glib/Makefile.am
index b0b8361a..fffad087 100644
--- a/test/glib/Makefile.am
+++ b/test/glib/Makefile.am
@@ -1,4 +1,4 @@
-INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS)
+INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) -DDBUS_COMPILATION
## note that TESTS has special meaning (stuff to use in make check)
## so if adding tests not to be run in make check, don't add them to
@@ -45,10 +45,10 @@ test_service_glib_SOURCES= \
BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h
test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool
- $(top_builddir)/glib/dbus-binding-tool --mode=glib-server --output=test-service-glib-glue.h test-service-glib.xml
+ $(top_builddir)/glib/dbus-binding-tool --prefix=my_object --mode=glib-server --output=test-service-glib-glue.h test-service-glib.xml
test-service-glib-bindings.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool
- $(top_builddir)/glib/dbus-binding-tool --mode=glib-client --output=test-service-glib-bindings.h test-service-glib.xml
+ $(top_builddir)/glib/dbus-binding-tool --prefix=my_object --mode=glib-client --output=test-service-glib-bindings.h test-service-glib.xml
CLEANFILES = test-service-glib-glue.h test-service-glib-bindings.h
diff --git a/test/glib/test-dbus-glib.c b/test/glib/test-dbus-glib.c
index b0dc9efc..2fc8665b 100644
--- a/test/glib/test-dbus-glib.c
+++ b/test/glib/test-dbus-glib.c
@@ -6,9 +6,11 @@
#include "test-service-glib-bindings.h"
#include <glib/dbus-gidl.h>
#include <glib/dbus-gparser.h>
+#include <glib-object.h>
static GMainLoop *loop = NULL;
static int n_times_foo_received = 0;
+static int n_times_frobnicate_received = 0;
static gboolean
timed_exit (gpointer loop)
@@ -27,6 +29,18 @@ foo_signal_handler (DBusGProxy *proxy,
g_main_loop_quit (loop);
}
+static void
+frobnicate_signal_handler (DBusGProxy *proxy,
+ int val,
+ void *user_data)
+{
+ n_times_frobnicate_received += 1;
+
+ g_assert (val == 42);
+
+ g_main_loop_quit (loop);
+}
+
static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2);
static void lose_gerror (const char *prefix, GError *error) G_GNUC_NORETURN;
@@ -60,8 +74,8 @@ main (int argc, char **argv)
DBusGProxy *proxy;
DBusGPendingCall *call;
char **name_list;
- int name_list_len;
- int i;
+ guint name_list_len;
+ guint i;
guint32 result;
const char *v_STRING;
char *v_STRING_2;
@@ -71,6 +85,8 @@ main (int argc, char **argv)
double v_DOUBLE_2;
g_type_init ();
+
+ g_log_set_always_fatal (G_LOG_LEVEL_WARNING);
loop = g_main_loop_new (NULL, FALSE);
@@ -94,17 +110,17 @@ main (int argc, char **argv)
/* Call ListNames method */
- call = dbus_g_proxy_begin_call (driver, "ListNames", DBUS_TYPE_INVALID);
+ call = dbus_g_proxy_begin_call (driver, "ListNames", G_TYPE_INVALID);
error = NULL;
if (!dbus_g_proxy_end_call (driver, call, &error,
- DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
- &name_list, &name_list_len,
- DBUS_TYPE_INVALID))
+ G_TYPE_STRV, &name_list,
+ G_TYPE_INVALID))
lose_gerror ("Failed to complete ListNames call", error);
g_print ("Names on the message bus:\n");
i = 0;
+ name_list_len = g_strv_length (name_list);
while (i < name_list_len)
{
g_assert (name_list[i] != NULL);
@@ -116,55 +132,49 @@ main (int argc, char **argv)
g_strfreev (name_list);
/* Test handling of unknown method */
- v_STRING = "blah blah blah blah blah";
- v_UINT32 = 10;
call = dbus_g_proxy_begin_call (driver, "ThisMethodDoesNotExist",
- DBUS_TYPE_STRING,
- &v_STRING,
- DBUS_TYPE_INT32,
- &v_UINT32,
- DBUS_TYPE_INVALID);
+ G_TYPE_STRING,
+ "blah blah blah blah blah",
+ G_TYPE_INT,
+ 10,
+ G_TYPE_INVALID);
error = NULL;
if (dbus_g_proxy_end_call (driver, call, &error,
- DBUS_TYPE_INVALID))
+ G_TYPE_INVALID))
lose ("Calling nonexistent method succeeded!");
g_print ("Got EXPECTED error from calling unknown method: %s\n", error->message);
g_error_free (error);
/* Activate a service */
- v_STRING = "org.freedesktop.DBus.TestSuiteEchoService";
- v_UINT32 = 0;
call = dbus_g_proxy_begin_call (driver, "StartServiceByName",
- DBUS_TYPE_STRING,
- &v_STRING,
- DBUS_TYPE_UINT32,
- &v_UINT32,
- DBUS_TYPE_INVALID);
+ G_TYPE_STRING,
+ "org.freedesktop.DBus.TestSuiteEchoService",
+ G_TYPE_UINT,
+ 0,
+ G_TYPE_INVALID);
error = NULL;
if (!dbus_g_proxy_end_call (driver, call, &error,
- DBUS_TYPE_UINT32, &result,
- DBUS_TYPE_INVALID))
+ G_TYPE_UINT, &result,
+ G_TYPE_INVALID))
lose_gerror ("Failed to complete Activate call", error);
g_print ("Starting echo service result = 0x%x\n", result);
/* Activate a service again */
- v_STRING = "org.freedesktop.DBus.TestSuiteEchoService";
- v_UINT32 = 0;
call = dbus_g_proxy_begin_call (driver, "StartServiceByName",
- DBUS_TYPE_STRING,
- &v_STRING,
- DBUS_TYPE_UINT32,
- &v_UINT32,
+ G_TYPE_STRING,
+ "org.freedesktop.DBus.TestSuiteEchoService",
+ G_TYPE_UINT,
+ 0,
DBUS_TYPE_INVALID);
error = NULL;
if (!dbus_g_proxy_end_call (driver, call, &error,
- DBUS_TYPE_UINT32, &result,
- DBUS_TYPE_INVALID))
+ G_TYPE_UINT, &result,
+ G_TYPE_INVALID))
lose_gerror ("Failed to complete Activate call", error);
g_print ("Duplicate start of echo service = 0x%x\n", result);
@@ -180,30 +190,30 @@ main (int argc, char **argv)
if (proxy == NULL)
lose_gerror ("Failed to create proxy for name owner", error);
- v_STRING = "my string hello";
call = dbus_g_proxy_begin_call (proxy, "Echo",
- DBUS_TYPE_STRING,
- &v_STRING,
- DBUS_TYPE_INVALID);
+ G_TYPE_STRING,
+ "my string hello",
+ G_TYPE_INVALID);
error = NULL;
if (!dbus_g_proxy_end_call (proxy, call, &error,
- DBUS_TYPE_STRING, &v_STRING,
- DBUS_TYPE_INVALID))
+ G_TYPE_STRING, &v_STRING_2,
+ G_TYPE_INVALID))
lose_gerror ("Failed to complete Echo call", error);
- g_print ("String echoed = \"%s\"\n", v_STRING);
+ g_print ("String echoed = \"%s\"\n", v_STRING_2);
+ g_free (v_STRING_2);
/* Test oneway call and signal handling */
- dbus_g_proxy_add_signal (proxy, "Foo", DBUS_TYPE_DOUBLE_AS_STRING);
+ dbus_g_proxy_add_signal (proxy, "Foo", G_TYPE_DOUBLE, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (proxy, "Foo",
G_CALLBACK (foo_signal_handler),
NULL, NULL);
dbus_g_proxy_call_no_reply (proxy, "EmitFoo",
- DBUS_TYPE_INVALID);
+ G_TYPE_INVALID);
dbus_g_connection_flush (connection);
@@ -216,20 +226,22 @@ main (int argc, char **argv)
/* Activate test servie */
g_print ("Activating TestSuiteGLibService\n");
- v_STRING = "org.freedesktop.DBus.TestSuiteGLibService";
- v_UINT32 = 0;
- call = dbus_g_proxy_begin_call (driver, "StartServiceByName",
- DBUS_TYPE_STRING,
- &v_STRING,
- DBUS_TYPE_UINT32,
- &v_UINT32,
- DBUS_TYPE_INVALID);
-
error = NULL;
- if (!dbus_g_proxy_end_call (driver, call, &error,
- DBUS_TYPE_UINT32, &result,
- DBUS_TYPE_INVALID))
+ if (!dbus_g_proxy_invoke (driver, "StartServiceByName", &error,
+ G_TYPE_STRING,
+ "org.freedesktop.DBus.TestSuiteGLibService",
+ G_TYPE_UINT,
+ 0,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &result,
+ G_TYPE_INVALID)) {
lose_gerror ("Failed to complete Activate call", error);
+ }
+
+ g_print ("TestSuiteGLibService activated\n");
+
+ if (getenv ("DBUS_GLIB_TEST_SLEEP_AFTER_ACTIVATION"))
+ g_usleep (8 * G_USEC_PER_SEC);
g_object_unref (G_OBJECT (proxy));
@@ -242,63 +254,64 @@ main (int argc, char **argv)
if (proxy == NULL)
lose_gerror ("Failed to create proxy for name owner", error);
+ g_print ("Beginning method calls\n");
+
call = dbus_g_proxy_begin_call (proxy, "DoNothing",
- DBUS_TYPE_INVALID);
+ G_TYPE_INVALID);
error = NULL;
- if (!dbus_g_proxy_end_call (proxy, call, &error, DBUS_TYPE_INVALID))
+ if (!dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID))
lose_gerror ("Failed to complete DoNothing call", error);
- v_UINT32 = 42;
- call = dbus_g_proxy_begin_call (proxy, "Increment",
- DBUS_TYPE_UINT32, &v_UINT32,
- DBUS_TYPE_INVALID);
error = NULL;
- if (!dbus_g_proxy_end_call (proxy, call, &error,
- DBUS_TYPE_UINT32, &v_UINT32_2,
- DBUS_TYPE_INVALID))
+ if (!dbus_g_proxy_invoke (proxy, "Increment", &error,
+ G_TYPE_UINT, 42,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &v_UINT32_2,
+ G_TYPE_INVALID))
lose_gerror ("Failed to complete Increment call", error);
- if (v_UINT32_2 != v_UINT32 + 1)
+ if (v_UINT32_2 != 43)
lose ("Increment call returned %d, should be 43", v_UINT32_2);
- call = dbus_g_proxy_begin_call (proxy, "ThrowError", DBUS_TYPE_INVALID);
+ call = dbus_g_proxy_begin_call (proxy, "ThrowError", G_TYPE_INVALID);
error = NULL;
- if (dbus_g_proxy_end_call (proxy, call, &error, DBUS_TYPE_INVALID) != FALSE)
+ if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID) != FALSE)
lose ("ThrowError call unexpectedly succeeded!");
g_print ("ThrowError failed (as expected) returned error: %s\n", error->message);
g_clear_error (&error);
- v_STRING = "foobar";
call = dbus_g_proxy_begin_call (proxy, "Uppercase",
- DBUS_TYPE_STRING, &v_STRING,
- DBUS_TYPE_INVALID);
+ G_TYPE_STRING, "foobar",
+ G_TYPE_INVALID);
error = NULL;
if (!dbus_g_proxy_end_call (proxy, call, &error,
- DBUS_TYPE_STRING, &v_STRING_2,
- DBUS_TYPE_INVALID))
+ G_TYPE_STRING, &v_STRING_2,
+ G_TYPE_INVALID))
lose_gerror ("Failed to complete Uppercase call", error);
if (strcmp ("FOOBAR", v_STRING_2) != 0)
lose ("Uppercase call returned unexpected string %s", v_STRING_2);
+ g_free (v_STRING_2);
v_STRING = "bazwhee";
v_UINT32 = 26;
v_DOUBLE = G_PI;
call = dbus_g_proxy_begin_call (proxy, "ManyArgs",
- DBUS_TYPE_UINT32, &v_UINT32,
- DBUS_TYPE_STRING, &v_STRING,
- DBUS_TYPE_DOUBLE, &v_DOUBLE,
- DBUS_TYPE_INVALID);
+ G_TYPE_UINT, 26,
+ G_TYPE_STRING, "bazwhee",
+ G_TYPE_DOUBLE, G_PI,
+ G_TYPE_INVALID);
error = NULL;
if (!dbus_g_proxy_end_call (proxy, call, &error,
- DBUS_TYPE_DOUBLE, &v_DOUBLE_2,
- DBUS_TYPE_STRING, &v_STRING_2,
- DBUS_TYPE_INVALID))
+ G_TYPE_DOUBLE, &v_DOUBLE_2,
+ G_TYPE_STRING, &v_STRING_2,
+ G_TYPE_INVALID))
lose_gerror ("Failed to complete ManyArgs call", error);
if (v_DOUBLE_2 < 55 || v_DOUBLE_2 > 56)
lose ("ManyArgs call returned unexpected double value %f", v_DOUBLE_2);
if (strcmp ("BAZWHEE", v_STRING_2) != 0)
lose ("ManyArgs call returned unexpected string %s", v_STRING_2);
+ g_free (v_STRING_2);
if (!org_freedesktop_DBus_Tests_MyObject_do_nothing (proxy, &error))
lose_gerror ("Failed to complete (wrapped) DoNothing call", error);
@@ -333,6 +346,313 @@ main (int argc, char **argv)
lose ("(wrapped) ManyArgs call returned unexpected string %s", v_STRING_2);
g_free (v_STRING_2);
+ {
+ guint32 arg0;
+ char *arg1;
+ gint32 arg2;
+ guint32 arg3;
+ guint32 arg4;
+ char *arg5;
+
+ if (!org_freedesktop_DBus_Tests_MyObject_many_return (proxy, &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &error))
+ lose_gerror ("Failed to complete (wrapped) ManyReturn call", error);
+
+ if (arg0 != 42)
+ lose ("(wrapped) ManyReturn call returned unexpected guint32 value %u", arg0);
+
+ if (strcmp ("42", arg1) != 0)
+ lose ("(wrapped) ManyReturn call returned unexpected string %s", arg1);
+ g_free (arg1);
+
+ if (arg2 != -67)
+ lose ("(wrapped) ManyReturn call returned unexpected gint32 value %u", arg2);
+
+ if (arg3 != 2)
+ lose ("(wrapped) ManyReturn call returned unexpected guint32 value %u", arg3);
+
+ if (arg4 != 26)
+ lose ("(wrapped) ManyReturn call returned unexpected guint32 value %u", arg4);
+
+ if (strcmp ("hello world", arg5))
+ lose ("(wrapped) ManyReturn call returned unexpected string %s", arg5);
+ g_free (arg5);
+ }
+
+ {
+ GValue value = {0, };
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, "foo");
+
+ if (!org_freedesktop_DBus_Tests_MyObject_stringify (proxy,
+ &value,
+ &v_STRING_2,
+ &error))
+ lose_gerror ("Failed to complete (wrapped) stringify call", error);
+ if (strcmp ("foo", v_STRING_2) != 0)
+ lose ("(wrapped) stringify call returned unexpected string %s", v_STRING_2);
+ g_free (v_STRING_2);
+
+ g_value_unset (&value);
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, 42);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_stringify (proxy,
+ &value,
+ &v_STRING_2,
+ &error))
+ lose_gerror ("Failed to complete (wrapped) stringify call 2", error);
+ if (strcmp ("42", v_STRING_2) != 0)
+ lose ("(wrapped) stringify call 2 returned unexpected string %s", v_STRING_2);
+ g_value_unset (&value);
+ g_free (v_STRING_2);
+
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, 88);
+ if (!org_freedesktop_DBus_Tests_MyObject_stringify (proxy,
+ &value,
+ NULL,
+ &error))
+ lose_gerror ("Failed to complete (wrapped) stringify call 3", error);
+ g_value_unset (&value);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_unstringify (proxy,
+ "foo",
+ &value,
+ &error))
+ lose_gerror ("Failed to complete (wrapped) unstringify call", error);
+ if (!G_VALUE_HOLDS_STRING (&value))
+ lose ("(wrapped) unstringify call returned unexpected value type %d", (int) G_VALUE_TYPE (&value));
+ if (strcmp (g_value_get_string (&value), "foo"))
+ lose ("(wrapped) unstringify call returned unexpected string %s",
+ g_value_get_string (&value));
+
+ g_value_unset (&value);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_unstringify (proxy,
+ "10",
+ &value,
+ &error))
+ lose_gerror ("Failed to complete (wrapped) unstringify call", error);
+ if (!G_VALUE_HOLDS_INT (&value))
+ lose ("(wrapped) unstringify call returned unexpected value type %d", (int) G_VALUE_TYPE (&value));
+ if (g_value_get_int (&value) != 10)
+ lose ("(wrapped) unstringify call returned unexpected integer %d",
+ g_value_get_int (&value));
+
+ g_value_unset (&value);
+ }
+
+ {
+ GArray *array;
+ guint32 val;
+ guint32 arraylen;
+
+ array = g_array_new (FALSE, TRUE, sizeof (guint32));
+ val = 42;
+ g_array_append_val (array, val);
+ val = 69;
+ g_array_append_val (array, val);
+ val = 88;
+ g_array_append_val (array, val);
+ val = 26;
+ g_array_append_val (array, val);
+ val = 2;
+ g_array_append_val (array, val);
+
+ arraylen = 0;
+ if (!org_freedesktop_DBus_Tests_MyObject_recursive1 (proxy, array,
+ &arraylen, &error))
+ lose_gerror ("Failed to complete (wrapped) recursive1 call", error);
+ if (arraylen != 5)
+ lose ("(wrapped) recursive1 call returned invalid length %u", arraylen);
+ }
+
+ {
+ GArray *array = NULL;
+ guint32 *arrayvals;
+
+ if (!org_freedesktop_DBus_Tests_MyObject_recursive2 (proxy, 2, &array, &error))
+ lose_gerror ("Failed to complete (wrapped) Recursive2 call", error);
+
+ if (array == NULL)
+ lose ("(wrapped) Recursive2 call returned NULL");
+ if (array->len != 5)
+ lose ("(wrapped) Recursive2 call returned unexpected array length %u", array->len);
+
+ arrayvals = (guint32*) array->data;
+ if (arrayvals[0] != 42)
+ lose ("(wrapped) Recursive2 call returned unexpected value %d in position 0", arrayvals[0]);
+ if (arrayvals[1] != 26)
+ lose ("(wrapped) Recursive2 call returned unexpected value %d in position 1", arrayvals[1]);
+ if (arrayvals[4] != 2)
+ lose ("(wrapped) Recursive2 call returned unexpected value %d in position 4", arrayvals[4]);
+
+ g_array_free (array, TRUE);
+ }
+
+ {
+ char **strs;
+ char **strs_ret;
+
+ strs = g_new0 (char *, 4);
+ strs[0] = "hello";
+ strs[1] = "HellO";
+ strs[2] = "HELLO";
+ strs[3] = NULL;
+
+ strs_ret = NULL;
+ if (!org_freedesktop_DBus_Tests_MyObject_many_uppercase (proxy, strs, &strs_ret, &error))
+ lose_gerror ("Failed to complete (wrapped) ManyUppercase call", error);
+ g_assert (strs_ret != NULL);
+ if (strcmp ("HELLO", strs_ret[0]) != 0)
+ lose ("(wrapped) ManyUppercase call returned unexpected string %s", strs_ret[0]);
+ if (strcmp ("HELLO", strs_ret[1]) != 0)
+ lose ("(wrapped) ManyUppercase call returned unexpected string %s", strs_ret[1]);
+ if (strcmp ("HELLO", strs_ret[2]) != 0)
+ lose ("(wrapped) ManyUppercase call returned unexpected string %s", strs_ret[2]);
+
+ g_strfreev (strs_ret);
+ }
+
+ {
+ GHashTable *table;
+ guint len;
+
+ table = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (table, "moooo", "b");
+ g_hash_table_insert (table, "xxx", "cow!");
+
+ len = 0;
+ if (!org_freedesktop_DBus_Tests_MyObject_str_hash_len (proxy, table, &len, &error))
+ lose_gerror ("(wrapped) StrHashLen call failed", error);
+ if (len != 13)
+ lose ("(wrapped) StrHashLen returned unexpected length %u", len);
+ g_hash_table_destroy (table);
+ }
+
+ {
+ GHashTable *table;
+ const char *val;
+
+ if (!org_freedesktop_DBus_Tests_MyObject_get_hash (proxy, &table, &error))
+ lose_gerror ("(wrapped) GetHash call failed", error);
+ val = g_hash_table_lookup (table, "foo");
+ if (val == NULL || strcmp ("bar", val))
+ lose ("(wrapped) StrHashLen returned invalid value %s for key \"foo\"",
+ val ? val : "(null)");
+ val = g_hash_table_lookup (table, "baz");
+ if (val == NULL || strcmp ("whee", val))
+ lose ("(wrapped) StrHashLen returned invalid value %s for key \"whee\"",
+ val ? val : "(null)");
+ val = g_hash_table_lookup (table, "cow");
+ if (val == NULL || strcmp ("crack", val))
+ lose ("(wrapped) StrHashLen returned invalid value %s for key \"cow\"",
+ val ? val : "(null)");
+ if (g_hash_table_size (table) != 3)
+ lose ("(wrapped) StrHashLen returned unexpected hash size %u",
+ g_hash_table_size (table));
+
+ g_hash_table_destroy (table);
+ }
+
+ {
+ guint val;
+ DBusGProxy *ret_proxy;
+
+ if (!org_freedesktop_DBus_Tests_MyObject_objpath (proxy, proxy, &ret_proxy, &error))
+ lose_gerror ("Failed to complete (wrapped) Objpath call", error);
+ if (strcmp ("/org/freedesktop/DBus/Tests/MyTestObject2",
+ dbus_g_proxy_get_path (ret_proxy)) != 0)
+ lose ("(wrapped) objpath call returned unexpected proxy %s",
+ dbus_g_proxy_get_path (ret_proxy));
+
+ val = 1;
+ if (!org_freedesktop_DBus_Tests_MyObject_get_val (ret_proxy, &val, &error))
+ lose_gerror ("Failed to complete (wrapped) GetVal call", error);
+ if (val != 0)
+ lose ("(wrapped) GetVal returned invalid value %d", val);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_increment_val (ret_proxy, &error))
+ lose_gerror ("Failed to complete (wrapped) IncrementVal call", error);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_increment_val (ret_proxy, &error))
+ lose_gerror ("Failed to complete (wrapped) IncrementVal call", error);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_increment_val (ret_proxy, &error))
+ lose_gerror ("Failed to complete (wrapped) IncrementVal call", error);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_get_val (ret_proxy, &val, &error))
+ lose_gerror ("Failed to complete (wrapped) GetVal call", error);
+ if (val != 3)
+ lose ("(wrapped) GetVal returned invalid value %d", val);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_get_val (proxy, &val, &error))
+ lose_gerror ("Failed to complete (wrapped) GetVal call", error);
+ if (val != 0)
+ lose ("(wrapped) GetVal returned invalid value %d", val);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_increment_val (proxy, &error))
+ lose_gerror ("Failed to complete (wrapped) IncrementVal call", error);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_get_val (proxy, &val, &error))
+ lose_gerror ("Failed to complete (wrapped) GetVal call", error);
+ if (val != 1)
+ lose ("(wrapped) GetVal returned invalid value %d", val);
+
+ if (!org_freedesktop_DBus_Tests_MyObject_get_val (ret_proxy, &val, &error))
+ lose_gerror ("Failed to complete (wrapped) GetVal call", error);
+ if (val != 3)
+ lose ("(wrapped) GetVal returned invalid value %d", val);
+
+ g_object_unref (G_OBJECT (ret_proxy));
+
+ ret_proxy = NULL;
+ if (!org_freedesktop_DBus_Tests_MyObject_objpath (proxy, proxy, &ret_proxy, &error))
+ lose_gerror ("Failed to complete (wrapped) Objpath call 2", error);
+ if (strcmp ("/org/freedesktop/DBus/Tests/MyTestObject2",
+ dbus_g_proxy_get_path (ret_proxy)) != 0)
+ lose ("(wrapped) objpath call 2 returned unexpected proxy %s",
+ dbus_g_proxy_get_path (ret_proxy));
+ {
+ const char *iface = dbus_g_proxy_get_interface (ret_proxy);
+ g_print ("returned proxy has interface \"%s\"\n",
+ iface ? iface : "(NULL)");
+ }
+
+ dbus_g_proxy_set_interface (ret_proxy, "org.freedesktop.DBus.Tests.FooObject");
+
+ val = 0;
+ if (!org_freedesktop_DBus_Tests_FooObject_get_value (ret_proxy, &val, &error))
+ lose_gerror ("Failed to complete (wrapped) GetValue call", error);
+ if (val != 3)
+ lose ("(wrapped) GetValue returned invalid value %d", val);
+ }
+
+ /* Signal handling tests */
+
+ dbus_g_proxy_add_signal (proxy, "Frobnicate", G_TYPE_INT, G_TYPE_INVALID);
+
+ dbus_g_proxy_connect_signal (proxy, "Frobnicate",
+ G_CALLBACK (frobnicate_signal_handler),
+ NULL, NULL);
+
+ if (!dbus_g_proxy_invoke (proxy, "EmitFrobnicate", &error,
+ G_TYPE_INVALID, G_TYPE_INVALID))
+ lose_gerror ("Failed to complete EmitFrobnicate call", error);
+
+
+ dbus_g_connection_flush (connection);
+
+#if 0
+ g_timeout_add (5000, timed_exit, loop);
+
+ g_main_loop_run (loop);
+
+ if (n_times_frobnicate_received != 1)
+ lose ("Frobnicate signal received %d times, should have been 1", n_times_frobnicate_received);
+#endif
+
g_object_unref (G_OBJECT (proxy));
proxy = dbus_g_proxy_new_for_name_owner (connection,
@@ -345,11 +665,11 @@ main (int argc, char **argv)
lose_gerror ("Failed to create proxy for name owner", error);
call = dbus_g_proxy_begin_call (proxy, "Introspect",
- DBUS_TYPE_INVALID);
+ G_TYPE_INVALID);
error = NULL;
if (!dbus_g_proxy_end_call (proxy, call, &error,
- DBUS_TYPE_STRING, &v_STRING,
- DBUS_TYPE_INVALID))
+ G_TYPE_STRING, &v_STRING_2,
+ G_TYPE_INVALID))
lose_gerror ("Failed to complete Introspect call", error);
/* Could just do strcmp(), but that seems more fragile */
@@ -359,9 +679,10 @@ main (int argc, char **argv)
gboolean found_introspectable;
gboolean found_properties;
gboolean found_myobject;
+ gboolean found_fooobject;
gboolean found_gtk_myobject;
- node = description_load_from_string (v_STRING, strlen (v_STRING), &error);
+ node = description_load_from_string (v_STRING_2, strlen (v_STRING_2), &error);
if (!node)
lose_gerror ("Failed to parse introspection data: %s", error);
@@ -369,6 +690,7 @@ main (int argc, char **argv)
found_properties = FALSE;
found_gtk_myobject = FALSE;
found_myobject = FALSE;
+ found_fooobject = FALSE;
for (elt = node_info_get_interfaces (node); elt ; elt = elt->next)
{
InterfaceInfo *iface = elt->data;
@@ -377,7 +699,7 @@ main (int argc, char **argv)
found_introspectable = TRUE;
else if (!found_properties && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.Properties") == 0)
found_properties = TRUE;
- else if (!found_gtk_myobject && strcmp (interface_info_get_name (iface), "org.gtk.objects.MyObject") == 0)
+ else if (strcmp (interface_info_get_name (iface), "org.gtk.objects.MyObject") == 0)
found_gtk_myobject = TRUE;
else if (!found_myobject && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.Tests.MyObject") == 0)
{
@@ -401,6 +723,8 @@ main (int argc, char **argv)
if (!found_manyargs)
lose ("Missing method org.freedesktop.DBus.Tests.MyObject.ManyArgs");
}
+ else if (!found_fooobject && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.Tests.FooObject") == 0)
+ found_fooobject = TRUE;
else
lose ("Unexpected or duplicate interface %s", interface_info_get_name (iface));
}
@@ -408,6 +732,7 @@ main (int argc, char **argv)
if (!(found_introspectable && found_gtk_myobject && found_myobject && found_properties))
lose ("Missing interface");
}
+ g_free (v_STRING_2);
g_object_unref (G_OBJECT (driver));
diff --git a/test/glib/test-service-glib.c b/test/glib/test-service-glib.c
index d929999d..208bfb24 100644
--- a/test/glib/test-service-glib.c
+++ b/test/glib/test-service-glib.c
@@ -20,6 +20,7 @@ struct MyObject
{
GObject parent;
char *this_is_a_string;
+ guint val;
};
struct MyObjectClass
@@ -46,7 +47,7 @@ typedef enum
gboolean my_object_do_nothing (MyObject *obj, GError **error);
-gboolean my_object_increment (MyObject *obj, gint32 x, int *ret, GError **error);
+gboolean my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error);
gboolean my_object_throw_error (MyObject *obj, GError **error);
@@ -54,6 +55,30 @@ gboolean my_object_uppercase (MyObject *obj, const char *str, char **ret, GError
gboolean my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error);
+gboolean my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, char **arg5, GError **error);
+
+gboolean my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error);
+gboolean my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **array, GError **error);
+
+gboolean my_object_objpath (MyObject *obj, GObject *in, GObject **arg1, GError **error);
+
+gboolean my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error);
+gboolean my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error);
+
+gboolean my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error);
+
+gboolean my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error);
+
+gboolean my_object_get_hash (MyObject *obj, GHashTable **table, GError **error);
+
+gboolean my_object_increment_val (MyObject *obj, GError **error);
+
+gboolean my_object_get_val (MyObject *obj, guint *ret, GError **error);
+
+gboolean my_object_get_value (MyObject *obj, guint *ret, GError **error);
+
+gboolean my_object_emit_frobnicate (MyObject *obj, GError **error);
+
#include "test-service-glib-glue.h"
GQuark my_object_error_quark (void);
@@ -65,6 +90,15 @@ enum
PROP_THIS_IS_A_STRING
};
+enum
+{
+ FROBNICATE,
+ LAST_SIGNAL
+};
+
+static void *parent_class;
+static guint signals[LAST_SIGNAL] = { 0 };
+
static void
my_object_finalize (GObject *object)
{
@@ -123,7 +157,7 @@ my_object_get_property (GObject *object,
static void
my_object_init (MyObject *obj)
{
-
+ obj->val = 0;
}
static void
@@ -142,6 +176,15 @@ my_object_class_init (MyObjectClass *mobject_class)
_("Example of a string property"),
"default value",
G_PARAM_READWRITE));
+ signals[FROBNICATE] =
+ g_signal_new ("frobnicate",
+ G_OBJECT_CLASS_TYPE (mobject_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+
}
GQuark
@@ -154,6 +197,9 @@ my_object_error_quark (void)
return quark;
}
+static GObject *obj;
+static GObject *obj2;
+
gboolean
my_object_do_nothing (MyObject *obj, GError **error)
{
@@ -161,7 +207,7 @@ my_object_do_nothing (MyObject *obj, GError **error)
}
gboolean
-my_object_increment (MyObject *obj, gint32 x, int *ret, GError **error)
+my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error)
{
*ret = x +1;
return TRUE;
@@ -191,7 +237,172 @@ my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble,
*str_ret = g_ascii_strup (str, -1);
return TRUE;
}
-
+
+gboolean
+my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, char **arg5, GError **error)
+{
+ *arg0 = 42;
+ *arg1 = g_strdup ("42");
+ *arg2 = -67;
+ *arg3 = 2;
+ *arg4 = 26;
+ *arg5 = g_strdup ("hello world");
+ return TRUE;
+}
+
+gboolean
+my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error)
+{
+ GValue valstr = {0, };
+
+ g_value_init (&valstr, G_TYPE_STRING);
+ if (!g_value_transform (value, &valstr))
+ {
+ g_set_error (error,
+ MY_OBJECT_ERROR,
+ MY_OBJECT_ERROR_FOO,
+ "couldn't transform value");
+ return FALSE;
+ }
+ *ret = g_value_dup_string (&valstr);
+ g_value_unset (&valstr);
+ return TRUE;
+}
+
+gboolean
+my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error)
+{
+ if (str[0] == '\0' || !g_ascii_isdigit (str[0])) {
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, str);
+ } else {
+ g_value_init (value, G_TYPE_INT);
+ g_value_set_int (value, (int) g_ascii_strtoull (str, NULL, 10));
+ }
+ return TRUE;
+}
+
+gboolean
+my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error)
+{
+ *len_ret = array->len;
+ return TRUE;
+}
+
+gboolean
+my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **ret, GError **error)
+{
+ guint32 val;
+ GArray *array;
+
+ array = g_array_new (FALSE, TRUE, sizeof (guint32));
+
+ while (reqlen > 0) {
+ val = 42;
+ g_array_append_val (array, val);
+ val = 26;
+ g_array_append_val (array, val);
+ reqlen--;
+ }
+ val = 2;
+ g_array_append_val (array, val);
+ *ret = array;
+ return TRUE;
+}
+
+gboolean
+my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error)
+{
+ int len;
+ int i;
+
+ len = g_strv_length ((char**) in);
+
+ *out = g_new0 (char *, len + 1);
+ for (i = 0; i < len; i++)
+ {
+ (*out)[i] = g_ascii_strup (in[i], -1);
+ }
+ (*out)[i] = NULL;
+
+ return TRUE;
+}
+
+gboolean
+my_object_objpath (MyObject *obj, GObject *incoming, GObject **outgoing, GError **error)
+{
+ if ((GObject*) obj != incoming)
+ {
+ g_set_error (error,
+ MY_OBJECT_ERROR,
+ MY_OBJECT_ERROR_FOO,
+ "invalid incoming object");
+ return FALSE;
+ }
+ *outgoing = g_object_ref (obj2);
+ return TRUE;
+}
+
+static void
+hash_foreach (gpointer key, gpointer val, gpointer user_data)
+{
+ const char *keystr = key;
+ const char *valstr = val;
+ guint *count = user_data;
+
+ *count += (strlen (keystr) + strlen (valstr));
+ g_print ("%s -> %s\n", keystr, valstr);
+}
+
+gboolean
+my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error)
+{
+ *len = 0;
+ g_hash_table_foreach (table, hash_foreach, len);
+ return TRUE;
+}
+
+gboolean
+my_object_get_hash (MyObject *obj, GHashTable **ret, GError **error)
+{
+ GHashTable *table;
+
+ table = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (table, "foo", "bar");
+ g_hash_table_insert (table, "baz", "whee");
+ g_hash_table_insert (table, "cow", "crack");
+ *ret = table;
+ return TRUE;
+}
+
+gboolean
+my_object_increment_val (MyObject *obj, GError **error)
+{
+ obj->val++;
+ return TRUE;
+}
+
+gboolean
+my_object_get_val (MyObject *obj, guint *ret, GError **error)
+{
+ *ret = obj->val;
+ return TRUE;
+}
+
+gboolean
+my_object_get_value (MyObject *obj, guint *ret, GError **error)
+{
+ *ret = obj->val;
+ return TRUE;
+}
+
+gboolean
+my_object_emit_frobnicate (MyObject *obj, GError **error)
+{
+ g_signal_emit (obj, signals[FROBNICATE], 0, 42);
+ return TRUE;
+}
+
static GMainLoop *loop;
#define TEST_SERVICE_NAME "org.freedesktop.DBus.TestSuiteGLibService"
@@ -201,13 +412,15 @@ main (int argc, char **argv)
{
DBusGConnection *connection;
GError *error;
- GObject *obj;
DBusGProxy *driver_proxy;
guint32 request_name_ret;
g_type_init ();
g_printerr ("Launching test-service-glib\n");
+
+ g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
+ g_log_set_always_fatal (G_LOG_LEVEL_WARNING);
loop = g_main_loop_new (NULL, FALSE);
@@ -223,12 +436,16 @@ main (int argc, char **argv)
}
obj = g_object_new (MY_TYPE_OBJECT, NULL);
+ obj2 = g_object_new (MY_TYPE_OBJECT, NULL);
- dbus_g_object_class_install_info (G_OBJECT_GET_CLASS (obj),
- &dbus_glib_my_object_object_info);
+ dbus_g_object_type_install_info (MY_TYPE_OBJECT,
+ &dbus_glib_my_object_object_info);
dbus_g_connection_register_g_object (connection,
"/org/freedesktop/DBus/Tests/MyTestObject",
obj);
+ dbus_g_connection_register_g_object (connection,
+ "/org/freedesktop/DBus/Tests/MyTestObject2",
+ obj2);
driver_proxy = dbus_g_proxy_new_for_name (connection,
DBUS_SERVICE_DBUS,
diff --git a/test/glib/test-service-glib.xml b/test/glib/test-service-glib.xml
index 80a815fa..f976572b 100644
--- a/test/glib/test-service-glib.xml
+++ b/test/glib/test-service-glib.xml
@@ -1,32 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/org/freedesktop/DBus/Tests/MyTestObject">
-
<interface name="org.freedesktop.DBus.Tests.MyObject">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/>
-
<method name="DoNothing">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_do_nothing"/>
</method>
<method name="Increment">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_increment"/>
<arg type="u" name="x" />
<arg type="u" direction="out" />
</method>
<method name="ThrowError">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_throw_error"/>
</method>
<method name="Uppercase">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_uppercase"/>
<arg type="s" direction="in" />
<arg type="s" direction="out" />
</method>
<method name="ManyArgs">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/>
<arg type="u" name="x" direction="in" />
<arg type="s" name="str" direction="in" />
<arg type="d" name="trouble" direction="in" />
@@ -34,6 +26,71 @@
<arg type="s" name="str_ret" direction="out" />
</method>
+ <method name="ManyReturn">
+ <arg type="u" direction="out" />
+ <arg type="s" direction="out" />
+ <arg type="i" direction="out" />
+ <arg type="u" direction="out" />
+ <arg type="u" direction="out" />
+ <arg type="s" direction="out" />
+ </method>
+
+ <method name="Stringify">
+ <arg type="v" name="val" direction="in"/>
+ <arg type="s" direction="out"/>
+ </method>
+
+ <method name="Unstringify">
+ <arg type="s" name="val" direction="in"/>
+ <arg type="v" direction="out"/>
+ </method>
+
+ <method name="Recursive1">
+ <arg type="au" direction="in"/>
+ <arg type="u" direction="out"/>
+ </method>
+
+ <method name="Recursive2">
+ <arg type="u" direction="in"/>
+ <arg type="au" direction="out"/>
+ </method>
+
+ <method name="ManyUppercase">
+ <arg type="as" direction="in"/>
+ <arg type="as" direction="out"/>
+ </method>
+
+ <method name="StrHashLen">
+ <arg type="a{ss}" direction="in"/>
+ <arg type="u" direction="out"/>
+ </method>
+
+ <method name="GetHash">
+ <arg type="a{ss}" direction="out"/>
+ </method>
+
+ <method name="Objpath">
+ <arg type="o" direction="in"/>
+ <arg type="o" direction="out"/>
+ </method>
+
+ <method name="IncrementVal">
+ </method>
+
+ <method name="GetVal">
+ <arg type="u" direction="out" />
+ </method>
+
+ <method name="EmitFrobnicate">
+ </method>
+
+ </interface>
+
+ <interface name="org.freedesktop.DBus.Tests.FooObject">
+ <method name="GetValue">
+ <arg type="u" direction="out" />
+ </method>
+
</interface>
</node>
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 333d89d1..71db5203 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,4 +1,4 @@
-INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS) $(DBUS_GTK_THREADS_CFLAGS) -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\"
+INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS) $(DBUS_GTK_THREADS_CFLAGS) -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DDBUS_COMPILATION
if HAVE_GLIB
GLIB_TOOLS=dbus-monitor
@@ -7,7 +7,7 @@ nodist_libdbus_glib_HEADERS = dbus-glib-bindings.h
libdbus_glibdir = $(includedir)/dbus-1.0/dbus
dbus-glib-bindings.h: dbus-bus-introspect.xml $(top_builddir)/glib/dbus-binding-tool
- $(top_builddir)/glib/dbus-binding-tool --ignore-unsupported --mode=glib-client --output=dbus-glib-bindings.h dbus-bus-introspect.xml # FIXME - remove --ignore-unsupported when we can do arrays
+ $(top_builddir)/glib/dbus-binding-tool --mode=glib-client --output=dbus-glib-bindings.h dbus-bus-introspect.xml
BUILT_SOURCES = dbus-glib-bindings.h dbus-bus-introspect.xml
diff --git a/tools/dbus-names-model.c b/tools/dbus-names-model.c
index ab83e5f2..01f7c4e8 100644
--- a/tools/dbus-names-model.c
+++ b/tools/dbus-names-model.c
@@ -23,6 +23,7 @@
#include "dbus-names-model.h"
#include <glib/gi18n.h>
#include <string.h>
+#include <dbus/dbus-protocol.h>
enum
{
@@ -76,8 +77,8 @@ have_names_notify (DBusGPendingCall *call,
error = NULL;
if (!dbus_g_proxy_end_call (names_model->driver_proxy,
names_model->pending_list_names,
- &error, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
- &names, &n_elements, DBUS_TYPE_INVALID))
+ &error, G_TYPE_STRV,
+ &names, &n_elements, G_TYPE_INVALID))
{
g_assert (names == NULL);
g_assert (error != NULL);
@@ -210,7 +211,7 @@ names_model_reload (NamesModel *names_model)
names_model->pending_list_names =
dbus_g_proxy_begin_call (names_model->driver_proxy,
"ListNames",
- DBUS_TYPE_INVALID);
+ G_TYPE_INVALID);
dbus_g_pending_call_set_notify (names_model->pending_list_names,
have_names_notify, names_model, NULL);
@@ -252,9 +253,10 @@ names_model_set_connection (NamesModel *names_model,
dbus_g_proxy_add_signal (names_model->driver_proxy,
"NameOwnerChanged",
- DBUS_TYPE_STRING_AS_STRING
- DBUS_TYPE_STRING_AS_STRING
- DBUS_TYPE_STRING_AS_STRING);
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
dbus_g_proxy_connect_signal (names_model->driver_proxy,
"NameOwnerChanged",
diff --git a/tools/dbus-viewer.c b/tools/dbus-viewer.c
index b031c7dd..95d00c19 100644
--- a/tools/dbus-viewer.c
+++ b/tools/dbus-viewer.c
@@ -148,7 +148,7 @@ load_child_nodes (const char *service_name,
{
DBusGProxy *proxy;
DBusGPendingCall *call;
- const char *data;
+ char *data;
NodeInfo *child;
NodeInfo *complete_child;
int save_len;
@@ -184,14 +184,19 @@ load_child_nodes (const char *service_name,
}
call = dbus_g_proxy_begin_call (proxy, "Introspect",
- DBUS_TYPE_INVALID);
+ G_TYPE_INVALID);
data = NULL;
- if (!dbus_g_proxy_end_call (proxy, call, error, DBUS_TYPE_STRING, &data,
- DBUS_TYPE_INVALID))
- goto done;
+ if (!dbus_g_proxy_end_call (proxy, call, error, G_TYPE_STRING, &data,
+ G_TYPE_INVALID))
+ {
+ call = NULL;
+ goto done;
+ }
+ call = NULL;
complete_child = description_load_from_string (data, -1, error);
+ g_free (data);
if (complete_child == NULL)
{
g_printerr ("%s\n", data);
@@ -300,16 +305,18 @@ load_from_service_thread_func (void *thread_data)
#endif
call = dbus_g_proxy_begin_call (root_proxy, "Introspect",
- DBUS_TYPE_INVALID);
+ G_TYPE_INVALID);
data = NULL;
- if (!dbus_g_proxy_end_call (root_proxy, call, &lfsd->error, DBUS_TYPE_STRING, &data,
- DBUS_TYPE_INVALID))
+ if (!dbus_g_proxy_end_call (root_proxy, call, &lfsd->error, G_TYPE_STRING, &data,
+ G_TYPE_INVALID))
{
+ call = NULL;
g_printerr ("Failed to Introspect() %s\n",
dbus_g_proxy_get_bus_name (root_proxy));
goto out;
}
+ call = NULL;
node = description_load_from_string (data, -1, &lfsd->error);
diff --git a/tools/print-introspect.c b/tools/print-introspect.c
index 9784af00..e9fe3ce4 100644
--- a/tools/print-introspect.c
+++ b/tools/print-introspect.c
@@ -41,7 +41,7 @@ main (int argc, char *argv[])
GError *error;
const char *service;
const char *path;
- const char *introspect_data;
+ char *introspect_data;
if (argc != 3)
usage (argv[0], 1);
@@ -64,9 +64,9 @@ main (int argc, char *argv[])
proxy = dbus_g_proxy_new_for_name (connection,
service, path,
DBUS_INTERFACE_INTROSPECTABLE);
- call = dbus_g_proxy_begin_call (proxy, "Introspect", DBUS_TYPE_INVALID);
- if (!dbus_g_proxy_end_call (proxy, call, &error, DBUS_TYPE_STRING,
- &introspect_data, DBUS_TYPE_INVALID))
+ call = dbus_g_proxy_begin_call (proxy, "Introspect", G_TYPE_INVALID);
+ if (!dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_STRING,
+ &introspect_data, G_TYPE_INVALID))
{
fprintf (stderr, "Failed to get introspection data: %s\n",
error->message);
@@ -75,8 +75,8 @@ main (int argc, char *argv[])
}
printf ("%s", introspect_data);
+ g_free (introspect_data);
- dbus_g_pending_call_unref (call);
g_object_unref (proxy);
exit (0);