1 #include "edje_private.h"
2 
3 static void _edje_message_propagate_send(Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id, void *emsg, Eina_Bool prop);
4 
5 static int _injob = 0;
6 static Ecore_Job *_job = NULL;
7 static Ecore_Timer *_job_loss_timer = NULL;
8 
9 static Eina_Inlist *msgq = NULL;
10 static Eina_Inlist *tmp_msgq = NULL;
11 static int tmp_msgq_processing = 0;
12 static int tmp_msgq_restart = 0;
13 
14 static Eina_Inlist *_edje_msg_trash = NULL;
15 
16 /*============================================================================*
17 *                                   API                                      *
18 *============================================================================*/
19 
20 #define INLIST_CONTAINER(container_type, list, list_entry) \
21    (container_type *)((unsigned char *)list - offsetof(container_type, list_entry))
22 
23 static Edje_Message *
_edje_msg_trash_pop(void)24 _edje_msg_trash_pop(void)
25 {
26    Edje_Message *em;
27 
28    if (!_edje_msg_trash) return NULL;
29    em = INLIST_CONTAINER(Edje_Message, _edje_msg_trash, inlist_main);
30    _edje_msg_trash = eina_inlist_remove(_edje_msg_trash, &(em->inlist_main));
31    memset(em, 0, sizeof(Edje_Message));
32    return em;
33 }
34 
35 static void
_edje_msg_trash_push(Edje_Message * em)36 _edje_msg_trash_push(Edje_Message *em)
37 {
38    _edje_msg_trash = eina_inlist_prepend(_edje_msg_trash, &(em->inlist_main));
39 }
40 
41 static void
_edje_msg_trash_clear(void)42 _edje_msg_trash_clear(void)
43 {
44    Edje_Message *em;
45 
46    while (_edje_msg_trash)
47      {
48         em = _edje_msg_trash_pop();
49         free(em);
50      }
51 }
52 
53 static void
_edje_object_message_propagate_send(Evas_Object * obj,Edje_Message_Type type,int id,void * msg,Eina_Bool prop)54 _edje_object_message_propagate_send(Evas_Object *obj, Edje_Message_Type type, int id, void *msg, Eina_Bool prop)
55 {
56    Edje *ed;
57    Eina_List *l;
58    Evas_Object *o;
59 
60    ed = _edje_fetch(obj);
61    if (!ed) return;
62    _edje_message_propagate_send(ed, EDJE_QUEUE_SCRIPT, type, id, msg, prop);
63    EINA_LIST_FOREACH(ed->subobjs, l, o)
64      {
65         _edje_object_message_propagate_send(o, type, id, msg, EINA_TRUE);
66      }
67 }
68 
69 EOLIAN void
_efl_canvas_layout_efl_layout_signal_message_send(Eo * obj,Edje * pd EINA_UNUSED,int id,const Eina_Value val)70 _efl_canvas_layout_efl_layout_signal_message_send(Eo *obj, Edje *pd EINA_UNUSED, int id, const Eina_Value val)
71 {
72    const Eina_Value_Type *valtype;
73    Edje_Message_Type msgtype;
74 
75    /* Note: Only primitive types & arrays of them are supported.
76     * This reduces complexity and I couldn't find many real uses for combo
77     * types (string+int or string+float).
78     */
79 
80    union {
81       Edje_Message_String str;
82       Edje_Message_Int i;
83       Edje_Message_Float f;
84       Edje_Message_String_Set ss;
85       Edje_Message_Int_Set is;
86       Edje_Message_Float_Set fs;
87       //Edje_Message_String_Int si;
88       //Edje_Message_String_Float sf;
89       //Edje_Message_String_Int_Set sis;
90       //Edje_Message_String_Float_Set sfs;
91    } msg, *pmsg;
92 
93    valtype = eina_value_type_get(&val);
94    if (!valtype) goto bad_type;
95 
96    pmsg = &msg;
97    if ((valtype == EINA_VALUE_TYPE_STRING) ||
98        (valtype == EINA_VALUE_TYPE_STRINGSHARE))
99      {
100         eina_value_get(&val, &msg.str.str);
101         msgtype = EDJE_MESSAGE_STRING;
102      }
103    else if (valtype == EINA_VALUE_TYPE_INT)
104      {
105         eina_value_get(&val, &msg.i.val);
106         msgtype = EDJE_MESSAGE_INT;
107      }
108    else if (valtype == EINA_VALUE_TYPE_FLOAT)
109      {
110         float f;
111         eina_value_get(&val, &f);
112         msg.f.val = (double) f;
113         msgtype = EDJE_MESSAGE_FLOAT;
114      }
115    else if (valtype == EINA_VALUE_TYPE_DOUBLE)
116      {
117         eina_value_get(&val, &msg.f.val);
118         msgtype = EDJE_MESSAGE_FLOAT;
119      }
120    else if (valtype == EINA_VALUE_TYPE_ARRAY)
121      {
122         Eina_Value_Array array = {};
123         size_t sz, k, count;
124 
125         eina_value_get(&val, &array);
126         count = eina_inarray_count(array.array);
127         if ((array.subtype == EINA_VALUE_TYPE_STRING) ||
128             (array.subtype == EINA_VALUE_TYPE_STRINGSHARE))
129           {
130              sz = sizeof(char *);
131              msgtype = EDJE_MESSAGE_STRING_SET;
132              pmsg = alloca(sizeof(*pmsg) + sz * count);
133              pmsg->ss.count = count;
134              for (k = 0; k < count; k++)
135                pmsg->ss.str[k] = eina_inarray_nth(array.array, k);
136           }
137         else if (array.subtype == EINA_VALUE_TYPE_INT)
138           {
139              sz = sizeof(int);
140              msgtype = EDJE_MESSAGE_INT_SET;
141              pmsg = alloca(sizeof(*pmsg) + sz * count);
142              pmsg->is.count = count;
143              for (k = 0; k < count; k++)
144                pmsg->is.val[k] = *((int *) eina_inarray_nth(array.array, k));
145           }
146         else if (array.subtype == EINA_VALUE_TYPE_DOUBLE)
147           {
148              sz = sizeof(double);
149              msgtype = EDJE_MESSAGE_FLOAT_SET;
150              pmsg = alloca(sizeof(*pmsg) + sz * count);
151              pmsg->fs.count = count;
152              for (k = 0; k < count; k++)
153                pmsg->fs.val[k] = *((double *) eina_inarray_nth(array.array, k));
154           }
155         else if (array.subtype == EINA_VALUE_TYPE_FLOAT)
156           {
157              sz = sizeof(double);
158              msgtype = EDJE_MESSAGE_FLOAT_SET;
159              pmsg = alloca(sizeof(*pmsg) + sz * count);
160              pmsg->fs.count = count;
161              for (k = 0; k < count; k++)
162                pmsg->fs.val[k] = (double) *((float *) eina_inarray_nth(array.array, k));
163           }
164         else goto bad_type;
165 
166      }
167    else goto bad_type;
168 
169    _edje_object_message_propagate_send(obj, msgtype, id, pmsg, EINA_FALSE);
170    return;
171 
172 bad_type:
173    ERR("Unsupported value type: %s. Only primitives types int, real "
174        "(float or double), string or arrays of those types are supported.",
175        eina_value_type_name_get(valtype));
176    return;
177 }
178 
179 static void
_edje_object_message_signal_process_do(Eo * obj EINA_UNUSED,Edje * ed)180 _edje_object_message_signal_process_do(Eo *obj EINA_UNUSED, Edje *ed)
181 {
182    Eina_Inlist *l, *ln;
183    Edje *lookup_ed = NULL;
184    Eina_List *groups = NULL, *lg;
185    Edje_Message *em;
186    int gotos = 0;
187 
188    if (!ed) return;
189 
190    groups = ed->groups;
191    if (groups)
192      {
193         for (l = msgq; l; l = ln)
194           {
195              ln = l->next;
196              em = INLIST_CONTAINER(Edje_Message, l, inlist_main);
197              EINA_LIST_FOREACH(groups, lg, lookup_ed)
198                {
199                   if (em->edje == lookup_ed)
200                     {
201                        msgq = eina_inlist_remove(msgq, &(em->inlist_main));
202                        tmp_msgq = eina_inlist_append(tmp_msgq, &(em->inlist_main));
203                        em->in_tmp_msgq = EINA_TRUE;
204                        break;
205                     }
206                }
207           }
208      }
209 
210    tmp_msgq_processing++;
211 again:
212    for (l = ed->messages; l; l = ln)
213      {
214         ln = l->next;
215         em = INLIST_CONTAINER(Edje_Message, l, inlist_edje);
216         if (!em->in_tmp_msgq) continue;
217         // so why this? any group edje is not the parent - skip this
218         lookup_ed = NULL;
219         EINA_LIST_FOREACH(groups, lg, lookup_ed)
220           {
221              if (em->edje == lookup_ed) break;
222           }
223         if (!lookup_ed) continue;
224         tmp_msgq = eina_inlist_remove(tmp_msgq, &(em->inlist_main));
225         lookup_ed->messages = eina_inlist_remove(lookup_ed->messages, &(em->inlist_edje));
226         lookup_ed->message.num--;
227         if (!lookup_ed->delete_me)
228           {
229              lookup_ed->processing_messages++;
230              _edje_message_process(em);
231              _edje_message_free(em);
232              lookup_ed->processing_messages--;
233           }
234         else
235           _edje_message_free(em);
236         if (lookup_ed->processing_messages == 0)
237           {
238              if (lookup_ed->delete_me) _edje_del(lookup_ed);
239           }
240         // if some child callback in _edje_message_process called
241         // edje_object_message_signal_process() or
242         // edje_message_signal_process() then those will mark the restart
243         // flag when they finish - it mabsicammyt means tmp_msgq and
244         // any item in it has potentially become invalid - so that means l
245         // and ln could be rogue pointers, so start again from the beginning
246         // and skip anything that is not this object and process only what is.
247         // to avoid self-feeding loops allow a max of 1024 loops.
248         if (tmp_msgq_restart)
249           {
250              tmp_msgq_restart = 0;
251              gotos++;
252              if (gotos < 1024) goto again;
253              else
254                {
255                   WRN("Edje is in a self-feeding message loop (> 1024 gotos needed in a row)");
256                   goto end;
257                }
258           }
259      }
260 end:
261    tmp_msgq_processing--;
262    if (tmp_msgq_processing == 0)
263      tmp_msgq_restart = 0;
264    else
265      tmp_msgq_restart = 1;
266 }
267 
268 EOLIAN void
_efl_canvas_layout_efl_layout_signal_signal_process(Eo * obj,Edje * ed,Eina_Bool recurse)269 _efl_canvas_layout_efl_layout_signal_signal_process(Eo *obj, Edje *ed, Eina_Bool recurse)
270 {
271    Eina_List *l;
272    Evas_Object *o;
273 
274    if (ed->delete_me) return;
275    _edje_object_message_signal_process_do(obj, ed);
276    if (!recurse) return;
277 
278    EINA_LIST_FOREACH(ed->subobjs, l, o)
279      efl_layout_signal_process(o, EINA_TRUE);
280 }
281 
282 static Eina_Bool
_edje_dummy_timer(void * data EINA_UNUSED)283 _edje_dummy_timer(void *data EINA_UNUSED)
284 {
285    return ECORE_CALLBACK_CANCEL;
286 }
287 
288 static void
_edje_job(void * data EINA_UNUSED)289 _edje_job(void *data EINA_UNUSED)
290 {
291    if (_job_loss_timer)
292      {
293         ecore_timer_del(_job_loss_timer);
294         _job_loss_timer = NULL;
295      }
296    _job = NULL;
297    _injob++;
298    _edje_message_queue_process();
299    _edje_msg_trash_clear();
300    _injob--;
301 }
302 
303 static Eina_Bool
_edje_job_loss_timer(void * data EINA_UNUSED)304 _edje_job_loss_timer(void *data EINA_UNUSED)
305 {
306    _job_loss_timer = NULL;
307    if (!_job)
308      {
309         _job = ecore_job_add(_edje_job, NULL);
310      }
311    return ECORE_CALLBACK_CANCEL;
312 }
313 
314 void
_edje_message_init(void)315 _edje_message_init(void)
316 {
317 }
318 
319 void
_edje_message_shutdown(void)320 _edje_message_shutdown(void)
321 {
322    _edje_message_queue_clear();
323    _edje_msg_trash_clear();
324    if (_job_loss_timer)
325      {
326         ecore_timer_del(_job_loss_timer);
327         _job_loss_timer = NULL;
328      }
329    if (_job)
330      {
331         ecore_job_del(_job);
332         _job = NULL;
333      }
334 }
335 
336 void
_edje_message_cb_set(Edje * ed,void (* func)(void * data,Evas_Object * obj,Edje_Message_Type type,int id,void * msg),void * data)337 _edje_message_cb_set(Edje *ed, void (*func)(void *data, Evas_Object *obj, Edje_Message_Type type, int id, void *msg), void *data)
338 {
339    Eina_List *l;
340    Evas_Object *o;
341 
342    ed->message.func = func;
343    ed->message.data = data;
344    EINA_LIST_FOREACH(ed->subobjs, l, o)
345      {
346         Edje *edj2 = _edje_fetch(o);
347         if (!edj2) continue;
348         _edje_message_cb_set(edj2, func, data);
349      }
350 }
351 
352 Edje_Message *
_edje_message_new(Edje * ed,Edje_Queue queue,Edje_Message_Type type,int id)353 _edje_message_new(Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id)
354 {
355    Edje_Message *em;
356 
357    em = _edje_msg_trash_pop();
358    if (em) memset(em, 0, sizeof(Edje_Message));
359    else em = calloc(1, sizeof(Edje_Message));
360    if (!em) return NULL;
361    em->edje = ed;
362    em->edje->message.num++;
363    em->queue = queue;
364    em->type = type;
365    em->id = id;
366    return em;
367 }
368 
369 void
_edje_message_free(Edje_Message * em)370 _edje_message_free(Edje_Message *em)
371 {
372    if (em->msg)
373      {
374         int i;
375 
376         switch (em->type)
377           {
378            case EDJE_MESSAGE_STRING:
379            {
380               Edje_Message_String *emsg;
381 
382               emsg = (Edje_Message_String *)em->msg;
383               free(emsg->str);
384               free(emsg);
385            }
386            break;
387 
388            case EDJE_MESSAGE_INT:
389            {
390               Edje_Message_Int *emsg;
391 
392               emsg = (Edje_Message_Int *)em->msg;
393               free(emsg);
394            }
395            break;
396 
397            case EDJE_MESSAGE_FLOAT:
398            {
399               Edje_Message_Float *emsg;
400 
401               emsg = (Edje_Message_Float *)em->msg;
402               free(emsg);
403            }
404            break;
405 
406            case EDJE_MESSAGE_INT_SET:
407            {
408               Edje_Message_Int_Set *emsg;
409 
410               emsg = (Edje_Message_Int_Set *)em->msg;
411               free(emsg);
412            }
413            break;
414 
415            case EDJE_MESSAGE_FLOAT_SET:
416            {
417               Edje_Message_Float_Set *emsg;
418 
419               emsg = (Edje_Message_Float_Set *)em->msg;
420               free(emsg);
421            }
422            break;
423 
424            case EDJE_MESSAGE_STRING_FLOAT:
425            {
426               Edje_Message_String_Float *emsg;
427 
428               emsg = (Edje_Message_String_Float *)em->msg;
429               free(emsg->str);
430               free(emsg);
431            }
432            break;
433 
434            case EDJE_MESSAGE_STRING_INT:
435            {
436               Edje_Message_String_Int *emsg;
437 
438               emsg = (Edje_Message_String_Int *)em->msg;
439               free(emsg->str);
440               free(emsg);
441            }
442            break;
443 
444            case EDJE_MESSAGE_STRING_FLOAT_SET:
445            {
446               Edje_Message_String_Float_Set *emsg;
447 
448               emsg = (Edje_Message_String_Float_Set *)em->msg;
449               free(emsg->str);
450               free(emsg);
451            }
452            break;
453 
454            case EDJE_MESSAGE_STRING_INT_SET:
455            {
456               Edje_Message_String_Int_Set *emsg;
457 
458               emsg = (Edje_Message_String_Int_Set *)em->msg;
459               free(emsg->str);
460               free(emsg);
461            }
462            break;
463 
464            case EDJE_MESSAGE_SIGNAL:
465            {
466               Edje_Message_Signal *emsg;
467 
468               emsg = (Edje_Message_Signal *)em->msg;
469               if (emsg->sig) eina_stringshare_del(emsg->sig);
470               if (emsg->src) eina_stringshare_del(emsg->src);
471               _edje_signal_data_free(emsg->data);
472               free(emsg);
473            }
474            break;
475 
476            case EDJE_MESSAGE_STRING_SET:
477            {
478               Edje_Message_String_Set *emsg;
479 
480               emsg = (Edje_Message_String_Set *)em->msg;
481               for (i = 0; i < emsg->count; i++)
482                 free(emsg->str[i]);
483               free(emsg);
484            }
485            break;
486 
487            case EDJE_MESSAGE_NONE:
488            default:
489              break;
490           }
491      }
492    _edje_msg_trash_push(em);
493 }
494 
495 static void
_edje_message_propagate_send(Edje * ed,Edje_Queue queue,Edje_Message_Type type,int id,void * emsg,Eina_Bool prop)496 _edje_message_propagate_send(Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id, void *emsg, Eina_Bool prop)
497 {
498    /* FIXME: check all malloc & strdup fails and gracefully unroll and exit */
499    Edje_Message *em;
500    int i;
501    unsigned char *msg = NULL;
502 
503    em = _edje_message_new(ed, queue, type, id);
504    if (!em) return;
505    em->propagated = prop;
506    if (_job)
507      {
508         ecore_job_del(_job);
509         _job = NULL;
510      }
511    if (_injob > 0)
512      {
513         if (!_job_loss_timer)
514           _job_loss_timer = ecore_timer_add(0.001, _edje_job_loss_timer, NULL);
515      }
516    else
517      {
518         if (!_job)
519           {
520              _job = ecore_job_add(_edje_job, NULL);
521           }
522         if (_job_loss_timer)
523           {
524              ecore_timer_del(_job_loss_timer);
525              _job_loss_timer = NULL;
526           }
527      }
528    switch (em->type)
529      {
530       case EDJE_MESSAGE_NONE:
531         break;
532 
533       case EDJE_MESSAGE_SIGNAL:
534       {
535          Edje_Message_Signal *emsg2, *emsg3;
536 
537          emsg2 = (Edje_Message_Signal *)emsg;
538          emsg3 = calloc(1, sizeof(Edje_Message_Signal));
539          if (emsg2->sig) emsg3->sig = eina_stringshare_add(emsg2->sig);
540          if (emsg2->src) emsg3->src = eina_stringshare_add(emsg2->src);
541          if (emsg2->data)
542            {
543               emsg3->data = emsg2->data;
544               _edje_signal_data_ref(emsg3->data);
545            }
546          msg = (unsigned char *)emsg3;
547       }
548       break;
549 
550       case EDJE_MESSAGE_STRING:
551       {
552          Edje_Message_String *emsg2, *emsg3;
553 
554          emsg2 = (Edje_Message_String *)emsg;
555 
556          emsg3 = malloc(sizeof(Edje_Message_String));
557          emsg3->str = strdup(emsg2->str);
558          msg = (unsigned char *)emsg3;
559       }
560       break;
561 
562       case EDJE_MESSAGE_INT:
563       {
564          Edje_Message_Int *emsg2, *emsg3;
565 
566          emsg2 = (Edje_Message_Int *)emsg;
567          emsg3 = malloc(sizeof(Edje_Message_Int));
568          emsg3->val = emsg2->val;
569          msg = (unsigned char *)emsg3;
570       }
571       break;
572 
573       case EDJE_MESSAGE_FLOAT:
574       {
575          Edje_Message_Float *emsg2, *emsg3;
576 
577          emsg2 = (Edje_Message_Float *)emsg;
578          emsg3 = malloc(sizeof(Edje_Message_Float));
579          emsg3->val = emsg2->val;
580          msg = (unsigned char *)emsg3;
581       }
582       break;
583 
584       case EDJE_MESSAGE_STRING_SET:
585       {
586          Edje_Message_String_Set *emsg2, *emsg3;
587 
588          emsg2 = (Edje_Message_String_Set *)emsg;
589          emsg3 = malloc(sizeof(Edje_Message_String_Set) + ((emsg2->count - 1) * sizeof(char *)));
590          emsg3->count = emsg2->count;
591          for (i = 0; i < emsg3->count; i++)
592            emsg3->str[i] = strdup(emsg2->str[i]);
593          msg = (unsigned char *)emsg3;
594       }
595       break;
596 
597       case EDJE_MESSAGE_INT_SET:
598       {
599          Edje_Message_Int_Set *emsg2, *emsg3;
600 
601          emsg2 = (Edje_Message_Int_Set *)emsg;
602          emsg3 = malloc(sizeof(Edje_Message_Int_Set) + ((emsg2->count - 1) * sizeof(int)));
603          emsg3->count = emsg2->count;
604          for (i = 0; i < emsg3->count; i++)
605            emsg3->val[i] = emsg2->val[i];
606          msg = (unsigned char *)emsg3;
607       }
608       break;
609 
610       case EDJE_MESSAGE_FLOAT_SET:
611       {
612          Edje_Message_Float_Set *emsg2, *emsg3;
613 
614          emsg2 = (Edje_Message_Float_Set *)emsg;
615          emsg3 = malloc(sizeof(Edje_Message_Float_Set) + ((emsg2->count - 1) * sizeof(double)));
616          emsg3->count = emsg2->count;
617          for (i = 0; i < emsg3->count; i++)
618            emsg3->val[i] = emsg2->val[i];
619          msg = (unsigned char *)emsg3;
620       }
621       break;
622 
623       case EDJE_MESSAGE_STRING_INT:
624       {
625          Edje_Message_String_Int *emsg2, *emsg3;
626 
627          emsg2 = (Edje_Message_String_Int *)emsg;
628          emsg3 = malloc(sizeof(Edje_Message_String_Int));
629          emsg3->str = strdup(emsg2->str);
630          emsg3->val = emsg2->val;
631          msg = (unsigned char *)emsg3;
632       }
633       break;
634 
635       case EDJE_MESSAGE_STRING_FLOAT:
636       {
637          Edje_Message_String_Float *emsg2, *emsg3;
638 
639          emsg2 = (Edje_Message_String_Float *)emsg;
640          emsg3 = malloc(sizeof(Edje_Message_String_Float));
641          emsg3->str = strdup(emsg2->str);
642          emsg3->val = emsg2->val;
643          msg = (unsigned char *)emsg3;
644       }
645       break;
646 
647       case EDJE_MESSAGE_STRING_INT_SET:
648       {
649          Edje_Message_String_Int_Set *emsg2, *emsg3;
650 
651          emsg2 = (Edje_Message_String_Int_Set *)emsg;
652          emsg3 = malloc(sizeof(Edje_Message_String_Int_Set) + ((emsg2->count - 1) * sizeof(int)));
653          emsg3->str = strdup(emsg2->str);
654          emsg3->count = emsg2->count;
655          for (i = 0; i < emsg3->count; i++)
656            emsg3->val[i] = emsg2->val[i];
657          msg = (unsigned char *)emsg3;
658       }
659       break;
660 
661       case EDJE_MESSAGE_STRING_FLOAT_SET:
662       {
663          Edje_Message_String_Float_Set *emsg2, *emsg3;
664 
665          emsg2 = (Edje_Message_String_Float_Set *)emsg;
666          emsg3 = malloc(sizeof(Edje_Message_String_Float_Set) + ((emsg2->count - 1) * sizeof(double)));
667          emsg3->str = strdup(emsg2->str);
668          emsg3->count = emsg2->count;
669          for (i = 0; i < emsg3->count; i++)
670            emsg3->val[i] = emsg2->val[i];
671          msg = (unsigned char *)emsg3;
672       }
673       break;
674 
675       default:
676         break;
677      }
678 
679    em->msg = msg;
680    msgq = eina_inlist_append(msgq, &(em->inlist_main));
681    em->edje->messages = eina_inlist_append(em->edje->messages, &(em->inlist_edje));
682 }
683 
684 void
_edje_util_message_send(Edje * ed,Edje_Queue queue,Edje_Message_Type type,int id,void * emsg)685 _edje_util_message_send(Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id, void *emsg)
686 {
687    _edje_message_propagate_send(ed, queue, type, id, emsg, EINA_FALSE);
688 }
689 
690 void
_edje_message_parameters_push(Edje_Message * em)691 _edje_message_parameters_push(Edje_Message *em)
692 {
693    int i;
694 
695    /* these params ALWAYS go on */
696    /* first param is the message type - always */
697    embryo_parameter_cell_push(em->edje->collection->script,
698                               (Embryo_Cell)em->type);
699    /* 2nd param is the integer of the event id - always there */
700    embryo_parameter_cell_push(em->edje->collection->script,
701                               (Embryo_Cell)em->id);
702    /* the rest is varags of whatever is in the msg */
703    switch (em->type)
704      {
705       case EDJE_MESSAGE_NONE:
706         break;
707 
708       case EDJE_MESSAGE_STRING:
709         embryo_parameter_string_push(em->edje->collection->script,
710                                      ((Edje_Message_String *)em->msg)->str);
711         break;
712 
713       case EDJE_MESSAGE_INT:
714       {
715          Embryo_Cell v;
716 
717          v = (Embryo_Cell)((Edje_Message_Int *)em->msg)->val;
718          embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
719       }
720       break;
721 
722       case EDJE_MESSAGE_FLOAT:
723       {
724          Embryo_Cell v;
725          float fv;
726 
727          fv = ((Edje_Message_Float *)em->msg)->val;
728          v = EMBRYO_FLOAT_TO_CELL(fv);
729          embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
730       }
731       break;
732 
733       case EDJE_MESSAGE_STRING_SET:
734         for (i = 0; i < ((Edje_Message_String_Set *)em->msg)->count; i++)
735           embryo_parameter_string_push(em->edje->collection->script,
736                                        ((Edje_Message_String_Set *)em->msg)->str[i]);
737         break;
738 
739       case EDJE_MESSAGE_INT_SET:
740         for (i = 0; i < ((Edje_Message_Int_Set *)em->msg)->count; i++)
741           {
742              Embryo_Cell v;
743 
744              v = (Embryo_Cell)((Edje_Message_Int_Set *)em->msg)->val[i];
745              embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
746           }
747         break;
748 
749       case EDJE_MESSAGE_FLOAT_SET:
750         for (i = 0; i < ((Edje_Message_Float_Set *)em->msg)->count; i++)
751           {
752              Embryo_Cell v;
753              float fv;
754 
755              fv = ((Edje_Message_Float_Set *)em->msg)->val[i];
756              v = EMBRYO_FLOAT_TO_CELL(fv);
757              embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
758           }
759         break;
760 
761       case EDJE_MESSAGE_STRING_INT:
762         embryo_parameter_string_push(em->edje->collection->script,
763                                      ((Edje_Message_String_Int *)em->msg)->str);
764         {
765            Embryo_Cell v;
766 
767            v = (Embryo_Cell)((Edje_Message_String_Int *)em->msg)->val;
768            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
769         }
770         break;
771 
772       case EDJE_MESSAGE_STRING_FLOAT:
773         embryo_parameter_string_push(em->edje->collection->script,
774                                      ((Edje_Message_String_Float *)em->msg)->str);
775         {
776            Embryo_Cell v;
777            float fv;
778 
779            fv = ((Edje_Message_String_Float *)em->msg)->val;
780            v = EMBRYO_FLOAT_TO_CELL(fv);
781            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
782         }
783         break;
784 
785       case EDJE_MESSAGE_STRING_INT_SET:
786         embryo_parameter_string_push(em->edje->collection->script,
787                                      ((Edje_Message_String_Int_Set *)em->msg)->str);
788         for (i = 0; i < ((Edje_Message_String_Int_Set *)em->msg)->count; i++)
789           {
790              Embryo_Cell v;
791 
792              v = (Embryo_Cell)((Edje_Message_String_Int_Set *)em->msg)->val[i];
793              embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
794           }
795         break;
796 
797       case EDJE_MESSAGE_STRING_FLOAT_SET:
798         embryo_parameter_string_push(em->edje->collection->script,
799                                      ((Edje_Message_String_Float_Set *)em->msg)->str);
800         for (i = 0; i < ((Edje_Message_String_Float_Set *)em->msg)->count; i++)
801           {
802              Embryo_Cell v;
803              float fv;
804 
805              fv = ((Edje_Message_String_Float_Set *)em->msg)->val[i];
806              v = EMBRYO_FLOAT_TO_CELL(fv);
807              embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
808           }
809         break;
810 
811       default:
812         break;
813      }
814 }
815 
816 void
_edje_message_process(Edje_Message * em)817 _edje_message_process(Edje_Message *em)
818 {
819    Embryo_Function fn;
820    void *pdata;
821    int ret;
822 
823    /* signals are only handled one way */
824    if (em->type == EDJE_MESSAGE_SIGNAL)
825      {
826         _edje_emit_handle(em->edje,
827                           ((Edje_Message_Signal *)em->msg)->sig,
828                           ((Edje_Message_Signal *)em->msg)->src,
829                           ((Edje_Message_Signal *)em->msg)->data,
830                           em->propagated);
831         return;
832      }
833    /* if this has been queued up for the app then just call the callback */
834    if (em->queue == EDJE_QUEUE_APP)
835      {
836         if (em->edje->message.func)
837           em->edje->message.func(em->edje->message.data, em->edje->obj,
838                                  em->type, em->id, em->msg);
839         return;
840      }
841    /* now this message is destined for the script message handler fn */
842    if (!(em->edje->collection)) return;
843    if (em->edje->L)
844      {
845         _edje_lua_script_only_message(em->edje, em);
846         return;
847      }
848    fn = embryo_program_function_find(em->edje->collection->script, "message");
849    if (fn == EMBRYO_FUNCTION_NONE) return;
850    /* reset the engine */
851    _edje_embryo_script_reset(em->edje);
852 
853    _edje_message_parameters_push(em);
854 
855    embryo_program_vm_push(em->edje->collection->script);
856    _edje_embryo_globals_init(em->edje);
857    pdata = embryo_program_data_get(em->edje->collection->script);
858    embryo_program_data_set(em->edje->collection->script, em->edje);
859    embryo_program_max_cycle_run_set(em->edje->collection->script, 5000000);
860    ret = embryo_program_run(em->edje->collection->script, fn);
861    if (ret == EMBRYO_PROGRAM_FAIL)
862      {
863         ERR("ERROR with embryo script. "
864             "OBJECT NAME: '%s', "
865             "OBJECT FILE: '%s', "
866             "ENTRY POINT: '%s', "
867             "ERROR: '%s'",
868             em->edje->collection->part,
869             em->edje->file->path,
870             "message",
871             embryo_error_string_get(embryo_program_error_get(em->edje->collection->script)));
872      }
873    else if (ret == EMBRYO_PROGRAM_TOOLONG)
874      {
875         ERR("ERROR with embryo script. "
876             "OBJECT NAME: '%s', "
877             "OBJECT FILE: '%s', "
878             "ENTRY POINT: '%s', "
879             "ERROR: 'Script exceeded maximum allowed cycle count of %i'",
880             em->edje->collection->part,
881             em->edje->file->path,
882             "message",
883             embryo_program_max_cycle_run_get(em->edje->collection->script));
884      }
885 
886    embryo_program_data_set(em->edje->collection->script, pdata);
887    embryo_program_vm_pop(em->edje->collection->script);
888 }
889 
890 void
_edje_message_queue_process(void)891 _edje_message_queue_process(void)
892 {
893    int i;
894    Edje_Message *em;
895 
896    if (!msgq) return;
897 
898    /* allow the message queue to feed itself up to 8 times before forcing */
899    /* us to go back to normal processing and let a 0 timeout deal with it */
900    for (i = 0; (i < 8) && (msgq); i++)
901      {
902         /* a temporary message queue */
903         while (msgq)
904           {
905              Eina_Inlist *l = msgq;
906 
907              em = INLIST_CONTAINER(Edje_Message, l, inlist_main);
908              msgq = eina_inlist_remove(msgq, &(em->inlist_main));
909              tmp_msgq = eina_inlist_append(tmp_msgq, &(em->inlist_main));
910              em->in_tmp_msgq = EINA_TRUE;
911           }
912 
913         tmp_msgq_processing++;
914         while (tmp_msgq)
915           {
916              Eina_Inlist *l = tmp_msgq;
917              Edje *ed;
918 
919              em = INLIST_CONTAINER(Edje_Message, l, inlist_main);
920              ed = em->edje;
921              tmp_msgq = eina_inlist_remove(tmp_msgq, &(em->inlist_main));
922              em->edje->messages = eina_inlist_remove(em->edje->messages, &(em->inlist_edje));
923              em->edje->message.num--;
924              if (!ed->delete_me)
925                {
926                   ed->processing_messages++;
927                   _edje_message_process(em);
928                   _edje_message_free(em);
929                   ed->processing_messages--;
930                }
931              else
932                _edje_message_free(em);
933              if (ed->processing_messages == 0)
934                {
935                   if (ed->delete_me) _edje_del(ed);
936                }
937           }
938         tmp_msgq_processing--;
939         if (tmp_msgq_processing == 0)
940           tmp_msgq_restart = 0;
941         else
942           tmp_msgq_restart = 1;
943      }
944 
945    /* if the message queue filled again set a timer to expire in 0.0 sec */
946    /* to get the idle enterer to be run again */
947    if (msgq)
948      {
949         static int self_feed_debug = -1;
950 
951         if (self_feed_debug == -1)
952           {
953              const char *s = getenv("EDJE_SELF_FEED_DEBUG");
954              if (s) self_feed_debug = atoi(s);
955              else self_feed_debug = 0;
956           }
957         if (self_feed_debug)
958           {
959              WRN("Edje is in a self-feeding message loop (> 8 loops needed)");
960           }
961         ecore_timer_add(0.0, _edje_dummy_timer, NULL);
962      }
963 }
964 
965 void
_edje_message_queue_clear(void)966 _edje_message_queue_clear(void)
967 {
968    Edje_Message *em;
969 
970    while (msgq)
971      {
972         Eina_Inlist *l = msgq;
973         em = INLIST_CONTAINER(Edje_Message, l, inlist_main);
974         msgq = eina_inlist_remove(msgq, &(em->inlist_main));
975         em->edje->message.num--;
976         em->edje->messages = eina_inlist_remove(em->edje->messages, &(em->inlist_edje));
977         _edje_message_free(em);
978      }
979    while (tmp_msgq)
980      {
981         Eina_Inlist *l = tmp_msgq;
982         em = INLIST_CONTAINER(Edje_Message, l, inlist_main);
983         tmp_msgq = eina_inlist_remove(tmp_msgq, &(em->inlist_main));
984         em->edje->message.num--;
985         em->edje->messages = eina_inlist_remove(em->edje->messages, &(em->inlist_edje));
986         _edje_message_free(em);
987      }
988 }
989 
990 void
_edje_message_del(Edje * ed)991 _edje_message_del(Edje *ed)
992 {
993    Eina_Inlist *l, *ln;
994    Edje_Message *em;
995 
996    if (ed->message.num <= 0) return;
997    // delete any messages on the main or tmp queue for this edje object
998    for (l = ed->messages; l; l = ln)
999      {
1000         ln = l->next;
1001         em = INLIST_CONTAINER(Edje_Message, l, inlist_edje);
1002         em->edje->message.num--;
1003         if (em->in_tmp_msgq)
1004           tmp_msgq = eina_inlist_remove(tmp_msgq, &(em->inlist_main));
1005         else
1006           msgq = eina_inlist_remove(msgq, &(em->inlist_main));
1007         em->edje->messages = eina_inlist_remove(em->edje->messages, &(em->inlist_edje));
1008         _edje_message_free(em);
1009         if (ed->message.num <= 0) return;
1010      }
1011 }
1012 
1013 /* Legacy EAPI */
1014 
1015 EAPI void
edje_object_message_send(Eo * obj,Edje_Message_Type type,int id,void * msg)1016 edje_object_message_send(Eo *obj, Edje_Message_Type type, int id, void *msg)
1017 {
1018    _edje_object_message_propagate_send(obj, type, id, msg, EINA_FALSE);
1019 }
1020 
1021 EAPI void
edje_message_signal_process(void)1022 edje_message_signal_process(void)
1023 {
1024    _edje_message_queue_process();
1025 }
1026 
1027 EAPI void
edje_object_message_handler_set(Eo * obj,Edje_Message_Handler_Cb func,void * data)1028 edje_object_message_handler_set(Eo *obj, Edje_Message_Handler_Cb func, void *data)
1029 {
1030    Edje *ed;
1031 
1032    ed = _edje_fetch(obj);
1033    if (!ed) return;
1034    _edje_message_cb_set(ed, func, data);
1035 }
1036