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