00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025 #include "dbus-glib.h"
00026 #include "dbus-gtest.h"
00027 #include "dbus-gutils.h"
00028 #include <string.h>
00029
00035 static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT;
00036 static GHashTable *info_hash = NULL;
00037
00038 static char*
00039 wincaps_to_uscore (const char *caps)
00040 {
00041 const char *p;
00042 GString *str;
00043
00044 str = g_string_new (NULL);
00045 p = caps;
00046 while (*p)
00047 {
00048 if (g_ascii_isupper (*p))
00049 {
00050 if (str->len > 0 &&
00051 (str->len < 2 || str->str[str->len-2] != '_'))
00052 g_string_append_c (str, '_');
00053 g_string_append_c (str, g_ascii_tolower (*p));
00054 }
00055 else
00056 {
00057 g_string_append_c (str, *p);
00058 }
00059 ++p;
00060 }
00061
00062 return g_string_free (str, FALSE);
00063 }
00064
00065 static char*
00066 uscore_to_wincaps (const char *uscore)
00067 {
00068 const char *p;
00069 GString *str;
00070 gboolean last_was_uscore;
00071
00072 last_was_uscore = TRUE;
00073
00074 str = g_string_new (NULL);
00075 p = uscore;
00076 while (*p)
00077 {
00078 if (*p == '-' || *p == '_')
00079 {
00080 last_was_uscore = TRUE;
00081 }
00082 else
00083 {
00084 if (last_was_uscore)
00085 {
00086 g_string_append_c (str, g_ascii_toupper (*p));
00087 last_was_uscore = FALSE;
00088 }
00089 else
00090 g_string_append_c (str, *p);
00091 }
00092 ++p;
00093 }
00094
00095 return g_string_free (str, FALSE);
00096 }
00097
00098 static void
00099 gobject_unregister_function (DBusConnection *connection,
00100 void *user_data)
00101 {
00102 GObject *object;
00103
00104 object = G_OBJECT (user_data);
00105
00106
00107
00108 }
00109
00110 static int
00111 gtype_to_dbus_type (GType type)
00112 {
00113 switch (type)
00114 {
00115 case G_TYPE_CHAR:
00116 case G_TYPE_UCHAR:
00117 return DBUS_TYPE_BYTE;
00118
00119 case G_TYPE_BOOLEAN:
00120 return DBUS_TYPE_BOOLEAN;
00121
00122
00123
00124
00125
00126 case G_TYPE_LONG:
00127 case G_TYPE_INT:
00128 return DBUS_TYPE_INT32;
00129 case G_TYPE_ULONG:
00130 case G_TYPE_UINT:
00131 return DBUS_TYPE_UINT32;
00132
00133 case G_TYPE_INT64:
00134 return DBUS_TYPE_INT64;
00135
00136 case G_TYPE_UINT64:
00137 return DBUS_TYPE_UINT64;
00138
00139 case G_TYPE_FLOAT:
00140 case G_TYPE_DOUBLE:
00141 return DBUS_TYPE_DOUBLE;
00142
00143 case G_TYPE_STRING:
00144 return DBUS_TYPE_STRING;
00145
00146 default:
00147 return DBUS_TYPE_INVALID;
00148 }
00149 }
00150
00151 static const char *
00152 dbus_type_to_string (int type)
00153 {
00154 switch (type)
00155 {
00156 case DBUS_TYPE_INVALID:
00157 return "invalid";
00158 case DBUS_TYPE_NIL:
00159 return "nil";
00160 case DBUS_TYPE_BOOLEAN:
00161 return "boolean";
00162 case DBUS_TYPE_INT32:
00163 return "int32";
00164 case DBUS_TYPE_UINT32:
00165 return "uint32";
00166 case DBUS_TYPE_DOUBLE:
00167 return "double";
00168 case DBUS_TYPE_STRING:
00169 return "string";
00170 case DBUS_TYPE_CUSTOM:
00171 return "custom";
00172 case DBUS_TYPE_ARRAY:
00173 return "array";
00174 case DBUS_TYPE_DICT:
00175 return "dict";
00176 default:
00177 return "unknown";
00178 }
00179 }
00180
00181 static DBusHandlerResult
00182 handle_introspect (DBusConnection *connection,
00183 DBusMessage *message,
00184 GObject *object)
00185 {
00186 GString *xml;
00187 GParamSpec **specs;
00188 unsigned int n_specs;
00189 unsigned int i;
00190 GType last_type;
00191 DBusMessage *ret;
00192 char **path;
00193 char **children;
00194
00195 if (!dbus_message_get_path_decomposed (message, &path))
00196 g_error ("Out of memory");
00197
00198 if (!dbus_connection_list_registered (connection, (const char**) path,
00199 &children))
00200 g_error ("Out of memory");
00201
00202 xml = g_string_new (NULL);
00203
00204 g_string_append (xml, "<node>\n");
00205
00206 last_type = G_TYPE_INVALID;
00207
00208 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object),
00209 &n_specs);
00210
00211 i = 0;
00212 while (i < n_specs)
00213 {
00214 GParamSpec *spec = specs[i];
00215 gboolean can_set;
00216 gboolean can_get;
00217 char *s;
00218 int dbus_type;
00219
00220 dbus_type = gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec));
00221 if (dbus_type == DBUS_TYPE_INVALID)
00222 goto next;
00223
00224 if (spec->owner_type != last_type)
00225 {
00226 if (last_type != G_TYPE_INVALID)
00227 g_string_append (xml, " </interface>\n");
00228
00229
00230
00231
00232
00233
00234
00235 g_string_append (xml, " <interface name=\"org.gtk.objects.");
00236 g_string_append (xml, g_type_name (spec->owner_type));
00237 g_string_append (xml, "\">\n");
00238
00239 last_type = spec->owner_type;
00240 }
00241
00242 can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
00243 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
00244
00245 can_get = (spec->flags & G_PARAM_READABLE) != 0;
00246
00247 s = uscore_to_wincaps (spec->name);
00248
00249 if (can_set)
00250 {
00251 g_string_append (xml, " <method name=\"set_");
00252 g_string_append (xml, s);
00253 g_string_append (xml, "\">\n");
00254
00255 g_string_append (xml, " <arg type=\"");
00256 g_string_append (xml, dbus_type_to_string (dbus_type));
00257 g_string_append (xml, "\"/>\n");
00258 }
00259
00260 if (can_get)
00261 {
00262 g_string_append (xml, " <method name=\"get_");
00263 g_string_append (xml, s);
00264 g_string_append (xml, "\">\n");
00265
00266 g_string_append (xml, " <arg type=\"");
00267 g_string_append (xml, dbus_type_to_string (dbus_type));
00268 g_string_append (xml, "\" direction=\"out\"/>\n");
00269 }
00270
00271 g_free (s);
00272
00273 next:
00274 ++i;
00275 }
00276
00277 if (last_type != G_TYPE_INVALID)
00278 g_string_append (xml, " </interface>\n");
00279
00280 g_free (specs);
00281
00282
00283
00284 i = 0;
00285 while (children[i])
00286 {
00287 g_string_append_printf (xml, " <node name=\"%s\"/>\n",
00288 children[i]);
00289 ++i;
00290 }
00291
00292
00293
00294 g_string_append (xml, "</node>\n");
00295
00296 ret = dbus_message_new_method_return (message);
00297 if (ret == NULL)
00298 g_error ("Out of memory");
00299
00300 dbus_message_append_args (message,
00301 DBUS_TYPE_STRING, xml->str,
00302 DBUS_TYPE_INVALID);
00303
00304 dbus_connection_send (connection, message, NULL);
00305 dbus_message_unref (message);
00306
00307 g_string_free (xml, TRUE);
00308
00309 dbus_free_string_array (path);
00310 dbus_free_string_array (children);
00311
00312 return DBUS_HANDLER_RESULT_HANDLED;
00313 }
00314
00315 static DBusMessage*
00316 set_object_property (DBusConnection *connection,
00317 DBusMessage *message,
00318 GObject *object,
00319 GParamSpec *pspec)
00320 {
00321 GValue value;
00322 DBusMessageIter iter;
00323 int type;
00324 gboolean can_set;
00325 DBusMessage *ret;
00326
00327 dbus_message_iter_init (message, &iter);
00328 type = dbus_message_get_type (message);
00329
00330 can_set = TRUE;
00331 switch (type)
00332 {
00333 case DBUS_TYPE_BYTE:
00334 {
00335 unsigned char b;
00336
00337 b = dbus_message_iter_get_byte (&iter);
00338
00339 g_value_init (&value, G_TYPE_UCHAR);
00340
00341 g_value_set_uchar (&value, b);
00342 }
00343 break;
00344 case DBUS_TYPE_BOOLEAN:
00345 {
00346 gboolean b;
00347
00348 b = dbus_message_iter_get_boolean (&iter);
00349
00350 g_value_init (&value, G_TYPE_BOOLEAN);
00351
00352 g_value_set_boolean (&value, b);
00353 }
00354 break;
00355 case DBUS_TYPE_INT32:
00356 {
00357 gint32 i;
00358
00359 i = dbus_message_iter_get_int32 (&iter);
00360
00361 g_value_init (&value, G_TYPE_INT);
00362
00363 g_value_set_int (&value, i);
00364 }
00365 break;
00366 case DBUS_TYPE_UINT32:
00367 {
00368 guint32 i;
00369
00370 i = dbus_message_iter_get_uint32 (&iter);
00371
00372 g_value_init (&value, G_TYPE_UINT);
00373
00374 g_value_set_uint (&value, i);
00375 }
00376 break;
00377 case DBUS_TYPE_INT64:
00378 {
00379 gint64 i;
00380
00381 i = dbus_message_iter_get_int64 (&iter);
00382
00383 g_value_init (&value, G_TYPE_INT64);
00384
00385 g_value_set_int64 (&value, i);
00386 }
00387 break;
00388 case DBUS_TYPE_UINT64:
00389 {
00390 guint64 i;
00391
00392 i = dbus_message_iter_get_uint64 (&iter);
00393
00394 g_value_init (&value, G_TYPE_UINT64);
00395
00396 g_value_set_uint64 (&value, i);
00397 }
00398 break;
00399 case DBUS_TYPE_DOUBLE:
00400 {
00401 double d;
00402
00403 d = dbus_message_iter_get_double (&iter);
00404
00405 g_value_init (&value, G_TYPE_DOUBLE);
00406
00407 g_value_set_double (&value, d);
00408 }
00409 break;
00410 case DBUS_TYPE_STRING:
00411 {
00412 char *s;
00413
00414
00415
00416 s = dbus_message_iter_get_string (&iter);
00417
00418 g_value_init (&value, G_TYPE_STRING);
00419
00420 g_value_set_string (&value, s);
00421
00422 g_free (s);
00423 }
00424 break;
00425
00426
00427
00428
00429
00430 default:
00431 can_set = FALSE;
00432 break;
00433 }
00434
00435
00436
00437
00438
00439
00440
00441 if (can_set)
00442 {
00443 g_object_set_property (object,
00444 pspec->name,
00445 &value);
00446
00447 ret = dbus_message_new_method_return (message);
00448 if (ret == NULL)
00449 g_error ("out of memory");
00450
00451 g_value_unset (&value);
00452 }
00453 else
00454 {
00455 ret = dbus_message_new_error (message,
00456 DBUS_ERROR_INVALID_ARGS,
00457 "Argument's D-BUS type can't be converted to a GType");
00458 if (ret == NULL)
00459 g_error ("out of memory");
00460 }
00461
00462 return ret;
00463 }
00464
00465 static DBusMessage*
00466 get_object_property (DBusConnection *connection,
00467 DBusMessage *message,
00468 GObject *object,
00469 GParamSpec *pspec)
00470 {
00471 GType value_type;
00472 gboolean can_get;
00473 DBusMessage *ret;
00474 GValue value;
00475 DBusMessageIter iter;
00476
00477 value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
00478
00479 ret = dbus_message_new_method_return (message);
00480 if (ret == NULL)
00481 g_error ("out of memory");
00482
00483 can_get = TRUE;
00484 g_value_init (&value, value_type);
00485 g_object_get_property (object, pspec->name, &value);
00486
00487 value_type = G_VALUE_TYPE (&value);
00488
00489 dbus_message_append_iter_init (message, &iter);
00490
00491 switch (value_type)
00492 {
00493 case G_TYPE_CHAR:
00494 dbus_message_iter_append_byte (&iter,
00495 g_value_get_char (&value));
00496 break;
00497 case G_TYPE_UCHAR:
00498 dbus_message_iter_append_byte (&iter,
00499 g_value_get_uchar (&value));
00500 break;
00501 case G_TYPE_BOOLEAN:
00502 dbus_message_iter_append_boolean (&iter,
00503 g_value_get_boolean (&value));
00504 break;
00505 case G_TYPE_INT:
00506 dbus_message_iter_append_int32 (&iter,
00507 g_value_get_int (&value));
00508 break;
00509 case G_TYPE_UINT:
00510 dbus_message_iter_append_uint32 (&iter,
00511 g_value_get_uint (&value));
00512 break;
00513
00514
00515
00516 case G_TYPE_LONG:
00517 dbus_message_iter_append_int32 (&iter,
00518 g_value_get_long (&value));
00519 break;
00520 case G_TYPE_ULONG:
00521 dbus_message_iter_append_uint32 (&iter,
00522 g_value_get_ulong (&value));
00523 break;
00524 case G_TYPE_INT64:
00525 dbus_message_iter_append_int64 (&iter,
00526 g_value_get_int64 (&value));
00527 break;
00528 case G_TYPE_UINT64:
00529 dbus_message_iter_append_uint64 (&iter,
00530 g_value_get_uint64 (&value));
00531 break;
00532 case G_TYPE_FLOAT:
00533 dbus_message_iter_append_double (&iter,
00534 g_value_get_float (&value));
00535 break;
00536 case G_TYPE_DOUBLE:
00537 dbus_message_iter_append_double (&iter,
00538 g_value_get_double (&value));
00539 break;
00540 case G_TYPE_STRING:
00541
00542 dbus_message_iter_append_string (&iter,
00543 g_value_get_string (&value));
00544 break;
00545 default:
00546 can_get = FALSE;
00547 break;
00548 }
00549
00550 g_value_unset (&value);
00551
00552 if (!can_get)
00553 {
00554 dbus_message_unref (ret);
00555 ret = dbus_message_new_error (message,
00556 DBUS_ERROR_UNKNOWN_METHOD,
00557 "Can't convert GType of object property to a D-BUS type");
00558 }
00559
00560 return ret;
00561 }
00562
00563 static DBusHandlerResult
00564 gobject_message_function (DBusConnection *connection,
00565 DBusMessage *message,
00566 void *user_data)
00567 {
00568 const DBusGObjectInfo *info;
00569 GParamSpec *pspec;
00570 GObject *object;
00571 const char *member;
00572 gboolean setter;
00573 gboolean getter;
00574 char *s;
00575
00576 object = G_OBJECT (user_data);
00577
00578 if (dbus_message_is_method_call (message,
00579 DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
00580 "Introspect"))
00581 return handle_introspect (connection, message, object);
00582
00583 member = dbus_message_get_member (message);
00584
00585
00586
00587 g_static_mutex_lock (&info_hash_mutex);
00588
00589
00590
00591 info = g_hash_table_lookup (info_hash,
00592 G_OBJECT_GET_CLASS (object));
00593 g_static_mutex_unlock (&info_hash_mutex);
00594
00595 if (info != NULL)
00596 {
00597
00598
00599
00600 }
00601
00602
00603
00604
00605 setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
00606 getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
00607
00608 if (!(setter || getter))
00609 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00610
00611 s = wincaps_to_uscore (&member[4]);
00612
00613 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
00614 s);
00615
00616 g_free (s);
00617
00618 if (pspec != NULL)
00619 {
00620 DBusMessage *ret;
00621
00622 if (setter)
00623 {
00624 ret = set_object_property (connection, message,
00625 object, pspec);
00626 }
00627 else if (getter)
00628 {
00629 ret = get_object_property (connection, message,
00630 object, pspec);
00631 }
00632 else
00633 {
00634 g_assert_not_reached ();
00635 ret = NULL;
00636 }
00637
00638 g_assert (ret != NULL);
00639
00640 dbus_connection_send (connection, ret, NULL);
00641 dbus_message_unref (ret);
00642 return DBUS_HANDLER_RESULT_HANDLED;
00643 }
00644
00645 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00646 }
00647
00648 static DBusObjectPathVTable gobject_dbus_vtable = {
00649 gobject_unregister_function,
00650 gobject_message_function,
00651 NULL
00652 };
00653
00655
00675 void
00676 dbus_g_object_class_install_info (GObjectClass *object_class,
00677 const DBusGObjectInfo *info)
00678 {
00679 g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
00680
00681 g_static_mutex_lock (&info_hash_mutex);
00682
00683 if (info_hash == NULL)
00684 {
00685 info_hash = g_hash_table_new (NULL, NULL);
00686 }
00687
00688 g_hash_table_replace (info_hash, object_class, (void*) info);
00689
00690 g_static_mutex_unlock (&info_hash_mutex);
00691 }
00692
00706 void
00707 dbus_connection_register_g_object (DBusConnection *connection,
00708 const char *at_path,
00709 GObject *object)
00710 {
00711 char **split;
00712
00713 g_return_if_fail (connection != NULL);
00714 g_return_if_fail (at_path != NULL);
00715 g_return_if_fail (G_IS_OBJECT (object));
00716
00717 split = _dbus_gutils_split_path (at_path);
00718
00719 if (!dbus_connection_register_object_path (connection,
00720 (const char**) split,
00721 &gobject_dbus_vtable,
00722 object))
00723 g_error ("Failed to register GObject with DBusConnection");
00724
00725 g_strfreev (split);
00726
00727
00728
00729
00730 }
00731
00733
00734 #ifdef DBUS_BUILD_TESTS
00735 #include <stdlib.h>
00736
00742 dbus_bool_t
00743 _dbus_gobject_test (const char *test_data_dir)
00744 {
00745 int i;
00746 static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
00747 { "SetFoo", "set_foo" },
00748 { "Foo", "foo" },
00749 { "GetFooBar", "get_foo_bar" },
00750 { "Hello", "hello" }
00751
00752
00753
00754 };
00755
00756 i = 0;
00757 while (i < (int) G_N_ELEMENTS (name_pairs))
00758 {
00759 char *uscore;
00760 char *wincaps;
00761
00762 uscore = wincaps_to_uscore (name_pairs[i].wincaps);
00763 wincaps = uscore_to_wincaps (name_pairs[i].uscore);
00764
00765 if (strcmp (uscore, name_pairs[i].uscore) != 0)
00766 {
00767 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
00768 name_pairs[i].wincaps, name_pairs[i].uscore,
00769 uscore);
00770 exit (1);
00771 }
00772
00773 if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
00774 {
00775 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
00776 name_pairs[i].uscore, name_pairs[i].wincaps,
00777 wincaps);
00778 exit (1);
00779 }
00780
00781 g_free (uscore);
00782 g_free (wincaps);
00783
00784 ++i;
00785 }
00786
00787 return TRUE;
00788 }
00789
00790 #endif