1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #define EFL_LOOP_PROTECTED
6 
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <math.h>
12 #include <sys/time.h>
13 #include <errno.h>
14 
15 #include "Ecore.h"
16 #include "ecore_private.h"
17 
18 #include "ecore_main_common.h"
19 
20 typedef struct _Efl_Loop_Promise_Simple_Data Efl_Loop_Promise_Simple_Data;
21 typedef struct _Efl_Internal_Promise Efl_Internal_Promise;
22 
23 struct _Efl_Loop_Promise_Simple_Data
24 {
25    union {
26       Efl_Loop_Timer *timer;
27       Ecore_Idler *idler;
28    };
29    Eina_Promise *promise;
30 };
31 GENERIC_ALLOC_SIZE_DECLARE(Efl_Loop_Promise_Simple_Data);
32 
33 Eo            *_mainloop_singleton = NULL;
34 Efl_Loop_Data *_mainloop_singleton_data = NULL;
35 
36 EAPI Eo *
efl_main_loop_get(void)37 efl_main_loop_get(void)
38 {
39    return efl_app_main_get();
40 }
41 
42 EOLIAN static void
_efl_loop_iterate(Eo * obj,Efl_Loop_Data * pd)43 _efl_loop_iterate(Eo *obj, Efl_Loop_Data *pd)
44 {
45    _ecore_main_loop_iterate(obj, pd);
46 }
47 
48 EOLIAN static int
_efl_loop_iterate_may_block(Eo * obj,Efl_Loop_Data * pd,int may_block)49 _efl_loop_iterate_may_block(Eo *obj, Efl_Loop_Data *pd, int may_block)
50 {
51    return _ecore_main_loop_iterate_may_block(obj, pd, may_block);
52 }
53 
54 EOLIAN static Eina_Value *
_efl_loop_begin(Eo * obj,Efl_Loop_Data * pd)55 _efl_loop_begin(Eo *obj, Efl_Loop_Data *pd)
56 {
57    _ecore_main_loop_begin(obj, pd);
58    if (pd->thread_children)
59      {
60         Eina_List *l, *ll;
61         Eo *child;
62 
63         // request all child threads to die and defer the quit until
64         // the children have all died and returned.
65         // run main loop again to clean out children and their exits
66         pd->quit_on_last_thread_child_del = EINA_TRUE;
67         EINA_LIST_FOREACH_SAFE(pd->thread_children, l, ll, child)
68           {
69              Efl_Task_Flags task_flags = efl_task_flags_get(child);
70 
71              if (task_flags & EFL_TASK_FLAGS_EXIT_WITH_PARENT)
72                efl_task_end(child);
73              else
74                _efl_thread_child_remove(obj, pd, child);
75           }
76         if (pd->thread_children) _ecore_main_loop_begin(obj, pd);
77      }
78    return &(pd->exit_code);
79 }
80 
81 EOLIAN static void
_efl_loop_quit(Eo * obj,Efl_Loop_Data * pd,Eina_Value exit_code)82 _efl_loop_quit(Eo *obj, Efl_Loop_Data *pd, Eina_Value exit_code)
83 {
84    _ecore_main_loop_quit(obj, pd);
85    pd->exit_code = exit_code;
86 }
87 
88 EOLIAN static void
_efl_loop_time_set(Eo * obj EINA_UNUSED,Efl_Loop_Data * pd,double t)89 _efl_loop_time_set(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, double t)
90 {
91    pd->loop_time = t;
92 }
93 
94 EOLIAN static double
_efl_loop_time_get(const Eo * obj EINA_UNUSED,Efl_Loop_Data * pd)95 _efl_loop_time_get(const Eo *obj EINA_UNUSED, Efl_Loop_Data *pd)
96 {
97    return pd->loop_time;
98 }
99 
100 EAPI void
efl_exit(int exit_code)101 efl_exit(int exit_code)
102 {
103    Eina_Value v = EINA_VALUE_EMPTY;
104 
105    eina_value_setup(&v, EINA_VALUE_TYPE_INT);
106    eina_value_set(&v, exit_code);
107    efl_loop_quit(efl_main_loop_get(), v);
108 }
109 
110 EAPI int
efl_loop_exit_code_process(Eina_Value * value)111 efl_loop_exit_code_process(Eina_Value *value)
112 {
113    Eina_Value def = EINA_VALUE_EMPTY;
114    const Eina_Value_Type *t;
115    int r = 0;
116 
117    if (value == NULL ||
118        !value->type)
119      {
120         def = eina_value_int_init(0);
121         value = &def;
122      }
123 
124    t = eina_value_type_get(value);
125 
126    if (t == EINA_VALUE_TYPE_UCHAR ||
127        t == EINA_VALUE_TYPE_USHORT ||
128        t == EINA_VALUE_TYPE_UINT ||
129        t == EINA_VALUE_TYPE_ULONG ||
130        t == EINA_VALUE_TYPE_UINT64 ||
131        t == EINA_VALUE_TYPE_CHAR ||
132        t == EINA_VALUE_TYPE_SHORT ||
133        t == EINA_VALUE_TYPE_INT ||
134        t == EINA_VALUE_TYPE_LONG ||
135        t == EINA_VALUE_TYPE_INT64 ||
136        t == EINA_VALUE_TYPE_FLOAT ||
137        t == EINA_VALUE_TYPE_DOUBLE)
138      {
139         Eina_Value v = EINA_VALUE_EMPTY;
140 
141         eina_value_setup(&v, EINA_VALUE_TYPE_INT);
142         if (!eina_value_convert(value, &v)) r = -1;
143         else eina_value_get(&v, &r);
144      }
145    else
146      {
147         FILE *out = stdout;
148         char *msg;
149 
150         msg = eina_value_to_string(value);
151 
152         if (t == EINA_VALUE_TYPE_ERROR)
153           {
154              r = -1;
155              out = stderr;
156           }
157         fprintf(out, "%s\n", msg);
158         free(msg);
159      }
160    return r;
161 }
162 
163 static void
_poll_trigger(void * data,const Efl_Event * event)164 _poll_trigger(void *data, const Efl_Event *event)
165 {
166    Eo *parent = efl_parent_get(event->object);
167 
168    efl_event_callback_call(parent, data, NULL);
169 }
170 
171 static void
_check_event_catcher_add(void * data,const Efl_Event * event)172 _check_event_catcher_add(void *data, const Efl_Event *event)
173 {
174    const Efl_Callback_Array_Item_Full *array = event->info;
175    Efl_Loop_Data *pd = data;
176    int i;
177 
178    for (i = 0; array[i].desc != NULL; i++)
179      {
180         if (array[i].desc == EFL_LOOP_EVENT_IDLE)
181           {
182              ++pd->idlers;
183           }
184         // XXX: all the below are kind of bad. ecore_pollers were special.
185         // they all woke up at the SAME time based on interval, (all pollers
186         // of interval 1 woke up together, those with 2 woke up when 1 and
187         // 2 woke up, 4 woke up together along with 1 and 2 etc.
188         // the below means they will just go off whenever but at a pre
189         // defined interval - 1/60th, 6 and 66 seconds. not really great
190         // pollers probably should be less frequent that 1/60th even on poll
191         // high, medium probably down to 1-2 sec and low - yes maybe 30 or 60
192         // sec... still - not timed to wake up together. :(
193         else if (array[i].desc == EFL_LOOP_EVENT_POLL_HIGH)
194           {
195              if (!pd->poll_high)
196                {
197                   // Would be better to have it in sync with normal wake up
198                   // of the main loop for better energy efficiency, I guess.
199                   pd->poll_high = efl_add
200                     (EFL_LOOP_TIMER_CLASS, event->object,
201                      efl_event_callback_add(efl_added,
202                                             EFL_LOOP_TIMER_EVENT_TIMER_TICK,
203                                             _poll_trigger,
204                                             EFL_LOOP_EVENT_POLL_HIGH),
205                      efl_loop_timer_interval_set(efl_added, 1.0 / 60.0));
206                }
207              ++pd->pollers.high;
208           }
209         else if (array[i].desc == EFL_LOOP_EVENT_POLL_MEDIUM)
210           {
211              if (!pd->poll_medium)
212                {
213                   pd->poll_medium = efl_add
214                     (EFL_LOOP_TIMER_CLASS, event->object,
215                      efl_event_callback_add(efl_added,
216                                             EFL_LOOP_TIMER_EVENT_TIMER_TICK,
217                                             _poll_trigger,
218                                             EFL_LOOP_EVENT_POLL_MEDIUM),
219                      efl_loop_timer_interval_set(efl_added, 6));
220                }
221              ++pd->pollers.medium;
222           }
223         else if (array[i].desc == EFL_LOOP_EVENT_POLL_LOW)
224           {
225              if (!pd->poll_low)
226                {
227                   pd->poll_low = efl_add
228                     (EFL_LOOP_TIMER_CLASS, event->object,
229                      efl_event_callback_add(efl_added,
230                                             EFL_LOOP_TIMER_EVENT_TIMER_TICK,
231                                             _poll_trigger,
232                                             EFL_LOOP_EVENT_POLL_LOW),
233                      efl_loop_timer_interval_set(efl_added, 66));
234                }
235              ++pd->pollers.low;
236           }
237      }
238 }
239 
240 static void
_check_event_catcher_del(void * data,const Efl_Event * event)241 _check_event_catcher_del(void *data, const Efl_Event *event)
242 {
243    const Efl_Callback_Array_Item_Full *array = event->info;
244    Efl_Loop_Data *pd = data;
245    int i;
246 
247    for (i = 0; array[i].desc != NULL; i++)
248      {
249         if (array[i].desc == EFL_LOOP_EVENT_IDLE)
250           {
251              --pd->idlers;
252           }
253         else if (array[i].desc == EFL_LOOP_EVENT_POLL_HIGH)
254           {
255              --pd->pollers.high;
256              if (!pd->pollers.high)
257                {
258                   efl_del(pd->poll_high);
259                   pd->poll_high = NULL;
260                }
261           }
262         else if (array[i].desc == EFL_LOOP_EVENT_POLL_MEDIUM)
263           {
264              --pd->pollers.medium;
265              if (!pd->pollers.medium)
266                {
267                   efl_del(pd->poll_medium);
268                   pd->poll_medium = NULL;
269                }
270           }
271         else if (array[i].desc == EFL_LOOP_EVENT_POLL_LOW)
272           {
273              --pd->pollers.low;
274              if (!pd->pollers.low)
275                {
276                   efl_del(pd->poll_low);
277                   pd->poll_low = NULL;
278                }
279           }
280      }
281 }
282 
283 EFL_CALLBACKS_ARRAY_DEFINE(event_catcher_watch,
284                           { EFL_EVENT_CALLBACK_ADD, _check_event_catcher_add },
285                           { EFL_EVENT_CALLBACK_DEL, _check_event_catcher_del });
286 
287 EOLIAN static Efl_Object *
_efl_loop_efl_object_constructor(Eo * obj,Efl_Loop_Data * pd)288 _efl_loop_efl_object_constructor(Eo *obj, Efl_Loop_Data *pd)
289 {
290    obj = efl_constructor(efl_super(obj, EFL_LOOP_CLASS));
291    if (!obj) return NULL;
292 
293    efl_event_callback_array_add(obj, event_catcher_watch(), pd);
294 
295    pd->loop_time = ecore_time_get();
296    pd->epoll_fd = -1;
297    pd->timer_fd = -1;
298    pd->future_message_handler = efl_add(EFL_LOOP_MESSAGE_FUTURE_HANDLER_CLASS, obj);
299    efl_provider_register(obj, EFL_LOOP_MESSAGE_FUTURE_HANDLER_CLASS, pd->future_message_handler);
300 
301    return obj;
302 }
303 
304 EOLIAN static void
_efl_loop_efl_object_invalidate(Eo * obj,Efl_Loop_Data * pd)305 _efl_loop_efl_object_invalidate(Eo *obj, Efl_Loop_Data *pd)
306 {
307    efl_invalidate(efl_super(obj, EFL_LOOP_CLASS));
308 
309    _ecore_main_content_clear(obj, pd);
310 
311    pd->poll_low = NULL;
312    pd->poll_medium = NULL;
313    pd->poll_high = NULL;
314 
315    // After invalidate, it won't be possible to parent to the singleton anymore
316    if (obj == _mainloop_singleton)
317      {
318         _mainloop_singleton = NULL;
319         _mainloop_singleton_data = NULL;
320      }
321 }
322 
323 EOLIAN static void
_efl_loop_efl_object_destructor(Eo * obj,Efl_Loop_Data * pd)324 _efl_loop_efl_object_destructor(Eo *obj, Efl_Loop_Data *pd)
325 {
326    pd->future_message_handler = NULL;
327    while (pd->thread_children)
328      _efl_thread_child_remove(obj, pd, pd->thread_children->data);
329    efl_destructor(efl_super(obj, EFL_LOOP_CLASS));
330 }
331 
332 static Eina_Value
_efl_loop_arguments_send(Eo * o EINA_UNUSED,void * data,const Eina_Value v)333 _efl_loop_arguments_send(Eo *o EINA_UNUSED, void *data, const Eina_Value v)
334 
335 {
336    static Eina_Bool initialization = EINA_TRUE;
337    Efl_Loop_Arguments arge;
338    Eina_Array *arga = data;
339 
340    arge.argv = arga;
341    arge.initialization = initialization;
342    initialization = EINA_FALSE;
343 
344    efl_event_callback_call(efl_main_loop_get(),
345                            EFL_LOOP_EVENT_ARGUMENTS, &arge);
346    return v;
347 }
348 
349 static void
_efl_loop_arguments_cleanup(Eo * o EINA_UNUSED,void * data,const Eina_Future * dead_future EINA_UNUSED)350 _efl_loop_arguments_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
351 {
352    Eina_Array *arga = data;
353    Eina_Stringshare *s;
354 
355    while ((s = eina_array_pop(arga))) eina_stringshare_del(s);
356    eina_array_free(arga);
357 }
358 
359 // It doesn't make sense to send those argument to any other mainloop
360 // As it also doesn't make sense to allow anyone to override this, so
361 // should be internal for sure, not even protected.
362 EAPI void
ecore_loop_arguments_send(int argc,const char ** argv)363 ecore_loop_arguments_send(int argc, const char **argv)
364 {
365    Eina_Array *arga, *cml;
366    int i = 0;
367 
368    arga = eina_array_new(argc);
369    cml = eina_array_new(argc);
370    for (i = 0; i < argc; i++)
371      {
372         Eina_Stringshare *arg;
373 
374         arg = eina_stringshare_add(argv[i]);
375         eina_array_push(arga, arg);
376         arg = eina_stringshare_add(argv[i]);
377         eina_array_push(cml, arg);
378      }
379 
380    efl_core_command_line_command_array_set(efl_app_main_get(), cml);
381    efl_future_then(efl_main_loop_get(), efl_loop_job(efl_main_loop_get()),
382                    .success = _efl_loop_arguments_send,
383                    .free = _efl_loop_arguments_cleanup,
384                    .data = arga);
385 }
386 
387 static Eina_Future *
_efl_loop_job(Eo * obj,Efl_Loop_Data * pd EINA_UNUSED)388 _efl_loop_job(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
389 {
390    // NOTE: Eolian should do efl_future_then() to bind future to object.
391    return efl_future_then(obj,
392                           eina_future_resolved(efl_loop_future_scheduler_get(obj), EINA_VALUE_EMPTY));
393 }
394 
395 EOLIAN static void
_efl_loop_throttle_set(Eo * obj EINA_UNUSED,Efl_Loop_Data * pd,double amount)396 _efl_loop_throttle_set(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, double amount)
397 {
398    pd->throttle = ((double)amount) * 1000000.0;
399 }
400 
401 EOLIAN static double
_efl_loop_throttle_get(const Eo * obj EINA_UNUSED,Efl_Loop_Data * pd)402 _efl_loop_throttle_get(const Eo *obj EINA_UNUSED, Efl_Loop_Data *pd)
403 {
404    return (double)(pd->throttle) / 1000000.0;
405 }
406 
407 static void
_efl_loop_idle_cancel(void * data,const Eina_Promise * dead_ptr EINA_UNUSED)408 _efl_loop_idle_cancel(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
409 {
410    Efl_Loop_Promise_Simple_Data *d = data;
411 
412    ecore_idler_del(d->idler);
413    d->idler = NULL;
414    d->promise = NULL;
415    efl_loop_promise_simple_data_mp_free(d);
416 }
417 
418 static Eina_Bool
_efl_loop_idle_done(void * data)419 _efl_loop_idle_done(void *data)
420 {
421    Efl_Loop_Promise_Simple_Data *d = data;
422    eina_promise_resolve(d->promise, EINA_VALUE_EMPTY);
423    d->idler = NULL;
424    d->promise = NULL;
425    efl_loop_promise_simple_data_mp_free(d);
426    return EINA_FALSE;
427 }
428 
429 static Eina_Future *
_efl_loop_idle(Eo * obj,Efl_Loop_Data * pd EINA_UNUSED)430 _efl_loop_idle(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
431 {
432    Efl_Loop_Promise_Simple_Data *d;
433    Eina_Promise *p;
434    Eina_Future_Scheduler *sched = efl_loop_future_scheduler_get(obj);
435 
436    d = efl_loop_promise_simple_data_calloc(1);
437    EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
438 
439    d->idler = ecore_idler_add(_efl_loop_idle_done, d);
440    EINA_SAFETY_ON_NULL_GOTO(d->idler, idler_error);
441 
442    p = eina_promise_new(sched, _efl_loop_idle_cancel, d);
443    // d is dead if p is NULL
444    EINA_SAFETY_ON_NULL_RETURN_VAL(p, NULL);
445    d->promise = p;
446 
447    // NOTE: Eolian should do efl_future_then() to bind future to object.
448    return efl_future_then(obj, eina_future_new(p));
449 
450 idler_error:
451    d->idler = NULL;
452    d->promise = NULL;
453    efl_loop_promise_simple_data_mp_free(d);
454    return NULL;
455 }
456 
457 static void
_efl_loop_timeout_cancel(void * data,const Eina_Promise * dead_ptr EINA_UNUSED)458 _efl_loop_timeout_cancel(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
459 {
460    Efl_Loop_Promise_Simple_Data *d = data;
461 
462    if (d->timer)
463      efl_del(d->timer);
464 }
465 
466 static void
_efl_loop_timeout_done(void * data,const Efl_Event * event)467 _efl_loop_timeout_done(void *data, const Efl_Event *event)
468 {
469    Efl_Loop_Promise_Simple_Data *d = data;
470 
471    eina_promise_resolve(d->promise, EINA_VALUE_EMPTY);
472    d->timer = NULL;
473    efl_del(event->object);
474 }
475 
476 static void
_efl_loop_timeout_del(void * data,const Efl_Event * event EINA_UNUSED)477 _efl_loop_timeout_del(void *data, const Efl_Event *event EINA_UNUSED)
478 {
479    Efl_Loop_Promise_Simple_Data *d = data;
480 
481    d->timer = NULL;
482    d->promise = NULL;
483    efl_loop_promise_simple_data_mp_free(d);
484 }
485 
486 static Eina_Future *
_efl_loop_timeout(Eo * obj,Efl_Loop_Data * pd EINA_UNUSED,double tim)487 _efl_loop_timeout(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED, double tim)
488 {
489    Efl_Loop_Promise_Simple_Data *d;
490    Eina_Promise *p;
491    Eina_Future_Scheduler *sched = efl_loop_future_scheduler_get(obj);
492 
493    d = efl_loop_promise_simple_data_calloc(1);
494    EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
495 
496    d->timer = efl_add(EFL_LOOP_TIMER_CLASS, obj,
497                       efl_loop_timer_interval_set(efl_added, tim),
498                       efl_event_callback_add(efl_added,
499                                              EFL_LOOP_TIMER_EVENT_TIMER_TICK,
500                                              _efl_loop_timeout_done, d),
501                       efl_event_callback_add(efl_added,
502                                              EFL_EVENT_DEL,
503                                              _efl_loop_timeout_del, d)
504                      );
505    EINA_SAFETY_ON_NULL_GOTO(d->timer, timer_error);
506 
507    p = eina_promise_new(sched, _efl_loop_timeout_cancel, d);
508    // d is dead if p is NULL
509    EINA_SAFETY_ON_NULL_RETURN_VAL(p, NULL);
510    d->promise = p;
511 
512    // NOTE: Eolian should do efl_future_then() to bind future to object.
513    return efl_future_then(obj, eina_future_new(p));
514 
515 timer_error:
516    d->timer = NULL;
517    d->promise = NULL;
518    efl_loop_promise_simple_data_mp_free(d);
519    return NULL;
520 }
521 
522 static Eina_Bool
_efl_loop_register(Eo * obj,Efl_Loop_Data * pd EINA_UNUSED,const Efl_Class * klass,const Efl_Object * provider)523 _efl_loop_register(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED,
524                    const Efl_Class *klass, const Efl_Object *provider)
525 {
526    return efl_provider_register(obj, klass, provider);
527 }
528 
529 EFL_FUNC_BODYV(efl_loop_register, Eina_Bool, EINA_FALSE, EFL_FUNC_CALL(klass, provider), const Efl_Class *klass, const Efl_Object *provider);
530 
531 static Eina_Bool
_efl_loop_unregister(Eo * obj,Efl_Loop_Data * pd EINA_UNUSED,const Efl_Class * klass,const Efl_Object * provider)532 _efl_loop_unregister(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED,
533                      const Efl_Class *klass, const Efl_Object *provider)
534 {
535    return efl_provider_unregister(obj, klass, provider);
536 }
537 
538 EFL_FUNC_BODYV(efl_loop_unregister, Eina_Bool, EINA_FALSE, EFL_FUNC_CALL(klass, provider), const Efl_Class *klass, const Efl_Object *provider);
539 
540 void
_efl_loop_messages_filter(Eo * obj EINA_UNUSED,Efl_Loop_Data * pd,void * handler_pd)541 _efl_loop_messages_filter(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, void *handler_pd)
542 {
543    Message *msg;
544 
545    pd->message_walking++;
546    EINA_INLIST_FOREACH(pd->message_queue, msg)
547      {
548         if ((msg->handler) && (msg->message) && (!msg->delete_me))
549           {
550              if (!_ecore_event_do_filter(handler_pd,
551                                          msg->handler, msg->message))
552                {
553                   efl_del(msg->message);
554                   msg->handler = NULL;
555                   msg->message = NULL;
556                   msg->delete_me = EINA_TRUE;
557                }
558           }
559      }
560    pd->message_walking--;
561 }
562 
563 void
_efl_loop_messages_call(Eo * obj EINA_UNUSED,Efl_Loop_Data * pd,void * func,void * data)564 _efl_loop_messages_call(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, void *func, void *data)
565 {
566    Message *msg;
567 
568    pd->message_walking++;
569    EINA_INLIST_FOREACH(pd->message_queue, msg)
570      {
571         if ((msg->handler) && (msg->message) && (!msg->delete_me))
572           {
573              Eina_Bool (*fn) (void *data, void *handler, void *msg);
574 
575              fn = func;
576              if (!fn(data, msg->handler, msg->message))
577                {
578                   efl_del(msg->message);
579                   msg->handler = NULL;
580                   msg->message = NULL;
581                   msg->delete_me = EINA_TRUE;
582                }
583           }
584      }
585    pd->message_walking--;
586 }
587 
588 EOLIAN static Eina_Bool
_efl_loop_message_process(Eo * obj,Efl_Loop_Data * pd)589 _efl_loop_message_process(Eo *obj, Efl_Loop_Data *pd)
590 {
591    if (!pd->message_queue) return EINA_FALSE;
592    pd->message_walking++;
593    _ecore_event_filters_call(obj, pd);
594    while (pd->message_queue)
595      {
596         Message *msg = (Message *)pd->message_queue;
597         if (!msg->delete_me)
598           efl_loop_message_handler_message_call(msg->handler, msg->message);
599         else
600           {
601              if (msg->message) efl_del(msg->message);
602              pd->message_queue =
603                eina_inlist_remove(pd->message_queue,
604                                   pd->message_queue);
605              free(msg);
606           }
607      }
608    pd->message_walking--;
609    if (pd->message_walking == 0)
610      {
611         Message *msg;
612 
613         EINA_INLIST_FREE(pd->message_queue, msg)
614           {
615              if (msg->message)
616                {
617                   if (!msg->delete_me)
618                     ERR("Found unprocessed event msg=%p handler=%p on queue",
619                         msg->message, msg->handler);
620                   efl_del(msg->message);
621                }
622              else free(msg);
623           }
624 
625         while (pd->message_pending_queue)
626           {
627              msg = (Message *)pd->message_pending_queue;
628              pd->message_pending_queue = eina_inlist_remove(pd->message_pending_queue,
629                                                             pd->message_pending_queue);
630              pd->message_queue = eina_inlist_append(pd->message_queue, EINA_INLIST_GET(msg));
631           }
632      }
633    return EINA_TRUE;
634 }
635 
636 EOAPI EFL_FUNC_BODY(efl_loop_message_process, Eina_Bool, 0);
637 
638 EWAPI void
efl_build_version_set(int vmaj,int vmin,int vmic,int revision,const char * flavor,const char * build_id)639 efl_build_version_set(int vmaj, int vmin, int vmic, int revision,
640                       const char *flavor, const char *build_id)
641 {
642    // note: EFL has not been initialized yet at this point (ie. no eina call)
643    _app_efl_version.major = vmaj;
644    _app_efl_version.minor = vmin;
645    _app_efl_version.micro = vmic;
646    _app_efl_version.revision = revision;
647    free((char *)_app_efl_version.flavor);
648    free((char *)_app_efl_version.build_id);
649    _app_efl_version.flavor = flavor ? strdup(flavor) : NULL;
650    _app_efl_version.build_id = build_id ? strdup(build_id) : NULL;
651 }
652 
653 EOLIAN static Eina_Bool
_efl_loop_efl_task_run(Eo * obj,Efl_Loop_Data * pd EINA_UNUSED)654 _efl_loop_efl_task_run(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
655 {
656    efl_loop_exit_code_process(efl_loop_begin(obj));
657    return EINA_TRUE;
658 }
659 
660 EOLIAN static void
_efl_loop_efl_task_end(Eo * obj,Efl_Loop_Data * pd EINA_UNUSED)661 _efl_loop_efl_task_end(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
662 {
663    efl_loop_quit(obj, eina_value_int_init(0));
664 }
665 
666 EFL_SCHEDULER_ARRAY_DEFINE(loop_scheduler,
667                            EFL_LOOP_EVENT_IDLE_ENTER,
668                            EFL_LOOP_EVENT_IDLE);
669 
670 EAPI Eina_Future_Scheduler *
efl_loop_future_scheduler_get(const Eo * obj)671 efl_loop_future_scheduler_get(const Eo *obj)
672 {
673    Efl_Loop *loop;
674 
675    if (!obj) return NULL;
676 
677    if (efl_isa(obj, EFL_LOOP_CLASS))
678      {
679         Efl_Loop_Data *pd = efl_data_scope_get(obj, EFL_LOOP_CLASS);
680 
681         if (!pd) return NULL;
682         return efl_event_future_scheduler_get(obj, loop_scheduler());
683      }
684    if (efl_isa(obj, EFL_LOOP_CONSUMER_CLASS))
685      return efl_loop_future_scheduler_get(efl_loop_get(obj));
686 
687    loop = efl_provider_find(obj, EFL_LOOP_CLASS);
688    if (loop)
689      return efl_loop_future_scheduler_get(loop);
690 
691    return NULL;
692 }
693 
694 #define EFL_LOOP_EXTRA_OPS                                              \
695   EFL_OBJECT_OP_FUNC(efl_loop_message_process, _efl_loop_message_process), \
696   EFL_OBJECT_OP_FUNC(efl_loop_register, _efl_loop_register),          \
697   EFL_OBJECT_OP_FUNC(efl_loop_unregister, _efl_loop_unregister)
698 
699 #include "efl_loop.eo.c"
700