]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
2005-02-17 Colin Walters <walters@verbum.org>
authorColin Walters <walters@verbum.org>
Thu, 17 Feb 2005 17:41:30 +0000 (17:41 +0000)
committerColin Walters <walters@verbum.org>
Thu, 17 Feb 2005 17:41:30 +0000 (17:41 +0000)
This patch is based on initial work from
Paul Kuliniewicz <kuliniew@purdue.edu>.

* glib/dbus-gvalue.c (dbus_gvalue_init): New function; move
initialization of GValue from dbus type to here.
(dbus_gvalue_genmarshal_name_from_type): New function; generates a string
for the "glib-genmarshal" program from a DBus type.
(dbus_gvalue_binding_type_from_type): New function; turns a DBus type
into the C name for it we use in the glib bindings.
(dbus_gvalue_ctype_from_type): New function; maps a DBus type into a
glib C type (not GValue).
(dbus_gvalue_demarshal): invoke dbus_gvalue_init.

* glib/dbus-gutils.c (_dbus_gutils_wincaps_to_uscore): Moved here
from dbus-gobject.c.

* glib/dbus-gutils.h: Prototype it.

* glib/dbus-gproxy.c: Include new dbus-gobject.h.
(marshal_dbus_message_to_g_marshaller): Use new shared function
dbus_glib_marshal_dbus_message_to_gvalue_array.

* glib/dbus-gparser.c (parse_interface, parse_method): Handle c_name attribute.
Will be changed once we have annotations.

* glib/dbus-gobject.c: Change info_hash_mutex from GStaticMutex to
GStaticRWLock.  Callers updated.
(wincaps_to_uscore): Move to dbus-gutils.c.  Callers updated.
(string_table_next): New function for iterating over zero-terminated
string value array.
(string_table_lookup): New function; retrieves specific entry in
array.
(get_method_data): New function; look up method data in object data chunk.
(object_error_domain_prefix_from_object_info)
(object_error_code_from_object_info): New functions, but not implemented yet.
(method_interface_from_object_info): New function; retrieve interface name.
(method_name_from_object_info): New function; retrieve method name.
(method_arg_info_from_object_info): New function; retrieve argument data.
(arg_iterate): New function; iterates over serialized argument data.
(method_dir_signature_from_object_info): New function; returns a
GString holding type signature for arguments for just one
direction (input or output).
(method_input_signature_from_object_info)
(method_output_signature_from_object_info): New functions.
(dbus_glib_marshal_dbus_message_to_gvalue_array): New shared function;
converts dbus message arguments into a GValue array.  Used for both
signal handling and method invocation.
(struct DBusGlibWriteIterfaceData): New utility structure.
(write_interface): New function; generate introspection XML for
an interface.
(introspect_interfaces): New function; gathers all interface->methods,
generates introspection XML for them.
(handle_introspect): Invoke introspect_interfaces.
(get_object_property): Be sure to zero-initalize stack-allocated GValue.
(lookup_object_and_method): New function; examines an incoming message
and attempts to match it up (via interface, method name, and argument
signature) with a known object and method.
(gerror_domaincode_to_dbus_error_name): New function; converts a
GError domain and code into a DBus error name.  Needs GError data
added to object introspection to work well.
(gerror_to_dbus_error_message): Creates a DBusMessage error return from
GError.
(invoke_object_method): New function to invoke an object method
looked up via lookup_object_and_method.  Parses the incoming
message, turns it into a GValue array, then invokes the marshaller
specified in the DBusGMethodInfo.  Creates a new message with
either return values or error message as appropriate.
(gobject_message_function): Invoke lookup_object_and_method and
invoke_object_method.

* glib/dbus-glib-tool.c: Include dbus-binding-tool-glib.h.
(enum DBusBindingOutputMode): New enum for binding output modes.
(pretty_print): Print binding names.
(dbus_binding_tool_error_quark): GError bits.
(version): Fix typo.
(main): Create GIOChannel for output.  Parse new --mode argument,
possible values are "pretty-print", "glib-server", "glib-client".
Use mode to invoke appropriate function.

* glib/dbus-gobject.h: Prototype dbus_glib_marshal_dbus_message_to_gvalue_array.

* glib/dbus-glib-tool.h: New header, just includes GError bits
for now.

* glib/dbus-gidl.c (struct InterfaceInfo): Add bindings hashtable;
maps binding style to name.
(struct MethodInfo): Ditto.
(get_hash_keys, get_hash_key): Utility function, returns keys for
a GHashTable.
(interface_info_new, method_info_new): Initialize bindings.
(interface_info_unref, method_info_unref): Destroy bindings.
(method_info_get_binding_names, method_info_get_binding_name)
(interface_info_get_binding_names, interface_info_get_binding_name):
Functions for retrieving binding names.
(method_info_set_binding_name, interface_info_set_binding_name):
Functions for setting binding names.

* glib/dbus-binding-tool-glib.h: New file, has prototypes
for glib binding generation.

* glib/dbus-binding-tool-glib.c: New file, implements server-side
and client-side glib glue generation.

* glib/Makefile.am (dbus_binding_tool_SOURCES): Add
dbus-binding-tool-glib.c, dbus-binding-tool-glib.h,
dbus-glib-tool.h.

* dbus/dbus-glib.h (struct DBusGMethodMarshaller): Remove in favor
of using GClosureMarshal directly.
(struct DBusGObjectInfo): Add n_infos member.

* test/glib/test-service-glib.xml: New file; contains introspection data
for MyTestObject used in test-service-glib.c.

* test/glib/test-service-glib.c (enum MyObjectError): New GError enum.
(my_object_do_nothing, my_object_increment, my_object_throw_error)
(my_object_uppercase, my_object_many_args): New test methods.
(main): Use dbus_g_object_class_install_info to include generated object
info.

* test/glib/Makefile.am: Generate server-side glue for test-service-glib.c,
as well as client-side bindings.

* test/glib/test-dbus-glib.c: Include test-service-glib-bindings.h.
(main): Activate TestSuiteGLibService; test invoke a bunch of its methods
using both the dbus_gproxy stuff directly as well as the generated bindings.

21 files changed:
ChangeLog
dbus/dbus-glib.h
glib/Makefile.am
glib/dbus-binding-tool-glib.c [new file with mode: 0644]
glib/dbus-binding-tool-glib.h [new file with mode: 0644]
glib/dbus-gidl.c
glib/dbus-gidl.h
glib/dbus-glib-tool.c
glib/dbus-glib-tool.h [new file with mode: 0644]
glib/dbus-gobject.c
glib/dbus-gobject.h [new file with mode: 0644]
glib/dbus-gparser.c
glib/dbus-gproxy.c
glib/dbus-gutils.c
glib/dbus-gutils.h
glib/dbus-gvalue.c
glib/dbus-gvalue.h
test/glib/Makefile.am
test/glib/test-dbus-glib.c
test/glib/test-service-glib.c
test/glib/test-service-glib.xml [new file with mode: 0644]

index 5b2b085d3a10c150ca010851854eca26ff064167..30decfa179929208833fa1d95c40d6600ff2b048 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,132 @@
+2005-02-17  Colin Walters  <walters@verbum.org>
+       
+       This patch is based on initial work from
+       Paul Kuliniewicz <kuliniew@purdue.edu>.
+
+       * glib/dbus-gvalue.c (dbus_gvalue_init): New function; move
+       initialization of GValue from dbus type to here.
+       (dbus_gvalue_genmarshal_name_from_type): New function; generates a string
+       for the "glib-genmarshal" program from a DBus type.
+       (dbus_gvalue_binding_type_from_type): New function; turns a DBus type
+       into the C name for it we use in the glib bindings.
+       (dbus_gvalue_ctype_from_type): New function; maps a DBus type into a
+       glib C type (not GValue).
+       (dbus_gvalue_demarshal): invoke dbus_gvalue_init.
+
+       * glib/dbus-gutils.c (_dbus_gutils_wincaps_to_uscore): Moved here
+       from dbus-gobject.c.
+
+       * glib/dbus-gutils.h: Prototype it.
+
+       * glib/dbus-gproxy.c: Include new dbus-gobject.h.
+       (marshal_dbus_message_to_g_marshaller): Use new shared function
+       dbus_glib_marshal_dbus_message_to_gvalue_array.
+
+       * glib/dbus-gparser.c (parse_interface, parse_method): Handle c_name attribute.
+       Will be changed once we have annotations.
+
+       * glib/dbus-gobject.c: Change info_hash_mutex from GStaticMutex to
+       GStaticRWLock.  Callers updated.
+       (wincaps_to_uscore): Move to dbus-gutils.c.  Callers updated.
+       (string_table_next): New function for iterating over zero-terminated
+       string value array.
+       (string_table_lookup): New function; retrieves specific entry in
+       array.
+       (get_method_data): New function; look up method data in object data chunk.
+       (object_error_domain_prefix_from_object_info)
+       (object_error_code_from_object_info): New functions, but not implemented yet.
+       (method_interface_from_object_info): New function; retrieve interface name.
+       (method_name_from_object_info): New function; retrieve method name.
+       (method_arg_info_from_object_info): New function; retrieve argument data.
+       (arg_iterate): New function; iterates over serialized argument data.
+       (method_dir_signature_from_object_info): New function; returns a
+       GString holding type signature for arguments for just one
+       direction (input or output).
+       (method_input_signature_from_object_info)
+       (method_output_signature_from_object_info): New functions.
+       (dbus_glib_marshal_dbus_message_to_gvalue_array): New shared function;
+       converts dbus message arguments into a GValue array.  Used for both
+       signal handling and method invocation.
+       (struct DBusGlibWriteIterfaceData): New utility structure.
+       (write_interface): New function; generate introspection XML for
+       an interface.
+       (introspect_interfaces): New function; gathers all interface->methods,
+       generates introspection XML for them.
+       (handle_introspect): Invoke introspect_interfaces.
+       (get_object_property): Be sure to zero-initalize stack-allocated GValue.
+       (lookup_object_and_method): New function; examines an incoming message
+       and attempts to match it up (via interface, method name, and argument
+       signature) with a known object and method.
+       (gerror_domaincode_to_dbus_error_name): New function; converts a
+       GError domain and code into a DBus error name.  Needs GError data
+       added to object introspection to work well.
+       (gerror_to_dbus_error_message): Creates a DBusMessage error return from
+       GError.
+       (invoke_object_method): New function to invoke an object method
+       looked up via lookup_object_and_method.  Parses the incoming
+       message, turns it into a GValue array, then invokes the marshaller
+       specified in the DBusGMethodInfo.  Creates a new message with
+       either return values or error message as appropriate.
+       (gobject_message_function): Invoke lookup_object_and_method and
+       invoke_object_method.
+
+       * glib/dbus-glib-tool.c: Include dbus-binding-tool-glib.h.
+       (enum DBusBindingOutputMode): New enum for binding output modes.
+       (pretty_print): Print binding names.
+       (dbus_binding_tool_error_quark): GError bits.
+       (version): Fix typo.
+       (main): Create GIOChannel for output.  Parse new --mode argument,
+       possible values are "pretty-print", "glib-server", "glib-client".
+       Use mode to invoke appropriate function.
+       
+       * glib/dbus-gobject.h: Prototype dbus_glib_marshal_dbus_message_to_gvalue_array.
+
+       * glib/dbus-glib-tool.h: New header, just includes GError bits
+       for now.
+
+       * glib/dbus-gidl.c (struct InterfaceInfo): Add bindings hashtable;
+       maps binding style to name.
+       (struct MethodInfo): Ditto.
+       (get_hash_keys, get_hash_key): Utility function, returns keys for
+       a GHashTable.
+       (interface_info_new, method_info_new): Initialize bindings.
+       (interface_info_unref, method_info_unref): Destroy bindings.
+       (method_info_get_binding_names, method_info_get_binding_name)
+       (interface_info_get_binding_names, interface_info_get_binding_name):
+       Functions for retrieving binding names.
+       (method_info_set_binding_name, interface_info_set_binding_name):
+       Functions for setting binding names.
+
+       * glib/dbus-binding-tool-glib.h: New file, has prototypes
+       for glib binding generation.
+
+       * glib/dbus-binding-tool-glib.c: New file, implements server-side
+       and client-side glib glue generation.
+
+       * glib/Makefile.am (dbus_binding_tool_SOURCES): Add
+       dbus-binding-tool-glib.c, dbus-binding-tool-glib.h,
+       dbus-glib-tool.h.
+
+       * dbus/dbus-glib.h (struct DBusGMethodMarshaller): Remove in favor
+       of using GClosureMarshal directly.
+       (struct DBusGObjectInfo): Add n_infos member.
+
+       * test/glib/test-service-glib.xml: New file; contains introspection data
+       for MyTestObject used in test-service-glib.c.
+
+       * test/glib/test-service-glib.c (enum MyObjectError): New GError enum.
+       (my_object_do_nothing, my_object_increment, my_object_throw_error)
+       (my_object_uppercase, my_object_many_args): New test methods.
+       (main): Use dbus_g_object_class_install_info to include generated object
+       info.
+
+       * test/glib/Makefile.am: Generate server-side glue for test-service-glib.c,
+       as well as client-side bindings.
+
+       * test/glib/test-dbus-glib.c: Include test-service-glib-bindings.h.
+       (main): Activate TestSuiteGLibService; test invoke a bunch of its methods
+       using both the dbus_gproxy stuff directly as well as the generated bindings.
+
 2005-02-15  Havoc Pennington  <hp@redhat.com>
 
        * dbus/dbus-connection.c (dbus_connection_dispatch): always
index 5c002f49f702a684a04fbc1288ff0999d6698e2f..a9aad5400c080d2c726f3d2f43745c4f1da9c17f 100644 (file)
@@ -89,25 +89,21 @@ DBusGConnection* dbus_g_bus_get     (DBusBusType   type,
 typedef struct DBusGObjectInfo DBusGObjectInfo;
 typedef struct DBusGMethodInfo DBusGMethodInfo;
 
-typedef DBusHandlerResult (* DBusGMethodMarshaller) (DBusGConnection    *connection,
-                                                     DBusGMessage       *message,
-                                                     void               *user_data);
-
 /**
- * Object typically generated by dbus-glib-tool that
+ * Object typically generated by dbus-binding-tool that
  * stores a mapping from introspection data to a
  * function pointer for a C method to be invoked.
  */
 struct DBusGMethodInfo
 {
   GCallback                 function;    /**< C method to invoke */
-  DBusGMethodMarshaller     marshaller;  /**< Marshaller to go DBusGMessage to C method */
+  GClosureMarshal           marshaller;  /**< Marshaller to invoke method */
   int                       data_offset; /**< Offset into the introspection data */
 };
 
 /**
  * Introspection data for a GObject, normally autogenerated by
- * a tool such as dbus-glib-tool.
+ * a tool such as dbus-binding-tool.
  */
 struct DBusGObjectInfo
 {
@@ -115,7 +111,8 @@ struct DBusGObjectInfo
                                  *   by adding DBusGObjectInfo2, DBusGObjectInfo3, etc.
                                  */
   const DBusGMethodInfo *infos; /**< Array of method pointers */
-  const unsigned char *data;    /**< Introspection data */
+  int   n_infos;                /**< Length of the infos array */
+  const char *data;             /**< Introspection data */
 };
 
 void dbus_g_object_class_install_info    (GObjectClass          *object_class,
@@ -174,6 +171,7 @@ void              dbus_g_proxy_call_no_reply         (DBusGProxy        *proxy,
                                                       const char        *method,
                                                       int                first_arg_type,
                                                       ...);
+
 const char*       dbus_g_proxy_get_bus_name          (DBusGProxy        *proxy);
 
 #undef DBUS_INSIDE_DBUS_GLIB_H
index 6a42e6f9d4a0ab8cc07eb8d5c1393cca9fd2a8bd..9afe4a729839b6b75cdbb06635d964673f863979 100644 (file)
@@ -39,6 +39,9 @@ libdbus_gtool_la_LIBADD = libdbus-glib-1.la
 bin_PROGRAMS=dbus-binding-tool
 
 dbus_binding_tool_SOURCES =                    \
+       dbus-binding-tool-glib.h                \
+       dbus-binding-tool-glib.c                \
+       dbus-glib-tool.h                        \
        dbus-glib-tool.c
 
 dbus_binding_tool_LDADD= -lexpat libdbus-gtool.la
diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c
new file mode 100644 (file)
index 0000000..98c1334
--- /dev/null
@@ -0,0 +1,812 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-binding-tool-glib.c: Output C glue
+ *
+ * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <config.h>
+#include "dbus-gidl.h"
+#include "dbus-gparser.h"
+#include "dbus-gutils.h"
+#include "dbus-gvalue.h"
+#include "dbus-glib-tool.h"
+#include "dbus-binding-tool-glib.h"
+#include <glib/gi18n.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MARSHAL_PREFIX "dbus_glib_marshal"
+
+typedef struct
+{
+  GIOChannel *channel;
+  
+  GError **error;
+  
+  GHashTable *generated;
+} 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 char *
+compute_marshaller (MethodInfo *method, GError **error)
+{
+  GSList *elt;
+  GString *ret;
+  gboolean first;
+
+  /* All methods required to return boolean for now;
+   * will be conditional on method info later */
+  ret = g_string_new ("BOOLEAN:");
+
+  first = TRUE;
+  /* Append input arguments */
+  for (elt = method_info_get_args (method); elt; elt = elt->next)
+    {
+      ArgInfo *arg = elt->data;
+
+      if (arg_info_get_direction (arg) == ARG_IN)
+       {
+         const char *marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg));
+         if (!marshal_name)
+           {
+             g_set_error (error,
+                          DBUS_BINDING_TOOL_ERROR,
+                          DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+                          _("Unsupported conversion from D-BUS type %d to glib-genmarshal type"),
+                          arg_info_get_type (arg));
+             g_string_free (ret, TRUE);
+             return NULL;
+           }
+         if (!first)
+           g_string_append (ret, ",");
+         else
+           first = FALSE;
+         g_string_append (ret, marshal_name);
+       }
+    }
+
+  /* Append pointer for each out arg storage */
+  for (elt = method_info_get_args (method); elt; elt = elt->next)
+    {
+      ArgInfo *arg = elt->data;
+
+      if (arg_info_get_direction (arg) == ARG_OUT)
+       {
+         if (!first)
+           g_string_append (ret, ",");
+         else
+           first = FALSE;
+         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);
+
+}
+
+static char *
+compute_marshaller_name (MethodInfo *method, GError **error)
+{
+  GSList *elt;
+  GString *ret;
+
+  /* All methods required to return boolean for now;
+   * will be conditional on method info later */
+  ret = g_string_new (MARSHAL_PREFIX "_BOOLEAN_");
+
+  /* Append input arguments */
+  for (elt = method_info_get_args (method); elt; elt = elt->next)
+    {
+      ArgInfo *arg = elt->data;
+
+      if (arg_info_get_direction (arg) == ARG_IN)
+       {
+         const char *marshal_name;
+         int type; 
+
+         type = arg_info_get_type (arg);
+         marshal_name = dbus_gvalue_genmarshal_name_from_type (type);
+         if (!marshal_name)
+           {
+             g_set_error (error,
+                          DBUS_BINDING_TOOL_ERROR,
+                          DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+                          _("Unsupported conversion from D-BUS type %d to glib-genmarshal type"),
+                          type);
+             g_string_free (ret, TRUE);
+             return NULL;
+           }
+
+         g_string_append (ret, "_");
+         g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg)));
+       }
+    }
+
+  /* Append pointer for each out arg storage */
+  for (elt = method_info_get_args (method); elt; elt = elt->next)
+    {
+      ArgInfo *arg = elt->data;
+
+      if (arg_info_get_direction (arg) == ARG_OUT)
+       {
+         g_string_append (ret, "_POINTER");
+       }
+    }
+
+  /* Final GError parameter */
+  g_string_append (ret, "_POINTER");
+
+  return g_string_free (ret, FALSE);
+}
+
+static gboolean
+gather_marshallers_list (GSList *list, DBusBindingToolCData *data, GError **error)
+{
+  GSList *tmp;
+
+  tmp = list;
+  while (tmp != NULL)
+    {
+      if (!gather_marshallers (tmp->data, data, error))
+       return FALSE;
+      tmp = tmp->next;
+    }
+  return TRUE;
+}
+
+static gboolean
+gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
+{
+  if (base_info_get_type (base) == INFO_TYPE_NODE)
+    {
+      if (!gather_marshallers_list (node_info_get_nodes ((NodeInfo *) base),
+                                   data, error))
+       return FALSE;
+      if (!gather_marshallers_list (node_info_get_interfaces ((NodeInfo *) base),
+                                   data, error))
+       return FALSE;
+    }
+  else
+    {
+      InterfaceInfo *interface;
+      GSList *methods;
+      GSList *tmp;
+      const char *interface_c_name;
+
+      interface = (InterfaceInfo *) base;
+      interface_c_name = interface_info_get_binding_name (interface, "C");
+      if (interface_c_name == NULL)
+        {
+          return TRUE;
+        }
+
+      methods = interface_info_get_methods (interface);
+
+      /* Generate the necessary marshallers for the methods. */
+
+      for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
+        {
+          MethodInfo *method;
+          char *marshaller_name;
+
+          method = (MethodInfo *) tmp->data;
+          if (method_info_get_binding_name (method, "C") == NULL)
+            {
+              continue;
+            }
+
+          marshaller_name = compute_marshaller (method, error);
+         if (!marshaller_name)
+           return FALSE;
+
+         if (g_hash_table_lookup (data->generated, marshaller_name))
+           {
+             g_free (marshaller_name);
+             continue;
+           }
+
+         g_hash_table_insert (data->generated, marshaller_name, NULL);
+        }
+
+    }
+  return TRUE;
+}
+
+static gboolean
+generate_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
+{
+  GSList *tmp;
+
+  tmp = list;
+  while (tmp != NULL)
+    {
+      if (!generate_glue (tmp->data, data, error))
+       return FALSE;
+      tmp = tmp->next;
+    }
+  return TRUE;
+}
+
+#define WRITE_OR_LOSE(x) do { gsize bytes_written; if (!g_io_channel_write_chars (channel, x, -1, &bytes_written, error)) goto io_lose; } while (0)
+
+static gboolean
+write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, ...)
+{
+  char *str;
+  va_list args;
+  GIOStatus status;
+  gsize written;
+  gboolean ret;
+
+  va_start (args, error);
+
+  str = g_strdup_vprintf (fmt, args);
+  if ((status = g_io_channel_write_chars (channel, str, -1, &written, error)) == G_IO_STATUS_NORMAL)
+    ret = TRUE;
+  else
+    ret = FALSE;
+
+  g_free (str);
+
+  va_end (args);
+
+  return ret;
+}
+
+static gboolean
+generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
+{
+  if (base_info_get_type (base) == INFO_TYPE_NODE)
+    {
+      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;
+    }
+  else
+    {
+      GIOChannel *channel;
+      InterfaceInfo *interface;
+      GSList *methods;
+      GSList *tmp;
+      gsize i;
+      int count;
+      const char *interface_c_name;
+      GString *object_introspection_data_blob;
+
+      channel = data->channel;
+
+      interface = (InterfaceInfo *) base;
+      interface_c_name = interface_info_get_binding_name (interface, "C");
+      if (interface_c_name == NULL)
+        {
+          return TRUE;
+        }
+
+      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_binding_name (interface, "C")))
+       goto io_lose;
+      for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
+        {
+          MethodInfo *method;
+          char *marshaller_name;
+         const char *method_c_name;
+         GSList *args;
+
+          method = (MethodInfo *) tmp->data;
+         method_c_name = method_info_get_binding_name (method, "C");
+          if (method_c_name == NULL)
+            {
+              continue;
+            }
+
+          if (!write_printf_to_iochannel ("  { (GCallback) %s, ", channel, error,
+                                         method_c_name))
+           goto io_lose;
+
+          marshaller_name = compute_marshaller_name (method, error);
+         if (!marshaller_name)
+           goto io_lose;
+
+          if (!write_printf_to_iochannel ("%s, %d },\n", channel, error,
+                                         marshaller_name,
+                                         object_introspection_data_blob->len))
+           {
+             g_free (marshaller_name);
+             goto io_lose;
+           }
+
+         /* Object method data blob format:
+          * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
+          */
+
+         g_string_append (object_introspection_data_blob, interface_info_get_name (interface));
+         g_string_append_c (object_introspection_data_blob, '\0');
+
+         g_string_append (object_introspection_data_blob, method_info_get_name (method));
+         g_string_append_c (object_introspection_data_blob, '\0');
+
+         for (args = method_info_get_args (method); args; args = args->next)
+           {
+             ArgInfo *arg;
+             char direction;
+
+             arg = args->data;
+
+             g_string_append (object_introspection_data_blob, arg_info_get_name (arg));
+             g_string_append_c (object_introspection_data_blob, '\0');
+
+             switch (arg_info_get_direction (arg))
+               {
+               case ARG_IN:
+                 direction = 'I';
+                 break;
+               case ARG_OUT:
+                 direction = 'O';
+                 break;
+               case ARG_INVALID:
+                 break;
+               }
+             g_string_append_c (object_introspection_data_blob, direction);
+             g_string_append_c (object_introspection_data_blob, '\0');
+
+             g_string_append_c (object_introspection_data_blob, arg_info_get_type (arg));
+             g_string_append_c (object_introspection_data_blob, '\0');
+           }
+
+         g_string_append_c (object_introspection_data_blob, '\0');
+
+          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:
+  return FALSE;
+}
+
+static void
+write_marshaller (gpointer key, gpointer value, gpointer user_data)
+{
+  DBusBindingToolCData *data;
+  const char *marshaller;
+  gsize bytes_written;
+
+  data = user_data;
+  marshaller = key;
+
+  if (data->error && *data->error)
+    return;
+
+  if (g_io_channel_write_chars (data->channel, marshaller, -1, &bytes_written, data->error) == G_IO_STATUS_NORMAL)
+    g_io_channel_write_chars (data->channel, "\n", -1, &bytes_written, data->error);
+}
+
+gboolean
+dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, GError **error)
+{
+  gboolean ret;
+  GPtrArray *argv;
+  gint child_stdout;
+  GIOChannel *genmarshal_stdout;
+  GPid child_pid;
+  DBusBindingToolCData data;
+  char *tempfile_name;
+  gint tempfile_fd;
+  GIOStatus iostatus;
+  char buf[4096];
+  gsize bytes_read, bytes_written;
+
+  memset (&data, 0, sizeof (data));
+
+  data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+  data.error = error;
+  genmarshal_stdout = NULL;
+  tempfile_name = NULL;
+
+  if (!gather_marshallers (info, &data, error))
+    goto io_lose;
+
+  tempfile_fd = g_file_open_tmp ("dbus-binding-tool-c-marshallers.XXXXXX",
+                                &tempfile_name, error);
+  if (tempfile_fd < 0)
+    goto io_lose;
+
+  data.channel = g_io_channel_unix_new (tempfile_fd);
+  if (!g_io_channel_set_encoding (data.channel, NULL, error))
+    goto io_lose;
+  g_hash_table_foreach (data.generated, write_marshaller, &data); 
+  if (error && *error != NULL)
+    {
+      ret = FALSE;
+      g_io_channel_close (data.channel);
+      g_io_channel_unref (data.channel);
+      goto io_lose;
+    }
+
+  g_io_channel_close (data.channel);
+  g_io_channel_unref (data.channel);
+  
+  /* Now spawn glib-genmarshal to insert all our required marshallers */
+  argv = g_ptr_array_new ();
+  g_ptr_array_add (argv, "glib-genmarshal");
+  g_ptr_array_add (argv, "--header");
+  g_ptr_array_add (argv, "--body");
+  g_ptr_array_add (argv, "--prefix=" MARSHAL_PREFIX);
+  g_ptr_array_add (argv, tempfile_name);
+  g_ptr_array_add (argv, NULL);
+  if (!g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL,
+                                G_SPAWN_SEARCH_PATH,
+                                NULL, NULL,
+                                &child_pid,
+                                NULL,
+                                &child_stdout, NULL, error))
+    {
+      g_ptr_array_free (argv, TRUE);
+      goto io_lose;
+    }
+  g_ptr_array_free (argv, TRUE);
+
+  genmarshal_stdout = g_io_channel_unix_new (child_stdout);
+  if (!g_io_channel_set_encoding (genmarshal_stdout, NULL, error))
+    goto io_lose;
+
+  WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
+
+  while ((iostatus = g_io_channel_read_chars (genmarshal_stdout, buf, sizeof (buf),
+                                             &bytes_read, error)) == G_IO_STATUS_NORMAL)
+    if (g_io_channel_write_chars (channel, buf, bytes_read, &bytes_written, error) != G_IO_STATUS_NORMAL)
+      goto io_lose;
+  if (iostatus != G_IO_STATUS_EOF)
+    goto io_lose;
+
+  g_io_channel_close (genmarshal_stdout);
+
+  WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n");
+
+  g_io_channel_ref (data.channel);
+  data.channel = channel;
+  if (!generate_glue (info, &data, error))
+    goto io_lose;
+  
+  ret = TRUE;
+ cleanup:
+  if (tempfile_name)
+    unlink (tempfile_name);
+  g_free (tempfile_name);
+  if (genmarshal_stdout)
+    g_io_channel_unref (genmarshal_stdout);
+  if (data.channel)
+    g_io_channel_unref (data.channel);
+  g_hash_table_destroy (data.generated);
+
+  return ret;
+ io_lose:
+  ret = FALSE;
+  goto cleanup;
+}
+
+static char *
+iface_to_c_prefix (const char *iface)
+{
+  char **components;
+  char **component;
+  GString *ret;
+  gboolean first;
+  
+  components = g_strsplit (iface, ".", 0);
+
+  first = TRUE;
+  ret = g_string_new ("");
+  for (component = components; *component; component++)
+    {
+      if (!first)
+       g_string_append_c (ret, '_');
+      else
+       first = FALSE;
+      g_string_append (ret, *component);
+    }
+  g_strfreev (components);
+  return g_string_free (ret, FALSE);
+}
+
+static char *
+compute_client_method_name (InterfaceInfo *iface, MethodInfo *method)
+{
+  GString *ret;
+  char *method_name_uscored;
+  char *iface_prefix;
+
+  iface_prefix = iface_to_c_prefix (interface_info_get_name (iface));
+  ret = g_string_new (iface_prefix);
+  g_free (iface_prefix);
+  
+  method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
+  g_string_append_c (ret, '_');
+  g_string_append (ret, method_name_uscored);
+  g_free (method_name_uscored);
+  return g_string_free (ret, FALSE);
+}
+
+static gboolean
+write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
+{
+  GSList *args;
+
+  for (args = method_info_get_args (method); args; args = args->next)
+    {
+      ArgInfo *arg;
+      const char *type_str;
+      int direction;
+
+      arg = args->data;
+
+      WRITE_OR_LOSE (", ");
+
+      direction = arg_info_get_direction (arg);
+
+      /* FIXME - broken for containers */
+      type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN);
+
+      if (!type_str)
+       {
+         g_set_error (error,
+                      DBUS_BINDING_TOOL_ERROR,
+                      DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+                      _("Unsupported conversion from D-BUS type %d to glib C type"),
+                      arg_info_get_type (arg));
+         return FALSE;
+       }
+
+      switch (direction)
+       {
+       case ARG_IN:
+         if (!write_printf_to_iochannel ("%s IN_%s", channel, error,
+                                         type_str,
+                                         arg_info_get_name (arg)))
+           goto io_lose;
+         break;
+       case ARG_OUT:
+         if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error,
+                                         type_str,
+                                         arg_info_get_name (arg)))
+           goto io_lose;
+         break;
+       case ARG_INVALID:
+         break;
+       }
+    }
+
+  return TRUE;
+ io_lose:
+  return FALSE;
+}
+
+static gboolean
+write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
+{
+  GSList *args;
+
+  for (args = method_info_get_args (method); args; args = args->next)
+    {
+      ArgInfo *arg;
+      const char *type_str;
+
+      arg = args->data;
+
+      if (direction != arg_info_get_direction (arg))
+       continue;
+
+      /* FIXME - broken for containers */
+      type_str = dbus_gvalue_binding_type_from_type (arg_info_get_type (arg));
+      if (!type_str)
+       {
+         g_set_error (error,
+                      DBUS_BINDING_TOOL_ERROR,
+                      DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+                      _("Unsupported conversion from D-BUS type %c"),
+                      (char) arg_info_get_type (arg));
+         return FALSE;
+       }
+
+      
+      switch (direction)
+       {
+       case ARG_IN:
+         if (!write_printf_to_iochannel ("                                  %s, &IN_%s,\n", channel, error,
+                                         type_str, arg_info_get_name (arg)))
+           goto io_lose;
+         break;
+       case ARG_OUT:
+         if (!write_printf_to_iochannel ("                               %s, OUT_%s,\n", channel, error,
+                                         type_str, arg_info_get_name (arg)))
+           goto io_lose;
+         break;
+       case ARG_INVALID:
+         break;
+       }
+    }
+
+  return TRUE;
+ io_lose:
+  return FALSE;
+}
+
+static gboolean
+generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
+{
+  GSList *tmp;
+
+  tmp = list;
+  while (tmp != NULL)
+    {
+      if (!generate_client_glue (tmp->data, data, error))
+       return FALSE;
+      tmp = tmp->next;
+    }
+  return TRUE;
+}
+
+static gboolean
+generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
+{
+  if (base_info_get_type (base) == INFO_TYPE_NODE)
+    {
+      if (!generate_client_glue_list (node_info_get_nodes ((NodeInfo *) base),
+                                     data, error))
+       return FALSE;
+      if (!generate_client_glue_list (node_info_get_interfaces ((NodeInfo *) base),
+                                     data, error))
+       return FALSE;
+    }
+  else
+    {
+      GIOChannel *channel;
+      InterfaceInfo *interface;
+      GSList *methods;
+      GSList *tmp;
+      int count;
+
+      channel = data->channel;
+
+      interface = (InterfaceInfo *) base;
+
+      methods = interface_info_get_methods (interface);
+      count = 0;
+
+      for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
+        {
+          MethodInfo *method;
+         char *method_name;
+
+          method = (MethodInfo *) tmp->data;
+
+         method_name = compute_client_method_name (interface, method);
+
+         WRITE_OR_LOSE ("static gboolean\n");
+         if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error,
+                                         method_name))
+           goto io_lose;
+         g_free (method_name);
+
+         if (!write_formal_parameters (interface, method, channel, error))
+           goto io_lose;
+
+         WRITE_OR_LOSE (", GError **error)\n\n");
+         
+         WRITE_OR_LOSE ("{\n");
+         WRITE_OR_LOSE ("  gboolean ret;\n\n");
+         WRITE_OR_LOSE ("  DBusGPendingCall *call;\n\n");
+         
+         if (!write_printf_to_iochannel ("  call = dbus_g_proxy_begin_call (proxy, \"%s\",\n",
+                                         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 ("                                  DBUS_TYPE_INVALID);\n");
+         WRITE_OR_LOSE ("  ret = dbus_g_proxy_end_call (proxy, call, error,\n");
+         
+         if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
+           goto io_lose;
+
+         WRITE_OR_LOSE ("                               DBUS_TYPE_INVALID);\n");
+
+         WRITE_OR_LOSE ("  dbus_g_pending_call_unref (call);\n");
+         WRITE_OR_LOSE ("  return ret;\n");
+
+         WRITE_OR_LOSE ("}\n\n");
+       }
+    }
+  return TRUE;
+ io_lose:
+  return FALSE;
+}
+
+
+gboolean
+dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, GError **error)
+{
+  DBusBindingToolCData data;
+  gboolean ret;
+
+  memset (&data, 0, sizeof (data));
+  
+  data.channel = channel;
+
+  WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
+  WRITE_OR_LOSE ("#include <glib/gtypes.h>\n");
+  WRITE_OR_LOSE ("#include <glib/gerror.h>\n");
+  WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n\n");
+
+  ret = generate_client_glue (info, &data, error);
+
+  return ret;
+ io_lose:
+  return FALSE;
+}
diff --git a/glib/dbus-binding-tool-glib.h b/glib/dbus-binding-tool-glib.h
new file mode 100644 (file)
index 0000000..d4589bc
--- /dev/null
@@ -0,0 +1,33 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-binding-tool-output-glib.h prototypes for glib output
+ *
+ * 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_BINDING_TOOL_OUTPUT_GLIB_H
+#define DBUS_BINDING_TOOL_OUTPUT_GLIB_H
+
+G_BEGIN_DECLS
+
+gboolean dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, GError **error);
+gboolean dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, GError **error);
+
+G_END_DECLS
+
+#endif
index ec87414d8c68fe7b4e1bb56ff3feb1bd5f0cf8c1..554e18c36a1ce8a191a76f18a7a98f1cd109fcea 100644 (file)
@@ -43,6 +43,7 @@ struct NodeInfo
 struct InterfaceInfo
 {
   BaseInfo base;
+  GHashTable *bindings;
   /* Since we have BaseInfo now these could be one list */
   GSList *methods;
   GSList *signals;
@@ -52,6 +53,7 @@ struct InterfaceInfo
 struct MethodInfo
 {
   BaseInfo base;
+  GHashTable *bindings;
   GSList *args;
 };
 
@@ -75,6 +77,23 @@ struct ArgInfo
   ArgDirection direction;
 };
 
+static void
+get_hash_key (gpointer key, gpointer value, gpointer data)
+{
+  GSList **list = data;
+  *list = g_slist_prepend (*list, key);
+}
+
+static GSList *
+get_hash_keys (GHashTable *table)
+{
+  GSList *ret = NULL;
+
+  g_hash_table_foreach (table, get_hash_key, &ret);
+
+  return ret;
+}
+
 BaseInfo *
 base_info_ref (BaseInfo *info)
 {
@@ -326,6 +345,9 @@ interface_info_new (const char *name)
   info->base.refcount = 1;
   info->base.name = g_strdup (name);
   info->base.type = INFO_TYPE_INTERFACE;
+  info->bindings = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                         (GDestroyNotify) g_free,
+                                         (GDestroyNotify) g_free);
   
   return info;
 }
@@ -344,6 +366,7 @@ interface_info_unref (InterfaceInfo *info)
   info->base.refcount -= 1;
   if (info->base.refcount == 0)
     {
+      g_hash_table_destroy (info->bindings);
       free_method_list (&info->methods);
       free_signal_list (&info->signals);
       free_property_list (&info->properties);
@@ -357,6 +380,19 @@ interface_info_get_name (InterfaceInfo *info)
   return info->base.name;
 }
 
+GSList *
+interface_info_get_binding_names (InterfaceInfo *info)
+{
+  return get_hash_keys (info->bindings);
+}
+
+const char*
+interface_info_get_binding_name (InterfaceInfo *info,
+                                const char    *binding_type)
+{
+  return g_hash_table_lookup (info->bindings, binding_type);
+}
+
 GSList*
 interface_info_get_methods (InterfaceInfo *info)
 {
@@ -375,6 +411,16 @@ interface_info_get_properties (InterfaceInfo *info)
   return info->properties;
 }
 
+void
+interface_info_set_binding_name (InterfaceInfo *info,
+                                const char    *binding_type,
+                                const char    *bound_name)
+{
+  g_hash_table_insert (info->bindings,
+                      g_strdup (binding_type),
+                      g_strdup (bound_name));
+}
+
 void
 interface_info_add_method (InterfaceInfo *info,
                            MethodInfo    *method)
@@ -424,6 +470,9 @@ method_info_new (const char *name)
   info->base.refcount = 1;
   info->base.name = g_strdup (name);
   info->base.type = INFO_TYPE_METHOD;
+  info->bindings = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                         (GDestroyNotify) g_free,
+                                         (GDestroyNotify) g_free);
   
   return info;
 }
@@ -442,6 +491,7 @@ method_info_unref (MethodInfo *info)
   info->base.refcount -= 1;
   if (info->base.refcount == 0)
     {
+      g_hash_table_destroy (info->bindings);
       free_arg_list (&info->args);
       base_info_free (info);
     }
@@ -453,6 +503,19 @@ method_info_get_name (MethodInfo *info)
   return info->base.name;
 }
 
+GSList *
+method_info_get_binding_names (MethodInfo *info)
+{
+  return get_hash_keys (info->bindings);
+}
+
+const char*
+method_info_get_binding_name (MethodInfo *info,
+                             const char *binding_type)
+{
+  return g_hash_table_lookup (info->bindings, binding_type);
+}
+
 GSList*
 method_info_get_args (MethodInfo *info)
 {
@@ -480,6 +543,16 @@ args_sort_by_direction (const void *a,
     return 1;
 }                  
 
+void
+method_info_set_binding_name (MethodInfo  *info,
+                             const char  *binding_type,
+                             const char  *bound_name)
+{
+  g_hash_table_insert (info->bindings,
+                      g_strdup (binding_type),
+                      g_strdup (bound_name));
+}
+
 void
 method_info_add_arg (MethodInfo    *info,
                      ArgInfo       *arg)
index a706c4d5e211cc47a1a8f0745ffa0bb7417eaa07..917432ee06dd0d03b10c550c98e1068f49ba82dd 100644 (file)
@@ -90,19 +90,31 @@ InterfaceInfo*      interface_info_new            (const char          *name);
 InterfaceInfo*      interface_info_ref            (InterfaceInfo       *info);
 void                interface_info_unref          (InterfaceInfo       *info);
 const char*         interface_info_get_name       (InterfaceInfo       *info);
+GSList*             interface_info_get_binding_names(InterfaceInfo     *info);
+const char*         interface_info_get_binding_name(InterfaceInfo*info,
+                                                   const char         *binding_type);
 GSList*             interface_info_get_methods    (InterfaceInfo       *info);
 GSList*             interface_info_get_signals    (InterfaceInfo       *info);
 GSList*             interface_info_get_properties (InterfaceInfo       *info);
+void                interface_info_set_binding_name(InterfaceInfo      *info,
+                                                   const char         *name,
+                                                   const char         *value);
 void                interface_info_add_method     (InterfaceInfo       *info,
                                                    MethodInfo          *method);
 void                interface_info_add_signal     (InterfaceInfo       *info,
                                                    SignalInfo          *signal);
 void                interface_info_add_property   (InterfaceInfo       *info,
                                                    PropertyInfo        *property);
-MethodInfo*         method_info_new               (const char          *name);
+MethodInfo*         method_info_new               (const char          *name); 
 MethodInfo*         method_info_ref               (MethodInfo          *info);
 void                method_info_unref             (MethodInfo          *info);
 const char*         method_info_get_name          (MethodInfo          *info);
+GSList*             method_info_get_binding_names (MethodInfo          *info);
+const char*         method_info_get_binding_name  (MethodInfo          *info,
+                                                  const char          *binding_type);
+void                method_info_set_binding_name  (MethodInfo          *info,
+                                                  const char          *binding_type,
+                                                  const char          *bound_name);
 GSList*             method_info_get_args          (MethodInfo          *info);
 void                method_info_add_arg           (MethodInfo          *info,
                                                    ArgInfo             *arg);
index c8273afaf8e44ce0291757cc4a12d0403a6f242b..022055e6b2d6f86b9b75f87d4177c8c9a31c4c68 100644 (file)
@@ -25,6 +25,7 @@
 #include "dbus-gidl.h"
 #include "dbus-gparser.h"
 #include "dbus-gutils.h"
+#include "dbus-binding-tool-glib.h"
 #include <locale.h>
 #include <libintl.h>
 #define _(x) dgettext (GETTEXT_PACKAGE, x)
 static void run_all_tests (const char *test_data_dir);
 #endif
 
+typedef enum {
+  DBUS_BINDING_OUTPUT_NONE,
+  DBUS_BINDING_OUTPUT_PRETTY,
+  DBUS_BINDING_OUTPUT_GLIB_SERVER,
+  DBUS_BINDING_OUTPUT_GLIB_CLIENT,
+} DBusBindingOutputMode;
+
 static void
 indent (int depth)
 {
@@ -99,11 +107,23 @@ pretty_print (BaseInfo *base,
     case INFO_TYPE_INTERFACE:
       {
         InterfaceInfo *i = (InterfaceInfo*) base;
+       GSList *binding_types, *elt;
 
         g_assert (name != NULL);
 
         printf (_("interface \"%s\" {\n"), name);
 
+       binding_types = interface_info_get_binding_names (i);
+       for (elt = binding_types; elt; elt = elt->next)
+         {
+           const char *binding_type = elt->data;
+           const char *binding_name = interface_info_get_binding_name (i, binding_type);
+
+           printf (_(" (binding \"%s\": \"%s\") "),
+                   binding_type, binding_name);
+         }
+       g_slist_free (binding_types);
+
         pretty_print_list (interface_info_get_methods (i), depth + 1);
         pretty_print_list (interface_info_get_signals (i), depth + 1);
         pretty_print_list (interface_info_get_properties (i), depth + 1);
@@ -115,10 +135,21 @@ pretty_print (BaseInfo *base,
     case INFO_TYPE_METHOD:
       {
         MethodInfo *m = (MethodInfo*) base;
+       GSList *binding_types, *elt;
 
         g_assert (name != NULL);
 
-        printf (_("method \"%s\" (\n"), name);
+       binding_types = method_info_get_binding_names (m);
+        printf (_("method \"%s\""), name);
+       for (elt = binding_types; elt; elt = elt->next)
+         {
+           const char *binding_type = elt->data;
+           const char *binding_name = method_info_get_binding_name (m, binding_type);
+
+           printf (_(" (binding \"%s\": \"%s\") "),
+                   binding_type, binding_name);
+         }
+       g_slist_free (binding_types);
 
         pretty_print_list (method_info_get_args (m), depth + 1);
 
@@ -174,6 +205,16 @@ pretty_print (BaseInfo *base,
     }
 }
 
+GQuark
+dbus_binding_tool_error_quark (void)
+{
+  static GQuark quark = 0;
+  if (!quark)
+    quark = g_quark_from_static_string ("dbus_binding_tool_error");
+
+  return quark;
+}
+
 static void
 usage (int ecode)
 {
@@ -186,7 +227,7 @@ version (void)
 {
   printf ("D-BUS Binding Tool %s\n"
           "Copyright (C) 2003-2005 Red Hat, Inc.\n"
-          "This is free software; xsee the source for copying conditions.\n"
+          "This is free software; see the source for copying conditions.\n"
           "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
           VERSION);
   exit (0);
@@ -198,16 +239,20 @@ main (int argc, char **argv)
   const char *prev_arg;
   int i;
   GSList *files;
+  DBusBindingOutputMode outputmode;
   gboolean end_of_args;
   GSList *tmp;
-  gboolean just_pretty_print;
+  GIOChannel *channel;
+  GError *error;
 
   setlocale (LC_ALL, "");
   bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR);
   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
   textdomain (GETTEXT_PACKAGE); 
 
-  just_pretty_print = FALSE;
+  g_type_init ();
+
+  outputmode = DBUS_BINDING_OUTPUT_NONE;
   end_of_args = FALSE;
   files = NULL;
   prev_arg = NULL;
@@ -228,8 +273,18 @@ main (int argc, char **argv)
           else if (strcmp (arg, "--self-test") == 0)
             run_all_tests (NULL);
 #endif /* DBUS_BUILD_TESTS */
-          else if (strcmp (arg, "--pretty-print") == 0)
-            just_pretty_print = TRUE;
+          else if (strncmp (arg, "--mode=", 7) == 0)
+            {
+             const char *mode = arg + 7;
+             if (!strcmp (mode, "pretty"))
+               outputmode = DBUS_BINDING_OUTPUT_PRETTY;
+             else if (!strcmp (mode, "glib-server"))
+               outputmode = DBUS_BINDING_OUTPUT_GLIB_SERVER;
+             else if (!strcmp (mode, "glib-client"))
+               outputmode = DBUS_BINDING_OUTPUT_GLIB_CLIENT;
+             else
+               usage (1);
+           }
           else if (arg[0] == '-' &&
                    arg[1] == '-' &&
                    arg[2] == '\0')
@@ -251,6 +306,15 @@ main (int argc, char **argv)
       ++i;
     }
 
+  error = NULL;
+  channel = g_io_channel_unix_new (fileno (stdout));
+  if (!g_io_channel_set_encoding (channel, NULL, &error))
+    {
+      fprintf (stderr, _("Couldn't set channel encoding to NULL: %s\n"),
+              error->message);
+      exit (1);
+    }
+
   files = g_slist_reverse (files);
 
   tmp = files;
@@ -273,27 +337,43 @@ main (int argc, char **argv)
           g_error_free (error);
           exit (1);
         }
-      else if (just_pretty_print)
-        {
-          pretty_print ((BaseInfo*) node, 0);
-        }
       else
-        {
-          /* FIXME process the file to generate metadata variable
-           * definition rather than just printing it.
-           * i.e. we want to create DBusGObjectInfo.
-           * This probably requires extending the introspection XML format to
-           * allow a "native function name":
-           *  <method name="Frobate" native="my_object_frobate">
-           */
-          pretty_print ((BaseInfo*) node, 0);
-        }
+       {
+         switch (outputmode)
+           {
+           case DBUS_BINDING_OUTPUT_PRETTY:
+             pretty_print ((BaseInfo*) node, 0);
+             break;
+           case DBUS_BINDING_OUTPUT_GLIB_SERVER:
+             if (!dbus_binding_tool_output_glib_server ((BaseInfo *) node, channel, &error))
+               {
+                 g_error (_("Compilation failed: %s\n"), error->message);
+                 exit (1);
+               }
+             break;
+           case DBUS_BINDING_OUTPUT_GLIB_CLIENT:
+             if (!dbus_binding_tool_output_glib_client ((BaseInfo *) node, channel, &error))
+               {
+                 g_error (_("Compilation failed: %s\n"), error->message);
+                 exit (1);
+               }
+             break;
+           case DBUS_BINDING_OUTPUT_NONE:
+             break;
+           }
+       }
 
       if (node)
         node_info_unref (node);
       
       tmp = tmp->next;
     }
+
+  if (!g_io_channel_flush (channel, &error))
+    {
+      g_error (_("Failed to flush IO channel: %s"), error->message);
+      exit (1);
+    }
   
   return 0;
 }
diff --git a/glib/dbus-glib-tool.h b/glib/dbus-glib-tool.h
new file mode 100644 (file)
index 0000000..b56d764
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-glib-tool.h: Definitions used internally by binding tool
+ *             
+ * 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_BINDING_TOOL_H
+#define DBUS_BINDING_TOOL_H
+
+#include <glib/gquark.h>
+
+typedef enum
+{
+  DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION
+} DBusBindingToolError;
+
+#define DBUS_BINDING_TOOL_ERROR dbus_binding_tool_error_quark ()
+
+GQuark dbus_binding_tool_error_quark (void);
+
+#endif
index abaf2e0eacdca6333f5cc94003035d690233481c..3bcd90d5f9cc307b5c70b066aa6b0026cf57ba2c 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus-gobject.c Exporting a GObject remotely
  *
- * Copyright (C) 2003, 2004 Red Hat, Inc.
+ * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
  *
  * Licensed under the Academic Free License version 2.1
  *
@@ -26,6 +26,7 @@
 #include <dbus/dbus-glib-lowlevel.h>
 #include "dbus-gtest.h"
 #include "dbus-gutils.h"
+#include "dbus-gobject.h"
 #include "dbus-gvalue.h"
 #include <string.h>
 
  * @{
  */
 
-static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT;
+static GStaticRWLock info_hash_lock = G_STATIC_RW_LOCK_INIT;
 static GHashTable *info_hash = NULL;
 
-static char*
-wincaps_to_uscore (const char *caps)
-{
-  const char *p;
-  GString *str;
-
-  str = g_string_new (NULL);
-  p = caps;
-  while (*p)
-    {
-      if (g_ascii_isupper (*p))
-        {
-          if (str->len > 0 &&
-              (str->len < 2 || str->str[str->len-2] != '_'))
-            g_string_append_c (str, '_');
-          g_string_append_c (str, g_ascii_tolower (*p));
-        }
-      else
-        {
-          g_string_append_c (str, *p);
-        }
-      ++p;
-    }
-
-  return g_string_free (str, FALSE);
-}
-
 static char*
 uscore_to_wincaps (const char *uscore)
 {
@@ -97,6 +71,164 @@ uscore_to_wincaps (const char *uscore)
   return g_string_free (str, FALSE);
 }
 
+static const char *
+string_table_next (const char *table)
+{
+  return (table + (strlen (table) + 1));
+}
+
+static const char *
+string_table_lookup (const char *table, int index)
+{
+  const char *ret;
+
+  ret = table;
+
+  while (index--)
+    ret = string_table_next (ret);
+
+  return ret;
+}
+
+static const char *
+get_method_data (const DBusGObjectInfo *object,
+                const DBusGMethodInfo *method)
+{
+  return object->data + method->data_offset;
+}
+
+static char *
+object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
+{
+  /* FIXME */
+  return NULL;
+}
+
+static char *
+object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
+{
+  /* FIXME */
+  return NULL;
+}
+
+static const char *
+method_interface_from_object_info (const DBusGObjectInfo *object,
+                             const DBusGMethodInfo *method)
+{
+  return string_table_lookup (get_method_data (object, method), 0);
+}
+
+static const char *
+method_name_from_object_info (const DBusGObjectInfo *object,
+                             const DBusGMethodInfo *method)
+{
+  return string_table_lookup (get_method_data (object, method), 1);
+}
+
+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);
+}
+
+static const char *
+arg_iterate (const char *data, const char **name, gboolean *in,
+            const char **type)
+{
+  *name = data;
+
+  data = string_table_next (data);
+  switch (*data)
+    {
+    case 'I':
+      *in = TRUE;
+      break;
+    case 'O':
+      *in = FALSE;
+      break;
+    default:
+      g_warning ("invalid arg direction");
+      break;
+    }
+  
+  data = string_table_next (data);
+  *type = data;
+
+  return string_table_next (data);
+}
+
+static char *
+method_dir_signature_from_object_info (const DBusGObjectInfo *object,
+                                      const DBusGMethodInfo *method,
+                                      gboolean               in)
+{
+  const char *arg;
+  GString *ret;
+
+  arg = method_arg_info_from_object_info (object, method);
+
+  ret = g_string_new (NULL);
+
+  while (*arg)
+    {
+      const char *name;
+      gboolean arg_in;
+      const char *type;
+
+      arg = arg_iterate (arg, &name, &arg_in, &type);
+
+      if (arg_in == in)
+       g_string_append (ret, type);
+    }
+
+  return g_string_free (ret, FALSE);
+}
+
+static char *
+method_input_signature_from_object_info (const DBusGObjectInfo *object,
+                                        const DBusGMethodInfo *method)
+{
+  return method_dir_signature_from_object_info (object, method, TRUE);
+}
+
+static char *
+method_output_signature_from_object_info (const DBusGObjectInfo *object,
+                                         const DBusGMethodInfo *method)
+{
+  return method_dir_signature_from_object_info (object, method, FALSE);
+}
+
+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)
@@ -272,6 +404,115 @@ introspect_signals (GType type, GString *xml)
   g_string_append (xml, "  </interface>\n");
 }
 
+typedef struct
+{
+  GString *xml;
+  const DBusGObjectInfo *object_info;
+} DBusGlibWriteIterfaceData;
+
+static void
+write_interface (gpointer key, gpointer val, gpointer user_data)
+{
+  const char *name;
+  GSList *methods;
+  GString *xml;
+  const DBusGObjectInfo *object_info;
+  DBusGlibWriteIterfaceData *data;
+
+  name = key;
+  methods = val;
+  data = user_data;
+  xml = data->xml;
+  object_info = data->object_info;
+
+  g_string_append_printf (xml, "  <interface name=\"%s\">\n", name);
+
+  /* FIXME: recurse to parent types ? */
+  for (; methods; methods = methods->next)
+    {
+      DBusGMethodInfo *method;
+      method = methods->data;
+      const char *args;
+
+      g_string_append_printf (xml, "    <method name=\"%s\">\n",
+                             method_name_from_object_info (object_info, method));
+
+      args = method_arg_info_from_object_info (object_info, method);
+
+      while (*args)
+       {
+         const char *name;
+         gboolean arg_in;
+         const char *type;
+         
+         args = arg_iterate (args, &name, &arg_in, &type);
+
+         /* FIXME - handle container types */
+         g_string_append_printf (xml, "      <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
+                                 name, _dbus_gutils_type_to_string (type[0]), arg_in ? "in" : "out");
+
+       }
+      g_string_append (xml, "    </method>\n");
+    }
+
+  g_string_append (xml, "  </interface>\n");
+}
+
+static void
+introspect_interfaces (GObject *object, GString *xml)
+{
+  GType classtype;
+
+  g_static_rw_lock_reader_lock (&info_hash_lock);
+
+  for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
+    {
+      const DBusGObjectInfo *info;
+      DBusGlibWriteIterfaceData data;
+
+      info = g_hash_table_lookup (info_hash,
+                                 g_type_class_peek (classtype));
+
+      if (info != NULL && info->format_version == 0)
+       {
+         int i;
+         GHashTable *interfaces;
+
+         /* Gather a list of all interfaces, indexed into their methods */
+         interfaces = g_hash_table_new (g_str_hash, g_str_equal);
+         for (i = 0; i < info->n_infos; i++)
+           {
+             const char *method_name;
+             const char *method_interface;
+             const char *method_args;
+             const DBusGMethodInfo *method;
+             GSList *methods;
+
+             method = &(info->infos[i]);
+
+             method_interface = method_interface_from_object_info (info, method);
+             method_name = method_name_from_object_info (info, method);
+             method_args = method_arg_info_from_object_info (info, method);
+
+             if ((methods = g_hash_table_lookup (interfaces, method_interface)) == NULL)
+                 methods = g_slist_prepend (NULL, (gpointer) method);
+             else
+                 methods = g_slist_prepend (methods, (gpointer) method);
+             g_hash_table_insert (interfaces, (gpointer) method_interface, methods);
+           }
+
+         memset (&data, 0, sizeof (data));
+         data.xml = xml;
+         data.object_info = info;
+         g_hash_table_foreach (interfaces, write_interface, &data);
+
+         g_hash_table_destroy (interfaces);
+       }
+    }
+
+  g_static_rw_lock_reader_lock (&info_hash_lock);
+}
+
 static DBusHandlerResult
 handle_introspect (DBusConnection *connection,
                    DBusMessage    *message,
@@ -316,6 +557,7 @@ handle_introspect (DBusConnection *connection,
   
   introspect_signals (G_OBJECT_TYPE (object), xml);
   introspect_properties (object, xml);
+  introspect_interfaces (object, xml);
 
   /* Append child nodes */
   for (i = 0; children[i]; i++)
@@ -392,7 +634,7 @@ get_object_property (DBusConnection *connection,
                      GParamSpec     *pspec)
 {
   GType value_type;
-  GValue value;
+  GValue value = {0, };
   DBusMessage *ret;
   DBusMessageIter iter;
 
@@ -420,12 +662,275 @@ get_object_property (DBusConnection *connection,
   return ret;
 }
 
+static gboolean
+lookup_object_and_method (GObject      *object,
+                         DBusMessage  *message,
+                         const DBusGObjectInfo **object_ret,
+                         const DBusGMethodInfo **method_ret)
+{
+  GType classtype;
+  const char *interface;
+  const char *member;
+  const char *signature;
+  gboolean ret;
+
+  interface = dbus_message_get_interface (message);
+  member = dbus_message_get_member (message);
+  signature = dbus_message_get_signature (message);
+  ret = FALSE;
+
+  g_static_rw_lock_reader_lock (&info_hash_lock);
+
+  if (!info_hash)
+    goto out;
+  
+  for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
+    {
+      const DBusGObjectInfo *info;
+
+      info = g_hash_table_lookup (info_hash,
+                                 g_type_class_peek (classtype));
+
+      *object_ret = info;
+
+      if (info != NULL && info->format_version == 0)
+       {
+         int i;
+         for (i = 0; i < info->n_infos; i++)
+           {
+             const char *expected_member;
+             const char *expected_interface;
+             char *expected_signature;
+             const DBusGMethodInfo *method;
+
+             method = &(info->infos[i]);
+
+             /* Check method interface/name and input signature */ 
+             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
+                 && strcmp (expected_signature, signature) == 0)
+               {
+                 g_free (expected_signature);
+                 *method_ret = method;
+                 ret = TRUE;
+                 goto out;
+               }
+             g_free (expected_signature);
+           }
+       }
+    }
+ out:
+  g_static_rw_lock_reader_lock (&info_hash_lock);
+  return ret;
+}
+
+static char *
+gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
+                                     GQuark domain, gint code)
+{
+  const char *domain_str;
+  const char *code_str;
+  GString *dbus_error_name;
+
+  domain_str = object_error_domain_prefix_from_object_info (object_info);
+  code_str = object_error_code_from_object_info (object_info, domain, code);
+
+  if (!domain_str || !code_str)
+    {
+      /* If we can't map it sensibly, make up an error name */
+      char *domain_from_quark;
+      
+      dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
+
+      domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
+      g_string_append (dbus_error_name, domain_from_quark);
+      g_free (domain_from_quark);
+       
+      g_string_append_printf (dbus_error_name, ".Code%d", code);
+    }
+  else
+    {
+      dbus_error_name = g_string_new (domain_str);
+      g_string_append_c (dbus_error_name, '.');
+      g_string_append (dbus_error_name, code_str);
+    }
+
+  return g_string_free (dbus_error_name, FALSE);
+}
+
+static DBusMessage *
+gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
+                             DBusMessage     *message,
+                             GError          *error)
+{
+  DBusMessage *reply;
+
+  if (!error)
+    {
+      char *error_msg;
+      
+      error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
+      reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
+      g_free (error_msg);
+    }
+  else
+    {
+      char *error_name;
+      error_name = gerror_domaincode_to_dbus_error_name (object_info, error->domain, error->code);
+      reply = dbus_message_new_error (message, error_name, error->message);
+      g_free (error_name); 
+    }
+  return reply;
+}
+
+static DBusHandlerResult
+invoke_object_method (GObject         *object,
+                     const DBusGObjectInfo *object_info,
+                     const DBusGMethodInfo *method,
+                     DBusConnection  *connection,
+                     DBusMessage     *message)
+{
+  gboolean had_error;
+  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;
+  DBusHandlerResult result;
+  DBusMessage *reply;
+
+  gerror = NULL;
+
+  /* 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));
+  
+  /* 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);
+
+  /* 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);
+
+  out_signature = method_output_signature_from_object_info (object_info, method); 
+  out_signature_len = strlen (out_signature);
+
+  /* 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++)
+    {
+      GValue value = {0, };
+      DBusBasicGValue basic;
+
+      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)));
+      g_value_array_append (value_array, &value);
+    }
+
+  /* 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);
+  had_error = !g_value_get_boolean (&return_value);
+
+  if (!had_error)
+    {
+      DBusMessageIter iter;
+
+      reply = dbus_message_new_method_return (message);
+      if (reply == NULL)
+       goto nomem;
+
+      /* Append OUT arguments to reply */
+      dbus_message_iter_init_append (reply, &iter);
+      for (i = 0; i < out_signature_len; i++)
+       {
+         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;
+         
+       }
+    }
+  else
+    reply = gerror_to_dbus_error_message (object_info, message, gerror);
+
+  if (reply)
+    {
+      dbus_connection_send (connection, reply, NULL);
+      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 (out_signature);
+  g_array_free (out_param_values, TRUE);
+  g_value_array_free (value_array);
+  g_value_unset (&object_value);
+  g_value_unset (&error_value);
+  g_value_unset (&return_value);
+  return result;
+ nomem:
+  result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+  goto done;
+}
+
 static DBusHandlerResult
 gobject_message_function (DBusConnection  *connection,
                           DBusMessage     *message,
                           void            *user_data)
 {
-  const DBusGObjectInfo *info;
   GParamSpec *pspec;
   GObject *object;
   gboolean setter;
@@ -434,6 +939,8 @@ gobject_message_function (DBusConnection  *connection,
   const char *wincaps_propname;
   /* const char *wincaps_propiface; */
   DBusMessageIter iter;
+  const DBusGMethodInfo *method;
+  const DBusGObjectInfo *object_info;
 
   object = G_OBJECT (user_data);
 
@@ -441,23 +948,10 @@ gobject_message_function (DBusConnection  *connection,
                                    DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
                                    "Introspect"))
     return handle_introspect (connection, message, object);
-
+  
   /* Try the metainfo, which lets us invoke methods */
-
-  g_static_mutex_lock (&info_hash_mutex);
-  /* FIXME this needs to walk up the inheritance tree, not
-   * just look at the most-derived class
-   */
-  info = g_hash_table_lookup (info_hash,
-                              G_OBJECT_GET_CLASS (object));
-  g_static_mutex_unlock (&info_hash_mutex);
-
-  if (info != NULL)
-    {
-
-
-
-    }
+  if (lookup_object_and_method (object, message, &object_info, &method))
+    return invoke_object_method (object, object_info, method, connection, message);
 
   /* If no metainfo, we can still do properties and signals
    * via standard GLib introspection
@@ -497,7 +991,7 @@ gobject_message_function (DBusConnection  *connection,
   dbus_message_iter_get_basic (&iter, &wincaps_propname);
   dbus_message_iter_next (&iter);
   
-  s = wincaps_to_uscore (wincaps_propname);
+  s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
 
   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
                                         s);
@@ -577,7 +1071,7 @@ dbus_g_object_class_install_info (GObjectClass          *object_class,
 {
   g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
 
-  g_static_mutex_lock (&info_hash_mutex);
+  g_static_rw_lock_writer_lock (&info_hash_lock);
 
   if (info_hash == NULL)
     {
@@ -586,7 +1080,7 @@ dbus_g_object_class_install_info (GObjectClass          *object_class,
 
   g_hash_table_replace (info_hash, object_class, (void*) info);
 
-  g_static_mutex_unlock (&info_hash_mutex);
+  g_static_rw_lock_writer_unlock (&info_hash_lock);
 }
 
 /**
@@ -652,7 +1146,7 @@ _dbus_gobject_test (const char *test_data_dir)
       char *uscore;
       char *wincaps;
 
-      uscore = wincaps_to_uscore (name_pairs[i].wincaps);
+      uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
       wincaps = uscore_to_wincaps (name_pairs[i].uscore);
 
       if (strcmp (uscore, name_pairs[i].uscore) != 0)
diff --git a/glib/dbus-gobject.h b/glib/dbus-gobject.h
new file mode 100644 (file)
index 0000000..28bba5c
--- /dev/null
@@ -0,0 +1,35 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gobject.h: common functions used to map between D-BUS and GObject
+ *
+ * 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_GLIB_OBJECT_H
+#define DBUS_GLIB_OBJECT_H
+
+#include <dbus/dbus.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+GValueArray*       dbus_glib_marshal_dbus_message_to_gvalue_array (DBusMessage         *message);
+
+G_END_DECLS
+
+#endif
index 680d830ad77cabbe2ea89904e61681c13bd4c522..05136aa892a2e7f51f9bfb1a636fefd4aefa3bed 100644 (file)
@@ -308,6 +308,7 @@ parse_interface (Parser      *parser,
                  GError     **error)
 {
   const char *name;
+  const char *c_name;
   InterfaceInfo *iface;
   NodeInfo *top;
   
@@ -329,6 +330,7 @@ parse_interface (Parser      *parser,
   if (!locate_attributes (element_name, attribute_names,
                           attribute_values, error,
                           "name", &name,
+                          "c_name", &c_name,
                           NULL))
     return FALSE;
 
@@ -344,6 +346,8 @@ parse_interface (Parser      *parser,
   top = parser->node_stack->data;
   
   iface = interface_info_new (name);
+  if (c_name)
+    interface_info_set_binding_name (iface, "C", c_name);
   node_info_add_interface (top, iface);
   interface_info_unref (iface);
 
@@ -360,6 +364,7 @@ parse_method (Parser      *parser,
               GError     **error)
 {
   const char *name;
+  const char *c_name;
   MethodInfo *method;
   NodeInfo *top;
   
@@ -381,6 +386,7 @@ parse_method (Parser      *parser,
   if (!locate_attributes (element_name, attribute_names,
                           attribute_values, error,
                           "name", &name,
+                          "c_name", &c_name,
                           NULL))
     return FALSE;
 
@@ -396,6 +402,8 @@ parse_method (Parser      *parser,
   top = parser->node_stack->data;
   
   method = method_info_new (name);
+  if (c_name)
+    method_info_set_binding_name (method, "C", c_name);
   interface_info_add_method (parser->interface, method);
   method_info_unref (method);
 
index 17b76d93402928bde07a9fb5a97aa70fa48e81e3..364facf8e0e9ebc698f70cb151763fb397348d7e 100644 (file)
@@ -25,6 +25,7 @@
 #include "dbus-gutils.h"
 #include "dbus-gmarshal.h"
 #include "dbus-gvalue.h"
+#include "dbus-gobject.h"
 #include <string.h>
 
 /**
@@ -900,11 +901,8 @@ marshal_dbus_message_to_g_marshaller (GClosure     *closure,
    * marshaller.
    */
 #define MAX_SIGNATURE_ARGS 20
-  GValue expanded[MAX_SIGNATURE_ARGS];
-  int arg;
-  int i;
-  DBusMessageIter iter;
-  int dtype;
+  GValueArray *value_array;
+  GValue value = {0, };
   GSignalCMarshaller c_marshaller;
   DBusGProxy *proxy;
   DBusMessage *message;
@@ -924,44 +922,18 @@ marshal_dbus_message_to_g_marshaller (GClosure     *closure,
 
   g_return_if_fail (c_marshaller != NULL);
   
-  memset (&expanded[0], 0, sizeof (expanded));
-  
-  arg = 0;
-      
-  g_value_init (&expanded[arg], G_TYPE_FROM_INSTANCE (proxy));
-  g_value_set_instance (&expanded[arg], proxy);
-  ++arg;
-  
-  dbus_message_iter_init (message, &iter);
+  value_array = dbus_glib_marshal_dbus_message_to_gvalue_array (message);
+
+  g_return_if_fail (value_array != NULL);
   
-  while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
-    {
-      if (arg == MAX_SIGNATURE_ARGS)
-        {
-          g_warning ("Don't support more than %d signal args\n", MAX_SIGNATURE_ARGS);
-          goto out;
-        }
-      
-      if (!dbus_gvalue_demarshal (&iter, &expanded[arg]))
-        {
-          g_warning ("Unable to convert arg type %d to GValue to emit DBusGProxy signal", dtype);
-          goto out;
-        }
-      
-      ++arg;
-      dbus_message_iter_next (&iter);
-    }
+  g_value_init (&value, G_TYPE_FROM_INSTANCE (proxy));
+  g_value_set_instance (&value, proxy);
+  g_value_array_prepend (value_array, &value);
 
-  (* c_marshaller) (closure, return_value, arg, &expanded[0],
-                    invocation_hint, marshal_data);
+  (* c_marshaller) (closure, return_value, value_array->n_values,
+                   value_array->values, invocation_hint, marshal_data);
   
- out:
-  i = 0;
-  while (i < arg)
-    {
-      g_value_unset (&expanded[i]);
-      ++i;
-    }
+  g_value_array_free (value_array);
 }
 
 static void
index cf12245cc42c9302ba1c7c2fc8bc373a64c2f00d..30d00fedb6fc2447a9856b31028efc124d380320 100644 (file)
@@ -125,6 +125,34 @@ _dbus_gutils_type_to_string (int type)
     }
 }
 
+char*
+_dbus_gutils_wincaps_to_uscore (const char *caps)
+{
+  const char *p;
+  GString *str;
+
+  str = g_string_new (NULL);
+  p = caps;
+  while (*p)
+    {
+      if (g_ascii_isupper (*p))
+        {
+          if (str->len > 0 &&
+              (str->len < 2 || str->str[str->len-2] != '_'))
+            g_string_append_c (str, '_');
+          g_string_append_c (str, g_ascii_tolower (*p));
+        }
+      else
+        {
+          g_string_append_c (str, *p);
+        }
+      ++p;
+    }
+
+  return g_string_free (str, FALSE);
+}
+
+
 #ifdef DBUS_BUILD_TESTS
 
 /**
index fd2cac885e193f1068c1ff5de508a2f080072c3a..0356b30e81e13eacb8c0be6d208100821ec60edd 100644 (file)
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
 char      **_dbus_gutils_split_path     (const char *path);
 const char *_dbus_gutils_type_to_string (int         type);
 
+char       *_dbus_gutils_wincaps_to_uscore (const char *uscore);
 
 /* These munge the pointer to enforce that a plain cast won't work,
  * accessor functions must be used; i.e. to ensure the ABI
index e2bf40b2e9c3d568033c6089cf93d3be3ceff1bf..8306be9bcb856d2724ba770637bc8af5643dc465 100644 (file)
@@ -2,6 +2,7 @@
 /* dbus-gvalue.c GValue to-from DBusMessageIter
  *
  * Copyright (C) 2004 Ximian, Inc.
+ * Copyright (C) 2005 Red Hat, Inc.
  *
  * Licensed under the Academic Free License version 2.1
  * 
 
 #include <dbus-gvalue.h>
 
+/* This is slightly evil, we don't use g_value_set_foo() functions */
+#define MAP_BASIC_INIT(d_t, g_t)                                     \
+    case DBUS_TYPE_##d_t:                                       \
+      g_value_init (value, G_TYPE_##g_t);                       \
+      break
+
+gboolean
+dbus_gvalue_init      (int     type,
+                      GValue *value)
+{
+  gboolean can_convert;
+
+  can_convert = TRUE;
+
+  switch (type)
+    {
+      MAP_BASIC_INIT (BOOLEAN, BOOLEAN);
+      MAP_BASIC_INIT (BYTE,    UCHAR);
+      MAP_BASIC_INIT (INT32,   INT);
+      MAP_BASIC_INIT (UINT32,  UINT);
+      MAP_BASIC_INIT (INT64,   INT64);
+      MAP_BASIC_INIT (UINT64,  UINT64);
+      MAP_BASIC_INIT (DOUBLE,  DOUBLE);
+
+    case DBUS_TYPE_INT16:
+        g_value_init (value, G_TYPE_INT);
+      break;
+    case DBUS_TYPE_UINT16:
+        g_value_init (value, G_TYPE_UINT);
+      break;
+      
+    case DBUS_TYPE_STRING:
+    case DBUS_TYPE_OBJECT_PATH:
+    case DBUS_TYPE_SIGNATURE:
+        g_value_init (value, G_TYPE_STRING);
+      break;
+      
+    case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_ARRAY:
+    case DBUS_TYPE_VARIANT:
+    default:
+      can_convert = FALSE;
+    }
+#undef MAP_BASIC_INIT
+  return can_convert;
+}
+
+const char *
+dbus_gvalue_genmarshal_name_from_type (int type)
+{
+  switch (type)
+    {
+    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;
+    }
+  return NULL;
+}
+
+const char *
+dbus_gvalue_binding_type_from_type (int type)
+{
+#define STRINGIFY(x) \
+  case x: \
+    return (#x)
+  
+  switch (type)
+    {
+      STRINGIFY(DBUS_TYPE_BOOLEAN);
+      STRINGIFY(DBUS_TYPE_BYTE);
+      STRINGIFY(DBUS_TYPE_INT32);
+      STRINGIFY(DBUS_TYPE_UINT32);
+      STRINGIFY(DBUS_TYPE_INT64);
+      STRINGIFY(DBUS_TYPE_UINT64);
+      STRINGIFY(DBUS_TYPE_DOUBLE);
+    case DBUS_TYPE_INT16:
+      return "DBUS_TYPE_INT32";
+    case DBUS_TYPE_UINT16:
+      return "DBUS_TYPE_UINT32";
+    STRINGIFY(DBUS_TYPE_STRING);
+    STRINGIFY(DBUS_TYPE_OBJECT_PATH);
+    STRINGIFY(DBUS_TYPE_SIGNATURE);
+
+    case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_ARRAY:
+    case DBUS_TYPE_VARIANT:
+      return NULL;
+    }
+#undef STRINGIFY
+  return NULL;
+}
+
+const char *
+dbus_gvalue_ctype_from_type (int type, gboolean in)
+{
+  switch (type)
+    {
+    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 *";
+      else
+       return "char *";
+    case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_ARRAY:
+    case DBUS_TYPE_VARIANT:
+      return NULL;
+    }
+  return NULL;
+}
+
 gboolean
 dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
 {
   gboolean can_convert = TRUE;
 
-  /* This is slightly evil, we don't use g_value_set_foo() functions */
+  g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int));
+
+  dbus_gvalue_init (dbus_message_iter_get_arg_type (iter), value);
+  
+/* This is slightly evil, we don't use g_value_set_foo() functions */
 #define MAP_BASIC(d_t, g_t)                                     \
     case DBUS_TYPE_##d_t:                                       \
-      g_value_init (value, G_TYPE_##g_t);                       \
       dbus_message_iter_get_basic (iter, &value->data[0]);      \
       break
 
-  g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int));
-  
   switch (dbus_message_iter_get_arg_type (iter))
     {
       MAP_BASIC (BOOLEAN, BOOLEAN);
@@ -50,7 +209,6 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
     case DBUS_TYPE_INT16:
       {
         dbus_int16_t v;
-        g_value_init (value, G_TYPE_INT);
         dbus_message_iter_get_basic (iter, &v);
         g_value_set_int (value, v);
       }
@@ -58,7 +216,6 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
     case DBUS_TYPE_UINT16:
       {
         dbus_uint16_t v;
-        g_value_init (value, G_TYPE_UINT);
         dbus_message_iter_get_basic (iter, &v);
         g_value_set_uint (value, v);
       }
@@ -70,8 +227,6 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
       {
         const char *s;
 
-        g_value_init (value, G_TYPE_STRING);
-
         dbus_message_iter_get_basic (iter, &s);
         g_value_set_string (value, s);
       }
index fc45f7e067b0eabcb35da5a779cc378c79277f32..fafda5851a0095e01756c130ed3ab4ce8762bc93 100644 (file)
@@ -7,8 +7,32 @@
 
 G_BEGIN_DECLS
 
-gboolean dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value);
-gboolean dbus_gvalue_marshal   (DBusMessageIter *iter, GValue *value);
+/* 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;
+
+const char *   dbus_gvalue_genmarshal_name_from_type (int type);
+
+const char *   dbus_gvalue_ctype_from_type           (int type, gboolean in);
+
+const char *   dbus_gvalue_binding_type_from_type    (int type);
+
+gboolean       dbus_gvalue_init           (int              type,
+                                          GValue          *value);
+
+gboolean       dbus_gvalue_demarshal      (DBusMessageIter *iter,
+                                          GValue          *value);
+gboolean       dbus_gvalue_marshal        (DBusMessageIter *iter,
+                                          GValue          *value);
 
 
 G_END_DECLS
index a679bcc194ddc26e1d3c353f4257b3ca95f8698c..0a2462520e14a4c570d32ca16dacdf790419ec72 100644 (file)
@@ -40,7 +40,20 @@ test_dbus_glib_SOURCES=                              \
 test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
 
 test_service_glib_SOURCES=                             \
-       test-service-glib.c
+       test-service-glib.c                             \
+       test-service-glib-glue.h
+
+BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h
+
+test-service-glib-glue.h: $(top_builddir)/glib/dbus-binding-tool test-service-glib.xml
+       $(top_builddir)/glib/dbus-binding-tool --mode=glib-server $(srcdir)/test-service-glib.xml > test-service-glib-glue.h.tmp
+       mv test-service-glib-glue.h.tmp test-service-glib-glue.h
+
+test-service-glib-bindings.h: $(top_builddir)/glib/dbus-binding-tool test-service-glib.xml
+       $(top_builddir)/glib/dbus-binding-tool --mode=glib-client $(srcdir)/test-service-glib.xml > test-service-glib-bindings.h.tmp
+       mv test-service-glib-bindings.h.tmp test-service-glib-bindings.h
+
+CLEANFILES = test-service-glib-glue.h test-service-glib-glue.h.tmp test-service-glib-bindings.h test-service-glib-bindings.h.tmp
 
 test_service_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
 
index cee9316bbd9708f0a901aa0dcef7875f6c8947c0..ca36af1f3c1fc4a8ba835e5d18927f6e4fe9f849 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "test-service-glib-bindings.h"
 
 static GMainLoop *loop = NULL;
 static int n_times_foo_received = 0;
@@ -37,7 +38,11 @@ main (int argc, char **argv)
   int i;
   guint32 result;
   const char *v_STRING;
+  char *v_STRING_2;
   guint32 v_UINT32;
+  guint32 v_UINT32_2;
+  double v_DOUBLE;
+  double v_DOUBLE_2;
     
   g_type_init ();
   
@@ -220,10 +225,204 @@ main (int argc, char **argv)
                   n_times_foo_received);
       exit (1);
     }
-  
-  g_object_unref (G_OBJECT (driver));
+
+  /* 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))
+    {
+      g_printerr ("Failed to complete Activate call: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+
   g_object_unref (G_OBJECT (proxy));
+
+  proxy = dbus_g_proxy_new_for_name_owner (connection,
+                                           "org.freedesktop.DBus.TestSuiteGLibService",
+                                           "/org/freedesktop/DBus/Tests/MyTestObject",
+                                           "org.freedesktop.DBus.Tests.MyObject",
+                                           &error);
   
+  if (proxy == NULL)
+    {
+      g_printerr ("Failed to create proxy for name owner: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);      
+    }
+
+  call = dbus_g_proxy_begin_call (proxy, "DoNothing",
+                                  DBUS_TYPE_INVALID);
+  error = NULL;
+  if (!dbus_g_proxy_end_call (proxy, call, &error, DBUS_TYPE_INVALID))
+    {
+      g_printerr ("Failed to complete DoNothing call: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+
+  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))
+    {
+      g_printerr ("Failed to complete Increment call: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+
+  if (v_UINT32_2 != v_UINT32 + 1)
+    {
+      g_printerr ("Increment call returned %d, should be 43\n", v_UINT32_2);
+      exit (1);
+    }
+
+  call = dbus_g_proxy_begin_call (proxy, "ThrowError", DBUS_TYPE_INVALID);
+  error = NULL;
+  if (dbus_g_proxy_end_call (proxy, call, &error, DBUS_TYPE_INVALID) != FALSE)
+    {
+      g_printerr ("ThrowError call unexpectedly succeeded!\n");
+      exit (1);
+    }
+
+  g_print ("ThrowError failed (as expected) returned error: %s\n", error->message);
+  g_error_free (error);
+
+  v_STRING = "foobar";
+  call = dbus_g_proxy_begin_call (proxy, "Uppercase",
+                                 DBUS_TYPE_STRING, &v_STRING,
+                                 DBUS_TYPE_INVALID);
+  error = NULL;
+  if (!dbus_g_proxy_end_call (proxy, call, &error,
+                             DBUS_TYPE_STRING, &v_STRING_2,
+                             DBUS_TYPE_INVALID))
+    {
+      g_printerr ("Failed to complete Uppercase call: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+  if (strcmp ("FOOBAR", v_STRING_2) != 0)
+    {
+      g_printerr ("Uppercase call returned unexpected string %s\n", v_STRING_2);
+      exit (1);
+    }
+
+  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);
+  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_printerr ("Failed to complete ManyArgs call: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+  if (v_DOUBLE_2 < 55 || v_DOUBLE_2 > 56)
+    {
+      g_printerr ("ManyArgs call returned unexpected double value %f\n", v_DOUBLE_2);
+      exit (1);
+    }
+  if (strcmp ("BAZWHEE", v_STRING_2) != 0)
+    {
+      g_printerr ("ManyArgs call returned unexpected string %s\n", v_STRING_2);
+      exit (1);
+    }
+
+  if (!org_freedesktop_DBus_Tests_MyObject_do_nothing (proxy, &error))
+    {
+      g_printerr ("Failed to complete (wrapped) DoNothing call: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+
+  if (!org_freedesktop_DBus_Tests_MyObject_increment (proxy, 42, &v_UINT32_2, &error))
+    {
+      g_printerr ("Failed to complete (wrapped) Increment call: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+
+  if (v_UINT32_2 != 43)
+    {
+      g_printerr ("(wrapped) increment call returned %d, should be 43\n", v_UINT32_2);
+      exit (1);
+    }
+
+  if (org_freedesktop_DBus_Tests_MyObject_throw_error (proxy, &error) != FALSE)
+    {
+      g_printerr ("(wrapped) ThrowError call unexpectedly succeeded!\n");
+      exit (1);
+    }
+
+  g_print ("(wrapped) ThrowError failed (as expected) returned error: %s\n", error->message);
+  g_error_free (error);
+
+  if (!org_freedesktop_DBus_Tests_MyObject_uppercase (proxy, "foobar", &v_STRING_2, &error)) 
+    {
+      g_printerr ("Failed to complete (wrapped) Uppercase call: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+  if (strcmp ("FOOBAR", v_STRING_2) != 0)
+    {
+      g_printerr ("(wrapped) Uppercase call returned unexpected string %s\n", v_STRING_2);
+      exit (1);
+    }
+
+  if (!org_freedesktop_DBus_Tests_MyObject_many_args (proxy, 26, "bazwhee", G_PI,
+                                                     &v_DOUBLE_2, &v_STRING_2, &error))
+    {
+      g_printerr ("Failed to complete (wrapped) ManyArgs call: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+  if (v_DOUBLE_2 < 55 || v_DOUBLE_2 > 56)
+    {
+      g_printerr ("(wrapped) ManyArgs call returned unexpected double value %f\n", v_DOUBLE_2);
+      exit (1);
+    }
+  if (strcmp ("BAZWHEE", v_STRING_2) != 0)
+    {
+      g_printerr ("(wrapped) ManyArgs call returned unexpected string %s\n", v_STRING_2);
+      exit (1);
+    }
+
+  g_object_unref (G_OBJECT (proxy));
+  g_object_unref (G_OBJECT (driver));
+
   g_print ("Successfully completed %s\n", argv[0]);
   
   return 0;
index 2fa3095cbdd6a3197b4b647945ab694a01761175..81cb556fd62193fef464247c3d66a2374cd6299d 100644 (file)
@@ -4,6 +4,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <glib/gi18n.h>
+#include <glib-object.h>
+#include <glib/gquark.h>
 
 typedef struct MyObject MyObject;
 typedef struct MyObjectClass MyObjectClass;
@@ -30,6 +32,28 @@ struct MyObjectClass
 
 G_DEFINE_TYPE(MyObject, my_object, G_TYPE_OBJECT)
 
+typedef enum
+{
+  MY_OBJECT_ERROR_FOO,
+  MY_OBJECT_ERROR_BAR
+} MyObjectError;
+
+#define MY_OBJECT_ERROR my_object_error_quark ()
+
+gboolean my_object_do_nothing (MyObject *obj, GError **error);
+
+gboolean my_object_increment (MyObject *obj, gint32 x, int *ret, GError **error);
+
+gboolean my_object_throw_error (MyObject *obj, GError **error);
+
+gboolean my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error);
+
+gboolean my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error);
+
+#include "test-service-glib-glue.h"
+
+GQuark my_object_error_quark (void);
+
 /* Properties */
 enum
 {
@@ -115,6 +139,54 @@ my_object_class_init (MyObjectClass *mobject_class)
                                                         "default value",
                                                         G_PARAM_READWRITE));
 }
+
+GQuark
+my_object_error_quark (void)
+{
+  static GQuark quark = 0;
+  if (!quark)
+    quark = g_quark_from_static_string ("my_object_error");
+
+  return quark;
+}
+
+gboolean
+my_object_do_nothing (MyObject *obj, GError **error)
+{
+  return TRUE;
+}
+
+gboolean
+my_object_increment (MyObject *obj, gint32 x, int *ret, GError **error)
+{
+  *ret = x +1;
+  return TRUE;
+}
+
+gboolean
+my_object_throw_error (MyObject *obj, GError **error)
+{
+  g_set_error (error,
+              MY_OBJECT_ERROR,
+              MY_OBJECT_ERROR_FOO,
+              "this method always loses");
+  return FALSE;
+}
+
+gboolean
+my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error)
+{
+  *ret = g_ascii_strup (str, -1);
+  return TRUE;
+}
+
+gboolean
+my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error)
+{
+  *d_ret = trouble + (x * 2);
+  *str_ret = g_ascii_strup (str, -1);
+  return TRUE;
+}
      
 static GMainLoop *loop;
 
@@ -148,8 +220,10 @@ main (int argc, char **argv)
 
   obj = 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_connection_register_g_object (connection,
-                                       "/org/freedesktop/my_test_object",
+                                       "/org/freedesktop/DBus/Tests/MyTestObject",
                                        obj);
 
   driver_proxy = dbus_g_proxy_new_for_name (connection,
diff --git a/test/glib/test-service-glib.xml b/test/glib/test-service-glib.xml
new file mode 100644 (file)
index 0000000..223bf67
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/org/freedesktop/DBus/Tests/MyTestObject">
+
+  <interface name="org.freedesktop.DBus.Tests.MyObject" c_name="my_object">
+
+    <method name="DoNothing" c_name="my_object_do_nothing">
+    </method>
+
+    <method name="Increment" c_name="my_object_increment">
+      <arg type="uint32" name="x" />
+      <arg type="uint32" direction="out" />
+    </method>
+
+    <method name="ThrowError" c_name="my_object_throw_error">
+    </method>
+
+    <method name="Uppercase" c_name="my_object_uppercase">
+      <arg type="string" direction="in" />
+      <arg type="string" direction="out" />
+    </method>
+
+    <method name="ManyArgs" c_name="my_object_many_args">
+      <arg type="uint32" name="x" direction="in" />
+      <arg type="string" name="str" direction="in" />
+      <arg type="double" name="trouble" direction="in" />
+      <arg type="double" name="d_ret" direction="out" />
+      <arg type="string" name="str_ret" direction="out" />
+    </method>
+
+  </interface>
+
+</node>