Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

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 
00451       s = _dbus_gutils_wincaps_to_uscore (spec->name);
00452 
00453       spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
00454       g_assert (spec != NULL);
00455       g_free (s);
00456       
00457       dbus_type = _dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
00458       g_assert (dbus_type != NULL);
00459       
00460       can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
00461                  (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
00462       
00463       can_get = (spec->flags & G_PARAM_READABLE) != 0;
00464       
00465       if (can_set || can_get)
00466         {
00467           g_string_append_printf (xml, "    <property name=\"%s\" ", propname);
00468           g_string_append (xml, "type=\"");
00469           g_string_append (xml, dbus_type);
00470           g_string_append (xml, "\" access=\"");
00471 
00472           if (can_set && can_get)
00473             g_string_append (xml, "readwrite");
00474           else if (can_get)
00475             g_string_append (xml, "read");
00476           else
00477             {
00478               g_assert (can_set);
00479               g_string_append (xml, "write");
00480             }
00481           
00482           g_string_append (xml, "\"/>\n");
00483         }
00484       
00485       g_free (dbus_type);
00486       g_free (s);
00487 
00488       g_string_append (xml, "    </property>\n");
00489     }
00490   g_slist_free (values->properties);
00491 
00492   g_free (values);
00493   g_string_append (xml, "  </interface>\n");
00494 }
00495 
00496 static DBusGLibWriteInterfaceValues *
00497 lookup_values (GHashTable *interfaces, const char *method_interface)
00498 {
00499   DBusGLibWriteInterfaceValues *values;
00500   if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
00501     {
00502       values = g_new0 (DBusGLibWriteInterfaceValues, 1);
00503       g_hash_table_insert (interfaces, (gpointer) method_interface, values);
00504     }
00505   return values;
00506 }
00507 
00508 static void
00509 introspect_interfaces (GObject *object, GString *xml)
00510 {
00511   const DBusGObjectInfo *info;
00512   DBusGLibWriteIterfaceData data;
00513   int i;
00514   GHashTable *interfaces;
00515   DBusGLibWriteInterfaceValues *values;
00516   const char *propsig;
00517 
00518   info = lookup_object_info (object);
00519 
00520   g_assert (info != NULL);
00521 
00522   /* Gather a list of all interfaces, indexed into their methods */
00523   interfaces = g_hash_table_new (g_str_hash, g_str_equal);
00524   for (i = 0; i < info->n_method_infos; i++)
00525     {
00526       const char *method_name;
00527       const char *method_interface;
00528       const char *method_args;
00529       const DBusGMethodInfo *method;
00530 
00531       method = &(info->method_infos[i]);
00532 
00533       method_interface = method_interface_from_object_info (info, method);
00534       method_name = method_name_from_object_info (info, method);
00535       method_args = method_arg_info_from_object_info (info, method);
00536 
00537       values = lookup_values (interfaces, method_interface);
00538       values->methods = g_slist_prepend (values->methods, (gpointer) method);
00539     }
00540 
00541   propsig = info->exported_signals;
00542   while (*propsig)
00543     {
00544       const char *iface;
00545       const char *signame;
00546 
00547       propsig = propsig_iterate (propsig, &iface, &signame);
00548 
00549       values = lookup_values (interfaces, iface);
00550       values->signals = g_slist_prepend (values->signals, (gpointer) signame);
00551     }
00552 
00553   propsig = info->exported_properties;
00554   while (*propsig)
00555     {
00556       const char *iface;
00557       const char *propname;
00558 
00559       propsig = propsig_iterate (propsig, &iface, &propname);
00560 
00561       values = lookup_values (interfaces, iface);
00562       values->properties = g_slist_prepend (values->properties, (gpointer) propname);
00563     }
00564   
00565   memset (&data, 0, sizeof (data));
00566   data.xml = xml;
00567   data.gtype = G_TYPE_FROM_INSTANCE (object);
00568   data.object_info = info;
00569   g_hash_table_foreach (interfaces, write_interface, &data);
00570   
00571   g_hash_table_destroy (interfaces);
00572 }
00573 
00574 static DBusHandlerResult
00575 handle_introspect (DBusConnection *connection,
00576                    DBusMessage    *message,
00577                    GObject        *object)
00578 {
00579   GString *xml;
00580   unsigned int i;
00581   DBusMessage *ret;
00582   char **children;
00583   
00584   if (!dbus_connection_list_registered (connection, 
00585                                         dbus_message_get_path (message),
00586                                         &children))
00587     g_error ("Out of memory");
00588   
00589   xml = g_string_new (NULL);
00590 
00591   g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
00592   
00593   g_string_append (xml, "<node>\n");
00594 
00595   /* We are introspectable, though I guess that was pretty obvious */
00596   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE);
00597   g_string_append (xml, "    <method name=\"Introspect\">\n");
00598   g_string_append_printf (xml, "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00599   g_string_append (xml, "    </method>\n");
00600   g_string_append (xml, "  </interface>\n");
00601 
00602   /* We support get/set properties */
00603   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_PROPERTIES);
00604   g_string_append (xml, "    <method name=\"Get\">\n");
00605   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00606   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00607   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00608   g_string_append (xml, "    </method>\n");
00609   g_string_append (xml, "    <method name=\"Set\">\n");
00610   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00611   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00612   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00613   g_string_append (xml, "    </method>\n");
00614   g_string_append (xml, "  </interface>\n");
00615   
00616   introspect_interfaces (object, xml);
00617 
00618   /* Append child nodes */
00619   for (i = 0; children[i]; i++)
00620       g_string_append_printf (xml, "  <node name=\"%s\"/>\n",
00621                               children[i]);
00622   
00623   /* Close the XML, and send it to the requesting app */
00624   g_string_append (xml, "</node>\n");
00625 
00626   ret = dbus_message_new_method_return (message);
00627   if (ret == NULL)
00628     g_error ("Out of memory");
00629 
00630   dbus_message_append_args (ret,
00631                             DBUS_TYPE_STRING, &xml->str,
00632                             DBUS_TYPE_INVALID);
00633 
00634   dbus_connection_send (connection, ret, NULL);
00635   dbus_message_unref (ret);
00636 
00637   g_string_free (xml, TRUE);
00638 
00639   dbus_free_string_array (children);
00640   
00641   return DBUS_HANDLER_RESULT_HANDLED;
00642 }
00643 
00644 static DBusMessage*
00645 set_object_property (DBusConnection  *connection,
00646                      DBusMessage     *message,
00647                      DBusMessageIter *iter,
00648                      GObject         *object,
00649                      GParamSpec      *pspec)
00650 {
00651   GValue value = { 0, };
00652   DBusMessage *ret;
00653   DBusMessageIter sub;
00654   DBusGValueMarshalCtx context;
00655 
00656   dbus_message_iter_recurse (iter, &sub);
00657 
00658   context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00659   context.proxy = NULL;
00660 
00661   g_value_init (&value, pspec->value_type);
00662   if (_dbus_gvalue_demarshal (&context, &sub, &value, NULL))
00663     {
00664       g_object_set_property (object,
00665                              pspec->name,
00666                              &value);
00667 
00668       g_value_unset (&value);
00669 
00670       ret = dbus_message_new_method_return (message);
00671       if (ret == NULL)
00672         g_error ("out of memory");
00673     }
00674   else
00675     {
00676       ret = dbus_message_new_error (message,
00677                                     DBUS_ERROR_INVALID_ARGS,
00678                                     "Argument's D-BUS type can't be converted to a GType");
00679       if (ret == NULL)
00680         g_error ("out of memory");
00681     }
00682 
00683   return ret;
00684 }
00685 
00686 static DBusMessage*
00687 get_object_property (DBusConnection *connection,
00688                      DBusMessage    *message,
00689                      GObject        *object,
00690                      GParamSpec     *pspec)
00691 {
00692   GType value_type;
00693   GValue value = {0, };
00694   DBusMessage *ret;
00695   DBusMessageIter iter;
00696 
00697   value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
00698 
00699   ret = dbus_message_new_method_return (message);
00700   if (ret == NULL)
00701     g_error ("out of memory");
00702 
00703   g_value_init (&value, value_type);
00704   g_object_get_property (object, pspec->name, &value);
00705 
00706   value_type = G_VALUE_TYPE (&value);
00707 
00708   dbus_message_iter_init_append (message, &iter);
00709 
00710   if (!_dbus_gvalue_marshal (&iter, &value))
00711     {
00712       dbus_message_unref (ret);
00713       ret = dbus_message_new_error (message,
00714                                     DBUS_ERROR_UNKNOWN_METHOD,
00715                                     "Can't convert GType of object property to a D-BUS type");
00716     }
00717 
00718   return ret;
00719 }
00720 
00721 static gboolean
00722 lookup_object_and_method (GObject      *object,
00723                           DBusMessage  *message,
00724                           const DBusGObjectInfo **object_ret,
00725                           const DBusGMethodInfo **method_ret)
00726 {
00727   const char *interface;
00728   const char *member;
00729   const char *signature;
00730   gboolean ret;
00731   const DBusGObjectInfo *info;
00732   int i;
00733 
00734   interface = dbus_message_get_interface (message);
00735   member = dbus_message_get_member (message);
00736   signature = dbus_message_get_signature (message);
00737   ret = FALSE;
00738 
00739   info = lookup_object_info (object);
00740   *object_ret = info;
00741   
00742   for (i = 0; i < info->n_method_infos; i++)
00743     {
00744       const char *expected_member;
00745       const char *expected_interface;
00746       char *expected_signature;
00747       const DBusGMethodInfo *method;
00748 
00749       method = &(info->method_infos[i]);
00750 
00751       /* Check method interface/name and input signature */ 
00752       expected_interface = method_interface_from_object_info (*object_ret, method);
00753       expected_member = method_name_from_object_info (*object_ret, method);
00754       expected_signature = method_input_signature_from_object_info (*object_ret, method);
00755 
00756       if ((interface == NULL
00757            || strcmp (expected_interface, interface) == 0)
00758           && strcmp (expected_member, member) == 0
00759           && strcmp (expected_signature, signature) == 0)
00760         {
00761           g_free (expected_signature);
00762           *method_ret = method;
00763           return TRUE;
00764         }
00765       g_free (expected_signature);
00766     }
00767 
00768   return ret;
00769 }
00770 
00771 static char *
00772 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
00773                                       const char *msg_interface,
00774                                       GQuark domain, gint code)
00775 {
00776   const char *domain_str;
00777   const char *code_str;
00778   GString *dbus_error_name;
00779 
00780   domain_str = object_error_domain_prefix_from_object_info (object_info);
00781   code_str = object_error_code_from_object_info (object_info, domain, code);
00782 
00783   if (!domain_str || !code_str)
00784     {
00785       DBusGErrorInfo *info;
00786 
00787       g_static_rw_lock_reader_lock (&globals_lock);
00788 
00789       if (error_metadata != NULL)
00790         info = g_datalist_id_get_data (&error_metadata, domain);
00791       else
00792         info = NULL;
00793 
00794       g_static_rw_lock_reader_unlock (&globals_lock);
00795 
00796       if (info)
00797         {
00798           GEnumValue *value;
00799           GEnumClass *klass;
00800 
00801           klass = g_type_class_ref (info->code_enum);
00802           value = g_enum_get_value (klass, code);
00803           g_type_class_unref (klass);
00804 
00805           domain_str = info->default_iface;
00806           code_str = value->value_nick;
00807         }
00808     }
00809 
00810   if (!domain_str)
00811     domain_str = msg_interface;
00812 
00813   if (!domain_str || !code_str)
00814     {
00815       /* If we can't map it sensibly, make up an error name */
00816       char *domain_from_quark;
00817       
00818       dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
00819 
00820       domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
00821       g_string_append (dbus_error_name, domain_from_quark);
00822       g_free (domain_from_quark);
00823         
00824       g_string_append_printf (dbus_error_name, ".Code%d", code);
00825     }
00826   else
00827     {
00828       dbus_error_name = g_string_new (domain_str);
00829       g_string_append_c (dbus_error_name, '.');
00830       g_string_append (dbus_error_name, code_str);
00831     }
00832 
00833   return g_string_free (dbus_error_name, FALSE);
00834 }
00835 
00836 static DBusMessage *
00837 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
00838                               DBusMessage     *message,
00839                               GError          *error)
00840 {
00841   DBusMessage *reply;
00842 
00843   if (!error)
00844     {
00845       char *error_msg;
00846       
00847       error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
00848       reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
00849       g_free (error_msg);
00850     }
00851   else
00852     {
00853       if (error->domain == DBUS_GERROR)
00854         reply = dbus_message_new_error (message,
00855                                         dbus_g_error_get_name (error),
00856                                         error->message);
00857       else
00858         {
00859           char *error_name;
00860           error_name = gerror_domaincode_to_dbus_error_name (object_info,
00861                                                              dbus_message_get_interface (message),
00862                                                              error->domain, error->code);
00863           reply = dbus_message_new_error (message, error_name, error->message);
00864           g_free (error_name); 
00865         }
00866     }
00867   return reply;
00868 }
00869 
00874 struct _DBusGMethodInvocation {
00875   DBusGConnection *connection; 
00876   DBusGMessage *message; 
00877   const DBusGObjectInfo *object; 
00878   const DBusGMethodInfo *method; 
00879 };
00880 
00881 static DBusHandlerResult
00882 invoke_object_method (GObject         *object,
00883                       const DBusGObjectInfo *object_info,
00884                       const DBusGMethodInfo *method,
00885                       DBusConnection  *connection,
00886                       DBusMessage     *message)
00887 {
00888   gboolean had_error, call_only;
00889   GError *gerror;
00890   GValueArray *value_array;
00891   GValue return_value = {0,};
00892   GClosure closure;
00893   char *in_signature;
00894   GArray *out_param_values = NULL;
00895   GValueArray *out_param_gvalues = NULL;
00896   int out_param_count;
00897   int out_param_pos, out_param_gvalue_pos;
00898   DBusHandlerResult result;
00899   DBusMessage *reply;
00900   gboolean have_retval;
00901   gboolean retval_signals_error;
00902   gboolean retval_is_synthetic;
00903   gboolean retval_is_constant;
00904   const char *arg_metadata;
00905 
00906   gerror = NULL;
00907 
00908   /* Determine whether or not this method should be invoked in a new
00909      thread
00910    */
00911   if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
00912     call_only = TRUE;
00913   else
00914     call_only = FALSE;
00915 
00916   have_retval = FALSE;
00917   retval_signals_error = FALSE;
00918   retval_is_synthetic = FALSE;
00919   retval_is_constant = FALSE;
00920 
00921   /* This is evil.  We do this to work around the fact that
00922    * the generated glib marshallers check a flag in the closure object
00923    * which we don't care about.  We don't need/want to create
00924    * a new closure for each invocation.
00925    */
00926   memset (&closure, 0, sizeof (closure));
00927 
00928   in_signature = method_input_signature_from_object_info (object_info, method); 
00929   
00930   /* Convert method IN parameters to GValueArray */
00931   {
00932     GArray *types_array;
00933     guint n_params;
00934     const GType *types;
00935     DBusGValueMarshalCtx context;
00936     GError *error = NULL;
00937     
00938     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00939     context.proxy = NULL;
00940 
00941     types_array = _dbus_gtypes_from_arg_signature (in_signature, FALSE);
00942     n_params = types_array->len;
00943     types = (const GType*) types_array->data;
00944 
00945     value_array = _dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
00946     if (value_array == NULL)
00947       {
00948         g_free (in_signature); 
00949         g_array_free (types_array, TRUE);
00950         reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
00951         dbus_connection_send (connection, reply, NULL);
00952         dbus_message_unref (reply);
00953         g_error_free (error);
00954         return DBUS_HANDLER_RESULT_HANDLED;
00955       }
00956     g_array_free (types_array, TRUE);
00957   }
00958 
00959   /* Prepend object as first argument */ 
00960   g_value_array_prepend (value_array, NULL);
00961   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT);
00962   g_value_set_object (g_value_array_get_nth (value_array, 0), object);
00963   
00964   if (call_only)
00965     {
00966       GValue context_value = {0,};
00967       DBusGMethodInvocation *context;
00968       context = g_new (DBusGMethodInvocation, 1);
00969       context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
00970       context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
00971       context->object = object_info;
00972       context->method = method;
00973       g_value_init (&context_value, G_TYPE_POINTER);
00974       g_value_set_pointer (&context_value, context);
00975       g_value_array_append (value_array, &context_value);
00976     }
00977   else
00978     {
00979       RetvalType retval;
00980       gboolean arg_in;
00981       gboolean arg_const;
00982       const char *argsig;
00983 
00984       arg_metadata = method_arg_info_from_object_info (object_info, method);
00985       
00986       /* Count number of output parameters, and look for a return value */
00987       out_param_count = 0;
00988       while (*arg_metadata)
00989         {
00990           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
00991           if (arg_in)
00992             continue;
00993           if (retval != RETVAL_NONE)
00994             {
00995               DBusSignatureIter tmp_sigiter;
00996               /* This is the function return value */
00997               g_assert (!have_retval);
00998               have_retval = TRUE;
00999               retval_is_synthetic = FALSE;
01000 
01001               switch (retval)
01002                 {
01003                 case RETVAL_NONE:
01004                   g_assert_not_reached ();
01005                   break;
01006                 case RETVAL_NOERROR:
01007                   retval_signals_error = FALSE;
01008                   break;
01009                 case RETVAL_ERROR:
01010                   retval_signals_error = TRUE;
01011                   break;
01012                 }
01013 
01014               retval_is_constant = arg_const;
01015 
01016               /* Initialize our return GValue with the specified type */
01017               dbus_signature_iter_init (&tmp_sigiter, argsig);
01018               g_value_init (&return_value, _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
01019             }
01020           else
01021             {
01022               /* It's a regular output value */
01023               out_param_count++;
01024             }
01025         }
01026 
01027       /* For compatibility, if we haven't found a return value, we assume
01028        * the function returns a gboolean for signalling an error
01029        * (and therefore also takes a GError).  We also note that it
01030        * is a "synthetic" return value; i.e. we aren't going to be
01031        * sending it over the bus, it's just to signal an error.
01032        */
01033       if (!have_retval)
01034         {
01035           have_retval = TRUE;
01036           retval_is_synthetic = TRUE;
01037           retval_signals_error = TRUE;
01038           g_value_init (&return_value, G_TYPE_BOOLEAN);
01039         }
01040 
01041       /* Create an array to store the actual values of OUT parameters
01042        * (other than the real function return, if any).  Then, create
01043        * a GValue boxed POINTER to each of those values, and append to
01044        * the invocation, so the method can return the OUT parameters.
01045        */
01046       out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
01047 
01048       /* We have a special array of GValues for toplevel GValue return
01049        * types.
01050        */
01051       out_param_gvalues = g_value_array_new (out_param_count);
01052       out_param_pos = 0;
01053       out_param_gvalue_pos = 0;
01054 
01055       /* Reset argument metadata pointer */
01056       arg_metadata = method_arg_info_from_object_info (object_info, method);
01057       
01058       /* Iterate over output arguments again, this time allocating space for
01059        * them as appopriate.
01060        */
01061       while (*arg_metadata)
01062         {
01063           GValue value = {0, };
01064           GTypeCValue storage;
01065           DBusSignatureIter tmp_sigiter;
01066           GType current_gtype;
01067 
01068           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
01069           /* Skip over input arguments and the return value, if any */
01070           if (arg_in || retval != RETVAL_NONE)
01071             continue;
01072 
01073           dbus_signature_iter_init (&tmp_sigiter, argsig);
01074           current_gtype = _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
01075 
01076           g_value_init (&value, G_TYPE_POINTER);
01077 
01078           /* We special case variants to make method invocation a bit nicer */
01079           if (current_gtype != G_TYPE_VALUE)
01080             {
01081               memset (&storage, 0, sizeof (storage));
01082               g_array_append_val (out_param_values, storage);
01083               g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
01084               out_param_pos++;
01085             }
01086           else
01087             {
01088               g_value_array_append (out_param_gvalues, NULL);
01089               g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
01090               out_param_gvalue_pos++;
01091             }
01092           g_value_array_append (value_array, &value);
01093         }
01094     }
01095 
01096   /* Append GError as final argument if necessary */
01097   if (retval_signals_error)
01098     {
01099       g_assert (have_retval);
01100       g_value_array_append (value_array, NULL);
01101       g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
01102       g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
01103     }
01104   
01105   /* Actually invoke method */
01106   method->marshaller (&closure, have_retval ? &return_value : NULL,
01107                       value_array->n_values,
01108                       value_array->values,
01109                       NULL, method->function);
01110   if (call_only)
01111     {
01112       result = DBUS_HANDLER_RESULT_HANDLED;
01113       goto done;
01114     }
01115   if (retval_signals_error)
01116     had_error = _dbus_gvalue_signals_error (&return_value);
01117   else
01118     had_error = FALSE;
01119 
01120   if (!had_error)
01121     {
01122       DBusMessageIter iter;
01123 
01124       reply = dbus_message_new_method_return (message);
01125       if (reply == NULL)
01126         goto nomem;
01127 
01128       /* Append output arguments to reply */
01129       dbus_message_iter_init_append (reply, &iter);
01130 
01131       /* First, append the return value, unless it's synthetic */
01132       if (have_retval && !retval_is_synthetic)
01133         {
01134           if (!_dbus_gvalue_marshal (&iter, &return_value))
01135             goto nomem;
01136           if (!retval_is_constant)
01137             g_value_unset (&return_value);
01138         }
01139 
01140       /* Grab the argument metadata and iterate over it */
01141       arg_metadata = method_arg_info_from_object_info (object_info, method);
01142       
01143       /* Now append any remaining return values */
01144       out_param_pos = 0;
01145       out_param_gvalue_pos = 0;
01146       while (*arg_metadata)
01147         {
01148           GValue gvalue = {0, };
01149           const char *arg_name;
01150           gboolean arg_in;
01151           gboolean constval;
01152           RetvalType retval;
01153           const char *arg_signature;
01154           DBusSignatureIter argsigiter;
01155 
01156           do
01157             {
01158               /* Iterate over only output values; skip over input
01159                  arguments and the return value */
01160               arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
01161             }
01162           while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
01163 
01164           /* If the last argument we saw was input or the return
01165            * value, we must be done iterating over output arguments.
01166            */
01167           if (arg_in || retval != RETVAL_NONE)
01168             break;
01169 
01170           dbus_signature_iter_init (&argsigiter, arg_signature);
01171           
01172           g_value_init (&gvalue, _dbus_gtype_from_signature_iter (&argsigiter, FALSE));
01173           if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
01174             {
01175               if (!_dbus_gvalue_take (&gvalue,
01176                                      &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
01177                 g_assert_not_reached ();
01178               out_param_pos++;
01179             }
01180           else
01181             {
01182               g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
01183               out_param_gvalue_pos++;
01184             }
01185               
01186           if (!_dbus_gvalue_marshal (&iter, &gvalue))
01187             goto nomem;
01188           /* Here we actually free the allocated value; we
01189            * took ownership of it with _dbus_gvalue_take, unless
01190            * an annotation has specified this value as constant.
01191            */
01192           if (!constval)
01193             g_value_unset (&gvalue);
01194         }
01195     }
01196   else
01197     reply = gerror_to_dbus_error_message (object_info, message, gerror);
01198 
01199   if (reply)
01200     {
01201       dbus_connection_send (connection, reply, NULL);
01202       dbus_message_unref (reply);
01203     }
01204 
01205   result = DBUS_HANDLER_RESULT_HANDLED;
01206  done:
01207   g_free (in_signature);
01208   if (!call_only)
01209     {
01210       g_array_free (out_param_values, TRUE);
01211       g_value_array_free (out_param_gvalues);
01212     }
01213   g_value_array_free (value_array);
01214   return result;
01215  nomem:
01216   result = DBUS_HANDLER_RESULT_NEED_MEMORY;
01217   goto done;
01218 }
01219 
01220 static DBusHandlerResult
01221 gobject_message_function (DBusConnection  *connection,
01222                           DBusMessage     *message,
01223                           void            *user_data)
01224 {
01225   GParamSpec *pspec;
01226   GObject *object;
01227   gboolean setter;
01228   gboolean getter;
01229   char *s;
01230   const char *wincaps_propname;
01231   /* const char *wincaps_propiface; */
01232   DBusMessageIter iter;
01233   const DBusGMethodInfo *method;
01234   const DBusGObjectInfo *object_info;
01235 
01236   object = G_OBJECT (user_data);
01237 
01238   if (dbus_message_is_method_call (message,
01239                                    DBUS_INTERFACE_INTROSPECTABLE,
01240                                    "Introspect"))
01241     return handle_introspect (connection, message, object);
01242   
01243   /* Try the metainfo, which lets us invoke methods */
01244   if (lookup_object_and_method (object, message, &object_info, &method))
01245     return invoke_object_method (object, object_info, method, connection, message);
01246 
01247   /* If no metainfo, we can still do properties and signals
01248    * via standard GLib introspection
01249    */
01250   getter = FALSE;
01251   setter = FALSE;
01252   if (dbus_message_is_method_call (message,
01253                                    DBUS_INTERFACE_PROPERTIES,
01254                                    "Get"))
01255     getter = TRUE;
01256   else if (dbus_message_is_method_call (message,
01257                                         DBUS_INTERFACE_PROPERTIES,
01258                                         "Set"))
01259     setter = TRUE;
01260 
01261   if (!(setter || getter))
01262     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01263 
01264   dbus_message_iter_init (message, &iter);
01265 
01266   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01267     {
01268       g_warning ("Property get or set does not have an interface string as first arg\n");
01269       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01270     }
01271   /* We never use the interface name; if we did, we'd need to
01272    * remember that it can be empty string for "pick one for me"
01273    */
01274   /* dbus_message_iter_get_basic (&iter, &wincaps_propiface); */
01275   dbus_message_iter_next (&iter);
01276 
01277   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01278     {
01279       g_warning ("Property get or set does not have a property name string as second arg\n");
01280       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01281     }
01282   dbus_message_iter_get_basic (&iter, &wincaps_propname);
01283   dbus_message_iter_next (&iter);
01284   
01285   s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
01286 
01287   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
01288                                         s);
01289 
01290   g_free (s);
01291 
01292   if (pspec != NULL)
01293     {
01294       DBusMessage *ret;
01295 
01296       if (setter)
01297         {
01298           if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
01299             {
01300               g_warning ("Property set does not have a variant value as third arg\n");
01301               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01302             }
01303           
01304           ret = set_object_property (connection, message, &iter,
01305                                      object, pspec);
01306           dbus_message_iter_next (&iter);
01307         }
01308       else if (getter)
01309         {     
01310           ret = get_object_property (connection, message,
01311                                      object, pspec);
01312         }
01313       else
01314         {
01315           g_assert_not_reached ();
01316           ret = NULL;
01317         }
01318 
01319       g_assert (ret != NULL);
01320 
01321       if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
01322         g_warning ("Property get or set had too many arguments\n");
01323       
01324       dbus_connection_send (connection, ret, NULL);
01325       dbus_message_unref (ret);
01326       return DBUS_HANDLER_RESULT_HANDLED;
01327     }
01328 
01329   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01330 }
01331 
01332 static DBusObjectPathVTable gobject_dbus_vtable = {
01333   gobject_unregister_function,
01334   gobject_message_function,
01335   NULL
01336 };
01337 
01338 typedef struct {
01339   GClosure         closure;
01340   DBusGConnection *connection;
01341   GObject         *object;
01342   const char      *signame;
01343   const char      *sigiface;
01344 } DBusGSignalClosure;
01345 
01346 static GClosure *
01347 dbus_g_signal_closure_new (DBusGConnection *connection,
01348                            GObject         *object,
01349                            const char      *signame,
01350                            const char      *sigiface)
01351 {
01352   DBusGSignalClosure *closure;
01353   
01354   closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
01355 
01356   closure->connection = dbus_g_connection_ref (connection);
01357   closure->object = object;
01358   closure->signame = signame;
01359   closure->sigiface = sigiface;
01360   return (GClosure*) closure;
01361 }
01362 
01363 static void
01364 dbus_g_signal_closure_finalize (gpointer data,
01365                                 GClosure *closure)
01366 {
01367   DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
01368 
01369   dbus_g_connection_unref (sigclosure->connection);
01370 }
01371 
01372 static void
01373 signal_emitter_marshaller (GClosure        *closure,
01374                            GValue          *retval,
01375                            guint            n_param_values,
01376                            const GValue    *param_values,
01377                            gpointer         invocation_hint,
01378                            gpointer         marshal_data)
01379 {
01380   DBusGSignalClosure *sigclosure;
01381   DBusMessage *signal;
01382   DBusMessageIter iter;
01383   guint i;
01384   const char *path;
01385 
01386   sigclosure = (DBusGSignalClosure *) closure;
01387   
01388   g_assert (retval == NULL);
01389 
01390   path = _dbus_gobject_get_path (sigclosure->object);
01391 
01392   g_assert (path != NULL);
01393 
01394   signal = dbus_message_new_signal (path,
01395                                     sigclosure->sigiface,
01396                                     sigclosure->signame);
01397   if (!signal)
01398     {
01399       g_error ("out of memory");
01400       return;
01401     }
01402 
01403   dbus_message_iter_init_append (signal, &iter);
01404 
01405   /* First argument is the object itself, and we can't marshall that */
01406   for (i = 1; i < n_param_values; i++)
01407     {
01408       if (!_dbus_gvalue_marshal (&iter,
01409                                 (GValue *) (&(param_values[i]))))
01410         {
01411           g_warning ("failed to marshal parameter %d for signal %s",
01412                      i, sigclosure->signame);
01413           goto out;
01414         }
01415     }
01416   dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
01417                         signal, NULL);
01418  out:
01419   dbus_message_unref (signal);
01420 }
01421 
01422 static void
01423 export_signals (DBusGConnection *connection, const DBusGObjectInfo *info, GObject *object)
01424 {
01425   GType gtype;
01426   const char *sigdata;
01427   const char *iface;
01428   const char *signame;
01429 
01430   gtype = G_TYPE_FROM_INSTANCE (object);
01431 
01432   sigdata = info->exported_signals;
01433   
01434   while (*sigdata != '\0')
01435     {
01436       guint id;
01437       GSignalQuery query;
01438       GClosure *closure;
01439       char *s;
01440 
01441       sigdata = propsig_iterate (sigdata, &iface, &signame);
01442       
01443       s = _dbus_gutils_wincaps_to_uscore (signame);
01444 
01445       id = g_signal_lookup (s, gtype);
01446       if (id == 0)
01447         {
01448           g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
01449                      s, signame, g_type_name (gtype));
01450           g_free (s);
01451           continue;
01452         }
01453 
01454       g_signal_query (id, &query);
01455 
01456       if (query.return_type != G_TYPE_NONE)
01457         {
01458           g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"",
01459                      s, g_type_name (gtype), g_type_name (query.return_type));
01460           g_free (s);
01461           continue; /* FIXME: these could be listed as methods ? */
01462         }
01463       
01464       closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
01465       g_closure_set_marshal (closure, signal_emitter_marshaller);
01466 
01467       g_signal_connect_closure_by_id (object,
01468                                       id,
01469                                       0,
01470                                       closure,
01471                                       FALSE);
01472 
01473       g_closure_add_finalize_notifier (closure, NULL,
01474                                        dbus_g_signal_closure_finalize);
01475       g_free (s);
01476     }
01477 }
01478 
01479 #include "dbus-glib-error-switch.h"
01480 
01481 void
01482 dbus_set_g_error (GError    **gerror,
01483                   DBusError  *error)
01484 {
01485   int code;
01486 
01487   code = dbus_error_to_gerror_code (error->name);
01488   if (code != DBUS_GERROR_REMOTE_EXCEPTION)
01489     g_set_error (gerror, DBUS_GERROR,
01490                  code,
01491                  "%s",
01492                  error->message);
01493   else
01494     g_set_error (gerror, DBUS_GERROR,
01495                  code,
01496                  "%s%c%s",
01497                  error->message ? error->message : "",
01498                  '\0',
01499                  error->name);
01500 }
01501 
01502 static void
01503 dbus_g_error_info_free (gpointer p)
01504 {
01505   DBusGErrorInfo *info;
01506 
01507   info = p;
01508 
01509   g_free (info->default_iface);
01510   g_free (info);
01511 }
01512  /* end of internals */
01514 
01534 void
01535 dbus_g_object_type_install_info (GType                  object_type,
01536                                  const DBusGObjectInfo *info)
01537 {
01538   g_return_if_fail (G_TYPE_IS_CLASSED (object_type));
01539 
01540   _dbus_g_value_types_init ();
01541 
01542   g_type_set_qdata (object_type,
01543                     dbus_g_object_type_dbus_metadata_quark (),
01544                     (gpointer) info);
01545 }
01546 
01556 void
01557 dbus_g_error_domain_register (GQuark                domain,
01558                               const char           *default_iface,
01559                               GType                 code_enum)
01560 {
01561   DBusGErrorInfo *info;
01562   
01563   g_return_if_fail (g_quark_to_string (domain) != NULL);
01564   g_return_if_fail (code_enum != G_TYPE_INVALID);
01565   g_return_if_fail (G_TYPE_FUNDAMENTAL (code_enum) == G_TYPE_ENUM);
01566 
01567   g_static_rw_lock_writer_lock (&globals_lock);
01568 
01569   if (error_metadata == NULL)
01570     g_datalist_init (&error_metadata);
01571 
01572   info = g_datalist_id_get_data (&error_metadata, domain);
01573 
01574   if (info != NULL)
01575     {
01576       g_warning ("Metadata for error domain \"%s\" already registered\n",
01577                  g_quark_to_string (domain));
01578     }
01579   else
01580     {
01581       info = g_new0 (DBusGErrorInfo, 1);
01582       info->default_iface = g_strdup (default_iface);
01583       info->code_enum = code_enum;
01584 
01585       g_datalist_id_set_data_full (&error_metadata,
01586                                    domain,
01587                                    info,
01588                                    dbus_g_error_info_free);
01589     }
01590 
01591   g_static_rw_lock_writer_unlock (&globals_lock);
01592 }
01593 
01594 static void
01595 unregister_gobject (DBusGConnection *connection, GObject *dead)
01596 {
01597   char *path;
01598   path = g_object_steal_data (dead, "dbus_glib_object_path");
01599   dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection), path);
01600   g_free (path);
01601 }
01602 
01616 void
01617 dbus_g_connection_register_g_object (DBusGConnection       *connection,
01618                                      const char            *at_path,
01619                                      GObject               *object)
01620 {
01621   const DBusGObjectInfo *info;
01622   g_return_if_fail (connection != NULL);
01623   g_return_if_fail (at_path != NULL);
01624   g_return_if_fail (G_IS_OBJECT (object));
01625 
01626   info = lookup_object_info (object);
01627   if (info == NULL)
01628     {
01629       g_warning ("No introspection data registered for object class \"%s\"",
01630                  g_type_name (G_TYPE_FROM_INSTANCE (object)));
01631       return;
01632     }
01633 
01634   if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
01635                                              at_path,
01636                                              &gobject_dbus_vtable,
01637                                              object))
01638     {
01639       g_error ("Failed to register GObject with DBusConnection");
01640       return;
01641     }
01642 
01643   export_signals (connection, info, object);
01644 
01645   g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
01646   g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
01647 }
01648 
01649 GObject *
01650 dbus_g_connection_lookup_g_object (DBusGConnection       *connection,
01651                                    const char            *at_path)
01652 {
01653   gpointer ret;
01654   if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
01655     return NULL;
01656   return ret;
01657 }
01658 
01659 typedef struct {
01660   GType    rettype;
01661   guint    n_params;
01662   GType   *params;
01663 } DBusGFuncSignature;
01664 
01665 static guint
01666 funcsig_hash (gconstpointer key)
01667 {
01668   const DBusGFuncSignature *sig = key;
01669   GType *types;
01670   guint ret;
01671   guint i;
01672 
01673   ret = sig->rettype;
01674   types = sig->params;
01675 
01676   for (i = 0; i < sig->n_params; i++)
01677     {
01678       ret += (int) (*types);
01679       types++;
01680     }
01681       
01682   return ret;
01683 }
01684 
01685 static gboolean
01686 funcsig_equal (gconstpointer aval,
01687                gconstpointer bval)
01688 {
01689   const DBusGFuncSignature *a = aval;
01690   const DBusGFuncSignature *b = bval;
01691   const GType *atypes;
01692   const GType *btypes;
01693   guint i;
01694 
01695   if (a->rettype != b->rettype
01696       || a->n_params != b->n_params)
01697     return FALSE;
01698 
01699   atypes = a->params;
01700   btypes = b->params;
01701 
01702   for (i = 0; i < a->n_params; i++)
01703     {
01704       if (*btypes != *atypes)
01705         return FALSE;
01706       atypes++;
01707       btypes++;
01708     }
01709       
01710   return TRUE;
01711 }
01712 
01713 GClosureMarshal
01714 _dbus_gobject_lookup_marshaller (GType        rettype,
01715                                  guint        n_params,
01716                                  const GType *param_types)
01717 {
01718   GClosureMarshal ret;
01719   DBusGFuncSignature sig;
01720   GType *params;
01721   guint i;
01722 
01723   /* Convert to fundamental types */
01724   rettype = G_TYPE_FUNDAMENTAL (rettype);
01725   params = g_new (GType, n_params);
01726   for (i = 0; i < n_params; i++)
01727     params[i] = G_TYPE_FUNDAMENTAL (param_types[i]);
01728 
01729   sig.rettype = rettype;
01730   sig.n_params = n_params;
01731   sig.params = params;
01732   
01733   g_static_rw_lock_reader_lock (&globals_lock);
01734 
01735   if (marshal_table)
01736     ret = g_hash_table_lookup (marshal_table, &sig);
01737   else
01738     ret = NULL;
01739 
01740   g_static_rw_lock_reader_unlock (&globals_lock);
01741 
01742   if (ret == NULL)
01743     {
01744       if (rettype == G_TYPE_NONE)
01745         {
01746           if (n_params == 0)
01747             ret = g_cclosure_marshal_VOID__VOID;
01748           else if (n_params == 1)
01749             {
01750               switch (params[0])
01751                 {
01752                 case G_TYPE_BOOLEAN:
01753                   ret = g_cclosure_marshal_VOID__BOOLEAN;
01754                   break;
01755                 case G_TYPE_UCHAR:
01756                   ret = g_cclosure_marshal_VOID__UCHAR;
01757                   break;
01758                 case G_TYPE_INT:
01759                   ret = g_cclosure_marshal_VOID__INT;
01760                   break;
01761                 case G_TYPE_UINT:
01762                   ret = g_cclosure_marshal_VOID__UINT;
01763                   break;
01764                 case G_TYPE_DOUBLE:
01765                   ret = g_cclosure_marshal_VOID__DOUBLE;
01766                   break;
01767                 case G_TYPE_STRING:
01768                   ret = g_cclosure_marshal_VOID__STRING;
01769                   break;
01770                 case G_TYPE_BOXED:
01771                   ret = g_cclosure_marshal_VOID__BOXED;
01772                   break;
01773                 }
01774             }
01775           else if (n_params == 3
01776                    && params[0] == G_TYPE_STRING
01777                    && params[1] == G_TYPE_STRING
01778                    && params[2] == G_TYPE_STRING)
01779             {
01780               ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
01781             }
01782         }
01783     }
01784 
01785   g_free (params);
01786   return ret;
01787 }
01788 
01800 void
01801 dbus_g_object_register_marshaller (GClosureMarshal  marshaller,
01802                                    GType            rettype,
01803                                    ...)
01804 {
01805   va_list args;
01806   GArray *types;
01807   GType gtype;
01808 
01809   va_start (args, rettype);
01810 
01811   types = g_array_new (TRUE, TRUE, sizeof (GType));
01812 
01813   while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
01814     g_array_append_val (types, gtype);
01815 
01816   dbus_g_object_register_marshaller_array (marshaller, rettype,
01817                                            types->len, (GType*) types->data);
01818 
01819   g_array_free (types, TRUE);
01820   va_end (args);
01821 }
01822 
01832 void
01833 dbus_g_object_register_marshaller_array (GClosureMarshal  marshaller,
01834                                          GType            rettype,
01835                                          guint            n_types,
01836                                          const GType*     types)
01837 {
01838   DBusGFuncSignature *sig;
01839   guint i;
01840 
01841   g_static_rw_lock_writer_lock (&globals_lock);
01842 
01843   if (marshal_table == NULL)
01844     marshal_table = g_hash_table_new_full (funcsig_hash,
01845                                            funcsig_equal,
01846                                            g_free,
01847                                            NULL);
01848   sig = g_new0 (DBusGFuncSignature, 1);
01849   sig->rettype = G_TYPE_FUNDAMENTAL (rettype);
01850   sig->n_params = n_types;
01851   sig->params = g_new (GType, n_types);
01852   for (i = 0; i < n_types; i++)
01853     sig->params[i] = G_TYPE_FUNDAMENTAL (types[i]);
01854 
01855   g_hash_table_insert (marshal_table, sig, marshaller);
01856 
01857   g_static_rw_lock_writer_unlock (&globals_lock);
01858 }
01859 
01866 void
01867 dbus_g_method_return (DBusGMethodInvocation *context, ...)
01868 {
01869   DBusMessage *reply;
01870   DBusMessageIter iter;
01871   va_list args;
01872   char *out_sig;
01873   GArray *argsig;
01874   guint i;
01875 
01876   reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
01877   out_sig = method_output_signature_from_object_info (context->object, context->method);
01878   argsig = _dbus_gtypes_from_arg_signature (out_sig, FALSE);
01879 
01880   dbus_message_iter_init_append (reply, &iter);
01881 
01882   va_start (args, context);
01883   for (i = 0; i < argsig->len; i++)
01884     {
01885       GValue value = {0,};
01886       char *error;
01887       g_value_init (&value, g_array_index (argsig, GType, i));
01888       error = NULL;
01889       G_VALUE_COLLECT (&value, args, G_VALUE_NOCOPY_CONTENTS, &error);
01890       if (error)
01891         {
01892           g_warning(error);
01893           g_free (error);
01894         }
01895       _dbus_gvalue_marshal (&iter, &value);
01896     }
01897   va_end (args);
01898 
01899   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
01900   dbus_message_unref (reply);
01901 
01902   dbus_g_connection_unref (context->connection);
01903   dbus_g_message_unref (context->message);
01904   g_free (context);
01905   g_free (out_sig);
01906 }
01907 
01915 void
01916 dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
01917 {
01918   DBusMessage *reply;
01919   reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
01920   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
01921   dbus_message_unref (reply);
01922   g_free (context);
01923 }
01924  /* end of public API */
01926 
01927 const char * _dbus_gobject_get_path (GObject *obj)
01928 {
01929   return g_object_get_data (obj, "dbus_glib_object_path");
01930 }
01931 
01932 #ifdef DBUS_BUILD_TESTS
01933 #include <stdlib.h>
01934 
01935 static void
01936 _dummy_function (void)
01937 {
01938 }
01939 
01940 /* Data structures copied from one generated by current dbus-binding-tool;
01941  * we need to support this layout forever
01942  */
01943 static const DBusGMethodInfo dbus_glib_internal_test_methods[] = {
01944   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 0 },
01945   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 49 },
01946   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 117 },
01947   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 191 },
01948   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 270 },
01949   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 320 },
01950   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 391 },
01951   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 495 },
01952   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 623 },
01953   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 693 },
01954   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 765 },
01955   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 838 },
01956   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 911 },
01957   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 988 },
01958   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1064 },
01959   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1140 },
01960   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1204 },
01961   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1278 },
01962   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1347 },
01963   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1408 },
01964   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1460 },
01965   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1533 },
01966   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1588 },
01967   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1647 },
01968   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1730 },
01969   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1784 },
01970   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1833 },
01971   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1895 },
01972   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1947 },
01973   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1999 },
01974 };
01975 
01976 const DBusGObjectInfo dbus_glib_internal_test_object_info = {
01977   0,
01978   dbus_glib_internal_test_methods,
01979   30,
01980 "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",
01981 "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",
01982 "\0"
01983 };
01984 
01985 
01991 gboolean
01992 _dbus_gobject_test (const char *test_data_dir)
01993 {
01994   int i;
01995   const char *arg;
01996   const char *arg_name;
01997   gboolean arg_in;
01998   gboolean constval;
01999   RetvalType retval;
02000   const char *arg_signature;
02001   const char *sigdata;
02002   const char *iface;
02003   const char *signame;
02004   
02005   static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
02006     { "SetFoo", "set_foo" },
02007     { "Foo", "foo" },
02008     { "GetFooBar", "get_foo_bar" },
02009     { "Hello", "hello" }
02010     
02011     /* Impossible-to-handle cases */
02012     /* { "FrobateUIHandler", "frobate_ui_handler" } */
02013   };
02014 
02015   /* Test lookup in our hardcoded object info; if these tests fail
02016    * then it likely means you changed the generated object info in an
02017    * incompatible way and broke the lookup functions.  In that case
02018    * you need to bump the version and use a new structure instead. */
02019   /* DoNothing */
02020   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02021                                           &(dbus_glib_internal_test_methods[0]));
02022   g_assert (*arg == '\0');
02023 
02024   /* Increment */
02025   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02026                                           &(dbus_glib_internal_test_methods[1]));
02027   g_assert (*arg != '\0');
02028   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02029   g_assert (!strcmp (arg_name, "x"));
02030   g_assert (arg_in == TRUE);
02031   g_assert (!strcmp (arg_signature, "u"));
02032   g_assert (*arg != '\0');
02033   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02034   g_assert (arg_in == FALSE);
02035   g_assert (retval == RETVAL_NONE);
02036   g_assert (!strcmp (arg_signature, "u"));
02037   g_assert (*arg == '\0');
02038 
02039   /* IncrementRetval */
02040   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02041                                           &(dbus_glib_internal_test_methods[2]));
02042   g_assert (*arg != '\0');
02043   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02044   g_assert (!strcmp (arg_name, "x"));
02045   g_assert (arg_in == TRUE);
02046   g_assert (!strcmp (arg_signature, "u"));
02047   g_assert (*arg != '\0');
02048   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02049   g_assert (retval == RETVAL_NOERROR);
02050   g_assert (arg_in == FALSE);
02051   g_assert (!strcmp (arg_signature, "u"));
02052   g_assert (*arg == '\0');
02053 
02054   /* IncrementRetvalError */
02055   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02056                                           &(dbus_glib_internal_test_methods[3]));
02057   g_assert (*arg != '\0');
02058   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02059   g_assert (!strcmp (arg_name, "x"));
02060   g_assert (arg_in == TRUE);
02061   g_assert (!strcmp (arg_signature, "u"));
02062   g_assert (*arg != '\0');
02063   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02064   g_assert (retval == RETVAL_ERROR);
02065   g_assert (arg_in == FALSE);
02066   g_assert (!strcmp (arg_signature, "u"));
02067   g_assert (*arg == '\0');
02068   
02069   /* Stringify */
02070   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02071                                           &(dbus_glib_internal_test_methods[8]));
02072   g_assert (*arg != '\0');
02073   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02074   g_assert (!strcmp (arg_name, "val"));
02075   g_assert (arg_in == TRUE);
02076   g_assert (!strcmp (arg_signature, "v"));
02077   g_assert (*arg != '\0');
02078   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02079   g_assert (retval == RETVAL_NONE);
02080   g_assert (arg_in == FALSE);
02081   g_assert (!strcmp (arg_signature, "s"));
02082   g_assert (*arg == '\0');
02083 
02084   sigdata = dbus_glib_internal_test_object_info.exported_signals;
02085   g_assert (*sigdata != '\0');
02086   sigdata = propsig_iterate (sigdata, &iface, &signame);
02087   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.MyObject"));
02088   g_assert (!strcmp (signame, "Frobnicate"));
02089   g_assert (*sigdata != '\0');
02090   sigdata = propsig_iterate (sigdata, &iface, &signame);
02091   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02092   g_assert (!strcmp (signame, "Sig0"));
02093   g_assert (*sigdata != '\0');
02094   sigdata = propsig_iterate (sigdata, &iface, &signame);
02095   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02096   g_assert (!strcmp (signame, "Sig1"));
02097   g_assert (*sigdata != '\0');
02098   sigdata = propsig_iterate (sigdata, &iface, &signame);
02099   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02100   g_assert (!strcmp (signame, "Sig2"));
02101   g_assert (*sigdata == '\0');
02102   
02103 
02104   i = 0;
02105   while (i < (int) G_N_ELEMENTS (name_pairs))
02106     {
02107       char *uscore;
02108       char *wincaps;
02109 
02110       uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
02111       wincaps = uscore_to_wincaps (name_pairs[i].uscore);
02112 
02113       if (strcmp (uscore, name_pairs[i].uscore) != 0)
02114         {
02115           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
02116                       name_pairs[i].wincaps, name_pairs[i].uscore,
02117                       uscore);
02118           exit (1);
02119         }
02120       
02121       if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
02122         {
02123           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
02124                       name_pairs[i].uscore, name_pairs[i].wincaps,
02125                       wincaps);
02126           exit (1);
02127         }
02128       
02129       g_free (uscore);
02130       g_free (wincaps);
02131 
02132       ++i;
02133     }
02134   
02135   return TRUE;
02136 }
02137 
02138 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Aug 30 16:35:50 2005 for D-BUS by  doxygen 1.4.3