Add const keywords
[platform/upstream/dbus.git] / glib / dbus-gobject.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gobject.c Exporting a GObject remotely
3  *
4  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
5  * Copyright (C) 2005 Nokia
6  *
7  * Licensed under the Academic Free License version 2.1
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include <config.h>
26 #include <gobject/gvaluecollector.h>
27 #include <dbus/dbus-glib.h>
28 #include <dbus/dbus-glib-lowlevel.h>
29 #include "dbus-gtest.h"
30 #include "dbus-gutils.h"
31 #include "dbus-gobject.h"
32 #include "dbus-gsignature.h"
33 #include "dbus-gvalue.h"
34 #include "dbus-gmarshal.h"
35 #include "dbus-gvalue-utils.h"
36 #include <string.h>
37
38 /**
39  * @addtogroup DBusGLibInternals
40  * @{
41  */
42
43 typedef struct
44 {
45   char *default_iface;
46   GType code_enum;
47 } DBusGErrorInfo;
48
49 static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
50 static GHashTable *marshal_table = NULL;
51 static GData *error_metadata = NULL;
52
53 static char*
54 uscore_to_wincaps (const char *uscore)
55 {
56   const char *p;
57   GString *str;
58   gboolean last_was_uscore;
59
60   last_was_uscore = TRUE;
61   
62   str = g_string_new (NULL);
63   p = uscore;
64   while (*p)
65     {
66       if (*p == '-' || *p == '_')
67         {
68           last_was_uscore = TRUE;
69         }
70       else
71         {
72           if (last_was_uscore)
73             {
74               g_string_append_c (str, g_ascii_toupper (*p));
75               last_was_uscore = FALSE;
76             }
77           else
78             g_string_append_c (str, *p);
79         }
80       ++p;
81     }
82
83   return g_string_free (str, FALSE);
84 }
85
86 static const char *
87 string_table_next (const char *table)
88 {
89   return (table + (strlen (table) + 1));
90 }
91
92 static const char *
93 string_table_lookup (const char *table, int index)
94 {
95   const char *ret;
96
97   ret = table;
98
99   while (index--)
100     ret = string_table_next (ret);
101
102   return ret;
103 }
104
105 static const char *
106 get_method_data (const DBusGObjectInfo *object,
107                  const DBusGMethodInfo *method)
108 {
109   return object->data + method->data_offset;
110 }
111
112 static char *
113 object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
114 {
115   /* FIXME */
116   return NULL;
117 }
118
119 static char *
120 object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
121 {
122   /* FIXME */
123   return NULL;
124 }
125
126 static const char *
127 method_interface_from_object_info (const DBusGObjectInfo *object,
128                               const DBusGMethodInfo *method)
129 {
130   return string_table_lookup (get_method_data (object, method), 0);
131 }
132
133 static const char *
134 method_name_from_object_info (const DBusGObjectInfo *object,
135                               const DBusGMethodInfo *method)
136 {
137   return string_table_lookup (get_method_data (object, method), 1);
138 }
139
140 static const char *
141 method_arg_info_from_object_info (const DBusGObjectInfo *object,
142                                   const DBusGMethodInfo *method)
143 {
144   return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
145 }
146
147 typedef enum
148 {
149   RETVAL_NONE,    
150   RETVAL_NOERROR,    
151   RETVAL_ERROR
152 } RetvalType;
153
154 static const char *
155 arg_iterate (const char    *data,
156              const char   **name,
157              gboolean      *in,
158              gboolean      *constval,
159              RetvalType    *retval,
160              const char   **type)
161 {
162   gboolean inarg;
163
164   if (name)
165     *name = data;
166
167   data = string_table_next (data);
168   switch (*data)
169     {
170     case 'I':
171       inarg = TRUE;
172       break;
173     case 'O':
174       inarg = FALSE;
175       break;
176     default:
177       g_warning ("invalid arg direction '%c'", *data);
178       inarg = FALSE;
179       break;
180     }
181   if (in)
182     *in = inarg;
183
184   if (!inarg)
185     {
186       data = string_table_next (data);
187       switch (*data)
188         {
189         case 'F':
190           if (constval)
191             *constval = FALSE;
192           break;
193         case 'C':
194           if (constval)
195             *constval = TRUE;
196           break;
197         default:
198           g_warning ("invalid arg const value '%c'", *data);
199           break;
200         }
201       data = string_table_next (data);
202       switch (*data)
203         {
204         case 'N':
205           if (retval)
206             *retval = RETVAL_NONE;
207           break;
208         case 'E':
209           if (retval)
210             *retval = RETVAL_ERROR;
211           break;
212         case 'R':
213           if (retval)
214             *retval = RETVAL_NOERROR;
215           break;
216         default:
217           g_warning ("invalid arg ret value '%c'", *data);
218           break;
219         }
220     }
221   else
222     {
223       if (constval)
224         *constval = FALSE;
225       if (retval)
226         *retval = FALSE;
227     }
228   
229   data = string_table_next (data);
230   if (type)
231     *type = data;
232
233   return string_table_next (data);
234 }
235
236 static char *
237 method_dir_signature_from_object_info (const DBusGObjectInfo *object,
238                                        const DBusGMethodInfo *method,
239                                        gboolean               in)
240 {
241   const char *arg;
242   GString *ret;
243
244   arg = method_arg_info_from_object_info (object, method);
245
246   ret = g_string_new (NULL);
247
248   while (*arg)
249     {
250       const char *name;
251       gboolean arg_in;
252       const char *type;
253
254       arg = arg_iterate (arg, &name, &arg_in, NULL, NULL, &type);
255
256       if (arg_in == in)
257         g_string_append (ret, type);
258     }
259
260   return g_string_free (ret, FALSE);
261 }
262
263 static char *
264 method_input_signature_from_object_info (const DBusGObjectInfo *object,
265                                          const DBusGMethodInfo *method)
266 {
267   return method_dir_signature_from_object_info (object, method, TRUE);
268 }
269
270 static char *
271 method_output_signature_from_object_info (const DBusGObjectInfo *object,
272                                           const DBusGMethodInfo *method)
273 {
274   return method_dir_signature_from_object_info (object, method, FALSE);
275 }
276
277 static const char *
278 propsig_iterate (const char *data, const char **iface, const char **name)
279 {
280   *iface = data;
281
282   data = string_table_next (data);
283   *name = data;
284
285   return string_table_next (data);
286 }
287
288 static GQuark
289 dbus_g_object_type_dbus_metadata_quark (void)
290 {
291   static GQuark quark;
292
293   if (!quark)
294     quark = g_quark_from_static_string ("DBusGObjectTypeDBusMetadataQuark");
295   return quark;
296 }
297
298 static const DBusGObjectInfo *
299 lookup_object_info (GObject *object)
300 {
301   const DBusGObjectInfo *ret;
302   GType classtype;
303   
304   ret = NULL;
305   
306   for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
307     {
308       const DBusGObjectInfo *info;
309
310       info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ()); 
311
312       if (info != NULL && info->format_version >= 0)
313         {
314           ret = info;
315           break;
316         }
317     }
318
319   return ret;
320 }
321
322 static void
323 gobject_unregister_function (DBusConnection  *connection,
324                              void            *user_data)
325 {
326   GObject *object;
327
328   object = G_OBJECT (user_data);
329
330   /* FIXME */
331
332 }
333
334 typedef struct
335 {
336   GString *xml;
337   GType gtype;
338   const DBusGObjectInfo *object_info;
339 } DBusGLibWriteIterfaceData;
340
341 typedef struct
342 {
343   GSList *methods;
344   GSList *signals;
345   GSList *properties;
346 } DBusGLibWriteInterfaceValues;
347
348 static void
349 write_interface (gpointer key, gpointer val, gpointer user_data)
350 {
351   const char *name;
352   GSList *methods;
353   GSList *signals;
354   GSList *properties;
355   GString *xml;
356   const DBusGObjectInfo *object_info;
357   DBusGLibWriteIterfaceData *data;
358   DBusGLibWriteInterfaceValues *values;
359
360   name = key;
361
362   values = val;
363   methods = values->methods;
364   signals = values->signals;
365   properties = values->properties;
366
367   data = user_data;
368   xml = data->xml;
369   object_info = data->object_info;
370
371   g_string_append_printf (xml, "  <interface name=\"%s\">\n", name);
372
373   /* FIXME: recurse to parent types ? */
374   for (; methods; methods = methods->next)
375     {
376       DBusGMethodInfo *method;
377       const char *args;
378       method = methods->data;
379
380       g_string_append_printf (xml, "    <method name=\"%s\">\n",
381                               method_name_from_object_info (object_info, method));
382
383       args = method_arg_info_from_object_info (object_info, method);
384
385       while (*args)
386         {
387           const char *name;
388           gboolean arg_in;
389           const char *type;
390           
391           args = arg_iterate (args, &name, &arg_in, NULL, NULL, &type);
392
393           /* FIXME - handle container types */
394           g_string_append_printf (xml, "      <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
395                                   name, type, arg_in ? "in" : "out");
396
397         }
398       g_string_append (xml, "    </method>\n");
399
400     }
401   g_slist_free (values->methods);
402
403   for (; signals; signals = signals->next)
404     {
405       guint id;
406       guint arg;
407       const char *signame;
408       GSignalQuery query;
409       char *s;
410
411       signame = signals->data;
412
413       s = _dbus_gutils_wincaps_to_uscore (signame);
414       
415       id = g_signal_lookup (s, data->gtype);
416       g_assert (id != 0);
417
418       g_signal_query (id, &query);
419       g_assert (query.return_type == G_TYPE_NONE);
420
421       g_string_append_printf (xml, "    <signal name=\"%s\">\n", signame);
422
423       for (arg = 0; arg < query.n_params; arg++)
424         {
425           char *dbus_type = _dbus_gtype_to_signature (query.param_types[arg]);
426
427           g_assert (dbus_type != NULL);
428
429           g_string_append (xml, "      <arg type=\"");
430           g_string_append (xml, dbus_type);
431           g_string_append (xml, "\"/>\n");
432           g_free (dbus_type);
433         }
434
435       g_string_append (xml, "    </signal>\n");
436       g_free (s);
437     }
438   g_slist_free (values->signals);
439
440   for (; properties; properties = properties->next)
441     {
442       const char *propname;
443       GParamSpec *spec;
444       char *dbus_type;
445       gboolean can_set;
446       gboolean can_get;
447       char *s;
448
449       propname = properties->data;
450
451       s = _dbus_gutils_wincaps_to_uscore (spec->name);
452
453       spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
454       g_assert (spec != NULL);
455       g_free (s);
456       
457       dbus_type = _dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
458       g_assert (dbus_type != NULL);
459       
460       can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
461                  (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
462       
463       can_get = (spec->flags & G_PARAM_READABLE) != 0;
464       
465       if (can_set || can_get)
466         {
467           g_string_append_printf (xml, "    <property name=\"%s\" ", propname);
468           g_string_append (xml, "type=\"");
469           g_string_append (xml, dbus_type);
470           g_string_append (xml, "\" access=\"");
471
472           if (can_set && can_get)
473             g_string_append (xml, "readwrite");
474           else if (can_get)
475             g_string_append (xml, "read");
476           else
477             {
478               g_assert (can_set);
479               g_string_append (xml, "write");
480             }
481           
482           g_string_append (xml, "\"/>\n");
483         }
484       
485       g_free (dbus_type);
486       g_free (s);
487
488       g_string_append (xml, "    </property>\n");
489     }
490   g_slist_free (values->properties);
491
492   g_free (values);
493   g_string_append (xml, "  </interface>\n");
494 }
495
496 static DBusGLibWriteInterfaceValues *
497 lookup_values (GHashTable *interfaces, const char *method_interface)
498 {
499   DBusGLibWriteInterfaceValues *values;
500   if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
501     {
502       values = g_new0 (DBusGLibWriteInterfaceValues, 1);
503       g_hash_table_insert (interfaces, (gpointer) method_interface, values);
504     }
505   return values;
506 }
507
508 static void
509 introspect_interfaces (GObject *object, GString *xml)
510 {
511   const DBusGObjectInfo *info;
512   DBusGLibWriteIterfaceData data;
513   int i;
514   GHashTable *interfaces;
515   DBusGLibWriteInterfaceValues *values;
516   const char *propsig;
517
518   info = lookup_object_info (object);
519
520   g_assert (info != NULL);
521
522   /* Gather a list of all interfaces, indexed into their methods */
523   interfaces = g_hash_table_new (g_str_hash, g_str_equal);
524   for (i = 0; i < info->n_method_infos; i++)
525     {
526       const char *method_name;
527       const char *method_interface;
528       const char *method_args;
529       const DBusGMethodInfo *method;
530
531       method = &(info->method_infos[i]);
532
533       method_interface = method_interface_from_object_info (info, method);
534       method_name = method_name_from_object_info (info, method);
535       method_args = method_arg_info_from_object_info (info, method);
536
537       values = lookup_values (interfaces, method_interface);
538       values->methods = g_slist_prepend (values->methods, (gpointer) method);
539     }
540
541   propsig = info->exported_signals;
542   while (*propsig)
543     {
544       const char *iface;
545       const char *signame;
546
547       propsig = propsig_iterate (propsig, &iface, &signame);
548
549       values = lookup_values (interfaces, iface);
550       values->signals = g_slist_prepend (values->signals, (gpointer) signame);
551     }
552
553   propsig = info->exported_properties;
554   while (*propsig)
555     {
556       const char *iface;
557       const char *propname;
558
559       propsig = propsig_iterate (propsig, &iface, &propname);
560
561       values = lookup_values (interfaces, iface);
562       values->properties = g_slist_prepend (values->properties, (gpointer) propname);
563     }
564   
565   memset (&data, 0, sizeof (data));
566   data.xml = xml;
567   data.gtype = G_TYPE_FROM_INSTANCE (object);
568   data.object_info = info;
569   g_hash_table_foreach (interfaces, write_interface, &data);
570   
571   g_hash_table_destroy (interfaces);
572 }
573
574 static DBusHandlerResult
575 handle_introspect (DBusConnection *connection,
576                    DBusMessage    *message,
577                    GObject        *object)
578 {
579   GString *xml;
580   unsigned int i;
581   DBusMessage *ret;
582   char **children;
583   
584   if (!dbus_connection_list_registered (connection, 
585                                         dbus_message_get_path (message),
586                                         &children))
587     g_error ("Out of memory");
588   
589   xml = g_string_new (NULL);
590
591   g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
592   
593   g_string_append (xml, "<node>\n");
594
595   /* We are introspectable, though I guess that was pretty obvious */
596   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE);
597   g_string_append (xml, "    <method name=\"Introspect\">\n");
598   g_string_append_printf (xml, "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
599   g_string_append (xml, "    </method>\n");
600   g_string_append (xml, "  </interface>\n");
601
602   /* We support get/set properties */
603   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_PROPERTIES);
604   g_string_append (xml, "    <method name=\"Get\">\n");
605   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
606   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
607   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
608   g_string_append (xml, "    </method>\n");
609   g_string_append (xml, "    <method name=\"Set\">\n");
610   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
611   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
612   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
613   g_string_append (xml, "    </method>\n");
614   g_string_append (xml, "  </interface>\n");
615   
616   introspect_interfaces (object, xml);
617
618   /* Append child nodes */
619   for (i = 0; children[i]; i++)
620       g_string_append_printf (xml, "  <node name=\"%s\"/>\n",
621                               children[i]);
622   
623   /* Close the XML, and send it to the requesting app */
624   g_string_append (xml, "</node>\n");
625
626   ret = dbus_message_new_method_return (message);
627   if (ret == NULL)
628     g_error ("Out of memory");
629
630   dbus_message_append_args (ret,
631                             DBUS_TYPE_STRING, &xml->str,
632                             DBUS_TYPE_INVALID);
633
634   dbus_connection_send (connection, ret, NULL);
635   dbus_message_unref (ret);
636
637   g_string_free (xml, TRUE);
638
639   dbus_free_string_array (children);
640   
641   return DBUS_HANDLER_RESULT_HANDLED;
642 }
643
644 static DBusMessage*
645 set_object_property (DBusConnection  *connection,
646                      DBusMessage     *message,
647                      DBusMessageIter *iter,
648                      GObject         *object,
649                      GParamSpec      *pspec)
650 {
651   GValue value = { 0, };
652   DBusMessage *ret;
653   DBusMessageIter sub;
654   DBusGValueMarshalCtx context;
655
656   dbus_message_iter_recurse (iter, &sub);
657
658   context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
659   context.proxy = NULL;
660
661   g_value_init (&value, pspec->value_type);
662   if (_dbus_gvalue_demarshal (&context, &sub, &value, NULL))
663     {
664       g_object_set_property (object,
665                              pspec->name,
666                              &value);
667
668       g_value_unset (&value);
669
670       ret = dbus_message_new_method_return (message);
671       if (ret == NULL)
672         g_error ("out of memory");
673     }
674   else
675     {
676       ret = dbus_message_new_error (message,
677                                     DBUS_ERROR_INVALID_ARGS,
678                                     "Argument's D-BUS type can't be converted to a GType");
679       if (ret == NULL)
680         g_error ("out of memory");
681     }
682
683   return ret;
684 }
685
686 static DBusMessage*
687 get_object_property (DBusConnection *connection,
688                      DBusMessage    *message,
689                      GObject        *object,
690                      GParamSpec     *pspec)
691 {
692   GType value_type;
693   GValue value = {0, };
694   DBusMessage *ret;
695   DBusMessageIter iter;
696
697   value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
698
699   ret = dbus_message_new_method_return (message);
700   if (ret == NULL)
701     g_error ("out of memory");
702
703   g_value_init (&value, value_type);
704   g_object_get_property (object, pspec->name, &value);
705
706   value_type = G_VALUE_TYPE (&value);
707
708   dbus_message_iter_init_append (message, &iter);
709
710   if (!_dbus_gvalue_marshal (&iter, &value))
711     {
712       dbus_message_unref (ret);
713       ret = dbus_message_new_error (message,
714                                     DBUS_ERROR_UNKNOWN_METHOD,
715                                     "Can't convert GType of object property to a D-BUS type");
716     }
717
718   return ret;
719 }
720
721 static gboolean
722 lookup_object_and_method (GObject      *object,
723                           DBusMessage  *message,
724                           const DBusGObjectInfo **object_ret,
725                           const DBusGMethodInfo **method_ret)
726 {
727   const char *interface;
728   const char *member;
729   const char *signature;
730   gboolean ret;
731   const DBusGObjectInfo *info;
732   int i;
733
734   interface = dbus_message_get_interface (message);
735   member = dbus_message_get_member (message);
736   signature = dbus_message_get_signature (message);
737   ret = FALSE;
738
739   info = lookup_object_info (object);
740   *object_ret = info;
741   
742   for (i = 0; i < info->n_method_infos; i++)
743     {
744       const char *expected_member;
745       const char *expected_interface;
746       char *expected_signature;
747       const DBusGMethodInfo *method;
748
749       method = &(info->method_infos[i]);
750
751       /* Check method interface/name and input signature */ 
752       expected_interface = method_interface_from_object_info (*object_ret, method);
753       expected_member = method_name_from_object_info (*object_ret, method);
754       expected_signature = method_input_signature_from_object_info (*object_ret, method);
755
756       if ((interface == NULL
757            || strcmp (expected_interface, interface) == 0)
758           && strcmp (expected_member, member) == 0
759           && strcmp (expected_signature, signature) == 0)
760         {
761           g_free (expected_signature);
762           *method_ret = method;
763           return TRUE;
764         }
765       g_free (expected_signature);
766     }
767
768   return ret;
769 }
770
771 static char *
772 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
773                                       const char *msg_interface,
774                                       GQuark domain, gint code)
775 {
776   const char *domain_str;
777   const char *code_str;
778   GString *dbus_error_name;
779
780   domain_str = object_error_domain_prefix_from_object_info (object_info);
781   code_str = object_error_code_from_object_info (object_info, domain, code);
782
783   if (!domain_str || !code_str)
784     {
785       DBusGErrorInfo *info;
786
787       g_static_rw_lock_reader_lock (&globals_lock);
788
789       if (error_metadata != NULL)
790         info = g_datalist_id_get_data (&error_metadata, domain);
791       else
792         info = NULL;
793
794       g_static_rw_lock_reader_unlock (&globals_lock);
795
796       if (info)
797         {
798           GEnumValue *value;
799           GEnumClass *klass;
800
801           klass = g_type_class_ref (info->code_enum);
802           value = g_enum_get_value (klass, code);
803           g_type_class_unref (klass);
804
805           domain_str = info->default_iface;
806           code_str = value->value_nick;
807         }
808     }
809
810   if (!domain_str)
811     domain_str = msg_interface;
812
813   if (!domain_str || !code_str)
814     {
815       /* If we can't map it sensibly, make up an error name */
816       char *domain_from_quark;
817       
818       dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
819
820       domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
821       g_string_append (dbus_error_name, domain_from_quark);
822       g_free (domain_from_quark);
823         
824       g_string_append_printf (dbus_error_name, ".Code%d", code);
825     }
826   else
827     {
828       dbus_error_name = g_string_new (domain_str);
829       g_string_append_c (dbus_error_name, '.');
830       g_string_append (dbus_error_name, code_str);
831     }
832
833   return g_string_free (dbus_error_name, FALSE);
834 }
835
836 static DBusMessage *
837 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
838                               DBusMessage     *message,
839                               GError          *error)
840 {
841   DBusMessage *reply;
842
843   if (!error)
844     {
845       char *error_msg;
846       
847       error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
848       reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
849       g_free (error_msg);
850     }
851   else
852     {
853       if (error->domain == DBUS_GERROR)
854         reply = dbus_message_new_error (message,
855                                         dbus_g_error_get_name (error),
856                                         error->message);
857       else
858         {
859           char *error_name;
860           error_name = gerror_domaincode_to_dbus_error_name (object_info,
861                                                              dbus_message_get_interface (message),
862                                                              error->domain, error->code);
863           reply = dbus_message_new_error (message, error_name, error->message);
864           g_free (error_name); 
865         }
866     }
867   return reply;
868 }
869
870 /**
871  * The context of an asynchronous method call.  See dbus_g_method_return() and
872  * dbus_g_method_return_error().
873  */
874 struct _DBusGMethodInvocation {
875   DBusGConnection *connection; /**< The connection */
876   DBusGMessage *message; /**< The message which generated the method call */
877   const DBusGObjectInfo *object; /**< The object the method was called on */
878   const DBusGMethodInfo *method; /**< The method called */
879 };
880
881 static DBusHandlerResult
882 invoke_object_method (GObject         *object,
883                       const DBusGObjectInfo *object_info,
884                       const DBusGMethodInfo *method,
885                       DBusConnection  *connection,
886                       DBusMessage     *message)
887 {
888   gboolean had_error, call_only;
889   GError *gerror;
890   GValueArray *value_array;
891   GValue return_value = {0,};
892   GClosure closure;
893   char *in_signature;
894   GArray *out_param_values = NULL;
895   GValueArray *out_param_gvalues = NULL;
896   int out_param_count;
897   int out_param_pos, out_param_gvalue_pos;
898   DBusHandlerResult result;
899   DBusMessage *reply;
900   gboolean have_retval;
901   gboolean retval_signals_error;
902   gboolean retval_is_synthetic;
903   gboolean retval_is_constant;
904   const char *arg_metadata;
905
906   gerror = NULL;
907
908   /* Determine whether or not this method should be invoked in a new
909      thread
910    */
911   if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
912     call_only = TRUE;
913   else
914     call_only = FALSE;
915
916   have_retval = FALSE;
917   retval_signals_error = FALSE;
918   retval_is_synthetic = FALSE;
919   retval_is_constant = FALSE;
920
921   /* This is evil.  We do this to work around the fact that
922    * the generated glib marshallers check a flag in the closure object
923    * which we don't care about.  We don't need/want to create
924    * a new closure for each invocation.
925    */
926   memset (&closure, 0, sizeof (closure));
927
928   in_signature = method_input_signature_from_object_info (object_info, method); 
929   
930   /* Convert method IN parameters to GValueArray */
931   {
932     GArray *types_array;
933     guint n_params;
934     const GType *types;
935     DBusGValueMarshalCtx context;
936     GError *error = NULL;
937     
938     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
939     context.proxy = NULL;
940
941     types_array = _dbus_gtypes_from_arg_signature (in_signature, FALSE);
942     n_params = types_array->len;
943     types = (const GType*) types_array->data;
944
945     value_array = _dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
946     if (value_array == NULL)
947       {
948         g_free (in_signature); 
949         g_array_free (types_array, TRUE);
950         reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
951         dbus_connection_send (connection, reply, NULL);
952         dbus_message_unref (reply);
953         g_error_free (error);
954         return DBUS_HANDLER_RESULT_HANDLED;
955       }
956     g_array_free (types_array, TRUE);
957   }
958
959   /* Prepend object as first argument */ 
960   g_value_array_prepend (value_array, NULL);
961   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT);
962   g_value_set_object (g_value_array_get_nth (value_array, 0), object);
963   
964   if (call_only)
965     {
966       GValue context_value = {0,};
967       DBusGMethodInvocation *context;
968       context = g_new (DBusGMethodInvocation, 1);
969       context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
970       context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
971       context->object = object_info;
972       context->method = method;
973       g_value_init (&context_value, G_TYPE_POINTER);
974       g_value_set_pointer (&context_value, context);
975       g_value_array_append (value_array, &context_value);
976     }
977   else
978     {
979       RetvalType retval;
980       gboolean arg_in;
981       gboolean arg_const;
982       const char *argsig;
983
984       arg_metadata = method_arg_info_from_object_info (object_info, method);
985       
986       /* Count number of output parameters, and look for a return value */
987       out_param_count = 0;
988       while (*arg_metadata)
989         {
990           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
991           if (arg_in)
992             continue;
993           if (retval != RETVAL_NONE)
994             {
995               DBusSignatureIter tmp_sigiter;
996               /* This is the function return value */
997               g_assert (!have_retval);
998               have_retval = TRUE;
999               retval_is_synthetic = FALSE;
1000
1001               switch (retval)
1002                 {
1003                 case RETVAL_NONE:
1004                   g_assert_not_reached ();
1005                   break;
1006                 case RETVAL_NOERROR:
1007                   retval_signals_error = FALSE;
1008                   break;
1009                 case RETVAL_ERROR:
1010                   retval_signals_error = TRUE;
1011                   break;
1012                 }
1013
1014               retval_is_constant = arg_const;
1015
1016               /* Initialize our return GValue with the specified type */
1017               dbus_signature_iter_init (&tmp_sigiter, argsig);
1018               g_value_init (&return_value, _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
1019             }
1020           else
1021             {
1022               /* It's a regular output value */
1023               out_param_count++;
1024             }
1025         }
1026
1027       /* For compatibility, if we haven't found a return value, we assume
1028        * the function returns a gboolean for signalling an error
1029        * (and therefore also takes a GError).  We also note that it
1030        * is a "synthetic" return value; i.e. we aren't going to be
1031        * sending it over the bus, it's just to signal an error.
1032        */
1033       if (!have_retval)
1034         {
1035           have_retval = TRUE;
1036           retval_is_synthetic = TRUE;
1037           retval_signals_error = TRUE;
1038           g_value_init (&return_value, G_TYPE_BOOLEAN);
1039         }
1040
1041       /* Create an array to store the actual values of OUT parameters
1042        * (other than the real function return, if any).  Then, create
1043        * a GValue boxed POINTER to each of those values, and append to
1044        * the invocation, so the method can return the OUT parameters.
1045        */
1046       out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
1047
1048       /* We have a special array of GValues for toplevel GValue return
1049        * types.
1050        */
1051       out_param_gvalues = g_value_array_new (out_param_count);
1052       out_param_pos = 0;
1053       out_param_gvalue_pos = 0;
1054
1055       /* Reset argument metadata pointer */
1056       arg_metadata = method_arg_info_from_object_info (object_info, method);
1057       
1058       /* Iterate over output arguments again, this time allocating space for
1059        * them as appopriate.
1060        */
1061       while (*arg_metadata)
1062         {
1063           GValue value = {0, };
1064           GTypeCValue storage;
1065           DBusSignatureIter tmp_sigiter;
1066           GType current_gtype;
1067
1068           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
1069           /* Skip over input arguments and the return value, if any */
1070           if (arg_in || retval != RETVAL_NONE)
1071             continue;
1072
1073           dbus_signature_iter_init (&tmp_sigiter, argsig);
1074           current_gtype = _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
1075
1076           g_value_init (&value, G_TYPE_POINTER);
1077
1078           /* We special case variants to make method invocation a bit nicer */
1079           if (current_gtype != G_TYPE_VALUE)
1080             {
1081               memset (&storage, 0, sizeof (storage));
1082               g_array_append_val (out_param_values, storage);
1083               g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
1084               out_param_pos++;
1085             }
1086           else
1087             {
1088               g_value_array_append (out_param_gvalues, NULL);
1089               g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
1090               out_param_gvalue_pos++;
1091             }
1092           g_value_array_append (value_array, &value);
1093         }
1094     }
1095
1096   /* Append GError as final argument if necessary */
1097   if (retval_signals_error)
1098     {
1099       g_assert (have_retval);
1100       g_value_array_append (value_array, NULL);
1101       g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
1102       g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
1103     }
1104   
1105   /* Actually invoke method */
1106   method->marshaller (&closure, have_retval ? &return_value : NULL,
1107                       value_array->n_values,
1108                       value_array->values,
1109                       NULL, method->function);
1110   if (call_only)
1111     {
1112       result = DBUS_HANDLER_RESULT_HANDLED;
1113       goto done;
1114     }
1115   if (retval_signals_error)
1116     had_error = _dbus_gvalue_signals_error (&return_value);
1117   else
1118     had_error = FALSE;
1119
1120   if (!had_error)
1121     {
1122       DBusMessageIter iter;
1123
1124       reply = dbus_message_new_method_return (message);
1125       if (reply == NULL)
1126         goto nomem;
1127
1128       /* Append output arguments to reply */
1129       dbus_message_iter_init_append (reply, &iter);
1130
1131       /* First, append the return value, unless it's synthetic */
1132       if (have_retval && !retval_is_synthetic)
1133         {
1134           if (!_dbus_gvalue_marshal (&iter, &return_value))
1135             goto nomem;
1136           if (!retval_is_constant)
1137             g_value_unset (&return_value);
1138         }
1139
1140       /* Grab the argument metadata and iterate over it */
1141       arg_metadata = method_arg_info_from_object_info (object_info, method);
1142       
1143       /* Now append any remaining return values */
1144       out_param_pos = 0;
1145       out_param_gvalue_pos = 0;
1146       while (*arg_metadata)
1147         {
1148           GValue gvalue = {0, };
1149           const char *arg_name;
1150           gboolean arg_in;
1151           gboolean constval;
1152           RetvalType retval;
1153           const char *arg_signature;
1154           DBusSignatureIter argsigiter;
1155
1156           do
1157             {
1158               /* Iterate over only output values; skip over input
1159                  arguments and the return value */
1160               arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
1161             }
1162           while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
1163
1164           /* If the last argument we saw was input or the return
1165            * value, we must be done iterating over output arguments.
1166            */
1167           if (arg_in || retval != RETVAL_NONE)
1168             break;
1169
1170           dbus_signature_iter_init (&argsigiter, arg_signature);
1171           
1172           g_value_init (&gvalue, _dbus_gtype_from_signature_iter (&argsigiter, FALSE));
1173           if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
1174             {
1175               if (!_dbus_gvalue_take (&gvalue,
1176                                      &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
1177                 g_assert_not_reached ();
1178               out_param_pos++;
1179             }
1180           else
1181             {
1182               g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
1183               out_param_gvalue_pos++;
1184             }
1185               
1186           if (!_dbus_gvalue_marshal (&iter, &gvalue))
1187             goto nomem;
1188           /* Here we actually free the allocated value; we
1189            * took ownership of it with _dbus_gvalue_take, unless
1190            * an annotation has specified this value as constant.
1191            */
1192           if (!constval)
1193             g_value_unset (&gvalue);
1194         }
1195     }
1196   else
1197     reply = gerror_to_dbus_error_message (object_info, message, gerror);
1198
1199   if (reply)
1200     {
1201       dbus_connection_send (connection, reply, NULL);
1202       dbus_message_unref (reply);
1203     }
1204
1205   result = DBUS_HANDLER_RESULT_HANDLED;
1206  done:
1207   g_free (in_signature);
1208   if (!call_only)
1209     {
1210       g_array_free (out_param_values, TRUE);
1211       g_value_array_free (out_param_gvalues);
1212     }
1213   g_value_array_free (value_array);
1214   return result;
1215  nomem:
1216   result = DBUS_HANDLER_RESULT_NEED_MEMORY;
1217   goto done;
1218 }
1219
1220 static DBusHandlerResult
1221 gobject_message_function (DBusConnection  *connection,
1222                           DBusMessage     *message,
1223                           void            *user_data)
1224 {
1225   GParamSpec *pspec;
1226   GObject *object;
1227   gboolean setter;
1228   gboolean getter;
1229   char *s;
1230   const char *wincaps_propname;
1231   /* const char *wincaps_propiface; */
1232   DBusMessageIter iter;
1233   const DBusGMethodInfo *method;
1234   const DBusGObjectInfo *object_info;
1235
1236   object = G_OBJECT (user_data);
1237
1238   if (dbus_message_is_method_call (message,
1239                                    DBUS_INTERFACE_INTROSPECTABLE,
1240                                    "Introspect"))
1241     return handle_introspect (connection, message, object);
1242   
1243   /* Try the metainfo, which lets us invoke methods */
1244   if (lookup_object_and_method (object, message, &object_info, &method))
1245     return invoke_object_method (object, object_info, method, connection, message);
1246
1247   /* If no metainfo, we can still do properties and signals
1248    * via standard GLib introspection
1249    */
1250   getter = FALSE;
1251   setter = FALSE;
1252   if (dbus_message_is_method_call (message,
1253                                    DBUS_INTERFACE_PROPERTIES,
1254                                    "Get"))
1255     getter = TRUE;
1256   else if (dbus_message_is_method_call (message,
1257                                         DBUS_INTERFACE_PROPERTIES,
1258                                         "Set"))
1259     setter = TRUE;
1260
1261   if (!(setter || getter))
1262     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1263
1264   dbus_message_iter_init (message, &iter);
1265
1266   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
1267     {
1268       g_warning ("Property get or set does not have an interface string as first arg\n");
1269       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1270     }
1271   /* We never use the interface name; if we did, we'd need to
1272    * remember that it can be empty string for "pick one for me"
1273    */
1274   /* dbus_message_iter_get_basic (&iter, &wincaps_propiface); */
1275   dbus_message_iter_next (&iter);
1276
1277   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
1278     {
1279       g_warning ("Property get or set does not have a property name string as second arg\n");
1280       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1281     }
1282   dbus_message_iter_get_basic (&iter, &wincaps_propname);
1283   dbus_message_iter_next (&iter);
1284   
1285   s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
1286
1287   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
1288                                         s);
1289
1290   g_free (s);
1291
1292   if (pspec != NULL)
1293     {
1294       DBusMessage *ret;
1295
1296       if (setter)
1297         {
1298           if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
1299             {
1300               g_warning ("Property set does not have a variant value as third arg\n");
1301               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1302             }
1303           
1304           ret = set_object_property (connection, message, &iter,
1305                                      object, pspec);
1306           dbus_message_iter_next (&iter);
1307         }
1308       else if (getter)
1309         {     
1310           ret = get_object_property (connection, message,
1311                                      object, pspec);
1312         }
1313       else
1314         {
1315           g_assert_not_reached ();
1316           ret = NULL;
1317         }
1318
1319       g_assert (ret != NULL);
1320
1321       if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
1322         g_warning ("Property get or set had too many arguments\n");
1323       
1324       dbus_connection_send (connection, ret, NULL);
1325       dbus_message_unref (ret);
1326       return DBUS_HANDLER_RESULT_HANDLED;
1327     }
1328
1329   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1330 }
1331
1332 static const DBusObjectPathVTable gobject_dbus_vtable = {
1333   gobject_unregister_function,
1334   gobject_message_function,
1335   NULL
1336 };
1337
1338 typedef struct {
1339   GClosure         closure;
1340   DBusGConnection *connection;
1341   GObject         *object;
1342   const char      *signame;
1343   const char      *sigiface;
1344 } DBusGSignalClosure;
1345
1346 static GClosure *
1347 dbus_g_signal_closure_new (DBusGConnection *connection,
1348                            GObject         *object,
1349                            const char      *signame,
1350                            const char      *sigiface)
1351 {
1352   DBusGSignalClosure *closure;
1353   
1354   closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
1355
1356   closure->connection = dbus_g_connection_ref (connection);
1357   closure->object = object;
1358   closure->signame = signame;
1359   closure->sigiface = sigiface;
1360   return (GClosure*) closure;
1361 }
1362
1363 static void
1364 dbus_g_signal_closure_finalize (gpointer data,
1365                                 GClosure *closure)
1366 {
1367   DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
1368
1369   dbus_g_connection_unref (sigclosure->connection);
1370 }
1371
1372 static void
1373 signal_emitter_marshaller (GClosure        *closure,
1374                            GValue          *retval,
1375                            guint            n_param_values,
1376                            const GValue    *param_values,
1377                            gpointer         invocation_hint,
1378                            gpointer         marshal_data)
1379 {
1380   DBusGSignalClosure *sigclosure;
1381   DBusMessage *signal;
1382   DBusMessageIter iter;
1383   guint i;
1384   const char *path;
1385
1386   sigclosure = (DBusGSignalClosure *) closure;
1387   
1388   g_assert (retval == NULL);
1389
1390   path = _dbus_gobject_get_path (sigclosure->object);
1391
1392   g_assert (path != NULL);
1393
1394   signal = dbus_message_new_signal (path,
1395                                     sigclosure->sigiface,
1396                                     sigclosure->signame);
1397   if (!signal)
1398     {
1399       g_error ("out of memory");
1400       return;
1401     }
1402
1403   dbus_message_iter_init_append (signal, &iter);
1404
1405   /* First argument is the object itself, and we can't marshall that */
1406   for (i = 1; i < n_param_values; i++)
1407     {
1408       if (!_dbus_gvalue_marshal (&iter,
1409                                 (GValue *) (&(param_values[i]))))
1410         {
1411           g_warning ("failed to marshal parameter %d for signal %s",
1412                      i, sigclosure->signame);
1413           goto out;
1414         }
1415     }
1416   dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
1417                         signal, NULL);
1418  out:
1419   dbus_message_unref (signal);
1420 }
1421
1422 static void
1423 export_signals (DBusGConnection *connection, const DBusGObjectInfo *info, GObject *object)
1424 {
1425   GType gtype;
1426   const char *sigdata;
1427   const char *iface;
1428   const char *signame;
1429
1430   gtype = G_TYPE_FROM_INSTANCE (object);
1431
1432   sigdata = info->exported_signals;
1433   
1434   while (*sigdata != '\0')
1435     {
1436       guint id;
1437       GSignalQuery query;
1438       GClosure *closure;
1439       char *s;
1440
1441       sigdata = propsig_iterate (sigdata, &iface, &signame);
1442       
1443       s = _dbus_gutils_wincaps_to_uscore (signame);
1444
1445       id = g_signal_lookup (s, gtype);
1446       if (id == 0)
1447         {
1448           g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
1449                      s, signame, g_type_name (gtype));
1450           g_free (s);
1451           continue;
1452         }
1453
1454       g_signal_query (id, &query);
1455
1456       if (query.return_type != G_TYPE_NONE)
1457         {
1458           g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"",
1459                      s, g_type_name (gtype), g_type_name (query.return_type));
1460           g_free (s);
1461           continue; /* FIXME: these could be listed as methods ? */
1462         }
1463       
1464       closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
1465       g_closure_set_marshal (closure, signal_emitter_marshaller);
1466
1467       g_signal_connect_closure_by_id (object,
1468                                       id,
1469                                       0,
1470                                       closure,
1471                                       FALSE);
1472
1473       g_closure_add_finalize_notifier (closure, NULL,
1474                                        dbus_g_signal_closure_finalize);
1475       g_free (s);
1476     }
1477 }
1478
1479 #include "dbus-glib-error-switch.h"
1480
1481 void
1482 dbus_set_g_error (GError    **gerror,
1483                   DBusError  *error)
1484 {
1485   int code;
1486
1487   code = dbus_error_to_gerror_code (error->name);
1488   if (code != DBUS_GERROR_REMOTE_EXCEPTION)
1489     g_set_error (gerror, DBUS_GERROR,
1490                  code,
1491                  "%s",
1492                  error->message);
1493   else
1494     g_set_error (gerror, DBUS_GERROR,
1495                  code,
1496                  "%s%c%s",
1497                  error->message ? error->message : "",
1498                  '\0',
1499                  error->name);
1500 }
1501
1502 static void
1503 dbus_g_error_info_free (gpointer p)
1504 {
1505   DBusGErrorInfo *info;
1506
1507   info = p;
1508
1509   g_free (info->default_iface);
1510   g_free (info);
1511 }
1512
1513 /** @} */ /* end of internals */
1514
1515 /**
1516  * @addtogroup DBusGLib
1517  * @{
1518  */
1519
1520 /**
1521  * Install introspection information about the given object GType
1522  * sufficient to allow methods on the object to be invoked by name.
1523  * The introspection information is normally generated by
1524  * dbus-glib-tool, then this function is called in the
1525  * class_init() for the object class.
1526  *
1527  * Once introspection information has been installed, instances of the
1528  * object registered with dbus_g_connection_register_g_object() can have
1529  * their methods invoked remotely.
1530  *
1531  * @param object_type GType for the object
1532  * @param info introspection data generated by dbus-glib-tool
1533  */
1534 void
1535 dbus_g_object_type_install_info (GType                  object_type,
1536                                  const DBusGObjectInfo *info)
1537 {
1538   g_return_if_fail (G_TYPE_IS_CLASSED (object_type));
1539
1540   _dbus_g_value_types_init ();
1541
1542   g_type_set_qdata (object_type,
1543                     dbus_g_object_type_dbus_metadata_quark (),
1544                     (gpointer) info);
1545 }
1546
1547 /**
1548  * Register a GError domain and set of codes with D-BUS.  You must
1549  * have created a GEnum for the error codes.  This function will not
1550  * be needed with an introspection-capable GLib.
1551  *
1552  * @param domain the GError domain 
1553  * @param default_iface the D-BUS interface used for error values by default, or #NULL
1554  * @param code_enum a GType for a GEnum of the error codes
1555  */
1556 void
1557 dbus_g_error_domain_register (GQuark                domain,
1558                               const char           *default_iface,
1559                               GType                 code_enum)
1560 {
1561   DBusGErrorInfo *info;
1562   
1563   g_return_if_fail (g_quark_to_string (domain) != NULL);
1564   g_return_if_fail (code_enum != G_TYPE_INVALID);
1565   g_return_if_fail (G_TYPE_FUNDAMENTAL (code_enum) == G_TYPE_ENUM);
1566
1567   g_static_rw_lock_writer_lock (&globals_lock);
1568
1569   if (error_metadata == NULL)
1570     g_datalist_init (&error_metadata);
1571
1572   info = g_datalist_id_get_data (&error_metadata, domain);
1573
1574   if (info != NULL)
1575     {
1576       g_warning ("Metadata for error domain \"%s\" already registered\n",
1577                  g_quark_to_string (domain));
1578     }
1579   else
1580     {
1581       info = g_new0 (DBusGErrorInfo, 1);
1582       info->default_iface = g_strdup (default_iface);
1583       info->code_enum = code_enum;
1584
1585       g_datalist_id_set_data_full (&error_metadata,
1586                                    domain,
1587                                    info,
1588                                    dbus_g_error_info_free);
1589     }
1590
1591   g_static_rw_lock_writer_unlock (&globals_lock);
1592 }
1593
1594 static void
1595 unregister_gobject (DBusGConnection *connection, GObject *dead)
1596 {
1597   char *path;
1598   path = g_object_steal_data (dead, "dbus_glib_object_path");
1599   dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection), path);
1600   g_free (path);
1601 }
1602
1603 /**
1604  * Registers a GObject at the given path. Properties, methods, and signals
1605  * of the object can then be accessed remotely. Methods are only available
1606  * if method introspection data has been added to the object's class
1607  * with g_object_class_install_info().
1608  *
1609  * The registration will be cancelled if either the DBusConnection or
1610  * the GObject gets finalized.
1611  *
1612  * @param connection the D-BUS connection
1613  * @param at_path the path where the object will live (the object's name)
1614  * @param object the object
1615  */
1616 void
1617 dbus_g_connection_register_g_object (DBusGConnection       *connection,
1618                                      const char            *at_path,
1619                                      GObject               *object)
1620 {
1621   const DBusGObjectInfo *info;
1622   g_return_if_fail (connection != NULL);
1623   g_return_if_fail (at_path != NULL);
1624   g_return_if_fail (G_IS_OBJECT (object));
1625
1626   info = lookup_object_info (object);
1627   if (info == NULL)
1628     {
1629       g_warning ("No introspection data registered for object class \"%s\"",
1630                  g_type_name (G_TYPE_FROM_INSTANCE (object)));
1631       return;
1632     }
1633
1634   if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
1635                                              at_path,
1636                                              &gobject_dbus_vtable,
1637                                              object))
1638     {
1639       g_error ("Failed to register GObject with DBusConnection");
1640       return;
1641     }
1642
1643   export_signals (connection, info, object);
1644
1645   g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
1646   g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
1647 }
1648
1649 GObject *
1650 dbus_g_connection_lookup_g_object (DBusGConnection       *connection,
1651                                    const char            *at_path)
1652 {
1653   gpointer ret;
1654   if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
1655     return NULL;
1656   return ret;
1657 }
1658
1659 typedef struct {
1660   GType    rettype;
1661   guint    n_params;
1662   GType   *params;
1663 } DBusGFuncSignature;
1664
1665 static guint
1666 funcsig_hash (gconstpointer key)
1667 {
1668   const DBusGFuncSignature *sig = key;
1669   GType *types;
1670   guint ret;
1671   guint i;
1672
1673   ret = sig->rettype;
1674   types = sig->params;
1675
1676   for (i = 0; i < sig->n_params; i++)
1677     {
1678       ret += (int) (*types);
1679       types++;
1680     }
1681       
1682   return ret;
1683 }
1684
1685 static gboolean
1686 funcsig_equal (gconstpointer aval,
1687                gconstpointer bval)
1688 {
1689   const DBusGFuncSignature *a = aval;
1690   const DBusGFuncSignature *b = bval;
1691   const GType *atypes;
1692   const GType *btypes;
1693   guint i;
1694
1695   if (a->rettype != b->rettype
1696       || a->n_params != b->n_params)
1697     return FALSE;
1698
1699   atypes = a->params;
1700   btypes = b->params;
1701
1702   for (i = 0; i < a->n_params; i++)
1703     {
1704       if (*btypes != *atypes)
1705         return FALSE;
1706       atypes++;
1707       btypes++;
1708     }
1709       
1710   return TRUE;
1711 }
1712
1713 GClosureMarshal
1714 _dbus_gobject_lookup_marshaller (GType        rettype,
1715                                  guint        n_params,
1716                                  const GType *param_types)
1717 {
1718   GClosureMarshal ret;
1719   DBusGFuncSignature sig;
1720   GType *params;
1721   guint i;
1722
1723   /* Convert to fundamental types */
1724   rettype = G_TYPE_FUNDAMENTAL (rettype);
1725   params = g_new (GType, n_params);
1726   for (i = 0; i < n_params; i++)
1727     params[i] = G_TYPE_FUNDAMENTAL (param_types[i]);
1728
1729   sig.rettype = rettype;
1730   sig.n_params = n_params;
1731   sig.params = params;
1732   
1733   g_static_rw_lock_reader_lock (&globals_lock);
1734
1735   if (marshal_table)
1736     ret = g_hash_table_lookup (marshal_table, &sig);
1737   else
1738     ret = NULL;
1739
1740   g_static_rw_lock_reader_unlock (&globals_lock);
1741
1742   if (ret == NULL)
1743     {
1744       if (rettype == G_TYPE_NONE)
1745         {
1746           if (n_params == 0)
1747             ret = g_cclosure_marshal_VOID__VOID;
1748           else if (n_params == 1)
1749             {
1750               switch (params[0])
1751                 {
1752                 case G_TYPE_BOOLEAN:
1753                   ret = g_cclosure_marshal_VOID__BOOLEAN;
1754                   break;
1755                 case G_TYPE_UCHAR:
1756                   ret = g_cclosure_marshal_VOID__UCHAR;
1757                   break;
1758                 case G_TYPE_INT:
1759                   ret = g_cclosure_marshal_VOID__INT;
1760                   break;
1761                 case G_TYPE_UINT:
1762                   ret = g_cclosure_marshal_VOID__UINT;
1763                   break;
1764                 case G_TYPE_DOUBLE:
1765                   ret = g_cclosure_marshal_VOID__DOUBLE;
1766                   break;
1767                 case G_TYPE_STRING:
1768                   ret = g_cclosure_marshal_VOID__STRING;
1769                   break;
1770                 case G_TYPE_BOXED:
1771                   ret = g_cclosure_marshal_VOID__BOXED;
1772                   break;
1773                 }
1774             }
1775           else if (n_params == 3
1776                    && params[0] == G_TYPE_STRING
1777                    && params[1] == G_TYPE_STRING
1778                    && params[2] == G_TYPE_STRING)
1779             {
1780               ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
1781             }
1782         }
1783     }
1784
1785   g_free (params);
1786   return ret;
1787 }
1788
1789 /**
1790  * Register a GClosureMarshal to be used for signal invocations,
1791  * giving its return type and a list of parameter types,
1792  * followed by G_TYPE_INVALID.
1793
1794  * This function will not be needed once GLib includes libffi.
1795  *
1796  * @param marshaller a GClosureMarshal to be used for invocation
1797  * @param rettype a GType for the return type of the function
1798  * @param ... The parameter GTypes, followed by G_TYPE_INVALID
1799  */
1800 void
1801 dbus_g_object_register_marshaller (GClosureMarshal  marshaller,
1802                                    GType            rettype,
1803                                    ...)
1804 {
1805   va_list args;
1806   GArray *types;
1807   GType gtype;
1808
1809   va_start (args, rettype);
1810
1811   types = g_array_new (TRUE, TRUE, sizeof (GType));
1812
1813   while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
1814     g_array_append_val (types, gtype);
1815
1816   dbus_g_object_register_marshaller_array (marshaller, rettype,
1817                                            types->len, (GType*) types->data);
1818
1819   g_array_free (types, TRUE);
1820   va_end (args);
1821 }
1822
1823 /**
1824  * Register a GClosureMarshal to be used for signal invocations.
1825  * See also #dbus_g_object_register_marshaller
1826  *
1827  * @param marshaller a GClosureMarshal to be used for invocation
1828  * @param rettype a GType for the return type of the function
1829  * @param n_types number of function parameters
1830  * @param types a C array of GTypes values
1831  */
1832 void
1833 dbus_g_object_register_marshaller_array (GClosureMarshal  marshaller,
1834                                          GType            rettype,
1835                                          guint            n_types,
1836                                          const GType*     types)
1837 {
1838   DBusGFuncSignature *sig;
1839   guint i;
1840
1841   g_static_rw_lock_writer_lock (&globals_lock);
1842
1843   if (marshal_table == NULL)
1844     marshal_table = g_hash_table_new_full (funcsig_hash,
1845                                            funcsig_equal,
1846                                            g_free,
1847                                            NULL);
1848   sig = g_new0 (DBusGFuncSignature, 1);
1849   sig->rettype = G_TYPE_FUNDAMENTAL (rettype);
1850   sig->n_params = n_types;
1851   sig->params = g_new (GType, n_types);
1852   for (i = 0; i < n_types; i++)
1853     sig->params[i] = G_TYPE_FUNDAMENTAL (types[i]);
1854
1855   g_hash_table_insert (marshal_table, sig, marshaller);
1856
1857   g_static_rw_lock_writer_unlock (&globals_lock);
1858 }
1859
1860 /**
1861  * Send a return message for a given method invocation, with arguments.
1862  * This function also frees the sending context.
1863  *
1864  * @param context the method context
1865  */
1866 void
1867 dbus_g_method_return (DBusGMethodInvocation *context, ...)
1868 {
1869   DBusMessage *reply;
1870   DBusMessageIter iter;
1871   va_list args;
1872   char *out_sig;
1873   GArray *argsig;
1874   guint i;
1875
1876   reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
1877   out_sig = method_output_signature_from_object_info (context->object, context->method);
1878   argsig = _dbus_gtypes_from_arg_signature (out_sig, FALSE);
1879
1880   dbus_message_iter_init_append (reply, &iter);
1881
1882   va_start (args, context);
1883   for (i = 0; i < argsig->len; i++)
1884     {
1885       GValue value = {0,};
1886       char *error;
1887       g_value_init (&value, g_array_index (argsig, GType, i));
1888       error = NULL;
1889       G_VALUE_COLLECT (&value, args, G_VALUE_NOCOPY_CONTENTS, &error);
1890       if (error)
1891         {
1892           g_warning(error);
1893           g_free (error);
1894         }
1895       _dbus_gvalue_marshal (&iter, &value);
1896     }
1897   va_end (args);
1898
1899   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
1900   dbus_message_unref (reply);
1901
1902   dbus_g_connection_unref (context->connection);
1903   dbus_g_message_unref (context->message);
1904   g_free (context);
1905   g_free (out_sig);
1906 }
1907
1908 /**
1909  * Send a error message for a given method invocation.
1910  * This function also frees the sending context.
1911  *
1912  * @param context the method context
1913  * @param error the error to send.
1914  */
1915 void
1916 dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
1917 {
1918   DBusMessage *reply;
1919   reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
1920   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
1921   dbus_message_unref (reply);
1922   g_free (context);
1923 }
1924
1925 /** @} */ /* end of public API */
1926
1927 const char * _dbus_gobject_get_path (GObject *obj)
1928 {
1929   return g_object_get_data (obj, "dbus_glib_object_path");
1930 }
1931
1932 #ifdef DBUS_BUILD_TESTS
1933 #include <stdlib.h>
1934
1935 static void
1936 _dummy_function (void)
1937 {
1938 }
1939
1940 /* Data structures copied from one generated by current dbus-binding-tool;
1941  * we need to support this layout forever
1942  */
1943 static const DBusGMethodInfo dbus_glib_internal_test_methods[] = {
1944   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 0 },
1945   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 49 },
1946   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 117 },
1947   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 191 },
1948   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 270 },
1949   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 320 },
1950   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 391 },
1951   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 495 },
1952   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 623 },
1953   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 693 },
1954   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 765 },
1955   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 838 },
1956   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 911 },
1957   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 988 },
1958   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1064 },
1959   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1140 },
1960   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1204 },
1961   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1278 },
1962   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1347 },
1963   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1408 },
1964   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1460 },
1965   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1533 },
1966   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1588 },
1967   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1647 },
1968   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1730 },
1969   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1784 },
1970   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1833 },
1971   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1895 },
1972   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1947 },
1973   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1999 },
1974 };
1975
1976 const DBusGObjectInfo dbus_glib_internal_test_object_info = {
1977   0,
1978   dbus_glib_internal_test_methods,
1979   30,
1980 "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",
1981 "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",
1982 "\0"
1983 };
1984
1985
1986 /**
1987  * @ingroup DBusGLibInternals
1988  * Unit test for GLib GObject integration ("skeletons")
1989  * @returns #TRUE on success.
1990  */
1991 gboolean
1992 _dbus_gobject_test (const char *test_data_dir)
1993 {
1994   int i;
1995   const char *arg;
1996   const char *arg_name;
1997   gboolean arg_in;
1998   gboolean constval;
1999   RetvalType retval;
2000   const char *arg_signature;
2001   const char *sigdata;
2002   const char *iface;
2003   const char *signame;
2004   
2005   static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
2006     { "SetFoo", "set_foo" },
2007     { "Foo", "foo" },
2008     { "GetFooBar", "get_foo_bar" },
2009     { "Hello", "hello" }
2010     
2011     /* Impossible-to-handle cases */
2012     /* { "FrobateUIHandler", "frobate_ui_handler" } */
2013   };
2014
2015   /* Test lookup in our hardcoded object info; if these tests fail
2016    * then it likely means you changed the generated object info in an
2017    * incompatible way and broke the lookup functions.  In that case
2018    * you need to bump the version and use a new structure instead. */
2019   /* DoNothing */
2020   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
2021                                           &(dbus_glib_internal_test_methods[0]));
2022   g_assert (*arg == '\0');
2023
2024   /* Increment */
2025   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
2026                                           &(dbus_glib_internal_test_methods[1]));
2027   g_assert (*arg != '\0');
2028   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
2029   g_assert (!strcmp (arg_name, "x"));
2030   g_assert (arg_in == TRUE);
2031   g_assert (!strcmp (arg_signature, "u"));
2032   g_assert (*arg != '\0');
2033   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
2034   g_assert (arg_in == FALSE);
2035   g_assert (retval == RETVAL_NONE);
2036   g_assert (!strcmp (arg_signature, "u"));
2037   g_assert (*arg == '\0');
2038
2039   /* IncrementRetval */
2040   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
2041                                           &(dbus_glib_internal_test_methods[2]));
2042   g_assert (*arg != '\0');
2043   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
2044   g_assert (!strcmp (arg_name, "x"));
2045   g_assert (arg_in == TRUE);
2046   g_assert (!strcmp (arg_signature, "u"));
2047   g_assert (*arg != '\0');
2048   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
2049   g_assert (retval == RETVAL_NOERROR);
2050   g_assert (arg_in == FALSE);
2051   g_assert (!strcmp (arg_signature, "u"));
2052   g_assert (*arg == '\0');
2053
2054   /* IncrementRetvalError */
2055   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
2056                                           &(dbus_glib_internal_test_methods[3]));
2057   g_assert (*arg != '\0');
2058   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
2059   g_assert (!strcmp (arg_name, "x"));
2060   g_assert (arg_in == TRUE);
2061   g_assert (!strcmp (arg_signature, "u"));
2062   g_assert (*arg != '\0');
2063   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
2064   g_assert (retval == RETVAL_ERROR);
2065   g_assert (arg_in == FALSE);
2066   g_assert (!strcmp (arg_signature, "u"));
2067   g_assert (*arg == '\0');
2068   
2069   /* Stringify */
2070   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
2071                                           &(dbus_glib_internal_test_methods[8]));
2072   g_assert (*arg != '\0');
2073   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
2074   g_assert (!strcmp (arg_name, "val"));
2075   g_assert (arg_in == TRUE);
2076   g_assert (!strcmp (arg_signature, "v"));
2077   g_assert (*arg != '\0');
2078   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
2079   g_assert (retval == RETVAL_NONE);
2080   g_assert (arg_in == FALSE);
2081   g_assert (!strcmp (arg_signature, "s"));
2082   g_assert (*arg == '\0');
2083
2084   sigdata = dbus_glib_internal_test_object_info.exported_signals;
2085   g_assert (*sigdata != '\0');
2086   sigdata = propsig_iterate (sigdata, &iface, &signame);
2087   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.MyObject"));
2088   g_assert (!strcmp (signame, "Frobnicate"));
2089   g_assert (*sigdata != '\0');
2090   sigdata = propsig_iterate (sigdata, &iface, &signame);
2091   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
2092   g_assert (!strcmp (signame, "Sig0"));
2093   g_assert (*sigdata != '\0');
2094   sigdata = propsig_iterate (sigdata, &iface, &signame);
2095   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
2096   g_assert (!strcmp (signame, "Sig1"));
2097   g_assert (*sigdata != '\0');
2098   sigdata = propsig_iterate (sigdata, &iface, &signame);
2099   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
2100   g_assert (!strcmp (signame, "Sig2"));
2101   g_assert (*sigdata == '\0');
2102   
2103
2104   i = 0;
2105   while (i < (int) G_N_ELEMENTS (name_pairs))
2106     {
2107       char *uscore;
2108       char *wincaps;
2109
2110       uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
2111       wincaps = uscore_to_wincaps (name_pairs[i].uscore);
2112
2113       if (strcmp (uscore, name_pairs[i].uscore) != 0)
2114         {
2115           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
2116                       name_pairs[i].wincaps, name_pairs[i].uscore,
2117                       uscore);
2118           exit (1);
2119         }
2120       
2121       if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
2122         {
2123           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
2124                       name_pairs[i].uscore, name_pairs[i].wincaps,
2125                       wincaps);
2126           exit (1);
2127         }
2128       
2129       g_free (uscore);
2130       g_free (wincaps);
2131
2132       ++i;
2133     }
2134   
2135   return TRUE;
2136 }
2137
2138 #endif /* DBUS_BUILD_TESTS */