From e888647a70094d5761f931e1a812764330ee5a2b Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 8 Jul 2005 16:25:39 +0000 Subject: 2005-07-08 Colin Walters * tools/Makefile.am: Kill of print-introspect in favor of using dbus-send --print-reply=literal. * tools/print-introspect.c: Deleted. * test/glib/test-service-glib.xml: * test/glib/test-service-glib.c (my_object_get_objs): New test for "ao". * test/glib/test-dbus-glib.c (echo_received_cb): Free echo data. (main): Test GetObjs. * glib/examples/statemachine/Makefile.am: * glib/examples/statemachine/sm-marshal.list: * glib/examples/statemachine/statemachine-client.c: * glib/examples/statemachine/statemachine-server.c: * glib/examples/statemachine/statemachine-server.xml: * glib/examples/statemachine/statemachine.c: * glib/examples/statemachine/statemachine.h: * glib/examples/statemachine/statemachine.xml: New example. * glib/examples/example-service.c (main): Move invocation of dbus_g_object_type_install_info earlier, to emphasize it should only be done once. * glib/examples/example-signal-emitter.c (main): Ditto. * glib/examples/Makefile.am (SUBDIRS): Include statemachine. * glib/dbus-gvalue.h (dbus_gtype_to_signature) (dbus_gvalue_marshal): Update prototypes. * glib/dbus-gvalue.c: Update all marshalling functions to take const GValue instead of GValue. (signature_iter_to_g_type_array): Return a GPtrArray for nonfixed types. (dbus_gvalue_to_signature): Update for dbus_gtype_to_signature change. (dbus_gtype_to_signature): Handle generic collecitons and maps. Return a newly-allocated string. (demarshal_proxy, demarshal_object_path, demarshal_object) (demarshal_strv, demarshal_ghashtable): Set error, don't assert if we get the wrong types from message. (get_type_demarshaller): New function, extracted from dbus_gvalue_demarshal. (demarshal_collection): New function, demarshals generic collection. (dbus_gvalue_demarshal): Just invoke result of get_type_demarshaller. Throw error if we don't have one. (marshal_garray_basic): Abort on OOM. (get_type_marshaller): New function, extracted from dbus_gvalue_marshal. (collection_marshal_iterator, marshal_collection): New functions; implements generic marshalling for an iteratable specialized collection. (dbus_gvalue_marshal): Just invoke result of get_type_marshaller. * glib/dbus-gvalue-utils.c (gvalue_from_ptrarray_value): Handle G_TYPE_STRING. (ptrarray_value_from_gvalue): Ditto. (ptrarray_append, ptrarray_free): New functions. (slist_constructor, slist_iterator, slist_copy_elt, slist_copy) (slist_append, slist_end_append, slist_free): New functions. (dbus_g_type_specialized_builtins_init): Add append fuctions for GPtrArray and GSList. Register GSList. (test_specialized_hash, _dbus_gvalue_utils_test): New functions. * glib/dbus-gtype-specialized.h (DBusGTypeSpecializedAppendContext): New. (dbus_g_type_specialized_collection_init_append) (dbus_g_type_specialized_collection_append) (dbus_g_type_specialized_collection_end_append): Prototype. (DBusGTypeSpecializedCollectionVtable): Add append_func and end_append_func. * glib/dbus-gtype-specialized.c (dbus_g_type_specialized_collection_init_append) (dbus_g_type_specialized_collection_append) (dbus_g_type_specialized_collection_end_append): New functions. (dbus_g_type_map_value_iterate): Take const GValue. (dbus_g_type_collection_value_iterate): Ditto. * glib/dbus-gtest.c (dbus_glib_internal_do_not_use_run_tests): Run _dbus_gvalue_utils_test. * glib/dbus-gtest.h: Prototype it. * glib/dbus-gproxy.c (dbus_g_proxy_manager_filter): Avoid using uninitialized owner_list. (dbus_g_proxy_begin_call_internal): Move return_if_fail to public API. (dbus_g_proxy_end_call_internal): Update to use error set from dbus_gvalue_demarshal instead of setting it here. (dbus_g_proxy_begin_call): Move return_if_fail here. * glib/dbus-gobject.c (write_interface): Update for dbus_gtype_to_signature returning new string. * configure.in: Add glib/examples/statemachine. --- ChangeLog | 101 ++++ configure.in | 1 + glib/dbus-gobject.c | 6 +- glib/dbus-gproxy.c | 31 +- glib/dbus-gtest.c | 7 + glib/dbus-gtest.h | 1 + glib/dbus-gtype-specialized.c | 44 +- glib/dbus-gtype-specialized.h | 32 +- glib/dbus-gvalue-utils.c | 261 +++++++++- glib/dbus-gvalue-utils.h | 1 - glib/dbus-gvalue.c | 388 ++++++++++++--- glib/dbus-gvalue.h | 4 +- glib/examples/Makefile.am | 2 + glib/examples/example-service.c | 4 +- glib/examples/example-signal-emitter.c | 4 +- glib/examples/statemachine/.cvsignore | 15 + glib/examples/statemachine/Makefile.am | 35 ++ glib/examples/statemachine/sm-marshal.list | 1 + glib/examples/statemachine/statemachine-client.c | 540 +++++++++++++++++++++ glib/examples/statemachine/statemachine-server.c | 202 ++++++++ glib/examples/statemachine/statemachine-server.h | 37 ++ glib/examples/statemachine/statemachine-server.xml | 14 + glib/examples/statemachine/statemachine.c | 351 ++++++++++++++ glib/examples/statemachine/statemachine.h | 77 +++ glib/examples/statemachine/statemachine.xml | 33 ++ test/glib/test-dbus-glib.c | 29 ++ test/glib/test-service-glib.c | 13 + test/glib/test-service-glib.xml | 4 + tools/Makefile.am | 9 +- tools/print-introspect.c | 83 ---- 30 files changed, 2133 insertions(+), 197 deletions(-) create mode 100644 glib/examples/statemachine/.cvsignore create mode 100644 glib/examples/statemachine/Makefile.am create mode 100644 glib/examples/statemachine/sm-marshal.list create mode 100644 glib/examples/statemachine/statemachine-client.c create mode 100644 glib/examples/statemachine/statemachine-server.c create mode 100644 glib/examples/statemachine/statemachine-server.h create mode 100644 glib/examples/statemachine/statemachine-server.xml create mode 100644 glib/examples/statemachine/statemachine.c create mode 100644 glib/examples/statemachine/statemachine.h create mode 100644 glib/examples/statemachine/statemachine.xml delete mode 100644 tools/print-introspect.c diff --git a/ChangeLog b/ChangeLog index 40c95889..7ce21a5c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,104 @@ +2005-07-08 Colin Walters + + * tools/Makefile.am: Kill of print-introspect in favor of using + dbus-send --print-reply=literal. + + * test/glib/test-service-glib.xml: + * test/glib/test-service-glib.c (my_object_get_objs): New test + for "ao". + + * test/glib/test-dbus-glib.c (echo_received_cb): Free echo data. + (main): Test GetObjs. + + * glib/examples/statemachine/Makefile.am: + * glib/examples/statemachine/sm-marshal.list: + * glib/examples/statemachine/statemachine-client.c: + * glib/examples/statemachine/statemachine-server.c: + * glib/examples/statemachine/statemachine-server.xml: + * glib/examples/statemachine/statemachine.c: + * glib/examples/statemachine/statemachine.h: + * glib/examples/statemachine/statemachine.xml: + + New example. + + * glib/examples/example-service.c (main): Move invocation + of dbus_g_object_type_install_info earlier, to emphasize it + should only be done once. + + * glib/examples/example-signal-emitter.c (main): Ditto. + + * glib/examples/Makefile.am (SUBDIRS): Include statemachine. + + * glib/dbus-gvalue.h (dbus_gtype_to_signature) + (dbus_gvalue_marshal): Update prototypes. + + * glib/dbus-gvalue.c: Update all marshalling functions to take + const GValue instead of GValue. + (signature_iter_to_g_type_array): Return a GPtrArray for nonfixed + types. + (dbus_gvalue_to_signature): Update for dbus_gtype_to_signature + change. + (dbus_gtype_to_signature): Handle generic collecitons and maps. + Return a newly-allocated string. + (demarshal_proxy, demarshal_object_path, demarshal_object) + (demarshal_strv, demarshal_ghashtable): Set error, don't assert if + we get the wrong types from message. + (get_type_demarshaller): New function, extracted from + dbus_gvalue_demarshal. + (demarshal_collection): New function, demarshals generic + collection. + (dbus_gvalue_demarshal): Just invoke result of + get_type_demarshaller. Throw error if we don't have one. + (marshal_garray_basic): Abort on OOM. + (get_type_marshaller): New function, extracted from + dbus_gvalue_marshal. + (collection_marshal_iterator, marshal_collection): New functions; + implements generic marshalling for an iteratable specialized + collection. + (dbus_gvalue_marshal): Just invoke result of get_type_marshaller. + + * glib/dbus-gvalue-utils.c (gvalue_from_ptrarray_value): Handle + G_TYPE_STRING. + (ptrarray_value_from_gvalue): Ditto. + (ptrarray_append, ptrarray_free): New functions. + (slist_constructor, slist_iterator, slist_copy_elt, slist_copy) + (slist_append, slist_end_append, slist_free): New functions. + (dbus_g_type_specialized_builtins_init): Add append fuctions + for GPtrArray and GSList. Register GSList. + (test_specialized_hash, _dbus_gvalue_utils_test): New functions. + + * glib/dbus-gtype-specialized.h (DBusGTypeSpecializedAppendContext): + New. + (dbus_g_type_specialized_collection_init_append) + (dbus_g_type_specialized_collection_append) + (dbus_g_type_specialized_collection_end_append): Prototype. + (DBusGTypeSpecializedCollectionVtable): Add append_func and + end_append_func. + + * glib/dbus-gtype-specialized.c (dbus_g_type_specialized_collection_init_append) + (dbus_g_type_specialized_collection_append) + (dbus_g_type_specialized_collection_end_append): New functions. + (dbus_g_type_map_value_iterate): Take const GValue. + (dbus_g_type_collection_value_iterate): Ditto. + + * glib/dbus-gtest.c (dbus_glib_internal_do_not_use_run_tests): Run + _dbus_gvalue_utils_test. + + * glib/dbus-gtest.h: Prototype it. + + * glib/dbus-gproxy.c (dbus_g_proxy_manager_filter): Avoid + using uninitialized owner_list. + (dbus_g_proxy_begin_call_internal): Move return_if_fail to + public API. + (dbus_g_proxy_end_call_internal): Update to use error set + from dbus_gvalue_demarshal instead of setting it here. + (dbus_g_proxy_begin_call): Move return_if_fail here. + + * glib/dbus-gobject.c (write_interface): Update for + dbus_gtype_to_signature returning new string. + + * configure.in: Add glib/examples/statemachine. + 2005-07-08 Joe Shaw * configure.in: Add a configure option, --with-console-auth-dir diff --git a/configure.in b/configure.in index 4c77ea54..0266d006 100644 --- a/configure.in +++ b/configure.in @@ -1272,6 +1272,7 @@ Makefile dbus/Makefile glib/Makefile glib/examples/Makefile +glib/examples/statemachine/Makefile python/Makefile python/examples/Makefile qt/Makefile diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index ed1f81ce..4f076cc6 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -358,13 +358,14 @@ write_interface (gpointer key, gpointer val, gpointer user_data) for (arg = 0; arg < query.n_params; arg++) { - const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]); + char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]); g_assert (dbus_type != NULL); g_string_append (xml, " \n"); + g_free (dbus_type); } g_string_append (xml, " \n"); @@ -376,7 +377,7 @@ write_interface (gpointer key, gpointer val, gpointer user_data) { const char *propname; GParamSpec *spec; - const char *dbus_type; + char *dbus_type; gboolean can_set; gboolean can_get; char *s; @@ -417,6 +418,7 @@ write_interface (gpointer key, gpointer val, gpointer user_data) g_string_append (xml, "\"/>\n"); } + g_free (dbus_type); g_free (s); g_string_append (xml, " \n"); diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index fd78b04d..929e52e4 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -1204,7 +1204,8 @@ dbus_g_proxy_manager_filter (DBusConnection *connection, dbus_message_get_interface (message)); owner_list = g_hash_table_lookup (manager->proxy_lists, tri); - full_list = g_slist_concat (full_list, g_slist_copy (owner_list->proxies)); + if (owner_list != NULL) + full_list = g_slist_concat (full_list, g_slist_copy (owner_list->proxies)); g_free (tri); } } @@ -2033,9 +2034,6 @@ dbus_g_proxy_begin_call_internal (DBusGProxy *proxy, GPendingNotifyClosure *closure; guint call_id; - g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE); - g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE); - pending = NULL; message = dbus_g_proxy_marshal_args_to_message (proxy, method, args); @@ -2152,26 +2150,8 @@ dbus_g_proxy_end_call_internal (DBusGProxy *proxy, { g_value_init (&gvalue, valtype); - /* FIXME, should use error here instead of NULL */ - if (!dbus_gvalue_demarshal (&context, &msgiter, &gvalue, NULL)) - { - g_set_error (error, - DBUS_GERROR, - DBUS_GERROR_INVALID_ARGS, - _("Couldn't convert argument, expected \"%s\""), - g_type_name (valtype)); - goto out; - } - - if (G_VALUE_TYPE (&gvalue) != valtype) - { - g_set_error (error, DBUS_GERROR, - DBUS_GERROR_INVALID_ARGS, - _("Reply argument was \"%s\", expected \"%s\""), - g_type_name (G_VALUE_TYPE (&gvalue)), - g_type_name (valtype)); - goto out; - } + if (!dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error)) + goto out; /* Anything that can be demarshaled must be storable */ if (!dbus_gvalue_store (&gvalue, (gpointer*) return_storage)) @@ -2274,6 +2254,9 @@ dbus_g_proxy_begin_call (DBusGProxy *proxy, va_list args; GValueArray *arg_values; + g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE); + g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE); + va_start (args, first_arg_type); DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args); diff --git a/glib/dbus-gtest.c b/glib/dbus-gtest.c index 77e2e7b2..2b79feb4 100644 --- a/glib/dbus-gtest.c +++ b/glib/dbus-gtest.c @@ -25,6 +25,7 @@ #include "dbus-gtest.h" #include #include +#include #ifdef DBUS_BUILD_TESTS static void @@ -56,6 +57,12 @@ dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir) else printf ("No test data!\n"); + g_type_init (); + + printf ("%s: running GValue util tests\n", "dbus-glib-test"); + if (!_dbus_gvalue_utils_test (test_data_dir)) + die ("gvalue utils"); + printf ("%s: running glib tests\n", "dbus-glib-test"); if (!_dbus_glib_test (test_data_dir)) die ("glib"); diff --git a/glib/dbus-gtest.h b/glib/dbus-gtest.h index b68ab23f..73bf0dda 100644 --- a/glib/dbus-gtest.h +++ b/glib/dbus-gtest.h @@ -30,6 +30,7 @@ gboolean _dbus_gmain_test (const char *test_data_dir); gboolean _dbus_gobject_test (const char *test_data_dir); gboolean _dbus_gutils_test (const char *test_data_dir); gboolean _dbus_glib_test (const char *test_data_dir); +gboolean _dbus_gvalue_utils_test (const char *test_data_dir); void dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir); diff --git a/glib/dbus-gtype-specialized.c b/glib/dbus-gtype-specialized.c index b331fcc5..d588fa86 100644 --- a/glib/dbus-gtype-specialized.c +++ b/glib/dbus-gtype-specialized.c @@ -401,7 +401,7 @@ dbus_g_type_collection_get_fixed (GValue *value, } void -dbus_g_type_collection_value_iterate (GValue *value, +dbus_g_type_collection_value_iterate (const GValue *value, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data) { @@ -420,8 +420,48 @@ dbus_g_type_collection_value_iterate (GValue *va iterator, user_data); } +typedef struct { + GValue *val; + GType specialization_type; + DBusGTypeSpecializedData *specdata; +} DBusGTypeSpecializedAppendContextReal; + +void +dbus_g_type_specialized_collection_init_append (GValue *value, DBusGTypeSpecializedAppendContext *ctx) +{ + DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx; + GType gtype; + DBusGTypeSpecializedData *specdata; + + g_return_if_fail (specialized_types_is_initialized ()); + g_return_if_fail (G_VALUE_HOLDS_BOXED (value)); + gtype = G_VALUE_TYPE (value); + specdata = lookup_specialization_data (gtype); + g_return_if_fail (specdata != NULL); + + realctx->val = value; + realctx->specialization_type = specdata->types[0]; + realctx->specdata = specdata; +} + +void +dbus_g_type_specialized_collection_append (DBusGTypeSpecializedAppendContext *ctx, + const GValue *elt) +{ + DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx; + ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->append_func (ctx, elt); +} + +void +dbus_g_type_specialized_collection_end_append (DBusGTypeSpecializedAppendContext *ctx) +{ + DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx; + if (((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func != NULL) + ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func (ctx); +} + void -dbus_g_type_map_value_iterate (GValue *value, +dbus_g_type_map_value_iterate (const GValue *value, DBusGTypeSpecializedMapIterator iterator, gpointer user_data) { diff --git a/glib/dbus-gtype-specialized.h b/glib/dbus-gtype-specialized.h index 5157f33f..8e47db98 100644 --- a/glib/dbus-gtype-specialized.h +++ b/glib/dbus-gtype-specialized.h @@ -48,21 +48,37 @@ typedef void (*DBusGTypeSpecializedMapIterator) (const GValue *key_v gpointer dbus_g_type_specialized_construct (GType type); +typedef struct { + /* public */ + GValue *val; + GType specialization_type; + /* padding */ + gpointer b; + guint c; + gpointer d; +} DBusGTypeSpecializedAppendContext; + +void dbus_g_type_specialized_collection_init_append (GValue *val, DBusGTypeSpecializedAppendContext *ctx); + +void dbus_g_type_specialized_collection_append (DBusGTypeSpecializedAppendContext *ctx, const GValue *elt); + +void dbus_g_type_specialized_collection_end_append (DBusGTypeSpecializedAppendContext *ctx); + gboolean dbus_g_type_collection_get_fixed (GValue *value, gpointer *data, guint *len); -void dbus_g_type_collection_value_iterate (GValue *value, +void dbus_g_type_collection_value_iterate (const GValue *value, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data); -void dbus_g_type_map_value_iterate (GValue *value, +void dbus_g_type_map_value_iterate (const GValue *value, DBusGTypeSpecializedMapIterator iterator, gpointer user_data); -typedef gpointer (*DBusGTypeSpecializedConstructor) (GType type); -typedef void (*DBusGTypeSpecializedFreeFunc) (GType type, gpointer val); -typedef gpointer (*DBusGTypeSpecializedCopyFunc) (GType type, gpointer src); +typedef gpointer (*DBusGTypeSpecializedConstructor) (GType type); +typedef void (*DBusGTypeSpecializedFreeFunc) (GType type, gpointer val); +typedef gpointer (*DBusGTypeSpecializedCopyFunc) (GType type, gpointer src); typedef struct { DBusGTypeSpecializedConstructor constructor; @@ -74,12 +90,16 @@ typedef struct { } DBusGTypeSpecializedVtable; typedef gboolean (*DBusGTypeSpecializedCollectionFixedAccessorFunc) (GType type, gpointer instance, gpointer *values, guint *len); -typedef void (*DBusGTypeSpecializedCollectionIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data); +typedef void (*DBusGTypeSpecializedCollectionIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data); +typedef void (*DBusGTypeSpecializedCollectionAppendFunc) (DBusGTypeSpecializedAppendContext *ctx, const GValue *val); +typedef void (*DBusGTypeSpecializedCollectionEndAppendFunc) (DBusGTypeSpecializedAppendContext *ctx); typedef struct { DBusGTypeSpecializedVtable base_vtable; DBusGTypeSpecializedCollectionFixedAccessorFunc fixed_accessor; DBusGTypeSpecializedCollectionIteratorFunc iterator; + DBusGTypeSpecializedCollectionAppendFunc append_func; + DBusGTypeSpecializedCollectionEndAppendFunc end_append_func; } DBusGTypeSpecializedCollectionVtable; typedef void (*DBusGTypeSpecializedMapIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedMapIterator iterator, gpointer user_data); diff --git a/glib/dbus-gvalue-utils.c b/glib/dbus-gvalue-utils.c index 9eea4bf0..b281f6ee 100644 --- a/glib/dbus-gvalue-utils.c +++ b/glib/dbus-gvalue-utils.c @@ -21,8 +21,10 @@ * */ +#include #include "dbus/dbus-glib.h" #include "dbus-gvalue-utils.h" +#include "dbus-gtest.h" #include #include #include @@ -572,6 +574,9 @@ gvalue_from_ptrarray_value (GValue *value, gpointer instance) { switch (g_type_fundamental (G_VALUE_TYPE (value))) { + case G_TYPE_STRING: + g_value_set_string (value, instance); + break; case G_TYPE_POINTER: g_value_set_pointer (value, instance); break; @@ -593,6 +598,9 @@ ptrarray_value_from_gvalue (const GValue *value) { switch (g_type_fundamental (G_VALUE_TYPE (value))) { + case G_TYPE_STRING: + return (gpointer) g_value_get_string (value); + break; case G_TYPE_POINTER: return g_value_get_pointer (value); break; @@ -658,12 +666,106 @@ ptrarray_copy (GType type, gpointer src) return new; } +static void +ptrarray_append (DBusGTypeSpecializedAppendContext *ctx, const GValue *value) +{ + GPtrArray *array; + + array = g_value_get_boxed (ctx->val); + + g_ptr_array_add (array, ptrarray_value_from_gvalue (value)); +} + static void ptrarray_free (GType type, gpointer val) { - GArray *array; + GPtrArray *array; array = val; - g_array_free (array, TRUE); + g_ptr_array_free (array, TRUE); +} + +static gpointer +slist_constructor (GType type) +{ + return NULL; +} + +static void +slist_iterator (GType list_type, + gpointer instance, + DBusGTypeSpecializedCollectionIterator iterator, + gpointer user_data) +{ + GSList *slist; + GType elt_gtype; + + slist = instance; + + elt_gtype = dbus_g_type_get_collection_specialization (list_type); + + while (slist != NULL) + { + GValue val = {0, }; + g_value_init (&val, elt_gtype); + gvalue_from_ptrarray_value (&val, slist->data); + iterator (&val, user_data); + } +} + +static void +slist_copy_elt (const GValue *val, gpointer user_data) +{ + GSList *dest = user_data; + GValue val_copy = {0, }; + + g_value_init (&val_copy, G_VALUE_TYPE (val)); + g_value_copy (val, &val_copy); + + g_slist_append (dest, ptrarray_value_from_gvalue (&val_copy)); +} + +static gpointer +slist_copy (GType type, gpointer src) +{ + GSList *new; + GValue slist_val = {0, }; + + g_value_init (&slist_val, type); + g_value_set_static_boxed (&slist_val, src); + + new = slist_constructor (type); + dbus_g_type_collection_value_iterate (&slist_val, slist_copy_elt, new); + + return new; +} + +static void +slist_append (DBusGTypeSpecializedAppendContext *ctx, const GValue *value) +{ + GSList *list; + + list = g_value_get_boxed (ctx->val); + list = g_slist_prepend (list, ptrarray_value_from_gvalue (value)); + g_value_set_static_boxed (ctx->val, list); +} + +static void +slist_end_append (DBusGTypeSpecializedAppendContext *ctx) +{ + GSList *list; + + list = g_value_get_boxed (ctx->val); + list = g_slist_reverse (list); + + g_value_set_static_boxed (ctx->val, list); +} + +static void +slist_free (GType type, gpointer val) +{ + GSList *list; + list = val; + g_slist_free (list); } void @@ -674,11 +776,10 @@ dbus_g_type_specialized_builtins_init (void) array_constructor, array_free, array_copy, - NULL, - NULL, - NULL }, array_fixed_accessor, + NULL, + NULL, NULL }; @@ -689,16 +790,29 @@ dbus_g_type_specialized_builtins_init (void) ptrarray_constructor, ptrarray_free, ptrarray_copy, - NULL, - NULL, - NULL }, NULL, - ptrarray_iterator + ptrarray_iterator, + ptrarray_append, + NULL, }; dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0); + static const DBusGTypeSpecializedCollectionVtable slist_vtable = { + { + slist_constructor, + slist_free, + slist_copy, + }, + NULL, + slist_iterator, + slist_append, + slist_end_append, + }; + + dbus_g_type_register_collection ("GSList", &slist_vtable, 0); + static const DBusGTypeSpecializedMapVtable hashtable_vtable = { { hashtable_constructor, @@ -713,3 +827,132 @@ dbus_g_type_specialized_builtins_init (void) dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0); } + +#ifdef DBUS_BUILD_TESTS + +typedef struct +{ + gboolean seen_foo; + gboolean seen_baz; +} TestSpecializedHashData; + +static void +test_specialized_hash (const GValue *key, const GValue *val, gpointer user_data) +{ + TestSpecializedHashData *data = user_data; + + g_assert (G_VALUE_HOLDS_STRING (key)); + g_assert (G_VALUE_HOLDS_STRING (val)); + + if (!strcmp (g_value_get_string (key), "foo")) + { + data->seen_foo = TRUE; + g_assert (!strcmp (g_value_get_string (val), "bar")); + } + else if (!strcmp (g_value_get_string (key), "baz")) + { + data->seen_baz = TRUE; + g_assert (!strcmp (g_value_get_string (val), "moo")); + } + else + { + g_assert_not_reached (); + } +} + +gboolean +_dbus_gvalue_utils_test (const char *datadir) +{ + GType type; + + dbus_g_type_specialized_init (); + dbus_g_type_specialized_builtins_init (); + + type = dbus_g_type_get_collection ("GArray", G_TYPE_UINT); + g_assert (dbus_g_type_is_collection (type)); + g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_UINT); + { + GArray *instance; + + instance = dbus_g_type_specialized_construct (type); + + g_assert (instance->len == 0); + + g_array_free (instance, TRUE); + } + + type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING); + g_assert (dbus_g_type_is_map (type)); + g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING); + g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_STRING); + { + GHashTable *instance; + GValue val = { 0, }; + TestSpecializedHashData hashdata; + + instance = dbus_g_type_specialized_construct (type); + + g_assert (g_hash_table_size (instance) == 0); + g_hash_table_insert (instance, g_strdup ("foo"), g_strdup ("bar")); + g_hash_table_insert (instance, g_strdup ("baz"), g_strdup ("moo")); + g_assert (g_hash_table_size (instance) == 2); + + g_value_init (&val, type); + g_value_set_boxed_take_ownership (&val, instance); + hashdata.seen_foo = FALSE; + hashdata.seen_baz = FALSE; + dbus_g_type_map_value_iterate (&val, + test_specialized_hash, + &hashdata); + + g_assert (hashdata.seen_foo); + g_assert (hashdata.seen_baz); + + g_value_unset (&val); + } + + type = dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING); + g_assert (dbus_g_type_is_collection (type)); + g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_STRING); + { + GPtrArray *instance; + DBusGTypeSpecializedAppendContext ctx; + GValue val = {0, }; + GValue eltval = {0, }; + + instance = dbus_g_type_specialized_construct (type); + + g_assert (instance->len == 0); + + g_value_init (&val, type); + g_value_set_boxed_take_ownership (&val, instance); + + dbus_g_type_specialized_collection_init_append (&val, &ctx); + + g_value_init (&eltval, G_TYPE_STRING); + g_value_set_static_string (&eltval, "foo"); + dbus_g_type_specialized_collection_append (&ctx, &eltval); + + g_value_reset (&eltval); + g_value_set_static_string (&eltval, "bar"); + dbus_g_type_specialized_collection_append (&ctx, &eltval); + + g_value_reset (&eltval); + g_value_set_static_string (&eltval, "baz"); + dbus_g_type_specialized_collection_append (&ctx, &eltval); + + dbus_g_type_specialized_collection_end_append (&ctx); + + g_assert (instance->len == 3); + + g_assert (!strcmp ("foo", g_ptr_array_index (instance, 0))); + g_assert (!strcmp ("bar", g_ptr_array_index (instance, 1))); + g_assert (!strcmp ("baz", g_ptr_array_index (instance, 2))); + + g_value_unset (&val); + } + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/glib/dbus-gvalue-utils.h b/glib/dbus-gvalue-utils.h index 781569ff..551e4289 100644 --- a/glib/dbus-gvalue-utils.h +++ b/glib/dbus-gvalue-utils.h @@ -64,7 +64,6 @@ gboolean dbus_gvalue_store (GValue *value, gboolean dbus_gvalue_take (GValue *value, GTypeCValue *cvalue); - G_END_DECLS #endif diff --git a/glib/dbus-gvalue.c b/glib/dbus-gvalue.c index e2786c48..4e7495c7 100644 --- a/glib/dbus-gvalue.c +++ b/glib/dbus-gvalue.c @@ -59,56 +59,70 @@ struct _DBusGValue }; static gboolean marshal_basic (DBusMessageIter *iter, - GValue *value); + const GValue *value); static gboolean demarshal_basic (DBusGValueMarshalCtx *context, DBusMessageIter *iter, GValue *value, GError **error); static gboolean marshal_strv (DBusMessageIter *iter, - GValue *value); + const GValue *value); static gboolean demarshal_strv (DBusGValueMarshalCtx *context, DBusMessageIter *iter, GValue *value, GError **error); static gboolean marshal_variant (DBusMessageIter *iter, - GValue *value); + const GValue *value); static gboolean demarshal_variant (DBusGValueMarshalCtx *context, DBusMessageIter *iter, GValue *value, GError **error); static gboolean marshal_garray_basic (DBusMessageIter *iter, - GValue *value); + const GValue *value); static gboolean demarshal_garray_basic (DBusGValueMarshalCtx *context, DBusMessageIter *iter, GValue *value, GError **error); static gboolean marshal_proxy (DBusMessageIter *iter, - GValue *value); + const GValue *value); static gboolean demarshal_proxy (DBusGValueMarshalCtx *context, DBusMessageIter *iter, GValue *value, GError **error); static gboolean marshal_object_path (DBusMessageIter *iter, - GValue *value); + const GValue *value); static gboolean demarshal_object_path (DBusGValueMarshalCtx *context, DBusMessageIter *iter, GValue *value, GError **error); static gboolean marshal_object (DBusMessageIter *iter, - GValue *value); + const GValue *value); static gboolean demarshal_object (DBusGValueMarshalCtx *context, DBusMessageIter *iter, GValue *value, GError **error); static gboolean marshal_map (DBusMessageIter *iter, - GValue *value); + const GValue *value); static gboolean demarshal_ghashtable (DBusGValueMarshalCtx *context, DBusMessageIter *iter, GValue *value, GError **error); +static gboolean marshal_collection (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_collection (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); + +static gboolean marshal_recurse (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_recurse (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); + typedef gboolean (*DBusGValueMarshalFunc) (DBusMessageIter *iter, - GValue *value); + const GValue *value); typedef gboolean (*DBusGValueDemarshalFunc) (DBusGValueMarshalCtx *context, DBusMessageIter *iter, GValue *value, @@ -602,6 +616,9 @@ signature_iter_to_g_type_array (DBusSignatureIter *iter, gboolean is_client) return G_TYPE_STRV; if (dbus_g_type_is_fixed (elt_gtype)) return dbus_g_type_get_collection ("GArray", elt_gtype); + else if (g_type_is_a (elt_gtype, G_TYPE_OBJECT) + || g_type_is_a (elt_gtype, G_TYPE_BOXED)) + return dbus_g_type_get_collection ("GPtrArray", elt_gtype); /* Later we need to return DBUS_TYPE_G_VALUE */ return G_TYPE_INVALID; @@ -681,11 +698,11 @@ dbus_gtype_from_signature (const char *signature, gboolean is_client) static char * dbus_gvalue_to_signature (GValue *value) { - const char *ret; + char *ret; ret = dbus_gtype_to_signature (G_VALUE_TYPE (value)); if (ret) - return g_strdup (ret); + return ret; else { DBusGValue *val; @@ -698,15 +715,45 @@ dbus_gvalue_to_signature (GValue *value) } } -const char * +char * dbus_gtype_to_signature (GType gtype) { + char *ret; DBusGTypeMarshalData *typedata; typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); if (typedata == NULL) return NULL; - return typedata->sig; + + if (dbus_g_type_is_collection (gtype)) + { + GType elt_gtype; + char *subsig; + + elt_gtype = dbus_g_type_get_collection_specialization (gtype); + subsig = dbus_gtype_to_signature (elt_gtype); + ret = g_strconcat (DBUS_TYPE_ARRAY_AS_STRING, subsig, NULL); + g_free (subsig); + } + else if (dbus_g_type_is_map (gtype)) + { + GType key_gtype; + GType val_gtype; + char *key_subsig; + char *val_subsig; + + key_gtype = dbus_g_type_get_map_key_specialization (gtype); + val_gtype = dbus_g_type_get_map_value_specialization (gtype); + key_subsig = dbus_gtype_to_signature (key_gtype); + val_subsig = dbus_gtype_to_signature (val_gtype); + ret = g_strconcat (DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING, key_subsig, val_subsig, DBUS_DICT_ENTRY_END_CHAR_AS_STRING, NULL); + g_free (key_subsig); + g_free (val_subsig); + } + else + ret = g_strdup (typedata->sig); + + return ret; } GArray * @@ -878,7 +925,14 @@ demarshal_proxy (DBusGValueMarshalCtx *context, int current_type; current_type = dbus_message_iter_get_arg_type (iter); - g_assert (current_type == DBUS_TYPE_OBJECT_PATH); + if (current_type != DBUS_TYPE_OBJECT_PATH) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS object path, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } g_assert (context->proxy != NULL); @@ -900,7 +954,14 @@ demarshal_object_path (DBusGValueMarshalCtx *context, int current_type; current_type = dbus_message_iter_get_arg_type (iter); - g_assert (current_type == DBUS_TYPE_OBJECT_PATH); + if (current_type != DBUS_TYPE_OBJECT_PATH) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS object path, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } dbus_message_iter_get_basic (iter, &objpath); @@ -920,7 +981,14 @@ demarshal_object (DBusGValueMarshalCtx *context, GObject *obj; current_type = dbus_message_iter_get_arg_type (iter); - g_assert (current_type == DBUS_TYPE_OBJECT_PATH); + if (current_type != DBUS_TYPE_OBJECT_PATH) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS object path, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } g_assert (context->proxy == NULL); dbus_message_iter_get_basic (iter, &objpath); @@ -952,8 +1020,29 @@ demarshal_strv (DBusGValueMarshalCtx *context, int len; int i; + current_type = dbus_message_iter_get_arg_type (iter); + if (current_type != DBUS_TYPE_ARRAY) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS array, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + dbus_message_iter_recurse (iter, &subiter); + current_type = dbus_message_iter_get_arg_type (&subiter); + if (current_type != DBUS_TYPE_INVALID + && current_type != DBUS_TYPE_STRING) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS string, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + len = dbus_message_iter_get_array_len (&subiter); g_assert (len >= 0); ret = g_malloc (sizeof (char *) * (len + 1)); @@ -1026,13 +1115,29 @@ demarshal_ghashtable (DBusGValueMarshalCtx *context, GType value_gtype; current_type = dbus_message_iter_get_arg_type (iter); - g_assert (current_type == DBUS_TYPE_ARRAY); + if (current_type != DBUS_TYPE_ARRAY) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS array, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } gtype = G_VALUE_TYPE (value); dbus_message_iter_recurse (iter, &subiter); - g_assert (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_DICT_ENTRY); + current_type = dbus_message_iter_get_arg_type (&subiter); + if (current_type != DBUS_TYPE_INVALID + && current_type != DBUS_TYPE_DICT_ENTRY) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS dict entry, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } key_gtype = dbus_g_type_get_map_key_specialization (gtype); g_assert (dbus_gtype_is_valid_hash_key (key_gtype)); @@ -1083,6 +1188,95 @@ demarshal_ghashtable (DBusGValueMarshalCtx *context, return TRUE; } +static DBusGValueDemarshalFunc +get_type_demarshaller (GType type) +{ + DBusGTypeMarshalData *typedata; + + typedata = g_type_get_qdata (type, dbus_g_type_metadata_data_quark ()); + if (typedata == NULL) + { + if (g_type_is_a (type, DBUS_TYPE_G_VALUE)) + return demarshal_recurse; + if (dbus_g_type_is_collection (type)) + return demarshal_collection; + + g_warning ("No demarshaller registered for type \"%s\"", g_type_name (type)); + return NULL; + } + g_assert (typedata->vtable); + return typedata->vtable->demarshaller; +} + +static gboolean +demarshal_collection (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + GType coltype; + GType subtype; + gpointer instance; + DBusGTypeSpecializedAppendContext ctx; + DBusGValueDemarshalFunc demarshaller; + DBusMessageIter subiter; + int current_type; + + current_type = dbus_message_iter_get_arg_type (iter); + + if (current_type != DBUS_TYPE_ARRAY) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS array, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + + dbus_message_iter_recurse (iter, &subiter); + + coltype = G_VALUE_TYPE (value); + subtype = dbus_g_type_get_collection_specialization (coltype); + + demarshaller = get_type_demarshaller (subtype); + + if (!demarshaller) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("No demarshaller registered for type \"%s\" of collection \"%s\""), + g_type_name (coltype), + g_type_name (subtype)); + return FALSE; + } + + instance = dbus_g_type_specialized_construct (coltype); + g_value_set_boxed_take_ownership (value, instance); + + dbus_g_type_specialized_collection_init_append (value, &ctx); + + while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) + { + GValue eltval = {0, }; + + g_value_init (&eltval, subtype); + + if (!demarshaller (context, &subiter, &eltval, error)) + { + dbus_g_type_specialized_collection_end_append (&ctx); + g_value_unset (value); + return FALSE; + } + dbus_g_type_specialized_collection_append (&ctx, &eltval); + + dbus_message_iter_next (&subiter); + } + dbus_g_type_specialized_collection_end_append (&ctx); + + return TRUE; +} + static gboolean demarshal_recurse (DBusGValueMarshalCtx *context, DBusMessageIter *iter, @@ -1099,21 +1293,23 @@ dbus_gvalue_demarshal (DBusGValueMarshalCtx *context, GError **error) { GType gtype; - DBusGTypeMarshalData *typedata; + DBusGValueDemarshalFunc demarshaller; gtype = G_VALUE_TYPE (value); - typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); - g_return_val_if_fail (typedata != NULL || g_type_is_a (gtype, DBUS_TYPE_G_VALUE), FALSE); + demarshaller = get_type_demarshaller (gtype); - if (typedata == NULL) + if (demarshaller == NULL) { - if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE)) - return demarshal_recurse (context, iter, value, error); - g_assert_not_reached (); + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("No demarshaller registered for type \"%s\""), + g_type_name (gtype)); + return FALSE; } - g_assert (typedata->vtable); - return typedata->vtable->demarshaller (context, iter, value, error); + + return demarshaller (context, iter, value, error); } gboolean @@ -1180,7 +1376,7 @@ dbus_gvalue_demarshal_message (DBusGValueMarshalCtx *context, } static gboolean -marshal_basic (DBusMessageIter *iter, GValue *value) +marshal_basic (DBusMessageIter *iter, const GValue *value) { GType value_type; @@ -1316,7 +1512,7 @@ marshal_basic (DBusMessageIter *iter, GValue *value) static gboolean marshal_strv (DBusMessageIter *iter, - GValue *value) + const GValue *value) { DBusMessageIter subiter; char **array; @@ -1350,14 +1546,13 @@ marshal_strv (DBusMessageIter *iter, static gboolean marshal_garray_basic (DBusMessageIter *iter, - GValue *value) + const GValue *value) { GType elt_gtype; DBusMessageIter subiter; GArray *array; guint elt_size; - const char *subsignature_str; - gboolean ret = FALSE; + char *subsignature_str; elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value)); /* FIXME - this means we can't send an array of DBusGValue right now... */ @@ -1372,7 +1567,7 @@ marshal_garray_basic (DBusMessageIter *iter, DBUS_TYPE_ARRAY, subsignature_str, &subiter)) - goto out; + goto oom; /* TODO - This assumes that basic values are the same size * is this always true? If it is we can probably avoid @@ -1382,18 +1577,20 @@ marshal_garray_basic (DBusMessageIter *iter, subsignature_str[0], &(array->data), array->len)) - goto out; + goto oom; if (!dbus_message_iter_close_container (iter, &subiter)) - goto out; - ret = TRUE; - out: - return ret; + goto oom; + g_free (subsignature_str); + return TRUE; + oom: + g_error ("out of memory"); + return FALSE; } static gboolean marshal_proxy (DBusMessageIter *iter, - GValue *value) + const GValue *value) { const char *path; DBusGProxy *proxy; @@ -1412,7 +1609,7 @@ marshal_proxy (DBusMessageIter *iter, static gboolean marshal_object_path (DBusMessageIter *iter, - GValue *value) + const GValue *value) { const char *path; @@ -1429,7 +1626,7 @@ marshal_object_path (DBusMessageIter *iter, static gboolean marshal_object (DBusMessageIter *iter, - GValue *value) + const GValue *value) { const char *path; GObject *obj; @@ -1472,10 +1669,10 @@ marshal_map_entry (const GValue *key, &subiter)) goto lose; - if (!dbus_gvalue_marshal (&subiter, (GValue*) key)) + if (!dbus_gvalue_marshal (&subiter, key)) goto lose; - if (!dbus_gvalue_marshal (&subiter, (GValue*) value)) + if (!dbus_gvalue_marshal (&subiter, value)) goto lose; if (!dbus_message_iter_close_container (hashdata->iter, &subiter)) @@ -1488,7 +1685,7 @@ marshal_map_entry (const GValue *key, static gboolean marshal_map (DBusMessageIter *iter, - GValue *value) + const GValue *value) { GType gtype; DBusMessageIter arr_iter; @@ -1545,7 +1742,7 @@ marshal_map (DBusMessageIter *iter, static gboolean marshal_variant (DBusMessageIter *iter, - GValue *value) + const GValue *value) { GType value_gtype; DBusMessageIter subiter; @@ -1582,29 +1779,106 @@ marshal_variant (DBusMessageIter *iter, return ret; } +static DBusGValueMarshalFunc +get_type_marshaller (GType type) +{ + DBusGTypeMarshalData *typedata; + + typedata = g_type_get_qdata (type, dbus_g_type_metadata_data_quark ()); + if (typedata == NULL) + { + if (g_type_is_a (type, DBUS_TYPE_G_VALUE)) + return marshal_recurse; + if (dbus_g_type_is_collection (type)) + return marshal_collection; + + g_warning ("No marshaller registered for type \"%s\"", g_type_name (type)); + return NULL; + } + g_assert (typedata->vtable); + return typedata->vtable->marshaller; +} + +typedef struct +{ + DBusMessageIter *iter; + DBusGValueMarshalFunc marshaller; + gboolean err; +} DBusGValueCollectionMarshalData; + +static void +collection_marshal_iterator (const GValue *eltval, + gpointer user_data) +{ + DBusGValueCollectionMarshalData *data = user_data; + + if (data->err) + return; + + if (!data->marshaller (data->iter, eltval)) + data->err = TRUE; +} + +static gboolean +marshal_collection (DBusMessageIter *iter, + const GValue *value) +{ + GType coltype; + GType elt_gtype; + DBusGValueCollectionMarshalData data; + DBusMessageIter subiter; + char *elt_sig; + + coltype = G_VALUE_TYPE (value); + elt_gtype = dbus_g_type_get_collection_specialization (coltype); + data.marshaller = get_type_marshaller (elt_gtype); + if (!data.marshaller) + return FALSE; + + /* FIXME - this means we can't send an array of DBusGValue right now... */ + elt_sig = dbus_gtype_to_signature (elt_gtype); + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_ARRAY, + elt_sig, + &subiter)) + goto oom; + g_free (elt_sig); + + data.iter = &subiter; + data.err = FALSE; + + dbus_g_type_collection_value_iterate (value, + collection_marshal_iterator, + &data); + + if (!dbus_message_iter_close_container (iter, &subiter)) + goto oom; + + return !data.err; + oom: + g_error ("out of memory"); + return FALSE; +} + static gboolean marshal_recurse (DBusMessageIter *iter, - GValue *value) + const GValue *value) { return FALSE; } gboolean dbus_gvalue_marshal (DBusMessageIter *iter, - GValue *value) + const GValue *value) { GType gtype; - DBusGTypeMarshalData *typedata; + DBusGValueMarshalFunc marshaller; gtype = G_VALUE_TYPE (value); - typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); - if (typedata == NULL) - { - if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE)) - return marshal_recurse (iter, value); - return FALSE; - } - g_assert (typedata->vtable); - return typedata->vtable->marshaller (iter, value); + marshaller = get_type_marshaller (gtype); + if (marshaller == NULL) + return FALSE; + return marshaller (iter, value); } diff --git a/glib/dbus-gvalue.h b/glib/dbus-gvalue.h index 54ef780b..99cfd07b 100644 --- a/glib/dbus-gvalue.h +++ b/glib/dbus-gvalue.h @@ -22,7 +22,7 @@ GType dbus_gtype_from_signature (const char *signatur GType dbus_gtype_from_signature_iter (DBusSignatureIter *sigiter, gboolean is_client); -const char * dbus_gtype_to_signature (GType type); +char * dbus_gtype_to_signature (GType type); GArray * dbus_gtypes_from_arg_signature (const char *signature, gboolean is_client); @@ -44,7 +44,7 @@ GValueArray * dbus_gvalue_demarshal_message (DBusGValueMarshalCtx *context, GError **error); gboolean dbus_gvalue_marshal (DBusMessageIter *iter, - GValue *value); + const GValue *value); G_END_DECLS diff --git a/glib/examples/Makefile.am b/glib/examples/Makefile.am index 2ba133e6..7592cacc 100644 --- a/glib/examples/Makefile.am +++ b/glib/examples/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = . statemachine + INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) -DDBUS_COMPILATION ## Makefile.am bits for sample client/server pair diff --git a/glib/examples/example-service.c b/glib/examples/example-service.c index 0ad700cd..d1f8c62e 100644 --- a/glib/examples/example-service.c +++ b/glib/examples/example-service.c @@ -106,6 +106,8 @@ main (int argc, char **argv) g_type_init (); + dbus_g_object_type_install_info (SOME_TYPE_OBJECT, &dbus_glib_some_object_object_info); + mainloop = g_main_loop_new (NULL, FALSE); bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); @@ -126,8 +128,6 @@ main (int argc, char **argv) obj = g_object_new (SOME_TYPE_OBJECT, NULL); - dbus_g_object_type_install_info (SOME_TYPE_OBJECT, &dbus_glib_some_object_object_info); - dbus_g_connection_register_g_object (bus, "/SomeObject", G_OBJECT (obj)); printf ("service running\n"); diff --git a/glib/examples/example-signal-emitter.c b/glib/examples/example-signal-emitter.c index 13b9c9f7..d1cc444c 100644 --- a/glib/examples/example-signal-emitter.c +++ b/glib/examples/example-signal-emitter.c @@ -99,6 +99,8 @@ main (int argc, char **argv) guint request_name_result; g_type_init (); + + dbus_g_object_type_install_info (TEST_TYPE_OBJECT, &dbus_glib_test_object_object_info); mainloop = g_main_loop_new (NULL, FALSE); @@ -120,8 +122,6 @@ main (int argc, char **argv) obj = g_object_new (TEST_TYPE_OBJECT, NULL); - dbus_g_object_type_install_info (TEST_TYPE_OBJECT, &dbus_glib_test_object_object_info); - dbus_g_connection_register_g_object (bus, "/org/designfu/TestService/object", G_OBJECT (obj)); printf ("test service running\n"); diff --git a/glib/examples/statemachine/.cvsignore b/glib/examples/statemachine/.cvsignore new file mode 100644 index 00000000..b1f9981d --- /dev/null +++ b/glib/examples/statemachine/.cvsignore @@ -0,0 +1,15 @@ +.deps +.libs +Makefile +Makefile.in +*.lo +*.la +statemachine-client +statemachine-server +statemachine-glue.h +run-with-tmp-session-bus.conf +sm-marshal.[ch] +*.bb +*.bbg +*.da +*.gcov diff --git a/glib/examples/statemachine/Makefile.am b/glib/examples/statemachine/Makefile.am new file mode 100644 index 00000000..11140b13 --- /dev/null +++ b/glib/examples/statemachine/Makefile.am @@ -0,0 +1,35 @@ +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GTK_THREADS_CFLAGS) -DDBUS_COMPILATION + +## Makefile.am bits for sample client/server pair + +noinst_PROGRAMS= statemachine-server + +if HAVE_GTK +noinst_PROGRAMS += statemachine-client +endif + +EXTRA_DIST = statemachine.h statemachine-server.h sm-marshal.list + +statemachine_server_SOURCES= statemachine-server.c sm-marshal.c statemachine.c +statemachine_server_LDADD= $(top_builddir)/glib/libdbus-glib-1.la + +statemachine_client_SOURCES= statemachine-client.c sm-marshal.c statemachine.h +statemachine_client_LDADD= $(top_builddir)/glib/libdbus-glib-1.la $(DBUS_GTK_THREADS_LIBS) + +BUILT_SOURCES = statemachine-server-glue.h statemachine-glue.h + +statemachine-server-glue.h: statemachine-server.xml + $(top_builddir)/glib/dbus-binding-tool --prefix=sm_server --mode=glib-server --output=$@ $< + +statemachine-glue.h: statemachine.xml + $(top_builddir)/glib/dbus-binding-tool --prefix=sm_object --mode=glib-server --output=$@ $< + +sm-marshal.c: Makefile sm-marshal.list + @GLIB_GENMARSHAL@ --prefix=sm_marshal $(srcdir)/sm-marshal.list --header --body > $@.tmp && mv $@.tmp $@ + +sm-marshal.h: Makefile sm-marshal.list + @GLIB_GENMARSHAL@ --prefix=sm_marshal $(srcdir)/sm-marshal.list --header > $@.tmp && mv $@.tmp $@ + +BUILT_SOURCES += sm-marshal.c sm-marshal.h + +CLEANFILES = $(BUILT_SOURCES) diff --git a/glib/examples/statemachine/sm-marshal.list b/glib/examples/statemachine/sm-marshal.list new file mode 100644 index 00000000..e72aa4bc --- /dev/null +++ b/glib/examples/statemachine/sm-marshal.list @@ -0,0 +1 @@ +VOID:STRING,BOXED diff --git a/glib/examples/statemachine/statemachine-client.c b/glib/examples/statemachine/statemachine-client.c new file mode 100644 index 00000000..54c630ff --- /dev/null +++ b/glib/examples/statemachine/statemachine-client.c @@ -0,0 +1,540 @@ +#include +#include +#include +#include +#include +#include +#include "sm-marshal.h" + +static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2); +static void lose_gerror (const char *prefix, GError *error) G_GNUC_NORETURN; + +static void +lose (const char *str, ...) +{ + va_list args; + GtkWidget *dialog; + char *text; + + va_start (args, str); + + text = g_strdup_vprintf (str, args); + + va_end (args); + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", + text); + gtk_dialog_run (GTK_DIALOG (dialog)); + + g_free (text); + + exit (1); +} + +static void +lose_gerror (const char *prefix, GError *error) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", + prefix); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + + gtk_dialog_run (GTK_DIALOG (dialog)); + + exit (1); +} + +typedef struct +{ + char *name; + char *state; + DBusGProxy *proxy; + DBusGProxyCall *get_initial_state_call; +} MachineInfo; + +typedef struct +{ + GtkWindow *window; + GtkWidget *view; + GtkTreeModel *store; + + DBusGConnection *bus; + DBusGProxy *server_proxy; + + GSList *pending_creation_calls; + DBusGProxyCall *get_machines_call; +} ClientState; + +static gboolean +proxy_to_iter (GtkTreeModel *model, DBusGProxy *proxy, GtkTreeIter *iter) +{ + if (!gtk_tree_model_get_iter_first (model, iter)) + return FALSE; + do { + MachineInfo *info; + gtk_tree_model_get (model, iter, 0, &info, -1); + if (info->proxy == proxy) + return TRUE; + } while (gtk_tree_model_iter_next (model, iter)); + return FALSE; +} + +static void +get_machine_info_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer data) +{ + GtkTreeIter iter; + ClientState *state = data; + GError *error = NULL; + char *name, *statename; + MachineInfo *info; + + if (!dbus_g_proxy_end_call (proxy, call, &error, + G_TYPE_STRING, &name, + G_TYPE_STRING, &statename, + G_TYPE_INVALID)) + lose_gerror ("Couldn't complete GetInfo", error); + + if (!proxy_to_iter (state->store, proxy, &iter)) + g_assert_not_reached (); + + gtk_tree_model_get (state->store, &iter, 0, &info, -1); + g_free (info->name); + info->name = name; + g_free (info->state); + info->state = statename; + { + GtkTreePath *path; + path = gtk_tree_model_get_path (state->store, &iter); + gtk_tree_model_row_changed (state->store, path, &iter); + gtk_tree_path_free (path); + } + info->get_initial_state_call = NULL; +} + +static void +proxy_state_changed_cb (DBusGProxy *proxy, + const char *statename, + gpointer user_data) +{ + MachineInfo *info; + GtkTreeIter iter; + ClientState *state = user_data; + + if (!proxy_to_iter (state->store, proxy, &iter)) + g_assert_not_reached (); + gtk_tree_model_get (state->store, &iter, 0, &info, -1); + + g_print ("Got state change for %p (%s) to %s\n", proxy, info->name ? info->name : "(unknown)", statename); + + /* If we got a signal for the state, we shouldn't update + * based on the (possibly stale) call + */ + if (info->get_initial_state_call != NULL) + { + g_print ("Cancelling outstanding GetInfo call for %p due to signal\n", proxy); + dbus_g_proxy_cancel_call (proxy, info->get_initial_state_call); + info->get_initial_state_call = NULL; + } + + g_free (info->state); + info->state = g_strdup (statename); + + { + GtkTreePath *path; + path = gtk_tree_model_get_path (state->store, &iter); + gtk_tree_model_row_changed (state->store, path, &iter); + gtk_tree_path_free (path); + } +} + +static void +add_machine (ClientState *state, + const char *name, + const char *mstate, + const char *path) +{ + MachineInfo *info; + GtkTreeIter iter; + + info = g_new0 (MachineInfo, 1); + info->name = g_strdup (name); + info->state = g_strdup (mstate); + + info->proxy = dbus_g_proxy_new_for_name (state->bus, + "com.example.StateServer", + path, + "com.example.StateMachine"); + + if (!info->state) + { + g_print ("Starting GetInfo call for %p\n", info->proxy); + info->get_initial_state_call + = dbus_g_proxy_begin_call (info->proxy, "GetInfo", + get_machine_info_cb, + state, NULL, + G_TYPE_INVALID); + } + else + info->get_initial_state_call = NULL; + + /* Watch for state changes */ + dbus_g_proxy_add_signal (info->proxy, "StateChanged", + G_TYPE_STRING, G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (info->proxy, + "StateChanged", + G_CALLBACK (proxy_state_changed_cb), + state, + NULL); + + gtk_list_store_prepend (GTK_LIST_STORE (state->store), &iter); + gtk_list_store_set (GTK_LIST_STORE (state->store), &iter, 0, info, -1); + +} + +static void +machine_created_cb (DBusGProxy *proxy, + const char *name, + const char *path, + gpointer data) +{ + ClientState *state = data; + + add_machine (state, name, NULL, path); +} + +static void +server_destroyed_cb (DBusGProxy *proxy, gpointer data) +{ + g_print ("Server terminated!\n"); + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + "State Machine server has exited"); + + gtk_dialog_run (GTK_DIALOG (dialog)); + + exit (1); +} + +static void +window_destroyed_cb (GtkWidget *window, gpointer data) +{ + gtk_main_quit (); +} + +static void +create_machine_completed_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer data) +{ + GError *error = NULL; + ClientState *state = data; + + if (!dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) + { + /* Ignore NameInUse errors */ + if (dbus_g_error_has_name (error, "com.example.StateServer.NameInUse")) + ; + else + lose_gerror ("Failed to create new state machine", error); + } + g_print ("machine created successfully\n"); + state->pending_creation_calls = g_slist_remove (state->pending_creation_calls, call); +} + +static void +send_create_machine (ClientState *state) +{ + DBusGProxyCall *call; + char *name; + gint n_children; + + n_children = gtk_tree_model_iter_n_children (state->store, NULL); + name = g_strdup_printf ("machine%d", n_children); + + g_print ("Invoking CreateMachine(%s)\n", name); + call = dbus_g_proxy_begin_call (state->server_proxy, "CreateMachine", + create_machine_completed_cb, + state, NULL, + G_TYPE_STRING, name, G_TYPE_INVALID); + g_free (name); + state->pending_creation_calls = g_slist_prepend (state->pending_creation_calls, call); +} + +static void +do_a_state_change (ClientState *state) +{ + gint index; + GtkTreeIter iter; + gint n_children; + MachineInfo *info; + + n_children = gtk_tree_model_iter_n_children (state->store, NULL); + if (n_children == 0) + { + g_print ("No machines yet, not doing a state switch\n"); + return; + } + + index = g_random_int_range (0, n_children); + gtk_tree_model_iter_nth_child (state->store, &iter, NULL, index); + gtk_tree_model_get (state->store, &iter, 0, &info, -1); + + if (!info->state) + { + g_print ("Machine not yet in known state, skipping state switch\n"); + return; + } + + if (!strcmp (info->state, "Shutdown")) + { + g_print ("Sending Start request to machine %s\n", info->name); + dbus_g_proxy_call_no_reply (info->proxy, "Start", G_TYPE_INVALID); + } + else + { + g_print ("Sending Shutdown request to machine %s\n", info->name); + dbus_g_proxy_call_no_reply (info->proxy, "Shutdown", G_TYPE_INVALID); + } +} + +static gboolean +do_something_random_2 (gpointer data) +{ + ClientState *state = data; + do_a_state_change (state); + g_timeout_add (g_random_int_range (500, 3000), do_something_random_2, state); + return FALSE; +} + +static gboolean +do_something_random (gpointer data) +{ + ClientState *state = data; + gint n_children; + + switch (g_random_int_range (0, 2)) + { + case 0: + send_create_machine (state); + break; + case 1: + do_a_state_change (state); + break; + default: + g_assert_not_reached (); + } + + n_children = gtk_tree_model_iter_n_children (state->store, NULL); + if (n_children >= 8) + g_timeout_add (g_random_int_range (500, 3000), do_something_random_2, state); + else + g_timeout_add (g_random_int_range (500, 3000), do_something_random, state); + return FALSE; +} + +static void +set_cell_name (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) +{ + MachineInfo *info; + + gtk_tree_model_get (tree_model, iter, 0, &info, -1); + + g_object_set (cell, "text", info->name ? info->name : "", NULL); +} + +static gint +sort_by_name (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + MachineInfo *info_a, *info_b; + + gtk_tree_model_get (model, a, 0, &info_a, -1); + gtk_tree_model_get (model, b, 0, &info_b, -1); + + return strcmp (info_a->name ? info_a->name : "", + info_b ? info_b->name : ""); +} + +static void +set_cell_state (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) +{ + MachineInfo *info; + + gtk_tree_model_get (tree_model, iter, 0, &info, -1); + + g_object_set (cell, "text", info->state ? info->state : "", NULL); +} + +static gint +sort_by_state (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + MachineInfo *info_a, *info_b; + + gtk_tree_model_get (model, a, 0, &info_a, -1); + gtk_tree_model_get (model, b, 0, &info_b, -1); + + return strcmp (info_a->state ? info_a->state : "", + info_b ? info_b->state : ""); +} + +static void +get_machines_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer data) +{ + GError *error = NULL; + ClientState *state = data; + GPtrArray *objs; + guint i; + GtkWidget *scrolledwin; + GtkTreeViewColumn *col; + GtkCellRenderer *rend; + + g_assert (call == state->get_machines_call); + + if (!dbus_g_proxy_end_call (proxy, call, &error, + dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), + &objs, + G_TYPE_INVALID)) + lose_gerror ("Failed to get current machine list", error); + + gtk_container_remove (GTK_CONTAINER (state->window), + gtk_bin_get_child (GTK_BIN (state->window))); + + scrolledwin = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwin); + + state->store = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_POINTER)); + state->view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (state->store)); + gtk_widget_show (state->view); + gtk_container_add (GTK_CONTAINER (scrolledwin), state->view); + gtk_container_add (GTK_CONTAINER (state->window), scrolledwin); + + rend = gtk_cell_renderer_text_new (); + col = gtk_tree_view_column_new_with_attributes (_("Name"), + rend, + NULL); + gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_name, NULL, NULL); + gtk_tree_view_column_set_resizable (col, TRUE); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (state->store), + 0, sort_by_name, NULL, NULL); + gtk_tree_view_column_set_sort_column_id (col, 0); + gtk_tree_view_append_column (GTK_TREE_VIEW (state->view), col); + + rend = gtk_cell_renderer_text_new (); + col = gtk_tree_view_column_new_with_attributes (_("State"), + rend, + NULL); + gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_state, NULL, NULL); + gtk_tree_view_column_set_resizable (col, TRUE); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (state->store), + 0, sort_by_state, NULL, NULL); + gtk_tree_view_column_set_sort_column_id (col, 0); + gtk_tree_view_append_column (GTK_TREE_VIEW (state->view), col); + + for (i = 0; i < objs->len; i++) + { + add_machine (state, NULL, NULL, g_ptr_array_index (objs, i)); + g_free (g_ptr_array_index (objs, i)); + } + g_ptr_array_free (objs, TRUE); + + g_idle_add (do_something_random, state); +} + +int +main (int argc, char **argv) +{ + DBusGConnection *bus; + DBusGProxy *server; + GError *error = NULL; + ClientState state; + GtkWidget *label; + + gtk_init (&argc, &argv); + + g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL); + + state.window = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL)); + gtk_window_set_resizable (GTK_WINDOW (state.window), TRUE); + g_signal_connect (G_OBJECT (state.window), "destroy", + G_CALLBACK (window_destroyed_cb), + &state); + gtk_window_set_title (GTK_WINDOW (state.window), _("D-BUS State Machine Demo")); + gtk_window_set_default_size (GTK_WINDOW (state.window), 320, 240); + + label = gtk_label_new (""); + gtk_label_set_markup (GTK_LABEL (label), "Loading..."); + gtk_widget_show (label); + + gtk_container_add (GTK_CONTAINER (state.window), label); + + bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (!bus) + lose_gerror ("Couldn't connect to session bus", error); + + state.bus = bus; + + server = dbus_g_proxy_new_for_name_owner (bus, + "com.example.StateServer", + "/com/example/StateServer", + "com.example.StateMachineServer", + &error); + if (!server) + lose_gerror ("Couldn't find \"com.example.StateServer\"", error); + + state.server_proxy = server; + + g_signal_connect (server, "destroy", + G_CALLBACK (server_destroyed_cb), + &state); + + dbus_g_object_register_marshaller (sm_marshal_VOID__STRING_BOXED, + G_TYPE_NONE, G_TYPE_STRING, + DBUS_TYPE_G_OBJECT_PATH); + + dbus_g_proxy_add_signal (server, "MachineCreated", G_TYPE_STRING, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (server, "MachineCreated", + G_CALLBACK (machine_created_cb), + &state, NULL); + + state.get_machines_call = dbus_g_proxy_begin_call (server, "GetMachines", + get_machines_cb, &state, NULL, + G_TYPE_INVALID); + + gtk_widget_show (GTK_WIDGET (state.window)); + + gtk_main (); + + g_object_unref (G_OBJECT (server)); + + exit(0); +} diff --git a/glib/examples/statemachine/statemachine-server.c b/glib/examples/statemachine/statemachine-server.c new file mode 100644 index 00000000..7cadf1fe --- /dev/null +++ b/glib/examples/statemachine/statemachine-server.c @@ -0,0 +1,202 @@ +#include +#include +#include + +#include "statemachine.h" +#include "sm-marshal.h" +#include "statemachine-server.h" + +enum +{ + PROP_O, + PROP_BUS +}; + +enum +{ + MACHINE_CREATED, + LAST_SIGNAL +}; + +static guint sm_server_signals[LAST_SIGNAL] = { 0 }; + +static void sm_server_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void sm_server_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +G_DEFINE_TYPE(SMServer, sm_server, G_TYPE_OBJECT) + +#include "statemachine-server-glue.h" +#include "statemachine-glue.h" + +static void +sm_server_init (SMServer *obj) +{ + obj->machines = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); +} + +static void +sm_server_class_init (SMServerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = sm_server_set_property; + object_class->get_property = sm_server_get_property; + + g_object_class_install_property (object_class, + PROP_BUS, + g_param_spec_boxed ("bus", + "bus", + "bus", + DBUS_TYPE_G_CONNECTION, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + sm_server_signals[MACHINE_CREATED] = + g_signal_new ("machine-created", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + sm_marshal_VOID__STRING_BOXED, + G_TYPE_NONE, 2, G_TYPE_STRING, DBUS_TYPE_G_OBJECT_PATH); +} + +static void +sm_server_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SMServer *server = SM_SERVER (object); + + switch (prop_id) + { + case PROP_BUS: + server->bus = g_value_get_boxed (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +sm_server_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SMServer *server = SM_SERVER (object); + + switch (prop_id) + { + case PROP_BUS: + g_value_set_boxed (value, server->bus); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +gboolean +sm_server_create_machine (SMServer *server, const char *name, GError **error) +{ + SMObject *machine; + char *path; + + machine = g_hash_table_lookup (server->machines, name); + if (machine != NULL) + { + g_set_error (error, + SM_ERROR, + SM_ERROR_NAME_IN_USE, + "Statemachine name \"%s\" is already in use", + name); + return FALSE; + } + + machine = g_object_new (SM_TYPE_OBJECT, "name", name, NULL); + + path = g_strdup_printf ("/com/example/StateMachines/%s", name); + dbus_g_connection_register_g_object (server->bus, path, G_OBJECT (machine)); + + g_hash_table_insert (server->machines, g_strdup (name), machine); + + g_print ("Created state machine with name %s at %s\n", name, path); + + g_signal_emit (server, sm_server_signals[MACHINE_CREATED], 0, name, path); + + return TRUE; +} + +static void +add_machine_to_ptr_array (gpointer key, gpointer val, gpointer data) +{ + const char *name = key; + /* SMObject *sm = val; */ + GPtrArray *ptrarray = data; + + g_ptr_array_add (ptrarray, g_strdup_printf ("/com/example/StateMachines/%s", + name)); +} + +gboolean +sm_server_get_machines (SMServer *server, GPtrArray **machines, GError **error) +{ + *machines = g_ptr_array_new (); + + g_hash_table_foreach (server->machines, add_machine_to_ptr_array, *machines); + + return TRUE; +} + +int +main (int argc, char **argv) +{ + DBusGConnection *bus; + DBusGProxy *bus_proxy; + GError *error = NULL; + SMServer *server; + GMainLoop *mainloop; + guint request_name_result; + + g_type_init (); + + dbus_g_object_type_install_info (SM_TYPE_SERVER, &dbus_glib_sm_server_object_info); + dbus_g_object_type_install_info (SM_TYPE_OBJECT, &dbus_glib_sm_object_object_info); + dbus_g_error_domain_register (SM_ERROR, NULL, SM_TYPE_ERROR); + + mainloop = g_main_loop_new (NULL, FALSE); + + bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (!bus) + g_critical ("Couldn't connect to session bus: %s\n", error->message); + + bus_proxy = dbus_g_proxy_new_for_name (bus, "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus"); + + if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error, + G_TYPE_STRING, "com.example.StateServer", + G_TYPE_UINT, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT, + G_TYPE_INVALID, + G_TYPE_UINT, &request_name_result, + G_TYPE_INVALID)) + g_critical ("Couldn't acquire com.example.StateServer: %s\n", error->message); + + server = g_object_new (SM_TYPE_SERVER, "bus", bus, NULL); + + dbus_g_connection_register_g_object (bus, "/com/example/StateServer", G_OBJECT (server)); + + g_print ("StateMachine server initialized\n"); + + g_main_loop_run (mainloop); + + exit (0); +} diff --git a/glib/examples/statemachine/statemachine-server.h b/glib/examples/statemachine/statemachine-server.h new file mode 100644 index 00000000..360be3a6 --- /dev/null +++ b/glib/examples/statemachine/statemachine-server.h @@ -0,0 +1,37 @@ +#ifndef _SM_SERVER_H +#define _SM_SERVER_H + +#include "statemachine.h" +#include + +typedef struct SMServer SMServer; +typedef struct SMServerClass SMServerClass; + +struct SMServer +{ + GObject parent; + + /* Private */ + DBusGConnection *bus; + GHashTable *machines; +}; + +struct SMServerClass +{ + GObjectClass parent; +}; + +#define SM_TYPE_SERVER (sm_server_get_type ()) +#define SM_SERVER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SM_TYPE_SERVER, SMServer)) +#define SM_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SM_TYPE_SERVER, SMServerClass)) +#define SM_IS_SERVER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SM_TYPE_SERVER)) +#define SM_IS_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SM_TYPE_SERVER)) +#define SM_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SM_TYPE_SERVER, SMServerClass)) + +GType sm_server_get_type (void); + +gboolean sm_server_create_machine (SMServer *server, const char *name, GError **error); + +gboolean sm_server_get_machines (SMServer *server, GPtrArray **machines, GError **error); + +#endif diff --git a/glib/examples/statemachine/statemachine-server.xml b/glib/examples/statemachine/statemachine-server.xml new file mode 100644 index 00000000..fe9caaf7 --- /dev/null +++ b/glib/examples/statemachine/statemachine-server.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/glib/examples/statemachine/statemachine.c b/glib/examples/statemachine/statemachine.c new file mode 100644 index 00000000..2bde0058 --- /dev/null +++ b/glib/examples/statemachine/statemachine.c @@ -0,0 +1,351 @@ +#include +#include +#include "statemachine.h" + +static void clear_pending_tasks (SMObject *object); +static void state_change (SMObject *object, SMObjectState new_state); +static void sm_object_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void sm_object_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +enum +{ + PROP_0, + PROP_NAME, +}; + +enum +{ + STATE_CHANGED, + ACQUISITION_FAILED, + ACQUISITION_PROGRESS, + LAST_SIGNAL +}; + +static guint sm_object_signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(SMObject, sm_object, G_TYPE_OBJECT) + +static void +sm_object_init (SMObject *obj) +{ + obj->state = SM_OBJECT_STATE_SHUTDOWN; +} + +static void +sm_object_class_init (SMObjectClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = sm_object_set_property; + object_class->get_property = sm_object_get_property; + + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + "name", + "name", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + sm_object_signals[STATE_CHANGED] = + g_signal_new ("state-changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + sm_object_signals[ACQUISITION_PROGRESS] = + g_signal_new ("acquisition-progress", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__DOUBLE, + G_TYPE_NONE, 1, G_TYPE_DOUBLE); + sm_object_signals[ACQUISITION_FAILED] = + g_signal_new ("acquisition-failed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/* This should really be standard. */ +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GQuark +sm_error_quark (void) +{ + static GQuark ret = 0; + if (!ret) + ret = g_quark_from_static_string ("SMObjectErrorQuark"); + return ret; +} + +GType +sm_object_state_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) + { + static const GEnumValue values[] = + { + + ENUM_ENTRY (SM_OBJECT_STATE_SHUTDOWN, "Shutdown"), + ENUM_ENTRY (SM_OBJECT_STATE_INITIALIZED, "Loading"), + ENUM_ENTRY (SM_OBJECT_STATE_ACQUIRED, "Resource acquired"), + ENUM_ENTRY (SM_OBJECT_STATE_OPERATING, "Operating normally"), + { 0, 0, 0 } + }; + + etype = g_enum_register_static ("SMObjectState", values); + } + + return etype; +} + +GType +sm_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) + { + static const GEnumValue values[] = + { + + ENUM_ENTRY (SM_ERROR_INVALID_STATE, "InvalidState"), + ENUM_ENTRY (SM_ERROR_NAME_IN_USE, "NameInUse"), + { 0, 0, 0 } + }; + + g_assert (SM_NUM_ERRORS == G_N_ELEMENTS (values) - 1); + + etype = g_enum_register_static ("SMError", values); + } + + return etype; +} + +static void +sm_object_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SMObject *sm = SM_OBJECT (object); + + switch (prop_id) + { + case PROP_NAME: + sm->name = g_strdup (g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +sm_object_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SMObject *sm= SM_OBJECT (object); + + switch (prop_id) + { + case PROP_NAME: + g_value_set_string (value, sm->name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +queue_task (SMObject *object, guint delay, GSourceFunc func) +{ + guint id; + id = g_timeout_add (delay, func, object); + object->pending_tasks = g_slist_prepend (object->pending_tasks, GUINT_TO_POINTER (id)); +} + +static gboolean +idle_state_change (gpointer data) +{ + SMObject *object = data; + + state_change (object, object->requested_state); + return FALSE; +} + +static gboolean +idle_further_acquire (gpointer data) +{ + SMObject *object = data; + + object->acquisition_progress += g_random_double_range (0.05, 0.5); + if (object->acquisition_progress > 1.0) + { + object->acquisition_progress = 1.0; + return FALSE; + } + else + { + g_signal_emit (object, sm_object_signals[ACQUISITION_PROGRESS], 0, object->acquisition_progress); + return TRUE; + } +} + +static void +clear_pending_tasks (SMObject *object) +{ + GSList *tmp; + for (tmp = object->pending_tasks; tmp; tmp = tmp->next) + g_source_remove (GPOINTER_TO_UINT (tmp->data)); + g_slist_free (object->pending_tasks); + object->pending_tasks = NULL; +} + +static const char * +state_to_string (SMObjectState state) +{ + GEnumValue *value; + GEnumClass *prop_class; + const char *ret; + + prop_class = g_type_class_ref (SM_TYPE_OBJECT_STATE); + value = g_enum_get_value (prop_class, state); + ret = value->value_nick; + + g_type_class_unref (prop_class); + return ret; +} + +static void +state_change (SMObject *object, SMObjectState new_state) +{ + g_signal_emit (object, sm_object_signals[STATE_CHANGED], 0, + state_to_string (object->state), + state_to_string (new_state)); + + clear_pending_tasks (object); + + if (new_state == SM_OBJECT_STATE_ACQUIRED) + { + object->acquisition_progress = 0.0; + queue_task (object, 1000, idle_further_acquire); + } + else if (new_state == SM_OBJECT_STATE_INITIALIZED) + { + if (g_random_int_range (0, 2) == 0) + { + object->requested_state = SM_OBJECT_STATE_ACQUIRED; + queue_task (object, 3000, idle_state_change); + } + } + + object->state = new_state; +} + +gboolean +sm_object_get_info (SMObject *object, char **name, char **state, GError **error) +{ + *name= g_strdup (object->name); + *state = g_strdup (state_to_string (object->state)); + return TRUE; +} + +gboolean +sm_object_start (SMObject *object, GError **error) +{ + if (object->state != SM_OBJECT_STATE_SHUTDOWN) + { + g_set_error (error, + SM_ERROR, + SM_ERROR_INVALID_STATE, + "%s", + "Can't start from non-shutdown state"); + return FALSE; + } + state_change (object, SM_OBJECT_STATE_INITIALIZED); + return TRUE; +} + +gboolean +sm_object_shutdown (SMObject *object, GError **error) +{ + if (object->state != SM_OBJECT_STATE_INITIALIZED) + { + g_set_error (error, + SM_ERROR, + SM_ERROR_INVALID_STATE, + "%s", + "Can't shutdown from shutdown state"); + return FALSE; + } + state_change (object, SM_OBJECT_STATE_SHUTDOWN); + return TRUE; +} + +gboolean +sm_object_reinitialize (SMObject *object, GError **error) +{ + if (object->state != SM_OBJECT_STATE_ACQUIRED + && object->state != SM_OBJECT_STATE_OPERATING) + { + g_set_error (error, + SM_ERROR, + SM_ERROR_INVALID_STATE, + "Can't reinitialize from state %d", + object->state); + return FALSE; + } + state_change (object, SM_OBJECT_STATE_INITIALIZED); + return TRUE; +} + +gboolean +sm_object_reacquire (SMObject *object, GError **error) +{ + if (object->state != SM_OBJECT_STATE_ACQUIRED) + { + g_set_error (error, + SM_ERROR, + SM_ERROR_INVALID_STATE, + "Can't reacquire from state %d", + object->state); + return FALSE; + } + state_change (object, SM_OBJECT_STATE_ACQUIRED); + return TRUE; +} + +gboolean +sm_object_get_acquiring_progress (SMObject *object, gdouble *out, GError **error) +{ + if (object->state != SM_OBJECT_STATE_ACQUIRED) + { + g_set_error (error, + SM_ERROR, + SM_ERROR_INVALID_STATE, + "Can't get progress from state %d", + object->state); + return FALSE; + } + *out = object->acquisition_progress; + return TRUE; +} diff --git a/glib/examples/statemachine/statemachine.h b/glib/examples/statemachine/statemachine.h new file mode 100644 index 00000000..ac6047bd --- /dev/null +++ b/glib/examples/statemachine/statemachine.h @@ -0,0 +1,77 @@ +#ifndef _SM_OBJECT_H +#define _SM_OBJECT_H + +#include +#include + +GQuark sm_error_quark (void); + +#define SM_ERROR (sm_error_quark ()) + +typedef enum +{ + SM_ERROR_INVALID_STATE = 0, + SM_ERROR_NAME_IN_USE, + SM_NUM_ERRORS +} SMError; + +GType sm_error_get_type (void); +#define SM_TYPE_ERROR (sm_error_get_type ()) + +typedef enum +{ + SM_OBJECT_STATE_SHUTDOWN = 0, + SM_OBJECT_STATE_INITIALIZED, + SM_OBJECT_STATE_ACQUIRED, + SM_OBJECT_STATE_OPERATING, + SM_OBJECT_NUM_STATES +} SMObjectState; + +GType sm_object_state_get_type (void); + +#define SM_TYPE_OBJECT_STATE (sm_object_state_get_type ()) + +typedef struct SMObject SMObject; +typedef struct SMObjectClass SMObjectClass; + +struct SMObject +{ + GObject parent; + + /* Private */ + char *name; + SMObjectState state; + double acquisition_progress; + + GSList /* guint */ *pending_tasks; + + SMObjectState requested_state; +}; + +struct SMObjectClass +{ + GObjectClass parent; +}; + +#define SM_TYPE_OBJECT (sm_object_get_type ()) +#define SM_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SM_TYPE_OBJECT, SMObject)) +#define SM_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SM_TYPE_OBJECT, SMObjectClass)) +#define SM_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SM_TYPE_OBJECT)) +#define SM_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SM_TYPE_OBJECT)) +#define SM_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SM_TYPE_OBJECT, SMObjectClass)) + +GType sm_object_get_type (void); + +gboolean sm_object_get_info (SMObject *object, char **name, char **state, GError **error); + +gboolean sm_object_start (SMObject *object, GError **error); + +gboolean sm_object_shutdown (SMObject *object, GError **error); + +gboolean sm_object_reinitialize (SMObject *object, GError **error); + +gboolean sm_object_reacquire (SMObject *object, GError **error); + +gboolean sm_object_get_acquiring_progress (SMObject *object, gdouble *out, GError **error); + +#endif diff --git a/glib/examples/statemachine/statemachine.xml b/glib/examples/statemachine/statemachine.xml new file mode 100644 index 00000000..c375ef1b --- /dev/null +++ b/glib/examples/statemachine/statemachine.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/glib/test-dbus-glib.c b/test/glib/test-dbus-glib.c index cac774ce..69875703 100644 --- a/test/glib/test-dbus-glib.c +++ b/test/glib/test-dbus-glib.c @@ -195,6 +195,7 @@ echo_received_cb (DBusGProxy *proxy, lose_gerror ("Failed to complete async Echo", error); g_assert (echo_data != NULL); g_print ("Async echo gave \"%s\"", echo_data); + g_free (echo_data); g_main_loop_quit (loop); g_source_remove (exit_timeout); } @@ -899,6 +900,34 @@ main (int argc, char **argv) run_mainloop (); + { + GPtrArray *objs; + guint i; + + g_print ("Calling GetObjs\n"); + + if (!dbus_g_proxy_call (proxy, "GetObjs", &error, G_TYPE_INVALID, + dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), + &objs, + G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetObjs call", error); + if (objs->len != 2) + lose ("GetObjs call returned unexpected number of objects %d, expected 2", + objs->len); + + if (strcmp ("/org/freedesktop/DBus/Tests/MyTestObject", + g_ptr_array_index (objs, 0)) != 0) + lose ("GetObjs call returned unexpected path \"%s\" in position 0; expected /org/freedesktop/DBus/Tests/MyTestObject", (char*) g_ptr_array_index (objs, 0)); + + if (strcmp ("/org/freedesktop/DBus/Tests/MyTestObject2", + g_ptr_array_index (objs, 1)) != 0) + lose ("GetObjs call returned unexpected path \"%s\" in position 1; expected /org/freedesktop/DBus/Tests/MyTestObject2", (char*) g_ptr_array_index (objs, 1)); + + for (i = 0; i < objs->len; i++) + g_free (g_ptr_array_index (objs, i)); + g_ptr_array_free (objs, TRUE); + } + /* Signal handling tests */ g_print ("Testing signal handling\n"); diff --git a/test/glib/test-service-glib.c b/test/glib/test-service-glib.c index 84b57c68..a9e57926 100644 --- a/test/glib/test-service-glib.c +++ b/test/glib/test-service-glib.c @@ -65,6 +65,8 @@ gboolean my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **array, GE gboolean my_object_objpath (MyObject *obj, const char *in, char **arg1, GError **error); +gboolean my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error); + gboolean my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error); gboolean my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error); @@ -410,6 +412,17 @@ my_object_objpath (MyObject *obj, const char *incoming, char **outgoing, GError return TRUE; } +gboolean +my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error) +{ + *objs = g_ptr_array_new (); + + g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/Tests/MyTestObject")); + g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/Tests/MyTestObject2")); + + return TRUE; +} + static void hash_foreach (gpointer key, gpointer val, gpointer user_data) { diff --git a/test/glib/test-service-glib.xml b/test/glib/test-service-glib.xml index 58058626..272f7b23 100644 --- a/test/glib/test-service-glib.xml +++ b/test/glib/test-service-glib.xml @@ -74,6 +74,10 @@ + + + + diff --git a/tools/Makefile.am b/tools/Makefile.am index 71db5203..6a37198d 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -22,13 +22,8 @@ GTK_TOOLS= endif if HAVE_GLIB -noinst_PROGRAMS = print-introspect - -print_introspect_SOURCES = print-introspect.c -print_introspect_LDADD = $(top_builddir)/glib/libdbus-glib-1.la - -dbus-bus-introspect.xml: $(top_builddir)/bus/dbus-daemon dbus-launch print-introspect $(top_builddir)/bus/dbus-daemon - DBUS_TOP_BUILDDIR=$(top_builddir) $(srcdir)/run-with-tmp-session-bus.sh ./print-introspect org.freedesktop.DBus /org/freedesktop/DBus > dbus-bus-introspect.xml.tmp && mv dbus-bus-introspect.xml.tmp dbus-bus-introspect.xml +dbus-bus-introspect.xml: $(top_builddir)/bus/dbus-daemon dbus-launch dbus-send $(top_builddir)/bus/dbus-daemon Makefile + DBUS_TOP_BUILDDIR=$(top_builddir) $(srcdir)/run-with-tmp-session-bus.sh ./dbus-send --print-reply=literal --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.Introspectable.Introspect > dbus-bus-introspect.xml.tmp && mv dbus-bus-introspect.xml.tmp dbus-bus-introspect.xml endif bin_PROGRAMS=dbus-send $(GLIB_TOOLS) dbus-launch dbus-cleanup-sockets $(GTK_TOOLS) diff --git a/tools/print-introspect.c b/tools/print-introspect.c deleted file mode 100644 index 91052cf6..00000000 --- a/tools/print-introspect.c +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* gather-introspect.c Dump introspection data from service to stdout - * - * Copyright (C) 2005 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include - -#include - -static void -usage (char *name, int ecode) -{ - fprintf (stderr, "Usage: %s \n", name); - exit (ecode); -} - -int -main (int argc, char *argv[]) -{ - DBusGConnection *connection; - DBusGProxy *proxy; - GError *error; - const char *service; - const char *path; - char *introspect_data; - - if (argc != 3) - usage (argv[0], 1); - - service = argv[1]; - path = argv[2]; - - g_type_init (); - - error = NULL; - connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); - if (connection == NULL) - { - fprintf (stderr, "Failed to open connection to session bus: %s\n", - error->message); - g_clear_error (&error); - exit (1); - } - - proxy = dbus_g_proxy_new_for_name (connection, - service, path, - DBUS_INTERFACE_INTROSPECTABLE); - if (!dbus_g_proxy_call (proxy, "Introspect", &error, - G_TYPE_INVALID, - G_TYPE_STRING, &introspect_data, - G_TYPE_INVALID)) - { - fprintf (stderr, "Failed to get introspection data: %s\n", - error->message); - g_clear_error (&error); - exit (1); - } - - printf ("%s", introspect_data); - g_free (introspect_data); - - g_object_unref (proxy); - - exit (0); -} -- cgit