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