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

Generated on Tue Sep 13 01:28:06 2005 for D-BUS by  doxygen 1.4.4