From ffc6f5cf9fdc774b9423e0aad234c240b6efee02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Fri, 9 Nov 2012 18:35:14 +0000 Subject: [PATCH] edbus: Implement DBus.Properties for services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch by: José Roberto de Souza SVN revision: 79035 --- .../complex_types_client_eina_value.c | 28 +- .../edbus/src/examples/complex_types_server.c | 116 ++---- legacy/edbus/src/lib/edbus_private_types.h | 5 + legacy/edbus/src/lib/edbus_service.c | 377 +++++++++++++++++- legacy/edbus/src/lib/edbus_service.h | 37 +- 5 files changed, 459 insertions(+), 104 deletions(-) diff --git a/legacy/edbus/src/examples/complex_types_client_eina_value.c b/legacy/edbus/src/examples/complex_types_client_eina_value.c index f5dcfb420e..2e9455f4ef 100644 --- a/legacy/edbus/src/examples/complex_types_client_eina_value.c +++ b/legacy/edbus/src/examples/complex_types_client_eina_value.c @@ -158,7 +158,7 @@ _property_changed(void *data, EDBus_Proxy *proxy, void *event_info) name = event->name; value = event->value; - if (!strcmp(name, "text")) + if (!strcmp(name, "text") || !strcmp(name, "Resp2")) { const char *txt; eina_value_get(value, &txt); @@ -189,18 +189,27 @@ _read_cache(void *data) Eina_Value *v; v = edbus_proxy_property_local_get(proxy, "text"); - eina_value_get(v, &txt); - printf("Read cache: [txt] = %s\n", txt); + if (v) + { + eina_value_get(v, &txt); + printf("Read cache: [txt] = %s\n", txt); + } v = edbus_proxy_property_local_get(proxy, "int32"); - eina_value_get(v, &num); - printf("Read cache: [int32] = %d\n", num); + if (v) + { + eina_value_get(v, &num); + printf("Read cache: [int32] = %d\n", num); + } v = edbus_proxy_property_local_get(proxy, "st"); - eina_value_struct_get(v, "arg0", &txt); - printf("Read cache: [st] %s | ", txt); - eina_value_struct_get(v, "arg1", &txt); - printf("%s\n", txt); + if (v) + { + eina_value_struct_get(v, "arg0", &txt); + printf("Read cache: [st] %s | ", txt); + eina_value_struct_get(v, "arg1", &txt); + printf("%s\n", txt); + } return EINA_FALSE; } @@ -258,6 +267,7 @@ main(void) EDBUS_PROXY_EVENT_PROPERTY_CHANGED, _property_changed, NULL); + edbus_proxy_properties_monitor(proxy, EINA_TRUE); ecore_timer_add(10, _read_cache, proxy); ecore_main_loop_begin(); diff --git a/legacy/edbus/src/examples/complex_types_server.c b/legacy/edbus/src/examples/complex_types_server.c index b958a4ee5d..05443a848e 100644 --- a/legacy/edbus/src/examples/complex_types_server.c +++ b/legacy/edbus/src/examples/complex_types_server.c @@ -6,6 +6,9 @@ #define IFACE "com.profusion.Test" static char *resp2; +/* dummy, incremented each time DBus.Properties.Get() is called */ +static int int32 = 35; +static Ecore_Timer *timer; static EDBus_Message * _receive_array(const EDBus_Service_Interface *iface, const EDBus_Message *msg) @@ -199,47 +202,31 @@ _double_container(const EDBus_Service_Interface *iface, const EDBus_Message *msg return reply; } -static EDBus_Message * -_properties_get(const EDBus_Service_Interface *iface, const EDBus_Message *msg) +static Eina_Bool +_properties_get(const EDBus_Service_Interface *iface, const char *propname, EDBus_Message_Iter *iter, EDBus_Message **error) { - EDBus_Message *reply; - char *interface, *property; - EDBus_Message_Iter *variant, *iter; - - if (!edbus_message_arguments_get(msg, "ss", &interface, &property)) + printf("Properties_get - %s\n", propname); + if (!strcmp(propname, "Resp2")) + edbus_message_iter_basic_append(iter, 's', resp2); + else if (!strcmp(propname, "text")) + edbus_message_iter_basic_append(iter, 's', "lalalala"); + else if (!strcmp(propname, "int32")) { - printf("Error on edbus_message_arguments_get()\n"); - return NULL; + edbus_message_iter_arguments_set(iter, "i", int32); + int32++; } - - if (strcmp(interface, IFACE)) + else if (!strcmp(propname, "st")) { - reply = edbus_message_error_new(msg, - "org.freedesktop.DBus.Error.UnknownInterface", - "Interface not found."); - return reply; + EDBus_Message_Iter *st; + edbus_message_iter_arguments_set(iter, "(ss)", &st); + edbus_message_iter_arguments_set(st, "ss", "string1", "string2"); + edbus_message_iter_container_close(iter, st); } - - if (strcmp(property, "Resp2")) - { - reply = edbus_message_error_new(msg, - "org.freedesktop.DBus.Error.UnknownProperty", - "Property not found."); - return reply; - } - - reply = edbus_message_method_return_new(msg); - iter = edbus_message_iter_get(reply); - variant = edbus_message_iter_container_new(iter, 'v', "s"); - edbus_message_iter_basic_append(variant, 's', resp2); - printf("get %s\n", resp2); - edbus_message_iter_container_close(iter, variant); - - return reply; + return EINA_TRUE; } static EDBus_Message * -_properties_set(const EDBus_Service_Interface *iface, const EDBus_Message *msg) +_properties_set(const EDBus_Service_Interface *iface, const char *propname, const EDBus_Message *msg) { EDBus_Message *reply; char *interface, *property, *type, *txt; @@ -251,24 +238,7 @@ _properties_set(const EDBus_Service_Interface *iface, const EDBus_Message *msg) return NULL; } - if (strcmp(interface, IFACE)) - { - reply = edbus_message_error_new(msg, - "org.freedesktop.DBus.Error.UnknownInterface", - "Interface not found."); - return reply; - } - - if (strcmp(property, "Resp2")) - { - reply = edbus_message_error_new(msg, - "org.freedesktop.DBus.Error.UnknownProperty", - "Property not found."); - return reply; - } - type = edbus_message_iter_signature_get(variant); - if (type[0] != 's') { reply = edbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidSignature", @@ -279,6 +249,7 @@ _properties_set(const EDBus_Service_Interface *iface, const EDBus_Message *msg) reply = edbus_message_method_return_new(msg); edbus_message_iter_arguments_get(variant, "s", &txt); + printf("Resp2 was set to: %s, previously was: %s\n", txt, resp2); free(type); free(resp2); resp2 = strdup(txt); @@ -319,38 +290,30 @@ static const EDBus_Method methods[] = { { } }; -static const EDBus_Method properties_methods[] = { - { - "Get", EDBUS_ARGS({"s", "interface"}, {"s", "property"}), - EDBUS_ARGS({"v", "value"}), _properties_get, 0 - }, - { - "Set", EDBUS_ARGS({"s", "interface"}, {"s", "property"}, {"v", "value"}), - NULL, _properties_set, 0 - }, +static const EDBus_Property properties[] = { + { "Resp2", "s", NULL, _properties_set }, + { "text", "s", NULL, NULL }, + { "int32", "i", NULL, NULL }, + { "st", "(ss)", NULL, NULL}, { } }; - -/* - * Temporary way to test the PropertiesChanged signal in FDO Properties - * interface. TODO: Remove me when service part is done. - */ -static const EDBus_Signal properties_signals[] = { - { "PropertiesChanged", - EDBUS_ARGS({"s", "interface"}, {"a{sv}", "data"}, {"as", "invalidate"}), 0 - }, - { } -}; - static const EDBus_Service_Interface_Desc iface_desc = { - IFACE, methods + IFACE, methods, NULL, properties, _properties_get }; +static Eina_Bool _emit_changed(void *data) +{ + EDBus_Service_Interface *iface = data; + edbus_service_property_changed(iface, "int32"); + return EINA_TRUE; +} + static void on_name_request(void *data, const EDBus_Message *msg, EDBus_Pending *pending) { unsigned int flag; + EDBus_Service_Interface *iface = data; resp2 = malloc(sizeof(char) * 5); strcpy(resp2, "test"); @@ -372,24 +335,29 @@ on_name_request(void *data, const EDBus_Message *msg, EDBus_Pending *pending) printf("error name already in use\n"); return; } + + timer = ecore_timer_add(3, _emit_changed, iface); } int main(void) { EDBus_Connection *conn; + EDBus_Service_Interface *iface; ecore_init(); edbus_init(); conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION); - edbus_service_interface_register(conn, PATH, &iface_desc); - edbus_name_request(conn, BUS, EDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, on_name_request, NULL); + iface = edbus_service_interface_register(conn, PATH, &iface_desc); + edbus_name_request(conn, BUS, EDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, + on_name_request, iface); ecore_main_loop_begin(); free(resp2); + ecore_timer_del(timer); edbus_connection_unref(conn); edbus_shutdown(); diff --git a/legacy/edbus/src/lib/edbus_private_types.h b/legacy/edbus/src/lib/edbus_private_types.h index a6c818fc78..3e47f64f47 100644 --- a/legacy/edbus/src/lib/edbus_private_types.h +++ b/legacy/edbus/src/lib/edbus_private_types.h @@ -150,6 +150,11 @@ struct _EDBus_Service_Interface const EDBus_Signal *signals; Eina_Array *sign_of_signals; EDBus_Service_Object *obj; + Eina_Hash *properties; + EDBus_Property_Set_Cb set_func; + EDBus_Property_Get_Cb get_func; + Ecore_Idler *idler_propschanged; + Eina_Array *props_changed; }; typedef struct _Signal_Argument diff --git a/legacy/edbus/src/lib/edbus_service.c b/legacy/edbus/src/lib/edbus_service.c index 278e647a54..ea41f8c493 100644 --- a/legacy/edbus/src/lib/edbus_service.c +++ b/legacy/edbus/src/lib/edbus_service.c @@ -51,6 +51,7 @@ static DBusObjectPathVTable vtable = { }; EDBus_Service_Interface *introspectable; +EDBus_Service_Interface *properties_iface; static void _introspect_append_signal(Eina_Strbuf *buf, const EDBus_Signal *sig) @@ -76,6 +77,23 @@ _introspect_append_signal(Eina_Strbuf *buf, const EDBus_Signal *sig) eina_strbuf_append(buf, ""); } +static void +_instrospect_append_property(Eina_Strbuf *buf, const EDBus_Property *prop, const EDBus_Service_Interface *iface) +{ + eina_strbuf_append_printf(buf, "name, prop->type); + if (iface->get_func || prop->get_func) + eina_strbuf_append(buf, "read"); + if (iface->set_func || prop->set_func) + eina_strbuf_append(buf, "write"); + eina_strbuf_append(buf, "\">"); + + if (prop->flags & EDBUS_PROPERTY_FLAG_DEPRECATED) + eina_strbuf_append(buf, DBUS_ANNOTATION_DEPRECATED); + + eina_strbuf_append(buf, ""); +} + static void _introspect_append_method(Eina_Strbuf *buf, const EDBus_Method *method) { @@ -122,6 +140,7 @@ static void _introspect_append_interface(Eina_Strbuf *buf, EDBus_Service_Interface *iface) { EDBus_Method *method; + EDBus_Property *prop; Eina_Iterator *iterator; unsigned short i; unsigned int size; @@ -136,9 +155,175 @@ _introspect_append_interface(Eina_Strbuf *buf, EDBus_Service_Interface *iface) for (i = 0; i < size; i++) _introspect_append_signal(buf, &iface->signals[i]); + iterator = eina_hash_iterator_data_new(iface->properties); + EINA_ITERATOR_FOREACH(iterator, prop) + _instrospect_append_property(buf, prop, iface); + eina_iterator_free(iterator); + eina_strbuf_append(buf, ""); } +static EDBus_Message * +_cb_property_get(const EDBus_Service_Interface *piface, const EDBus_Message *msg) +{ + const char *propname, *iface_name; + EDBus_Service_Object *obj = piface->obj; + EDBus_Service_Interface *iface; + EDBus_Property *prop; + EDBus_Message *reply, *error_reply = NULL; + EDBus_Message_Iter *main_iter, *variant; + Eina_Bool ret; + EDBus_Property_Get_Cb getter = NULL; + + if (!edbus_message_arguments_get(msg, "ss", &iface_name, &propname)) + return NULL; + + iface = eina_hash_find(obj->interfaces, iface_name); + if (!iface) + return edbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_INTERFACE, + "Interface not found."); + + prop = eina_hash_find(iface->properties, propname); + if (!prop) goto not_found; + + if (prop->get_func) + getter = prop->get_func; + else if (iface->get_func) + getter = iface->get_func; + + if (!getter) goto not_found; + + reply = edbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(reply, NULL); + + main_iter = edbus_message_iter_get(reply); + variant = edbus_message_iter_container_new(main_iter, 'v', prop->type); + + ret = getter(iface, propname, variant, &error_reply); + + if (ret) + { + edbus_message_iter_container_close(main_iter, variant); + return reply; + } + + edbus_message_unref(reply); + return error_reply; + +not_found: + return edbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_PROPERTY, + "Property not found."); +} + +static EDBus_Message * +_cb_property_getall(const EDBus_Service_Interface *piface, const EDBus_Message *msg) +{ + const char *iface_name; + EDBus_Service_Object *obj = piface->obj; + EDBus_Service_Interface *iface; + Eina_Iterator *iterator; + EDBus_Property *prop; + EDBus_Message *reply, *error_reply; + EDBus_Message_Iter *main_iter, *dict; + + if (!edbus_message_arguments_get(msg, "s", &iface_name)) + return NULL; + + iface = eina_hash_find(obj->interfaces, iface_name); + if (!iface) + return edbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_INTERFACE, + "Interface not found."); + + reply = edbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(reply, NULL); + main_iter = edbus_message_iter_get(reply); + if (!edbus_message_iter_arguments_set(main_iter, "a{sv}", &dict)) + { + edbus_message_unref(reply); + return NULL; + } + + iterator = eina_hash_iterator_data_new(iface->properties); + EINA_ITERATOR_FOREACH(iterator, prop) + { + EDBus_Message_Iter *entry, *var; + Eina_Bool ret; + EDBus_Property_Get_Cb getter = NULL; + + if (prop->get_func) + getter = prop->get_func; + else if (iface->get_func) + getter = iface->get_func; + + if (!getter) + continue; + + if (!edbus_message_iter_arguments_set(dict, "{sv}", &entry)) + continue; + + edbus_message_iter_basic_append(entry, 's', prop->name); + var = edbus_message_iter_container_new(entry, 'v', prop->type); + + ret = getter(iface, prop->name, var, &error_reply); + + if (!ret) + { + edbus_message_unref(reply); + reply = error_reply; + goto end; + } + + edbus_message_iter_container_close(entry, var); + edbus_message_iter_container_close(dict, entry); + } + edbus_message_iter_container_close(main_iter, dict); + +end: + eina_iterator_free(iterator); + return reply; +} + +static EDBus_Message * +_cb_property_set(const EDBus_Service_Interface *piface, const EDBus_Message *msg) +{ + const char *propname, *iface_name; + EDBus_Service_Object *obj = piface->obj; + EDBus_Service_Interface *iface; + EDBus_Property *prop; + EDBus_Message *reply; + EDBus_Message_Iter *main_iter; + EDBus_Property_Set_Cb setter = NULL; + + main_iter = edbus_message_iter_get(msg); + if (!edbus_message_iter_get_and_next(main_iter, 's', &iface_name) || + !edbus_message_iter_get_and_next(main_iter, 's', &propname)) + return NULL; + + dbus_message_iter_init(msg->dbus_msg, + &main_iter->dbus_iterator); + + iface = eina_hash_find(obj->interfaces, iface_name); + if (!iface) + return edbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_INTERFACE, + "Interface not found."); + + prop = eina_hash_find(iface->properties, propname); + if (!prop) + return edbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_PROPERTY, + "Property not found."); + + if (prop->set_func) + setter = prop->set_func; + else if (iface->set_func) + setter = iface->set_func; + + if (!setter) + return edbus_message_error_new(msg, DBUS_ERROR_PROPERTY_READ_ONLY, + "This property is read only"); + reply = setter(iface, propname, msg); + return reply; +} + static EDBus_Message * cb_introspect(const EDBus_Service_Interface *_iface, const EDBus_Message *message) { @@ -184,6 +369,7 @@ _introspectable_create(void) EINA_MAGIC_SET(introspectable, EDBUS_SERVICE_INTERFACE_MAGIC); introspectable->sign_of_signals = eina_array_new(1); + introspectable->properties = eina_hash_string_small_new(NULL); introspectable->name = eina_stringshare_add("org.freedesktop.DBus.Introspectable"); introspectable->methods = eina_hash_string_small_new(NULL); @@ -191,12 +377,63 @@ _introspectable_create(void) } static void -_introspectable_free(void) +_default_interfaces_free(void) { eina_hash_free(introspectable->methods); + eina_hash_free(introspectable->properties); eina_stringshare_del(introspectable->name); eina_array_free(introspectable->sign_of_signals); free(introspectable); + + eina_hash_free(properties_iface->methods); + eina_hash_free(properties_iface->properties); + eina_array_free(properties_iface->sign_of_signals); + free(properties_iface); +} + +static const EDBus_Method _property_methods[] = { + { + "Get", EDBUS_ARGS({"s", "interface"}, {"s", "property"}), + EDBUS_ARGS({"v", "value"}), _cb_property_get + }, + { + "Set", EDBUS_ARGS({"s", "interface"}, {"s", "property"}, {"v", "value"}), + NULL, _cb_property_set + }, + { + "GetAll", EDBUS_ARGS({"s", "interface"}), EDBUS_ARGS({"a{sv}", "props"}), + _cb_property_getall + } +}; + +static const EDBus_Signal _properties_signals[] = { + { + "PropertiesChanged", + EDBUS_ARGS({"s", "interface"}, {"a{sv}", "changed_properties"}, {"as", "invalidated_properties"}) + } +}; + +static void +_properties_create(void) +{ + properties_iface = calloc(1, sizeof(EDBus_Service_Interface)); + if (!properties_iface) return; + + properties_iface->sign_of_signals = eina_array_new(1); + properties_iface->properties = eina_hash_string_small_new(NULL); + properties_iface->name = EDBUS_FDO_INTERFACE_PROPERTIES; + properties_iface->methods = eina_hash_string_small_new(NULL); + EINA_MAGIC_SET(properties_iface, EDBUS_SERVICE_INTERFACE_MAGIC); + + eina_hash_add(properties_iface->methods, _property_methods[0].member, + &_property_methods[0]); + eina_hash_add(properties_iface->methods, _property_methods[1].member, + &_property_methods[1]); + eina_hash_add(properties_iface->methods, _property_methods[2].member, + &_property_methods[2]); + + properties_iface->signals = _properties_signals; + eina_array_push(properties_iface->sign_of_signals, "sa{sv}as"); } Eina_Bool @@ -204,6 +441,8 @@ edbus_service_init(void) { _introspectable_create(); EINA_SAFETY_ON_NULL_RETURN_VAL(introspectable, EINA_FALSE); + _properties_create(); + EINA_SAFETY_ON_NULL_RETURN_VAL(properties_iface, EINA_FALSE); return EINA_TRUE; } @@ -211,7 +450,7 @@ edbus_service_init(void) void edbus_service_shutdown(void) { - _introspectable_free(); + _default_interfaces_free(); } static EDBus_Service_Object * @@ -235,6 +474,7 @@ _edbus_service_object_add(EDBus_Connection *conn, const char *path) edbus_connection_cb_free_add(conn, _on_connection_free, obj); eina_hash_add(obj->interfaces, introspectable->name, introspectable); + eina_hash_add(obj->interfaces, properties_iface->name, properties_iface); return obj; } @@ -253,6 +493,7 @@ _edbus_service_interface_add(EDBus_Service_Object *obj, const char *interface) EINA_MAGIC_SET(iface, EDBUS_SERVICE_INTERFACE_MAGIC); iface->name = eina_stringshare_add(interface); iface->methods = eina_hash_string_superfast_new(NULL); + iface->properties = eina_hash_string_superfast_new(NULL); iface->obj = obj; eina_hash_add(obj->interfaces, iface->name, iface); return iface; @@ -292,12 +533,25 @@ _edbus_service_method_add(EDBus_Service_Interface *interface, EDBus_Method *meth return EINA_TRUE; } +static Eina_Bool +_edbus_service_property_add(EDBus_Service_Interface *interface, EDBus_Property *property) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL(!!eina_hash_find(interface->properties, + property->name), EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(property->type, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL( + dbus_signature_validate_single(property->type, NULL), EINA_FALSE); + + return eina_hash_add(interface->properties, property->name, property); +} + EAPI EDBus_Service_Interface * edbus_service_interface_register(EDBus_Connection *conn, const char *path, const EDBus_Service_Interface_Desc *desc) { EDBus_Service_Object *obj; EDBus_Service_Interface *iface; EDBus_Method *method; + EDBus_Property *property; unsigned short i, z; Eina_Strbuf *buf = NULL; @@ -352,6 +606,13 @@ edbus_service_interface_register(EDBus_Connection *conn, const char *path, const } iface->signals = desc->signals; + for (property = (EDBus_Property *)desc->properties; + property && property->name; property++) + _edbus_service_property_add(iface, property); + + iface->get_func = desc->default_get; + iface->set_func = desc->default_set; + return iface; } @@ -359,7 +620,7 @@ static void _interface_free(EDBus_Service_Interface *interface) { unsigned size, i; - if (interface == introspectable) return; + if (interface == introspectable || interface == properties_iface) return; eina_hash_free(interface->methods); eina_stringshare_del(interface->name); @@ -367,6 +628,11 @@ _interface_free(EDBus_Service_Interface *interface) for (i = 0; i < size; i++) eina_stringshare_del(eina_array_data_get(interface->sign_of_signals, i)); eina_array_free(interface->sign_of_signals); + eina_hash_free(interface->properties); + if (interface->props_changed) + eina_array_free(interface->props_changed); + if (interface->idler_propschanged) + ecore_idler_del(interface->idler_propschanged); free(interface); } @@ -402,7 +668,7 @@ edbus_service_interface_unregister(EDBus_Service_Interface *iface) { EDBUS_SERVICE_INTERFACE_CHECK(iface); eina_hash_del(iface->obj->interfaces, NULL, iface); - if (eina_hash_population(iface->obj->interfaces) < 2) + if (eina_hash_population(iface->obj->interfaces) < 3) edbus_service_object_unregister(iface); _interface_free(iface); } @@ -585,3 +851,106 @@ edbus_service_object_data_del(EDBus_Service_Interface *iface, const char *key) EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL); return edbus_data_del(&(((EDBus_Service_Object *)iface->obj)->data), key); } + +static Eina_Bool +_idler_propschanged(void *data) +{ + EDBus_Service_Interface *iface = data; + EDBus_Message *msg; + EDBus_Message_Iter *main_iter, *dict, *array_invalidate; + Eina_Hash *added = NULL; + EDBus_Property *prop; + + iface->idler_propschanged = NULL; + + added = eina_hash_string_small_new(NULL); + msg = edbus_message_signal_new(iface->obj->path, properties_iface->name, + properties_iface->signals[0].name); + EINA_SAFETY_ON_NULL_GOTO(msg, error); + + main_iter = edbus_message_iter_get(msg); + if (!edbus_message_iter_arguments_set(main_iter, "sa{sv}", iface->name, &dict)) + { + edbus_message_unref(msg); + goto error; + } + + if (!iface->props_changed) + goto invalidate; + while ((prop = eina_array_pop(iface->props_changed))) + { + EDBus_Message_Iter *entry, *var; + EDBus_Message *error_reply; + Eina_Bool ret; + EDBus_Property_Get_Cb getter = NULL; + + if (eina_hash_find(added, prop->name)) + continue; + eina_hash_add(added, prop->name, prop); + + if (prop->get_func) + getter = prop->get_func; + else if (iface->get_func) + getter = iface->get_func; + + if (!getter) + continue; + + EINA_SAFETY_ON_FALSE_GOTO( + edbus_message_iter_arguments_set(dict, "{sv}", &entry), error); + + edbus_message_iter_basic_append(entry, 's', prop->name); + var = edbus_message_iter_container_new(entry, 'v', prop->type); + + ret = getter(iface, prop->name, var, &error_reply); + + if (!ret) + { + const char *errorname, *errormsg; + if (error_reply && + edbus_message_error_get(error_reply, &errorname, &errormsg)) + ERR("%s %s", errorname, errormsg); + + edbus_message_unref(msg); + if (error_reply) edbus_message_unref(error_reply); + goto error; + } + + edbus_message_iter_container_close(entry, var); + edbus_message_iter_container_close(dict, entry); + } +invalidate: + edbus_message_iter_container_close(main_iter, dict); + + edbus_message_iter_arguments_set(main_iter, "as", &array_invalidate); + edbus_message_iter_container_close(main_iter, array_invalidate); + + edbus_service_signal_send(iface, msg); + edbus_message_unref(msg); +error: + if (added) + eina_hash_free(added); + if (iface->props_changed) + eina_array_flush(iface->props_changed); + return ECORE_CALLBACK_CANCEL; +} + +EAPI Eina_Bool +edbus_service_property_changed(EDBus_Service_Interface *iface, const char *name) +{ + EDBus_Property *prop; + EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); + + prop = eina_hash_find(iface->properties, name); + EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE); + + if (!iface->idler_propschanged) + { + iface->idler_propschanged = ecore_idler_add(_idler_propschanged, iface); + if (!iface->props_changed) + iface->props_changed = eina_array_new(1); + } + + return eina_array_push(iface->props_changed, prop); +} diff --git a/legacy/edbus/src/lib/edbus_service.h b/legacy/edbus/src/lib/edbus_service.h index 4a260cddca..761797cede 100644 --- a/legacy/edbus/src/lib/edbus_service.h +++ b/legacy/edbus/src/lib/edbus_service.h @@ -11,6 +11,8 @@ #define EDBUS_SIGNAL_FLAG_DEPRECATED 1 +#define EDBUS_PROPERTY_FLAG_DEPRECATED 1 + typedef struct _EDBus_Arg_Info { const char *signature; @@ -29,8 +31,8 @@ typedef struct _EDBus_Arg_Info typedef struct _EDBus_Service_Interface EDBus_Service_Interface; typedef EDBus_Message * (*EDBus_Method_Cb)(const EDBus_Service_Interface *iface, const EDBus_Message *message); -typedef Eina_Bool (*EDBus_Property_Get_Cb)(EDBus_Service_Interface *iface, const char *propname, EDBus_Message_Iter *iter, EDBus_Message **error); -typedef EDBus_Message *(*EDBus_Property_Set_Cb)(EDBus_Service_Interface *iface, const char *propname, EDBus_Message *input_msg); +typedef Eina_Bool (*EDBus_Property_Get_Cb)(const EDBus_Service_Interface *iface, const char *propname, EDBus_Message_Iter *iter, EDBus_Message **error); +typedef EDBus_Message *(*EDBus_Property_Set_Cb)(const EDBus_Service_Interface *iface, const char *propname, const EDBus_Message *input_msg); typedef struct _EDBus_Method { @@ -52,19 +54,19 @@ typedef struct _EDBus_Property { const char *name; const char *type; - unsigned int flags; - EDBus_Property_Set_Cb set_func; EDBus_Property_Get_Cb get_func; + EDBus_Property_Set_Cb set_func; + unsigned int flags; } EDBus_Property; typedef struct _EDBus_Service_Interface_Desc { - const char *interface; - const EDBus_Method *methods; - const EDBus_Signal *signals; - const EDBus_Property *properties; - const EDBus_Property_Set_Cb default_set; - const EDBus_Property_Get_Cb default_get; + const char *interface; /**< interface name */ + const EDBus_Method *methods; /**< array of the methods that should be registered in this interface, the last item of array should be filled with NULL */ + const EDBus_Signal *signals; /**< array of signal that this interface send, the last item of array should be filled with NULL */ + const EDBus_Property *properties; /**< array of property that this interface have, the last item of array should be filled with NULL */ + const EDBus_Property_Get_Cb default_get; /**< default get function, if a property don't have a get function this will be used */ + const EDBus_Property_Set_Cb default_set; /**< default set function, if a property don't have a set function this will be used */ } EDBus_Service_Interface_Desc; /** @@ -72,13 +74,7 @@ typedef struct _EDBus_Service_Interface_Desc * * @param conn where the interface should listen * @param path object path - * @param iface interface - * @param methods array of the methods that should be registered in this - * interface, the last item of array should be filled with NULL - * @param signals array of signal that this interface send, the last item - * of array should be filled with NULL - * - * @note methods and signals must be static variables + * @param desc description of interface * * @return Interface */ @@ -150,6 +146,13 @@ EAPI void *edbus_service_object_data_get(const EDBus_Service_Interface *iface, c * @return pointer to data if found otherwise NULL */ EAPI void *edbus_service_object_data_del(EDBus_Service_Interface *iface, const char *key); + +/** + * Add property to changed list. * + * A PropertiesChanged signal will be send on next idler iteration with all + * properties in changed list. + */ +EAPI Eina_Bool edbus_service_property_changed(EDBus_Service_Interface *iface, const char *name); /** * @} */