efl/src/lib/eldbus/eldbus_model_arguments.c

347 lines
10 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "eldbus_model_arguments_private.h"
#include "eldbus_model_private.h"
#include <Ecore.h>
#include <Eina.h>
#include <Eldbus.h>
#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"