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