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 "dbus-gvalue.h"
00029 #include <string.h>
00030
00036 static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT;
00037 static GHashTable *info_hash = NULL;
00038
00039 static char*
00040 wincaps_to_uscore (const char *caps)
00041 {
00042 const char *p;
00043 GString *str;
00044
00045 str = g_string_new (NULL);
00046 p = caps;
00047 while (*p)
00048 {
00049 if (g_ascii_isupper (*p))
00050 {
00051 if (str->len > 0 &&
00052 (str->len < 2 || str->str[str->len-2] != '_'))
00053 g_string_append_c (str, '_');
00054 g_string_append_c (str, g_ascii_tolower (*p));
00055 }
00056 else
00057 {
00058 g_string_append_c (str, *p);
00059 }
00060 ++p;
00061 }
00062
00063 return g_string_free (str, FALSE);
00064 }
00065
00066 static char*
00067 uscore_to_wincaps (const char *uscore)
00068 {
00069 const char *p;
00070 GString *str;
00071 gboolean last_was_uscore;
00072
00073 last_was_uscore = TRUE;
00074
00075 str = g_string_new (NULL);
00076 p = uscore;
00077 while (*p)
00078 {
00079 if (*p == '-' || *p == '_')
00080 {
00081 last_was_uscore = TRUE;
00082 }
00083 else
00084 {
00085 if (last_was_uscore)
00086 {
00087 g_string_append_c (str, g_ascii_toupper (*p));
00088 last_was_uscore = FALSE;
00089 }
00090 else
00091 g_string_append_c (str, *p);
00092 }
00093 ++p;
00094 }
00095
00096 return g_string_free (str, FALSE);
00097 }
00098
00099 static void
00100 gobject_unregister_function (DBusConnection *connection,
00101 void *user_data)
00102 {
00103 GObject *object;
00104
00105 object = G_OBJECT (user_data);
00106
00107
00108
00109 }
00110
00111 static int
00112 gtype_to_dbus_type (GType type)
00113 {
00114 switch (type)
00115 {
00116 case G_TYPE_CHAR:
00117 case G_TYPE_UCHAR:
00118 return DBUS_TYPE_BYTE;
00119
00120 case G_TYPE_BOOLEAN:
00121 return DBUS_TYPE_BOOLEAN;
00122
00123
00124
00125
00126
00127 case G_TYPE_LONG:
00128 case G_TYPE_INT:
00129 return DBUS_TYPE_INT32;
00130 case G_TYPE_ULONG:
00131 case G_TYPE_UINT:
00132 return DBUS_TYPE_UINT32;
00133
00134 case G_TYPE_INT64:
00135 return DBUS_TYPE_INT64;
00136
00137 case G_TYPE_UINT64:
00138 return DBUS_TYPE_UINT64;
00139
00140 case G_TYPE_FLOAT:
00141 case G_TYPE_DOUBLE:
00142 return DBUS_TYPE_DOUBLE;
00143
00144 case G_TYPE_STRING:
00145 return DBUS_TYPE_STRING;
00146
00147 default:
00148 return DBUS_TYPE_INVALID;
00149 }
00150 }
00151
00152 static void
00153 introspect_properties (GObject *object, GString *xml)
00154 {
00155 unsigned int i;
00156 unsigned int n_specs;
00157 GType last_type;
00158 GParamSpec **specs;
00159
00160 last_type = G_TYPE_INVALID;
00161 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object),
00162 &n_specs);
00163
00164 for (i = 0; i < n_specs; i++ )
00165 {
00166 char *s;
00167 int dbus_type;
00168 gboolean can_set;
00169 gboolean can_get;
00170 GParamSpec *spec = specs[i];
00171
00172 dbus_type = gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec));
00173 if (dbus_type == DBUS_TYPE_INVALID)
00174 continue;
00175
00176 if (spec->owner_type != last_type)
00177 {
00178 if (last_type != G_TYPE_INVALID)
00179 g_string_append (xml, " </interface>\n");
00180
00181
00182
00183
00184
00185
00186 g_string_append (xml, " <interface name=\"org.gtk.objects.");
00187 g_string_append (xml, g_type_name (spec->owner_type));
00188 g_string_append (xml, "\">\n");
00189
00190 last_type = spec->owner_type;
00191 }
00192
00193 can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
00194 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
00195
00196 can_get = (spec->flags & G_PARAM_READABLE) != 0;
00197
00198 s = uscore_to_wincaps (spec->name);
00199
00200 if (can_set)
00201 {
00202 g_string_append (xml, " <method name=\"set_");
00203 g_string_append (xml, s);
00204 g_string_append (xml, "\">\n");
00205
00206 g_string_append (xml, " <arg type=\"");
00207 g_string_append (xml, _dbus_gutils_type_to_string (dbus_type));
00208 g_string_append (xml, "\"/>\n");
00209 }
00210
00211 if (can_get)
00212 {
00213 g_string_append (xml, " <method name=\"get_");
00214 g_string_append (xml, s);
00215 g_string_append (xml, "\">\n");
00216
00217 g_string_append (xml, " <arg type=\"");
00218 g_string_append (xml, _dbus_gutils_type_to_string (dbus_type));
00219 g_string_append (xml, "\" direction=\"out\"/>\n");
00220 }
00221
00222 g_free (s);
00223 }
00224
00225 if (last_type != G_TYPE_INVALID)
00226 g_string_append (xml, " </interface>\n");
00227
00228 g_free (specs);
00229 }
00230
00231 static void
00232 introspect_signals (GType type, GString *xml)
00233 {
00234 guint i;
00235 guint *ids, n_ids;
00236
00237 ids = g_signal_list_ids (type, &n_ids);
00238 if (!n_ids)
00239 return;
00240
00241 g_string_append (xml, " <interface name=\"org.gtk.objects.");
00242 g_string_append (xml, g_type_name (type));
00243 g_string_append (xml, "\">\n");
00244
00245
00246 for (i = 0; i < n_ids; i++)
00247 {
00248 guint arg;
00249 GSignalQuery query;
00250
00251 g_signal_query (ids[i], &query);
00252
00253 if (query.return_type)
00254 continue;
00255
00256 g_string_append (xml, " <signal name=\"");
00257 g_string_append (xml, query.signal_name);
00258 g_string_append (xml, "\">\n");
00259
00260 for (arg = 0; arg < query.n_params; arg++)
00261 {
00262 int dbus_type = gtype_to_dbus_type (query.param_types[arg]);
00263
00264 g_string_append (xml, " <arg type=\"");
00265 g_string_append (xml, _dbus_gutils_type_to_string (dbus_type));
00266 g_string_append (xml, "\"/>\n");
00267 }
00268
00269 g_string_append (xml, " </signal>\n");
00270 }
00271
00272 g_string_append (xml, " </interface>\n");
00273 }
00274
00275 static DBusHandlerResult
00276 handle_introspect (DBusConnection *connection,
00277 DBusMessage *message,
00278 GObject *object)
00279 {
00280 GString *xml;
00281 unsigned int i;
00282 DBusMessage *ret;
00283 char **children;
00284
00285 if (!dbus_connection_list_registered (connection,
00286 dbus_message_get_path (message),
00287 &children))
00288 g_error ("Out of memory");
00289
00290 xml = g_string_new (NULL);
00291
00292 introspect_signals (G_OBJECT_TYPE (object), xml);
00293 introspect_properties (object, xml);
00294
00295 g_string_append (xml, "<node>\n");
00296
00297
00298 for (i = 0; children[i]; i++)
00299 g_string_append_printf (xml, " <node name=\"%s\"/>\n",
00300 children[i]);
00301
00302
00303 g_string_append (xml, "</node>\n");
00304
00305 ret = dbus_message_new_method_return (message);
00306 if (ret == NULL)
00307 g_error ("Out of memory");
00308
00309 dbus_message_append_args (message,
00310 DBUS_TYPE_STRING, xml->str,
00311 DBUS_TYPE_INVALID);
00312
00313 dbus_connection_send (connection, message, NULL);
00314 dbus_message_unref (message);
00315
00316 g_string_free (xml, TRUE);
00317
00318 dbus_free_string_array (children);
00319
00320 return DBUS_HANDLER_RESULT_HANDLED;
00321 }
00322
00323 static DBusMessage*
00324 set_object_property (DBusConnection *connection,
00325 DBusMessage *message,
00326 GObject *object,
00327 GParamSpec *pspec)
00328 {
00329 GValue value = { 0, };
00330 DBusMessage *ret;
00331 DBusMessageIter iter;
00332
00333 dbus_message_iter_init (message, &iter);
00334
00335
00336
00337
00338
00339
00340 if (dbus_gvalue_demarshal (&iter, &value))
00341 {
00342 g_object_set_property (object,
00343 pspec->name,
00344 &value);
00345
00346 g_value_unset (&value);
00347
00348 ret = dbus_message_new_method_return (message);
00349 if (ret == NULL)
00350 g_error ("out of memory");
00351 }
00352 else
00353 {
00354 ret = dbus_message_new_error (message,
00355 DBUS_ERROR_INVALID_ARGS,
00356 "Argument's D-BUS type can't be converted to a GType");
00357 if (ret == NULL)
00358 g_error ("out of memory");
00359 }
00360
00361 return ret;
00362 }
00363
00364 static DBusMessage*
00365 get_object_property (DBusConnection *connection,
00366 DBusMessage *message,
00367 GObject *object,
00368 GParamSpec *pspec)
00369 {
00370 GType value_type;
00371 GValue value;
00372 DBusMessage *ret;
00373 DBusMessageIter iter;
00374
00375 value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
00376
00377 ret = dbus_message_new_method_return (message);
00378 if (ret == NULL)
00379 g_error ("out of memory");
00380
00381 g_value_init (&value, value_type);
00382 g_object_get_property (object, pspec->name, &value);
00383
00384 value_type = G_VALUE_TYPE (&value);
00385
00386 dbus_message_append_iter_init (message, &iter);
00387
00388 if (!dbus_gvalue_marshal (&iter, &value))
00389 {
00390 dbus_message_unref (ret);
00391 ret = dbus_message_new_error (message,
00392 DBUS_ERROR_UNKNOWN_METHOD,
00393 "Can't convert GType of object property to a D-BUS type");
00394 }
00395
00396 return ret;
00397 }
00398
00399 static DBusHandlerResult
00400 gobject_message_function (DBusConnection *connection,
00401 DBusMessage *message,
00402 void *user_data)
00403 {
00404 const DBusGObjectInfo *info;
00405 GParamSpec *pspec;
00406 GObject *object;
00407 const char *member;
00408 gboolean setter;
00409 gboolean getter;
00410 char *s;
00411
00412 object = G_OBJECT (user_data);
00413
00414 if (dbus_message_is_method_call (message,
00415 DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
00416 "Introspect"))
00417 return handle_introspect (connection, message, object);
00418
00419 member = dbus_message_get_member (message);
00420
00421
00422
00423 g_static_mutex_lock (&info_hash_mutex);
00424
00425
00426
00427 info = g_hash_table_lookup (info_hash,
00428 G_OBJECT_GET_CLASS (object));
00429 g_static_mutex_unlock (&info_hash_mutex);
00430
00431 if (info != NULL)
00432 {
00433
00434
00435
00436 }
00437
00438
00439
00440
00441 setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
00442 getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
00443
00444 if (!(setter || getter))
00445 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00446
00447 s = wincaps_to_uscore (&member[4]);
00448
00449 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
00450 s);
00451
00452 g_free (s);
00453
00454 if (pspec != NULL)
00455 {
00456 DBusMessage *ret;
00457
00458 if (setter)
00459 {
00460 ret = set_object_property (connection, message,
00461 object, pspec);
00462 }
00463 else if (getter)
00464 {
00465 ret = get_object_property (connection, message,
00466 object, pspec);
00467 }
00468 else
00469 {
00470 g_assert_not_reached ();
00471 ret = NULL;
00472 }
00473
00474 g_assert (ret != NULL);
00475
00476 dbus_connection_send (connection, ret, NULL);
00477 dbus_message_unref (ret);
00478 return DBUS_HANDLER_RESULT_HANDLED;
00479 }
00480
00481 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00482 }
00483
00484 static DBusObjectPathVTable gobject_dbus_vtable = {
00485 gobject_unregister_function,
00486 gobject_message_function,
00487 NULL
00488 };
00489
00491
00511 void
00512 dbus_g_object_class_install_info (GObjectClass *object_class,
00513 const DBusGObjectInfo *info)
00514 {
00515 g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
00516
00517 g_static_mutex_lock (&info_hash_mutex);
00518
00519 if (info_hash == NULL)
00520 {
00521 info_hash = g_hash_table_new (NULL, NULL);
00522 }
00523
00524 g_hash_table_replace (info_hash, object_class, (void*) info);
00525
00526 g_static_mutex_unlock (&info_hash_mutex);
00527 }
00528
00542 void
00543 dbus_connection_register_g_object (DBusConnection *connection,
00544 const char *at_path,
00545 GObject *object)
00546 {
00547 g_return_if_fail (connection != NULL);
00548 g_return_if_fail (at_path != NULL);
00549 g_return_if_fail (G_IS_OBJECT (object));
00550
00551 if (!dbus_connection_register_object_path (connection,
00552 at_path,
00553 &gobject_dbus_vtable,
00554 object))
00555 g_error ("Failed to register GObject with DBusConnection");
00556
00557
00558
00559
00560 }
00561
00563
00564 #ifdef DBUS_BUILD_TESTS
00565 #include <stdlib.h>
00566
00572 dbus_bool_t
00573 _dbus_gobject_test (const char *test_data_dir)
00574 {
00575 int i;
00576 static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
00577 { "SetFoo", "set_foo" },
00578 { "Foo", "foo" },
00579 { "GetFooBar", "get_foo_bar" },
00580 { "Hello", "hello" }
00581
00582
00583
00584 };
00585
00586 i = 0;
00587 while (i < (int) G_N_ELEMENTS (name_pairs))
00588 {
00589 char *uscore;
00590 char *wincaps;
00591
00592 uscore = wincaps_to_uscore (name_pairs[i].wincaps);
00593 wincaps = uscore_to_wincaps (name_pairs[i].uscore);
00594
00595 if (strcmp (uscore, name_pairs[i].uscore) != 0)
00596 {
00597 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
00598 name_pairs[i].wincaps, name_pairs[i].uscore,
00599 uscore);
00600 exit (1);
00601 }
00602
00603 if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
00604 {
00605 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
00606 name_pairs[i].uscore, name_pairs[i].wincaps,
00607 wincaps);
00608 exit (1);
00609 }
00610
00611 g_free (uscore);
00612 g_free (wincaps);
00613
00614 ++i;
00615 }
00616
00617 return TRUE;
00618 }
00619
00620 #endif