#ifdef HAVE_CONFIG_H # include #endif #include "eldbus_model_arguments_private.h" #include "eldbus_model_private.h" #include #include #include #define MY_CLASS ELDBUS_MODEL_ARGUMENTS_CLASS #define MY_CLASS_NAME "Eldbus_Model_Arguments" static void _eldbus_model_arguments_properties_load(Eldbus_Model_Arguments_Data *); static void _eldbus_model_arguments_unload(Eldbus_Model_Arguments_Data *); static Eina_Bool _eldbus_model_arguments_is_input_argument(Eldbus_Model_Arguments_Data *, const char *); static Eina_Bool _eldbus_model_arguments_is_output_argument(Eldbus_Model_Arguments_Data *, const char *); static Eina_Bool _eldbus_model_arguments_property_set(Eldbus_Model_Arguments_Data *, Eina_Value *, const char *); static unsigned int _eldbus_model_arguments_argument_index_get(Eldbus_Model_Arguments_Data *, const char *); static void _eldbus_model_arguments_hash_free(Eina_Value *value) { eina_value_free(value); } static Efl_Object* _eldbus_model_arguments_efl_object_constructor(Eo *obj, Eldbus_Model_Arguments_Data *pd) { pd->obj = obj; // We do keep strings here as some of our API are looking for arg%u as a key instead of just indexes. pd->properties = eina_hash_string_superfast_new(EINA_FREE_CB(_eldbus_model_arguments_hash_free)); pd->pending_list = NULL; pd->proxy = NULL; pd->arguments = NULL; pd->name = NULL; return efl_constructor(efl_super(obj, MY_CLASS)); } static void _cleanup_proxy_cb(void *data, const void *deadptr) { Eldbus_Model_Arguments_Data *pd = data; if (pd->proxy == deadptr) pd->proxy = NULL; } static Efl_Object * _eldbus_model_arguments_efl_object_finalize(Eo *obj, Eldbus_Model_Arguments_Data *pd) { if (!pd->proxy) return NULL; if (!eldbus_model_connection_get(obj)) eldbus_model_connection_set(obj, eldbus_object_connection_get(eldbus_proxy_object_get(pd->proxy))); eldbus_proxy_free_cb_add(pd->proxy, _cleanup_proxy_cb, pd); return efl_finalize(efl_super(obj, MY_CLASS)); } static void _eldbus_model_arguments_custom_constructor(Eo *obj EINA_UNUSED, Eldbus_Model_Arguments_Data *pd, Eldbus_Proxy *proxy, const char *name, const Eina_List *arguments) { EINA_SAFETY_ON_NULL_RETURN(proxy); EINA_SAFETY_ON_NULL_RETURN(name); pd->proxy = eldbus_proxy_ref(proxy); pd->arguments = arguments; pd->name = eina_stringshare_add(name); } static void _eldbus_model_arguments_efl_object_invalidate(Eo *obj, Eldbus_Model_Arguments_Data *pd) { _eldbus_model_arguments_unload(pd); eina_hash_free(pd->properties); eina_stringshare_del(pd->name); if (pd->proxy) { eldbus_proxy_free_cb_del(pd->proxy, _cleanup_proxy_cb, pd); eldbus_proxy_unref(pd->proxy); pd->proxy = NULL; } efl_invalidate(efl_super(obj, MY_CLASS)); } static Eina_Iterator * _eldbus_model_arguments_efl_model_properties_get(const Eo *obj EINA_UNUSED, Eldbus_Model_Arguments_Data *pd) { EINA_SAFETY_ON_NULL_RETURN_VAL(pd, NULL); _eldbus_model_arguments_properties_load(pd); return eina_hash_iterator_key_new(pd->properties); } static void _eldbus_model_arguments_properties_load(Eldbus_Model_Arguments_Data *pd) { unsigned int arguments_count; unsigned int i; if (eina_hash_population(pd->properties) > 0) return ; arguments_count = eina_list_count(pd->arguments); for (i = 0; i < arguments_count; ++i) { Eldbus_Introspection_Argument *arg; const Eina_Value_Type *type; Eina_Slstr *name; Eina_Value *value; name = eina_slstr_printf(ARGUMENT_FORMAT, i); if (!name) continue; arg = eina_list_nth(pd->arguments, i); type = _dbus_type_to_eina_value_type(arg->type[0]); value = eina_value_new(type); eina_hash_add(pd->properties, name, value); } } static Eina_Future * _eldbus_model_arguments_efl_model_property_set(Eo *obj, Eldbus_Model_Arguments_Data *pd, const char *property, Eina_Value *value) { Eina_Value *prop_value; Eina_Error err = 0; Eina_Bool ret; DBG("(%p): property=%s", obj, property); err = EFL_MODEL_ERROR_NOT_FOUND; if (!property || !value) goto on_error; _eldbus_model_arguments_properties_load(pd); err = EFL_MODEL_ERROR_READ_ONLY; ret = _eldbus_model_arguments_is_input_argument(pd, property); if (!ret) goto on_error; err = EFL_MODEL_ERROR_NOT_FOUND; prop_value = eina_hash_find(pd->properties, property); if (!prop_value) goto on_error; eina_value_flush(prop_value); eina_value_copy(value, prop_value); return efl_loop_future_resolved(obj, eina_value_reference_copy(value)); on_error: return efl_loop_future_rejected(obj, err); } static Eina_Value * _eldbus_model_arguments_efl_model_property_get(const Eo *obj, Eldbus_Model_Arguments_Data *pd, const char *property) { Eina_Value *value; Eina_Bool ret; DBG("(%p): property=%s", obj, property); if (!property) return eina_value_error_new(EFL_MODEL_ERROR_INCORRECT_VALUE); _eldbus_model_arguments_properties_load(pd); value = eina_hash_find(pd->properties, property); if (!value) return eina_value_error_new(EFL_MODEL_ERROR_NOT_FOUND); ret = _eldbus_model_arguments_is_output_argument(pd, property); if (!ret) return eina_value_error_new(EFL_MODEL_ERROR_PERMISSION_DENIED); return eina_value_dup(value); } static const char * _eldbus_model_arguments_arg_name_get(const Eo *obj EINA_UNUSED, Eldbus_Model_Arguments_Data *pd) { return pd->name; } static void _eldbus_model_arguments_unload(Eldbus_Model_Arguments_Data *pd) { Eldbus_Pending *pending; EINA_SAFETY_ON_NULL_RETURN(pd); EINA_LIST_FREE(pd->pending_list, pending) eldbus_pending_cancel(pending); eina_hash_free_buckets(pd->properties); } Eina_Bool eldbus_model_arguments_process_arguments(Eldbus_Model_Arguments_Data *pd, const Eldbus_Message *msg, Eldbus_Pending *pending) { const Eldbus_Introspection_Argument *argument; const char *error_name, *error_text; const Eina_List *it; Eina_Value *value_struct; Eina_Array *changed_properties; unsigned int i = 0; Eina_Stringshare *property; Eina_Bool result = EINA_FALSE; _eldbus_model_arguments_properties_load(pd); pd->pending_list = eina_list_remove(pd->pending_list, pending); if (eldbus_message_error_get(msg, &error_name, &error_text)) { ERR("%s: %s", error_name, error_text); //efl_model_error_notify(pd->obj); return EINA_FALSE; } value_struct = eldbus_message_to_eina_value(msg); if (value_struct == NULL) { INF("%s", "No output arguments"); return EINA_TRUE; } changed_properties = eina_array_new(1); EINA_LIST_FOREACH(pd->arguments, it, argument) { if (ELDBUS_INTROSPECTION_ARGUMENT_DIRECTION_IN != argument->direction) { Eina_Bool ret; property = eina_stringshare_printf(ARGUMENT_FORMAT, i); ret = eina_array_push(changed_properties, property); EINA_SAFETY_ON_FALSE_GOTO(ret, on_error); ret = _eldbus_model_arguments_property_set(pd, value_struct, property); EINA_SAFETY_ON_FALSE_GOTO(ret, on_error); } ++i; } if (eina_array_count(changed_properties)) { Efl_Model_Property_Event evt = {.changed_properties = changed_properties}; efl_event_callback_call(pd->obj, EFL_MODEL_EVENT_PROPERTIES_CHANGED, &evt); } result = EINA_TRUE; on_error: while ((property = eina_array_pop(changed_properties))) eina_stringshare_del(property); eina_array_free(changed_properties); eina_value_free(value_struct); return result; } static Eina_Bool _eldbus_model_arguments_property_set(Eldbus_Model_Arguments_Data *pd, Eina_Value *value_struct, const char *property) { Eina_Value *prop_value; Eina_Value value; Eina_Bool ret; _eldbus_model_arguments_properties_load(pd); prop_value = eina_hash_find(pd->properties, property); EINA_SAFETY_ON_NULL_RETURN_VAL(prop_value, EINA_FALSE); ret = eina_value_struct_value_get(value_struct, "arg0", &value); EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, EINA_FALSE); eina_value_flush(prop_value); ret = eina_value_copy(&value, prop_value); eina_value_flush(&value); EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, EINA_FALSE); return ret; } static Eina_Bool _eldbus_model_arguments_is(Eldbus_Model_Arguments_Data *pd, const char *argument, Eldbus_Introspection_Argument_Direction direction) { Eldbus_Introspection_Argument *argument_introspection; unsigned int i; _eldbus_model_arguments_properties_load(pd); i = _eldbus_model_arguments_argument_index_get(pd, argument); if ((i > 0x7fffffff) || ((int)i >= eina_hash_population(pd->properties))) { WRN("Argument not found: %s", argument); return false; } argument_introspection = eina_list_nth(pd->arguments, i); EINA_SAFETY_ON_NULL_RETURN_VAL(argument_introspection, EINA_FALSE); return argument_introspection->direction == direction; } static Eina_Bool _eldbus_model_arguments_is_input_argument(Eldbus_Model_Arguments_Data *pd, const char *argument) { return _eldbus_model_arguments_is(pd, argument, ELDBUS_INTROSPECTION_ARGUMENT_DIRECTION_IN); } static Eina_Bool _eldbus_model_arguments_is_output_argument(Eldbus_Model_Arguments_Data *pd, const char *argument) { return _eldbus_model_arguments_is(pd, argument, ELDBUS_INTROSPECTION_ARGUMENT_DIRECTION_OUT) || _eldbus_model_arguments_is(pd, argument, ELDBUS_INTROSPECTION_ARGUMENT_DIRECTION_NONE); } static unsigned int _eldbus_model_arguments_argument_index_get(Eldbus_Model_Arguments_Data *pd, const char *argument) { unsigned int i = 0; if (sscanf(argument, ARGUMENT_FORMAT, &i) > 0) return i; return eina_hash_population(pd->properties); } #include "eldbus_model_arguments.eo.c"