#ifdef HAVE_CONFIG_H # include "config.h" #endif #include "eldbus_private.h" #include "eldbus_private_types.h" /* TODO: mempool of Eldbus_Proxy, Eldbus_Proxy_Context_Event_Cb and * Eldbus_Proxy_Context_Event */ typedef struct _Eldbus_Proxy_Context_Event_Cb { EINA_INLIST; Eldbus_Proxy_Event_Cb cb; const void *cb_data; Eina_Bool deleted : 1; } Eldbus_Proxy_Context_Event_Cb; typedef struct _Eldbus_Proxy_Context_Event { Eina_Inlist *list; int walking; Eina_List *to_delete; } Eldbus_Proxy_Context_Event; struct _Eldbus_Proxy { EINA_MAGIC; int refcount; Eldbus_Object *obj; const char *interface; Eina_Inlist *pendings; Eina_List *handlers; Eina_Inlist *cbs_free; Eina_Inlist *data; Eldbus_Proxy_Context_Event event_handlers[ELDBUS_PROXY_EVENT_LAST]; Eina_Hash *props; Eldbus_Signal_Handler *properties_changed; Eina_Bool monitor_enabled:1; }; #define ELDBUS_PROXY_CHECK(proxy) \ do \ { \ EINA_SAFETY_ON_NULL_RETURN(proxy); \ if (!EINA_MAGIC_CHECK(proxy, ELDBUS_PROXY_MAGIC)) \ { \ EINA_MAGIC_FAIL(proxy, ELDBUS_PROXY_MAGIC); \ return; \ } \ EINA_SAFETY_ON_TRUE_RETURN(proxy->refcount <= 0); \ } \ while (0) #define ELDBUS_PROXY_CHECK_RETVAL(proxy, retval) \ do \ { \ EINA_SAFETY_ON_NULL_RETURN_VAL(proxy, retval); \ if (!EINA_MAGIC_CHECK(proxy, ELDBUS_PROXY_MAGIC)) \ { \ EINA_MAGIC_FAIL(proxy, ELDBUS_PROXY_MAGIC); \ return retval; \ } \ EINA_SAFETY_ON_TRUE_RETURN_VAL(proxy->refcount <= 0, retval); \ } \ while (0) #define ELDBUS_PROXY_CHECK_GOTO(proxy, label) \ do \ { \ EINA_SAFETY_ON_NULL_GOTO(proxy, label); \ if (!EINA_MAGIC_CHECK(proxy, ELDBUS_PROXY_MAGIC)) \ { \ EINA_MAGIC_FAIL(proxy, ELDBUS_PROXY_MAGIC); \ goto label; \ } \ EINA_SAFETY_ON_TRUE_GOTO(proxy->refcount <= 0, label); \ } \ while (0) Eina_Bool eldbus_proxy_init(void) { return EINA_TRUE; } void eldbus_proxy_shutdown(void) { } static void _eldbus_proxy_event_callback_call(Eldbus_Proxy *proxy, Eldbus_Proxy_Event_Type type, const void *event_info); static void _eldbus_proxy_context_event_cb_del(Eldbus_Proxy_Context_Event *ce, Eldbus_Proxy_Context_Event_Cb *ctx); static void _on_signal_handler_free(void *data, const void *dead_pointer); static void _eldbus_proxy_call_del(Eldbus_Proxy *proxy) { Eldbus_Proxy_Context_Event *ce; _eldbus_proxy_event_callback_call(proxy, ELDBUS_PROXY_EVENT_DEL, NULL); /* clear all del callbacks so we don't call them twice at * _eldbus_proxy_clear() */ ce = proxy->event_handlers + ELDBUS_PROXY_EVENT_DEL; while (ce->list) { Eldbus_Proxy_Context_Event_Cb *ctx; ctx = EINA_INLIST_CONTAINER_GET(ce->list, Eldbus_Proxy_Context_Event_Cb); _eldbus_proxy_context_event_cb_del(ce, ctx); } } static void _eldbus_proxy_clear(Eldbus_Proxy *proxy) { Eldbus_Signal_Handler *h; Eldbus_Pending *p; Eina_List *iter, *iter_next; Eina_Inlist *in_l; DBG("proxy=%p, refcount=%d, interface=%s, obj=%p", proxy, proxy->refcount, proxy->interface, proxy->obj); proxy->refcount = 1; eldbus_object_proxy_del(proxy->obj, proxy, proxy->interface); _eldbus_proxy_call_del(proxy); EINA_LIST_FOREACH_SAFE(proxy->handlers, iter, iter_next, h) { DBG("proxy=%p delete owned signal handler %p %s", proxy, h, eldbus_signal_handler_match_get(h)); eldbus_signal_handler_del(h); } EINA_INLIST_FOREACH_SAFE(proxy->pendings, in_l, p) { DBG("proxy=%p delete owned pending call=%p dest=%s path=%s %s.%s()", proxy, p, eldbus_pending_destination_get(p), eldbus_pending_path_get(p), eldbus_pending_interface_get(p), eldbus_pending_method_get(p)); eldbus_pending_cancel(p); } eldbus_cbs_free_dispatch(&(proxy->cbs_free), proxy); if (proxy->props) { eina_hash_free(proxy->props); proxy->props = NULL; } proxy->refcount = 0; } static void _eldbus_proxy_free(Eldbus_Proxy *proxy) { unsigned int i; Eldbus_Signal_Handler *h; DBG("freeing proxy=%p", proxy); EINA_LIST_FREE(proxy->handlers, h) { if (h->dangling) eldbus_signal_handler_free_cb_del(h, _on_signal_handler_free, proxy); else ERR("proxy=%p alive handler=%p %s", proxy, h, eldbus_signal_handler_match_get(h)); } if (proxy->pendings) CRI("Proxy %p released with live pending calls!", proxy); for (i = 0; i < ELDBUS_PROXY_EVENT_LAST; i++) { Eldbus_Proxy_Context_Event *ce = proxy->event_handlers + i; while (ce->list) { Eldbus_Proxy_Context_Event_Cb *ctx; ctx = EINA_INLIST_CONTAINER_GET(ce->list, Eldbus_Proxy_Context_Event_Cb); _eldbus_proxy_context_event_cb_del(ce, ctx); } eina_list_free(ce->to_delete); } eina_stringshare_del(proxy->interface); EINA_MAGIC_SET(proxy, EINA_MAGIC_NONE); free(proxy); } static void _on_object_free(void *data, const void *dead_pointer EINA_UNUSED) { Eldbus_Proxy *proxy = data; ELDBUS_PROXY_CHECK(proxy); DBG("proxy=%p, refcount=%d, interface=%s, obj=%p", proxy, proxy->refcount, proxy->interface, proxy->obj); eldbus_data_del_all(&(proxy->data)); _eldbus_proxy_clear(proxy); _eldbus_proxy_free(proxy); } EAPI Eldbus_Proxy * eldbus_proxy_get(Eldbus_Object *obj, const char *interface) { Eldbus_Proxy *proxy; EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL); proxy = eldbus_object_proxy_get(obj, interface); if (proxy) return eldbus_proxy_ref(proxy); proxy = calloc(1, sizeof(Eldbus_Proxy)); EINA_SAFETY_ON_NULL_RETURN_VAL(proxy, NULL); proxy->refcount = 1; proxy->obj = obj; proxy->interface = eina_stringshare_add(interface); EINA_MAGIC_SET(proxy, ELDBUS_PROXY_MAGIC); if (!eldbus_object_proxy_add(obj, proxy)) goto cleanup; eldbus_object_free_cb_add(obj, _on_object_free, proxy); return proxy; cleanup: eina_stringshare_del(proxy->interface); free(proxy); return NULL; } static void _on_signal_handler_free(void *data, const void *dead_pointer); static void _eldbus_proxy_unref(Eldbus_Proxy *proxy) { proxy->refcount--; if (proxy->refcount > 0) return; eldbus_object_free_cb_del(proxy->obj, _on_object_free, proxy); eldbus_data_del_all(&(proxy->data)); _eldbus_proxy_clear(proxy); _eldbus_proxy_free(proxy); } EAPI Eldbus_Proxy * eldbus_proxy_ref(Eldbus_Proxy *proxy) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); DBG("proxy=%p, pre-refcount=%d, interface=%s, obj=%p", proxy, proxy->refcount, proxy->interface, proxy->obj); proxy->refcount++; return proxy; } EAPI void eldbus_proxy_unref(Eldbus_Proxy *proxy) { ELDBUS_PROXY_CHECK(proxy); DBG("proxy=%p, pre-refcount=%d, interface=%s, obj=%p", proxy, proxy->refcount, proxy->interface, proxy->obj); _eldbus_proxy_unref(proxy); } EAPI void eldbus_proxy_free_cb_add(Eldbus_Proxy *proxy, Eldbus_Free_Cb cb, const void *data) { ELDBUS_PROXY_CHECK(proxy); EINA_SAFETY_ON_NULL_RETURN(cb); proxy->cbs_free = eldbus_cbs_free_add(proxy->cbs_free, cb, data); } EAPI void eldbus_proxy_free_cb_del(Eldbus_Proxy *proxy, Eldbus_Free_Cb cb, const void *data) { ELDBUS_PROXY_CHECK(proxy); EINA_SAFETY_ON_NULL_RETURN(cb); proxy->cbs_free = eldbus_cbs_free_del(proxy->cbs_free, cb, data); } EAPI void eldbus_proxy_data_set(Eldbus_Proxy *proxy, const char *key, const void *data) { ELDBUS_PROXY_CHECK(proxy); EINA_SAFETY_ON_NULL_RETURN(key); EINA_SAFETY_ON_NULL_RETURN(data); eldbus_data_set(&(proxy->data), key, data); } EAPI void * eldbus_proxy_data_get(const Eldbus_Proxy *proxy, const char *key) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL); return eldbus_data_get(&(((Eldbus_Proxy *)proxy)->data), key); } EAPI void * eldbus_proxy_data_del(Eldbus_Proxy *proxy, const char *key) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL); return eldbus_data_del(&(((Eldbus_Proxy *)proxy)->data), key); } static Eina_Value * _iter_hash_value_set(Eina_Hash *props, const char *key, Eldbus_Message_Iter *var) EINA_ARG_NONNULL(1, 2, 3) { Eina_Value *st_value = _message_iter_struct_to_eina_value(var); Eina_Value *value; Eina_Value stack_value; eina_value_struct_value_get(st_value, "arg0", &stack_value); value = eina_hash_find(props, key); if (!value) { value = eina_value_new(eina_value_type_get(&stack_value)); eina_hash_add(props, key, value); } eina_value_flush(value); eina_value_copy(&stack_value, value); eina_value_flush(&stack_value); eina_value_free(st_value); return value; } static void _property_changed_iter(void *data, const void *key, Eldbus_Message_Iter *var) { Eldbus_Proxy *proxy = data; const char *skey = key; Eina_Value *value = _iter_hash_value_set(proxy->props, skey, var); Eldbus_Proxy_Event_Property_Changed event = {.name = skey, .value = value, .proxy = proxy}; _eldbus_proxy_event_callback_call(proxy, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED, &event); } static void _properties_changed(void *data, const Eldbus_Message *msg) { Eldbus_Proxy *proxy = data; Eldbus_Message_Iter *array, *invalidate; const char *iface; const char *invalidate_prop; if (!eldbus_message_arguments_get(msg, "sa{sv}as", &iface, &array, &invalidate)) { ERR("Error getting data from properties changed signal."); return; } if (proxy->props) eldbus_message_iter_dict_iterate(array, "sv", _property_changed_iter, proxy); while (eldbus_message_iter_get_and_next(invalidate, 's', &invalidate_prop)) { Eldbus_Proxy_Event_Property_Removed event; event.interface = proxy->interface; event.name = invalidate_prop; event.proxy = proxy; if (proxy->props) eina_hash_del(proxy->props, event.name, NULL); _eldbus_proxy_event_callback_call(proxy, ELDBUS_PROXY_EVENT_PROPERTY_REMOVED, &event); } } static void _props_cache_free(void *data) { Eina_Value *value = data; eina_value_free(value); } EAPI void eldbus_proxy_event_callback_add(Eldbus_Proxy *proxy, Eldbus_Proxy_Event_Type type, Eldbus_Proxy_Event_Cb cb, const void *cb_data) { Eldbus_Proxy_Context_Event *ce; Eldbus_Proxy_Context_Event_Cb *ctx; ELDBUS_PROXY_CHECK(proxy); EINA_SAFETY_ON_NULL_RETURN(cb); EINA_SAFETY_ON_TRUE_RETURN(type >= ELDBUS_PROXY_EVENT_LAST); ce = proxy->event_handlers + type; ctx = calloc(1, sizeof(Eldbus_Proxy_Context_Event_Cb)); EINA_SAFETY_ON_NULL_RETURN(ctx); ctx->cb = cb; ctx->cb_data = cb_data; ce->list = eina_inlist_append(ce->list, EINA_INLIST_GET(ctx)); if (type == ELDBUS_PROXY_EVENT_PROPERTY_CHANGED) { if (proxy->properties_changed) return; if (!proxy->props) proxy->props = eina_hash_string_superfast_new(_props_cache_free); proxy->properties_changed = eldbus_proxy_properties_changed_callback_add(proxy, _properties_changed, proxy); } else if (type == ELDBUS_PROXY_EVENT_PROPERTY_REMOVED) { if (proxy->properties_changed) return; proxy->properties_changed = eldbus_proxy_properties_changed_callback_add(proxy, _properties_changed, proxy); } } static void _eldbus_proxy_context_event_cb_del(Eldbus_Proxy_Context_Event *ce, Eldbus_Proxy_Context_Event_Cb *ctx) { ce->list = eina_inlist_remove(ce->list, EINA_INLIST_GET(ctx)); free(ctx); } EAPI void eldbus_proxy_event_callback_del(Eldbus_Proxy *proxy, Eldbus_Proxy_Event_Type type, Eldbus_Proxy_Event_Cb cb, const void *cb_data) { Eldbus_Proxy_Context_Event *ce; Eldbus_Proxy_Context_Event_Cb *iter, *found = NULL; ELDBUS_PROXY_CHECK(proxy); EINA_SAFETY_ON_NULL_RETURN(cb); EINA_SAFETY_ON_TRUE_RETURN(type >= ELDBUS_PROXY_EVENT_LAST); ce = proxy->event_handlers + type; EINA_INLIST_FOREACH(ce->list, iter) { if (cb != iter->cb) continue; if ((cb_data) && (cb_data != iter->cb_data)) continue; found = iter; break; } EINA_SAFETY_ON_NULL_RETURN(found); EINA_SAFETY_ON_TRUE_RETURN(found->deleted); if (ce->walking) { found->deleted = EINA_TRUE; ce->to_delete = eina_list_append(ce->to_delete, found); return; } _eldbus_proxy_context_event_cb_del(ce, found); if (type == ELDBUS_PROXY_EVENT_PROPERTY_CHANGED) { Eldbus_Proxy_Context_Event *ce_prop_remove; ce_prop_remove = proxy->event_handlers + ELDBUS_PROXY_EVENT_PROPERTY_REMOVED; if (!ce->list && !proxy->monitor_enabled) { eina_hash_free(proxy->props); proxy->props = NULL; } if (!ce_prop_remove->list && !ce->list && !proxy->monitor_enabled) { eldbus_signal_handler_unref(proxy->properties_changed); proxy->properties_changed = NULL; } } else if (type == ELDBUS_PROXY_EVENT_PROPERTY_REMOVED) { Eldbus_Proxy_Context_Event *ce_prop_changed; ce_prop_changed = proxy->event_handlers + ELDBUS_PROXY_EVENT_PROPERTY_CHANGED; if (!ce_prop_changed->list && !ce->list && !proxy->monitor_enabled) { eldbus_signal_handler_unref(proxy->properties_changed); proxy->properties_changed = NULL; } } } static void _eldbus_proxy_event_callback_call(Eldbus_Proxy *proxy, Eldbus_Proxy_Event_Type type, const void *event_info) { Eldbus_Proxy_Context_Event *ce; Eldbus_Proxy_Context_Event_Cb *iter; ce = proxy->event_handlers + type; ce->walking++; EINA_INLIST_FOREACH(ce->list, iter) { if (iter->deleted) continue; iter->cb((void *)iter->cb_data, proxy, (void *)event_info); } ce->walking--; if (ce->walking > 0) return; EINA_LIST_FREE(ce->to_delete, iter) _eldbus_proxy_context_event_cb_del(ce, iter); } EAPI Eldbus_Object * eldbus_proxy_object_get(const Eldbus_Proxy *proxy) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); return proxy->obj; } EAPI const char * eldbus_proxy_interface_get(const Eldbus_Proxy *proxy) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); return proxy->interface; } static void _on_proxy_message_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) { Eldbus_Message_Cb cb = eldbus_pending_data_del(pending, "__user_cb"); Eldbus_Proxy *proxy = eldbus_pending_data_del(pending, "__proxy"); ELDBUS_PROXY_CHECK(proxy); proxy->pendings = eina_inlist_remove(proxy->pendings, EINA_INLIST_GET(pending)); cb(data, msg, pending); } static Eldbus_Pending * _eldbus_proxy_send(Eldbus_Proxy *proxy, Eldbus_Message *msg, Eldbus_Message_Cb cb, const void *cb_data, double timeout) { Eldbus_Pending *pending; if (!cb) { _eldbus_connection_send(proxy->obj->conn, msg, NULL, NULL, timeout); return NULL; } pending = _eldbus_connection_send(proxy->obj->conn, msg, _on_proxy_message_cb, cb_data, timeout); EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL); eldbus_pending_data_set(pending, "__user_cb", cb); eldbus_pending_data_set(pending, "__proxy", proxy); proxy->pendings = eina_inlist_append(proxy->pendings, EINA_INLIST_GET(pending)); return pending; } static Eldbus_Message * _eldbus_proxy_send_and_block(Eldbus_Proxy *proxy, Eldbus_Message *msg, double timeout) { return _eldbus_connection_send_and_block(proxy->obj->conn, msg, timeout); } EAPI Eldbus_Pending * eldbus_proxy_send(Eldbus_Proxy *proxy, Eldbus_Message *msg, Eldbus_Message_Cb cb, const void *cb_data, double timeout) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL); return _eldbus_proxy_send(proxy, msg, cb, cb_data, timeout); } EAPI Eldbus_Message * eldbus_proxy_send_and_block(Eldbus_Proxy *proxy, Eldbus_Message *msg, double timeout) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL); return _eldbus_proxy_send_and_block(proxy, msg, timeout); } EAPI Eldbus_Message * eldbus_proxy_method_call_new(Eldbus_Proxy *proxy, const char *member) { Eldbus_Message *msg; ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); msg = eldbus_message_method_call_new( eldbus_object_bus_name_get(proxy->obj), eldbus_object_path_get(proxy->obj), proxy->interface, member); return msg; } static Eldbus_Pending * _eldbus_proxy_vcall(Eldbus_Proxy *proxy, const char *member, Eldbus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, va_list ap) { Eldbus_Message *msg = eldbus_proxy_method_call_new(proxy, member); EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL); if (!eldbus_message_arguments_vappend(msg, signature, ap)) { eldbus_message_unref(msg); ERR("Error setting arguments"); return NULL; } return _eldbus_proxy_send(proxy, msg, cb, cb_data, timeout); } EAPI Eldbus_Pending * eldbus_proxy_call(Eldbus_Proxy *proxy, const char *member, Eldbus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, ...) { Eldbus_Pending *pending; va_list ap; ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(member, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(signature, NULL); va_start(ap, signature); pending = _eldbus_proxy_vcall(proxy, member, cb, cb_data, timeout, signature, ap); va_end(ap); return pending; } EAPI Eldbus_Pending * eldbus_proxy_vcall(Eldbus_Proxy *proxy, const char *member, Eldbus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, va_list ap) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(member, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(signature, NULL); return _eldbus_proxy_vcall(proxy, member, cb, cb_data, timeout, signature, ap); } static void _on_signal_handler_free(void *data, const void *dead_pointer) { Eldbus_Proxy *proxy = data; ELDBUS_PROXY_CHECK(proxy); proxy->handlers = eina_list_remove(proxy->handlers, dead_pointer); } EAPI Eldbus_Signal_Handler * eldbus_proxy_signal_handler_add(Eldbus_Proxy *proxy, const char *member, Eldbus_Signal_Cb cb, const void *cb_data) { Eldbus_Signal_Handler *handler; const char *name, *path; ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL); name = eldbus_object_bus_name_get(proxy->obj); path = eldbus_object_path_get(proxy->obj); handler = _eldbus_signal_handler_add(proxy->obj->conn, name, path, proxy->interface, member, cb, cb_data); EINA_SAFETY_ON_NULL_RETURN_VAL(handler, NULL); DBG("signal handler added: proxy=%p handler=%p cb=%p", proxy, handler, cb); eldbus_signal_handler_free_cb_add(handler, _on_signal_handler_free, proxy); proxy->handlers = eina_list_append(proxy->handlers, handler); return handler; } EAPI Eldbus_Pending * eldbus_proxy_property_get(Eldbus_Proxy *proxy, const char *name, Eldbus_Message_Cb cb, const void *data) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); return eldbus_proxy_call(proxy->obj->properties, "Get", cb, data, -1, "ss", proxy->interface, name); } static inline Eina_Bool _type_is_number(char sig) { switch (sig) { case 'y': case 'b': case 'n': case 'q': case 'i': case 'u': case 'x': case 't': case 'd': case 'h': return EINA_TRUE; default: break; } return EINA_FALSE; } EAPI Eldbus_Pending * eldbus_proxy_property_set(Eldbus_Proxy *proxy, const char *name, const char *sig, const void *value, Eldbus_Message_Cb cb, const void *data) { Eldbus_Message *msg; Eldbus_Message_Iter *iter, *variant; ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(sig, NULL); EINA_SAFETY_ON_FALSE_RETURN_VAL(dbus_signature_validate_single(sig, NULL), NULL); EINA_SAFETY_ON_FALSE_RETURN_VAL((_type_is_number(sig[0]) || value), NULL); msg = eldbus_proxy_method_call_new(proxy->obj->properties, "Set"); iter = eldbus_message_iter_get(msg); eldbus_message_iter_basic_append(iter, 's', proxy->interface); eldbus_message_iter_basic_append(iter, 's', name); variant = eldbus_message_iter_container_new(iter, 'v', sig); if (dbus_type_is_basic(sig[0])) dbus_message_iter_append_basic(&variant->dbus_iterator, sig[0], &value); else { if (!_message_iter_from_eina_value_struct(sig, variant, value)) { eldbus_message_unref(msg); return NULL; } } eldbus_message_iter_container_close(iter, variant); return eldbus_proxy_send(proxy->obj->properties, msg, cb, data, -1); } EAPI Eldbus_Pending * eldbus_proxy_property_value_set(Eldbus_Proxy *proxy, const char *name, const char *sig, const Eina_Value *value, Eldbus_Message_Cb cb, const void *data) { Eldbus_Message *msg; Eldbus_Message_Iter *iter, *variant; ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(sig, NULL); EINA_SAFETY_ON_FALSE_RETURN_VAL(dbus_signature_validate_single(sig, NULL), NULL); EINA_SAFETY_ON_FALSE_RETURN_VAL((_type_is_number(sig[0]) || value), NULL); msg = eldbus_proxy_method_call_new(proxy->obj->properties, "Set"); iter = eldbus_message_iter_get(msg); eldbus_message_iter_basic_append(iter, 's', proxy->interface); eldbus_message_iter_basic_append(iter, 's', name); variant = eldbus_message_iter_container_new(iter, 'v', sig); if (dbus_type_is_basic(sig[0])) { if (!_message_iter_from_eina_value(sig, variant, value)) goto error; } else { if (!_message_iter_from_eina_value_struct(sig, variant, value)) goto error; } eldbus_message_iter_container_close(iter, variant); return eldbus_proxy_send(proxy->obj->properties, msg, cb, data, -1); error: eldbus_message_unref(msg); return NULL; } EAPI Eldbus_Pending * eldbus_proxy_property_get_all(Eldbus_Proxy *proxy, Eldbus_Message_Cb cb, const void *data) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); return eldbus_proxy_call(proxy->obj->properties, "GetAll", cb, data, -1, "s", proxy->interface); } EAPI Eldbus_Signal_Handler * eldbus_proxy_properties_changed_callback_add(Eldbus_Proxy *proxy, Eldbus_Signal_Cb cb, const void *data) { Eldbus_Signal_Handler *sh; ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); sh = eldbus_proxy_signal_handler_add(proxy->obj->properties, "PropertiesChanged", cb, data); EINA_SAFETY_ON_NULL_RETURN_VAL(sh, NULL); eldbus_signal_handler_match_extra_set(sh, "arg0", proxy->interface, NULL); return sh; } static void _property_iter(void *data, const void *key, Eldbus_Message_Iter *var) { Eldbus_Proxy *proxy = data; const char *skey = key; _iter_hash_value_set(proxy->props, skey, var); } static void _on_monitored_proxy_del(void *data, Eldbus_Proxy *proxy EINA_UNUSED, void *event_info EINA_UNUSED) { Eldbus_Pending *pending = data; eldbus_pending_cancel(pending); } static void _props_get_all(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) { Eldbus_Proxy *proxy = data; Eldbus_Message_Iter *dict; const char *name, *error_msg; Eldbus_Proxy_Event_Property_Loaded event; eldbus_proxy_event_callback_del(proxy, ELDBUS_PROXY_EVENT_DEL, _on_monitored_proxy_del, pending); if (eldbus_message_error_get(msg, &name, &error_msg)) { /* don't print warnings for user-canceled calls */ if (!eina_streq(name, "org.enlightenment.DBus.Canceled")) WRN("Error getting all properties of %s %s, error message: %s %s", proxy->obj->name, proxy->obj->path, name, error_msg); return; } if (!eldbus_message_arguments_get(msg, "a{sv}", &dict)) { char *txt; if (eldbus_message_arguments_get(msg, "s", &txt)) WRN("Error getting data from properties getAll: %s", txt); return; } eldbus_message_iter_dict_iterate(dict, "sv", _property_iter, proxy); event.proxy = proxy; _eldbus_proxy_event_callback_call(proxy, ELDBUS_PROXY_EVENT_PROPERTY_LOADED, &event); } EAPI Eina_Bool eldbus_proxy_properties_monitor(Eldbus_Proxy *proxy, Eina_Bool enable) { Eldbus_Pending *pending; ELDBUS_PROXY_CHECK_RETVAL(proxy, EINA_FALSE); if (proxy->monitor_enabled == enable) return proxy->props ? !!eina_hash_population(proxy->props) : EINA_FALSE; proxy->monitor_enabled = enable; if (!enable) { Eldbus_Proxy_Context_Event *ce_prop_changed, *ce_prop_removed; ce_prop_changed = proxy->event_handlers + ELDBUS_PROXY_EVENT_PROPERTY_CHANGED; ce_prop_removed = proxy->event_handlers + ELDBUS_PROXY_EVENT_PROPERTY_REMOVED; if (!ce_prop_changed->list) { eina_hash_free(proxy->props); proxy->props = NULL; } if (!ce_prop_changed->list && !ce_prop_removed->list) { eldbus_signal_handler_unref(proxy->properties_changed); proxy->properties_changed = NULL; } return EINA_TRUE; } if (!proxy->props) proxy->props = eina_hash_string_superfast_new(_props_cache_free); pending = eldbus_proxy_property_get_all(proxy, _props_get_all, proxy); eldbus_proxy_event_callback_add(proxy, ELDBUS_PROXY_EVENT_DEL, _on_monitored_proxy_del, pending); if (proxy->properties_changed) return !!eina_hash_population(proxy->props); proxy->properties_changed = eldbus_proxy_properties_changed_callback_add(proxy, _properties_changed, proxy); return !!eina_hash_population(proxy->props); } EAPI Eina_Value * eldbus_proxy_property_local_get(Eldbus_Proxy *proxy, const char *name) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(proxy->props, NULL); return eina_hash_find(proxy->props, name); } EAPI const Eina_Hash * eldbus_proxy_property_local_get_all(Eldbus_Proxy *proxy) { ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(proxy->props, NULL); return proxy->props; }