diff options
| -rw-r--r-- | ChangeLog | 184 | ||||
| -rw-r--r-- | dbus/dbus-glib.h | 126 | ||||
| -rw-r--r-- | doc/TODO | 9 | ||||
| -rw-r--r-- | doc/dbus-tutorial.xml | 680 | ||||
| -rw-r--r-- | glib/Makefile.am | 6 | ||||
| -rw-r--r-- | glib/dbus-binding-tool-glib.c | 642 | ||||
| -rw-r--r-- | glib/dbus-binding-tool-glib.h | 1 | ||||
| -rw-r--r-- | glib/dbus-gmain.c | 29 | ||||
| -rw-r--r-- | glib/dbus-gobject.c | 599 | ||||
| -rw-r--r-- | glib/dbus-gobject.h | 10 | ||||
| -rw-r--r-- | glib/dbus-gproxy.c | 789 | ||||
| -rw-r--r-- | glib/dbus-gtype-specialized.c | 441 | ||||
| -rw-r--r-- | glib/dbus-gtype-specialized.h | 104 | ||||
| -rw-r--r-- | glib/dbus-gvalue-utils.c | 715 | ||||
| -rw-r--r-- | glib/dbus-gvalue-utils.h | 70 | ||||
| -rw-r--r-- | glib/dbus-gvalue.c | 1508 | ||||
| -rw-r--r-- | glib/dbus-gvalue.h | 55 | ||||
| -rw-r--r-- | python/Makefile.am | 2 | ||||
| -rw-r--r-- | test/glib/Makefile.am | 6 | ||||
| -rw-r--r-- | test/glib/test-dbus-glib.c | 487 | ||||
| -rw-r--r-- | test/glib/test-service-glib.c | 231 | ||||
| -rw-r--r-- | test/glib/test-service-glib.xml | 73 | ||||
| -rw-r--r-- | tools/Makefile.am | 4 | ||||
| -rw-r--r-- | tools/dbus-names-model.c | 14 | ||||
| -rw-r--r-- | tools/dbus-viewer.c | 23 | ||||
| -rw-r--r-- | tools/print-introspect.c | 10 | 
26 files changed, 5825 insertions, 993 deletions
| @@ -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 @@ -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 -      <dbus/dbus-glib.h>. The API is very small, in sharp contrast to the -      low-level <dbus/dbus.h>. - +      <dbus/dbus-glib.h>.      </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, &error, -                              DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, -                              &name_list, &name_list_len, -                              DBUS_TYPE_INVALID)) +  if (!dbus_g_proxy_invoke (proxy, "ListNames", &error, G_TYPE_INVALID, +                            G_TYPE_STRV, &name_list, G_TYPE_INVALID))      {        g_printerr ("Failed to complete ListNames call: %s\n",                    error->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 < 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", &error, +                            G_TYPE_INT, 42, G_TYPE_STRING, "hello", +			    G_TYPE_INVALID, +			    DBUS_TYPE_G_UCHAR_ARRAY, &arr, G_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete Foobar: %s\n", +                  error->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", &error, +                            DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID, +			    G_TYPE_UINT, &ret, G_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete HashSize: %s\n", +                  error->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", &error, +			    G_TYPE_INVALID, +                            G_TYPE_BOOLEAN, &boolret, +                            G_TYPE_STRING, &strret, +			    G_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete GetStuff: %s\n", +                  error->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", &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->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", &error, +                            G_TYPE_BOOLEAN, blah, +			    G_TYPE_INVALID, +                            G_TYPE_STRV, &strs, +			    G_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete GetStrs: %s\n", +                  error->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 (&val, G_TYPE_STRING); +  g_value_set_string (&val, "hello world"); +   +  error = NULL; +  if (!dbus_g_proxy_invoke (proxy, "SendVariant", &error, +                            G_TYPE_VALUE, &val, G_TYPE_INVALID, +			    G_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete SendVariant: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } +  g_assert (ret == 2); +  g_value_unset (&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", &error, G_TYPE_INVALID, +                            G_TYPE_VALUE, &val, G_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete GetVariant: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } +  if (G_VALUE_TYPE (&val) == G_TYPE_STRING) +    printf ("%s\n", g_value_get_string (&val)); +  else if (G_VALUE_TYPE (&val) == G_TYPE_INT) +    printf ("%d\n", g_value_get_int (&val)); +  else +    ... +  g_value_unset (&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 -      <dbus/dbus-glib.h>. 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> +<?xml version="1.0" encoding="UTF-8" ?> + +<node name="/com/example/MyObject"> +  <interface name="com.example.MyObject"> +    <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/> +    <method name="ManyArgs"> +      <!-- This is optional, and in this case is redunundant --> +      <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" /> +      <arg type="d" name="d_ret" direction="out" /> +      <arg type="s" name="str_ret" direction="out" /> +    </method> +  </interface> +</node> +</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> -> +      <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> > <replaceable>HEADER_NAME</replaceable>.</literal> to +      generate a header file.  For example: <command>dbus-binding-tool --mode=glib-server my-objet.xml > 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, &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 (¶m_values[0]);    message = g_value_get_boxed (¶m_values[1]); -  signature = g_value_get_string (¶m_values[2]); +  gsignature = g_value_get_pointer (¶m_values[2]);    g_return_if_fail (DBUS_IS_G_PROXY (proxy));    g_return_if_fail (message != NULL); -  g_return_if_fail (signature != NULL); -   -  c_marshaller = lookup_g_marshaller (proxy, signature); +  g_return_if_fail (gsignature != NULL); + +  c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len, +						  (GType*) gsignature->data);    g_return_if_fail (c_marshaller != NULL); -  value_array = _dbus_glib_marshal_dbus_message_to_gvalue_array (message); +  { +    DBusGValueMarshalCtx context; +    context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection); +    context.proxy = proxy; -  g_return_if_fail (value_array != NULL); +    types = (const GType*) gsignature->data; +    value_array = dbus_gvalue_demarshal_message (&context, message, +						 gsignature->len, types, NULL); +  } + +  if (value_array == NULL) +    return;    g_value_init (&value, G_TYPE_FROM_INSTANCE (proxy));    g_value_set_instance (&value, proxy); @@ -966,37 +903,40 @@ 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); | 
