2013-02-19 01:55:37 -08:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "edje_private.h"
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2013-06-20 04:28:18 -07:00
|
|
|
if (gp->matches->patterns) return;
|
2013-02-19 01:55:37 -08:00
|
|
|
|
|
|
|
tmp = (Edje_Signal_Callback_Matches*) gp->matches;
|
|
|
|
tmp->patterns = calloc(1, sizeof (Edje_Signals_Sources_Patterns));
|
2013-06-20 04:28:18 -07:00
|
|
|
if (!gp->matches->patterns) return;
|
2013-02-19 01:55:37 -08:00
|
|
|
|
|
|
|
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,
|
2013-07-18 15:00:57 -07:00
|
|
|
Edje_Signal_Cb func, void *data, Edje_Signal_Callback_Flags flags)
|
2013-02-19 01:55:37 -08:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2013-07-18 15:00:57 -07:00
|
|
|
gp->flags[idx] = flags;
|
2013-02-19 01:55:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static Edje_Signal_Callback_Group *
|
|
|
|
_edje_signal_callback_grow(Edje_Signal_Callback_Group *gp)
|
|
|
|
{
|
|
|
|
Edje_Signal_Callback_Matches *tmp;
|
|
|
|
|
|
|
|
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);
|
2013-07-18 15:00:57 -07:00
|
|
|
gp->flags = realloc(gp->flags, sizeof (Edje_Signal_Callback_Flags) * tmp->matches_count);
|
2013-02-19 01:55:37 -08:00
|
|
|
|
|
|
|
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;
|
2013-07-18 15:00:57 -07:00
|
|
|
Edje_Signal_Callback_Flags flags;
|
|
|
|
|
|
|
|
flags.delete_me = EINA_FALSE;
|
|
|
|
flags.just_added = EINA_TRUE;
|
|
|
|
flags.propagate = !!propagate;
|
2013-02-19 01:55:37 -08:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
{
|
2013-07-18 15:00:57 -07:00
|
|
|
if (gp->flags[i].delete_me)
|
2013-02-19 01:55:37 -08:00
|
|
|
{
|
|
|
|
_edje_signal_callback_unset(gp, i);
|
2013-07-18 15:00:57 -07:00
|
|
|
_edje_signal_callback_set(gp, i, sig, src, func, data, flags);
|
2013-06-20 04:28:18 -07:00
|
|
|
return;
|
2013-02-19 01:55:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2013-06-20 04:28:18 -07:00
|
|
|
if (!tmp_dup) return;
|
2013-02-19 01:55:37 -08:00
|
|
|
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
|
2013-07-18 15:00:57 -07:00
|
|
|
for (i = 0; i < gp->matches->matches_count; i++)
|
|
|
|
if (gp->flags[i].delete_me)
|
2013-02-19 01:55:37 -08:00
|
|
|
{
|
2013-07-18 15:00:57 -07:00
|
|
|
_edje_signal_callback_unset(gp, i);
|
|
|
|
_edje_signal_callback_set(gp, i, sig, src, func, data, flags);
|
|
|
|
return;
|
2013-02-19 01:55:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
_edje_signal_callback_grow(gp);
|
|
|
|
|
|
|
|
// Set propagate and just_added flags
|
|
|
|
_edje_signal_callback_set(gp, gp->matches->matches_count - 1,
|
2013-07-18 15:00:57 -07:00
|
|
|
sig, src, func, data, flags);
|
2013-02-19 01:55:37 -08:00
|
|
|
|
2013-06-20 04:28:18 -07:00
|
|
|
return;
|
2013-02-19 01:55:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2013-06-20 04:28:18 -07:00
|
|
|
if (!gp) return;
|
2013-02-19 01:55:37 -08:00
|
|
|
|
|
|
|
_edje_signal_callback_matches_unref((Edje_Signal_Callback_Matches*) gp->matches);
|
|
|
|
gp->matches = NULL;
|
2013-03-22 05:01:53 -07:00
|
|
|
free(gp->flags);
|
2013-02-19 01:55:37 -08:00
|
|
|
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;
|
|
|
|
|
2013-03-18 22:48:57 -07:00
|
|
|
if (!gp || !gp->matches) return NULL;
|
|
|
|
|
2013-02-19 01:55:37 -08:00
|
|
|
// 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)
|
|
|
|
{
|
2013-07-18 15:00:57 -07:00
|
|
|
gp->flags[i].delete_me = EINA_TRUE;
|
2013-02-19 01:55:37 -08:00
|
|
|
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)
|
|
|
|
{
|
2013-07-18 15:00:57 -07:00
|
|
|
gp->flags[i].delete_me = EINA_TRUE;
|
2013-02-19 01:55:37 -08:00
|
|
|
return gp->custom_data[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_edje_signal_callback_move_last(Edje_Signal_Callback_Group *gp,
|
2013-07-18 15:00:57 -07:00
|
|
|
unsigned int i)
|
2013-02-19 01:55:37 -08:00
|
|
|
{
|
|
|
|
Edje_Signal_Callback_Matches *m;
|
2013-07-18 15:00:57 -07:00
|
|
|
unsigned int j;
|
2013-02-19 01:55:37 -08:00
|
|
|
|
|
|
|
m = (Edje_Signal_Callback_Matches*) gp->matches;
|
|
|
|
|
2013-07-18 15:00:57 -07:00
|
|
|
for (j = --m->matches_count; j > i; --j)
|
2013-02-19 01:55:37 -08:00
|
|
|
{
|
2013-07-18 15:00:57 -07:00
|
|
|
if (!gp->flags[j].delete_me)
|
2013-02-19 01:55:37 -08:00
|
|
|
{
|
2013-07-18 10:09:19 -07:00
|
|
|
_edje_signal_callback_unset(gp, i);
|
2013-02-19 01:55:37 -08:00
|
|
|
m->matches[i].signal = m->matches[j].signal;
|
|
|
|
m->matches[i].source = m->matches[j].source;
|
|
|
|
m->matches[i].func = m->matches[j].func;
|
2013-07-18 15:00:57 -07:00
|
|
|
gp->flags[i] = gp->flags[j];
|
2013-07-19 07:33:02 -07:00
|
|
|
gp->custom_data[i] = gp->custom_data[j];
|
2013-06-20 04:28:18 -07:00
|
|
|
return;
|
2013-02-19 01:55:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
unsigned int i;
|
|
|
|
|
2013-07-18 15:00:57 -07:00
|
|
|
for (i = 0; i < tmp->matches_count; i++)
|
2013-02-19 01:55:37 -08:00
|
|
|
{
|
2013-07-18 15:00:57 -07:00
|
|
|
if (gp->flags[i].delete_me)
|
|
|
|
_edje_signal_callback_move_last((Edje_Signal_Callback_Group*) gp, i);
|
2013-02-19 01:55:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
_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;
|
|
|
|
|
2013-06-20 04:28:18 -07:00
|
|
|
if (!essp) return;
|
2013-02-19 01:55:37 -08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2013-03-16 21:00:20 -07:00
|
|
|
|
|
|
|
void
|
2013-07-18 15:00:57 -07:00
|
|
|
_edje_signal_callback_reset(Edje_Signal_Callback_Flags *flags, unsigned int length)
|
2013-03-16 21:00:20 -07:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < length; ++i)
|
2013-07-18 15:00:57 -07:00
|
|
|
flags[i].just_added = EINA_FALSE;
|
2013-03-16 21:00:20 -07:00
|
|
|
}
|
|
|
|
|