edje: reduce memory usage of Edje signal callbacks and automates.

This patch try to share signal callbacks and automate accross all Edje
object. It does use an Eina_Hash on the callback description (signal,
source, func). There is no need to check it against Edje file or group
only the callbacks matter.

This version remove all use of size_t as it should never be above 32bits.
We have a hard limit on the number of callback to 2^32 now. I am considering
it would be sane to make it a short.
This commit is contained in:
Cedric BAIL 2013-02-19 18:55:37 +09:00
parent c78f4d7bfa
commit 488ea9ec82
8 changed files with 886 additions and 417 deletions

View File

@ -46,7 +46,8 @@ lib/edje/edje_smart.c \
lib/edje/edje_text.c \
lib/edje/edje_textblock_styles.c \
lib/edje/edje_util.c \
lib/edje/edje_var.c
lib/edje/edje_var.c \
lib/edje/edje_signal.c
lib_edje_libedje_la_CPPFLAGS = $(EDJE_COMMON_CPPFLAGS)
lib_edje_libedje_la_LIBADD = @EDJE_LIBS@

View File

@ -893,7 +893,6 @@ enum
EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_ADD,
EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_DEL,
EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_DEL_FULL,
EDJE_OBJ_SUB_ID_SIGNAL_EMIT,
EDJE_OBJ_SUB_ID_PLAY_SET,
EDJE_OBJ_SUB_ID_PLAY_GET,
@ -2709,23 +2708,7 @@ enum
*
* @see edje_object_signal_callback_del
*/
#define edje_obj_signal_callback_del(emission, source, func, ret) EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_DEL), EO_TYPECHECK(const char *, emission), EO_TYPECHECK(const char *, source), EO_TYPECHECK(Edje_Signal_Cb, func), EO_TYPECHECK(void **, ret)
/**
* @def edje_obj_signal_callback_del_full
* @since 1.8
*
* @brief Unregister/delete a callback set for an arriving Edje
*
* @param[in] emission
* @param[in] source
* @param[in] func
* @param[in] data
* @param[out] ret
*
* @see edje_object_signal_callback_del_full
*/
#define edje_obj_signal_callback_del_full(emission, source, func, data, ret) EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_DEL_FULL), EO_TYPECHECK(const char *, emission), EO_TYPECHECK(const char *, source), EO_TYPECHECK(Edje_Signal_Cb, func), EO_TYPECHECK(void *, data), EO_TYPECHECK(void **, ret)
#define edje_obj_signal_callback_del(emission, source, func, data, ret) EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_DEL), EO_TYPECHECK(const char *, emission), EO_TYPECHECK(const char *, source), EO_TYPECHECK(Edje_Signal_Cb, func), EO_TYPECHECK(void *, data), EO_TYPECHECK(void **, ret)
/**
* @def edje_obj_signal_emit

View File

@ -78,6 +78,7 @@ edje_init(void)
_edje_module_init();
_edje_message_init();
_edje_multisense_init();
edje_signal_init();
_edje_real_part_mp = eina_mempool_add("chained_mempool",
"Edje_Real_Part", NULL,
@ -147,6 +148,7 @@ _edje_shutdown_core(void)
_edje_real_part_state_mp = NULL;
_edje_real_part_mp = NULL;
edje_signal_shutdown();
_edje_multisense_shutdown();
_edje_message_shutdown();
_edje_module_shutdown();
@ -242,7 +244,6 @@ _edje_del(Edje *ed)
{
Edje_Running_Program *runp;
Edje_Pending_Program *pp;
Edje_Signal_Callback *escb;
Edje_Text_Class *tc;
Edje_Text_Insert_Filter_Callback *cb;
@ -252,7 +253,7 @@ _edje_del(Edje *ed)
return;
}
_edje_message_del(ed);
_edje_callbacks_patterns_clean(ed);
_edje_signal_callback_free(ed->callbacks);
_edje_file_del(ed);
if (ed->path) eina_stringshare_del(ed->path);
if (ed->group) eina_stringshare_del(ed->group);
@ -267,12 +268,6 @@ _edje_del(Edje *ed)
free(runp);
EINA_LIST_FREE(ed->pending_actions, pp)
free(pp);
EINA_LIST_FREE(ed->callbacks, escb)
{
if (escb->signal) eina_stringshare_del(escb->signal);
if (escb->source) eina_stringshare_del(escb->source);
free(escb);
}
eina_hash_free(ed->color_classes);
EINA_LIST_FREE(ed->text_classes, tc)
{

View File

@ -5,20 +5,20 @@
typedef struct _Edje_State Edje_State;
struct _Edje_State
{
size_t idx;
size_t pos;
unsigned int idx;
unsigned int pos;
};
struct _Edje_States
{
size_t size;
unsigned int size;
Edje_State *states;
Eina_Bool *has;
};
static void
_edje_match_states_free(Edje_States *states,
size_t states_size)
_edje_match_states_free(Edje_States *states,
unsigned int states_size)
{
(void) states_size;
free(states);
@ -36,15 +36,15 @@ _edje_match_states_alloc(Edje_Patterns *ppat, int n)
{
Edje_States *l;
const size_t patterns_size = ppat->patterns_size;
const size_t patterns_max_length = ppat->max_length;
const unsigned int patterns_size = ppat->patterns_size;
const unsigned int patterns_max_length = ppat->max_length;
const size_t array_len = (patterns_max_length + 1) * patterns_size;
const unsigned int array_len = (patterns_max_length + 1) * patterns_size;
size_t states_size;
size_t has_size;
size_t states_has_size;
size_t struct_size;
unsigned int states_size;
unsigned int has_size;
unsigned int states_has_size;
unsigned int struct_size;
unsigned char *states;
unsigned char *has;
@ -88,12 +88,12 @@ _edje_match_states_alloc(Edje_Patterns *ppat, int n)
}
static void
_edje_match_states_insert(Edje_States *list,
size_t patterns_max_length,
size_t idx,
size_t pos)
_edje_match_states_insert(Edje_States *list,
unsigned int patterns_max_length,
unsigned int idx,
unsigned int pos)
{
size_t i;
unsigned int i;
i = (idx * (patterns_max_length + 1)) + pos;
@ -112,8 +112,8 @@ _edje_match_states_insert(Edje_States *list,
static void
_edje_match_states_clear(Edje_States *list,
EINA_UNUSED size_t patterns_size,
EINA_UNUSED size_t patterns_max_length)
EINA_UNUSED unsigned int patterns_size,
EINA_UNUSED unsigned int patterns_max_length)
{
list->size = 0;
}
@ -127,7 +127,7 @@ enum status
patterns_syntax_error = 2
};
static size_t
static unsigned int
_edje_match_patterns_exec_class_token(enum status *status,
const char *cl_tok,
char c)
@ -152,7 +152,7 @@ _edje_match_patterns_exec_class_token(enum status *status,
}
static Edje_Match_Error
_edje_match_patterns_exec_class_complement(const char *cl_tok, size_t *ret)
_edje_match_patterns_exec_class_complement(const char *cl_tok, unsigned int *ret)
{
switch (*cl_tok)
{
@ -170,13 +170,13 @@ _edje_match_patterns_exec_class_complement(const char *cl_tok, size_t *ret)
}
static Edje_Match_Error
_edje_match_patterns_exec_class(const char *cl,
char c,
size_t *ret)
_edje_match_patterns_exec_class(const char *cl,
char c,
unsigned int *ret)
{
enum status status = patterns_not_found;
int pos = 1;
size_t neg;
enum status status = patterns_not_found;
int pos = 1;
size_t neg;
if (_edje_match_patterns_exec_class_complement(cl + 1, &neg) != EDJE_MATCH_OK)
return EDJE_MATCH_SYNTAX_ERROR;
@ -201,9 +201,9 @@ _edje_match_patterns_exec_class(const char *cl,
}
static Edje_Match_Error
_edje_match_patterns_exec_token(const char *tok,
char c,
size_t *ret)
_edje_match_patterns_exec_token(const char *tok,
char c,
unsigned int *ret)
{
switch (*tok)
{
@ -229,11 +229,11 @@ _edje_match_patterns_exec_token(const char *tok,
}
static void
_edje_match_patterns_exec_init_states(Edje_States *states,
size_t patterns_size,
size_t patterns_max_length)
_edje_match_patterns_exec_init_states(Edje_States *states,
unsigned int patterns_size,
unsigned int patterns_max_length)
{
size_t i;
unsigned int i;
states->size = patterns_size;
@ -251,8 +251,8 @@ _edje_match_patterns_exec_init_states(Edje_States *states,
Edje_Patterns* \
Func(const Eina_List *lst) \
{ \
Edje_Patterns *r; \
size_t i; \
Edje_Patterns *r; \
unsigned int i; \
\
if (!lst || eina_list_count(lst) <= 0) \
return NULL; \
@ -273,7 +273,7 @@ _edje_match_patterns_exec_init_states(Edje_States *states,
{ \
const char *str; \
Type *data; \
size_t j; \
unsigned int j; \
int special = 0; \
\
data = eina_list_data_get(lst); \
@ -318,8 +318,8 @@ _edje_match_patterns_exec_init_states(Edje_States *states,
Edje_Patterns* \
Func(Type * const *lst, unsigned int count) \
{ \
Edje_Patterns *r; \
size_t i; \
Edje_Patterns *r; \
unsigned int i; \
\
if (!lst || count == 0) \
return NULL; \
@ -339,7 +339,7 @@ _edje_match_patterns_exec_init_states(Edje_States *states,
for (i = 0; i < count; ++i) \
{ \
const char *str; \
size_t j; \
unsigned int j; \
int special = 0; \
\
if (!lst[i]) \
@ -377,6 +377,66 @@ _edje_match_patterns_exec_init_states(Edje_States *states,
return r; \
}
#define EDJE_MATCH_INIT_INARRAY(Func, Source, Show) \
Edje_Patterns* \
Func(const Eina_Inarray *array, const Edje_Signal_Callback_Match *matches) \
{ \
Edje_Patterns *r; \
int *it; \
unsigned int i = 0; \
\
if (!matches) \
return NULL; \
\
r = malloc(sizeof (Edje_Patterns) + \
eina_inarray_count(array) \
* sizeof(*r->finals) \
* sizeof(*r->patterns)); \
if (!r) return NULL; \
\
r->ref = 1; \
r->delete_me = EINA_FALSE; \
r->patterns_size = eina_inarray_count(array); \
r->max_length = 0; \
r->patterns = (const char **) r->finals + r->patterns_size + 1; \
\
EINA_INARRAY_FOREACH(array, it) \
{ \
const char *str; \
unsigned int j; \
int special = 0; \
\
str = (matches + *it)->Source; \
if (!str) str = ""; \
r->patterns[i] = str; \
\
if (Show) \
INF("%lu [%s]", (unsigned long)i, str); \
\
r->finals[i] = 0; \
for (j = 0; str[j]; ++j) \
if (str[j] != '*') \
{ \
r->finals[i] = j + 1; \
special++; \
} \
j += special ? special + 1 : 0; \
\
if (j > r->max_length) \
r->max_length = j; \
\
i++; \
} \
\
if (!_edje_match_states_alloc(r, 2)) \
{ \
free(r); \
return NULL; \
} \
\
return r; \
}
EDJE_MATCH_INIT_LIST(edje_match_collection_dir_init,
Edje_Part_Collection_Directory_Entry,
entry, 0);
@ -386,18 +446,16 @@ EDJE_MATCH_INIT_ARRAY(edje_match_programs_signal_init,
EDJE_MATCH_INIT_ARRAY(edje_match_programs_source_init,
Edje_Program,
source, 0);
EDJE_MATCH_INIT_LIST(edje_match_callback_signal_init,
Edje_Signal_Callback,
signal, 0);
EDJE_MATCH_INIT_LIST(edje_match_callback_source_init,
Edje_Signal_Callback,
source, 0);
EDJE_MATCH_INIT_INARRAY(edje_match_callback_signal_init,
signal, 0);
EDJE_MATCH_INIT_INARRAY(edje_match_callback_source_init,
source, 0);
static Eina_Bool
_edje_match_collection_dir_exec_finals(const size_t *finals,
const Edje_States *states)
_edje_match_collection_dir_exec_finals(const unsigned int *finals,
const Edje_States *states)
{
size_t i;
unsigned int i;
for (i = 0; i < states->size; ++i)
{
@ -408,17 +466,17 @@ _edje_match_collection_dir_exec_finals(const size_t *finals,
}
static Eina_Bool
edje_match_programs_exec_check_finals(const size_t *signal_finals,
const size_t *source_finals,
const Edje_States *signal_states,
const Edje_States *source_states,
Edje_Program **programs,
edje_match_programs_exec_check_finals(const unsigned int *signal_finals,
const unsigned int *source_finals,
const Edje_States *signal_states,
const Edje_States *source_states,
Edje_Program **programs,
Eina_Bool (*func)(Edje_Program *pr, void *data),
void *data,
Eina_Bool prop EINA_UNUSED)
void *data,
Eina_Bool prop EINA_UNUSED)
{
size_t i;
size_t j;
unsigned int i;
unsigned int j;
/* when not enought memory, they could be NULL */
if (!signal_finals || !source_finals) return EINA_TRUE;
@ -449,61 +507,59 @@ edje_match_programs_exec_check_finals(const size_t *signal_finals,
}
static int
edje_match_callback_exec_check_finals(const Edje_Patterns *signal_ppat,
const Edje_Patterns *source_ppat,
const size_t *signal_finals,
const size_t *source_finals,
edje_match_callback_exec_check_finals(const Edje_Signals_Sources_Patterns *ssp,
const Edje_Signal_Callback_Match *matches,
const void **custom_data,
const Eina_Bool *flags,
const Edje_States *signal_states,
const Edje_States *source_states,
const char *sig,
const char *source,
Eina_List *callbacks,
Edje *ed,
Eina_Bool prop
)
Eina_Bool prop)
{
Edje_Signal_Callback *escb;
const Edje_Signal_Callback_Match *cb;
Eina_Array run;
size_t i;
size_t j;
unsigned int i;
unsigned int j;
int r = 1;
eina_array_step_set(&run, sizeof (Eina_Array), 4);
for (i = 0; i < signal_states->size; ++i)
{
if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx])
{
for (j = 0; j < source_states->size; ++j)
{
if (signal_states->states[i].idx == source_states->states[j].idx
&& source_states->states[j].pos >= source_finals[source_states->states[j].idx])
{
escb = eina_list_nth(callbacks, signal_states->states[i].idx);
if (escb)
{
if ((prop) && (escb->propagate)) continue;
if ((!escb->just_added)
&& (!escb->delete_me))
{
eina_array_push(&run, escb);
r = 2;
}
}
}
}
}
}
if (signal_states->states[i].pos >= ssp->signals_patterns->finals[signal_states->states[i].idx])
{
for (j = 0; j < source_states->size; ++j)
{
if (signal_states->states[i].idx == source_states->states[j].idx
&& source_states->states[j].pos >= ssp->sources_patterns->finals[source_states->states[j].idx])
{
int *e;
while ((escb = eina_array_pop(&run)))
e = eina_inarray_nth(&ssp->u.callbacks.globing, signal_states->states[i].idx);
cb = &matches[*e];
if (cb)
{
if ((prop) && _edje_signal_callback_prop(flags, *e)) continue;
eina_array_push(&run, cb);
r = 2;
}
}
}
}
while ((cb = eina_array_pop(&run)))
{
escb->func(escb->data, ed->obj, sig, source);
int idx = cb - matches;
cb->func((void*) custom_data[idx], ed->obj, sig, source);
if (_edje_block_break(ed))
{
r = 0;
break;
}
if ((signal_ppat->delete_me) || (source_ppat->delete_me))
if ((ssp->signals_patterns->delete_me) || (ssp->sources_patterns->delete_me))
{
r = 0;
break;
@ -526,14 +582,14 @@ _edje_match_fn(const Edje_Patterns *ppat,
for (c = string; *c && states->size; ++c)
{
size_t i;
unsigned int i;
_edje_match_states_clear(new_states, ppat->patterns_size, ppat->max_length);
for (i = 0; i < states->size; ++i)
{
const size_t idx = states->states[i].idx;
const size_t pos = states->states[i].pos;
const unsigned int idx = states->states[i].idx;
const unsigned int pos = states->states[i].pos;
if (!ppat->patterns[idx][pos])
continue;
@ -544,7 +600,7 @@ _edje_match_fn(const Edje_Patterns *ppat,
}
else
{
size_t m;
unsigned int m;
if (_edje_match_patterns_exec_token(ppat->patterns[idx] + pos,
*c,
@ -626,50 +682,49 @@ edje_match_programs_exec(const Edje_Patterns *ppat_signal,
}
int
edje_match_callback_exec(Edje_Patterns *ppat_signal,
Edje_Patterns *ppat_source,
const char *sig,
const char *source,
Eina_List *callbacks,
Edje *ed,
Eina_Bool prop
)
edje_match_callback_exec(const Edje_Signals_Sources_Patterns *ssp,
const Edje_Signal_Callback_Match *matches,
const void **custom_data,
const Eina_Bool *flags,
const char *sig,
const char *source,
Edje *ed,
Eina_Bool prop)
{
Edje_States *signal_result;
Edje_States *source_result;
int r = 0;
/* under high memory presure, they could be NULL */
if (!ppat_source || !ppat_signal) return 0;
if (!ssp->sources_patterns || !ssp->signals_patterns) return 0;
ppat_signal->ref++;
ppat_source->ref++;
_edje_match_patterns_exec_init_states(ppat_signal->states,
ppat_signal->patterns_size,
ppat_signal->max_length);
_edje_match_patterns_exec_init_states(ppat_source->states,
ppat_source->patterns_size,
ppat_source->max_length);
ssp->signals_patterns->ref++;
ssp->sources_patterns->ref++;
_edje_match_patterns_exec_init_states(ssp->signals_patterns->states,
ssp->signals_patterns->patterns_size,
ssp->signals_patterns->max_length);
_edje_match_patterns_exec_init_states(ssp->sources_patterns->states,
ssp->sources_patterns->patterns_size,
ssp->sources_patterns->max_length);
signal_result = _edje_match_fn(ppat_signal, sig, ppat_signal->states);
source_result = _edje_match_fn(ppat_source, source, ppat_source->states);
signal_result = _edje_match_fn(ssp->signals_patterns, sig, ssp->signals_patterns->states);
source_result = _edje_match_fn(ssp->sources_patterns, source, ssp->sources_patterns->states);
if (signal_result && source_result)
r = edje_match_callback_exec_check_finals(ppat_signal,
ppat_source,
ppat_signal->finals,
ppat_source->finals,
signal_result,
source_result,
sig,
source,
callbacks,
ed,
prop);
ppat_signal->ref--;
ppat_source->ref--;
if (ppat_signal->ref <= 0) edje_match_patterns_free(ppat_signal);
if (ppat_source->ref <= 0) edje_match_patterns_free(ppat_source);
r = edje_match_callback_exec_check_finals(ssp,
matches,
custom_data,
flags,
signal_result,
source_result,
sig,
source,
ed,
prop);
ssp->signals_patterns->ref--;
ssp->sources_patterns->ref--;
if (ssp->signals_patterns->ref <= 0) edje_match_patterns_free(ssp->signals_patterns);
if (ssp->sources_patterns->ref <= 0) edje_match_patterns_free(ssp->sources_patterns);
return r;
}
@ -750,13 +805,13 @@ edje_match_program_hash_build(Edje_Program * const *programs,
item->signal = programs[i]->signal;
item->source = programs[i]->source;
eina_array_step_set(&item->list, sizeof (Eina_Array), 8);
eina_inarray_step_set(&item->list, sizeof (Eina_Inarray), sizeof (void*), 8);
new = eina_rbtree_inline_insert(new, EINA_RBTREE_GET(item),
EINA_RBTREE_CMP_NODE_CB(_edje_signal_source_node_cmp), NULL);
}
eina_array_push(&item->list, programs[i]);
eina_inarray_push(&item->list, &programs[i]);
}
else
result = eina_list_prepend(result, programs[i]);
@ -766,48 +821,51 @@ edje_match_program_hash_build(Edje_Program * const *programs,
return result;
}
Eina_List *
edje_match_callback_hash_build(const Eina_List *callbacks,
Eina_Rbtree **tree)
void
edje_match_callback_hash_build(const Edje_Signal_Callback_Match *callbacks,
int callbacks_count,
Eina_Rbtree **tree,
Eina_Inarray *result)
{
Eina_List *result = NULL;
Eina_Rbtree *new = NULL;
Edje_Signal_Callback *callback;
const Eina_List *l;
int i;
EINA_LIST_FOREACH(callbacks, l, callback)
eina_inarray_step_set(result, sizeof (Eina_Inarray), sizeof (int), 8);
for (i = 0; i < callbacks_count; ++i, ++callbacks)
{
if (callback->signal && !strpbrk(callback->signal, "*?[\\")
&& callback->source && !strpbrk(callback->source, "*?[\\"))
if (callbacks->signal && !strpbrk(callbacks->signal, "*?[\\")
&& callbacks->source && !strpbrk(callbacks->source, "*?[\\"))
{
Edje_Signal_Source_Char *item;
item = (Edje_Signal_Source_Char*) eina_rbtree_inline_lookup(new, callback->signal, 0,
EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), callback->source);
item = (Edje_Signal_Source_Char*) eina_rbtree_inline_lookup(new, callbacks->signal, 0,
EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), callbacks->source);
if (!item)
{
item = malloc(sizeof (Edje_Signal_Source_Char));
if (!item) continue;
item->signal = callback->signal;
item->source = callback->source;
eina_array_step_set(&item->list, sizeof (Eina_Array), 8);
item->signal = callbacks->signal;
item->source = callbacks->source;
eina_inarray_step_set(&item->list, sizeof (Eina_Inarray), sizeof (int), 8);
new = eina_rbtree_inline_insert(new, EINA_RBTREE_GET(item),
EINA_RBTREE_CMP_NODE_CB(_edje_signal_source_node_cmp), NULL);
}
eina_array_push(&item->list, callback);
eina_inarray_push(&item->list, &i);
}
else
result = eina_list_prepend(result, callback);
{
eina_inarray_push(result, &i);
}
}
*tree = new;
return result;
}
const Eina_Array *
const Eina_Inarray *
edje_match_signal_source_hash_get(const char *sig,
const char *source,
const Eina_Rbtree *tree)
@ -824,6 +882,6 @@ edje_match_signal_source_hash_get(const char *sig,
void
edje_match_signal_source_free(Edje_Signal_Source_Char *key, EINA_UNUSED void *data)
{
eina_array_flush(&key->list);
eina_inarray_flush(&key->list);
free(key);
}

View File

@ -323,6 +323,10 @@ typedef struct _Edje_Signal_Source_Char Edje_Signal_Source_Char;
typedef struct _Edje_Text_Insert_Filter_Callback Edje_Text_Insert_Filter_Callback;
typedef struct _Edje_Markup_Filter_Callback Edje_Markup_Filter_Callback;
typedef struct _Edje_Signals_Sources_Patterns Edje_Signals_Sources_Patterns;
typedef struct _Edje_Signal_Callback_Group Edje_Signal_Callback_Group;
typedef struct _Edje_Signal_Callback_Match Edje_Signal_Callback_Match;
typedef struct _Edje_Signal_Callback_Matches Edje_Signal_Callback_Matches;
typedef struct _Edje_Signal_Callback_Custom Edje_Signal_Callback_Custom;
#define EDJE_INF_MAX_W 100000
#define EDJE_INF_MAX_H 100000
@ -772,6 +776,7 @@ struct _Edje_Part_Limit
struct _Edje_Signals_Sources_Patterns
{
EINA_REFCOUNT;
Edje_Patterns *signals_patterns;
Edje_Patterns *sources_patterns;
@ -783,11 +788,39 @@ struct _Edje_Signals_Sources_Patterns
unsigned int count;
} programs;
struct {
Eina_List *globing;
Eina_Inarray globing;
} callbacks;
} u;
};
struct _Edje_Signal_Callback_Match
{
const char *signal;
const char *source;
Edje_Signal_Cb func;
};
struct _Edje_Signal_Callback_Matches
{
Edje_Signal_Callback_Match *matches;
Edje_Signals_Sources_Patterns *patterns;
unsigned int matches_count;
EINA_REFCOUNT;
Eina_Bool hashed : 1;
};
struct _Edje_Signal_Callback_Group
{
const Edje_Signal_Callback_Matches *matches;
void **custom_data;
Eina_Bool *flags; /* 4 bits per custom data (delete_me, just_added, propagate) */
};
/*----------*/
struct _Edje_Part_Collection
@ -1189,7 +1222,7 @@ struct _Edje_Signal_Source_Char
const char *signal;
const char *source;
Eina_Array list;
Eina_Inarray list;
};
struct _Edje
@ -1207,7 +1240,6 @@ struct _Edje
Edje_File *file; /* the file the data comes form */
Edje_Part_Collection *collection; /* the description being used */
Eina_List *actions; /* currently running actions */
Eina_List *callbacks;
Eina_List *pending_actions;
Eina_Hash *color_classes;
Eina_List *text_classes;
@ -1230,9 +1262,7 @@ struct _Edje
Edje_Perspective *persp;
struct {
Edje_Signals_Sources_Patterns callbacks;
} patterns;
const Edje_Signal_Callback_Group *callbacks;
struct {
Edje_Text_Change_Cb func;
@ -1789,8 +1819,10 @@ Edje_Patterns *edje_match_programs_signal_init(Edje_Program * const *array,
unsigned int count);
Edje_Patterns *edje_match_programs_source_init(Edje_Program * const *array,
unsigned int count);
Edje_Patterns *edje_match_callback_signal_init(const Eina_List *lst);
Edje_Patterns *edje_match_callback_source_init(const Eina_List *lst);
Edje_Patterns *edje_match_callback_signal_init(const Eina_Inarray *lst,
const Edje_Signal_Callback_Match *matches);
Edje_Patterns *edje_match_callback_source_init(const Eina_Inarray *lst,
const Edje_Signal_Callback_Match *matches);
Eina_Bool edje_match_collection_dir_exec(const Edje_Patterns *ppat,
const char *string);
@ -1802,25 +1834,29 @@ Eina_Bool edje_match_programs_exec(const Edje_Patterns *ppat_signal,
Eina_Bool (*func)(Edje_Program *pr, void *data),
void *data,
Eina_Bool prop);
int edje_match_callback_exec(Edje_Patterns *ppat_signal,
Edje_Patterns *ppat_source,
const char *signal,
const char *source,
Eina_List *callbacks,
Edje *ed,
Eina_Bool prop);
int edje_match_callback_exec(const Edje_Signals_Sources_Patterns *ssp,
const Edje_Signal_Callback_Match *matches,
const void **custom_data,
const Eina_Bool *flags,
const char *sig,
const char *source,
Edje *ed,
Eina_Bool prop);
void edje_match_patterns_free(Edje_Patterns *ppat);
Eina_List *edje_match_program_hash_build(Edje_Program * const * programs,
unsigned int count,
Eina_Rbtree **tree);
Eina_List *edje_match_callback_hash_build(const Eina_List *callbacks,
Eina_Rbtree **tree);
const Eina_Array *edje_match_signal_source_hash_get(const char *signal,
const char *source,
const Eina_Rbtree *tree);
void edje_match_callback_hash_build(const Edje_Signal_Callback_Match *callback,
int callbacks_count,
Eina_Rbtree **tree,
Eina_Inarray *result);
const Eina_Inarray *edje_match_signal_source_hash_get(const char *signal,
const char *source,
const Eina_Rbtree *tree);
void edje_match_signal_source_free(Edje_Signal_Source_Char *key, void *data);
void _edje_signal_callback_matches_unref(Edje_Signal_Callback_Matches *m);
// FIXME remove below 3 eapi decls when edje_convert goes
EAPI void _edje_edd_init(void);
@ -1881,6 +1917,16 @@ void _edje_callbacks_focus_add(Evas_Object *obj, Edje *ed, Edje_Real_Part *rp);
void _edje_callbacks_del(Evas_Object *obj, Edje *ed);
void _edje_callbacks_focus_del(Evas_Object *obj, Edje *ed);
const Edje_Signal_Callback_Group *_edje_signal_callback_alloc(void);
void _edje_signal_callback_free(const Edje_Signal_Callback_Group *cgp);
void _edje_signal_callback_push(const Edje_Signal_Callback_Group *cgp,
const char *signal, const char *source,
Edje_Signal_Cb func, void *data,
Eina_Bool propagate);
void *_edje_signal_callback_disable(const Edje_Signal_Callback_Group *cgp,
const char *signal, const char *source,
Edje_Signal_Cb func, void *data);
EAPI void _edje_edd_init(void);
EAPI void _edje_edd_shutdown(void);
@ -1917,7 +1963,12 @@ void _edje_emit(Edje *ed, const char *sig, const char *src);
void _edje_emit_full(Edje *ed, const char *sig, const char *src, void *data, void (*free_func)(void *));
void _edje_emit_handle(Edje *ed, const char *sig, const char *src, Edje_Message_Signal_Data *data, Eina_Bool prop);
void _edje_signals_sources_patterns_clean(Edje_Signals_Sources_Patterns *ssp);
void _edje_callbacks_patterns_clean(Edje *ed);
const Edje_Signals_Sources_Patterns *_edje_signal_callback_patterns_ref(const Edje_Signal_Callback_Group *gp);
void _edje_signal_callback_patterns_unref(const Edje_Signals_Sources_Patterns *essp);
Eina_Bool _edje_signal_callback_prop(const Eina_Bool *flags, int i);
void _edje_signal_callback_free(const Edje_Signal_Callback_Group *gp);
void _edje_text_init(void);
void _edje_text_part_on_add(Edje *ed, Edje_Real_Part *ep);
@ -2462,6 +2513,9 @@ void _play_get(Eo *obj, void *_pd, va_list *list);
void _animation_set(Eo *obj, void *_pd, va_list *list);
void _animation_get(Eo *obj, void *_pd, va_list *list);
void edje_signal_init(void);
void edje_signal_shutdown(void);
#ifdef HAVE_LIBREMIX
#include <remix/remix.h>
#endif

View File

@ -28,26 +28,27 @@ edje_frametime_get(void)
void
edje_object_propagate_callback_add(Evas_Object *obj, void (*func) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
{
const char *sig;
const char *src;
Edje *ed;
Edje_Signal_Callback *escb;
ed = _edje_fetch(obj);
if (!ed) return;
if (ed->delete_me) return;
escb = calloc(1, sizeof(Edje_Signal_Callback));
escb->propagate = EINA_TRUE;
escb->signal = eina_stringshare_add("*");
escb->source = eina_stringshare_add("*");
escb->func = func;
escb->data = data;
ed->callbacks = eina_list_append(ed->callbacks, escb);
if (ed->walking_callbacks)
{
escb->just_added = 1;
ed->just_added_callbacks = EINA_TRUE;
}
else
_edje_callbacks_patterns_clean(ed);
if (!ed->callbacks)
ed->callbacks = _edje_signal_callback_alloc();
sig = eina_stringshare_add("*");
src = eina_stringshare_add("*");
_edje_signal_callback_push(ed->callbacks,
sig, src,
func, data,
EINA_TRUE);
eina_stringshare_del(sig);
eina_stringshare_del(src);
}
EAPI void
@ -66,27 +67,24 @@ _signal_callback_add(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
void *data = va_arg(*list, void *);
Edje *ed = _pd;
Edje_Signal_Callback *escb;
if ((!emission) || (!source) || (!func)) return;
ed = _pd;
if (!ed) return;
if (ed->delete_me) return;
escb = calloc(1, sizeof(Edje_Signal_Callback));
if (emission[0])
escb->signal = eina_stringshare_add(emission);
if (source[0])
escb->source = eina_stringshare_add(source);
escb->func = func;
escb->data = data;
ed->callbacks = eina_list_append(ed->callbacks, escb);
if (ed->walking_callbacks)
{
escb->just_added = 1;
ed->just_added_callbacks = EINA_TRUE;
}
else
_edje_callbacks_patterns_clean(ed);
emission = eina_stringshare_add(emission);
source = eina_stringshare_add(source);
if (!ed->callbacks)
ed->callbacks = _edje_signal_callback_alloc();
_edje_signal_callback_push(ed->callbacks,
emission, source,
func, data, EINA_FALSE);
eina_stringshare_del(emission);
eina_stringshare_del(source);
}
EAPI void *
@ -94,7 +92,7 @@ edje_object_signal_callback_del(Evas_Object *obj, const char *emission, const ch
{
if (!obj) return NULL;
void *ret = NULL;
eo_do(obj, edje_obj_signal_callback_del(emission, source, (Edje_Signal_Cb)func, &ret));
eo_do(obj, edje_obj_signal_callback_del(emission, source, (Edje_Signal_Cb)func, NULL, &ret));
return ret;
}
@ -104,46 +102,25 @@ _signal_callback_del(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
const char *emission = va_arg(*list, const char *);
const char *source = va_arg(*list, const char *);
Edje_Signal_Cb func = va_arg(*list, Edje_Signal_Cb);
void *data = va_arg(*list, void *);
void **ret = va_arg(*list, void **);
if (ret) *ret = NULL;
Edje *ed = _pd;
Eina_List *l;
Edje_Signal_Callback *escb;
if (ret) *ret = NULL;
if ((!emission) || (!source) || (!func)) return;
if (!ed) return;
if (ed->delete_me) return;
EINA_LIST_FOREACH(ed->callbacks, l, escb)
{
if ((escb->func == func) &&
((!escb->signal && !emission[0]) ||
(escb->signal && !strcmp(escb->signal, emission))) &&
((!escb->source && !source[0]) ||
(escb->source && !strcmp(escb->source, source))))
{
void *data;
data = escb->data;
if (ed->walking_callbacks)
{
escb->delete_me = EINA_TRUE;
ed->delete_callbacks = EINA_TRUE;
}
else
{
_edje_callbacks_patterns_clean(ed);
emission = eina_stringshare_add(emission);
source = eina_stringshare_add(source);
ed->callbacks = eina_list_remove_list(ed->callbacks, l);
if (escb->signal) eina_stringshare_del(escb->signal);
if (escb->source) eina_stringshare_del(escb->source);
free(escb);
}
if (ret) *ret = data;
return;
}
}
return;
_edje_signal_callback_disable(ed->callbacks,
emission, source,
func, data);
eina_stringshare_del(emission);
eina_stringshare_del(source);
}
EAPI void *
@ -151,59 +128,10 @@ edje_object_signal_callback_del_full(Evas_Object *obj, const char *emission, con
{
if (!obj) return NULL;
void *ret = NULL;
eo_do(obj, edje_obj_signal_callback_del_full(emission, source, func, data, &ret));
eo_do(obj, edje_obj_signal_callback_del(emission, source, func, data, &ret));
return ret;
}
void
_signal_callback_del_full(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
{
const char *emission = va_arg(*list, const char *);
const char *source = va_arg(*list, const char *);
Edje_Signal_Cb func = va_arg(*list, Edje_Signal_Cb);
void *data = va_arg(*list, void *);
void **ret = va_arg(*list, void **);
if (ret) *ret = NULL;
Edje *ed = _pd;
Eina_List *l;
Edje_Signal_Callback *escb;
if ((!emission) || (!source) || (!func)) return;
if (!ed) return;
if (ed->delete_me) return;
EINA_LIST_FOREACH(ed->callbacks, l, escb)
{
if ((escb->func == func) && (escb->data == data) &&
((!escb->signal && !emission[0]) ||
(escb->signal && !strcmp(escb->signal, emission))) &&
((!escb->source && !source[0]) ||
(escb->source && !strcmp(escb->source, source))))
{
void *data2;
data2 = escb->data;
if (ed->walking_callbacks)
{
escb->delete_me = EINA_TRUE;
ed->delete_callbacks = EINA_TRUE;
}
else
{
_edje_callbacks_patterns_clean(ed);
ed->callbacks = eina_list_remove_list(ed->callbacks, l);
if (escb->signal) eina_stringshare_del(escb->signal);
if (escb->source) eina_stringshare_del(escb->source);
free(escb);
}
if (ret) *ret = data2;
return;
}
}
return;
}
EAPI void
edje_object_signal_emit(Evas_Object *obj, const char *emission, const char *source)
{
@ -627,9 +555,20 @@ _edje_program_run(Edje *ed, Edje_Program *pr, Eina_Bool force, const char *ssig,
tmp = calloc(1, sizeof(Edje_Calc_Params));
if (!tmp) goto low_mem_current;
tmp->map = eina_cow_alloc(_edje_calc_params_map_cow);
#ifdef HAVE_EPHYSICS
tmp->physics = eina_cow_alloc(_edje_calc_params_physics_cow);
#endif
_edje_part_recalc(ed, rp, FLAG_XY, tmp);
if (rp->current) free(rp->current);
if (rp->current)
{
eina_cow_free(_edje_calc_params_map_cow, rp->current->map);
#ifdef HAVE_EPHYSICS
eina_cow_free(_edje_calc_params_physics_cow, rp->current->physics);
#endif
free(rp->current);
}
rp->current = tmp;
rp->current->x -= ed->x;
@ -650,7 +589,14 @@ _edje_program_run(Edje *ed, Edje_Program *pr, Eina_Bool force, const char *ssig,
else
{
low_mem_current:
if (rp->current) free(rp->current);
if (rp->current)
{
eina_cow_free(_edje_calc_params_map_cow, rp->current->map);
#ifdef HAVE_EPHYSICS
eina_cow_free(_edje_calc_params_physics_cow, rp->current->physics);
#endif
free(rp->current);
}
rp->current = NULL;
}
@ -1093,7 +1039,7 @@ _edje_emit_full(Edje *ed, const char *sig, const char *src, void *data, void (*f
Edje *ed2;
char *part;
char *idx;
size_t length;
unsigned int length;
/* the signal contains a colon, split the signal into "parts:signal" */
length = sep - sig + 1;
@ -1279,37 +1225,6 @@ static Eina_Bool _edje_glob_callback(Edje_Program *pr, void *dt)
return EINA_FALSE;
}
void
_edje_callbacks_patterns_clean(Edje *ed)
{
if (ed->walking_callbacks > 0) return;
_edje_signals_sources_patterns_clean(&ed->patterns.callbacks);
eina_rbtree_delete(ed->patterns.callbacks.exact_match,
EINA_RBTREE_FREE_CB(edje_match_signal_source_free),
NULL);
ed->patterns.callbacks.exact_match = NULL;
ed->patterns.callbacks.u.callbacks.globing = eina_list_free(ed->patterns.callbacks.u.callbacks.globing);
}
static void
_edje_callbacks_patterns_init(Edje *ed)
{
Edje_Signals_Sources_Patterns *ssp = &ed->patterns.callbacks;
if ((ssp->signals_patterns) || (ssp->sources_patterns) ||
(ssp->u.callbacks.globing) || (ssp->exact_match))
return;
ssp->u.callbacks.globing = edje_match_callback_hash_build(ed->callbacks,
&ssp->exact_match);
ssp->signals_patterns = edje_match_callback_signal_init(ssp->u.callbacks.globing);
ssp->sources_patterns = edje_match_callback_source_init(ssp->u.callbacks.globing);
}
/* FIXME: what if we delete the evas object??? */
void
_edje_emit_handle(Edje *ed, const char *sig, const char *src,
@ -1403,13 +1318,11 @@ _edje_emit_handle(Edje *ed, const char *sig, const char *src,
if (ed->collection->patterns.table_programs_size > 0)
{
const Eina_Array *match;
const Eina_Inarray *match;
#ifdef EDJE_PROGRAM_CACHE
const Eina_List *l;
#endif
Edje_Program *pr;
Eina_Array_Iterator iterator;
unsigned int i;
if (ed->collection->patterns.programs.u.programs.globing)
if (edje_match_programs_exec(ed->collection->patterns.programs.signals_patterns,
@ -1420,13 +1333,17 @@ _edje_emit_handle(Edje *ed, const char *sig, const char *src,
_edje_glob_callback,
&data,
prop) == 0)
goto break_prog;
goto break_prog;
match = edje_match_signal_source_hash_get(sig, src,
ed->collection->patterns.programs.exact_match);
if (match)
EINA_ARRAY_ITER_NEXT(match, i, pr, iterator)
_edje_glob_callback(pr, &data);
{
Edje_Program **tpr;
EINA_INARRAY_FOREACH(match, tpr)
_edje_glob_callback(*tpr, &data);
}
#ifdef EDJE_PROGRAM_CACHE
EINA_LIST_FOREACH(data.matches, l, pr)
@ -1489,82 +1406,68 @@ edje_object_signal_callback_extra_data_get(void)
static void
_edje_emit_cb(Edje *ed, const char *sig, const char *src, Edje_Message_Signal_Data *data, Eina_Bool prop)
{
Eina_List *l;
const Edje_Signals_Sources_Patterns *ssp;
Edje_Signal_Callback_Matches *m;
const void **custom_data;
Eina_Bool *flags;
const Eina_Inarray *match;
int r = 1;
if (ed->delete_me) return;
if (!ed->callbacks || !ed->callbacks->matches) return;
_edje_ref(ed);
_edje_freeze(ed);
_edje_block(ed);
if (ed->just_added_callbacks)
_edje_callbacks_patterns_clean(ed);
ssp = _edje_signal_callback_patterns_ref(ed->callbacks);
ed->walking_callbacks++;
m = (Edje_Signal_Callback_Matches*) ed->callbacks->matches;
EINA_REFCOUNT_REF(m);
if (ed->callbacks)
callback_extra_data = (data) ? data->data : NULL;
custom_data = alloca(sizeof (void*) * m->matches_count);
memcpy(custom_data, ed->callbacks->custom_data, sizeof (void*) * m->matches_count);
flags = alloca(sizeof (Eina_Bool) * m->matches_count);
memcpy(flags, ed->callbacks->flags, sizeof (Eina_Bool) * (m->matches_count >> 1));
if (eina_inarray_count(&ssp->u.callbacks.globing))
r = edje_match_callback_exec(ssp,
m->matches,
custom_data,
flags,
sig,
src,
ed,
prop);
if (!r)
goto break_prog;
match = edje_match_signal_source_hash_get(sig, src,
ssp->exact_match);
if (match)
{
Edje_Signal_Callback *escb;
const Eina_Array *match;
Eina_Array_Iterator iterator;
unsigned int i;
int r = 1;
callback_extra_data = (data) ? data->data : NULL;
const Edje_Signal_Callback_Match *cb;
unsigned int *i;
_edje_callbacks_patterns_init(ed);
if (ed->patterns.callbacks.u.callbacks.globing)
r = edje_match_callback_exec(ed->patterns.callbacks.signals_patterns,
ed->patterns.callbacks.sources_patterns,
sig,
src,
ed->patterns.callbacks.u.callbacks.globing,
ed,
prop);
EINA_INARRAY_FOREACH(match, i)
{
cb = &m->matches[*i];
if (!r)
goto break_prog;
if ((prop) && (_edje_signal_callback_prop(flags, *i))) continue;
match = edje_match_signal_source_hash_get(sig, src,
ed->patterns.callbacks.exact_match);
if (match)
EINA_ARRAY_ITER_NEXT(match, i, escb, iterator)
{
if ((prop) && (escb->propagate)) continue;
if ((!escb->just_added) && (!escb->delete_me))
{
escb->func(escb->data, ed->obj, sig, src);
if (_edje_block_break(ed))
break;
}
}
cb->func((void*) custom_data[*i], ed->obj, sig, src);
if (_edje_block_break(ed))
break;
}
}
break_prog:
ed->walking_callbacks--;
if (!ed->walking_callbacks &&
((ed->delete_callbacks) || (ed->just_added_callbacks)))
{
ed->delete_callbacks = EINA_FALSE;
ed->just_added_callbacks = EINA_FALSE;
l = ed->callbacks;
while (l)
{
Edje_Signal_Callback *escb = l->data;
Eina_List *next_l = l->next;
break_prog:
_edje_signal_callback_matches_unref(m);
if (escb->just_added)
escb->just_added = 0;
if (escb->delete_me)
{
ed->callbacks = eina_list_remove_list(ed->callbacks, l);
if (escb->signal) eina_stringshare_del(escb->signal);
if (escb->source) eina_stringshare_del(escb->source);
free(escb);
}
l = next_l;
}
_edje_signal_callback_patterns_unref(ssp);
_edje_callbacks_patterns_clean(ed);
}
_edje_unblock(ed);
_edje_thaw(ed);
_edje_unref(ed);

477
src/lib/edje/edje_signal.c Normal file
View File

@ -0,0 +1,477 @@
#include <assert.h>
#include "edje_private.h"
#define _DELETE_ME 0x4
#define _JUST_ADDED 0x2
#define _PROPAGATE 0x1
static Eina_Hash *signal_match = NULL;
static unsigned int
_edje_signal_match_key_length(const void *key EINA_UNUSED)
{
return sizeof (Edje_Signal_Callback_Matches);
}
static int
_edje_signal_match_key_cmp(const void *key1, int key1_length EINA_UNUSED, const void *key2, int key2_length EINA_UNUSED)
{
const Edje_Signal_Callback_Matches *a = key1;
const Edje_Signal_Callback_Matches *b = key2;
unsigned int i;
if (a->matches_count != b->matches_count) return a->matches_count - b->matches_count;
for (i = 0; i < a->matches_count; ++i)
{
if (a->matches[i].signal != b->matches[i].signal) return a->matches[i].signal - b->matches[i].signal;
if (a->matches[i].source != b->matches[i].source) return a->matches[i].source - b->matches[i].source;
if (a->matches[i].func != b->matches[i].func) return (unsigned char*) a->matches[i].func - (unsigned char*) b->matches[i].func;
}
return 0;
}
static int
_edje_signal_match_key_hash(const void *key, int key_length EINA_UNUSED)
{
const Edje_Signal_Callback_Matches *a = key;
unsigned int hash, i;
hash = eina_hash_int32(&a->matches_count, sizeof (int));
for (i = 0; i < a->matches_count; ++i)
{
#ifdef __LP64__
hash ^= eina_hash_int64((const unsigned long int*) &a->matches[i].signal, sizeof (char *));
hash ^= eina_hash_int64((const unsigned long int*) &a->matches[i].source, sizeof (char *));
hash ^= eina_hash_int64((const unsigned long int*) &a->matches[i].func, sizeof (Edje_Signal_Cb));
#else
hash ^= eina_hash_int32((const unsigned int*) a->matches[i].signal, sizeof (char *));
hash ^= eina_hash_int32((const unsigned int*) a->matches[i].source, sizeof (char *));
hash ^= eina_hash_int32((const unsigned int*) a->matches[i].func, sizeof (Edje_Signal_Cb));
#endif
}
return hash;
}
static const Edje_Signal_Callback_Matches *
_edje_signal_callback_matches_dup(const Edje_Signal_Callback_Matches *src)
{
Edje_Signal_Callback_Matches *result;
unsigned int i;
result = calloc(1, sizeof (Edje_Signal_Callback_Matches));
if (!result) return NULL;
result->hashed = EINA_FALSE;
result->matches = malloc(sizeof (Edje_Signal_Callback_Match) * src->matches_count);
result->matches_count = src->matches_count;
result->patterns = NULL;
EINA_REFCOUNT_REF(result);
for (i = 0; i < src->matches_count; i++)
{
result->matches[i].signal = eina_stringshare_ref(src->matches[i].signal);
result->matches[i].source = eina_stringshare_ref(src->matches[i].source);
result->matches[i].func = src->matches[i].func;
}
return result;
}
void
_edje_callbacks_patterns_clean(Edje_Signal_Callback_Group *gp)
{
Edje_Signal_Callback_Matches *tmp;
assert(EINA_REFCOUNT_GET(gp->matches) == 1);
tmp = (Edje_Signal_Callback_Matches*) gp->matches;
_edje_signal_callback_patterns_unref(tmp->patterns);
tmp->patterns = NULL;
}
static void
_edje_callbacks_patterns_init(Edje_Signal_Callback_Group *gp)
{
Edje_Signals_Sources_Patterns *ssp;
Edje_Signal_Callback_Matches *tmp;
if (gp->matches->patterns) return ;
tmp = (Edje_Signal_Callback_Matches*) gp->matches;
tmp->patterns = calloc(1, sizeof (Edje_Signals_Sources_Patterns));
if (!gp->matches->patterns) return ;
ssp = gp->matches->patterns;
edje_match_callback_hash_build(gp->matches->matches,
gp->matches->matches_count,
&ssp->exact_match,
&ssp->u.callbacks.globing);
ssp->signals_patterns = edje_match_callback_signal_init(&ssp->u.callbacks.globing, tmp->matches);
ssp->sources_patterns = edje_match_callback_source_init(&ssp->u.callbacks.globing, tmp->matches);
EINA_REFCOUNT_REF(ssp);
}
void
edje_signal_init(void)
{
signal_match = eina_hash_new(_edje_signal_match_key_length,
_edje_signal_match_key_cmp,
_edje_signal_match_key_hash,
NULL,
3);
}
void
edje_signal_shutdown(void)
{
// FIXME: iterate and destroy leftover signal matcher
eina_hash_free(signal_match);
}
static void
_edje_signal_callback_unset(Edje_Signal_Callback_Group *gp, int idx)
{
Edje_Signal_Callback_Match *m;
m = gp->matches->matches + idx;
eina_stringshare_del(m->signal);
m->signal = NULL;
eina_stringshare_del(m->source);
m->source = NULL;
}
static void
_edje_signal_callback_set(Edje_Signal_Callback_Group *gp, int idx,
const char *sig, const char *src,
Edje_Signal_Cb func, void *data, Eina_Bool flags)
{
Edje_Signal_Callback_Match *m;
m = gp->matches->matches + idx;
m->signal = eina_stringshare_ref(sig);
m->source = eina_stringshare_ref(src);
m->func = func;
gp->custom_data[idx] = data;
gp->flags[idx >> 1] = (gp->flags[idx >> 1] & (0xF << (((idx & 1) ^ 1) * 4))) |
((flags & 0xF) << ((idx & 1) * 4));
}
Eina_Bool
_edje_signal_callback_prop(const Eina_Bool *flags, int i)
{
Eina_Bool b;
b = flags[i >> 1];
return b & (_PROPAGATE << ((i & 1) * 4));
}
static Edje_Signal_Callback_Group *
_edje_signal_callback_grow(Edje_Signal_Callback_Group *gp)
{
Edje_Signal_Callback_Matches *tmp;
unsigned int c;
tmp = (Edje_Signal_Callback_Matches*) gp->matches;
tmp->matches_count++;
tmp->matches = realloc(tmp->matches, sizeof (Edje_Signal_Callback_Match) * tmp->matches_count);
gp->custom_data = realloc(gp->custom_data, sizeof (void*) * tmp->matches_count);
c = ((tmp->matches_count >> 1) | (tmp->matches_count & 1));
gp->flags = realloc(gp->flags, sizeof (Edje_Signal_Callback_Group) + c);
// We have just expanded by one char, set it to 0
if (tmp->matches_count & 1) gp->flags[tmp->matches_count >> 1] = 0;
return gp;
}
void
_edje_signal_callback_push(const Edje_Signal_Callback_Group *cgp,
const char *sig, const char *src,
Edje_Signal_Cb func, void *data, Eina_Bool propagate)
{
Edje_Signal_Callback_Group *gp = (Edje_Signal_Callback_Group*) cgp;
unsigned int i;
// let's first try to see if we do find an empty matching stop
for (i = 0; i < gp->matches->matches_count; i++)
if (sig == gp->matches->matches[i].signal &&
src == gp->matches->matches[i].source &&
func == gp->matches->matches[i].func)
{
Eina_Bool flags;
flags = gp->flags[i >> 1] & (0xF << ((i & 1) * 4));
if (flags & _DELETE_ME)
{
_edje_signal_callback_unset(gp, i);
_edje_signal_callback_set(gp, i,
sig, src, func, data,
(((!!propagate) & 1) | _JUST_ADDED));
return ;
}
}
if (gp->matches->hashed)
{
Edje_Signal_Callback_Matches *tmp;
tmp = (Edje_Signal_Callback_Matches*) gp->matches;
if (EINA_REFCOUNT_GET(tmp) == 1)
{
eina_hash_del(signal_match, tmp, tmp);
tmp->hashed = 0;
}
else
{
Edje_Signal_Callback_Matches *tmp_dup;
tmp_dup = (Edje_Signal_Callback_Matches*) _edje_signal_callback_matches_dup(tmp);
if (!tmp_dup) return ;
EINA_REFCOUNT_UNREF(tmp)
(void) 0; // Nothing to do because the case where refcount == 1 was already handle above.
gp->matches = tmp_dup;
}
}
// search an empty spot now
for (i = 0; i < gp->matches->matches_count; i += 2)
if (gp->flags[i >> 1] & (_DELETE_ME | (_DELETE_ME << 4)))
{
if (gp->flags[i >> 1] & _DELETE_ME)
{
_edje_signal_callback_unset(gp, i);
_edje_signal_callback_set(gp, i,
sig, src, func, data,
(((!!propagate) & 1) | _JUST_ADDED));
return ;
}
if (gp->flags[i >> 1] & (_DELETE_ME << 4))
{
_edje_signal_callback_unset(gp, i + 1);
_edje_signal_callback_set(gp, i + 1,
sig, src, func, data,
(((!!propagate) & 1) | _JUST_ADDED));
return ;
}
}
_edje_signal_callback_grow(gp);
// Set propagate and just_added flags
_edje_signal_callback_set(gp, gp->matches->matches_count - 1,
sig, src, func, data, (((!!propagate) & 1) | _JUST_ADDED));
return ;
}
const Edje_Signal_Callback_Group *
_edje_signal_callback_alloc(void)
{
Edje_Signal_Callback_Group *escg;
Edje_Signal_Callback_Matches *m;
escg = calloc(1, sizeof (Edje_Signal_Callback_Group));
if (!escg) return NULL;
m = calloc(1, sizeof (Edje_Signal_Callback_Matches));
if (!m)
{
free(escg);
return NULL;
}
EINA_REFCOUNT_REF(m);
escg->matches = m;
return escg;
}
void
_edje_signal_callback_matches_unref(Edje_Signal_Callback_Matches *m)
{
EINA_REFCOUNT_UNREF(m)
{
unsigned int i;
_edje_signal_callback_patterns_unref(m->patterns);
if (m->hashed)
eina_hash_del(signal_match, m, m);
for (i = 0; i < m->matches_count; ++i)
{
eina_stringshare_del(m->matches[i].signal);
eina_stringshare_del(m->matches[i].source);
}
free(m->matches);
free(m);
}
}
void
_edje_signal_callback_free(const Edje_Signal_Callback_Group *cgp)
{
Edje_Signal_Callback_Group *gp = (Edje_Signal_Callback_Group*) cgp;
if (!gp) return ;
_edje_signal_callback_matches_unref((Edje_Signal_Callback_Matches*) gp->matches);
gp->matches = NULL;
free(gp->custom_data);
free(gp);
}
void *
_edje_signal_callback_disable(const Edje_Signal_Callback_Group *cgp,
const char *sig, const char *src,
Edje_Signal_Cb func, void *data)
{
Edje_Signal_Callback_Group *gp = (Edje_Signal_Callback_Group*) cgp;
unsigned int i;
// FIXME: Shall we check DELETE_ME flags ?
for (i = 0; i < gp->matches->matches_count; ++i)
{
if (sig == gp->matches->matches[i].signal &&
src == gp->matches->matches[i].source &&
func == gp->matches->matches[i].func &&
gp->custom_data[i] == data)
{
Eina_Bool flags;
flags = gp->flags[i >> 1] | (_DELETE_ME << ((i & 1) * 4));
gp->flags[i >> 1] = flags;
return gp->custom_data[i];
}
}
if (data == NULL)
{
for (i = 0; i < gp->matches->matches_count; ++i)
{
if (sig == gp->matches->matches[i].signal &&
src == gp->matches->matches[i].source &&
func == gp->matches->matches[i].func)
{
Eina_Bool flags;
flags = gp->flags[i >> 1] | (_DELETE_ME << ((i & 1) * 4));
gp->flags[i >> 1] = flags;
return gp->custom_data[i];
}
}
}
return NULL;
}
static void
_edje_signal_callback_move_last(Edje_Signal_Callback_Group *gp,
int i)
{
Edje_Signal_Callback_Matches *m;
int j;
m = (Edje_Signal_Callback_Matches*) gp->matches;
for (j = (int) --m->matches_count; j > i; --j)
{
if (!(gp->flags[j >> 1] & (_DELETE_ME << ((j & 1) * 4))))
{
m->matches[i].signal = m->matches[j].signal;
m->matches[i].source = m->matches[j].source;
m->matches[i].func = m->matches[j].func;
gp->flags[i] = (gp->flags[i >> 1] & (0xF << (((i & 1) ^ 1) * 4))) |
(gp->flags[j >> 1] & (0xF << (((j & 1) * 4))));
return ;
}
--m->matches_count;
}
}
const Edje_Signals_Sources_Patterns *
_edje_signal_callback_patterns_ref(const Edje_Signal_Callback_Group *gp)
{
const Edje_Signal_Callback_Matches *m;
Edje_Signal_Callback_Matches *tmp;
if (gp->matches->hashed)
goto got_it;
m = eina_hash_find(signal_match, gp->matches);
if (!m)
{
tmp = (Edje_Signal_Callback_Matches*) gp->matches;
if (!(tmp->patterns && (EINA_REFCOUNT_GET(tmp->patterns) > 1)))
{
// Let compact it and remove uneeded pattern before building it
// We can do that because the custom data are kept local into the matching code.
Eina_Bool delete_me = _DELETE_ME | (_DELETE_ME << 4);
unsigned int i;
for (i = 0; i < tmp->matches_count; i += 2)
{
if (gp->flags[i >> 1] & delete_me)
{
if (gp->flags[i >> 1] & _DELETE_ME)
{
_edje_signal_callback_move_last((Edje_Signal_Callback_Group*) gp, i);
}
if (i + 1 < gp->matches->matches_count &&
(gp->flags[i >> 1] & (_DELETE_ME << 4)))
{
_edje_signal_callback_move_last((Edje_Signal_Callback_Group*) gp, i + 1);
}
}
}
}
_edje_signal_callback_patterns_unref(tmp->patterns);
tmp->patterns = NULL;
_edje_callbacks_patterns_init((Edje_Signal_Callback_Group*) gp);
eina_hash_add(signal_match, tmp, tmp);
tmp->hashed = EINA_TRUE;
}
else
{
_edje_signal_callback_matches_unref((Edje_Signal_Callback_Matches*) gp->matches);
((Edje_Signal_Callback_Group*)gp)->matches = m;
tmp = (Edje_Signal_Callback_Matches*) gp->matches;
EINA_REFCOUNT_REF(tmp);
}
got_it:
tmp = (Edje_Signal_Callback_Matches*) gp->matches;
EINA_REFCOUNT_REF(tmp->patterns);
return gp->matches->patterns;
}
void
_edje_signal_callback_patterns_unref(const Edje_Signals_Sources_Patterns *essp)
{
Edje_Signals_Sources_Patterns *ssp;
if (!essp) return ;
ssp = (Edje_Signals_Sources_Patterns*) essp;
EINA_REFCOUNT_UNREF(ssp)
{
_edje_signals_sources_patterns_clean(ssp);
eina_rbtree_delete(ssp->exact_match,
EINA_RBTREE_FREE_CB(edje_match_signal_source_free),
NULL);
ssp->exact_match = NULL;
eina_inarray_flush(&ssp->u.callbacks.globing);
free(ssp);
}
}

View File

@ -480,7 +480,6 @@ _edje_smart_class_constructor(Eo_Class *klass)
EO_OP_FUNC(EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_MESSAGE_SIGNAL_PROCESS), _message_signal_process),
EO_OP_FUNC(EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_ADD), _signal_callback_add),
EO_OP_FUNC(EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_DEL), _signal_callback_del),
EO_OP_FUNC(EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_DEL_FULL), _signal_callback_del_full),
EO_OP_FUNC(EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_SIGNAL_EMIT), _signal_emit),
EO_OP_FUNC(EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_PLAY_SET), _play_set),
EO_OP_FUNC(EDJE_OBJ_ID(EDJE_OBJ_SUB_ID_PLAY_GET), _play_get),
@ -626,7 +625,6 @@ static const Eo_Op_Description op_desc[] = {
EO_OP_DESCRIPTION(EDJE_OBJ_SUB_ID_MESSAGE_SIGNAL_PROCESS, "Process an object's message queue."),
EO_OP_DESCRIPTION(EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_ADD, "Add a callback for an arriving Edje signal, emitted by"),
EO_OP_DESCRIPTION(EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_DEL, "Remove a signal-triggered callback from an object."),
EO_OP_DESCRIPTION(EDJE_OBJ_SUB_ID_SIGNAL_CALLBACK_DEL_FULL, "Unregister/delete a callback set for an arriving Edje"),
EO_OP_DESCRIPTION(EDJE_OBJ_SUB_ID_SIGNAL_EMIT, "Send/emit an Edje signal to a given Edje object"),
EO_OP_DESCRIPTION(EDJE_OBJ_SUB_ID_PLAY_SET, "Set the Edje object to playing or paused states."),
EO_OP_DESCRIPTION(EDJE_OBJ_SUB_ID_PLAY_GET, "Get the Edje object's state."),