dbus-gobject.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-gobject.c Exporting a GObject remotely
00003  *
00004  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
00005  * Copyright (C) 2005 Nokia
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 #include <gobject/gvaluecollector.h>
00027 #include <dbus/dbus-glib.h>
00028 #include <dbus/dbus-glib-lowlevel.h>
00029 #include "dbus-gtest.h"
00030 #include "dbus-gutils.h"
00031 #include "dbus-gobject.h"
00032 #include "dbus-gsignature.h"
00033 #include "dbus-gvalue.h"
00034 #include "dbus-gmarshal.h"
00035 #include "dbus-gvalue-utils.h"
00036 #include <string.h>
00037 
00043 typedef struct
00044 {
00045   char *default_iface;
00046   GType code_enum;
00047 } DBusGErrorInfo;
00048 
00049 static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
00050 static GHashTable *marshal_table = NULL;
00051 static GData *error_metadata = NULL;
00052 
00053 static char*
00054 uscore_to_wincaps (const char *uscore)
00055 {
00056   const char *p;
00057   GString *str;
00058   gboolean last_was_uscore;
00059 
00060   last_was_uscore = TRUE;
00061   
00062   str = g_string_new (NULL);
00063   p = uscore;
00064   while (*p)
00065     {
00066       if (*p == '-' || *p == '_')
00067         {
00068           last_was_uscore = TRUE;
00069         }
00070       else
00071         {
00072           if (last_was_uscore)
00073             {
00074               g_string_append_c (str, g_ascii_toupper (*p));
00075               last_was_uscore = FALSE;
00076             }
00077           else
00078             g_string_append_c (str, *p);
00079         }
00080       ++p;
00081     }
00082 
00083   return g_string_free (str, FALSE);
00084 }
00085 
00086 static const char *
00087 string_table_next (const char *table)
00088 {
00089   return (table + (strlen (table) + 1));
00090 }
00091 
00092 static const char *
00093 string_table_lookup (const char *table, int index)
00094 {
00095   const char *ret;
00096 
00097   ret = table;
00098 
00099   while (index--)
00100     ret = string_table_next (ret);
00101 
00102   return ret;
00103 }
00104 
00105 static const char *
00106 get_method_data (const DBusGObjectInfo *object,
00107                  const DBusGMethodInfo *method)
00108 {
00109   return object->data + method->data_offset;
00110 }
00111 
00112 static char *
00113 object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
00114 {
00115   /* FIXME */
00116   return NULL;
00117 }
00118 
00119 static char *
00120 object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
00121 {
00122   /* FIXME */
00123   return NULL;
00124 }
00125 
00126 static const char *
00127 method_interface_from_object_info (const DBusGObjectInfo *object,
00128                               const DBusGMethodInfo *method)
00129 {
00130   return string_table_lookup (get_method_data (object, method), 0);
00131 }
00132 
00133 static const char *
00134 method_name_from_object_info (const DBusGObjectInfo *object,
00135                               const DBusGMethodInfo *method)
00136 {
00137   return string_table_lookup (get_method_data (object, method), 1);
00138 }
00139 
00140 static const char *
00141 method_arg_info_from_object_info (const DBusGObjectInfo *object,
00142                                   const DBusGMethodInfo *method)
00143 {
00144   return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
00145 }
00146 
00147 typedef enum
00148 {
00149   RETVAL_NONE,    
00150   RETVAL_NOERROR,    
00151   RETVAL_ERROR
00152 } RetvalType;
00153 
00154 static const char *
00155 arg_iterate (const char    *data,
00156              const char   **name,
00157              gboolean      *in,
00158              gboolean      *constval,
00159              RetvalType    *retval,
00160              const char   **type)
00161 {
00162   gboolean inarg;
00163 
00164   if (name)
00165     *name = data;
00166 
00167   data = string_table_next (data);
00168   switch (*data)
00169     {
00170     case 'I':
00171       inarg = TRUE;
00172       break;
00173     case 'O':
00174       inarg = FALSE;
00175       break;
00176     default:
00177       g_warning ("invalid arg direction '%c'", *data);
00178       inarg = FALSE;
00179       break;
00180     }
00181   if (in)
00182     *in = inarg;
00183 
00184   if (!inarg)
00185     {
00186       data = string_table_next (data);
00187       switch (*data)
00188         {
00189         case 'F':
00190           if (constval)
00191             *constval = FALSE;
00192           break;
00193         case 'C':
00194           if (constval)
00195             *constval = TRUE;
00196           break;
00197         default:
00198           g_warning ("invalid arg const value '%c'", *data);
00199           break;
00200         }
00201       data = string_table_next (data);
00202       switch (*data)
00203         {
00204         case 'N':
00205           if (retval)
00206             *retval = RETVAL_NONE;
00207           break;
00208         case 'E':
00209           if (retval)
00210             *retval = RETVAL_ERROR;
00211           break;
00212         case 'R':
00213           if (retval)
00214             *retval = RETVAL_NOERROR;
00215           break;
00216         default:
00217           g_warning ("invalid arg ret value '%c'", *data);
00218           break;
00219         }
00220     }
00221   else
00222     {
00223       if (constval)
00224         *constval = FALSE;
00225       if (retval)
00226         *retval = FALSE;
00227     }
00228   
00229   data = string_table_next (data);
00230   if (type)
00231     *type = data;
00232 
00233   return string_table_next (data);
00234 }
00235 
00236 static char *
00237 method_dir_signature_from_object_info (const DBusGObjectInfo *object,
00238                                        const DBusGMethodInfo *method,
00239                                        gboolean               in)
00240 {
00241   const char *arg;
00242   GString *ret;
00243 
00244   arg = method_arg_info_from_object_info (object, method);
00245 
00246   ret = g_string_new (NULL);
00247 
00248   while (*arg)
00249     {
00250       const char *name;
00251       gboolean arg_in;
00252       const char *type;
00253 
00254       arg = arg_iterate (arg, &name, &arg_in, NULL, NULL, &type);
00255 
00256       if (arg_in == in)
00257         g_string_append (ret, type);
00258     }
00259 
00260   return g_string_free (ret, FALSE);
00261 }
00262 
00263 static char *
00264 method_input_signature_from_object_info (const DBusGObjectInfo *object,
00265                                          const DBusGMethodInfo *method)
00266 {
00267   return method_dir_signature_from_object_info (object, method, TRUE);
00268 }
00269 
00270 static char *
00271 method_output_signature_from_object_info (const DBusGObjectInfo *object,
00272                                           const DBusGMethodInfo *method)
00273 {
00274   return method_dir_signature_from_object_info (object, method, FALSE);
00275 }
00276 
00277 static const char *
00278 propsig_iterate (const char *data, const char **iface, const char **name)
00279 {
00280   *iface = data;
00281 
00282   data = string_table_next (data);
00283   *name = data;
00284 
00285   return string_table_next (data);
00286 }
00287 
00288 static GQuark
00289 dbus_g_object_type_dbus_metadata_quark (void)
00290 {
00291   static GQuark quark;
00292 
00293   if (!quark)
00294     quark = g_quark_from_static_string ("DBusGObjectTypeDBusMetadataQuark");
00295   return quark;
00296 }
00297 
00298 static const DBusGObjectInfo *
00299 lookup_object_info (GObject *object)
00300 {
00301   const DBusGObjectInfo *ret;
00302   GType classtype;
00303   
00304   ret = NULL;
00305   
00306   for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
00307     {
00308       const DBusGObjectInfo *info;
00309 
00310       info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ()); 
00311 
00312       if (info != NULL && info->format_version >= 0)
00313         {
00314           ret = info;
00315           break;
00316         }
00317     }
00318 
00319   return ret;
00320 }
00321 
00322 static void
00323 gobject_unregister_function (DBusConnection  *connection,
00324                              void            *user_data)
00325 {
00326   GObject *object;
00327 
00328   object = G_OBJECT (user_data);
00329 
00330   /* FIXME */
00331 
00332 }
00333 
00334 typedef struct
00335 {
00336   GString *xml;
00337   GType gtype;
00338   const DBusGObjectInfo *object_info;
00339 } DBusGLibWriteIterfaceData;
00340 
00341 typedef struct
00342 {
00343   GSList *methods;
00344   GSList *signals;
00345   GSList *properties;
00346 } DBusGLibWriteInterfaceValues;
00347 
00348 static void
00349 write_interface (gpointer key, gpointer val, gpointer user_data)
00350 {
00351   const char *name;
00352   GSList *methods;
00353   GSList *signals;
00354   GSList *properties;
00355   GString *xml;
00356   const DBusGObjectInfo *object_info;
00357   DBusGLibWriteIterfaceData *data;
00358   DBusGLibWriteInterfaceValues *values;
00359 
00360   name = key;
00361 
00362   values = val;
00363   methods = values->methods;
00364   signals = values->signals;
00365   properties = values->properties;
00366 
00367   data = user_data;
00368   xml = data->xml;
00369   object_info = data->object_info;
00370 
00371   g_string_append_printf (xml, "  <interface name=\"%s\">\n", name);
00372 
00373   /* FIXME: recurse to parent types ? */
00374   for (; methods; methods = methods->next)
00375     {
00376       DBusGMethodInfo *method;
00377       const char *args;
00378       method = methods->data;
00379 
00380       g_string_append_printf (xml, "    <method name=\"%s\">\n",
00381                               method_name_from_object_info (object_info, method));
00382 
00383       args = method_arg_info_from_object_info (object_info, method);
00384 
00385       while (*args)
00386         {
00387           const char *name;
00388           gboolean arg_in;
00389           const char *type;
00390           
00391           args = arg_iterate (args, &name, &arg_in, NULL, NULL, &type);
00392 
00393           /* FIXME - handle container types */
00394           g_string_append_printf (xml, "      <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
00395                                   name, type, arg_in ? "in" : "out");
00396 
00397         }
00398       g_string_append (xml, "    </method>\n");
00399 
00400     }
00401   g_slist_free (values->methods);
00402 
00403   for (; signals; signals = signals->next)
00404     {
00405       guint id;
00406       guint arg;
00407       const char *signame;
00408       GSignalQuery query;
00409       char *s;
00410 
00411       signame = signals->data;
00412 
00413       s = _dbus_gutils_wincaps_to_uscore (signame);
00414       
00415       id = g_signal_lookup (s, data->gtype);
00416       g_assert (id != 0);
00417 
00418       g_signal_query (id, &query);
00419       g_assert (query.return_type == G_TYPE_NONE);
00420 
00421       g_string_append_printf (xml, "    <signal name=\"%s\">\n", signame);
00422 
00423       for (arg = 0; arg < query.n_params; arg++)
00424         {
00425           char *dbus_type = _dbus_gtype_to_signature (query.param_types[arg]);
00426 
00427           g_assert (dbus_type != NULL);
00428 
00429           g_string_append (xml, "      <arg type=\"");
00430           g_string_append (xml, dbus_type);
00431           g_string_append (xml, "\"/>\n");
00432           g_free (dbus_type);
00433         }
00434 
00435       g_string_append (xml, "    </signal>\n");
00436       g_free (s);
00437     }
00438   g_slist_free (values->signals);
00439 
00440   for (; properties; properties = properties->next)
00441     {
00442       const char *propname;
00443       GParamSpec *spec;
00444       char *dbus_type;
00445       gboolean can_set;
00446       gboolean can_get;
00447       char *s;
00448 
00449       propname = properties->data;
00450       spec = NULL;
00451 
00452       s = _dbus_gutils_wincaps_to_uscore (spec->name);
00453 
00454       spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
00455       g_assert (spec != NULL);
00456       g_free (s);
00457       
00458       dbus_type = _dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
00459       g_assert (dbus_type != NULL);
00460       
00461       can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
00462                  (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
00463       
00464       can_get = (spec->flags & G_PARAM_READABLE) != 0;
00465       
00466       if (can_set || can_get)
00467         {
00468           g_string_append_printf (xml, "    <property name=\"%s\" ", propname);
00469           g_string_append (xml, "type=\"");
00470           g_string_append (xml, dbus_type);
00471           g_string_append (xml, "\" access=\"");
00472 
00473           if (can_set && can_get)
00474             g_string_append (xml, "readwrite");
00475           else if (can_get)
00476             g_string_append (xml, "read");
00477           else
00478             {
00479               g_assert (can_set);
00480               g_string_append (xml, "write");
00481             }
00482           
00483           g_string_append (xml, "\"/>\n");
00484         }
00485       
00486       g_free (dbus_type);
00487       g_free (s);
00488 
00489       g_string_append (xml, "    </property>\n");
00490     }
00491   g_slist_free (values->properties);
00492 
00493   g_free (values);
00494   g_string_append (xml, "  </interface>\n");
00495 }
00496 
00497 static DBusGLibWriteInterfaceValues *
00498 lookup_values (GHashTable *interfaces, const char *method_interface)
00499 {
00500   DBusGLibWriteInterfaceValues *values;
00501   if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
00502     {
00503       values = g_new0 (DBusGLibWriteInterfaceValues, 1);
00504       g_hash_table_insert (interfaces, (gpointer) method_interface, values);
00505     }
00506   return values;
00507 }
00508 
00509 static void
00510 introspect_interfaces (GObject *object, GString *xml)
00511 {
00512   const DBusGObjectInfo *info;
00513   DBusGLibWriteIterfaceData data;
00514   int i;
00515   GHashTable *interfaces;
00516   DBusGLibWriteInterfaceValues *values;
00517   const char *propsig;
00518 
00519   info = lookup_object_info (object);
00520 
00521   g_assert (info != NULL);
00522 
00523   /* Gather a list of all interfaces, indexed into their methods */
00524   interfaces = g_hash_table_new (g_str_hash, g_str_equal);
00525   for (i = 0; i < info->n_method_infos; i++)
00526     {
00527       const char *method_name;
00528       const char *method_interface;
00529       const char *method_args;
00530       const DBusGMethodInfo *method;
00531 
00532       method = &(info->method_infos[i]);
00533 
00534       method_interface = method_interface_from_object_info (info, method);
00535       method_name = method_name_from_object_info (info, method);
00536       method_args = method_arg_info_from_object_info (info, method);
00537 
00538       values = lookup_values (interfaces, method_interface);
00539       values->methods = g_slist_prepend (values->methods, (gpointer) method);
00540     }
00541 
00542   propsig = info->exported_signals;
00543   while (*propsig)
00544     {
00545       const char *iface;
00546       const char *signame;
00547 
00548       propsig = propsig_iterate (propsig, &iface, &signame);
00549 
00550       values = lookup_values (interfaces, iface);
00551       values->signals = g_slist_prepend (values->signals, (gpointer) signame);
00552     }
00553 
00554   propsig = info->exported_properties;
00555   while (*propsig)
00556     {
00557       const char *iface;
00558       const char *propname;
00559 
00560       propsig = propsig_iterate (propsig, &iface, &propname);
00561 
00562       values = lookup_values (interfaces, iface);
00563       values->properties = g_slist_prepend (values->properties, (gpointer) propname);
00564     }
00565   
00566   memset (&data, 0, sizeof (data));
00567   data.xml = xml;
00568   data.gtype = G_TYPE_FROM_INSTANCE (object);
00569   data.object_info = info;
00570   g_hash_table_foreach (interfaces, write_interface, &data);
00571   
00572   g_hash_table_destroy (interfaces);
00573 }
00574 
00575 static DBusHandlerResult
00576 handle_introspect (DBusConnection *connection,
00577                    DBusMessage    *message,
00578                    GObject        *object)
00579 {
00580   GString *xml;
00581   unsigned int i;
00582   DBusMessage *ret;
00583   char **children;
00584   
00585   if (!dbus_connection_list_registered (connection, 
00586                                         dbus_message_get_path (message),
00587                                         &children))
00588     g_error ("Out of memory");
00589   
00590   xml = g_string_new (NULL);
00591 
00592   g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
00593   
00594   g_string_append (xml, "<node>\n");
00595 
00596   /* We are introspectable, though I guess that was pretty obvious */
00597   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE);
00598   g_string_append (xml, "    <method name=\"Introspect\">\n");
00599   g_string_append_printf (xml, "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00600   g_string_append (xml, "    </method>\n");
00601   g_string_append (xml, "  </interface>\n");
00602 
00603   /* We support get/set properties */
00604   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_PROPERTIES);
00605   g_string_append (xml, "    <method name=\"Get\">\n");
00606   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00607   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00608   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00609   g_string_append (xml, "    </method>\n");
00610   g_string_append (xml, "    <method name=\"Set\">\n");
00611   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00612   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00613   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00614   g_string_append (xml, "    </method>\n");
00615   g_string_append (xml, "  </interface>\n");
00616   
00617   introspect_interfaces (object, xml);
00618 
00619   /* Append child nodes */
00620   for (i = 0; children[i]; i++)
00621       g_string_append_printf (xml, "  <node name=\"%s\"/>\n",
00622                               children[i]);
00623   
00624   /* Close the XML, and send it to the requesting app */
00625   g_string_append (xml, "</node>\n");
00626 
00627   ret = dbus_message_new_method_return (message);
00628   if (ret == NULL)
00629     g_error ("Out of memory");
00630 
00631   dbus_message_append_args (ret,
00632                             DBUS_TYPE_STRING, &xml->str,
00633                             DBUS_TYPE_INVALID);
00634 
00635   dbus_connection_send (connection, ret, NULL);
00636   dbus_message_unref (ret);
00637 
00638   g_string_free (xml, TRUE);
00639 
00640   dbus_free_string_array (children);
00641   
00642   return DBUS_HANDLER_RESULT_HANDLED;
00643 }
00644 
00645 static DBusMessage*
00646 set_object_property (DBusConnection  *connection,
00647                      DBusMessage     *message,
00648                      DBusMessageIter *iter,
00649                      GObject         *object,
00650                      GParamSpec      *pspec)
00651 {
00652   GValue value = { 0, };
00653   DBusMessage *ret;
00654   DBusMessageIter sub;
00655   DBusGValueMarshalCtx context;
00656 
00657   dbus_message_iter_recurse (iter, &sub);
00658 
00659   context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00660   context.proxy = NULL;
00661 
00662   g_value_init (&value, pspec->value_type);
00663   if (_dbus_gvalue_demarshal (&context, &sub, &value, NULL))
00664     {
00665       g_object_set_property (object,
00666                              pspec->name,
00667                              &value);
00668 
00669       g_value_unset (&value);
00670 
00671       ret = dbus_message_new_method_return (message);
00672       if (ret == NULL)
00673         g_error ("out of memory");
00674     }
00675   else
00676     {
00677       ret = dbus_message_new_error (message,
00678                                     DBUS_ERROR_INVALID_ARGS,
00679                                     "Argument's D-BUS type can't be converted to a GType");
00680       if (ret == NULL)
00681         g_error ("out of memory");
00682     }
00683 
00684   return ret;
00685 }
00686 
00687 static DBusMessage*
00688 get_object_property (DBusConnection *connection,
00689                      DBusMessage    *message,
00690                      GObject        *object,
00691                      GParamSpec     *pspec)
00692 {
00693   GType value_gtype;
00694   GValue value = {0, };
00695   gchar *variant_sig;
00696   DBusMessage *ret;
00697   DBusMessageIter iter, subiter;
00698 
00699   ret = dbus_message_new_method_return (message);
00700   if (ret == NULL)
00701     g_error ("out of memory");
00702 
00703 
00704   g_value_init (&value, pspec->value_type);
00705   g_object_get_property (object, pspec->name, &value);
00706 
00707   variant_sig = _dbus_gvalue_to_signature (&value);
00708   if (variant_sig == NULL)
00709     {
00710       value_gtype = G_VALUE_TYPE (&value);
00711       g_warning ("Cannot marshal type \"%s\" in variant", g_type_name (value_gtype));
00712       g_value_unset (&value);
00713       return ret;
00714     }
00715 
00716   dbus_message_iter_init_append (ret, &iter);
00717   if (!dbus_message_iter_open_container (&iter,
00718                                          DBUS_TYPE_VARIANT,
00719                                          variant_sig,
00720                                          &subiter))
00721     {
00722       g_free (variant_sig);
00723       g_value_unset (&value);
00724       return ret;
00725     }
00726 
00727   if (!_dbus_gvalue_marshal (&subiter, &value))
00728     {
00729       dbus_message_unref (ret);
00730       ret = dbus_message_new_error (message,
00731                                     DBUS_ERROR_UNKNOWN_METHOD,
00732                                     "Can't convert GType of object property to a D-BUS type");
00733     }
00734 
00735   dbus_message_iter_close_container (&iter, &subiter);
00736 
00737   g_value_unset (&value);
00738   g_free (variant_sig);
00739 
00740   return ret;
00741 }
00742 
00743 static gboolean
00744 lookup_object_and_method (GObject      *object,
00745                           DBusMessage  *message,
00746                           const DBusGObjectInfo **object_ret,
00747                           const DBusGMethodInfo **method_ret)
00748 {
00749   const char *interface;
00750   const char *member;
00751   const char *signature;
00752   gboolean ret;
00753   const DBusGObjectInfo *info;
00754   int i;
00755 
00756   interface = dbus_message_get_interface (message);
00757   member = dbus_message_get_member (message);
00758   signature = dbus_message_get_signature (message);
00759   ret = FALSE;
00760 
00761   info = lookup_object_info (object);
00762   *object_ret = info;
00763   
00764   for (i = 0; i < info->n_method_infos; i++)
00765     {
00766       const char *expected_member;
00767       const char *expected_interface;
00768       char *expected_signature;
00769       const DBusGMethodInfo *method;
00770 
00771       method = &(info->method_infos[i]);
00772 
00773       /* Check method interface/name and input signature */ 
00774       expected_interface = method_interface_from_object_info (*object_ret, method);
00775       expected_member = method_name_from_object_info (*object_ret, method);
00776       expected_signature = method_input_signature_from_object_info (*object_ret, method);
00777 
00778       if ((interface == NULL
00779            || strcmp (expected_interface, interface) == 0)
00780           && strcmp (expected_member, member) == 0
00781           && strcmp (expected_signature, signature) == 0)
00782         {
00783           g_free (expected_signature);
00784           *method_ret = method;
00785           return TRUE;
00786         }
00787       g_free (expected_signature);
00788     }
00789 
00790   return ret;
00791 }
00792 
00793 static char *
00794 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
00795                                       const char *msg_interface,
00796                                       GQuark domain, gint code)
00797 {
00798   const char *domain_str;
00799   const char *code_str;
00800   GString *dbus_error_name;
00801 
00802   domain_str = object_error_domain_prefix_from_object_info (object_info);
00803   code_str = object_error_code_from_object_info (object_info, domain, code);
00804 
00805   if (!domain_str || !code_str)
00806     {
00807       DBusGErrorInfo *info;
00808 
00809       g_static_rw_lock_reader_lock (&globals_lock);
00810 
00811       if (error_metadata != NULL)
00812         info = g_datalist_id_get_data (&error_metadata, domain);
00813       else
00814         info = NULL;
00815 
00816       g_static_rw_lock_reader_unlock (&globals_lock);
00817 
00818       if (info)
00819         {
00820           GEnumValue *value;
00821           GEnumClass *klass;
00822 
00823           klass = g_type_class_ref (info->code_enum);
00824           value = g_enum_get_value (klass, code);
00825           g_type_class_unref (klass);
00826 
00827           domain_str = info->default_iface;
00828           code_str = value->value_nick;
00829         }
00830     }
00831 
00832   if (!domain_str)
00833     domain_str = msg_interface;
00834 
00835   if (!domain_str || !code_str)
00836     {
00837       /* If we can't map it sensibly, make up an error name */
00838       char *domain_from_quark;
00839       
00840       dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
00841 
00842       domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
00843       g_string_append (dbus_error_name, domain_from_quark);
00844       g_free (domain_from_quark);
00845         
00846       g_string_append_printf (dbus_error_name, ".Code%d", code);
00847     }
00848   else
00849     {
00850       dbus_error_name = g_string_new (domain_str);
00851       g_string_append_c (dbus_error_name, '.');
00852       g_string_append (dbus_error_name, code_str);
00853     }
00854 
00855   return g_string_free (dbus_error_name, FALSE);
00856 }
00857 
00858 static DBusMessage *
00859 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
00860                               DBusMessage     *message,
00861                               GError          *error)
00862 {
00863   DBusMessage *reply;
00864 
00865   if (!error)
00866     {
00867       char *error_msg;
00868       
00869       error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
00870       reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
00871       g_free (error_msg);
00872     }
00873   else
00874     {
00875       if (error->domain == DBUS_GERROR)
00876         reply = dbus_message_new_error (message,
00877                                         dbus_g_error_get_name (error),
00878                                         error->message);
00879       else
00880         {
00881           char *error_name;
00882           error_name = gerror_domaincode_to_dbus_error_name (object_info,
00883                                                              dbus_message_get_interface (message),
00884                                                              error->domain, error->code);
00885           reply = dbus_message_new_error (message, error_name, error->message);
00886           g_free (error_name); 
00887         }
00888     }
00889   return reply;
00890 }
00891 
00896 struct _DBusGMethodInvocation {
00897   DBusGConnection *connection; 
00898   DBusGMessage *message; 
00899   const DBusGObjectInfo *object; 
00900   const DBusGMethodInfo *method; 
00901 };
00902 
00903 static DBusHandlerResult
00904 invoke_object_method (GObject         *object,
00905                       const DBusGObjectInfo *object_info,
00906                       const DBusGMethodInfo *method,
00907                       DBusConnection  *connection,
00908                       DBusMessage     *message)
00909 {
00910   gboolean had_error, call_only;
00911   GError *gerror;
00912   GValueArray *value_array;
00913   GValue return_value = {0,};
00914   GClosure closure;
00915   char *in_signature;
00916   GArray *out_param_values = NULL;
00917   GValueArray *out_param_gvalues = NULL;
00918   int out_param_count;
00919   int out_param_pos, out_param_gvalue_pos;
00920   DBusHandlerResult result;
00921   DBusMessage *reply;
00922   gboolean have_retval;
00923   gboolean retval_signals_error;
00924   gboolean retval_is_synthetic;
00925   gboolean retval_is_constant;
00926   const char *arg_metadata;
00927 
00928   gerror = NULL;
00929 
00930   /* Determine whether or not this method should be invoked in a new
00931      thread
00932    */
00933   if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
00934     call_only = TRUE;
00935   else
00936     call_only = FALSE;
00937 
00938   have_retval = FALSE;
00939   retval_signals_error = FALSE;
00940   retval_is_synthetic = FALSE;
00941   retval_is_constant = FALSE;
00942 
00943   /* This is evil.  We do this to work around the fact that
00944    * the generated glib marshallers check a flag in the closure object
00945    * which we don't care about.  We don't need/want to create
00946    * a new closure for each invocation.
00947    */
00948   memset (&closure, 0, sizeof (closure));
00949 
00950   in_signature = method_input_signature_from_object_info (object_info, method); 
00951   
00952   /* Convert method IN parameters to GValueArray */
00953   {
00954     GArray *types_array;
00955     guint n_params;
00956     const GType *types;
00957     DBusGValueMarshalCtx context;
00958     GError *error = NULL;
00959     
00960     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00961     context.proxy = NULL;
00962 
00963     types_array = _dbus_gtypes_from_arg_signature (in_signature, FALSE);
00964     n_params = types_array->len;
00965     types = (const GType*) types_array->data;
00966 
00967     value_array = _dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
00968     if (value_array == NULL)
00969       {
00970         g_free (in_signature); 
00971         g_array_free (types_array, TRUE);
00972         reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
00973         dbus_connection_send (connection, reply, NULL);
00974         dbus_message_unref (reply);
00975         g_error_free (error);
00976         return DBUS_HANDLER_RESULT_HANDLED;
00977       }
00978     g_array_free (types_array, TRUE);
00979   }
00980 
00981   /* Prepend object as first argument */ 
00982   g_value_array_prepend (value_array, NULL);
00983   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT);
00984   g_value_set_object (g_value_array_get_nth (value_array, 0), object);
00985   
00986   if (call_only)
00987     {
00988       GValue context_value = {0,};
00989       DBusGMethodInvocation *context;
00990       context = g_new (DBusGMethodInvocation, 1);
00991       context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
00992       context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
00993       context->object = object_info;
00994       context->method = method;
00995       g_value_init (&context_value, G_TYPE_POINTER);
00996       g_value_set_pointer (&context_value, context);
00997       g_value_array_append (value_array, &context_value);
00998     }
00999   else
01000     {
01001       RetvalType retval;
01002       gboolean arg_in;
01003       gboolean arg_const;
01004       const char *argsig;
01005 
01006       arg_metadata = method_arg_info_from_object_info (object_info, method);
01007       
01008       /* Count number of output parameters, and look for a return value */
01009       out_param_count = 0;
01010       while (*arg_metadata)
01011         {
01012           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
01013           if (arg_in)
01014             continue;
01015           if (retval != RETVAL_NONE)
01016             {
01017               DBusSignatureIter tmp_sigiter;
01018               /* This is the function return value */
01019               g_assert (!have_retval);
01020               have_retval = TRUE;
01021               retval_is_synthetic = FALSE;
01022 
01023               switch (retval)
01024                 {
01025                 case RETVAL_NONE:
01026                   g_assert_not_reached ();
01027                   break;
01028                 case RETVAL_NOERROR:
01029                   retval_signals_error = FALSE;
01030                   break;
01031                 case RETVAL_ERROR:
01032                   retval_signals_error = TRUE;
01033                   break;
01034                 }
01035 
01036               retval_is_constant = arg_const;
01037 
01038               /* Initialize our return GValue with the specified type */
01039               dbus_signature_iter_init (&tmp_sigiter, argsig);
01040               g_value_init (&return_value, _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
01041             }
01042           else
01043             {
01044               /* It's a regular output value */
01045               out_param_count++;
01046             }
01047         }
01048 
01049       /* For compatibility, if we haven't found a return value, we assume
01050        * the function returns a gboolean for signalling an error
01051        * (and therefore also takes a GError).  We also note that it
01052        * is a "synthetic" return value; i.e. we aren't going to be
01053        * sending it over the bus, it's just to signal an error.
01054        */
01055       if (!have_retval)
01056         {
01057           have_retval = TRUE;
01058           retval_is_synthetic = TRUE;
01059           retval_signals_error = TRUE;
01060           g_value_init (&return_value, G_TYPE_BOOLEAN);
01061         }
01062 
01063       /* Create an array to store the actual values of OUT parameters
01064        * (other than the real function return, if any).  Then, create
01065        * a GValue boxed POINTER to each of those values, and append to
01066        * the invocation, so the method can return the OUT parameters.
01067        */
01068       out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
01069 
01070       /* We have a special array of GValues for toplevel GValue return
01071        * types.
01072        */
01073       out_param_gvalues = g_value_array_new (out_param_count);
01074       out_param_pos = 0;
01075       out_param_gvalue_pos = 0;
01076 
01077       /* Reset argument metadata pointer */
01078       arg_metadata = method_arg_info_from_object_info (object_info, method);
01079       
01080       /* Iterate over output arguments again, this time allocating space for
01081        * them as appopriate.
01082        */
01083       while (*arg_metadata)
01084         {
01085           GValue value = {0, };
01086           GTypeCValue storage;
01087           DBusSignatureIter tmp_sigiter;
01088           GType current_gtype;
01089 
01090           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
01091           /* Skip over input arguments and the return value, if any */
01092           if (arg_in || retval != RETVAL_NONE)
01093             continue;
01094 
01095           dbus_signature_iter_init (&tmp_sigiter, argsig);
01096           current_gtype = _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
01097 
01098           g_value_init (&value, G_TYPE_POINTER);
01099 
01100           /* We special case variants to make method invocation a bit nicer */
01101           if (current_gtype != G_TYPE_VALUE)
01102             {
01103               memset (&storage, 0, sizeof (storage));
01104               g_array_append_val (out_param_values, storage);
01105               g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
01106               out_param_pos++;
01107             }
01108           else
01109             {
01110               g_value_array_append (out_param_gvalues, NULL);
01111               g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
01112               out_param_gvalue_pos++;
01113             }
01114           g_value_array_append (value_array, &value);
01115         }
01116     }
01117 
01118   /* Append GError as final argument if necessary */
01119   if (retval_signals_error)
01120     {
01121       g_assert (have_retval);
01122       g_value_array_append (value_array, NULL);
01123       g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
01124       g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
01125     }
01126   
01127   /* Actually invoke method */
01128   method->marshaller (&closure, have_retval ? &return_value : NULL,
01129                       value_array->n_values,
01130                       value_array->values,
01131                       NULL, method->function);
01132   if (call_only)
01133     {
01134       result = DBUS_HANDLER_RESULT_HANDLED;
01135       goto done;
01136     }
01137   if (retval_signals_error)
01138     had_error = _dbus_gvalue_signals_error (&return_value);
01139   else
01140     had_error = FALSE;
01141 
01142   if (!had_error)
01143     {
01144       DBusMessageIter iter;
01145 
01146       reply = dbus_message_new_method_return (message);
01147       if (reply == NULL)
01148         goto nomem;
01149 
01150       /* Append output arguments to reply */
01151       dbus_message_iter_init_append (reply, &iter);
01152 
01153       /* First, append the return value, unless it's synthetic */
01154       if (have_retval && !retval_is_synthetic)
01155         {
01156           if (!_dbus_gvalue_marshal (&iter, &return_value))
01157             goto nomem;
01158           if (!retval_is_constant)
01159             g_value_unset (&return_value);
01160         }
01161 
01162       /* Grab the argument metadata and iterate over it */
01163       arg_metadata = method_arg_info_from_object_info (object_info, method);
01164       
01165       /* Now append any remaining return values */
01166       out_param_pos = 0;
01167       out_param_gvalue_pos = 0;
01168       while (*arg_metadata)
01169         {
01170           GValue gvalue = {0, };
01171           const char *arg_name;
01172           gboolean arg_in;
01173           gboolean constval;
01174           RetvalType retval;
01175           const char *arg_signature;
01176           DBusSignatureIter argsigiter;
01177 
01178           do
01179             {
01180               /* Iterate over only output values; skip over input
01181                  arguments and the return value */
01182               arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
01183             }
01184           while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
01185 
01186           /* If the last argument we saw was input or the return
01187            * value, we must be done iterating over output arguments.
01188            */
01189           if (arg_in || retval != RETVAL_NONE)
01190             break;
01191 
01192           dbus_signature_iter_init (&argsigiter, arg_signature);
01193           
01194           g_value_init (&gvalue, _dbus_gtype_from_signature_iter (&argsigiter, FALSE));
01195           if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
01196             {
01197               if (!_dbus_gvalue_take (&gvalue,
01198                                      &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
01199                 g_assert_not_reached ();
01200               out_param_pos++;
01201             }
01202           else
01203             {
01204               g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
01205               out_param_gvalue_pos++;
01206             }
01207               
01208           if (!_dbus_gvalue_marshal (&iter, &gvalue))
01209             goto nomem;
01210           /* Here we actually free the allocated value; we
01211            * took ownership of it with _dbus_gvalue_take, unless
01212            * an annotation has specified this value as constant.
01213            */
01214           if (!constval)
01215             g_value_unset (&gvalue);
01216         }
01217     }
01218   else
01219     reply = gerror_to_dbus_error_message (object_info, message, gerror);
01220 
01221   if (reply)
01222     {
01223       dbus_connection_send (connection, reply, NULL);
01224       dbus_message_unref (reply);
01225     }
01226 
01227   result = DBUS_HANDLER_RESULT_HANDLED;
01228  done:
01229   g_free (in_signature);
01230   if (!call_only)
01231     {
01232       g_array_free (out_param_values, TRUE);
01233       g_value_array_free (out_param_gvalues);
01234     }
01235   g_value_array_free (value_array);
01236   return result;
01237  nomem:
01238   result = DBUS_HANDLER_RESULT_NEED_MEMORY;
01239   goto done;
01240 }
01241 
01242 static DBusHandlerResult
01243 gobject_message_function (DBusConnection  *connection,
01244                           DBusMessage     *message,
01245                           void            *user_data)
01246 {
01247   GParamSpec *pspec;
01248   GObject *object;
01249   gboolean setter;
01250   gboolean getter;
01251   char *s;
01252   const char *wincaps_propname;
01253   /* const char *wincaps_propiface; */
01254   DBusMessageIter iter;
01255   const DBusGMethodInfo *method;
01256   const DBusGObjectInfo *object_info;
01257 
01258   object = G_OBJECT (user_data);
01259 
01260   if (dbus_message_is_method_call (message,
01261                                    DBUS_INTERFACE_INTROSPECTABLE,
01262                                    "Introspect"))
01263     return handle_introspect (connection, message, object);
01264   
01265   /* Try the metainfo, which lets us invoke methods */
01266   if (lookup_object_and_method (object, message, &object_info, &method))
01267     return invoke_object_method (object, object_info, method, connection, message);
01268 
01269   /* If no metainfo, we can still do properties and signals
01270    * via standard GLib introspection
01271    */
01272   getter = FALSE;
01273   setter = FALSE;
01274   if (dbus_message_is_method_call (message,
01275                                    DBUS_INTERFACE_PROPERTIES,
01276                                    "Get"))
01277     getter = TRUE;
01278   else if (dbus_message_is_method_call (message,
01279                                         DBUS_INTERFACE_PROPERTIES,
01280                                         "Set"))
01281     setter = TRUE;
01282 
01283   if (!(setter || getter))
01284     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01285 
01286   dbus_message_iter_init (message, &iter);
01287 
01288   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01289     {
01290       g_warning ("Property get or set does not have an interface string as first arg\n");
01291       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01292     }
01293   /* We never use the interface name; if we did, we'd need to
01294    * remember that it can be empty string for "pick one for me"
01295    */
01296   /* dbus_message_iter_get_basic (&iter, &wincaps_propiface); */
01297   dbus_message_iter_next (&iter);
01298 
01299   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01300     {
01301       g_warning ("Property get or set does not have a property name string as second arg\n");
01302       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01303     }
01304   dbus_message_iter_get_basic (&iter, &wincaps_propname);
01305   dbus_message_iter_next (&iter);
01306   
01307   s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
01308 
01309   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
01310                                         s);
01311 
01312   g_free (s);
01313 
01314   if (pspec != NULL)
01315     {
01316       DBusMessage *ret;
01317 
01318       if (setter)
01319         {
01320           if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
01321             {
01322               g_warning ("Property set does not have a variant value as third arg\n");
01323               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01324             }
01325           
01326           ret = set_object_property (connection, message, &iter,
01327                                      object, pspec);
01328           dbus_message_iter_next (&iter);
01329         }
01330       else if (getter)
01331         {
01332           ret = get_object_property (connection, message,
01333                                      object, pspec);
01334         }
01335       else
01336         {
01337           g_assert_not_reached ();
01338           ret = NULL;
01339         }
01340 
01341       g_assert (ret != NULL);
01342 
01343       if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
01344         g_warning ("Property get or set had too many arguments\n");
01345 
01346       dbus_connection_send (connection, ret, NULL);
01347       dbus_message_unref (ret);
01348       return DBUS_HANDLER_RESULT_HANDLED;
01349     }
01350 
01351   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01352 }
01353 
01354 static const DBusObjectPathVTable gobject_dbus_vtable = {
01355   gobject_unregister_function,
01356   gobject_message_function,
01357   NULL
01358 };
01359 
01360 typedef struct {
01361   GClosure         closure;
01362   DBusGConnection *connection;
01363   GObject         *object;
01364   const char      *signame;
01365   const char      *sigiface;
01366 } DBusGSignalClosure;
01367 
01368 static GClosure *
01369 dbus_g_signal_closure_new (DBusGConnection *connection,
01370                            GObject         *object,
01371                            const char      *signame,
01372                            const char      *sigiface)
01373 {
01374   DBusGSignalClosure *closure;
01375   
01376   closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
01377 
01378   closure->connection = dbus_g_connection_ref (connection);
01379   closure->object = object;
01380   closure->signame = signame;
01381   closure->sigiface = sigiface;
01382   return (GClosure*) closure;
01383 }
01384 
01385 static void
01386 dbus_g_signal_closure_finalize (gpointer data,
01387                                 GClosure *closure)
01388 {
01389   DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
01390 
01391   dbus_g_connection_unref (sigclosure->connection);
01392 }
01393 
01394 static void
01395 signal_emitter_marshaller (GClosure        *closure,
01396                            GValue          *retval,
01397                            guint            n_param_values,
01398                            const GValue    *param_values,
01399                            gpointer         invocation_hint,
01400                            gpointer         marshal_data)
01401 {
01402   DBusGSignalClosure *sigclosure;
01403   DBusMessage *signal;
01404   DBusMessageIter iter;
01405   guint i;
01406   const char *path;
01407 
01408   sigclosure = (DBusGSignalClosure *) closure;
01409   
01410   g_assert (retval == NULL);
01411 
01412   path = _dbus_gobject_get_path (sigclosure->object);
01413 
01414   g_assert (path != NULL);
01415 
01416   signal = dbus_message_new_signal (path,
01417                                     sigclosure->sigiface,
01418                                     sigclosure->signame);
01419   if (!signal)
01420     {
01421       g_error ("out of memory");
01422       return;
01423     }
01424 
01425   dbus_message_iter_init_append (signal, &iter);
01426 
01427   /* First argument is the object itself, and we can't marshall that */
01428   for (i = 1; i < n_param_values; i++)
01429     {
01430       if (!_dbus_gvalue_marshal (&iter,
01431                                 (GValue *) (&(param_values[i]))))
01432         {
01433           g_warning ("failed to marshal parameter %d for signal %s",
01434                      i, sigclosure->signame);
01435           goto out;
01436         }
01437     }
01438   dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
01439                         signal, NULL);
01440  out:
01441   dbus_message_unref (signal);
01442 }
01443 
01444 static void
01445 export_signals (DBusGConnection *connection, const DBusGObjectInfo *info, GObject *object)
01446 {
01447   GType gtype;
01448   const char *sigdata;
01449   const char *iface;
01450   const char *signame;
01451 
01452   gtype = G_TYPE_FROM_INSTANCE (object);
01453 
01454   sigdata = info->exported_signals;
01455   
01456   while (*sigdata != '\0')
01457     {
01458       guint id;
01459       GSignalQuery query;
01460       GClosure *closure;
01461       char *s;
01462 
01463       sigdata = propsig_iterate (sigdata, &iface, &signame);
01464       
01465       s = _dbus_gutils_wincaps_to_uscore (signame);
01466 
01467       id = g_signal_lookup (s, gtype);
01468       if (id == 0)
01469         {
01470           g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
01471                      s, signame, g_type_name (gtype));
01472           g_free (s);
01473           continue;
01474         }
01475 
01476       g_signal_query (id, &query);
01477 
01478       if (query.return_type != G_TYPE_NONE)
01479         {
01480           g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"",
01481                      s, g_type_name (gtype), g_type_name (query.return_type));
01482           g_free (s);
01483           continue; /* FIXME: these could be listed as methods ? */
01484         }
01485       
01486       closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
01487       g_closure_set_marshal (closure, signal_emitter_marshaller);
01488 
01489       g_signal_connect_closure_by_id (object,
01490                                       id,
01491                                       0,
01492                                       closure,
01493                                       FALSE);
01494 
01495       g_closure_add_finalize_notifier (closure, NULL,
01496                                        dbus_g_signal_closure_finalize);
01497       g_free (s);
01498     }
01499 }
01500 
01501 #include "dbus-glib-error-switch.h"
01502 
01503 void
01504 dbus_set_g_error (GError    **gerror,
01505                   DBusError  *error)
01506 {
01507   int code;
01508 
01509   code = dbus_error_to_gerror_code (error->name);
01510   if (code != DBUS_GERROR_REMOTE_EXCEPTION)
01511     g_set_error (gerror, DBUS_GERROR,
01512                  code,
01513                  "%s",
01514                  error->message);
01515   else
01516     g_set_error (gerror, DBUS_GERROR,
01517                  code,
01518                  "%s%c%s",
01519                  error->message ? error->message : "",
01520                  '\0',
01521                  error->name);
01522 }
01523 
01524 static void
01525 dbus_g_error_info_free (gpointer p)
01526 {
01527   DBusGErrorInfo *info;
01528 
01529   info = p;
01530 
01531   g_free (info->default_iface);
01532   g_free (info);
01533 }
01534  /* end of internals */
01536 
01556 void
01557 dbus_g_object_type_install_info (GType                  object_type,
01558                                  const DBusGObjectInfo *info)
01559 {
01560   g_return_if_fail (G_TYPE_IS_CLASSED (object_type));
01561 
01562   _dbus_g_value_types_init ();
01563 
01564   g_type_set_qdata (object_type,
01565                     dbus_g_object_type_dbus_metadata_quark (),
01566                     (gpointer) info);
01567 }
01568 
01578 void
01579 dbus_g_error_domain_register (GQuark                domain,
01580                               const char           *default_iface,
01581                               GType                 code_enum)
01582 {
01583   DBusGErrorInfo *info;
01584   
01585   g_return_if_fail (g_quark_to_string (domain) != NULL);
01586   g_return_if_fail (code_enum != G_TYPE_INVALID);
01587   g_return_if_fail (G_TYPE_FUNDAMENTAL (code_enum) == G_TYPE_ENUM);
01588 
01589   g_static_rw_lock_writer_lock (&globals_lock);
01590 
01591   if (error_metadata == NULL)
01592     g_datalist_init (&error_metadata);
01593 
01594   info = g_datalist_id_get_data (&error_metadata, domain);
01595 
01596   if (info != NULL)
01597     {
01598       g_warning ("Metadata for error domain \"%s\" already registered\n",
01599                  g_quark_to_string (domain));
01600     }
01601   else
01602     {
01603       info = g_new0 (DBusGErrorInfo, 1);
01604       info->default_iface = g_strdup (default_iface);
01605       info->code_enum = code_enum;
01606 
01607       g_datalist_id_set_data_full (&error_metadata,
01608                                    domain,
01609                                    info,
01610                                    dbus_g_error_info_free);
01611     }
01612 
01613   g_static_rw_lock_writer_unlock (&globals_lock);
01614 }
01615 
01616 static void
01617 unregister_gobject (DBusGConnection *connection, GObject *dead)
01618 {
01619   char *path;
01620   path = g_object_steal_data (dead, "dbus_glib_object_path");
01621   dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection), path);
01622   g_free (path);
01623 }
01624 
01638 void
01639 dbus_g_connection_register_g_object (DBusGConnection       *connection,
01640                                      const char            *at_path,
01641                                      GObject               *object)
01642 {
01643   const DBusGObjectInfo *info;
01644   g_return_if_fail (connection != NULL);
01645   g_return_if_fail (at_path != NULL);
01646   g_return_if_fail (G_IS_OBJECT (object));
01647 
01648   info = lookup_object_info (object);
01649   if (info == NULL)
01650     {
01651       g_warning ("No introspection data registered for object class \"%s\"",
01652                  g_type_name (G_TYPE_FROM_INSTANCE (object)));
01653       return;
01654     }
01655 
01656   if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
01657                                              at_path,
01658                                              &gobject_dbus_vtable,
01659                                              object))
01660     {
01661       g_error ("Failed to register GObject with DBusConnection");
01662       return;
01663     }
01664 
01665   export_signals (connection, info, object);
01666 
01667   g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
01668   g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
01669 }
01670 
01671 GObject *
01672 dbus_g_connection_lookup_g_object (DBusGConnection       *connection,
01673                                    const char            *at_path)
01674 {
01675   gpointer ret;
01676   if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
01677     return NULL;
01678   return ret;
01679 }
01680 
01681 typedef struct {
01682   GType    rettype;
01683   guint    n_params;
01684   GType   *params;
01685 } DBusGFuncSignature;
01686 
01687 static guint
01688 funcsig_hash (gconstpointer key)
01689 {
01690   const DBusGFuncSignature *sig = key;
01691   GType *types;
01692   guint ret;
01693   guint i;
01694 
01695   ret = sig->rettype;
01696   types = sig->params;
01697 
01698   for (i = 0; i < sig->n_params; i++)
01699     {
01700       ret += (int) (*types);
01701       types++;
01702     }
01703       
01704   return ret;
01705 }
01706 
01707 static gboolean
01708 funcsig_equal (gconstpointer aval,
01709                gconstpointer bval)
01710 {
01711   const DBusGFuncSignature *a = aval;
01712   const DBusGFuncSignature *b = bval;
01713   const GType *atypes;
01714   const GType *btypes;
01715   guint i;
01716 
01717   if (a->rettype != b->rettype
01718       || a->n_params != b->n_params)
01719     return FALSE;
01720 
01721   atypes = a->params;
01722   btypes = b->params;
01723 
01724   for (i = 0; i < a->n_params; i++)
01725     {
01726       if (*btypes != *atypes)
01727         return FALSE;
01728       atypes++;
01729       btypes++;
01730     }
01731       
01732   return TRUE;
01733 }
01734 
01735 GClosureMarshal
01736 _dbus_gobject_lookup_marshaller (GType        rettype,
01737                                  guint        n_params,
01738                                  const GType *param_types)
01739 {
01740   GClosureMarshal ret;
01741   DBusGFuncSignature sig;
01742   GType *params;
01743   guint i;
01744 
01745   /* Convert to fundamental types */
01746   rettype = G_TYPE_FUNDAMENTAL (rettype);
01747   params = g_new (GType, n_params);
01748   for (i = 0; i < n_params; i++)
01749     params[i] = G_TYPE_FUNDAMENTAL (param_types[i]);
01750 
01751   sig.rettype = rettype;
01752   sig.n_params = n_params;
01753   sig.params = params;
01754   
01755   g_static_rw_lock_reader_lock (&globals_lock);
01756 
01757   if (marshal_table)
01758     ret = g_hash_table_lookup (marshal_table, &sig);
01759   else
01760     ret = NULL;
01761 
01762   g_static_rw_lock_reader_unlock (&globals_lock);
01763 
01764   if (ret == NULL)
01765     {
01766       if (rettype == G_TYPE_NONE)
01767         {
01768           if (n_params == 0)
01769             ret = g_cclosure_marshal_VOID__VOID;
01770           else if (n_params == 1)
01771             {
01772               switch (params[0])
01773                 {
01774                 case G_TYPE_BOOLEAN:
01775                   ret = g_cclosure_marshal_VOID__BOOLEAN;
01776                   break;
01777                 case G_TYPE_UCHAR:
01778                   ret = g_cclosure_marshal_VOID__UCHAR;
01779                   break;
01780                 case G_TYPE_INT:
01781                   ret = g_cclosure_marshal_VOID__INT;
01782                   break;
01783                 case G_TYPE_UINT:
01784                   ret = g_cclosure_marshal_VOID__UINT;
01785                   break;
01786                 case G_TYPE_DOUBLE:
01787                   ret = g_cclosure_marshal_VOID__DOUBLE;
01788                   break;
01789                 case G_TYPE_STRING:
01790                   ret = g_cclosure_marshal_VOID__STRING;
01791                   break;
01792                 case G_TYPE_BOXED:
01793                   ret = g_cclosure_marshal_VOID__BOXED;
01794                   break;
01795                 }
01796             }
01797           else if (n_params == 3
01798                    && params[0] == G_TYPE_STRING
01799                    && params[1] == G_TYPE_STRING
01800                    && params[2] == G_TYPE_STRING)
01801             {
01802               ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
01803             }
01804         }
01805     }
01806 
01807   g_free (params);
01808   return ret;
01809 }
01810 
01822 void
01823 dbus_g_object_register_marshaller (GClosureMarshal  marshaller,
01824                                    GType            rettype,
01825                                    ...)
01826 {
01827   va_list args;
01828   GArray *types;
01829   GType gtype;
01830 
01831   va_start (args, rettype);
01832 
01833   types = g_array_new (TRUE, TRUE, sizeof (GType));
01834 
01835   while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
01836     g_array_append_val (types, gtype);
01837 
01838   dbus_g_object_register_marshaller_array (marshaller, rettype,
01839                                            types->len, (GType*) types->data);
01840 
01841   g_array_free (types, TRUE);
01842   va_end (args);
01843 }
01844 
01854 void
01855 dbus_g_object_register_marshaller_array (GClosureMarshal  marshaller,
01856                                          GType            rettype,
01857                                          guint            n_types,
01858                                          const GType*     types)
01859 {
01860   DBusGFuncSignature *sig;
01861   guint i;
01862 
01863   g_static_rw_lock_writer_lock (&globals_lock);
01864 
01865   if (marshal_table == NULL)
01866     marshal_table = g_hash_table_new_full (funcsig_hash,
01867                                            funcsig_equal,
01868                                            g_free,
01869                                            NULL);
01870   sig = g_new0 (DBusGFuncSignature, 1);
01871   sig->rettype = G_TYPE_FUNDAMENTAL (rettype);
01872   sig->n_params = n_types;
01873   sig->params = g_new (GType, n_types);
01874   for (i = 0; i < n_types; i++)
01875     sig->params[i] = G_TYPE_FUNDAMENTAL (types[i]);
01876 
01877   g_hash_table_insert (marshal_table, sig, marshaller);
01878 
01879   g_static_rw_lock_writer_unlock (&globals_lock);
01880 }
01881 
01892 gchar *
01893 dbus_g_method_get_sender (DBusGMethodInvocation *context)
01894 {
01895   const gchar *sender;
01896 
01897   sender = dbus_message_get_sender (dbus_g_message_get_message (context->message));
01898 
01899   if (sender == NULL)
01900     return NULL;
01901     
01902   return strdup (sender);
01903 }
01904 
01912 DBusMessage *
01913 dbus_g_method_get_reply (DBusGMethodInvocation *context)
01914 {
01915   return dbus_message_new_method_return (dbus_g_message_get_message (context->message));
01916 }
01917 
01926 void
01927 dbus_g_method_send_reply (DBusGMethodInvocation *context, DBusMessage *reply)
01928 {
01929   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
01930   dbus_message_unref (reply);
01931 
01932   dbus_g_connection_unref (context->connection);
01933   dbus_g_message_unref (context->message);
01934   g_free (context);
01935 }
01936 
01937 
01944 void
01945 dbus_g_method_return (DBusGMethodInvocation *context, ...)
01946 {
01947   DBusMessage *reply;
01948   DBusMessageIter iter;
01949   va_list args;
01950   char *out_sig;
01951   GArray *argsig;
01952   guint i;
01953 
01954   reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
01955   out_sig = method_output_signature_from_object_info (context->object, context->method);
01956   argsig = _dbus_gtypes_from_arg_signature (out_sig, FALSE);
01957 
01958   dbus_message_iter_init_append (reply, &iter);
01959 
01960   va_start (args, context);
01961   for (i = 0; i < argsig->len; i++)
01962     {
01963       GValue value = {0,};
01964       char *error;
01965       g_value_init (&value, g_array_index (argsig, GType, i));
01966       error = NULL;
01967       G_VALUE_COLLECT (&value, args, G_VALUE_NOCOPY_CONTENTS, &error);
01968       if (error)
01969         {
01970           g_warning(error);
01971           g_free (error);
01972         }
01973       _dbus_gvalue_marshal (&iter, &value);
01974     }
01975   va_end (args);
01976 
01977   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
01978   dbus_message_unref (reply);
01979 
01980   dbus_g_connection_unref (context->connection);
01981   dbus_g_message_unref (context->message);
01982   g_free (context);
01983   g_free (out_sig);
01984 }
01985 
01993 void
01994 dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
01995 {
01996   DBusMessage *reply;
01997   reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
01998   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
01999   dbus_message_unref (reply);
02000   g_free (context);
02001 }
02002  /* end of public API */
02004 
02005 const char * _dbus_gobject_get_path (GObject *obj)
02006 {
02007   return g_object_get_data (obj, "dbus_glib_object_path");
02008 }
02009 
02010 #ifdef DBUS_BUILD_TESTS
02011 #include <stdlib.h>
02012 
02013 static void
02014 _dummy_function (void)
02015 {
02016 }
02017 
02018 /* Data structures copied from one generated by current dbus-binding-tool;
02019  * we need to support this layout forever
02020  */
02021 static const DBusGMethodInfo dbus_glib_internal_test_methods[] = {
02022   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 0 },
02023   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 49 },
02024   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 117 },
02025   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 191 },
02026   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 270 },
02027   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 320 },
02028   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 391 },
02029   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 495 },
02030   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 623 },
02031   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 693 },
02032   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 765 },
02033   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 838 },
02034   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 911 },
02035   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 988 },
02036   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1064 },
02037   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1140 },
02038   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1204 },
02039   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1278 },
02040   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1347 },
02041   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1408 },
02042   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1460 },
02043   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1533 },
02044   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1588 },
02045   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1647 },
02046   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1730 },
02047   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1784 },
02048   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1833 },
02049   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1895 },
02050   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1947 },
02051   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1999 },
02052 };
02053 
02054 const DBusGObjectInfo dbus_glib_internal_test_object_info = {
02055   0,
02056   dbus_glib_internal_test_methods,
02057   30,
02058 "org.freedesktop.DBus.Tests.MyObject\0DoNothing\0S\0\0org.freedesktop.DBus.Tests.MyObject\0Increment\0S\0x\0I\0u\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0IncrementRetval\0S\0x\0I\0u\0arg1\0O\0F\0R\0u\0\0org.freedesktop.DBus.Tests.MyObject\0IncrementRetvalError\0S\0x\0I\0u\0arg1\0O\0F\0E\0u\0\0org.freedesktop.DBus.Tests.MyObject\0ThrowError\0S\0\0org.freedesktop.DBus.Tests.MyObject\0Uppercase\0S\0arg0\0I\0s\0arg1\0O\0F\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0ManyArgs\0S\0x\0I\0u\0str\0I\0s\0trouble\0I\0d\0d_ret\0O\0F\0N\0d\0str_ret\0O\0F\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0ManyReturn\0S\0arg0\0O\0F\0N\0u\0arg1\0O\0F\0N\0s\0arg2\0O\0F\0N\0i\0arg3\0O\0F\0N\0u\0arg4\0O\0F\0N\0u\0arg5\0O\0C\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0Stringify\0S\0val\0I\0v\0arg1\0O\0F\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0Unstringify\0S\0val\0I\0s\0arg1\0O\0F\0N\0v\0\0org.freedesktop.DBus.Tests.MyObject\0Recursive1\0S\0arg0\0I\0au\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0Recursive2\0S\0arg0\0I\0u\0arg1\0O\0F\0N\0au\0\0org.freedesktop.DBus.Tests.MyObject\0ManyUppercase\0S\0arg0\0I\0as\0arg1\0O\0F\0N\0as\0\0org.freedesktop.DBus.Tests.MyObject\0StrHashLen\0S\0arg0\0I\0a{ss}\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0SendCar\0S\0arg0\0I\0(suv)\0arg1\0O\0F\0N\0(uo)\0\0org.freedesktop.DBus.Tests.MyObject\0GetHash\0S\0arg0\0O\0F\0N\0a{ss}\0\0org.freedesktop.DBus.Tests.MyObject\0RecArrays\0S\0val\0I\0aas\0arg1\0O\0F\0N\0aau\0\0org.freedesktop.DBus.Tests.MyObject\0Objpath\0S\0arg0\0I\0o\0arg1\0O\0C\0N\0o\0\0org.freedesktop.DBus.Tests.MyObject\0GetObjs\0S\0arg0\0O\0F\0N\0ao\0\0org.freedesktop.DBus.Tests.MyObject\0IncrementVal\0S\0\0org.freedesktop.DBus.Tests.MyObject\0AsyncIncrement\0A\0x\0I\0u\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0AsyncThrowError\0A\0\0org.freedesktop.DBus.Tests.MyObject\0GetVal\0S\0arg0\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0ManyStringify\0S\0arg0\0I\0a{sv}\0arg1\0O\0F\0N\0a{sv}\0\0org.freedesktop.DBus.Tests.MyObject\0EmitFrobnicate\0S\0\0org.freedesktop.DBus.Tests.MyObject\0Terminate\0S\0\0org.freedesktop.DBus.Tests.FooObject\0GetValue\0S\0arg0\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.FooObject\0EmitSignals\0S\0\0org.freedesktop.DBus.Tests.FooObject\0EmitSignal2\0S\0\0org.freedesktop.DBus.Tests.FooObject\0Terminate\0S\0\0\0",
02059 "org.freedesktop.DBus.Tests.MyObject\0Frobnicate\0org.freedesktop.DBus.Tests.FooObject\0Sig0\0org.freedesktop.DBus.Tests.FooObject\0Sig1\0org.freedesktop.DBus.Tests.FooObject\0Sig2\0\0",
02060 "\0"
02061 };
02062 
02063 
02069 gboolean
02070 _dbus_gobject_test (const char *test_data_dir)
02071 {
02072   int i;
02073   const char *arg;
02074   const char *arg_name;
02075   gboolean arg_in;
02076   gboolean constval;
02077   RetvalType retval;
02078   const char *arg_signature;
02079   const char *sigdata;
02080   const char *iface;
02081   const char *signame;
02082   
02083   static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
02084     { "SetFoo", "set_foo" },
02085     { "Foo", "foo" },
02086     { "GetFooBar", "get_foo_bar" },
02087     { "Hello", "hello" }
02088     
02089     /* Impossible-to-handle cases */
02090     /* { "FrobateUIHandler", "frobate_ui_handler" } */
02091   };
02092 
02093   /* Test lookup in our hardcoded object info; if these tests fail
02094    * then it likely means you changed the generated object info in an
02095    * incompatible way and broke the lookup functions.  In that case
02096    * you need to bump the version and use a new structure instead. */
02097   /* DoNothing */
02098   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02099                                           &(dbus_glib_internal_test_methods[0]));
02100   g_assert (*arg == '\0');
02101 
02102   /* Increment */
02103   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02104                                           &(dbus_glib_internal_test_methods[1]));
02105   g_assert (*arg != '\0');
02106   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02107   g_assert (!strcmp (arg_name, "x"));
02108   g_assert (arg_in == TRUE);
02109   g_assert (!strcmp (arg_signature, "u"));
02110   g_assert (*arg != '\0');
02111   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02112   g_assert (arg_in == FALSE);
02113   g_assert (retval == RETVAL_NONE);
02114   g_assert (!strcmp (arg_signature, "u"));
02115   g_assert (*arg == '\0');
02116 
02117   /* IncrementRetval */
02118   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02119                                           &(dbus_glib_internal_test_methods[2]));
02120   g_assert (*arg != '\0');
02121   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02122   g_assert (!strcmp (arg_name, "x"));
02123   g_assert (arg_in == TRUE);
02124   g_assert (!strcmp (arg_signature, "u"));
02125   g_assert (*arg != '\0');
02126   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02127   g_assert (retval == RETVAL_NOERROR);
02128   g_assert (arg_in == FALSE);
02129   g_assert (!strcmp (arg_signature, "u"));
02130   g_assert (*arg == '\0');
02131 
02132   /* IncrementRetvalError */
02133   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02134                                           &(dbus_glib_internal_test_methods[3]));
02135   g_assert (*arg != '\0');
02136   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02137   g_assert (!strcmp (arg_name, "x"));
02138   g_assert (arg_in == TRUE);
02139   g_assert (!strcmp (arg_signature, "u"));
02140   g_assert (*arg != '\0');
02141   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02142   g_assert (retval == RETVAL_ERROR);
02143   g_assert (arg_in == FALSE);
02144   g_assert (!strcmp (arg_signature, "u"));
02145   g_assert (*arg == '\0');
02146   
02147   /* Stringify */
02148   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02149                                           &(dbus_glib_internal_test_methods[8]));
02150   g_assert (*arg != '\0');
02151   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02152   g_assert (!strcmp (arg_name, "val"));
02153   g_assert (arg_in == TRUE);
02154   g_assert (!strcmp (arg_signature, "v"));
02155   g_assert (*arg != '\0');
02156   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02157   g_assert (retval == RETVAL_NONE);
02158   g_assert (arg_in == FALSE);
02159   g_assert (!strcmp (arg_signature, "s"));
02160   g_assert (*arg == '\0');
02161 
02162   sigdata = dbus_glib_internal_test_object_info.exported_signals;
02163   g_assert (*sigdata != '\0');
02164   sigdata = propsig_iterate (sigdata, &iface, &signame);
02165   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.MyObject"));
02166   g_assert (!strcmp (signame, "Frobnicate"));
02167   g_assert (*sigdata != '\0');
02168   sigdata = propsig_iterate (sigdata, &iface, &signame);
02169   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02170   g_assert (!strcmp (signame, "Sig0"));
02171   g_assert (*sigdata != '\0');
02172   sigdata = propsig_iterate (sigdata, &iface, &signame);
02173   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02174   g_assert (!strcmp (signame, "Sig1"));
02175   g_assert (*sigdata != '\0');
02176   sigdata = propsig_iterate (sigdata, &iface, &signame);
02177   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02178   g_assert (!strcmp (signame, "Sig2"));
02179   g_assert (*sigdata == '\0');
02180   
02181 
02182   i = 0;
02183   while (i < (int) G_N_ELEMENTS (name_pairs))
02184     {
02185       char *uscore;
02186       char *wincaps;
02187 
02188       uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
02189       wincaps = uscore_to_wincaps (name_pairs[i].uscore);
02190 
02191       if (strcmp (uscore, name_pairs[i].uscore) != 0)
02192         {
02193           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
02194                       name_pairs[i].wincaps, name_pairs[i].uscore,
02195                       uscore);
02196           exit (1);
02197         }
02198       
02199       if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
02200         {
02201           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
02202                       name_pairs[i].uscore, name_pairs[i].wincaps,
02203                       wincaps);
02204           exit (1);
02205         }
02206       
02207       g_free (uscore);
02208       g_free (wincaps);
02209 
02210       ++i;
02211     }
02212   
02213   return TRUE;
02214 }
02215 
02216 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Jul 7 15:13:58 2009 for D-BUS by  doxygen 1.4.6