1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gobject.c Exporting a GObject remotely
4 * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
5 * Copyright (C) 2005 Nokia
7 * Licensed under the Academic Free License version 2.1
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.
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.
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
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"
38 * @addtogroup DBusGLibInternals
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;
54 uscore_to_wincaps (const char *uscore)
58 gboolean last_was_uscore;
60 last_was_uscore = TRUE;
62 str = g_string_new (NULL);
66 if (*p == '-' || *p == '_')
68 last_was_uscore = TRUE;
74 g_string_append_c (str, g_ascii_toupper (*p));
75 last_was_uscore = FALSE;
78 g_string_append_c (str, *p);
83 return g_string_free (str, FALSE);
87 string_table_next (const char *table)
89 return (table + (strlen (table) + 1));
93 string_table_lookup (const char *table, int index)
100 ret = string_table_next (ret);
106 get_method_data (const DBusGObjectInfo *object,
107 const DBusGMethodInfo *method)
109 return object->data + method->data_offset;
113 object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
120 object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
127 method_interface_from_object_info (const DBusGObjectInfo *object,
128 const DBusGMethodInfo *method)
130 return string_table_lookup (get_method_data (object, method), 0);
134 method_name_from_object_info (const DBusGObjectInfo *object,
135 const DBusGMethodInfo *method)
137 return string_table_lookup (get_method_data (object, method), 1);
141 method_arg_info_from_object_info (const DBusGObjectInfo *object,
142 const DBusGMethodInfo *method)
144 return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
148 arg_iterate (const char *data, const char **name, gboolean *in,
153 data = string_table_next (data);
163 g_warning ("invalid arg direction");
167 data = string_table_next (data);
170 return string_table_next (data);
174 method_dir_signature_from_object_info (const DBusGObjectInfo *object,
175 const DBusGMethodInfo *method,
181 arg = method_arg_info_from_object_info (object, method);
183 ret = g_string_new (NULL);
191 arg = arg_iterate (arg, &name, &arg_in, &type);
194 g_string_append (ret, type);
197 return g_string_free (ret, FALSE);
201 method_input_signature_from_object_info (const DBusGObjectInfo *object,
202 const DBusGMethodInfo *method)
204 return method_dir_signature_from_object_info (object, method, TRUE);
208 method_output_signature_from_object_info (const DBusGObjectInfo *object,
209 const DBusGMethodInfo *method)
211 return method_dir_signature_from_object_info (object, method, FALSE);
215 propsig_iterate (const char *data, const char **iface, const char **name)
219 data = string_table_next (data);
222 return string_table_next (data);
225 static const DBusGObjectInfo *
226 lookup_object_info (GObject *object)
228 const DBusGObjectInfo *ret;
233 g_static_rw_lock_reader_lock (&globals_lock);
235 if (info_hash == NULL)
238 for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
240 const DBusGObjectInfo *info;
242 info = g_hash_table_lookup (info_hash, g_type_class_peek (classtype));
244 if (info != NULL && info->format_version == 0)
252 g_static_rw_lock_reader_unlock (&globals_lock);
258 gobject_unregister_function (DBusConnection *connection,
263 object = G_OBJECT (user_data);
273 const DBusGObjectInfo *object_info;
274 } DBusGLibWriteIterfaceData;
281 } DBusGLibWriteInterfaceValues;
284 write_interface (gpointer key, gpointer val, gpointer user_data)
291 const DBusGObjectInfo *object_info;
292 DBusGLibWriteIterfaceData *data;
293 DBusGLibWriteInterfaceValues *values;
298 methods = values->methods;
299 signals = values->signals;
300 properties = values->properties;
304 object_info = data->object_info;
306 g_string_append_printf (xml, " <interface name=\"%s\">\n", name);
308 /* FIXME: recurse to parent types ? */
309 for (; methods; methods = methods->next)
311 DBusGMethodInfo *method;
312 method = methods->data;
315 g_string_append_printf (xml, " <method name=\"%s\">\n",
316 method_name_from_object_info (object_info, method));
318 args = method_arg_info_from_object_info (object_info, method);
326 args = arg_iterate (args, &name, &arg_in, &type);
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");
333 g_string_append (xml, " </method>\n");
336 g_slist_free (values->methods);
338 for (; signals; signals = signals->next)
346 signame = signals->data;
348 s = _dbus_gutils_wincaps_to_uscore (signame);
350 id = g_signal_lookup (s, data->gtype);
353 g_signal_query (id, &query);
354 g_assert (query.return_type == G_TYPE_NONE);
356 g_string_append_printf (xml, " <signal name=\"%s\">\n", signame);
358 for (arg = 0; arg < query.n_params; arg++)
360 const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]);
362 g_assert (dbus_type != NULL);
364 g_string_append (xml, " <arg type=\"");
365 g_string_append (xml, dbus_type);
366 g_string_append (xml, "\"/>\n");
369 g_string_append (xml, " </signal>\n");
372 g_slist_free (values->signals);
374 for (; properties; properties = properties->next)
376 const char *propname;
378 const char *dbus_type;
383 propname = properties->data;
385 s = _dbus_gutils_wincaps_to_uscore (spec->name);
387 spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
388 g_assert (spec != NULL);
391 dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
392 g_assert (dbus_type != NULL);
394 can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
395 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
397 can_get = (spec->flags & G_PARAM_READABLE) != 0;
399 if (can_set || can_get)
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=\"");
406 if (can_set && can_get)
407 g_string_append (xml, "readwrite");
409 g_string_append (xml, "read");
413 g_string_append (xml, "write");
416 g_string_append (xml, "\"/>\n");
421 g_string_append (xml, " </property>\n");
423 g_slist_free (values->properties);
426 g_string_append (xml, " </interface>\n");
429 static DBusGLibWriteInterfaceValues *
430 lookup_values (GHashTable *interfaces, const char *method_interface)
432 DBusGLibWriteInterfaceValues *values;
433 if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
435 values = g_new0 (DBusGLibWriteInterfaceValues, 1);
436 g_hash_table_insert (interfaces, (gpointer) method_interface, values);
442 introspect_interfaces (GObject *object, GString *xml)
444 const DBusGObjectInfo *info;
445 DBusGLibWriteIterfaceData data;
447 GHashTable *interfaces;
448 DBusGLibWriteInterfaceValues *values;
451 info = lookup_object_info (object);
453 g_assert (info != NULL);
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++)
459 const char *method_name;
460 const char *method_interface;
461 const char *method_args;
462 const DBusGMethodInfo *method;
464 method = &(info->method_infos[i]);
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);
470 values = lookup_values (interfaces, method_interface);
471 values->methods = g_slist_prepend (values->methods, (gpointer) method);
474 propsig = info->exported_signals;
480 propsig = propsig_iterate (propsig, &iface, &signame);
482 values = lookup_values (interfaces, iface);
483 values->signals = g_slist_prepend (values->signals, (gpointer) signame);
486 propsig = info->exported_properties;
490 const char *propname;
492 propsig = propsig_iterate (propsig, &iface, &propname);
494 values = lookup_values (interfaces, iface);
495 values->properties = g_slist_prepend (values->properties, (gpointer) propname);
498 memset (&data, 0, sizeof (data));
500 data.gtype = G_TYPE_FROM_INSTANCE (object);
501 data.object_info = info;
502 g_hash_table_foreach (interfaces, write_interface, &data);
504 g_hash_table_destroy (interfaces);
507 static DBusHandlerResult
508 handle_introspect (DBusConnection *connection,
509 DBusMessage *message,
517 if (!dbus_connection_list_registered (connection,
518 dbus_message_get_path (message),
520 g_error ("Out of memory");
522 xml = g_string_new (NULL);
524 g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
526 g_string_append (xml, "<node>\n");
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");
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");
549 introspect_interfaces (object, xml);
551 /* Append child nodes */
552 for (i = 0; children[i]; i++)
553 g_string_append_printf (xml, " <node name=\"%s\"/>\n",
556 /* Close the XML, and send it to the requesting app */
557 g_string_append (xml, "</node>\n");
559 ret = dbus_message_new_method_return (message);
561 g_error ("Out of memory");
563 dbus_message_append_args (ret,
564 DBUS_TYPE_STRING, &xml->str,
567 dbus_connection_send (connection, ret, NULL);
568 dbus_message_unref (ret);
570 g_string_free (xml, TRUE);
572 dbus_free_string_array (children);
574 return DBUS_HANDLER_RESULT_HANDLED;
578 set_object_property (DBusConnection *connection,
579 DBusMessage *message,
580 DBusMessageIter *iter,
584 GValue value = { 0, };
587 DBusGValueMarshalCtx context;
589 dbus_message_iter_recurse (iter, &sub);
591 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
592 context.proxy = NULL;
594 g_value_init (&value, pspec->value_type);
595 if (dbus_gvalue_demarshal (&context, &sub, &value, NULL))
597 g_object_set_property (object,
601 g_value_unset (&value);
603 ret = dbus_message_new_method_return (message);
605 g_error ("out of memory");
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");
613 g_error ("out of memory");
620 get_object_property (DBusConnection *connection,
621 DBusMessage *message,
626 GValue value = {0, };
628 DBusMessageIter iter;
630 value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
632 ret = dbus_message_new_method_return (message);
634 g_error ("out of memory");
636 g_value_init (&value, value_type);
637 g_object_get_property (object, pspec->name, &value);
639 value_type = G_VALUE_TYPE (&value);
641 dbus_message_iter_init_append (message, &iter);
643 if (!dbus_gvalue_marshal (&iter, &value))
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");
655 lookup_object_and_method (GObject *object,
656 DBusMessage *message,
657 const DBusGObjectInfo **object_ret,
658 const DBusGMethodInfo **method_ret)
660 const char *interface;
662 const char *signature;
664 const DBusGObjectInfo *info;
667 interface = dbus_message_get_interface (message);
668 member = dbus_message_get_member (message);
669 signature = dbus_message_get_signature (message);
672 info = lookup_object_info (object);
675 for (i = 0; i < info->n_method_infos; i++)
677 const char *expected_member;
678 const char *expected_interface;
679 char *expected_signature;
680 const DBusGMethodInfo *method;
682 method = &(info->method_infos[i]);
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);
689 if ((interface == NULL
690 || strcmp (expected_interface, interface) == 0)
691 && strcmp (expected_member, member) == 0
692 && strcmp (expected_signature, signature) == 0)
694 g_free (expected_signature);
695 *method_ret = method;
698 g_free (expected_signature);
705 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
706 const char *msg_interface,
707 GQuark domain, gint code)
709 const char *domain_str;
710 const char *code_str;
711 GString *dbus_error_name;
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);
716 if (!domain_str || !code_str)
718 DBusGErrorInfo *info;
720 g_static_rw_lock_reader_lock (&globals_lock);
722 if (error_metadata != NULL)
723 info = g_datalist_id_get_data (&error_metadata, domain);
727 g_static_rw_lock_reader_unlock (&globals_lock);
734 klass = g_type_class_ref (info->code_enum);
735 value = g_enum_get_value (klass, code);
736 g_type_class_unref (klass);
738 domain_str = info->default_iface;
739 code_str = value->value_nick;
744 domain_str = msg_interface;
746 if (!domain_str || !code_str)
748 /* If we can't map it sensibly, make up an error name */
749 char *domain_from_quark;
751 dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
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);
757 g_string_append_printf (dbus_error_name, ".Code%d", code);
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);
766 return g_string_free (dbus_error_name, FALSE);
770 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
771 DBusMessage *message,
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);
786 if (error->domain == DBUS_GERROR)
787 reply = dbus_message_new_error (message,
788 dbus_g_error_get_name (error),
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);
804 * The context of an asynchronous method call. See dbus_g_method_return() and
805 * dbus_g_method_return_error().
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 */
814 static DBusHandlerResult
815 invoke_object_method (GObject *object,
816 const DBusGObjectInfo *object_info,
817 const DBusGMethodInfo *method,
818 DBusConnection *connection,
819 DBusMessage *message)
821 gboolean had_error, call_only;
823 GValueArray *value_array;
824 GValue object_value = {0,};
825 GValue error_value = {0,};
826 GValue return_value = {0,};
829 char *out_signature = NULL;
831 DBusSignatureIter out_signature_iter;
832 GArray *out_param_values = NULL;
833 GValueArray *out_param_gvalues = NULL;
835 int out_param_pos, out_param_gvalue_pos;
836 DBusHandlerResult result;
841 if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
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.
851 memset (&closure, 0, sizeof (closure));
853 in_signature = method_input_signature_from_object_info (object_info, method);
855 /* Convert method IN parameters to GValueArray */
860 DBusGValueMarshalCtx context;
861 GError *error = NULL;
863 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
864 context.proxy = NULL;
866 types_array = dbus_gtypes_from_arg_signature (in_signature, FALSE);
867 n_params = types_array->len;
868 types = (const GType*) types_array->data;
870 value_array = dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
871 if (value_array == NULL)
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;
881 g_array_free (types_array, TRUE);
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);
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);
905 out_signature = method_output_signature_from_object_info (object_info, method);
907 /* Count number of output parameters */
908 dbus_signature_iter_init (&out_signature_iter, out_signature);
910 while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
913 dbus_signature_iter_next (&out_signature_iter);
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.
921 out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
923 /* We have a special array of GValues for toplevel GValue return
926 out_param_gvalues = g_value_array_new (out_param_count);
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)
932 GValue value = {0, };
935 g_value_init (&value, G_TYPE_POINTER);
937 /* We special case variants to make method invocation a bit nicer */
938 if (current_type != DBUS_TYPE_VARIANT)
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)));
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++;
951 g_value_array_append (value_array, &value);
952 dbus_signature_iter_next (&out_signature_iter);
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);
960 /* Actually invoke method */
961 g_value_init (&return_value, G_TYPE_BOOLEAN);
962 method->marshaller (&closure, &return_value,
963 value_array->n_values,
965 NULL, method->function);
968 result = DBUS_HANDLER_RESULT_HANDLED;
971 had_error = !g_value_get_boolean (&return_value);
975 DBusMessageIter iter;
977 reply = dbus_message_new_method_return (message);
981 /* Append OUT arguments to reply */
982 dbus_message_iter_init_append (reply, &iter);
983 dbus_signature_iter_init (&out_signature_iter, out_signature);
985 out_param_gvalue_pos = 0;
986 while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
988 GValue gvalue = {0, };
990 g_value_init (&gvalue, dbus_gtype_from_signature_iter (&out_signature_iter, FALSE));
991 if (current_type != DBUS_TYPE_VARIANT)
993 if (!dbus_gvalue_take (&gvalue,
994 &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
995 g_assert_not_reached ();
1000 g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
1001 out_param_gvalue_pos++;
1004 if (!dbus_gvalue_marshal (&iter, &gvalue))
1006 /* Here we actually free the allocated value; we
1007 * took ownership of it with dbus_gvalue_take.
1009 g_value_unset (&gvalue);
1010 dbus_signature_iter_next (&out_signature_iter);
1014 reply = gerror_to_dbus_error_message (object_info, message, gerror);
1018 dbus_connection_send (connection, reply, NULL);
1019 dbus_message_unref (reply);
1022 result = DBUS_HANDLER_RESULT_HANDLED;
1024 g_free (in_signature);
1025 g_free (out_signature);
1028 g_array_free (out_param_values, TRUE);
1029 g_value_array_free (out_param_gvalues);
1030 g_value_unset (&error_value);
1032 g_value_array_free (value_array);
1033 g_value_unset (&return_value);
1036 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
1040 static DBusHandlerResult
1041 gobject_message_function (DBusConnection *connection,
1042 DBusMessage *message,
1050 const char *wincaps_propname;
1051 /* const char *wincaps_propiface; */
1052 DBusMessageIter iter;
1053 const DBusGMethodInfo *method;
1054 const DBusGObjectInfo *object_info;
1056 object = G_OBJECT (user_data);
1058 if (dbus_message_is_method_call (message,
1059 DBUS_INTERFACE_INTROSPECTABLE,
1061 return handle_introspect (connection, message, object);
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);
1067 /* If no metainfo, we can still do properties and signals
1068 * via standard GLib introspection
1072 if (dbus_message_is_method_call (message,
1073 DBUS_INTERFACE_PROPERTIES,
1076 else if (dbus_message_is_method_call (message,
1077 DBUS_INTERFACE_PROPERTIES,
1081 if (!(setter || getter))
1082 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1084 dbus_message_iter_init (message, &iter);
1086 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
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;
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"
1094 /* dbus_message_iter_get_basic (&iter, &wincaps_propiface); */
1095 dbus_message_iter_next (&iter);
1097 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
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;
1102 dbus_message_iter_get_basic (&iter, &wincaps_propname);
1103 dbus_message_iter_next (&iter);
1105 s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
1107 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
1118 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
1120 g_warning ("Property set does not have a variant value as third arg\n");
1121 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1124 ret = set_object_property (connection, message, &iter,
1126 dbus_message_iter_next (&iter);
1130 ret = get_object_property (connection, message,
1135 g_assert_not_reached ();
1139 g_assert (ret != NULL);
1141 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
1142 g_warning ("Property get or set had too many arguments\n");
1144 dbus_connection_send (connection, ret, NULL);
1145 dbus_message_unref (ret);
1146 return DBUS_HANDLER_RESULT_HANDLED;
1149 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1152 static DBusObjectPathVTable gobject_dbus_vtable = {
1153 gobject_unregister_function,
1154 gobject_message_function,
1160 DBusGConnection *connection;
1162 const char *signame;
1163 const char *sigiface;
1164 } DBusGSignalClosure;
1167 dbus_g_signal_closure_new (DBusGConnection *connection,
1169 const char *signame,
1170 const char *sigiface)
1172 DBusGSignalClosure *closure;
1174 closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
1176 closure->connection = dbus_g_connection_ref (connection);
1177 closure->object = object;
1178 closure->signame = signame;
1179 closure->sigiface = sigiface;
1180 return (GClosure*) closure;
1184 dbus_g_signal_closure_finalize (gpointer data,
1187 DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
1189 dbus_g_connection_unref (sigclosure->connection);
1193 signal_emitter_marshaller (GClosure *closure,
1195 guint n_param_values,
1196 const GValue *param_values,
1197 gpointer invocation_hint,
1198 gpointer marshal_data)
1200 DBusGSignalClosure *sigclosure;
1201 DBusMessage *signal;
1202 DBusMessageIter iter;
1206 sigclosure = (DBusGSignalClosure *) closure;
1208 g_assert (retval == NULL);
1210 path = _dbus_gobject_get_path (sigclosure->object);
1212 g_assert (path != NULL);
1214 signal = dbus_message_new_signal (path,
1215 sigclosure->sigiface,
1216 sigclosure->signame);
1219 g_error ("out of memory");
1223 dbus_message_iter_init_append (signal, &iter);
1225 /* First argument is the object itself, and we can't marshall that */
1226 for (i = 1; i < n_param_values; i++)
1228 if (!dbus_gvalue_marshal (&iter,
1229 (GValue *) (&(param_values[i]))))
1231 g_warning ("failed to marshal parameter %d for signal %s",
1232 i, sigclosure->signame);
1236 dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
1239 dbus_message_unref (signal);
1243 export_signals (DBusGConnection *connection, const DBusGObjectInfo *info, GObject *object)
1246 const char *sigdata;
1248 const char *signame;
1250 gtype = G_TYPE_FROM_INSTANCE (object);
1252 sigdata = info->exported_signals;
1254 while (*sigdata != '\0')
1261 sigdata = propsig_iterate (sigdata, &iface, &signame);
1263 s = _dbus_gutils_wincaps_to_uscore (signame);
1265 id = g_signal_lookup (s, gtype);
1268 g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
1269 s, signame, g_type_name (gtype));
1274 g_signal_query (id, &query);
1276 if (query.return_type != G_TYPE_NONE)
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));
1281 continue; /* FIXME: these could be listed as methods ? */
1284 closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
1285 g_closure_set_marshal (closure, signal_emitter_marshaller);
1287 g_signal_connect_closure_by_id (object,
1293 g_closure_add_finalize_notifier (closure, NULL,
1294 dbus_g_signal_closure_finalize);
1299 #include "dbus-glib-error-switch.h"
1302 dbus_set_g_error (GError **gerror,
1307 code = dbus_error_to_gerror_code (error->name);
1308 if (code != DBUS_GERROR_REMOTE_EXCEPTION)
1309 g_set_error (gerror, DBUS_GERROR,
1314 g_set_error (gerror, DBUS_GERROR,
1323 dbus_g_error_info_free (gpointer p)
1325 DBusGErrorInfo *info;
1329 g_free (info->default_iface);
1333 /** @} */ /* end of internals */
1336 * @addtogroup DBusGLib
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.
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.
1351 * @param object_type GType for the object
1352 * @param info introspection data generated by dbus-glib-tool
1355 dbus_g_object_type_install_info (GType object_type,
1356 const DBusGObjectInfo *info)
1358 GObjectClass *object_class;
1360 g_return_if_fail (G_TYPE_IS_OBJECT (object_type));
1362 dbus_g_value_types_init ();
1364 object_class = g_type_class_ref (object_type);
1366 g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
1368 g_static_rw_lock_writer_lock (&globals_lock);
1370 if (info_hash == NULL)
1372 info_hash = g_hash_table_new (NULL, NULL); /* direct hash */
1375 g_hash_table_replace (info_hash, object_class, (void*) info);
1377 g_static_rw_lock_writer_unlock (&globals_lock);
1379 g_type_class_unref (object_class);
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.
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
1392 dbus_g_error_domain_register (GQuark domain,
1393 const char *default_iface,
1396 DBusGErrorInfo *info;
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);
1402 g_static_rw_lock_writer_lock (&globals_lock);
1404 if (error_metadata == NULL)
1405 g_datalist_init (&error_metadata);
1407 info = g_datalist_id_get_data (&error_metadata, domain);
1411 g_warning ("Metadata for error domain \"%s\" already registered\n",
1412 g_quark_to_string (domain));
1416 info = g_new0 (DBusGErrorInfo, 1);
1417 info->default_iface = g_strdup (default_iface);
1418 info->code_enum = code_enum;
1420 g_datalist_id_set_data_full (&error_metadata,
1423 dbus_g_error_info_free);
1426 g_static_rw_lock_writer_unlock (&globals_lock);
1430 unregister_gobject (DBusGConnection *connection, GObject *dead)
1433 path = g_object_steal_data (dead, "dbus_glib_object_path");
1434 dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection), path);
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().
1444 * The registration will be cancelled if either the DBusConnection or
1445 * the GObject gets finalized.
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
1452 dbus_g_connection_register_g_object (DBusGConnection *connection,
1453 const char *at_path,
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));
1461 info = lookup_object_info (object);
1464 g_warning ("No introspection data registered for object class \"%s\"",
1465 g_type_name (G_TYPE_FROM_INSTANCE (object)));
1469 if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
1471 &gobject_dbus_vtable,
1474 g_error ("Failed to register GObject with DBusConnection");
1478 export_signals (connection, info, object);
1480 g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
1481 g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
1485 dbus_g_connection_lookup_g_object (DBusGConnection *connection,
1486 const char *at_path)
1489 if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
1498 } DBusGFuncSignature;
1501 funcsig_hash (gconstpointer key)
1503 const DBusGFuncSignature *sig = key;
1509 types = sig->params;
1511 for (i = 0; i < sig->n_params; i++)
1513 ret += (int) (*types);
1521 funcsig_equal (gconstpointer aval,
1524 const DBusGFuncSignature *a = aval;
1525 const DBusGFuncSignature *b = bval;
1526 const GType *atypes;
1527 const GType *btypes;
1530 if (a->rettype != b->rettype
1531 || a->n_params != b->n_params)
1537 for (i = 0; i < a->n_params; i++)
1539 if (*btypes != *atypes)
1549 _dbus_gobject_lookup_marshaller (GType rettype,
1551 const GType *param_types)
1553 GClosureMarshal ret;
1554 DBusGFuncSignature sig;
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]);
1564 sig.rettype = rettype;
1565 sig.n_params = n_params;
1566 sig.params = params;
1568 g_static_rw_lock_reader_lock (&globals_lock);
1571 ret = g_hash_table_lookup (marshal_table, &sig);
1575 g_static_rw_lock_reader_unlock (&globals_lock);
1579 if (rettype == G_TYPE_NONE)
1582 ret = g_cclosure_marshal_VOID__VOID;
1583 else if (n_params == 1)
1587 case G_TYPE_BOOLEAN:
1588 ret = g_cclosure_marshal_VOID__BOOLEAN;
1591 ret = g_cclosure_marshal_VOID__UCHAR;
1594 ret = g_cclosure_marshal_VOID__INT;
1597 ret = g_cclosure_marshal_VOID__UINT;
1600 ret = g_cclosure_marshal_VOID__DOUBLE;
1603 ret = g_cclosure_marshal_VOID__STRING;
1606 ret = g_cclosure_marshal_VOID__BOXED;
1610 else if (n_params == 3
1611 && params[0] == G_TYPE_STRING
1612 && params[1] == G_TYPE_STRING
1613 && params[2] == G_TYPE_STRING)
1615 ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
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.
1629 * This function will not be needed once GLib includes libffi.
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
1636 dbus_g_object_register_marshaller (GClosureMarshal marshaller,
1644 va_start (args, rettype);
1646 types = g_array_new (TRUE, TRUE, sizeof (GType));
1648 while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
1649 g_array_append_val (types, gtype);
1651 dbus_g_object_register_marshaller_array (marshaller, rettype,
1652 types->len, (GType*) types->data);
1654 g_array_free (types, TRUE);
1659 * Register a GClosureMarshal to be used for signal invocations.
1660 * See also #dbus_g_object_register_marshaller
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
1668 dbus_g_object_register_marshaller_array (GClosureMarshal marshaller,
1673 DBusGFuncSignature *sig;
1676 g_static_rw_lock_writer_lock (&globals_lock);
1678 if (marshal_table == NULL)
1679 marshal_table = g_hash_table_new_full (funcsig_hash,
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]);
1690 g_hash_table_insert (marshal_table, sig, marshaller);
1692 g_static_rw_lock_writer_unlock (&globals_lock);
1696 * Send a return message for a given method invocation, with arguments.
1697 * This function also frees the sending context.
1699 * @param context the method context
1702 dbus_g_method_return (DBusGMethodInvocation *context, ...)
1705 DBusMessageIter iter;
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);
1715 dbus_message_iter_init_append (reply, &iter);
1717 va_start (args, context);
1718 for (i = 0; i < argsig->len; i++)
1720 GValue value = {0,};
1722 g_value_init (&value, g_array_index (argsig, GType, i));
1724 G_VALUE_COLLECT (&value, args, G_VALUE_NOCOPY_CONTENTS, &error);
1730 dbus_gvalue_marshal (&iter, &value);
1734 dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
1735 dbus_message_unref (reply);
1737 dbus_g_connection_unref (context->connection);
1738 dbus_g_message_unref (context->message);
1744 * Send a error message for a given method invocation.
1745 * This function also frees the sending context.
1747 * @param context the method context
1748 * @param error the error to send.
1751 dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
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);
1760 /** @} */ /* end of public API */
1762 const char * _dbus_gobject_get_path (GObject *obj)
1764 return g_object_get_data (obj, "dbus_glib_object_path");
1767 #ifdef DBUS_BUILD_TESTS
1771 * @ingroup DBusGLibInternals
1772 * Unit test for GLib GObject integration ("skeletons")
1773 * @returns #TRUE on success.
1776 _dbus_gobject_test (const char *test_data_dir)
1779 static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
1780 { "SetFoo", "set_foo" },
1782 { "GetFooBar", "get_foo_bar" },
1783 { "Hello", "hello" }
1785 /* Impossible-to-handle cases */
1786 /* { "FrobateUIHandler", "frobate_ui_handler" } */
1790 while (i < (int) G_N_ELEMENTS (name_pairs))
1795 uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
1796 wincaps = uscore_to_wincaps (name_pairs[i].uscore);
1798 if (strcmp (uscore, name_pairs[i].uscore) != 0)
1800 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
1801 name_pairs[i].wincaps, name_pairs[i].uscore,
1806 if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
1808 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
1809 name_pairs[i].uscore, name_pairs[i].wincaps,
1823 #endif /* DBUS_BUILD_TESTS */