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