00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <config.h>
00026 #include <gobject/gvaluecollector.h>
00027 #include <dbus/dbus-glib.h>
00028 #include <dbus/dbus-glib-lowlevel.h>
00029 #include "dbus-gtest.h"
00030 #include "dbus-gutils.h"
00031 #include "dbus-gobject.h"
00032 #include "dbus-gvalue.h"
00033 #include "dbus-gmarshal.h"
00034 #include "dbus-gvalue-utils.h"
00035 #include <string.h>
00036
00042 typedef struct
00043 {
00044 char *default_iface;
00045 GType code_enum;
00046 } DBusGErrorInfo;
00047
00048 static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
00049 static GHashTable *marshal_table = NULL;
00050 static GData *error_metadata = NULL;
00051
00052 static char*
00053 uscore_to_wincaps (const char *uscore)
00054 {
00055 const char *p;
00056 GString *str;
00057 gboolean last_was_uscore;
00058
00059 last_was_uscore = TRUE;
00060
00061 str = g_string_new (NULL);
00062 p = uscore;
00063 while (*p)
00064 {
00065 if (*p == '-' || *p == '_')
00066 {
00067 last_was_uscore = TRUE;
00068 }
00069 else
00070 {
00071 if (last_was_uscore)
00072 {
00073 g_string_append_c (str, g_ascii_toupper (*p));
00074 last_was_uscore = FALSE;
00075 }
00076 else
00077 g_string_append_c (str, *p);
00078 }
00079 ++p;
00080 }
00081
00082 return g_string_free (str, FALSE);
00083 }
00084
00085 static const char *
00086 string_table_next (const char *table)
00087 {
00088 return (table + (strlen (table) + 1));
00089 }
00090
00091 static const char *
00092 string_table_lookup (const char *table, int index)
00093 {
00094 const char *ret;
00095
00096 ret = table;
00097
00098 while (index--)
00099 ret = string_table_next (ret);
00100
00101 return ret;
00102 }
00103
00104 static const char *
00105 get_method_data (const DBusGObjectInfo *object,
00106 const DBusGMethodInfo *method)
00107 {
00108 return object->data + method->data_offset;
00109 }
00110
00111 static char *
00112 object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
00113 {
00114
00115 return NULL;
00116 }
00117
00118 static char *
00119 object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
00120 {
00121
00122 return NULL;
00123 }
00124
00125 static const char *
00126 method_interface_from_object_info (const DBusGObjectInfo *object,
00127 const DBusGMethodInfo *method)
00128 {
00129 return string_table_lookup (get_method_data (object, method), 0);
00130 }
00131
00132 static const char *
00133 method_name_from_object_info (const DBusGObjectInfo *object,
00134 const DBusGMethodInfo *method)
00135 {
00136 return string_table_lookup (get_method_data (object, method), 1);
00137 }
00138
00139 static const char *
00140 method_arg_info_from_object_info (const DBusGObjectInfo *object,
00141 const DBusGMethodInfo *method)
00142 {
00143 return string_table_lookup (get_method_data (object, method), 3);
00144 }
00145
00146 typedef enum
00147 {
00148 RETVAL_NONE,
00149 RETVAL_NOERROR,
00150 RETVAL_ERROR
00151 } RetvalType;
00152
00153 static const char *
00154 arg_iterate (const char *data,
00155 const char **name,
00156 gboolean *in,
00157 gboolean *constval,
00158 RetvalType *retval,
00159 const char **type)
00160 {
00161 gboolean inarg;
00162
00163 if (name)
00164 *name = data;
00165
00166 data = string_table_next (data);
00167 switch (*data)
00168 {
00169 case 'I':
00170 inarg = TRUE;
00171 break;
00172 case 'O':
00173 inarg = FALSE;
00174 break;
00175 default:
00176 g_warning ("invalid arg direction '%c'", *data);
00177 inarg = FALSE;
00178 break;
00179 }
00180 if (in)
00181 *in = inarg;
00182
00183 if (!inarg)
00184 {
00185 data = string_table_next (data);
00186 switch (*data)
00187 {
00188 case 'F':
00189 if (constval)
00190 *constval = FALSE;
00191 break;
00192 case 'C':
00193 if (constval)
00194 *constval = TRUE;
00195 break;
00196 default:
00197 g_warning ("invalid arg const value '%c'", *data);
00198 break;
00199 }
00200 data = string_table_next (data);
00201 switch (*data)
00202 {
00203 case 'N':
00204 if (retval)
00205 *retval = RETVAL_NONE;
00206 break;
00207 case 'E':
00208 if (retval)
00209 *retval = RETVAL_ERROR;
00210 break;
00211 case 'R':
00212 if (retval)
00213 *retval = RETVAL_NOERROR;
00214 break;
00215 default:
00216 g_warning ("invalid arg ret value '%c'", *data);
00217 break;
00218 }
00219 }
00220 else
00221 {
00222 if (constval)
00223 *constval = FALSE;
00224 if (retval)
00225 *retval = FALSE;
00226 }
00227
00228 data = string_table_next (data);
00229 if (type)
00230 *type = data;
00231
00232 return string_table_next (data);
00233 }
00234
00235 static char *
00236 method_dir_signature_from_object_info (const DBusGObjectInfo *object,
00237 const DBusGMethodInfo *method,
00238 gboolean in)
00239 {
00240 const char *arg;
00241 GString *ret;
00242
00243 arg = method_arg_info_from_object_info (object, method);
00244
00245 ret = g_string_new (NULL);
00246
00247 while (*arg)
00248 {
00249 const char *name;
00250 gboolean arg_in;
00251 const char *type;
00252
00253 arg = arg_iterate (arg, &name, &arg_in, NULL, NULL, &type);
00254
00255 if (arg_in == in)
00256 g_string_append (ret, type);
00257 }
00258
00259 return g_string_free (ret, FALSE);
00260 }
00261
00262 static char *
00263 method_input_signature_from_object_info (const DBusGObjectInfo *object,
00264 const DBusGMethodInfo *method)
00265 {
00266 return method_dir_signature_from_object_info (object, method, TRUE);
00267 }
00268
00269 static char *
00270 method_output_signature_from_object_info (const DBusGObjectInfo *object,
00271 const DBusGMethodInfo *method)
00272 {
00273 return method_dir_signature_from_object_info (object, method, FALSE);
00274 }
00275
00276 static const char *
00277 propsig_iterate (const char *data, const char **iface, const char **name)
00278 {
00279 *iface = data;
00280
00281 data = string_table_next (data);
00282 *name = data;
00283
00284 return string_table_next (data);
00285 }
00286
00287 static GQuark
00288 dbus_g_object_type_dbus_metadata_quark (void)
00289 {
00290 static GQuark quark;
00291
00292 if (!quark)
00293 quark = g_quark_from_static_string ("DBusGObjectTypeDBusMetadataQuark");
00294 return quark;
00295 }
00296
00297 static const DBusGObjectInfo *
00298 lookup_object_info (GObject *object)
00299 {
00300 const DBusGObjectInfo *ret;
00301 GType classtype;
00302
00303 ret = NULL;
00304
00305 for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
00306 {
00307 const DBusGObjectInfo *info;
00308
00309 info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ());
00310
00311 if (info != NULL && info->format_version >= 0)
00312 {
00313 ret = info;
00314 break;
00315 }
00316 }
00317
00318 return ret;
00319 }
00320
00321 static void
00322 gobject_unregister_function (DBusConnection *connection,
00323 void *user_data)
00324 {
00325 GObject *object;
00326
00327 object = G_OBJECT (user_data);
00328
00329
00330
00331 }
00332
00333 typedef struct
00334 {
00335 GString *xml;
00336 GType gtype;
00337 const DBusGObjectInfo *object_info;
00338 } DBusGLibWriteIterfaceData;
00339
00340 typedef struct
00341 {
00342 GSList *methods;
00343 GSList *signals;
00344 GSList *properties;
00345 } DBusGLibWriteInterfaceValues;
00346
00347 static void
00348 write_interface (gpointer key, gpointer val, gpointer user_data)
00349 {
00350 const char *name;
00351 GSList *methods;
00352 GSList *signals;
00353 GSList *properties;
00354 GString *xml;
00355 const DBusGObjectInfo *object_info;
00356 DBusGLibWriteIterfaceData *data;
00357 DBusGLibWriteInterfaceValues *values;
00358
00359 name = key;
00360
00361 values = val;
00362 methods = values->methods;
00363 signals = values->signals;
00364 properties = values->properties;
00365
00366 data = user_data;
00367 xml = data->xml;
00368 object_info = data->object_info;
00369
00370 g_string_append_printf (xml, " <interface name=\"%s\">\n", name);
00371
00372
00373 for (; methods; methods = methods->next)
00374 {
00375 DBusGMethodInfo *method;
00376 method = methods->data;
00377 const char *args;
00378
00379 g_string_append_printf (xml, " <method name=\"%s\">\n",
00380 method_name_from_object_info (object_info, method));
00381
00382 args = method_arg_info_from_object_info (object_info, method);
00383
00384 while (*args)
00385 {
00386 const char *name;
00387 gboolean arg_in;
00388 const char *type;
00389
00390 args = arg_iterate (args, &name, &arg_in, NULL, NULL, &type);
00391
00392
00393 g_string_append_printf (xml, " <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
00394 name, type, arg_in ? "in" : "out");
00395
00396 }
00397 g_string_append (xml, " </method>\n");
00398
00399 }
00400 g_slist_free (values->methods);
00401
00402 for (; signals; signals = signals->next)
00403 {
00404 guint id;
00405 guint arg;
00406 const char *signame;
00407 GSignalQuery query;
00408 char *s;
00409
00410 signame = signals->data;
00411
00412 s = _dbus_gutils_wincaps_to_uscore (signame);
00413
00414 id = g_signal_lookup (s, data->gtype);
00415 g_assert (id != 0);
00416
00417 g_signal_query (id, &query);
00418 g_assert (query.return_type == G_TYPE_NONE);
00419
00420 g_string_append_printf (xml, " <signal name=\"%s\">\n", signame);
00421
00422 for (arg = 0; arg < query.n_params; arg++)
00423 {
00424 char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]);
00425
00426 g_assert (dbus_type != NULL);
00427
00428 g_string_append (xml, " <arg type=\"");
00429 g_string_append (xml, dbus_type);
00430 g_string_append (xml, "\"/>\n");
00431 g_free (dbus_type);
00432 }
00433
00434 g_string_append (xml, " </signal>\n");
00435 g_free (s);
00436 }
00437 g_slist_free (values->signals);
00438
00439 for (; properties; properties = properties->next)
00440 {
00441 const char *propname;
00442 GParamSpec *spec;
00443 char *dbus_type;
00444 gboolean can_set;
00445 gboolean can_get;
00446 char *s;
00447
00448 propname = properties->data;
00449
00450 s = _dbus_gutils_wincaps_to_uscore (spec->name);
00451
00452 spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
00453 g_assert (spec != NULL);
00454 g_free (s);
00455
00456 dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
00457 g_assert (dbus_type != NULL);
00458
00459 can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
00460 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
00461
00462 can_get = (spec->flags & G_PARAM_READABLE) != 0;
00463
00464 if (can_set || can_get)
00465 {
00466 g_string_append_printf (xml, " <property name=\"%s\" ", propname);
00467 g_string_append (xml, "type=\"");
00468 g_string_append (xml, dbus_type);
00469 g_string_append (xml, "\" access=\"");
00470
00471 if (can_set && can_get)
00472 g_string_append (xml, "readwrite");
00473 else if (can_get)
00474 g_string_append (xml, "read");
00475 else
00476 {
00477 g_assert (can_set);
00478 g_string_append (xml, "write");
00479 }
00480
00481 g_string_append (xml, "\"/>\n");
00482 }
00483
00484 g_free (dbus_type);
00485 g_free (s);
00486
00487 g_string_append (xml, " </property>\n");
00488 }
00489 g_slist_free (values->properties);
00490
00491 g_free (values);
00492 g_string_append (xml, " </interface>\n");
00493 }
00494
00495 static DBusGLibWriteInterfaceValues *
00496 lookup_values (GHashTable *interfaces, const char *method_interface)
00497 {
00498 DBusGLibWriteInterfaceValues *values;
00499 if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
00500 {
00501 values = g_new0 (DBusGLibWriteInterfaceValues, 1);
00502 g_hash_table_insert (interfaces, (gpointer) method_interface, values);
00503 }
00504 return values;
00505 }
00506
00507 static void
00508 introspect_interfaces (GObject *object, GString *xml)
00509 {
00510 const DBusGObjectInfo *info;
00511 DBusGLibWriteIterfaceData data;
00512 int i;
00513 GHashTable *interfaces;
00514 DBusGLibWriteInterfaceValues *values;
00515 const char *propsig;
00516
00517 info = lookup_object_info (object);
00518
00519 g_assert (info != NULL);
00520
00521
00522 interfaces = g_hash_table_new (g_str_hash, g_str_equal);
00523 for (i = 0; i < info->n_method_infos; i++)
00524 {
00525 const char *method_name;
00526 const char *method_interface;
00527 const char *method_args;
00528 const DBusGMethodInfo *method;
00529
00530 method = &(info->method_infos[i]);
00531
00532 method_interface = method_interface_from_object_info (info, method);
00533 method_name = method_name_from_object_info (info, method);
00534 method_args = method_arg_info_from_object_info (info, method);
00535
00536 values = lookup_values (interfaces, method_interface);
00537 values->methods = g_slist_prepend (values->methods, (gpointer) method);
00538 }
00539
00540 propsig = info->exported_signals;
00541 while (*propsig)
00542 {
00543 const char *iface;
00544 const char *signame;
00545
00546 propsig = propsig_iterate (propsig, &iface, &signame);
00547
00548 values = lookup_values (interfaces, iface);
00549 values->signals = g_slist_prepend (values->signals, (gpointer) signame);
00550 }
00551
00552 propsig = info->exported_properties;
00553 while (*propsig)
00554 {
00555 const char *iface;
00556 const char *propname;
00557
00558 propsig = propsig_iterate (propsig, &iface, &propname);
00559
00560 values = lookup_values (interfaces, iface);
00561 values->properties = g_slist_prepend (values->properties, (gpointer) propname);
00562 }
00563
00564 memset (&data, 0, sizeof (data));
00565 data.xml = xml;
00566 data.gtype = G_TYPE_FROM_INSTANCE (object);
00567 data.object_info = info;
00568 g_hash_table_foreach (interfaces, write_interface, &data);
00569
00570 g_hash_table_destroy (interfaces);
00571 }
00572
00573 static DBusHandlerResult
00574 handle_introspect (DBusConnection *connection,
00575 DBusMessage *message,
00576 GObject *object)
00577 {
00578 GString *xml;
00579 unsigned int i;
00580 DBusMessage *ret;
00581 char **children;
00582
00583 if (!dbus_connection_list_registered (connection,
00584 dbus_message_get_path (message),
00585 &children))
00586 g_error ("Out of memory");
00587
00588 xml = g_string_new (NULL);
00589
00590 g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
00591
00592 g_string_append (xml, "<node>\n");
00593
00594
00595 g_string_append_printf (xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE);
00596 g_string_append (xml, " <method name=\"Introspect\">\n");
00597 g_string_append_printf (xml, " <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00598 g_string_append (xml, " </method>\n");
00599 g_string_append (xml, " </interface>\n");
00600
00601
00602 g_string_append_printf (xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_PROPERTIES);
00603 g_string_append (xml, " <method name=\"Get\">\n");
00604 g_string_append_printf (xml, " <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00605 g_string_append_printf (xml, " <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00606 g_string_append_printf (xml, " <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00607 g_string_append (xml, " </method>\n");
00608 g_string_append (xml, " <method name=\"Set\">\n");
00609 g_string_append_printf (xml, " <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00610 g_string_append_printf (xml, " <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00611 g_string_append_printf (xml, " <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00612 g_string_append (xml, " </method>\n");
00613 g_string_append (xml, " </interface>\n");
00614
00615 introspect_interfaces (object, xml);
00616
00617
00618 for (i = 0; children[i]; i++)
00619 g_string_append_printf (xml, " <node name=\"%s\"/>\n",
00620 children[i]);
00621
00622
00623 g_string_append (xml, "</node>\n");
00624
00625 ret = dbus_message_new_method_return (message);
00626 if (ret == NULL)
00627 g_error ("Out of memory");
00628
00629 dbus_message_append_args (ret,
00630 DBUS_TYPE_STRING, &xml->str,
00631 DBUS_TYPE_INVALID);
00632
00633 dbus_connection_send (connection, ret, NULL);
00634 dbus_message_unref (ret);
00635
00636 g_string_free (xml, TRUE);
00637
00638 dbus_free_string_array (children);
00639
00640 return DBUS_HANDLER_RESULT_HANDLED;
00641 }
00642
00643 static DBusMessage*
00644 set_object_property (DBusConnection *connection,
00645 DBusMessage *message,
00646 DBusMessageIter *iter,
00647 GObject *object,
00648 GParamSpec *pspec)
00649 {
00650 GValue value = { 0, };
00651 DBusMessage *ret;
00652 DBusMessageIter sub;
00653 DBusGValueMarshalCtx context;
00654
00655 dbus_message_iter_recurse (iter, &sub);
00656
00657 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00658 context.proxy = NULL;
00659
00660 g_value_init (&value, pspec->value_type);
00661 if (dbus_gvalue_demarshal (&context, &sub, &value, NULL))
00662 {
00663 g_object_set_property (object,
00664 pspec->name,
00665 &value);
00666
00667 g_value_unset (&value);
00668
00669 ret = dbus_message_new_method_return (message);
00670 if (ret == NULL)
00671 g_error ("out of memory");
00672 }
00673 else
00674 {
00675 ret = dbus_message_new_error (message,
00676 DBUS_ERROR_INVALID_ARGS,
00677 "Argument's D-BUS type can't be converted to a GType");
00678 if (ret == NULL)
00679 g_error ("out of memory");
00680 }
00681
00682 return ret;
00683 }
00684
00685 static DBusMessage*
00686 get_object_property (DBusConnection *connection,
00687 DBusMessage *message,
00688 GObject *object,
00689 GParamSpec *pspec)
00690 {
00691 GType value_type;
00692 GValue value = {0, };
00693 DBusMessage *ret;
00694 DBusMessageIter iter;
00695
00696 value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
00697
00698 ret = dbus_message_new_method_return (message);
00699 if (ret == NULL)
00700 g_error ("out of memory");
00701
00702 g_value_init (&value, value_type);
00703 g_object_get_property (object, pspec->name, &value);
00704
00705 value_type = G_VALUE_TYPE (&value);
00706
00707 dbus_message_iter_init_append (message, &iter);
00708
00709 if (!dbus_gvalue_marshal (&iter, &value))
00710 {
00711 dbus_message_unref (ret);
00712 ret = dbus_message_new_error (message,
00713 DBUS_ERROR_UNKNOWN_METHOD,
00714 "Can't convert GType of object property to a D-BUS type");
00715 }
00716
00717 return ret;
00718 }
00719
00720 static gboolean
00721 lookup_object_and_method (GObject *object,
00722 DBusMessage *message,
00723 const DBusGObjectInfo **object_ret,
00724 const DBusGMethodInfo **method_ret)
00725 {
00726 const char *interface;
00727 const char *member;
00728 const char *signature;
00729 gboolean ret;
00730 const DBusGObjectInfo *info;
00731 int i;
00732
00733 interface = dbus_message_get_interface (message);
00734 member = dbus_message_get_member (message);
00735 signature = dbus_message_get_signature (message);
00736 ret = FALSE;
00737
00738 info = lookup_object_info (object);
00739 *object_ret = info;
00740
00741 for (i = 0; i < info->n_method_infos; i++)
00742 {
00743 const char *expected_member;
00744 const char *expected_interface;
00745 char *expected_signature;
00746 const DBusGMethodInfo *method;
00747
00748 method = &(info->method_infos[i]);
00749
00750
00751 expected_interface = method_interface_from_object_info (*object_ret, method);
00752 expected_member = method_name_from_object_info (*object_ret, method);
00753 expected_signature = method_input_signature_from_object_info (*object_ret, method);
00754
00755 if ((interface == NULL
00756 || strcmp (expected_interface, interface) == 0)
00757 && strcmp (expected_member, member) == 0
00758 && strcmp (expected_signature, signature) == 0)
00759 {
00760 g_free (expected_signature);
00761 *method_ret = method;
00762 return TRUE;
00763 }
00764 g_free (expected_signature);
00765 }
00766
00767 return ret;
00768 }
00769
00770 static char *
00771 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
00772 const char *msg_interface,
00773 GQuark domain, gint code)
00774 {
00775 const char *domain_str;
00776 const char *code_str;
00777 GString *dbus_error_name;
00778
00779 domain_str = object_error_domain_prefix_from_object_info (object_info);
00780 code_str = object_error_code_from_object_info (object_info, domain, code);
00781
00782 if (!domain_str || !code_str)
00783 {
00784 DBusGErrorInfo *info;
00785
00786 g_static_rw_lock_reader_lock (&globals_lock);
00787
00788 if (error_metadata != NULL)
00789 info = g_datalist_id_get_data (&error_metadata, domain);
00790 else
00791 info = NULL;
00792
00793 g_static_rw_lock_reader_unlock (&globals_lock);
00794
00795 if (info)
00796 {
00797 GEnumValue *value;
00798 GEnumClass *klass;
00799
00800 klass = g_type_class_ref (info->code_enum);
00801 value = g_enum_get_value (klass, code);
00802 g_type_class_unref (klass);
00803
00804 domain_str = info->default_iface;
00805 code_str = value->value_nick;
00806 }
00807 }
00808
00809 if (!domain_str)
00810 domain_str = msg_interface;
00811
00812 if (!domain_str || !code_str)
00813 {
00814
00815 char *domain_from_quark;
00816
00817 dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
00818
00819 domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
00820 g_string_append (dbus_error_name, domain_from_quark);
00821 g_free (domain_from_quark);
00822
00823 g_string_append_printf (dbus_error_name, ".Code%d", code);
00824 }
00825 else
00826 {
00827 dbus_error_name = g_string_new (domain_str);
00828 g_string_append_c (dbus_error_name, '.');
00829 g_string_append (dbus_error_name, code_str);
00830 }
00831
00832 return g_string_free (dbus_error_name, FALSE);
00833 }
00834
00835 static DBusMessage *
00836 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
00837 DBusMessage *message,
00838 GError *error)
00839 {
00840 DBusMessage *reply;
00841
00842 if (!error)
00843 {
00844 char *error_msg;
00845
00846 error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
00847 reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
00848 g_free (error_msg);
00849 }
00850 else
00851 {
00852 if (error->domain == DBUS_GERROR)
00853 reply = dbus_message_new_error (message,
00854 dbus_g_error_get_name (error),
00855 error->message);
00856 else
00857 {
00858 char *error_name;
00859 error_name = gerror_domaincode_to_dbus_error_name (object_info,
00860 dbus_message_get_interface (message),
00861 error->domain, error->code);
00862 reply = dbus_message_new_error (message, error_name, error->message);
00863 g_free (error_name);
00864 }
00865 }
00866 return reply;
00867 }
00868
00873 struct _DBusGMethodInvocation {
00874 DBusGConnection *connection;
00875 DBusGMessage *message;
00876 const DBusGObjectInfo *object;
00877 const DBusGMethodInfo *method;
00878 };
00879
00880 static DBusHandlerResult
00881 invoke_object_method (GObject *object,
00882 const DBusGObjectInfo *object_info,
00883 const DBusGMethodInfo *method,
00884 DBusConnection *connection,
00885 DBusMessage *message)
00886 {
00887 gboolean had_error, call_only;
00888 GError *gerror;
00889 GValueArray *value_array;
00890 GValue return_value = {0,};
00891 GClosure closure;
00892 char *in_signature;
00893 GArray *out_param_values = NULL;
00894 GValueArray *out_param_gvalues = NULL;
00895 int out_param_count;
00896 int out_param_pos, out_param_gvalue_pos;
00897 DBusHandlerResult result;
00898 DBusMessage *reply;
00899 gboolean have_retval;
00900 gboolean retval_signals_error;
00901 gboolean retval_is_synthetic;
00902 gboolean retval_is_constant;
00903 const char *arg_metadata;
00904
00905 gerror = NULL;
00906
00907
00908
00909
00910 if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
00911 call_only = TRUE;
00912 else
00913 call_only = FALSE;
00914
00915 have_retval = FALSE;
00916 retval_signals_error = FALSE;
00917 retval_is_synthetic = FALSE;
00918 retval_is_constant = FALSE;
00919
00920
00921
00922
00923
00924
00925 memset (&closure, 0, sizeof (closure));
00926
00927 in_signature = method_input_signature_from_object_info (object_info, method);
00928
00929
00930 {
00931 GArray *types_array;
00932 guint n_params;
00933 const GType *types;
00934 DBusGValueMarshalCtx context;
00935 GError *error = NULL;
00936
00937 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00938 context.proxy = NULL;
00939
00940 types_array = dbus_gtypes_from_arg_signature (in_signature, FALSE);
00941 n_params = types_array->len;
00942 types = (const GType*) types_array->data;
00943
00944 value_array = dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
00945 if (value_array == NULL)
00946 {
00947 g_free (in_signature);
00948 g_array_free (types_array, TRUE);
00949 reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
00950 dbus_connection_send (connection, reply, NULL);
00951 dbus_message_unref (reply);
00952 g_error_free (error);
00953 return DBUS_HANDLER_RESULT_HANDLED;
00954 }
00955 g_array_free (types_array, TRUE);
00956 }
00957
00958
00959 g_value_array_prepend (value_array, NULL);
00960 g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT);
00961 g_value_set_object (g_value_array_get_nth (value_array, 0), object);
00962
00963 if (call_only)
00964 {
00965 GValue context_value = {0,};
00966 DBusGMethodInvocation *context;
00967 context = g_new (DBusGMethodInvocation, 1);
00968 context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
00969 context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
00970 context->object = object_info;
00971 context->method = method;
00972 g_value_init (&context_value, G_TYPE_POINTER);
00973 g_value_set_pointer (&context_value, context);
00974 g_value_array_append (value_array, &context_value);
00975 }
00976 else
00977 {
00978 RetvalType retval;
00979 gboolean arg_in;
00980 gboolean arg_const;
00981 const char *argsig;
00982
00983 arg_metadata = method_arg_info_from_object_info (object_info, method);
00984
00985
00986 out_param_count = 0;
00987 while (*arg_metadata)
00988 {
00989 arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
00990 if (arg_in)
00991 continue;
00992 if (retval != RETVAL_NONE)
00993 {
00994 DBusSignatureIter tmp_sigiter;
00995
00996 g_assert (!have_retval);
00997 have_retval = TRUE;
00998 retval_is_synthetic = FALSE;
00999
01000 switch (retval)
01001 {
01002 case RETVAL_NONE:
01003 g_assert_not_reached ();
01004 break;
01005 case RETVAL_NOERROR:
01006 retval_signals_error = FALSE;
01007 break;
01008 case RETVAL_ERROR:
01009 retval_signals_error = TRUE;
01010 break;
01011 }
01012
01013 retval_is_constant = arg_const;
01014
01015
01016 dbus_signature_iter_init (&tmp_sigiter, argsig);
01017 g_value_init (&return_value, dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
01018 }
01019 else
01020 {
01021
01022 out_param_count++;
01023 }
01024 }
01025
01026
01027
01028
01029
01030
01031
01032 if (!have_retval)
01033 {
01034 have_retval = TRUE;
01035 retval_is_synthetic = TRUE;
01036 retval_signals_error = TRUE;
01037 g_value_init (&return_value, G_TYPE_BOOLEAN);
01038 }
01039
01040
01041
01042
01043
01044
01045 out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
01046
01047
01048
01049
01050 out_param_gvalues = g_value_array_new (out_param_count);
01051 out_param_pos = 0;
01052 out_param_gvalue_pos = 0;
01053
01054
01055 arg_metadata = method_arg_info_from_object_info (object_info, method);
01056
01057
01058
01059
01060 while (*arg_metadata)
01061 {
01062 GValue value = {0, };
01063 GTypeCValue storage;
01064 DBusSignatureIter tmp_sigiter;
01065 GType current_gtype;
01066
01067 arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
01068
01069 if (arg_in || retval != RETVAL_NONE)
01070 continue;
01071
01072 dbus_signature_iter_init (&tmp_sigiter, argsig);
01073 current_gtype = dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
01074
01075 g_value_init (&value, G_TYPE_POINTER);
01076
01077
01078 if (current_gtype != G_TYPE_VALUE)
01079 {
01080 memset (&storage, 0, sizeof (storage));
01081 g_array_append_val (out_param_values, storage);
01082 g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
01083 out_param_pos++;
01084 }
01085 else
01086 {
01087 g_value_array_append (out_param_gvalues, NULL);
01088 g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
01089 out_param_gvalue_pos++;
01090 }
01091 g_value_array_append (value_array, &value);
01092 }
01093 }
01094
01095
01096 if (retval_signals_error)
01097 {
01098 g_assert (have_retval);
01099 g_value_array_append (value_array, NULL);
01100 g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
01101 g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
01102 }
01103
01104
01105 method->marshaller (&closure, have_retval ? &return_value : NULL,
01106 value_array->n_values,
01107 value_array->values,
01108 NULL, method->function);
01109 if (call_only)
01110 {
01111 result = DBUS_HANDLER_RESULT_HANDLED;
01112 goto done;
01113 }
01114 if (retval_signals_error)
01115 had_error = _dbus_gvalue_signals_error (&return_value);
01116 else
01117 had_error = FALSE;
01118
01119 if (!had_error)
01120 {
01121 DBusMessageIter iter;
01122
01123 reply = dbus_message_new_method_return (message);
01124 if (reply == NULL)
01125 goto nomem;
01126
01127
01128 dbus_message_iter_init_append (reply, &iter);
01129
01130
01131 if (have_retval && !retval_is_synthetic)
01132 {
01133 if (!dbus_gvalue_marshal (&iter, &return_value))
01134 goto nomem;
01135 if (!retval_is_constant)
01136 g_value_unset (&return_value);
01137 }
01138
01139
01140 arg_metadata = method_arg_info_from_object_info (object_info, method);
01141
01142
01143 out_param_pos = 0;
01144 out_param_gvalue_pos = 0;
01145 while (*arg_metadata)
01146 {
01147 GValue gvalue = {0, };
01148 const char *arg_name;
01149 gboolean arg_in;
01150 gboolean constval;
01151 RetvalType retval;
01152 const char *arg_signature;
01153 DBusSignatureIter argsigiter;
01154
01155 do
01156 {
01157
01158
01159 arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
01160 }
01161 while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
01162
01163
01164
01165
01166 if (arg_in || retval != RETVAL_NONE)
01167 break;
01168
01169 dbus_signature_iter_init (&argsigiter, arg_signature);
01170
01171 g_value_init (&gvalue, dbus_gtype_from_signature_iter (&argsigiter, FALSE));
01172 if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
01173 {
01174 if (!dbus_gvalue_take (&gvalue,
01175 &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
01176 g_assert_not_reached ();
01177 out_param_pos++;
01178 }
01179 else
01180 {
01181 g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
01182 out_param_gvalue_pos++;
01183 }
01184
01185 if (!dbus_gvalue_marshal (&iter, &gvalue))
01186 goto nomem;
01187
01188
01189
01190
01191 if (!constval)
01192 g_value_unset (&gvalue);
01193 }
01194 }
01195 else
01196 reply = gerror_to_dbus_error_message (object_info, message, gerror);
01197
01198 if (reply)
01199 {
01200 dbus_connection_send (connection, reply, NULL);
01201 dbus_message_unref (reply);
01202 }
01203
01204 result = DBUS_HANDLER_RESULT_HANDLED;
01205 done:
01206 g_free (in_signature);
01207 if (!call_only)
01208 {
01209 g_array_free (out_param_values, TRUE);
01210 g_value_array_free (out_param_gvalues);
01211 }
01212 g_value_array_free (value_array);
01213 return result;
01214 nomem:
01215 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
01216 goto done;
01217 }
01218
01219 static DBusHandlerResult
01220 gobject_message_function (DBusConnection *connection,
01221 DBusMessage *message,
01222 void *user_data)
01223 {
01224 GParamSpec *pspec;
01225 GObject *object;
01226 gboolean setter;
01227 gboolean getter;
01228 char *s;
01229 const char *wincaps_propname;
01230
01231 DBusMessageIter iter;
01232 const DBusGMethodInfo *method;
01233 const DBusGObjectInfo *object_info;
01234
01235 object = G_OBJECT (user_data);
01236
01237 if (dbus_message_is_method_call (message,
01238 DBUS_INTERFACE_INTROSPECTABLE,
01239 "Introspect"))
01240 return handle_introspect (connection, message, object);
01241
01242
01243 if (lookup_object_and_method (object, message, &object_info, &method))
01244 return invoke_object_method (object, object_info, method, connection, message);
01245
01246
01247
01248
01249 getter = FALSE;
01250 setter = FALSE;
01251 if (dbus_message_is_method_call (message,
01252 DBUS_INTERFACE_PROPERTIES,
01253 "Get"))
01254 getter = TRUE;
01255 else if (dbus_message_is_method_call (message,
01256 DBUS_INTERFACE_PROPERTIES,
01257 "Set"))
01258 setter = TRUE;
01259
01260 if (!(setter || getter))
01261 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01262
01263 dbus_message_iter_init (message, &iter);
01264
01265 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01266 {
01267 g_warning ("Property get or set does not have an interface string as first arg\n");
01268 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01269 }
01270
01271
01272
01273
01274 dbus_message_iter_next (&iter);
01275
01276 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01277 {
01278 g_warning ("Property get or set does not have a property name string as second arg\n");
01279 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01280 }
01281 dbus_message_iter_get_basic (&iter, &wincaps_propname);
01282 dbus_message_iter_next (&iter);
01283
01284 s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
01285
01286 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
01287 s);
01288
01289 g_free (s);
01290
01291 if (pspec != NULL)
01292 {
01293 DBusMessage *ret;
01294
01295 if (setter)
01296 {
01297 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
01298 {
01299 g_warning ("Property set does not have a variant value as third arg\n");
01300 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01301 }
01302
01303 ret = set_object_property (connection, message, &iter,
01304 object, pspec);
01305 dbus_message_iter_next (&iter);
01306 }
01307 else if (getter)
01308 {
01309 ret = get_object_property (connection, message,
01310 object, pspec);
01311 }
01312 else
01313 {
01314 g_assert_not_reached ();
01315 ret = NULL;
01316 }
01317
01318 g_assert (ret != NULL);
01319
01320 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
01321 g_warning ("Property get or set had too many arguments\n");
01322
01323 dbus_connection_send (connection, ret, NULL);
01324 dbus_message_unref (ret);
01325 return DBUS_HANDLER_RESULT_HANDLED;
01326 }
01327
01328 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01329 }
01330
01331 static DBusObjectPathVTable gobject_dbus_vtable = {
01332 gobject_unregister_function,
01333 gobject_message_function,
01334 NULL
01335 };
01336
01337 typedef struct {
01338 GClosure closure;
01339 DBusGConnection *connection;
01340 GObject *object;
01341 const char *signame;
01342 const char *sigiface;
01343 } DBusGSignalClosure;
01344
01345 static GClosure *
01346 dbus_g_signal_closure_new (DBusGConnection *connection,
01347 GObject *object,
01348 const char *signame,
01349 const char *sigiface)
01350 {
01351 DBusGSignalClosure *closure;
01352
01353 closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
01354
01355 closure->connection = dbus_g_connection_ref (connection);
01356 closure->object = object;
01357 closure->signame = signame;
01358 closure->sigiface = sigiface;
01359 return (GClosure*) closure;
01360 }
01361
01362 static void
01363 dbus_g_signal_closure_finalize (gpointer data,
01364 GClosure *closure)
01365 {
01366 DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
01367
01368 dbus_g_connection_unref (sigclosure->connection);
01369 }
01370
01371 static void
01372 signal_emitter_marshaller (GClosure *closure,
01373 GValue *retval,
01374 guint n_param_values,
01375 const GValue *param_values,
01376 gpointer invocation_hint,
01377 gpointer marshal_data)
01378 {
01379 DBusGSignalClosure *sigclosure;
01380 DBusMessage *signal;
01381 DBusMessageIter iter;
01382 guint i;
01383 const char *path;
01384
01385 sigclosure = (DBusGSignalClosure *) closure;
01386
01387 g_assert (retval == NULL);
01388
01389 path = _dbus_gobject_get_path (sigclosure->object);
01390
01391 g_assert (path != NULL);
01392
01393 signal = dbus_message_new_signal (path,
01394 sigclosure->sigiface,
01395 sigclosure->signame);
01396 if (!signal)
01397 {
01398 g_error ("out of memory");
01399 return;
01400 }
01401
01402 dbus_message_iter_init_append (signal, &iter);
01403
01404
01405 for (i = 1; i < n_param_values; i++)
01406 {
01407 if (!dbus_gvalue_marshal (&iter,
01408 (GValue *) (&(param_values[i]))))
01409 {
01410 g_warning ("failed to marshal parameter %d for signal %s",
01411 i, sigclosure->signame);
01412 goto out;
01413 }
01414 }
01415 dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
01416 signal, NULL);
01417 out:
01418 dbus_message_unref (signal);
01419 }
01420
01421 static void
01422 export_signals (DBusGConnection *connection, const DBusGObjectInfo *info, GObject *object)
01423 {
01424 GType gtype;
01425 const char *sigdata;
01426 const char *iface;
01427 const char *signame;
01428
01429 gtype = G_TYPE_FROM_INSTANCE (object);
01430
01431 sigdata = info->exported_signals;
01432
01433 while (*sigdata != '\0')
01434 {
01435 guint id;
01436 GSignalQuery query;
01437 GClosure *closure;
01438 char *s;
01439
01440 sigdata = propsig_iterate (sigdata, &iface, &signame);
01441
01442 s = _dbus_gutils_wincaps_to_uscore (signame);
01443
01444 id = g_signal_lookup (s, gtype);
01445 if (id == 0)
01446 {
01447 g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
01448 s, signame, g_type_name (gtype));
01449 g_free (s);
01450 continue;
01451 }
01452
01453 g_signal_query (id, &query);
01454
01455 if (query.return_type != G_TYPE_NONE)
01456 {
01457 g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"",
01458 s, g_type_name (gtype), g_type_name (query.return_type));
01459 g_free (s);
01460 continue;
01461 }
01462
01463 closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
01464 g_closure_set_marshal (closure, signal_emitter_marshaller);
01465
01466 g_signal_connect_closure_by_id (object,
01467 id,
01468 0,
01469 closure,
01470 FALSE);
01471
01472 g_closure_add_finalize_notifier (closure, NULL,
01473 dbus_g_signal_closure_finalize);
01474 g_free (s);
01475 }
01476 }
01477
01478 #include "dbus-glib-error-switch.h"
01479
01480 void
01481 dbus_set_g_error (GError **gerror,
01482 DBusError *error)
01483 {
01484 int code;
01485
01486 code = dbus_error_to_gerror_code (error->name);
01487 if (code != DBUS_GERROR_REMOTE_EXCEPTION)
01488 g_set_error (gerror, DBUS_GERROR,
01489 code,
01490 "%s",
01491 error->message);
01492 else
01493 g_set_error (gerror, DBUS_GERROR,
01494 code,
01495 "%s%c%s",
01496 error->message,
01497 '\0',
01498 error->name);
01499 }
01500
01501 static void
01502 dbus_g_error_info_free (gpointer p)
01503 {
01504 DBusGErrorInfo *info;
01505
01506 info = p;
01507
01508 g_free (info->default_iface);
01509 g_free (info);
01510 }
01511
01513
01533 void
01534 dbus_g_object_type_install_info (GType object_type,
01535 const DBusGObjectInfo *info)
01536 {
01537 g_return_if_fail (G_TYPE_IS_CLASSED (object_type));
01538
01539 dbus_g_value_types_init ();
01540
01541 g_type_set_qdata (object_type,
01542 dbus_g_object_type_dbus_metadata_quark (),
01543 (gpointer) info);
01544 }
01545
01555 void
01556 dbus_g_error_domain_register (GQuark domain,
01557 const char *default_iface,
01558 GType code_enum)
01559 {
01560 DBusGErrorInfo *info;
01561
01562 g_return_if_fail (g_quark_to_string (domain) != NULL);
01563 g_return_if_fail (code_enum != G_TYPE_INVALID);
01564 g_return_if_fail (G_TYPE_FUNDAMENTAL (code_enum) == G_TYPE_ENUM);
01565
01566 g_static_rw_lock_writer_lock (&globals_lock);
01567
01568 if (error_metadata == NULL)
01569 g_datalist_init (&error_metadata);
01570
01571 info = g_datalist_id_get_data (&error_metadata, domain);
01572
01573 if (info != NULL)
01574 {
01575 g_warning ("Metadata for error domain \"%s\" already registered\n",
01576 g_quark_to_string (domain));
01577 }
01578 else
01579 {
01580 info = g_new0 (DBusGErrorInfo, 1);
01581 info->default_iface = g_strdup (default_iface);
01582 info->code_enum = code_enum;
01583
01584 g_datalist_id_set_data_full (&error_metadata,
01585 domain,
01586 info,
01587 dbus_g_error_info_free);
01588 }
01589
01590 g_static_rw_lock_writer_unlock (&globals_lock);
01591 }
01592
01593 static void
01594 unregister_gobject (DBusGConnection *connection, GObject *dead)
01595 {
01596 char *path;
01597 path = g_object_steal_data (dead, "dbus_glib_object_path");
01598 dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection), path);
01599 g_free (path);
01600 }
01601
01615 void
01616 dbus_g_connection_register_g_object (DBusGConnection *connection,
01617 const char *at_path,
01618 GObject *object)
01619 {
01620 const DBusGObjectInfo *info;
01621 g_return_if_fail (connection != NULL);
01622 g_return_if_fail (at_path != NULL);
01623 g_return_if_fail (G_IS_OBJECT (object));
01624
01625 info = lookup_object_info (object);
01626 if (info == NULL)
01627 {
01628 g_warning ("No introspection data registered for object class \"%s\"",
01629 g_type_name (G_TYPE_FROM_INSTANCE (object)));
01630 return;
01631 }
01632
01633 if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
01634 at_path,
01635 &gobject_dbus_vtable,
01636 object))
01637 {
01638 g_error ("Failed to register GObject with DBusConnection");
01639 return;
01640 }
01641
01642 export_signals (connection, info, object);
01643
01644 g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
01645 g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
01646 }
01647
01648 GObject *
01649 dbus_g_connection_lookup_g_object (DBusGConnection *connection,
01650 const char *at_path)
01651 {
01652 gpointer ret;
01653 if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
01654 return NULL;
01655 return ret;
01656 }
01657
01658 typedef struct {
01659 GType rettype;
01660 guint n_params;
01661 GType *params;
01662 } DBusGFuncSignature;
01663
01664 static guint
01665 funcsig_hash (gconstpointer key)
01666 {
01667 const DBusGFuncSignature *sig = key;
01668 GType *types;
01669 guint ret;
01670 guint i;
01671
01672 ret = sig->rettype;
01673 types = sig->params;
01674
01675 for (i = 0; i < sig->n_params; i++)
01676 {
01677 ret += (int) (*types);
01678 types++;
01679 }
01680
01681 return ret;
01682 }
01683
01684 static gboolean
01685 funcsig_equal (gconstpointer aval,
01686 gconstpointer bval)
01687 {
01688 const DBusGFuncSignature *a = aval;
01689 const DBusGFuncSignature *b = bval;
01690 const GType *atypes;
01691 const GType *btypes;
01692 guint i;
01693
01694 if (a->rettype != b->rettype
01695 || a->n_params != b->n_params)
01696 return FALSE;
01697
01698 atypes = a->params;
01699 btypes = b->params;
01700
01701 for (i = 0; i < a->n_params; i++)
01702 {
01703 if (*btypes != *atypes)
01704 return FALSE;
01705 atypes++;
01706 btypes++;
01707 }
01708
01709 return TRUE;
01710 }
01711
01712 GClosureMarshal
01713 _dbus_gobject_lookup_marshaller (GType rettype,
01714 guint n_params,
01715 const GType *param_types)
01716 {
01717 GClosureMarshal ret;
01718 DBusGFuncSignature sig;
01719 GType *params;
01720 guint i;
01721
01722
01723 rettype = G_TYPE_FUNDAMENTAL (rettype);
01724 params = g_new (GType, n_params);
01725 for (i = 0; i < n_params; i++)
01726 params[i] = G_TYPE_FUNDAMENTAL (param_types[i]);
01727
01728 sig.rettype = rettype;
01729 sig.n_params = n_params;
01730 sig.params = params;
01731
01732 g_static_rw_lock_reader_lock (&globals_lock);
01733
01734 if (marshal_table)
01735 ret = g_hash_table_lookup (marshal_table, &sig);
01736 else
01737 ret = NULL;
01738
01739 g_static_rw_lock_reader_unlock (&globals_lock);
01740
01741 if (ret == NULL)
01742 {
01743 if (rettype == G_TYPE_NONE)
01744 {
01745 if (n_params == 0)
01746 ret = g_cclosure_marshal_VOID__VOID;
01747 else if (n_params == 1)
01748 {
01749 switch (params[0])
01750 {
01751 case G_TYPE_BOOLEAN:
01752 ret = g_cclosure_marshal_VOID__BOOLEAN;
01753 break;
01754 case G_TYPE_UCHAR:
01755 ret = g_cclosure_marshal_VOID__UCHAR;
01756 break;
01757 case G_TYPE_INT:
01758 ret = g_cclosure_marshal_VOID__INT;
01759 break;
01760 case G_TYPE_UINT:
01761 ret = g_cclosure_marshal_VOID__UINT;
01762 break;
01763 case G_TYPE_DOUBLE:
01764 ret = g_cclosure_marshal_VOID__DOUBLE;
01765 break;
01766 case G_TYPE_STRING:
01767 ret = g_cclosure_marshal_VOID__STRING;
01768 break;
01769 case G_TYPE_BOXED:
01770 ret = g_cclosure_marshal_VOID__BOXED;
01771 break;
01772 }
01773 }
01774 else if (n_params == 3
01775 && params[0] == G_TYPE_STRING
01776 && params[1] == G_TYPE_STRING
01777 && params[2] == G_TYPE_STRING)
01778 {
01779 ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
01780 }
01781 }
01782 }
01783
01784 g_free (params);
01785 return ret;
01786 }
01787
01799 void
01800 dbus_g_object_register_marshaller (GClosureMarshal marshaller,
01801 GType rettype,
01802 ...)
01803 {
01804 va_list args;
01805 GArray *types;
01806 GType gtype;
01807
01808 va_start (args, rettype);
01809
01810 types = g_array_new (TRUE, TRUE, sizeof (GType));
01811
01812 while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
01813 g_array_append_val (types, gtype);
01814
01815 dbus_g_object_register_marshaller_array (marshaller, rettype,
01816 types->len, (GType*) types->data);
01817
01818 g_array_free (types, TRUE);
01819 va_end (args);
01820 }
01821
01831 void
01832 dbus_g_object_register_marshaller_array (GClosureMarshal marshaller,
01833 GType rettype,
01834 guint n_types,
01835 const GType* types)
01836 {
01837 DBusGFuncSignature *sig;
01838 guint i;
01839
01840 g_static_rw_lock_writer_lock (&globals_lock);
01841
01842 if (marshal_table == NULL)
01843 marshal_table = g_hash_table_new_full (funcsig_hash,
01844 funcsig_equal,
01845 g_free,
01846 NULL);
01847 sig = g_new0 (DBusGFuncSignature, 1);
01848 sig->rettype = G_TYPE_FUNDAMENTAL (rettype);
01849 sig->n_params = n_types;
01850 sig->params = g_new (GType, n_types);
01851 for (i = 0; i < n_types; i++)
01852 sig->params[i] = G_TYPE_FUNDAMENTAL (types[i]);
01853
01854 g_hash_table_insert (marshal_table, sig, marshaller);
01855
01856 g_static_rw_lock_writer_unlock (&globals_lock);
01857 }
01858
01865 void
01866 dbus_g_method_return (DBusGMethodInvocation *context, ...)
01867 {
01868 DBusMessage *reply;
01869 DBusMessageIter iter;
01870 va_list args;
01871 char *out_sig;
01872 GArray *argsig;
01873 guint i;
01874
01875 reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
01876 out_sig = method_output_signature_from_object_info (context->object, context->method);
01877 argsig = dbus_gtypes_from_arg_signature (out_sig, FALSE);
01878
01879 dbus_message_iter_init_append (reply, &iter);
01880
01881 va_start (args, context);
01882 for (i = 0; i < argsig->len; i++)
01883 {
01884 GValue value = {0,};
01885 char *error;
01886 g_value_init (&value, g_array_index (argsig, GType, i));
01887 error = NULL;
01888 G_VALUE_COLLECT (&value, args, G_VALUE_NOCOPY_CONTENTS, &error);
01889 if (error)
01890 {
01891 g_warning(error);
01892 g_free (error);
01893 }
01894 dbus_gvalue_marshal (&iter, &value);
01895 }
01896 va_end (args);
01897
01898 dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
01899 dbus_message_unref (reply);
01900
01901 dbus_g_connection_unref (context->connection);
01902 dbus_g_message_unref (context->message);
01903 g_free (context);
01904 g_free (out_sig);
01905 }
01906
01914 void
01915 dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
01916 {
01917 DBusMessage *reply;
01918 reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
01919 dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
01920 dbus_message_unref (reply);
01921 g_free (context);
01922 }
01923
01925
01926 const char * _dbus_gobject_get_path (GObject *obj)
01927 {
01928 return g_object_get_data (obj, "dbus_glib_object_path");
01929 }
01930
01931 #ifdef DBUS_BUILD_TESTS
01932 #include <stdlib.h>
01933
01939 gboolean
01940 _dbus_gobject_test (const char *test_data_dir)
01941 {
01942 int i;
01943 static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
01944 { "SetFoo", "set_foo" },
01945 { "Foo", "foo" },
01946 { "GetFooBar", "get_foo_bar" },
01947 { "Hello", "hello" }
01948
01949
01950
01951 };
01952
01953 i = 0;
01954 while (i < (int) G_N_ELEMENTS (name_pairs))
01955 {
01956 char *uscore;
01957 char *wincaps;
01958
01959 uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
01960 wincaps = uscore_to_wincaps (name_pairs[i].uscore);
01961
01962 if (strcmp (uscore, name_pairs[i].uscore) != 0)
01963 {
01964 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
01965 name_pairs[i].wincaps, name_pairs[i].uscore,
01966 uscore);
01967 exit (1);
01968 }
01969
01970 if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
01971 {
01972 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
01973 name_pairs[i].uscore, name_pairs[i].wincaps,
01974 wincaps);
01975 exit (1);
01976 }
01977
01978 g_free (uscore);
01979 g_free (wincaps);
01980
01981 ++i;
01982 }
01983
01984 return TRUE;
01985 }
01986
01987 #endif