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