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 *marshal_table = NULL;
50 static GData *error_metadata = NULL;
53 uscore_to_wincaps (const char *uscore)
57 gboolean last_was_uscore;
59 last_was_uscore = TRUE;
61 str = g_string_new (NULL);
65 if (*p == '-' || *p == '_')
67 last_was_uscore = TRUE;
73 g_string_append_c (str, g_ascii_toupper (*p));
74 last_was_uscore = FALSE;
77 g_string_append_c (str, *p);
82 return g_string_free (str, FALSE);
86 string_table_next (const char *table)
88 return (table + (strlen (table) + 1));
92 string_table_lookup (const char *table, int index)
99 ret = string_table_next (ret);
105 get_method_data (const DBusGObjectInfo *object,
106 const DBusGMethodInfo *method)
108 return object->data + method->data_offset;
112 object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
119 object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
126 method_interface_from_object_info (const DBusGObjectInfo *object,
127 const DBusGMethodInfo *method)
129 return string_table_lookup (get_method_data (object, method), 0);
133 method_name_from_object_info (const DBusGObjectInfo *object,
134 const DBusGMethodInfo *method)
136 return string_table_lookup (get_method_data (object, method), 1);
140 method_arg_info_from_object_info (const DBusGObjectInfo *object,
141 const DBusGMethodInfo *method)
143 return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
154 arg_iterate (const char *data,
166 data = string_table_next (data);
176 g_warning ("invalid arg direction '%c'", *data);
185 data = string_table_next (data);
197 g_warning ("invalid arg const value '%c'", *data);
200 data = string_table_next (data);
205 *retval = RETVAL_NONE;
209 *retval = RETVAL_ERROR;
213 *retval = RETVAL_NOERROR;
216 g_warning ("invalid arg ret value '%c'", *data);
228 data = string_table_next (data);
232 return string_table_next (data);
236 method_dir_signature_from_object_info (const DBusGObjectInfo *object,
237 const DBusGMethodInfo *method,
243 arg = method_arg_info_from_object_info (object, method);
245 ret = g_string_new (NULL);
253 arg = arg_iterate (arg, &name, &arg_in, NULL, NULL, &type);
256 g_string_append (ret, type);
259 return g_string_free (ret, FALSE);
263 method_input_signature_from_object_info (const DBusGObjectInfo *object,
264 const DBusGMethodInfo *method)
266 return method_dir_signature_from_object_info (object, method, TRUE);
270 method_output_signature_from_object_info (const DBusGObjectInfo *object,
271 const DBusGMethodInfo *method)
273 return method_dir_signature_from_object_info (object, method, FALSE);
277 propsig_iterate (const char *data, const char **iface, const char **name)
281 data = string_table_next (data);
284 return string_table_next (data);
288 dbus_g_object_type_dbus_metadata_quark (void)
293 quark = g_quark_from_static_string ("DBusGObjectTypeDBusMetadataQuark");
297 static const DBusGObjectInfo *
298 lookup_object_info (GObject *object)
300 const DBusGObjectInfo *ret;
305 for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
307 const DBusGObjectInfo *info;
309 info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ());
311 if (info != NULL && info->format_version >= 0)
322 gobject_unregister_function (DBusConnection *connection,
327 object = G_OBJECT (user_data);
337 const DBusGObjectInfo *object_info;
338 } DBusGLibWriteIterfaceData;
345 } DBusGLibWriteInterfaceValues;
348 write_interface (gpointer key, gpointer val, gpointer user_data)
355 const DBusGObjectInfo *object_info;
356 DBusGLibWriteIterfaceData *data;
357 DBusGLibWriteInterfaceValues *values;
362 methods = values->methods;
363 signals = values->signals;
364 properties = values->properties;
368 object_info = data->object_info;
370 g_string_append_printf (xml, " <interface name=\"%s\">\n", name);
372 /* FIXME: recurse to parent types ? */
373 for (; methods; methods = methods->next)
375 DBusGMethodInfo *method;
377 method = methods->data;
379 g_string_append_printf (xml, " <method name=\"%s\">\n",
380 method_name_from_object_info (object_info, method));
382 args = method_arg_info_from_object_info (object_info, method);
390 args = arg_iterate (args, &name, &arg_in, NULL, NULL, &type);
392 /* FIXME - handle container types */
393 g_string_append_printf (xml, " <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
394 name, type, arg_in ? "in" : "out");
397 g_string_append (xml, " </method>\n");
400 g_slist_free (values->methods);
402 for (; signals; signals = signals->next)
410 signame = signals->data;
412 s = _dbus_gutils_wincaps_to_uscore (signame);
414 id = g_signal_lookup (s, data->gtype);
417 g_signal_query (id, &query);
418 g_assert (query.return_type == G_TYPE_NONE);
420 g_string_append_printf (xml, " <signal name=\"%s\">\n", signame);
422 for (arg = 0; arg < query.n_params; arg++)
424 char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]);
426 g_assert (dbus_type != NULL);
428 g_string_append (xml, " <arg type=\"");
429 g_string_append (xml, dbus_type);
430 g_string_append (xml, "\"/>\n");
434 g_string_append (xml, " </signal>\n");
437 g_slist_free (values->signals);
439 for (; properties; properties = properties->next)
441 const char *propname;
448 propname = properties->data;
450 s = _dbus_gutils_wincaps_to_uscore (spec->name);
452 spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
453 g_assert (spec != NULL);
456 dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
457 g_assert (dbus_type != NULL);
459 can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
460 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
462 can_get = (spec->flags & G_PARAM_READABLE) != 0;
464 if (can_set || can_get)
466 g_string_append_printf (xml, " <property name=\"%s\" ", propname);
467 g_string_append (xml, "type=\"");
468 g_string_append (xml, dbus_type);
469 g_string_append (xml, "\" access=\"");
471 if (can_set && can_get)
472 g_string_append (xml, "readwrite");
474 g_string_append (xml, "read");
478 g_string_append (xml, "write");
481 g_string_append (xml, "\"/>\n");
487 g_string_append (xml, " </property>\n");
489 g_slist_free (values->properties);
492 g_string_append (xml, " </interface>\n");
495 static DBusGLibWriteInterfaceValues *
496 lookup_values (GHashTable *interfaces, const char *method_interface)
498 DBusGLibWriteInterfaceValues *values;
499 if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
501 values = g_new0 (DBusGLibWriteInterfaceValues, 1);
502 g_hash_table_insert (interfaces, (gpointer) method_interface, values);
508 introspect_interfaces (GObject *object, GString *xml)
510 const DBusGObjectInfo *info;
511 DBusGLibWriteIterfaceData data;
513 GHashTable *interfaces;
514 DBusGLibWriteInterfaceValues *values;
517 info = lookup_object_info (object);
519 g_assert (info != NULL);
521 /* Gather a list of all interfaces, indexed into their methods */
522 interfaces = g_hash_table_new (g_str_hash, g_str_equal);
523 for (i = 0; i < info->n_method_infos; i++)
525 const char *method_name;
526 const char *method_interface;
527 const char *method_args;
528 const DBusGMethodInfo *method;
530 method = &(info->method_infos[i]);
532 method_interface = method_interface_from_object_info (info, method);
533 method_name = method_name_from_object_info (info, method);
534 method_args = method_arg_info_from_object_info (info, method);
536 values = lookup_values (interfaces, method_interface);
537 values->methods = g_slist_prepend (values->methods, (gpointer) method);
540 propsig = info->exported_signals;
546 propsig = propsig_iterate (propsig, &iface, &signame);
548 values = lookup_values (interfaces, iface);
549 values->signals = g_slist_prepend (values->signals, (gpointer) signame);
552 propsig = info->exported_properties;
556 const char *propname;
558 propsig = propsig_iterate (propsig, &iface, &propname);
560 values = lookup_values (interfaces, iface);
561 values->properties = g_slist_prepend (values->properties, (gpointer) propname);
564 memset (&data, 0, sizeof (data));
566 data.gtype = G_TYPE_FROM_INSTANCE (object);
567 data.object_info = info;
568 g_hash_table_foreach (interfaces, write_interface, &data);
570 g_hash_table_destroy (interfaces);
573 static DBusHandlerResult
574 handle_introspect (DBusConnection *connection,
575 DBusMessage *message,
583 if (!dbus_connection_list_registered (connection,
584 dbus_message_get_path (message),
586 g_error ("Out of memory");
588 xml = g_string_new (NULL);
590 g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
592 g_string_append (xml, "<node>\n");
594 /* We are introspectable, though I guess that was pretty obvious */
595 g_string_append_printf (xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE);
596 g_string_append (xml, " <method name=\"Introspect\">\n");
597 g_string_append_printf (xml, " <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
598 g_string_append (xml, " </method>\n");
599 g_string_append (xml, " </interface>\n");
601 /* We support get/set properties */
602 g_string_append_printf (xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_PROPERTIES);
603 g_string_append (xml, " <method name=\"Get\">\n");
604 g_string_append_printf (xml, " <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
605 g_string_append_printf (xml, " <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
606 g_string_append_printf (xml, " <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
607 g_string_append (xml, " </method>\n");
608 g_string_append (xml, " <method name=\"Set\">\n");
609 g_string_append_printf (xml, " <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
610 g_string_append_printf (xml, " <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
611 g_string_append_printf (xml, " <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
612 g_string_append (xml, " </method>\n");
613 g_string_append (xml, " </interface>\n");
615 introspect_interfaces (object, xml);
617 /* Append child nodes */
618 for (i = 0; children[i]; i++)
619 g_string_append_printf (xml, " <node name=\"%s\"/>\n",
622 /* Close the XML, and send it to the requesting app */
623 g_string_append (xml, "</node>\n");
625 ret = dbus_message_new_method_return (message);
627 g_error ("Out of memory");
629 dbus_message_append_args (ret,
630 DBUS_TYPE_STRING, &xml->str,
633 dbus_connection_send (connection, ret, NULL);
634 dbus_message_unref (ret);
636 g_string_free (xml, TRUE);
638 dbus_free_string_array (children);
640 return DBUS_HANDLER_RESULT_HANDLED;
644 set_object_property (DBusConnection *connection,
645 DBusMessage *message,
646 DBusMessageIter *iter,
650 GValue value = { 0, };
653 DBusGValueMarshalCtx context;
655 dbus_message_iter_recurse (iter, &sub);
657 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
658 context.proxy = NULL;
660 g_value_init (&value, pspec->value_type);
661 if (dbus_gvalue_demarshal (&context, &sub, &value, NULL))
663 g_object_set_property (object,
667 g_value_unset (&value);
669 ret = dbus_message_new_method_return (message);
671 g_error ("out of memory");
675 ret = dbus_message_new_error (message,
676 DBUS_ERROR_INVALID_ARGS,
677 "Argument's D-BUS type can't be converted to a GType");
679 g_error ("out of memory");
686 get_object_property (DBusConnection *connection,
687 DBusMessage *message,
692 GValue value = {0, };
694 DBusMessageIter iter;
696 value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
698 ret = dbus_message_new_method_return (message);
700 g_error ("out of memory");
702 g_value_init (&value, value_type);
703 g_object_get_property (object, pspec->name, &value);
705 value_type = G_VALUE_TYPE (&value);
707 dbus_message_iter_init_append (message, &iter);
709 if (!dbus_gvalue_marshal (&iter, &value))
711 dbus_message_unref (ret);
712 ret = dbus_message_new_error (message,
713 DBUS_ERROR_UNKNOWN_METHOD,
714 "Can't convert GType of object property to a D-BUS type");
721 lookup_object_and_method (GObject *object,
722 DBusMessage *message,
723 const DBusGObjectInfo **object_ret,
724 const DBusGMethodInfo **method_ret)
726 const char *interface;
728 const char *signature;
730 const DBusGObjectInfo *info;
733 interface = dbus_message_get_interface (message);
734 member = dbus_message_get_member (message);
735 signature = dbus_message_get_signature (message);
738 info = lookup_object_info (object);
741 for (i = 0; i < info->n_method_infos; i++)
743 const char *expected_member;
744 const char *expected_interface;
745 char *expected_signature;
746 const DBusGMethodInfo *method;
748 method = &(info->method_infos[i]);
750 /* Check method interface/name and input signature */
751 expected_interface = method_interface_from_object_info (*object_ret, method);
752 expected_member = method_name_from_object_info (*object_ret, method);
753 expected_signature = method_input_signature_from_object_info (*object_ret, method);
755 if ((interface == NULL
756 || strcmp (expected_interface, interface) == 0)
757 && strcmp (expected_member, member) == 0
758 && strcmp (expected_signature, signature) == 0)
760 g_free (expected_signature);
761 *method_ret = method;
764 g_free (expected_signature);
771 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
772 const char *msg_interface,
773 GQuark domain, gint code)
775 const char *domain_str;
776 const char *code_str;
777 GString *dbus_error_name;
779 domain_str = object_error_domain_prefix_from_object_info (object_info);
780 code_str = object_error_code_from_object_info (object_info, domain, code);
782 if (!domain_str || !code_str)
784 DBusGErrorInfo *info;
786 g_static_rw_lock_reader_lock (&globals_lock);
788 if (error_metadata != NULL)
789 info = g_datalist_id_get_data (&error_metadata, domain);
793 g_static_rw_lock_reader_unlock (&globals_lock);
800 klass = g_type_class_ref (info->code_enum);
801 value = g_enum_get_value (klass, code);
802 g_type_class_unref (klass);
804 domain_str = info->default_iface;
805 code_str = value->value_nick;
810 domain_str = msg_interface;
812 if (!domain_str || !code_str)
814 /* If we can't map it sensibly, make up an error name */
815 char *domain_from_quark;
817 dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
819 domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
820 g_string_append (dbus_error_name, domain_from_quark);
821 g_free (domain_from_quark);
823 g_string_append_printf (dbus_error_name, ".Code%d", code);
827 dbus_error_name = g_string_new (domain_str);
828 g_string_append_c (dbus_error_name, '.');
829 g_string_append (dbus_error_name, code_str);
832 return g_string_free (dbus_error_name, FALSE);
836 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
837 DBusMessage *message,
846 error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
847 reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
852 if (error->domain == DBUS_GERROR)
853 reply = dbus_message_new_error (message,
854 dbus_g_error_get_name (error),
859 error_name = gerror_domaincode_to_dbus_error_name (object_info,
860 dbus_message_get_interface (message),
861 error->domain, error->code);
862 reply = dbus_message_new_error (message, error_name, error->message);
870 * The context of an asynchronous method call. See dbus_g_method_return() and
871 * dbus_g_method_return_error().
873 struct _DBusGMethodInvocation {
874 DBusGConnection *connection; /**< The connection */
875 DBusGMessage *message; /**< The message which generated the method call */
876 const DBusGObjectInfo *object; /**< The object the method was called on */
877 const DBusGMethodInfo *method; /**< The method called */
880 static DBusHandlerResult
881 invoke_object_method (GObject *object,
882 const DBusGObjectInfo *object_info,
883 const DBusGMethodInfo *method,
884 DBusConnection *connection,
885 DBusMessage *message)
887 gboolean had_error, call_only;
889 GValueArray *value_array;
890 GValue return_value = {0,};
893 GArray *out_param_values = NULL;
894 GValueArray *out_param_gvalues = NULL;
896 int out_param_pos, out_param_gvalue_pos;
897 DBusHandlerResult result;
899 gboolean have_retval;
900 gboolean retval_signals_error;
901 gboolean retval_is_synthetic;
902 gboolean retval_is_constant;
903 const char *arg_metadata;
907 /* Determine whether or not this method should be invoked in a new
910 if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
916 retval_signals_error = FALSE;
917 retval_is_synthetic = FALSE;
918 retval_is_constant = FALSE;
920 /* This is evil. We do this to work around the fact that
921 * the generated glib marshallers check a flag in the closure object
922 * which we don't care about. We don't need/want to create
923 * a new closure for each invocation.
925 memset (&closure, 0, sizeof (closure));
927 in_signature = method_input_signature_from_object_info (object_info, method);
929 /* Convert method IN parameters to GValueArray */
934 DBusGValueMarshalCtx context;
935 GError *error = NULL;
937 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
938 context.proxy = NULL;
940 types_array = dbus_gtypes_from_arg_signature (in_signature, FALSE);
941 n_params = types_array->len;
942 types = (const GType*) types_array->data;
944 value_array = dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
945 if (value_array == NULL)
947 g_free (in_signature);
948 g_array_free (types_array, TRUE);
949 reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
950 dbus_connection_send (connection, reply, NULL);
951 dbus_message_unref (reply);
952 g_error_free (error);
953 return DBUS_HANDLER_RESULT_HANDLED;
955 g_array_free (types_array, TRUE);
958 /* Prepend object as first argument */
959 g_value_array_prepend (value_array, NULL);
960 g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT);
961 g_value_set_object (g_value_array_get_nth (value_array, 0), object);
965 GValue context_value = {0,};
966 DBusGMethodInvocation *context;
967 context = g_new (DBusGMethodInvocation, 1);
968 context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
969 context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
970 context->object = object_info;
971 context->method = method;
972 g_value_init (&context_value, G_TYPE_POINTER);
973 g_value_set_pointer (&context_value, context);
974 g_value_array_append (value_array, &context_value);
983 arg_metadata = method_arg_info_from_object_info (object_info, method);
985 /* Count number of output parameters, and look for a return value */
987 while (*arg_metadata)
989 arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
992 if (retval != RETVAL_NONE)
994 DBusSignatureIter tmp_sigiter;
995 /* This is the function return value */
996 g_assert (!have_retval);
998 retval_is_synthetic = FALSE;
1003 g_assert_not_reached ();
1005 case RETVAL_NOERROR:
1006 retval_signals_error = FALSE;
1009 retval_signals_error = TRUE;
1013 retval_is_constant = arg_const;
1015 /* Initialize our return GValue with the specified type */
1016 dbus_signature_iter_init (&tmp_sigiter, argsig);
1017 g_value_init (&return_value, dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
1021 /* It's a regular output value */
1026 /* For compatibility, if we haven't found a return value, we assume
1027 * the function returns a gboolean for signalling an error
1028 * (and therefore also takes a GError). We also note that it
1029 * is a "synthetic" return value; i.e. we aren't going to be
1030 * sending it over the bus, it's just to signal an error.
1035 retval_is_synthetic = TRUE;
1036 retval_signals_error = TRUE;
1037 g_value_init (&return_value, G_TYPE_BOOLEAN);
1040 /* Create an array to store the actual values of OUT parameters
1041 * (other than the real function return, if any). Then, create
1042 * a GValue boxed POINTER to each of those values, and append to
1043 * the invocation, so the method can return the OUT parameters.
1045 out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
1047 /* We have a special array of GValues for toplevel GValue return
1050 out_param_gvalues = g_value_array_new (out_param_count);
1052 out_param_gvalue_pos = 0;
1054 /* Reset argument metadata pointer */
1055 arg_metadata = method_arg_info_from_object_info (object_info, method);
1057 /* Iterate over output arguments again, this time allocating space for
1058 * them as appopriate.
1060 while (*arg_metadata)
1062 GValue value = {0, };
1063 GTypeCValue storage;
1064 DBusSignatureIter tmp_sigiter;
1065 GType current_gtype;
1067 arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
1068 /* Skip over input arguments and the return value, if any */
1069 if (arg_in || retval != RETVAL_NONE)
1072 dbus_signature_iter_init (&tmp_sigiter, argsig);
1073 current_gtype = dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
1075 g_value_init (&value, G_TYPE_POINTER);
1077 /* We special case variants to make method invocation a bit nicer */
1078 if (current_gtype != G_TYPE_VALUE)
1080 memset (&storage, 0, sizeof (storage));
1081 g_array_append_val (out_param_values, storage);
1082 g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
1087 g_value_array_append (out_param_gvalues, NULL);
1088 g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
1089 out_param_gvalue_pos++;
1091 g_value_array_append (value_array, &value);
1095 /* Append GError as final argument if necessary */
1096 if (retval_signals_error)
1098 g_assert (have_retval);
1099 g_value_array_append (value_array, NULL);
1100 g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
1101 g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
1104 /* Actually invoke method */
1105 method->marshaller (&closure, have_retval ? &return_value : NULL,
1106 value_array->n_values,
1107 value_array->values,
1108 NULL, method->function);
1111 result = DBUS_HANDLER_RESULT_HANDLED;
1114 if (retval_signals_error)
1115 had_error = _dbus_gvalue_signals_error (&return_value);
1121 DBusMessageIter iter;
1123 reply = dbus_message_new_method_return (message);
1127 /* Append output arguments to reply */
1128 dbus_message_iter_init_append (reply, &iter);
1130 /* First, append the return value, unless it's synthetic */
1131 if (have_retval && !retval_is_synthetic)
1133 if (!dbus_gvalue_marshal (&iter, &return_value))
1135 if (!retval_is_constant)
1136 g_value_unset (&return_value);
1139 /* Grab the argument metadata and iterate over it */
1140 arg_metadata = method_arg_info_from_object_info (object_info, method);
1142 /* Now append any remaining return values */
1144 out_param_gvalue_pos = 0;
1145 while (*arg_metadata)
1147 GValue gvalue = {0, };
1148 const char *arg_name;
1152 const char *arg_signature;
1153 DBusSignatureIter argsigiter;
1157 /* Iterate over only output values; skip over input
1158 arguments and the return value */
1159 arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
1161 while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
1163 /* If the last argument we saw was input or the return
1164 * value, we must be done iterating over output arguments.
1166 if (arg_in || retval != RETVAL_NONE)
1169 dbus_signature_iter_init (&argsigiter, arg_signature);
1171 g_value_init (&gvalue, dbus_gtype_from_signature_iter (&argsigiter, FALSE));
1172 if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
1174 if (!dbus_gvalue_take (&gvalue,
1175 &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
1176 g_assert_not_reached ();
1181 g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
1182 out_param_gvalue_pos++;
1185 if (!dbus_gvalue_marshal (&iter, &gvalue))
1187 /* Here we actually free the allocated value; we
1188 * took ownership of it with dbus_gvalue_take, unless
1189 * an annotation has specified this value as constant.
1192 g_value_unset (&gvalue);
1196 reply = gerror_to_dbus_error_message (object_info, message, gerror);
1200 dbus_connection_send (connection, reply, NULL);
1201 dbus_message_unref (reply);
1204 result = DBUS_HANDLER_RESULT_HANDLED;
1206 g_free (in_signature);
1209 g_array_free (out_param_values, TRUE);
1210 g_value_array_free (out_param_gvalues);
1212 g_value_array_free (value_array);
1215 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
1219 static DBusHandlerResult
1220 gobject_message_function (DBusConnection *connection,
1221 DBusMessage *message,
1229 const char *wincaps_propname;
1230 /* const char *wincaps_propiface; */
1231 DBusMessageIter iter;
1232 const DBusGMethodInfo *method;
1233 const DBusGObjectInfo *object_info;
1235 object = G_OBJECT (user_data);
1237 if (dbus_message_is_method_call (message,
1238 DBUS_INTERFACE_INTROSPECTABLE,
1240 return handle_introspect (connection, message, object);
1242 /* Try the metainfo, which lets us invoke methods */
1243 if (lookup_object_and_method (object, message, &object_info, &method))
1244 return invoke_object_method (object, object_info, method, connection, message);
1246 /* If no metainfo, we can still do properties and signals
1247 * via standard GLib introspection
1251 if (dbus_message_is_method_call (message,
1252 DBUS_INTERFACE_PROPERTIES,
1255 else if (dbus_message_is_method_call (message,
1256 DBUS_INTERFACE_PROPERTIES,
1260 if (!(setter || getter))
1261 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1263 dbus_message_iter_init (message, &iter);
1265 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
1267 g_warning ("Property get or set does not have an interface string as first arg\n");
1268 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1270 /* We never use the interface name; if we did, we'd need to
1271 * remember that it can be empty string for "pick one for me"
1273 /* dbus_message_iter_get_basic (&iter, &wincaps_propiface); */
1274 dbus_message_iter_next (&iter);
1276 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
1278 g_warning ("Property get or set does not have a property name string as second arg\n");
1279 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1281 dbus_message_iter_get_basic (&iter, &wincaps_propname);
1282 dbus_message_iter_next (&iter);
1284 s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
1286 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
1297 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
1299 g_warning ("Property set does not have a variant value as third arg\n");
1300 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1303 ret = set_object_property (connection, message, &iter,
1305 dbus_message_iter_next (&iter);
1309 ret = get_object_property (connection, message,
1314 g_assert_not_reached ();
1318 g_assert (ret != NULL);
1320 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
1321 g_warning ("Property get or set had too many arguments\n");
1323 dbus_connection_send (connection, ret, NULL);
1324 dbus_message_unref (ret);
1325 return DBUS_HANDLER_RESULT_HANDLED;
1328 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1331 static DBusObjectPathVTable gobject_dbus_vtable = {
1332 gobject_unregister_function,
1333 gobject_message_function,
1339 DBusGConnection *connection;
1341 const char *signame;
1342 const char *sigiface;
1343 } DBusGSignalClosure;
1346 dbus_g_signal_closure_new (DBusGConnection *connection,
1348 const char *signame,
1349 const char *sigiface)
1351 DBusGSignalClosure *closure;
1353 closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
1355 closure->connection = dbus_g_connection_ref (connection);
1356 closure->object = object;
1357 closure->signame = signame;
1358 closure->sigiface = sigiface;
1359 return (GClosure*) closure;
1363 dbus_g_signal_closure_finalize (gpointer data,
1366 DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
1368 dbus_g_connection_unref (sigclosure->connection);
1372 signal_emitter_marshaller (GClosure *closure,
1374 guint n_param_values,
1375 const GValue *param_values,
1376 gpointer invocation_hint,
1377 gpointer marshal_data)
1379 DBusGSignalClosure *sigclosure;
1380 DBusMessage *signal;
1381 DBusMessageIter iter;
1385 sigclosure = (DBusGSignalClosure *) closure;
1387 g_assert (retval == NULL);
1389 path = _dbus_gobject_get_path (sigclosure->object);
1391 g_assert (path != NULL);
1393 signal = dbus_message_new_signal (path,
1394 sigclosure->sigiface,
1395 sigclosure->signame);
1398 g_error ("out of memory");
1402 dbus_message_iter_init_append (signal, &iter);
1404 /* First argument is the object itself, and we can't marshall that */
1405 for (i = 1; i < n_param_values; i++)
1407 if (!dbus_gvalue_marshal (&iter,
1408 (GValue *) (&(param_values[i]))))
1410 g_warning ("failed to marshal parameter %d for signal %s",
1411 i, sigclosure->signame);
1415 dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
1418 dbus_message_unref (signal);
1422 export_signals (DBusGConnection *connection, const DBusGObjectInfo *info, GObject *object)
1425 const char *sigdata;
1427 const char *signame;
1429 gtype = G_TYPE_FROM_INSTANCE (object);
1431 sigdata = info->exported_signals;
1433 while (*sigdata != '\0')
1440 sigdata = propsig_iterate (sigdata, &iface, &signame);
1442 s = _dbus_gutils_wincaps_to_uscore (signame);
1444 id = g_signal_lookup (s, gtype);
1447 g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
1448 s, signame, g_type_name (gtype));
1453 g_signal_query (id, &query);
1455 if (query.return_type != G_TYPE_NONE)
1457 g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"",
1458 s, g_type_name (gtype), g_type_name (query.return_type));
1460 continue; /* FIXME: these could be listed as methods ? */
1463 closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
1464 g_closure_set_marshal (closure, signal_emitter_marshaller);
1466 g_signal_connect_closure_by_id (object,
1472 g_closure_add_finalize_notifier (closure, NULL,
1473 dbus_g_signal_closure_finalize);
1478 #include "dbus-glib-error-switch.h"
1481 dbus_set_g_error (GError **gerror,
1486 code = dbus_error_to_gerror_code (error->name);
1487 if (code != DBUS_GERROR_REMOTE_EXCEPTION)
1488 g_set_error (gerror, DBUS_GERROR,
1493 g_set_error (gerror, DBUS_GERROR,
1502 dbus_g_error_info_free (gpointer p)
1504 DBusGErrorInfo *info;
1508 g_free (info->default_iface);
1512 /** @} */ /* end of internals */
1515 * @addtogroup DBusGLib
1520 * Install introspection information about the given object GType
1521 * sufficient to allow methods on the object to be invoked by name.
1522 * The introspection information is normally generated by
1523 * dbus-glib-tool, then this function is called in the
1524 * class_init() for the object class.
1526 * Once introspection information has been installed, instances of the
1527 * object registered with dbus_g_connection_register_g_object() can have
1528 * their methods invoked remotely.
1530 * @param object_type GType for the object
1531 * @param info introspection data generated by dbus-glib-tool
1534 dbus_g_object_type_install_info (GType object_type,
1535 const DBusGObjectInfo *info)
1537 g_return_if_fail (G_TYPE_IS_CLASSED (object_type));
1539 dbus_g_value_types_init ();
1541 g_type_set_qdata (object_type,
1542 dbus_g_object_type_dbus_metadata_quark (),
1547 * Register a GError domain and set of codes with D-BUS. You must
1548 * have created a GEnum for the error codes. This function will not
1549 * be needed with an introspection-capable GLib.
1551 * @param domain the GError domain
1552 * @param default_iface the D-BUS interface used for error values by default, or #NULL
1553 * @param code_enum a GType for a GEnum of the error codes
1556 dbus_g_error_domain_register (GQuark domain,
1557 const char *default_iface,
1560 DBusGErrorInfo *info;
1562 g_return_if_fail (g_quark_to_string (domain) != NULL);
1563 g_return_if_fail (code_enum != G_TYPE_INVALID);
1564 g_return_if_fail (G_TYPE_FUNDAMENTAL (code_enum) == G_TYPE_ENUM);
1566 g_static_rw_lock_writer_lock (&globals_lock);
1568 if (error_metadata == NULL)
1569 g_datalist_init (&error_metadata);
1571 info = g_datalist_id_get_data (&error_metadata, domain);
1575 g_warning ("Metadata for error domain \"%s\" already registered\n",
1576 g_quark_to_string (domain));
1580 info = g_new0 (DBusGErrorInfo, 1);
1581 info->default_iface = g_strdup (default_iface);
1582 info->code_enum = code_enum;
1584 g_datalist_id_set_data_full (&error_metadata,
1587 dbus_g_error_info_free);
1590 g_static_rw_lock_writer_unlock (&globals_lock);
1594 unregister_gobject (DBusGConnection *connection, GObject *dead)
1597 path = g_object_steal_data (dead, "dbus_glib_object_path");
1598 dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection), path);
1603 * Registers a GObject at the given path. Properties, methods, and signals
1604 * of the object can then be accessed remotely. Methods are only available
1605 * if method introspection data has been added to the object's class
1606 * with g_object_class_install_info().
1608 * The registration will be cancelled if either the DBusConnection or
1609 * the GObject gets finalized.
1611 * @param connection the D-BUS connection
1612 * @param at_path the path where the object will live (the object's name)
1613 * @param object the object
1616 dbus_g_connection_register_g_object (DBusGConnection *connection,
1617 const char *at_path,
1620 const DBusGObjectInfo *info;
1621 g_return_if_fail (connection != NULL);
1622 g_return_if_fail (at_path != NULL);
1623 g_return_if_fail (G_IS_OBJECT (object));
1625 info = lookup_object_info (object);
1628 g_warning ("No introspection data registered for object class \"%s\"",
1629 g_type_name (G_TYPE_FROM_INSTANCE (object)));
1633 if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
1635 &gobject_dbus_vtable,
1638 g_error ("Failed to register GObject with DBusConnection");
1642 export_signals (connection, info, object);
1644 g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
1645 g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
1649 dbus_g_connection_lookup_g_object (DBusGConnection *connection,
1650 const char *at_path)
1653 if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
1662 } DBusGFuncSignature;
1665 funcsig_hash (gconstpointer key)
1667 const DBusGFuncSignature *sig = key;
1673 types = sig->params;
1675 for (i = 0; i < sig->n_params; i++)
1677 ret += (int) (*types);
1685 funcsig_equal (gconstpointer aval,
1688 const DBusGFuncSignature *a = aval;
1689 const DBusGFuncSignature *b = bval;
1690 const GType *atypes;
1691 const GType *btypes;
1694 if (a->rettype != b->rettype
1695 || a->n_params != b->n_params)
1701 for (i = 0; i < a->n_params; i++)
1703 if (*btypes != *atypes)
1713 _dbus_gobject_lookup_marshaller (GType rettype,
1715 const GType *param_types)
1717 GClosureMarshal ret;
1718 DBusGFuncSignature sig;
1722 /* Convert to fundamental types */
1723 rettype = G_TYPE_FUNDAMENTAL (rettype);
1724 params = g_new (GType, n_params);
1725 for (i = 0; i < n_params; i++)
1726 params[i] = G_TYPE_FUNDAMENTAL (param_types[i]);
1728 sig.rettype = rettype;
1729 sig.n_params = n_params;
1730 sig.params = params;
1732 g_static_rw_lock_reader_lock (&globals_lock);
1735 ret = g_hash_table_lookup (marshal_table, &sig);
1739 g_static_rw_lock_reader_unlock (&globals_lock);
1743 if (rettype == G_TYPE_NONE)
1746 ret = g_cclosure_marshal_VOID__VOID;
1747 else if (n_params == 1)
1751 case G_TYPE_BOOLEAN:
1752 ret = g_cclosure_marshal_VOID__BOOLEAN;
1755 ret = g_cclosure_marshal_VOID__UCHAR;
1758 ret = g_cclosure_marshal_VOID__INT;
1761 ret = g_cclosure_marshal_VOID__UINT;
1764 ret = g_cclosure_marshal_VOID__DOUBLE;
1767 ret = g_cclosure_marshal_VOID__STRING;
1770 ret = g_cclosure_marshal_VOID__BOXED;
1774 else if (n_params == 3
1775 && params[0] == G_TYPE_STRING
1776 && params[1] == G_TYPE_STRING
1777 && params[2] == G_TYPE_STRING)
1779 ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
1789 * Register a GClosureMarshal to be used for signal invocations,
1790 * giving its return type and a list of parameter types,
1791 * followed by G_TYPE_INVALID.
1793 * This function will not be needed once GLib includes libffi.
1795 * @param marshaller a GClosureMarshal to be used for invocation
1796 * @param rettype a GType for the return type of the function
1797 * @param ... The parameter GTypes, followed by G_TYPE_INVALID
1800 dbus_g_object_register_marshaller (GClosureMarshal marshaller,
1808 va_start (args, rettype);
1810 types = g_array_new (TRUE, TRUE, sizeof (GType));
1812 while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
1813 g_array_append_val (types, gtype);
1815 dbus_g_object_register_marshaller_array (marshaller, rettype,
1816 types->len, (GType*) types->data);
1818 g_array_free (types, TRUE);
1823 * Register a GClosureMarshal to be used for signal invocations.
1824 * See also #dbus_g_object_register_marshaller
1826 * @param marshaller a GClosureMarshal to be used for invocation
1827 * @param rettype a GType for the return type of the function
1828 * @param n_types number of function parameters
1829 * @param types a C array of GTypes values
1832 dbus_g_object_register_marshaller_array (GClosureMarshal marshaller,
1837 DBusGFuncSignature *sig;
1840 g_static_rw_lock_writer_lock (&globals_lock);
1842 if (marshal_table == NULL)
1843 marshal_table = g_hash_table_new_full (funcsig_hash,
1847 sig = g_new0 (DBusGFuncSignature, 1);
1848 sig->rettype = G_TYPE_FUNDAMENTAL (rettype);
1849 sig->n_params = n_types;
1850 sig->params = g_new (GType, n_types);
1851 for (i = 0; i < n_types; i++)
1852 sig->params[i] = G_TYPE_FUNDAMENTAL (types[i]);
1854 g_hash_table_insert (marshal_table, sig, marshaller);
1856 g_static_rw_lock_writer_unlock (&globals_lock);
1860 * Send a return message for a given method invocation, with arguments.
1861 * This function also frees the sending context.
1863 * @param context the method context
1866 dbus_g_method_return (DBusGMethodInvocation *context, ...)
1869 DBusMessageIter iter;
1875 reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
1876 out_sig = method_output_signature_from_object_info (context->object, context->method);
1877 argsig = dbus_gtypes_from_arg_signature (out_sig, FALSE);
1879 dbus_message_iter_init_append (reply, &iter);
1881 va_start (args, context);
1882 for (i = 0; i < argsig->len; i++)
1884 GValue value = {0,};
1886 g_value_init (&value, g_array_index (argsig, GType, i));
1888 G_VALUE_COLLECT (&value, args, G_VALUE_NOCOPY_CONTENTS, &error);
1894 dbus_gvalue_marshal (&iter, &value);
1898 dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
1899 dbus_message_unref (reply);
1901 dbus_g_connection_unref (context->connection);
1902 dbus_g_message_unref (context->message);
1908 * Send a error message for a given method invocation.
1909 * This function also frees the sending context.
1911 * @param context the method context
1912 * @param error the error to send.
1915 dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
1918 reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
1919 dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
1920 dbus_message_unref (reply);
1924 /** @} */ /* end of public API */
1926 const char * _dbus_gobject_get_path (GObject *obj)
1928 return g_object_get_data (obj, "dbus_glib_object_path");
1931 #ifdef DBUS_BUILD_TESTS
1935 * @ingroup DBusGLibInternals
1936 * Unit test for GLib GObject integration ("skeletons")
1937 * @returns #TRUE on success.
1940 _dbus_gobject_test (const char *test_data_dir)
1943 static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
1944 { "SetFoo", "set_foo" },
1946 { "GetFooBar", "get_foo_bar" },
1947 { "Hello", "hello" }
1949 /* Impossible-to-handle cases */
1950 /* { "FrobateUIHandler", "frobate_ui_handler" } */
1954 while (i < (int) G_N_ELEMENTS (name_pairs))
1959 uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
1960 wincaps = uscore_to_wincaps (name_pairs[i].uscore);
1962 if (strcmp (uscore, name_pairs[i].uscore) != 0)
1964 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
1965 name_pairs[i].wincaps, name_pairs[i].uscore,
1970 if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
1972 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
1973 name_pairs[i].uscore, name_pairs[i].wincaps,
1987 #endif /* DBUS_BUILD_TESTS */