efl/legacy/edje/src/lib/edje_message_queue.c

817 lines
20 KiB
C

#include <string.h>
#include "edje_private.h"
static int _injob = 0;
static Ecore_Job *_job = NULL;
static Ecore_Timer *_job_loss_timer = NULL;
static Eina_List *msgq = NULL;
static Eina_List *tmp_msgq = NULL;
/*============================================================================*
* API *
*============================================================================*/
/**
* @addtogroup Edje_message_queue_Group Message_Queue
*
* @brief These functions provide an abstraction layer between the
* application code and the interface, while allowing extremely
* flexible dynamic layouts and animations.
*
* @{
*/
/**
* @brief Send message to object.
*
* @param obj The edje object reference.
* @param type The type of message to send.
* @param id A identification number for the message.
* @param msg The message to be send.
*
*
* This function sends messages to this object and to all of its child
* objects, if applicable. The function that handles messages arriving
* at this edje object is is set with
* edje_object_message_handler_set().
*
* @see edje_object_message_handler_set()
*
*/
EAPI void
edje_object_message_send(Evas_Object *obj, Edje_Message_Type type, int id, void *msg)
{
Edje *ed;
unsigned int i;
ed = _edje_fetch(obj);
if (!ed) return;
_edje_message_send(ed, EDJE_QUEUE_SCRIPT, type, id, msg);
for (i = 0; i < ed->table_parts_size; i++)
{
Edje_Real_Part *rp = ed->table_parts[i];
if ((rp->part->type == EDJE_PART_TYPE_GROUP) && (rp->swallowed_object))
edje_object_message_send(rp->swallowed_object, type, id, msg);
}
}
/**
* @brief Set the message handler function for this an object.
*
* @param obj The edje object reference.
* @param func The function to handle messages.
* @param data The data to be associated to the message handler.
*
*
* This function associates a message handler function and data to the
* edje object.
*
*/
EAPI void
edje_object_message_handler_set(Evas_Object *obj, void (*func) (void *data, Evas_Object *obj, Edje_Message_Type type, int id, void *msg), void *data)
{
Edje *ed;
ed = _edje_fetch(obj);
if (!ed) return;
_edje_message_cb_set(ed, func, data);
}
/**
* @brief Process an object's message queue.
*
* @param obj The edje object reference.
*
* This function goes through the object message queue processing the
* pending messages for *this* specific edje object. Normally they'd
* be processed only at idle time.
*
*/
EAPI void
edje_object_message_signal_process(Evas_Object *obj)
{
Eina_List *l, *tmpq = NULL;
Edje *ed;
Edje_Message *em;
const void *data;
ed = _edje_fetch(obj);
if (!ed) return;
EINA_LIST_FOREACH(msgq, l, em)
if (em->edje == ed)
tmpq = eina_list_append(tmpq, em);
/* now remove them from the old queue */
EINA_LIST_FOREACH(tmpq, l, data)
msgq = eina_list_remove(msgq, data);
/* a temporary message queue */
if (tmp_msgq)
{
while (tmpq)
{
tmp_msgq = eina_list_append(tmp_msgq, tmpq->data);
tmpq = eina_list_remove_list(tmpq, tmpq);
}
}
else
{
tmp_msgq = tmpq;
tmpq = NULL;
}
while (tmp_msgq)
{
Edje_Message *em;
em = tmp_msgq->data;
tmp_msgq = eina_list_remove_list(tmp_msgq, tmp_msgq);
em->edje->message.num--;
_edje_message_process(em);
_edje_message_free(em);
}
}
/**
* @brief Process all queued up edje messages.
*
* This function triggers the processing of messages addressed to any
* (alive) edje objects.
*
*/
EAPI void
edje_message_signal_process(void)
{
_edje_message_queue_process();
}
static Eina_Bool
_edje_dummy_timer(void *data __UNUSED__)
{
return ECORE_CALLBACK_CANCEL;
}
static void
_edje_job(void *data __UNUSED__)
{
if (_job_loss_timer)
{
ecore_timer_del(_job_loss_timer);
_job_loss_timer = NULL;
}
_job = NULL;
_injob++;
_edje_message_queue_process();
_injob--;
}
static Eina_Bool
_edje_job_loss_timer(void *data __UNUSED__)
{
_job_loss_timer = NULL;
if (!_job)
{
_job = ecore_job_add(_edje_job, NULL);
}
return ECORE_CALLBACK_CANCEL;
}
void
_edje_message_init(void)
{
}
void
_edje_message_shutdown(void)
{
_edje_message_queue_clear();
if (_job_loss_timer)
{
ecore_timer_del(_job_loss_timer);
_job_loss_timer = NULL;
}
if (_job)
{
ecore_job_del(_job);
_job = NULL;
}
}
void
_edje_message_cb_set(Edje *ed, void (*func) (void *data, Evas_Object *obj, Edje_Message_Type type, int id, void *msg), void *data)
{
unsigned int i;
ed->message.func = func;
ed->message.data = data;
for (i = 0 ; i < ed->table_parts_size ; i++) {
Edje_Real_Part *rp;
rp = ed->table_parts[i];
if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object) {
Edje *edj2 = _edje_fetch(rp->swallowed_object);
if (!edj2) continue;
_edje_message_cb_set(edj2, func, data);
}
}
}
Edje_Message *
_edje_message_new(Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id)
{
Edje_Message *em;
em = calloc(1, sizeof(Edje_Message));
if (!em) return NULL;
em->edje = ed;
em->queue = queue;
em->type = type;
em->id = id;
em->edje->message.num++;
return em;
}
void
_edje_message_free(Edje_Message *em)
{
if (em->msg)
{
int i;
switch (em->type)
{
case EDJE_MESSAGE_STRING:
{
Edje_Message_String *emsg;
emsg = (Edje_Message_String *)em->msg;
free(emsg->str);
free(emsg);
}
break;
case EDJE_MESSAGE_INT:
{
Edje_Message_Int *emsg;
emsg = (Edje_Message_Int *)em->msg;
free(emsg);
}
break;
case EDJE_MESSAGE_FLOAT:
{
Edje_Message_Float *emsg;
emsg = (Edje_Message_Float *)em->msg;
free(emsg);
}
break;
case EDJE_MESSAGE_INT_SET:
{
Edje_Message_Int_Set *emsg;
emsg = (Edje_Message_Int_Set *)em->msg;
free(emsg);
}
break;
case EDJE_MESSAGE_FLOAT_SET:
{
Edje_Message_Float_Set *emsg;
emsg = (Edje_Message_Float_Set *)em->msg;
free(emsg);
}
break;
case EDJE_MESSAGE_STRING_FLOAT:
{
Edje_Message_String_Float *emsg;
emsg = (Edje_Message_String_Float *)em->msg;
free(emsg->str);
free(emsg);
}
break;
case EDJE_MESSAGE_STRING_INT:
{
Edje_Message_String_Int *emsg;
emsg = (Edje_Message_String_Int *)em->msg;
free(emsg->str);
free(emsg);
}
break;
case EDJE_MESSAGE_STRING_FLOAT_SET:
{
Edje_Message_String_Float_Set *emsg;
emsg = (Edje_Message_String_Float_Set *)em->msg;
free(emsg->str);
free(emsg);
}
break;
case EDJE_MESSAGE_STRING_INT_SET:
{
Edje_Message_String_Int_Set *emsg;
emsg = (Edje_Message_String_Int_Set *)em->msg;
free(emsg->str);
free(emsg);
}
break;
case EDJE_MESSAGE_SIGNAL:
{
Edje_Message_Signal *emsg;
emsg = (Edje_Message_Signal *)em->msg;
if (emsg->sig) eina_stringshare_del(emsg->sig);
if (emsg->src) eina_stringshare_del(emsg->src);
free(emsg);
}
break;
case EDJE_MESSAGE_STRING_SET:
{
Edje_Message_String_Set *emsg;
emsg = (Edje_Message_String_Set *)em->msg;
for (i = 0; i < emsg->count; i++)
free(emsg->str[i]);
free(emsg);
}
break;
case EDJE_MESSAGE_NONE:
default:
break;
}
}
free(em);
}
void
_edje_message_send(Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id, void *emsg)
{
/* FIXME: check all malloc & strdup fails and gracefully unroll and exit */
Edje_Message *em;
int i;
unsigned char *msg = NULL;
em = _edje_message_new(ed, queue, type, id);
if (!em) return;
if (_job)
{
ecore_job_del(_job);
_job = NULL;
}
if (_injob > 0)
{
_job_loss_timer = ecore_timer_add(0.01, _edje_job_loss_timer, NULL);
}
else
{
if (!_job)
{
_job = ecore_job_add(_edje_job, NULL);
}
if (_job_loss_timer)
{
ecore_timer_del(_job_loss_timer);
_job_loss_timer = NULL;
}
}
switch (em->type)
{
case EDJE_MESSAGE_NONE:
break;
case EDJE_MESSAGE_SIGNAL:
{
Edje_Message_Signal *emsg2, *emsg3;
emsg2 = (Edje_Message_Signal *)emsg;
emsg3 = calloc(1, sizeof(Edje_Message_Signal));
if (emsg2->sig) emsg3->sig = eina_stringshare_add(emsg2->sig);
if (emsg2->src) emsg3->src = eina_stringshare_add(emsg2->src);
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_STRING:
{
Edje_Message_String *emsg2, *emsg3;
emsg2 = (Edje_Message_String *)emsg;
emsg3 = malloc(sizeof(Edje_Message_String));
emsg3->str = strdup(emsg2->str);
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_INT:
{
Edje_Message_Int *emsg2, *emsg3;
emsg2 = (Edje_Message_Int *)emsg;
emsg3 = malloc(sizeof(Edje_Message_Int));
emsg3->val = emsg2->val;
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_FLOAT:
{
Edje_Message_Float *emsg2, *emsg3;
emsg2 = (Edje_Message_Float *)emsg;
emsg3 = malloc(sizeof(Edje_Message_Float));
emsg3->val = emsg2->val;
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_STRING_SET:
{
Edje_Message_String_Set *emsg2, *emsg3;
emsg2 = (Edje_Message_String_Set *)emsg;
emsg3 = malloc(sizeof(Edje_Message_String_Set) + ((emsg2->count - 1) * sizeof(char *)));
emsg3->count = emsg2->count;
for (i = 0; i < emsg3->count; i++)
emsg3->str[i] = strdup(emsg2->str[i]);
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_INT_SET:
{
Edje_Message_Int_Set *emsg2, *emsg3;
emsg2 = (Edje_Message_Int_Set *)emsg;
emsg3 = malloc(sizeof(Edje_Message_Int_Set) + ((emsg2->count - 1) * sizeof(int)));
emsg3->count = emsg2->count;
for (i = 0; i < emsg3->count; i++)
emsg3->val[i] = emsg2->val[i];
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_FLOAT_SET:
{
Edje_Message_Float_Set *emsg2, *emsg3;
emsg2 = (Edje_Message_Float_Set *)emsg;
emsg3 = malloc(sizeof(Edje_Message_Float_Set) + ((emsg2->count - 1) * sizeof(double)));
emsg3->count = emsg2->count;
for (i = 0; i < emsg3->count; i++)
emsg3->val[i] = emsg2->val[i];
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_STRING_INT:
{
Edje_Message_String_Int *emsg2, *emsg3;
emsg2 = (Edje_Message_String_Int *)emsg;
emsg3 = malloc(sizeof(Edje_Message_String_Int));
emsg3->str = strdup(emsg2->str);
emsg3->val = emsg2->val;
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_STRING_FLOAT:
{
Edje_Message_String_Float *emsg2, *emsg3;
emsg2 = (Edje_Message_String_Float *)emsg;
emsg3 = malloc(sizeof(Edje_Message_String_Float));
emsg3->str = strdup(emsg2->str);
emsg3->val = emsg2->val;
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_STRING_INT_SET:
{
Edje_Message_String_Int_Set *emsg2, *emsg3;
emsg2 = (Edje_Message_String_Int_Set *)emsg;
emsg3 = malloc(sizeof(Edje_Message_String_Int_Set) + ((emsg2->count - 1) * sizeof(int)));
emsg3->str = strdup(emsg2->str);
emsg3->count = emsg2->count;
for (i = 0; i < emsg3->count; i++)
emsg3->val[i] = emsg2->val[i];
msg = (unsigned char *)emsg3;
}
break;
case EDJE_MESSAGE_STRING_FLOAT_SET:
{
Edje_Message_String_Float_Set *emsg2, *emsg3;
emsg2 = (Edje_Message_String_Float_Set *)emsg;
emsg3 = malloc(sizeof(Edje_Message_String_Float_Set) + ((emsg2->count - 1) * sizeof(double)));
emsg3->str = strdup(emsg2->str);
emsg3->count = emsg2->count;
for (i = 0; i < emsg3->count; i++)
emsg3->val[i] = emsg2->val[i];
msg = (unsigned char *)emsg3;
}
break;
default:
break;
}
em->msg = msg;
msgq = eina_list_append(msgq, em);
}
void
_edje_message_parameters_push(Edje_Message *em)
{
int i;
/* these params ALWAYS go on */
/* first param is the message type - always */
embryo_parameter_cell_push(em->edje->collection->script,
(Embryo_Cell)em->type);
/* 2nd param is the integer of the event id - always there */
embryo_parameter_cell_push(em->edje->collection->script,
(Embryo_Cell)em->id);
/* the rest is varags of whatever is in the msg */
switch (em->type)
{
case EDJE_MESSAGE_NONE:
break;
case EDJE_MESSAGE_STRING:
embryo_parameter_string_push(em->edje->collection->script,
((Edje_Message_String *)em->msg)->str);
break;
case EDJE_MESSAGE_INT:
{
Embryo_Cell v;
v = (Embryo_Cell)((Edje_Message_Int *)em->msg)->val;
embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
}
break;
case EDJE_MESSAGE_FLOAT:
{
Embryo_Cell v;
float fv;
fv = ((Edje_Message_Float *)em->msg)->val;
v = EMBRYO_FLOAT_TO_CELL(fv);
embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
}
break;
case EDJE_MESSAGE_STRING_SET:
for (i = 0; i < ((Edje_Message_String_Set *)em->msg)->count; i++)
embryo_parameter_string_push(em->edje->collection->script,
((Edje_Message_String_Set *)em->msg)->str[i]);
break;
case EDJE_MESSAGE_INT_SET:
for (i = 0; i < ((Edje_Message_Int_Set *)em->msg)->count; i++)
{
Embryo_Cell v;
v = (Embryo_Cell)((Edje_Message_Int_Set *)em->msg)->val[i];
embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
}
break;
case EDJE_MESSAGE_FLOAT_SET:
for (i = 0; i < ((Edje_Message_Float_Set *)em->msg)->count; i++)
{
Embryo_Cell v;
float fv;
fv = ((Edje_Message_Float_Set *)em->msg)->val[i];
v = EMBRYO_FLOAT_TO_CELL(fv);
embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
}
break;
case EDJE_MESSAGE_STRING_INT:
embryo_parameter_string_push(em->edje->collection->script,
((Edje_Message_String_Int *)em->msg)->str);
{
Embryo_Cell v;
v = (Embryo_Cell)((Edje_Message_String_Int *)em->msg)->val;
embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
}
break;
case EDJE_MESSAGE_STRING_FLOAT:
embryo_parameter_string_push(em->edje->collection->script,
((Edje_Message_String_Float *)em->msg)->str);
{
Embryo_Cell v;
float fv;
fv = ((Edje_Message_String_Float *)em->msg)->val;
v = EMBRYO_FLOAT_TO_CELL(fv);
embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
}
break;
case EDJE_MESSAGE_STRING_INT_SET:
embryo_parameter_string_push(em->edje->collection->script,
((Edje_Message_String_Int_Set *)em->msg)->str);
for (i = 0; i < ((Edje_Message_String_Int_Set *)em->msg)->count; i++)
{
Embryo_Cell v;
v = (Embryo_Cell)((Edje_Message_String_Int_Set *)em->msg)->val[i];
embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
}
break;
case EDJE_MESSAGE_STRING_FLOAT_SET:
embryo_parameter_string_push(em->edje->collection->script,
((Edje_Message_String_Float_Set *)em->msg)->str);
for (i = 0; i < ((Edje_Message_String_Float_Set *)em->msg)->count; i++)
{
Embryo_Cell v;
float fv;
fv = ((Edje_Message_String_Float_Set *)em->msg)->val[i];
v = EMBRYO_FLOAT_TO_CELL(fv);
embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
}
break;
default:
break;
}
}
void
_edje_message_process(Edje_Message *em)
{
Embryo_Function fn;
void *pdata;
/* signals are only handled one way */
if (em->type == EDJE_MESSAGE_SIGNAL)
{
_edje_emit_handle(em->edje,
((Edje_Message_Signal *)em->msg)->sig,
((Edje_Message_Signal *)em->msg)->src);
return;
}
/* if this has been queued up for the app then just call the callback */
if (em->queue == EDJE_QUEUE_APP)
{
if (em->edje->message.func)
em->edje->message.func(em->edje->message.data, em->edje->obj,
em->type, em->id, em->msg);
return;
}
/* now this message is destined for the script message handler fn */
if (!(em->edje->collection)) return;
if ((em->edje->collection->script) && _edje_script_only (em->edje))
{
_edje_script_only_message(em->edje, em);
return;
}
if (em->edje->L)
{
_edje_lua_script_only_message(em->edje, em);
return;
}
fn = embryo_program_function_find(em->edje->collection->script, "message");
if (fn == EMBRYO_FUNCTION_NONE) return;
/* reset the engine */
_edje_embryo_script_reset(em->edje);
_edje_message_parameters_push(em);
embryo_program_vm_push(em->edje->collection->script);
_edje_embryo_globals_init(em->edje);
pdata = embryo_program_data_get(em->edje->collection->script);
embryo_program_data_set(em->edje->collection->script, em->edje);
embryo_program_max_cycle_run_set(em->edje->collection->script, 5000000);
embryo_program_run(em->edje->collection->script, fn);
embryo_program_data_set(em->edje->collection->script, pdata);
embryo_program_vm_pop(em->edje->collection->script);
}
void
_edje_message_queue_process(void)
{
int i;
if (!msgq) return;
/* allow the message queue to feed itself up to 8 times before forcing */
/* us to go back to normal processing and let a 0 timeout deal with it */
for (i = 0; (i < 8) && (msgq); i++)
{
/* a temporary message queue */
if (tmp_msgq)
{
while (msgq)
{
tmp_msgq = eina_list_append(tmp_msgq, msgq->data);
msgq = eina_list_remove_list(msgq, msgq);
}
}
else
{
tmp_msgq = msgq;
msgq = NULL;
}
while (tmp_msgq)
{
Edje_Message *em;
Edje *ed;
em = tmp_msgq->data;
ed = em->edje;
tmp_msgq = eina_list_remove_list(tmp_msgq, tmp_msgq);
em->edje->message.num--;
if (!ed->delete_me)
{
ed->processing_messages++;
_edje_message_process(em);
_edje_message_free(em);
ed->processing_messages--;
}
else
_edje_message_free(em);
if (ed->processing_messages == 0)
{
if (ed->delete_me) _edje_del(ed);
}
}
}
/* if the message queue filled again set a timer to expire in 0.0 sec */
/* to get the idle enterer to be run again */
if (msgq)
{
ecore_timer_add(0.0, _edje_dummy_timer, NULL);
}
}
void
_edje_message_queue_clear(void)
{
while (msgq)
{
Edje_Message *em;
em = msgq->data;
msgq = eina_list_remove_list(msgq, msgq);
em->edje->message.num--;
_edje_message_free(em);
}
while (tmp_msgq)
{
Edje_Message *em;
em = tmp_msgq->data;
tmp_msgq = eina_list_remove_list(tmp_msgq, tmp_msgq);
em->edje->message.num--;
_edje_message_free(em);
}
}
void
_edje_message_del(Edje *ed)
{
Eina_List *l;
if (ed->message.num <= 0) return;
/* delete any messages on the main queue for this edje object */
for (l = msgq; l; )
{
Edje_Message *em;
Eina_List *lp;
em = eina_list_data_get(l);
lp = l;
l = eina_list_next(l);
if (em->edje == ed)
{
msgq = eina_list_remove_list(msgq, lp);
em->edje->message.num--;
_edje_message_free(em);
}
if (ed->message.num <= 0) return;
}
/* delete any on the processing queue */
for (l = tmp_msgq; l; )
{
Edje_Message *em;
Eina_List *lp;
em = eina_list_data_get(l);
lp = l;
l = eina_list_next(l);
if (em->edje == ed)
{
tmp_msgq = eina_list_remove_list(tmp_msgq, lp);
em->edje->message.num--;
_edje_message_free(em);
}
if (ed->message.num <= 0) return;
}
}
/**
*
* @}
*/