1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gobject.c Exporting a GObject remotely
4 * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <gobject/gvaluecollector.h>
26 #include <dbus/dbus-glib.h>
27 #include <dbus/dbus-glib-lowlevel.h>
28 #include "dbus-gtest.h"
29 #include "dbus-gutils.h"
30 #include "dbus-gobject.h"
31 #include "dbus-gvalue.h"
32 #include "dbus-gmarshal.h"
33 #include "dbus-gvalue-utils.h"
37 * @addtogroup DBusGLibInternals
41 static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
42 static GHashTable *info_hash = NULL;
43 static GHashTable *marshal_table = NULL;
46 uscore_to_wincaps (const char *uscore)
50 gboolean last_was_uscore;
52 last_was_uscore = TRUE;
54 str = g_string_new (NULL);
58 if (*p == '-' || *p == '_')
60 last_was_uscore = TRUE;
66 g_string_append_c (str, g_ascii_toupper (*p));
67 last_was_uscore = FALSE;
70 g_string_append_c (str, *p);
75 return g_string_free (str, FALSE);
79 string_table_next (const char *table)
81 return (table + (strlen (table) + 1));
85 string_table_lookup (const char *table, int index)
92 ret = string_table_next (ret);
98 get_method_data (const DBusGObjectInfo *object,
99 const DBusGMethodInfo *method)
101 return object->data + method->data_offset;
105 object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
112 object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
119 method_interface_from_object_info (const DBusGObjectInfo *object,
120 const DBusGMethodInfo *method)
122 return string_table_lookup (get_method_data (object, method), 0);
126 method_name_from_object_info (const DBusGObjectInfo *object,
127 const DBusGMethodInfo *method)
129 return string_table_lookup (get_method_data (object, method), 1);
133 method_arg_info_from_object_info (const DBusGObjectInfo *object,
134 const DBusGMethodInfo *method)
136 return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
140 arg_iterate (const char *data, const char **name, gboolean *in,
145 data = string_table_next (data);
155 g_warning ("invalid arg direction");
159 data = string_table_next (data);
162 return string_table_next (data);
166 method_dir_signature_from_object_info (const DBusGObjectInfo *object,
167 const DBusGMethodInfo *method,
173 arg = method_arg_info_from_object_info (object, method);
175 ret = g_string_new (NULL);
183 arg = arg_iterate (arg, &name, &arg_in, &type);
186 g_string_append (ret, type);
189 return g_string_free (ret, FALSE);
193 method_input_signature_from_object_info (const DBusGObjectInfo *object,
194 const DBusGMethodInfo *method)
196 return method_dir_signature_from_object_info (object, method, TRUE);
200 method_output_signature_from_object_info (const DBusGObjectInfo *object,
201 const DBusGMethodInfo *method)
203 return method_dir_signature_from_object_info (object, method, FALSE);
207 gobject_unregister_function (DBusConnection *connection,
212 object = G_OBJECT (user_data);
219 introspect_properties (GObject *object, GString *xml)
222 unsigned int n_specs;
226 last_type = G_TYPE_INVALID;
227 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object),
230 for (i = 0; i < n_specs; i++ )
233 const char *dbus_type;
236 GParamSpec *spec = specs[i];
238 dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
239 if (dbus_type == NULL)
242 if (spec->owner_type != last_type)
244 if (last_type != G_TYPE_INVALID)
245 g_string_append (xml, " </interface>\n");
248 /* FIXME what should the namespace on the interface be in
249 * general? should people be able to set it for their
252 g_string_append (xml, " <interface name=\"org.gtk.objects.");
253 g_string_append (xml, g_type_name (spec->owner_type));
254 g_string_append (xml, "\">\n");
256 last_type = spec->owner_type;
259 can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
260 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
262 can_get = (spec->flags & G_PARAM_READABLE) != 0;
264 s = uscore_to_wincaps (spec->name);
266 if (can_set || can_get)
268 g_string_append (xml, " <property name=\"");
269 g_string_append (xml, s);
270 g_string_append (xml, "\" type=\"");
271 g_string_append (xml, dbus_type);
272 g_string_append (xml, "\" access=\"");
274 if (can_set && can_get)
275 g_string_append (xml, "readwrite");
277 g_string_append (xml, "read");
281 g_string_append (xml, "write");
284 g_string_append (xml, "\"/>\n");
290 if (last_type != G_TYPE_INVALID)
291 g_string_append (xml, " </interface>\n");
297 introspect_signals (GType type, GString *xml)
302 ids = g_signal_list_ids (type, &n_ids);
306 g_string_append (xml, " <interface name=\"org.gtk.objects.");
307 g_string_append (xml, g_type_name (type));
308 g_string_append (xml, "\">\n");
310 /* FIXME: recurse to parent types ? */
311 for (i = 0; i < n_ids; i++)
316 g_signal_query (ids[i], &query);
318 if (query.return_type != G_TYPE_NONE)
319 continue; /* FIXME: these could be listed as methods ? */
321 g_string_append (xml, " <signal name=\"");
322 g_string_append (xml, query.signal_name);
323 g_string_append (xml, "\">\n");
325 for (arg = 0; arg < query.n_params; arg++)
327 const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]);
332 g_string_append (xml, " <arg type=\"");
333 g_string_append (xml, dbus_type);
334 g_string_append (xml, "\"/>\n");
337 g_string_append (xml, " </signal>\n");
340 g_string_append (xml, " </interface>\n");
346 const DBusGObjectInfo *object_info;
347 } DBusGlibWriteIterfaceData;
350 write_interface (gpointer key, gpointer val, gpointer user_data)
355 const DBusGObjectInfo *object_info;
356 DBusGlibWriteIterfaceData *data;
362 object_info = data->object_info;
364 g_string_append_printf (xml, " <interface name=\"%s\">\n", name);
366 /* FIXME: recurse to parent types ? */
367 for (; methods; methods = methods->next)
369 DBusGMethodInfo *method;
370 method = methods->data;
373 g_string_append_printf (xml, " <method name=\"%s\">\n",
374 method_name_from_object_info (object_info, method));
376 args = method_arg_info_from_object_info (object_info, method);
384 args = arg_iterate (args, &name, &arg_in, &type);
386 /* FIXME - handle container types */
387 g_string_append_printf (xml, " <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
388 name, type, arg_in ? "in" : "out");
391 g_string_append (xml, " </method>\n");
394 g_string_append (xml, " </interface>\n");
398 introspect_interfaces (GObject *object, GString *xml)
402 g_static_rw_lock_reader_lock (&globals_lock);
404 for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
406 const DBusGObjectInfo *info;
407 DBusGlibWriteIterfaceData data;
409 info = g_hash_table_lookup (info_hash,
410 g_type_class_peek (classtype));
412 if (info != NULL && info->format_version == 0)
415 GHashTable *interfaces;
417 /* Gather a list of all interfaces, indexed into their methods */
418 interfaces = g_hash_table_new (g_str_hash, g_str_equal);
419 for (i = 0; i < info->n_infos; i++)
421 const char *method_name;
422 const char *method_interface;
423 const char *method_args;
424 const DBusGMethodInfo *method;
427 method = &(info->infos[i]);
429 method_interface = method_interface_from_object_info (info, method);
430 method_name = method_name_from_object_info (info, method);
431 method_args = method_arg_info_from_object_info (info, method);
433 if ((methods = g_hash_table_lookup (interfaces, method_interface)) == NULL)
434 methods = g_slist_prepend (NULL, (gpointer) method);
436 methods = g_slist_prepend (methods, (gpointer) method);
437 g_hash_table_insert (interfaces, (gpointer) method_interface, methods);
440 memset (&data, 0, sizeof (data));
442 data.object_info = info;
443 g_hash_table_foreach (interfaces, write_interface, &data);
445 g_hash_table_destroy (interfaces);
449 g_static_rw_lock_reader_unlock (&globals_lock);
452 static DBusHandlerResult
453 handle_introspect (DBusConnection *connection,
454 DBusMessage *message,
462 if (!dbus_connection_list_registered (connection,
463 dbus_message_get_path (message),
465 g_error ("Out of memory");
467 xml = g_string_new (NULL);
469 g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
471 g_string_append (xml, "<node>\n");
473 /* We are introspectable, though I guess that was pretty obvious */
474 g_string_append_printf (xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE);
475 g_string_append (xml, " <method name=\"Introspect\">\n");
476 g_string_append_printf (xml, " <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
477 g_string_append (xml, " </method>\n");
478 g_string_append (xml, " </interface>\n");
480 /* We support get/set properties */
481 g_string_append_printf (xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_PROPERTIES);
482 g_string_append (xml, " <method name=\"Get\">\n");
483 g_string_append_printf (xml, " <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
484 g_string_append_printf (xml, " <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
485 g_string_append_printf (xml, " <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
486 g_string_append (xml, " </method>\n");
487 g_string_append (xml, " <method name=\"Set\">\n");
488 g_string_append_printf (xml, " <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
489 g_string_append_printf (xml, " <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
490 g_string_append_printf (xml, " <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
491 g_string_append (xml, " </method>\n");
492 g_string_append (xml, " </interface>\n");
494 introspect_signals (G_OBJECT_TYPE (object), xml);
495 introspect_properties (object, xml);
496 introspect_interfaces (object, xml);
498 /* Append child nodes */
499 for (i = 0; children[i]; i++)
500 g_string_append_printf (xml, " <node name=\"%s\"/>\n",
503 /* Close the XML, and send it to the requesting app */
504 g_string_append (xml, "</node>\n");
506 ret = dbus_message_new_method_return (message);
508 g_error ("Out of memory");
510 dbus_message_append_args (ret,
511 DBUS_TYPE_STRING, &xml->str,
514 dbus_connection_send (connection, ret, NULL);
515 dbus_message_unref (ret);
517 g_string_free (xml, TRUE);
519 dbus_free_string_array (children);
521 return DBUS_HANDLER_RESULT_HANDLED;
525 set_object_property (DBusConnection *connection,
526 DBusMessage *message,
527 DBusMessageIter *iter,
531 GValue value = { 0, };
534 DBusGValueMarshalCtx context;
536 dbus_message_iter_recurse (iter, &sub);
538 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
539 context.proxy = NULL;
541 g_value_init (&value, pspec->value_type);
542 if (dbus_gvalue_demarshal (&context, &sub, &value, NULL))
544 g_object_set_property (object,
548 g_value_unset (&value);
550 ret = dbus_message_new_method_return (message);
552 g_error ("out of memory");
556 ret = dbus_message_new_error (message,
557 DBUS_ERROR_INVALID_ARGS,
558 "Argument's D-BUS type can't be converted to a GType");
560 g_error ("out of memory");
567 get_object_property (DBusConnection *connection,
568 DBusMessage *message,
573 GValue value = {0, };
575 DBusMessageIter iter;
577 value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
579 ret = dbus_message_new_method_return (message);
581 g_error ("out of memory");
583 g_value_init (&value, value_type);
584 g_object_get_property (object, pspec->name, &value);
586 value_type = G_VALUE_TYPE (&value);
588 dbus_message_iter_init_append (message, &iter);
590 if (!dbus_gvalue_marshal (&iter, &value))
592 dbus_message_unref (ret);
593 ret = dbus_message_new_error (message,
594 DBUS_ERROR_UNKNOWN_METHOD,
595 "Can't convert GType of object property to a D-BUS type");
602 lookup_object_and_method (GObject *object,
603 DBusMessage *message,
604 const DBusGObjectInfo **object_ret,
605 const DBusGMethodInfo **method_ret)
608 const char *interface;
610 const char *signature;
613 interface = dbus_message_get_interface (message);
614 member = dbus_message_get_member (message);
615 signature = dbus_message_get_signature (message);
618 g_static_rw_lock_reader_lock (&globals_lock);
623 for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
625 const DBusGObjectInfo *info;
627 info = g_hash_table_lookup (info_hash,
628 g_type_class_peek (classtype));
632 if (info != NULL && info->format_version == 0)
635 for (i = 0; i < info->n_infos; i++)
637 const char *expected_member;
638 const char *expected_interface;
639 char *expected_signature;
640 const DBusGMethodInfo *method;
642 method = &(info->infos[i]);
644 /* Check method interface/name and input signature */
645 expected_interface = method_interface_from_object_info (*object_ret, method);
646 expected_member = method_name_from_object_info (*object_ret, method);
647 expected_signature = method_input_signature_from_object_info (*object_ret, method);
649 if ((interface == NULL
650 || strcmp (expected_interface, interface) == 0)
651 && strcmp (expected_member, member) == 0
652 && strcmp (expected_signature, signature) == 0)
654 g_free (expected_signature);
655 *method_ret = method;
659 g_free (expected_signature);
664 g_static_rw_lock_reader_unlock (&globals_lock);
669 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
670 GQuark domain, gint code)
672 const char *domain_str;
673 const char *code_str;
674 GString *dbus_error_name;
676 domain_str = object_error_domain_prefix_from_object_info (object_info);
677 code_str = object_error_code_from_object_info (object_info, domain, code);
679 if (!domain_str || !code_str)
681 /* If we can't map it sensibly, make up an error name */
682 char *domain_from_quark;
684 dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
686 domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
687 g_string_append (dbus_error_name, domain_from_quark);
688 g_free (domain_from_quark);
690 g_string_append_printf (dbus_error_name, ".Code%d", code);
694 dbus_error_name = g_string_new (domain_str);
695 g_string_append_c (dbus_error_name, '.');
696 g_string_append (dbus_error_name, code_str);
699 return g_string_free (dbus_error_name, FALSE);
703 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
704 DBusMessage *message,
713 error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
714 reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
720 error_name = gerror_domaincode_to_dbus_error_name (object_info, error->domain, error->code);
721 reply = dbus_message_new_error (message, error_name, error->message);
728 * The context of an asynchronous method call. See dbus_g_method_return() and
729 * dbus_g_method_return_error().
731 struct DBusGMethodInvocation {
732 DBusGConnection *connection; /**< The connection */
733 DBusGMessage *message; /**< The message which generated the method call */
734 const DBusGObjectInfo *object; /**< The object the method was called on */
735 const DBusGMethodInfo *method; /**< The method called */
738 static DBusHandlerResult
739 invoke_object_method (GObject *object,
740 const DBusGObjectInfo *object_info,
741 const DBusGMethodInfo *method,
742 DBusConnection *connection,
743 DBusMessage *message)
745 gboolean had_error, call_only;
747 GValueArray *value_array;
748 GValue object_value = {0,};
749 GValue error_value = {0,};
750 GValue return_value = {0,};
753 char *out_signature = NULL;
755 DBusSignatureIter out_signature_iter;
756 GArray *out_param_values = NULL;
757 GValueArray *out_param_gvalues = NULL;
759 int out_param_pos, out_param_gvalue_pos;
760 DBusHandlerResult result;
765 if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
770 /* This is evil. We do this to work around the fact that
771 * the generated glib marshallers check a flag in the closure object
772 * which we don't care about. We don't need/want to create
773 * a new closure for each invocation.
775 memset (&closure, 0, sizeof (closure));
777 in_signature = method_input_signature_from_object_info (object_info, method);
779 /* Convert method IN parameters to GValueArray */
784 DBusGValueMarshalCtx context;
785 GError *error = NULL;
787 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
788 context.proxy = NULL;
790 types_array = dbus_gtypes_from_arg_signature (in_signature, FALSE);
791 n_params = types_array->len;
792 types = (const GType*) types_array->data;
794 value_array = dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
795 if (value_array == NULL)
797 g_free (in_signature);
798 g_array_free (types_array, TRUE);
799 reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
800 dbus_connection_send (connection, reply, NULL);
801 dbus_message_unref (reply);
802 g_error_free (error);
803 return DBUS_HANDLER_RESULT_HANDLED;
805 g_array_free (types_array, TRUE);
808 /* Prepend object as first argument */
809 g_value_init (&object_value, G_TYPE_OBJECT);
810 g_value_set_object (&object_value, object);
811 g_value_array_prepend (value_array, &object_value);
815 GValue context_value = {0,};
816 DBusGMethodInvocation *context;
817 context = g_new (DBusGMethodInvocation, 1);
818 context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
819 context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
820 context->object = object_info;
821 context->method = method;
822 g_value_init (&context_value, G_TYPE_POINTER);
823 g_value_set_pointer (&context_value, context);
824 g_value_array_append (value_array, &context_value);
828 out_signature = method_output_signature_from_object_info (object_info, method);
830 /* Count number of output parameters */
831 dbus_signature_iter_init (&out_signature_iter, out_signature);
833 while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
836 dbus_signature_iter_next (&out_signature_iter);
839 /* Create an array to store the actual values of OUT
840 * parameters. Then, create a GValue boxed POINTER
841 * to each of those values, and append to the invocation,
842 * so the method can return the OUT parameters.
844 out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
846 /* We have a special array of GValues for toplevel GValue return
849 out_param_gvalues = g_value_array_new (out_param_count);
851 out_param_gvalue_pos = 0;
852 dbus_signature_iter_init (&out_signature_iter, out_signature);
853 while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
855 GValue value = {0, };
858 g_value_init (&value, G_TYPE_POINTER);
860 /* We special case variants to make method invocation a bit nicer */
861 if (current_type != DBUS_TYPE_VARIANT)
863 memset (&storage, 0, sizeof (storage));
864 g_array_append_val (out_param_values, storage);
865 g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
870 g_value_array_append (out_param_gvalues, NULL);
871 g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
872 out_param_gvalue_pos++;
874 g_value_array_append (value_array, &value);
875 dbus_signature_iter_next (&out_signature_iter);
878 /* Append GError as final argument */
879 g_value_init (&error_value, G_TYPE_POINTER);
880 g_value_set_pointer (&error_value, &gerror);
881 g_value_array_append (value_array, &error_value);
883 /* Actually invoke method */
884 g_value_init (&return_value, G_TYPE_BOOLEAN);
885 method->marshaller (&closure, &return_value,
886 value_array->n_values,
888 NULL, method->function);
891 result = DBUS_HANDLER_RESULT_HANDLED;
894 had_error = !g_value_get_boolean (&return_value);
898 DBusMessageIter iter;
900 reply = dbus_message_new_method_return (message);
904 /* Append OUT arguments to reply */
905 dbus_message_iter_init_append (reply, &iter);
906 dbus_signature_iter_init (&out_signature_iter, out_signature);
908 out_param_gvalue_pos = 0;
909 while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
911 GValue gvalue = {0, };
913 g_value_init (&gvalue, dbus_gtype_from_signature_iter (&out_signature_iter, FALSE));
914 if (current_type != DBUS_TYPE_VARIANT)
916 if (!dbus_gvalue_take (&gvalue,
917 &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
918 g_assert_not_reached ();
923 g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
924 out_param_gvalue_pos++;
927 if (!dbus_gvalue_marshal (&iter, &gvalue))
929 /* Here we actually free the allocated value; we
930 * took ownership of it with dbus_gvalue_take.
932 g_value_unset (&gvalue);
933 dbus_signature_iter_next (&out_signature_iter);
937 reply = gerror_to_dbus_error_message (object_info, message, gerror);
941 dbus_connection_send (connection, reply, NULL);
942 dbus_message_unref (reply);
945 result = DBUS_HANDLER_RESULT_HANDLED;
947 g_free (in_signature);
948 g_free (out_signature);
951 g_array_free (out_param_values, TRUE);
952 g_value_array_free (out_param_gvalues);
953 g_value_unset (&object_value);
954 g_value_unset (&error_value);
956 g_value_array_free (value_array);
957 g_value_unset (&return_value);
960 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
964 static DBusHandlerResult
965 gobject_message_function (DBusConnection *connection,
966 DBusMessage *message,
974 const char *wincaps_propname;
975 /* const char *wincaps_propiface; */
976 DBusMessageIter iter;
977 const DBusGMethodInfo *method;
978 const DBusGObjectInfo *object_info;
980 object = G_OBJECT (user_data);
982 if (dbus_message_is_method_call (message,
983 DBUS_INTERFACE_INTROSPECTABLE,
985 return handle_introspect (connection, message, object);
987 /* Try the metainfo, which lets us invoke methods */
988 if (lookup_object_and_method (object, message, &object_info, &method))
989 return invoke_object_method (object, object_info, method, connection, message);
991 /* If no metainfo, we can still do properties and signals
992 * via standard GLib introspection
996 if (dbus_message_is_method_call (message,
997 DBUS_INTERFACE_PROPERTIES,
1000 else if (dbus_message_is_method_call (message,
1001 DBUS_INTERFACE_PROPERTIES,
1005 if (!(setter || getter))
1006 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1008 dbus_message_iter_init (message, &iter);
1010 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
1012 g_warning ("Property get or set does not have an interface string as first arg\n");
1013 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1015 /* We never use the interface name; if we did, we'd need to
1016 * remember that it can be empty string for "pick one for me"
1018 /* dbus_message_iter_get_basic (&iter, &wincaps_propiface); */
1019 dbus_message_iter_next (&iter);
1021 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
1023 g_warning ("Property get or set does not have a property name string as second arg\n");
1024 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1026 dbus_message_iter_get_basic (&iter, &wincaps_propname);
1027 dbus_message_iter_next (&iter);
1029 s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
1031 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
1042 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
1044 g_warning ("Property set does not have a variant value as third arg\n");
1045 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1048 ret = set_object_property (connection, message, &iter,
1050 dbus_message_iter_next (&iter);
1054 ret = get_object_property (connection, message,
1059 g_assert_not_reached ();
1063 g_assert (ret != NULL);
1065 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
1066 g_warning ("Property get or set had too many arguments\n");
1068 dbus_connection_send (connection, ret, NULL);
1069 dbus_message_unref (ret);
1070 return DBUS_HANDLER_RESULT_HANDLED;
1073 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1076 static DBusObjectPathVTable gobject_dbus_vtable = {
1077 gobject_unregister_function,
1078 gobject_message_function,
1084 DBusGConnection *connection;
1087 } DBusGSignalClosure;
1090 dbus_g_signal_closure_new (DBusGConnection *connection,
1092 const char *signame)
1094 DBusGSignalClosure *closure;
1096 closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
1098 closure->connection = dbus_g_connection_ref (connection);
1099 closure->object = object;
1100 closure->signame = g_strdup (signame);
1101 return (GClosure*) closure;
1105 dbus_g_signal_closure_finalize (gpointer data,
1108 DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
1110 dbus_g_connection_unref (sigclosure->connection);
1111 g_free (sigclosure->signame);
1115 signal_emitter_marshaller (GClosure *closure,
1117 guint n_param_values,
1118 const GValue *param_values,
1119 gpointer invocation_hint,
1120 gpointer marshal_data)
1122 DBusGSignalClosure *sigclosure;
1123 DBusMessage *signal;
1124 DBusMessageIter iter;
1128 sigclosure = (DBusGSignalClosure *) closure;
1130 g_assert (retval == NULL);
1132 path = _dbus_gobject_get_path (sigclosure->object);
1134 g_assert (path != NULL);
1136 signal = dbus_message_new_signal (path,
1138 sigclosure->signame);
1141 g_error ("out of memory");
1145 dbus_message_iter_init_append (signal, &iter);
1147 /* First argument is the object itself, and we can't marshall that */
1148 for (i = 1; i < n_param_values; i++)
1150 if (!dbus_gvalue_marshal (&iter,
1151 (GValue *) (&(param_values[i]))))
1153 g_warning ("failed to marshal parameter %d for signal %s",
1154 i, sigclosure->signame);
1158 dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
1161 dbus_message_unref (signal);
1165 export_signals (DBusGConnection *connection, GObject *object)
1170 ids = g_signal_list_ids (G_TYPE_FROM_INSTANCE (object), &n_ids);
1174 /* FIXME: recurse to parent types ? */
1175 for (i = 0; i < n_ids; i++)
1180 g_signal_query (ids[i], &query);
1182 if (query.return_type != G_TYPE_NONE)
1184 g_warning("Not exporting signal '%s' as it has a return type %s", query.signal_name, g_type_name (query.return_type));
1185 continue; /* FIXME: these could be listed as methods ? */
1188 closure = dbus_g_signal_closure_new (connection, object, query.signal_name);
1189 g_closure_set_marshal (closure, signal_emitter_marshaller);
1191 g_signal_connect_closure_by_id (object,
1197 g_closure_add_finalize_notifier (closure, NULL,
1198 dbus_g_signal_closure_finalize);
1202 /** @} */ /* end of internals */
1205 * @addtogroup DBusGLib
1210 * Install introspection information about the given object GType
1211 * sufficient to allow methods on the object to be invoked by name.
1212 * The introspection information is normally generated by
1213 * dbus-glib-tool, then this function is called in the
1214 * class_init() for the object class.
1216 * Once introspection information has been installed, instances of the
1217 * object registered with dbus_g_connection_register_g_object() can have
1218 * their methods invoked remotely.
1220 * @param object_type GType for the object
1221 * @param info introspection data generated by dbus-glib-tool
1224 dbus_g_object_type_install_info (GType object_type,
1225 const DBusGObjectInfo *info)
1227 GObjectClass *object_class;
1229 g_return_if_fail (G_TYPE_IS_OBJECT (object_type));
1231 dbus_g_value_types_init ();
1233 object_class = g_type_class_peek (object_type);
1235 g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
1237 g_static_rw_lock_writer_lock (&globals_lock);
1239 if (info_hash == NULL)
1241 info_hash = g_hash_table_new (NULL, NULL); /* direct hash */
1244 g_hash_table_replace (info_hash, object_class, (void*) info);
1246 g_static_rw_lock_writer_unlock (&globals_lock);
1250 unregister_gobject (DBusGConnection *connection, GObject *dead)
1253 path = g_object_steal_data (dead, "dbus_glib_object_path");
1254 dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection), path);
1259 * Registers a GObject at the given path. Properties, methods, and signals
1260 * of the object can then be accessed remotely. Methods are only available
1261 * if method introspection data has been added to the object's class
1262 * with g_object_class_install_info().
1264 * The registration will be cancelled if either the DBusConnection or
1265 * the GObject gets finalized.
1267 * @param connection the D-BUS connection
1268 * @param at_path the path where the object will live (the object's name)
1269 * @param object the object
1272 dbus_g_connection_register_g_object (DBusGConnection *connection,
1273 const char *at_path,
1276 g_return_if_fail (connection != NULL);
1277 g_return_if_fail (at_path != NULL);
1278 g_return_if_fail (G_IS_OBJECT (object));
1280 if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
1282 &gobject_dbus_vtable,
1285 g_error ("Failed to register GObject with DBusConnection");
1289 export_signals (connection, object);
1291 g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
1292 g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
1296 dbus_g_connection_lookup_g_object (DBusGConnection *connection,
1297 const char *at_path)
1300 if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
1309 } DBusGFuncSignature;
1312 funcsig_hash (gconstpointer key)
1314 const DBusGFuncSignature *sig = key;
1319 types = sig->params;
1321 while (*types != G_TYPE_INVALID)
1323 ret += (int) (*types);
1331 funcsig_equal (gconstpointer aval,
1334 const DBusGFuncSignature *a = aval;
1335 const DBusGFuncSignature *b = bval;
1336 const GType *atypes;
1337 const GType *btypes;
1339 if (a->rettype != b->rettype)
1345 while (*atypes != G_TYPE_INVALID)
1347 if (*btypes != *atypes)
1352 if (*btypes != G_TYPE_INVALID)
1359 _dbus_gobject_lookup_marshaller (GType rettype,
1361 const GType *param_types)
1363 GClosureMarshal ret;
1364 DBusGFuncSignature sig;
1366 sig.rettype = rettype;
1367 sig.n_params = n_params;
1368 sig.params = (GType*) param_types;
1370 g_static_rw_lock_reader_lock (&globals_lock);
1373 ret = g_hash_table_lookup (marshal_table, &sig);
1377 g_static_rw_lock_reader_unlock (&globals_lock);
1381 if (rettype == G_TYPE_NONE)
1384 ret = g_cclosure_marshal_VOID__VOID;
1385 else if (n_params == 1)
1387 switch (param_types[0])
1389 case G_TYPE_BOOLEAN:
1390 ret = g_cclosure_marshal_VOID__BOOLEAN;
1393 ret = g_cclosure_marshal_VOID__UCHAR;
1396 ret = g_cclosure_marshal_VOID__INT;
1399 ret = g_cclosure_marshal_VOID__UINT;
1402 ret = g_cclosure_marshal_VOID__DOUBLE;
1405 ret = g_cclosure_marshal_VOID__STRING;
1410 else if (n_params == 3
1411 && param_types[0] == G_TYPE_STRING
1412 && param_types[1] == G_TYPE_STRING
1413 && param_types[2] == G_TYPE_STRING)
1415 ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
1423 * Register a GClosureMarshal to be used for signal invocations.
1424 * This function will not be needed once GLib includes libffi.
1426 * @param rettype a GType for the return type of the function
1427 * @param n_types number of function parameters
1428 * @param param_types a C array of GTypes values
1429 * @param marshaller a GClosureMarshal to be used for invocation
1432 dbus_g_object_register_marshaller (GType rettype,
1434 const GType *param_types,
1435 GClosureMarshal marshaller)
1437 DBusGFuncSignature *sig;
1439 g_static_rw_lock_writer_lock (&globals_lock);
1441 if (marshal_table == NULL)
1442 marshal_table = g_hash_table_new_full (funcsig_hash,
1446 sig = g_new0 (DBusGFuncSignature, 1);
1447 sig->rettype = rettype;
1448 sig->n_params = n_types;
1449 sig->params = g_new (GType, n_types);
1450 memcpy (sig->params, param_types, n_types * sizeof (GType));
1452 g_hash_table_insert (marshal_table, sig, marshaller);
1454 g_static_rw_lock_writer_unlock (&globals_lock);
1458 * Send a return message for a given method invocation, with arguments.
1460 * @param context the method context
1463 dbus_g_method_return (DBusGMethodInvocation *context, ...)
1466 DBusMessageIter iter;
1472 reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
1473 out_sig = method_output_signature_from_object_info (context->object, context->method);
1474 argsig = dbus_gtypes_from_arg_signature (out_sig, FALSE);
1476 dbus_message_iter_init_append (reply, &iter);
1478 va_start (args, context);
1479 for (i = 0; i < argsig->len; i++)
1481 GValue value = {0,};
1483 g_value_init (&value, g_array_index (argsig, GType, i));
1485 G_VALUE_COLLECT (&value, args, 0, &error);
1491 dbus_gvalue_marshal (&iter, &value);
1495 dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
1496 dbus_message_unref (reply);
1498 dbus_g_connection_unref (context->connection);
1499 dbus_g_message_unref (context->message);
1504 * Send a error message for a given method invocation.
1506 * @param context the method context
1507 * @param error the error to send.
1510 dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
1513 reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
1514 dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
1515 dbus_message_unref (reply);
1518 /** @} */ /* end of public API */
1520 const char * _dbus_gobject_get_path (GObject *obj)
1522 return g_object_get_data (obj, "dbus_glib_object_path");
1525 #ifdef DBUS_BUILD_TESTS
1529 * @ingroup DBusGLibInternals
1530 * Unit test for GLib GObject integration ("skeletons")
1531 * @returns #TRUE on success.
1534 _dbus_gobject_test (const char *test_data_dir)
1537 static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
1538 { "SetFoo", "set_foo" },
1540 { "GetFooBar", "get_foo_bar" },
1541 { "Hello", "hello" }
1543 /* Impossible-to-handle cases */
1544 /* { "FrobateUIHandler", "frobate_ui_handler" } */
1548 while (i < (int) G_N_ELEMENTS (name_pairs))
1553 uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
1554 wincaps = uscore_to_wincaps (name_pairs[i].uscore);
1556 if (strcmp (uscore, name_pairs[i].uscore) != 0)
1558 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
1559 name_pairs[i].wincaps, name_pairs[i].uscore,
1564 if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
1566 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
1567 name_pairs[i].uscore, name_pairs[i].wincaps,
1581 #endif /* DBUS_BUILD_TESTS */