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