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

Generated on Mon Mar 17 16:28:48 2008 for D-BUSGLibBindings by  doxygen 1.5.1