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