efl

Форк
0
/
eo_base_class.c 
2853 строки · 84.4 Кб
1
#ifdef HAVE_CONFIG_H
2
# include <config.h>
3
#endif
4

5
#include <Eina.h>
6

7
#include <Eo.h>
8

9
#include "eo_internal.h"
10

11
#include "eo_ptr_indirection.h"
12
#include "eo_private.h"
13
#include "eina_promise_private.h"
14

15
EO_API const Efl_Event_Description _EFL_EVENT_CALLBACK_ADD =
16
    EFL_EVENT_DESCRIPTION_HOT("callback,add");
17

18
EO_API const Efl_Event_Description _EFL_EVENT_CALLBACK_DEL =
19
    EFL_EVENT_DESCRIPTION_HOT("callback,del");
20

21
static int event_freeze_count = 0;
22

23
typedef struct _Eo_Callback_Description  Eo_Callback_Description;
24
typedef struct _Efl_Event_Callback_Frame Efl_Event_Callback_Frame;
25
typedef struct _Efl_Event_Forwarder Efl_Event_Forwarder;
26

27
struct _Efl_Event_Forwarder
28
{
29
   const Efl_Event_Description *desc;
30
   Eo *source;
31
   Eo *new_obj;
32

33
   short priority;
34

35
   Eina_Bool inserted : 1;
36
};
37

38
struct _Efl_Event_Callback_Frame
39
{
40
   const Efl_Event_Description    *desc;
41
   Efl_Event_Callback_Frame *next;
42
   unsigned int              idx;
43
   unsigned int              inserted_before;
44
   unsigned short            generation;
45
};
46

47
typedef struct
48
{
49
   const char                *name;
50
   const char                *comment;
51
   Eo                        *composite_parent;
52
   Eina_Inlist               *generic_data;
53
   Eo                      ***wrefs;
54
   Eina_Hash                 *providers;
55
   Eina_Hash                 *schedulers;
56
   Eina_Hash                 *forwarders;
57
} Efl_Object_Extension;
58

59
#define EFL_OBJECT_EVENT_CALLBACK(Event) Eina_Bool event_cb_##Event : 1;
60

61
struct _Efl_Object_Data
62
{
63
   Eina_Inlist               *children;
64
   Eo                        *parent;
65

66
   Efl_Object_Extension      *ext;
67

68
   Efl_Event_Callback_Frame  *event_frame;
69
   Eo_Callback_Description  **callbacks;
70
#ifdef EFL64
71
   uint64_t                   callbacks_mask;
72
#else
73
   uint32_t                   callbacks_mask;
74
#endif
75
   Eina_Inlist               *pending_futures;
76
   unsigned int               callbacks_count;
77

78
   unsigned short             event_freeze_count;
79

80
   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_CALLBACK_ADD);
81
   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_CALLBACK_DEL);
82
   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_DEL);
83
   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_NOREF);
84

85
   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_INVALIDATE);
86
   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_DESTRUCT); // No proper count: minor optimization triggered at destruction only
87
   Eina_Bool                  callback_stopped : 1;
88
   Eina_Bool                  need_cleaning : 1;
89

90
   Eina_Bool                  allow_parent_unref : 1; // Allows unref to zero even with a parent
91
};
92

93
typedef enum
94
{
95
   DATA_PTR,
96
   DATA_OBJ,
97
   DATA_OBJ_WEAK,
98
   DATA_VAL
99
} Eo_Generic_Data_Node_Type;
100

101
typedef struct
102
{
103
   EINA_INLIST;
104
   const Eo                  *obj;
105
   Eina_Stringshare          *key;
106
   union {
107
        Eina_Value           *val;
108
        Eo                   *obj;
109
        void                 *ptr;
110
   } d;
111
   Eo_Generic_Data_Node_Type  d_type;
112
} Eo_Generic_Data_Node;
113

114
typedef struct _Efl_Future_Pending
115
{
116
   EINA_INLIST;
117
   const Eo *o;
118
   Eina_Future *future;
119
   Efl_Future_Cb_Desc desc;
120
} Efl_Future_Pending;
121

122

123
typedef struct
124
{
125
   EINA_INLIST;
126
   const Efl_Event_Description *desc;
127
   unsigned int current;
128
} Eo_Current_Callback_Description;
129

130
#define EVENT_STACK_PUSH(pd, fr) do { \
131
   (fr)->next = (pd)->event_frame; \
132
   (pd)->event_frame = (fr); \
133
} while (0)
134
#define EVENT_STACK_POP(pd) do { \
135
   if ((pd)->event_frame) (pd)->event_frame = (pd)->event_frame->next; \
136
} while (0)
137

138
static void _efl_event_forwarder_callback(void *data, const Efl_Event *event);
139

140
static int _eo_nostep_alloc = -1;
141

142
static void
143
_efl_pending_futures_clear(Efl_Object_Data *pd)
144
{
145
   while (pd->pending_futures)
146
     {
147
        Efl_Future_Pending *pending = EINA_INLIST_CONTAINER_GET(pd->pending_futures, Efl_Future_Pending);
148
        Eina_Future *future = *pending->desc.storage;
149
        assert(future);
150
        eina_future_cancel(future);
151
     }
152
}
153

154
static inline void
155
_efl_object_extension_free(Efl_Object_Extension *ext)
156
{
157
   eina_freeq_ptr_main_add(ext, free, sizeof(*ext));
158
}
159

160
static inline Efl_Object_Extension *
161
_efl_object_extension_need(Efl_Object_Data *pd)
162
{
163
   if (!pd->ext) pd->ext = calloc(1, sizeof(Efl_Object_Extension));
164
   return pd->ext;
165
}
166

167
static inline void
168
_efl_object_extension_noneed(Efl_Object_Data *pd)
169
{
170
   Efl_Object_Extension *ext = pd->ext;
171
   if ((!ext) ||
172
       (ext->name) ||
173
       (ext->comment) ||
174
       (ext->generic_data) ||
175
       (ext->wrefs) ||
176
       (ext->composite_parent) ||
177
       (ext->providers) ||
178
       (ext->schedulers) ||
179
       (ext->forwarders)) return;
180
   _efl_object_extension_free(pd->ext);
181
   pd->ext = NULL;
182
}
183

184
static void
185
_efl_object_invalidate(Eo *obj_id, Efl_Object_Data *pd)
186
{
187
   _efl_pending_futures_clear(pd);
188

189
   if (pd->ext && pd->ext->forwarders)
190
     {
191
        eina_hash_free(pd->ext->forwarders);
192
        pd->ext->forwarders = NULL;
193
        _efl_object_extension_noneed(pd);
194
     }
195

196
   if (pd->ext && pd->ext->providers)
197
     {
198
        eina_hash_free(pd->ext->providers);
199
        pd->ext->providers = NULL;
200
        _efl_object_extension_noneed(pd);
201
     }
202
   if (pd->ext && pd->ext->schedulers)
203
     {
204
        eina_hash_free(pd->ext->schedulers);
205
        pd->ext->schedulers = NULL;
206
        _efl_object_extension_noneed(pd);
207
     }
208

209
   EO_OBJ_POINTER_RETURN(obj_id, obj);
210

211
   // Finally invalidate itself if it wasn't done already
212
   // I am not sure this is a good idea, but it force the
213
   // behavior of calling directly efl_invalidate to be the
214
   // same as efl_parent_set(NULL).
215
   if (!obj->is_invalidating)
216
     efl_parent_set(obj_id, NULL);
217

218
   EO_OBJ_DONE(obj_id);
219
}
220

221
// Generate the invalidate event in all case and make sure it happens
222
// before any user code can change the children invalidate state. This
223
// make sure that the entire tree of object is valid at the time of
224
// the invalidate event.
225
void
226
_efl_invalidate(_Eo_Object *obj)
227
{
228
   Eina_Array stash = { 0 };
229
   Efl_Object_Data *pd;
230
   _Eo_Object *child;
231
   Eo *id;
232

233
   if (obj->is_invalidating) return ;
234
   obj->is_invalidating = EINA_TRUE;
235
   if (obj->invalidate) return;
236

237
   id = _eo_obj_id_get(obj);
238

239
   pd = efl_data_scope_get(id, EFL_OBJECT_CLASS);
240
   if (pd->event_cb_EFL_EVENT_INVALIDATE)
241
     efl_event_callback_call(id, EFL_EVENT_INVALIDATE, NULL);
242

243
   efl_invalidate(id);
244

245
   eina_array_step_set(&stash, sizeof (stash), 4);
246

247
   // Invalidate all children too
248
   EINA_INLIST_FOREACH(pd->children, child)
249
     eina_array_push(&stash, _efl_ref(child));
250

251
   while ((child = eina_array_pop(&stash)))
252
     {
253
        Eo *child_id = _eo_obj_id_get(child);
254

255
        efl_parent_set(child_id, NULL);
256
        _efl_unref(child);
257
     }
258

259
   eina_array_flush(&stash);
260

261
   obj->invalidate = EINA_TRUE;
262
}
263

264
static void _key_generic_cb_del(void *data, const Efl_Event *event);
265

266
static void
267
_eo_generic_data_node_free(Eo_Generic_Data_Node *node)
268
{
269
   switch (node->d_type)
270
     {
271
      case DATA_PTR:
272
        break;
273
      case DATA_OBJ:
274
        // FIXME: should this use "destruct" event instead?
275
        efl_event_callback_del(node->d.obj, EFL_EVENT_DEL, _key_generic_cb_del, node);
276
        efl_unref(node->d.obj);
277
        break;
278
      case DATA_OBJ_WEAK:
279
        // FIXME: should this use "destruct" event instead?
280
        efl_event_callback_del(node->d.obj, EFL_EVENT_DEL, _key_generic_cb_del, node);
281
        break;
282
      case DATA_VAL:
283
        eina_value_free(node->d.val);
284
        break;
285
     }
286
   eina_stringshare_del(node->key);
287
   eina_freeq_ptr_main_add(node, free, sizeof(*node));
288
}
289

290
static void
291
_eo_generic_data_del_all(Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
292
{
293
   Eo_Generic_Data_Node *node;
294
   Efl_Object_Extension *ext = pd->ext;
295

296
   if (!ext) return;
297

298
   while (ext->generic_data)
299
     {
300
        node = (Eo_Generic_Data_Node *)ext->generic_data;
301
        ext->generic_data = eina_inlist_remove(ext->generic_data,
302
              EINA_INLIST_GET(node));
303

304
        _eo_generic_data_node_free(node);
305
     }
306
}
307

308
static void
309
_eo_key_generic_direct_del(Efl_Object_Data *pd, Eo_Generic_Data_Node *node, Eina_Bool call_free)
310
{
311
   Efl_Object_Extension *ext = pd->ext;
312

313
   ext->generic_data = eina_inlist_remove
314
     (ext->generic_data, EINA_INLIST_GET(node));
315
   if (call_free) _eo_generic_data_node_free(node);
316
}
317

318
static void
319
_eo_key_generic_del(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *key, Eina_Bool call_free)
320
{
321
   Eo_Generic_Data_Node *node;
322
   Efl_Object_Extension *ext = pd->ext;
323

324
   EINA_INLIST_FOREACH(ext->generic_data, node)
325
     {
326
        if (!strcmp(node->key, key))
327
          {
328
             ext->generic_data = eina_inlist_remove
329
               (ext->generic_data, EINA_INLIST_GET(node));
330
             if (call_free) _eo_generic_data_node_free(node);
331
             return;
332
          }
333
     }
334
}
335

336
/* Return TRUE if the object was newly added. */
337
static Eo_Generic_Data_Node *
338
_key_generic_set(const Eo *obj, Efl_Object_Data *pd, const char *key, const void *data, Eo_Generic_Data_Node_Type d_type, Eina_Bool call_free)
339
{
340
   Eo_Generic_Data_Node *node;
341
   Efl_Object_Extension *ext = pd->ext;
342

343
   if (!key) return NULL;
344
   if (ext)
345
     {
346
        if (!data)
347
          {
348
             _eo_key_generic_del(obj, pd, key, call_free);
349
             return NULL;
350
          }
351
        EINA_INLIST_FOREACH(ext->generic_data, node)
352
          {
353
             if (!strcmp(node->key, key))
354
               {
355
                  if ((node->d_type == d_type) && (node->d.ptr == data))
356
                     return NULL;
357
                  ext->generic_data = eina_inlist_remove
358
                    (ext->generic_data, EINA_INLIST_GET(node));
359
                  _eo_generic_data_node_free(node);
360
                  break;
361
               }
362
          }
363
     }
364
   else
365
     if (!data) return NULL;
366

367
   ext = _efl_object_extension_need(pd);
368
   if (ext)
369
     {
370
        node = calloc(1, sizeof(Eo_Generic_Data_Node));
371
        if (!node) return NULL;
372
        node->obj = obj;
373
        node->key = eina_stringshare_add(key);
374
        node->d.ptr = (void *) data;
375
        node->d_type = d_type;
376
        ext->generic_data = eina_inlist_prepend
377
          (ext->generic_data, EINA_INLIST_GET(node));
378
        return node;
379
     }
380

381
   return NULL;
382
}
383

384
static void *
385
_key_generic_get(const Eo *obj, Efl_Object_Data *pd, const char *key, Eo_Generic_Data_Node_Type d_type)
386
{
387
   Eo_Generic_Data_Node *node;
388
   Efl_Object_Extension *ext = pd->ext;
389

390
   if (!key) return NULL;
391
   if (!ext) return NULL;
392
   EINA_INLIST_FOREACH(ext->generic_data, node)
393
     {
394
        if (node->key && !strcmp(node->key, key))
395
          {
396
             if (node->d_type == d_type)
397
               {
398
                  ext->generic_data = eina_inlist_promote
399
                    (ext->generic_data, EINA_INLIST_GET(node));
400
                  return node->d.ptr;
401
               }
402
             else
403
               {
404
                  ERR("Object %p key '%s' asked for %d but is %d'",
405
                      obj, key, d_type, node->d_type);
406
                  return NULL;
407
               }
408
          }
409
     }
410
   return NULL;
411
}
412

413
static void
414
_key_generic_cb_del(void *data, const Efl_Event *event EINA_UNUSED)
415
{
416
   Eo_Generic_Data_Node *node = data;
417
   Efl_Object_Data *pd = efl_data_scope_get(node->obj, EFL_OBJECT_CLASS);
418
   _eo_key_generic_direct_del(pd, node, EINA_TRUE);
419
}
420

421
EOLIAN static void
422
_efl_object_key_data_set(Eo *obj, Efl_Object_Data *pd, const char *key, const void *data)
423
{
424
   _key_generic_set(obj, pd, key, data, DATA_PTR, EINA_TRUE);
425
}
426

427
EO_API EFL_VOID_FUNC_BODYV(efl_key_data_set, EFL_FUNC_CALL(key, data),
428
                          const char *key, const void *data);
429

430
EOLIAN static void *
431
_efl_object_key_data_get(Eo *obj, Efl_Object_Data *pd, const char *key)
432
{
433
   return _key_generic_get(obj, pd, key, DATA_PTR);
434
}
435

436
EO_API EFL_FUNC_BODYV_CONST(efl_key_data_get, void *, NULL, EFL_FUNC_CALL(key),
437
                           const char *key);
438

439
EOLIAN static void
440
_efl_object_key_ref_set(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *key, const Eo *objdata)
441
{
442
   Eo_Generic_Data_Node *node;
443

444
   if (!_eo_id_domain_compatible(obj, objdata)) return;
445
   node = _key_generic_set(obj, pd, key, objdata, DATA_OBJ, EINA_TRUE);
446
   if (node)
447
     {
448
        efl_ref(objdata);
449
        efl_event_callback_add((Eo *)objdata, EFL_EVENT_DEL, _key_generic_cb_del, node);
450
     }
451
}
452

453
EO_API EFL_VOID_FUNC_BODYV(efl_key_ref_set, EFL_FUNC_CALL(key, objdata),
454
                          const char *key, const Efl_Object *objdata);
455

456
EOLIAN static Eo *
457
_efl_object_key_ref_get(Eo *obj, Efl_Object_Data *pd, const char *key)
458
{
459
   return _key_generic_get(obj, pd, key, DATA_OBJ);
460
}
461

462
EO_API EFL_FUNC_BODYV_CONST(efl_key_ref_get, Efl_Object *, NULL,
463
                           EFL_FUNC_CALL(key), const char *key);
464

465
EOLIAN static void
466
_efl_object_key_wref_set(Eo *obj, Efl_Object_Data *pd, const char * key, const Efl_Object *objdata)
467
{
468
   Eo_Generic_Data_Node *node;
469

470
   if (!_eo_id_domain_compatible(obj, objdata)) return;
471
   node = _key_generic_set(obj, pd, key, objdata, DATA_OBJ_WEAK, EINA_TRUE);
472
   if (node)
473
     {
474
        efl_event_callback_add((Eo *)objdata, EFL_EVENT_DEL, _key_generic_cb_del, node);
475
     }
476
}
477

478
EO_API EFL_VOID_FUNC_BODYV(efl_key_wref_set, EFL_FUNC_CALL(key, objdata),
479
                          const char *key, const Efl_Object *objdata);
480

481
EOLIAN static Eo *
482
_efl_object_key_wref_get(Eo *obj, Efl_Object_Data *pd, const char * key)
483
{
484
   return _key_generic_get(obj, pd, key, DATA_OBJ_WEAK);
485
}
486

487
EO_API EFL_FUNC_BODYV_CONST(efl_key_wref_get, Efl_Object *, NULL,
488
                           EFL_FUNC_CALL(key), const char *key);
489

490
EOLIAN static void
491
_efl_object_key_value_set(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *key, Eina_Value *value)
492
{
493
   _key_generic_set(obj, pd, key, value, DATA_VAL, EINA_TRUE);
494
}
495

496
EO_API EFL_VOID_FUNC_BODYV(efl_key_value_set, EFL_FUNC_CALL(key, value),
497
                          const char *key, Eina_Value *value);
498

499
EOLIAN static Eina_Value *
500
_efl_object_key_value_get(Eo *obj, Efl_Object_Data *pd, const char *key)
501
{
502
   return _key_generic_get(obj, pd, key, DATA_VAL);
503
}
504

505
EO_API EFL_FUNC_BODYV_CONST(efl_key_value_get, Eina_Value *, NULL,
506
                           EFL_FUNC_CALL(key), const char *key);
507

508
EOLIAN static void
509
_efl_object_name_set(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *name)
510
{
511
   if ((name) && (!name[0])) name = NULL;
512
   if (name)
513
     {
514
        _efl_object_extension_need(pd);
515
        if (pd->ext) eina_stringshare_replace(&(pd->ext->name), name);
516
     }
517
   else
518
     {
519
        if (!pd->ext) return;
520
        if (pd->ext->name)
521
          {
522
             eina_stringshare_replace(&(pd->ext->name), name);
523
             _efl_object_extension_noneed(pd);
524
          }
525
     }
526
}
527

528
EOLIAN static const char *
529
_efl_object_name_get(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
530
{
531
   if (!pd->ext) return NULL;
532
   return pd->ext->name;
533
}
534

535
static inline Eina_Bool
536
_name_match(const char *match, Eina_Bool is_glob, const char *str)
537
{
538
   if (str)
539
     {
540
        if (is_glob)
541
          {
542
             // if match string is empty - then it matches - same as "*"
543
             if (!match[0]) return EINA_TRUE;
544
             // if match string is "*" special case it and match
545
             if ((match[0] == '*') && (match[1] == 0)) return EINA_TRUE;
546
             // actual compare
547
             if (eina_fnmatch(match, str, 0)) return EINA_TRUE;
548
          }
549
        else
550
          {
551
             // if match string is empty - then it matches - same as "*"
552
             if (!match[0]) return EINA_TRUE;
553
             // if pointers are the same they must be the same
554
             if (match == str) return EINA_TRUE;
555
             // actual compare
556
             if (!strcmp(match, str)) return EINA_TRUE;
557
          }
558
     }
559
   return EINA_FALSE;
560
}
561

562
static inline Eina_Bool
563
_matchall(const char *match)
564
{
565
   if ((match[0] == 0) || ((match[0] == '*') && (match[1] == 0)))
566
     return EINA_TRUE;
567
   return EINA_FALSE;
568
}
569

570
static Eina_Bool
571
_hasglob(const char *match)
572
{
573
   if (strpbrk(match, "*?[")) return EINA_TRUE;
574
   return EINA_FALSE;
575
}
576

577
static Eina_Bool
578
_ismultiglob(const char *match)
579
{
580
   if ((match[0] == '*') && (match[1] == '*') && (match[2] == 0))
581
     return EINA_TRUE;
582
   if ((match[0] == '*') && (match[1] == '*') && (match[2] == '/'))
583
     return EINA_TRUE;
584
   if ((match[0] == '/') && (match[1] == '*') && (match[2] == '*') && (match[3] == 0))
585
     return EINA_TRUE;
586
   if ((match[0] == '/') && (match[1] == '*') && (match[2] == '*') && (match[3] == '/'))
587
     return EINA_TRUE;
588
   return EINA_FALSE;
589
}
590

591
EOLIAN static Efl_Object *
592
_efl_object_name_find(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *search)
593
{
594
   Eo *child;
595
   _Eo_Object *child_eo;
596
   const char *name, *p, *klass_name;
597

598
   // notes:
599
   // if search contains NO "/" char, then its just a name search.
600
   // if there is one or more "/" chars, then these are explicitly object
601
   // delimiters.
602
   // a name of "**" means 0 or more objects in the heirachy chain
603
   // if the string has no "/" char at the start, it implies "/**/"
604
   // a name can be a name or the form "class:name" where the object must
605
   // be of class named "class" and name "name". if "name" is empty like:
606
   // "class:" then an object of any name will match like "class:*". an
607
   // empty class like ":name" is the sanme as "*:name" which is the same
608
   // as "name". class ane name of course can be basic globs but not **
609

610
   // search string NULL or "" is invalid
611
   if (!search) return NULL;
612
   if (!search[0]) return NULL;
613

614
   if (strchr(search, '/'))
615
     {
616
        ERR("Looking up object by path '%s' is not supported", search);
617
        return NULL;
618
     }
619
   else
620
     {
621
        // if this is a multi glob - "**" then we don't have a name or
622
        // class to match at all so just don't look
623
        if (_ismultiglob(search)) return NULL;
624
        // check if this is "class:name" or just "name"
625
        if ((p = strchr(search, ':')))
626
          {
627
             // "class:name"
628
             char *klass;
629
             char *search_name;
630
             size_t colon_location = p - search;
631
             Eina_Bool klass_glob = EINA_FALSE;
632
             Eina_Bool name_glob = EINA_FALSE;
633

634
             // split class:name into 2 strings dropping :
635
             klass = alloca(strlen(search) + 1);
636
             strcpy(klass, search);
637
             klass[colon_location] = '\0';
638
             search_name = klass + colon_location + 1;
639

640
             // figure out if class or name are globs
641
             klass_glob = _hasglob(klass);
642
             name_glob = _hasglob(search_name);
643
             EINA_INLIST_FOREACH(pd->children, child_eo)
644
               {
645
                  child = _eo_obj_id_get(child_eo);
646
                  name = efl_name_get(child);
647
                  klass_name = efl_class_name_get(efl_class_get(child));
648
                  if (_name_match(klass, klass_glob, klass_name) &&
649
                      (((!_matchall(klass)) && (!name) && (_matchall(search_name))) ||
650
                       ((name) && _name_match(search_name, name_glob, name))))
651
                    return child;
652
                  child = efl_name_find(child, search);
653
                  if (child) return child;
654
               }
655
          }
656
        else
657
          {
658
             if (_hasglob(search))
659
               {
660
                  // we have a glob - fnmatch
661
                  EINA_INLIST_FOREACH(pd->children, child_eo)
662
                    {
663
                       child = _eo_obj_id_get(child_eo);
664
                       name = efl_name_get(child);
665
                       if ((name) && (_name_match(search, EINA_TRUE, name)))
666
                         return child;
667
                       child = efl_name_find(child, search);
668
                       if (child) return child;
669
                    }
670
               }
671
             else
672
               {
673
                  // fast path for simple "name"
674
                  EINA_INLIST_FOREACH(pd->children, child_eo)
675
                    {
676
                       child = _eo_obj_id_get(child_eo);
677
                       name = efl_name_get(child);
678
                       if ((name) && (_name_match(search, EINA_FALSE, name)))
679
                         return child;
680
                       child = efl_name_find(child, search);
681
                       if (child) return child;
682
                    }
683
               }
684
          }
685
     }
686
   return NULL;
687
}
688

689
EOLIAN static void
690
_efl_object_comment_set(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *comment)
691
{
692
   if ((comment) && (!comment[0])) comment = NULL;
693
   if (comment)
694
     {
695
        _efl_object_extension_need(pd);
696
        if (pd->ext) eina_stringshare_replace(&(pd->ext->comment), comment);
697
     }
698
   else
699
     {
700
        if (!pd->ext) return;
701
        if (pd->ext->comment)
702
          {
703
             eina_stringshare_replace(&(pd->ext->comment), comment);
704
             _efl_object_extension_noneed(pd);
705
          }
706
     }
707
}
708

709
EOLIAN static const char *
710
_efl_object_comment_get(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
711
{
712
   if (!pd->ext) return NULL;
713
   return pd->ext->comment;
714
}
715

716
EOLIAN static void
717
_efl_object_debug_name_override(Eo *obj_id EINA_UNUSED, Efl_Object_Data *pd EINA_UNUSED, Eina_Strbuf *sb EINA_UNUSED)
718
{
719
}
720

721
EO_API void
722
efl_del(const Eo *obj)
723
{
724
   if (!obj) return ;
725
   EO_OBJ_POINTER_RETURN(obj, oid);
726
   _efl_ref(oid);
727
   if (efl_parent_get((Eo *) obj))
728
     {
729
        efl_parent_set((Eo *) obj, NULL);
730
     }
731
   else
732
     {
733
        ERR("Calling efl_del on object %s with no parent is not advised any more.", efl_debug_name_get(obj));
734
        efl_unref(obj);
735
     }
736
   _efl_unref(oid);
737
   EO_OBJ_DONE(obj);
738
}
739

740
void
741
_efl_object_reuse(_Eo_Object *obj)
742
{
743
   obj->is_invalidating = EINA_FALSE;
744
   obj->invalidate = EINA_FALSE;
745
}
746

747
EOLIAN void
748
_efl_object_parent_set(Eo *obj, Efl_Object_Data *pd, Eo *parent_id)
749
{
750
   Eo *prev_parent = pd->parent;
751
   Eina_Bool bad_parent = EINA_FALSE;
752

753
   if ((pd->parent == parent_id) ||
754
       ((parent_id) && (!_eo_id_domain_compatible(parent_id, obj))))
755
     return;
756

757
   if (parent_id != NULL)
758
     {
759
        EO_OBJ_POINTER_GOTO(parent_id, parent_obj, err_impossible);
760
        bad_parent = parent_obj->invalidate || (obj == parent_id);
761
        EO_OBJ_DONE(parent_id);
762
     }
763

764
   if (bad_parent) goto err_parent;
765

766
   EO_OBJ_POINTER_GOTO(obj, eo_obj, err_impossible);
767

768
   // Invalidated object can not be bring back to life
769
   if (eo_obj->invalidate)
770
     {
771
        ERR("Call of efl_parent_set(%p, %p) when object of clas '%s' is already invalidated.\n", obj, parent_id, efl_class_name_get(obj));
772
        goto err_impossible;
773
     }
774

775
   if (!parent_id)
776
     {
777
        if (prev_parent) _efl_invalidate(eo_obj);
778
     }
779

780
   if (pd->parent)
781
     {
782
        Efl_Object_Data *old_parent_pd = efl_data_scope_get(pd->parent,
783
                                                            EFL_OBJECT_CLASS);
784

785
        if (old_parent_pd)
786
          old_parent_pd->children = eina_inlist_remove(old_parent_pd->children,
787
                                                       EINA_INLIST_GET(eo_obj));
788
        // this error is highly unlikely so move it out of the normal
789
        // instruction path to avoid l1 cache pollution
790
        else goto err_impossible;
791
     }
792

793
   /* Set new parent */
794
   if (parent_id)
795
     {
796
        Efl_Object_Data *parent_pd = efl_data_scope_get(parent_id,
797
                                                        EFL_OBJECT_CLASS);
798

799
        if (EINA_LIKELY(parent_pd != NULL))
800
          {
801
             pd->parent = parent_id;
802
             parent_pd->children = eina_inlist_append(parent_pd->children,
803
                                                      EINA_INLIST_GET(eo_obj));
804
             if (!prev_parent) efl_ref(obj);
805
          }
806
        else
807
          {
808
             pd->parent = NULL;
809
             if (prev_parent) efl_unref(obj);
810
             // unlikely this error happens, so move it out of execution path
811
             // to improve l1 cache efficiency
812
             goto err_parent_done;
813
          }
814

815
        eo_obj->parent = EINA_TRUE;
816
     }
817
   else
818
     {
819
        pd->parent = NULL;
820
        eo_obj->parent = EINA_FALSE;
821

822
        if (prev_parent && !eo_obj->del_triggered) efl_unref(obj);
823
     }
824

825
   EO_OBJ_DONE(obj);
826
   return;
827

828
err_parent_done:
829
   EO_OBJ_DONE(obj);
830
err_parent:
831
   if (obj == parent_id)
832
     ERR("New parent %p for object %p will not be set: THIS IS THE SAME OBJECT.",
833
         parent_id, obj);
834
   else
835
     ERR("New parent %p for object %p is not a valid Eo object.",
836
         parent_id, obj);
837
   return;
838

839
err_impossible:
840
   ERR("CONTACT DEVS!!! SHOULD NEVER HAPPEN!!! Old parent %p for object %p is not a valid Eo object.",
841
       pd->parent, obj);
842
}
843

844
EOLIAN static Eo *
845
_efl_object_parent_get(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
846
{
847
   return pd->parent;
848
}
849

850
EOLIAN static Eina_Bool
851
_efl_object_finalized_get(const Eo *obj_id, Efl_Object_Data *pd EINA_UNUSED)
852
{
853
   Eina_Bool finalized;
854
   EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE);
855
   finalized = obj->finalized;
856
   EO_OBJ_DONE(obj_id);
857
   return finalized;
858
}
859

860
EOLIAN static Eina_Bool
861
_efl_object_invalidated_get(const Eo *obj_id, Efl_Object_Data *pd)
862
{
863
   Eina_Bool invalidate;
864
   EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_TRUE);
865
   invalidate = obj->invalidate;
866
   EO_OBJ_DONE(obj_id);
867
   if (!invalidate && pd && pd->parent)
868
     return efl_invalidated_get(pd->parent);
869
   return invalidate;
870
}
871

872
EOLIAN static Eina_Bool
873
_efl_object_invalidating_get(const Eo *obj_id, Efl_Object_Data *pd EINA_UNUSED)
874
{
875
   Eina_Bool invalidating;
876
   EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_TRUE);
877
   invalidating = obj->is_invalidating;
878
   EO_OBJ_DONE(obj_id);
879
   return invalidating;
880
}
881

882
EOLIAN static Efl_Object *
883
_efl_object_provider_find(const Eo *obj, Efl_Object_Data *pd, const Efl_Object *klass)
884
{
885
   Eina_Bool invalidate;
886
   Efl_Object *r = NULL;
887

888
   invalidate = _efl_object_invalidated_get((Eo*) obj, NULL);
889
   if (invalidate)
890
     {
891
        ERR("Calling efl_provider_find(%p) after the object was invalidated.", obj);
892
        return NULL;
893
     }
894

895
   if (efl_isa(obj, klass)) return (Eo *) obj;
896

897
   if (pd->ext) r = eina_hash_find(pd->ext->providers, &klass);
898
   if (r) return r;
899

900
   if (pd->parent) return efl_provider_find(pd->parent, klass);
901
   return NULL;
902
}
903

904
static Eina_Bool
905
_efl_object_provider_register(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const Efl_Class *klass, const Efl_Object *provider)
906
{
907
   // The passed object does not provide that said class.
908
   if (!efl_isa(provider, klass)) return EINA_FALSE;
909

910
   _efl_object_extension_need(pd);
911
   if (!pd->ext) return EINA_FALSE;
912
   if (!pd->ext->providers) pd->ext->providers = eina_hash_pointer_new(EINA_FREE_CB(efl_unref));
913

914
   // Prevent double insertion for the same class
915
   if (eina_hash_find(pd->ext->providers, &klass)) return EINA_FALSE;
916

917
   // Note: I would prefer to use efl_xref here, but I can't figure a nice way to
918
   // call efl_xunref on hash destruction.
919
   return eina_hash_add(pd->ext->providers, &klass, efl_ref(provider));
920
}
921

922
static Eina_Bool
923
_efl_object_provider_unregister(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const Efl_Class *klass, const Efl_Object *provider)
924
{
925
   Eina_Bool r;
926

927
   if (!pd->ext) return EINA_FALSE;
928
   r = eina_hash_del(pd->ext->providers, &klass, provider);
929

930
   if (eina_hash_population(pd->ext->providers) != 0) return r;
931
   eina_hash_free(pd->ext->providers);
932
   pd->ext->providers = NULL;
933
   _efl_object_extension_noneed(pd);
934

935
   return r;
936
}
937

938
/* Children accessor */
939
typedef struct _Eo_Children_Iterator Eo_Children_Iterator;
940
struct _Eo_Children_Iterator
941
{
942
   Eina_Iterator iterator;
943
   Eina_Inlist *current;
944
   _Eo_Object *obj;
945
   Eo *obj_id;
946
};
947

948
static Eina_Bool
949
_efl_children_iterator_next(Eo_Children_Iterator *it, void **data)
950
{
951
   if (!it->current) return EINA_FALSE;
952

953
   if (data)
954
     {
955
        _Eo_Object *eo_obj = EINA_INLIST_CONTAINER_GET(it->current, _Eo_Object);
956
        *data = _eo_obj_id_get(eo_obj);
957
     }
958
   it->current = it->current->next;
959

960
   return EINA_TRUE;
961
}
962

963
static Eo *
964
_efl_children_iterator_container(Eo_Children_Iterator *it)
965
{
966
   return it->obj_id;
967
}
968

969
static void
970
_efl_children_iterator_free(Eo_Children_Iterator *it)
971
{
972
   _Efl_Class *klass;
973
   _Eo_Object *obj;
974

975
   klass = (_Efl_Class*) it->obj->klass;
976
   obj = it->obj;
977

978
   eina_spinlock_take(&klass->iterators.trash_lock);
979
   if (klass->iterators.trash_count < 8)
980
     {
981
        klass->iterators.trash_count++;
982
        eina_trash_push(&klass->iterators.trash, it);
983
     }
984
   else
985
     {
986
        eina_freeq_ptr_main_add(it, free, sizeof(*it));
987
     }
988
   eina_spinlock_release(&klass->iterators.trash_lock);
989

990
   _efl_unref(obj);
991
}
992

993
EOLIAN static Eina_Iterator *
994
_efl_object_children_iterator_new(Eo *obj_id, Efl_Object_Data *pd)
995
{
996
   _Efl_Class *klass;
997
   Eo_Children_Iterator *it = NULL;
998

999
   EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
1000

1001
   if (pd->children)
1002
     {
1003
        klass = (_Efl_Class *)obj->klass;
1004

1005
        eina_spinlock_take(&klass->iterators.trash_lock);
1006
        it = eina_trash_pop(&klass->iterators.trash);
1007
        if (it)
1008
          {
1009
             klass->iterators.trash_count--;
1010
             memset(it, 0, sizeof (Eo_Children_Iterator));
1011
          }
1012
        else it = calloc(1, sizeof (Eo_Children_Iterator));
1013
        eina_spinlock_release(&klass->iterators.trash_lock);
1014
        // very unlikely to not allocate the iterator to move this error
1015
        // handling out of l1 instruction cache
1016
        if (!it) goto done;
1017

1018
        EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
1019
        it->current = pd->children;
1020
        it->obj = _efl_ref(obj);
1021
        it->obj_id = obj_id;
1022
        it->iterator.next = FUNC_ITERATOR_NEXT(_efl_children_iterator_next);
1023
        it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_efl_children_iterator_container);
1024
        it->iterator.free = FUNC_ITERATOR_FREE(_efl_children_iterator_free);
1025
     }
1026
done:
1027
   EO_OBJ_DONE(obj_id);
1028
   return (Eina_Iterator *)it;
1029
}
1030

1031
EOLIAN static void
1032
_efl_object_dbg_info_get(Eo *obj EINA_UNUSED, Efl_Object_Data *pd EINA_UNUSED, Efl_Dbg_Info *root_node EINA_UNUSED)
1033
{  /* No info required in the meantime */
1034
   return;
1035
}
1036

1037
EO_API EFL_VOID_FUNC_BODYV(efl_dbg_info_get, EFL_FUNC_CALL(root_node), Efl_Dbg_Info *root_node);
1038

1039
/* Weak reference. */
1040

1041
static inline size_t
1042
_wref_count(Efl_Object_Data *pd)
1043
{
1044
   Eo ***itr;
1045
   size_t count = 0;
1046
   Efl_Object_Extension *ext = pd->ext;
1047

1048
   if ((!ext) || (!ext->wrefs)) return 0;
1049
   for (itr = ext->wrefs; *itr; itr++) count++;
1050

1051
   return count;
1052
}
1053

1054
EOLIAN static void
1055
_efl_object_wref_add(Eo *obj, Efl_Object_Data *pd, Eo **wref)
1056
{
1057
   size_t count;
1058
   Eo ***tmp;
1059
   Efl_Object_Extension *ext;
1060

1061
   count = _wref_count(pd);
1062
   count += 1; /* New wref. */
1063

1064
   ext = _efl_object_extension_need(pd);
1065
   if (ext)
1066
     {
1067
        tmp = realloc(ext->wrefs, sizeof(*ext->wrefs) * (count + 1));
1068
        if (tmp)
1069
          {
1070
             ext->wrefs = tmp;
1071
             ext->wrefs[count - 1] = wref;
1072
             ext->wrefs[count] = NULL;
1073
             *wref = obj;
1074
          }
1075
     }
1076
}
1077

1078
EO_API EFL_VOID_FUNC_BODYV(efl_wref_add, EFL_FUNC_CALL(wref), Efl_Object **wref);
1079

1080
EOLIAN static void
1081
_efl_object_wref_del(Eo *obj, Efl_Object_Data *pd, Eo **wref)
1082
{
1083
   size_t count;
1084
   Efl_Object_Extension *ext = pd->ext;
1085

1086
   // very unlikely so improve l1 instr cache by using goto
1087
   if (*wref != obj) goto err_wref_not_obj;
1088

1089
   // very unlikely so improve l1 instr cache by using goto
1090
   if ((!ext) || (!ext->wrefs)) goto err_wref_none;
1091

1092
   /* Move the last item in the array instead of the current wref. */
1093
   count = _wref_count(pd);
1094

1095
     {
1096
        Eo ***itr;
1097
        for (itr = ext->wrefs; *itr; itr++)
1098
          {
1099
             if (*itr == wref)
1100
               {
1101
                  *itr = ext->wrefs[count - 1];
1102
                  break;
1103
               }
1104
          }
1105
        // very unlikely so improve l1 instr cache by using goto
1106
        if (!*itr) goto err_noiter;
1107
     }
1108

1109
   if (count > 1)
1110
     {
1111
        Eo ***tmp;
1112
        // No count--; because of the NULL that is not included in the count
1113
        tmp = realloc(ext->wrefs, sizeof(*ext->wrefs) * count);
1114
        if (!tmp) return;
1115
        ext->wrefs = tmp;
1116
        ext->wrefs[count - 1] = NULL;
1117
        *wref = NULL;
1118
        return;
1119
     }
1120
   else
1121
     {
1122
        eina_freeq_ptr_main_add(ext->wrefs, free, 0);
1123
        ext->wrefs = NULL;
1124
        _efl_object_extension_noneed(pd);
1125
     }
1126

1127
   *wref = NULL;
1128
   return;
1129

1130
err_noiter:
1131
   ERR("Wref %p is not associated with object %p", wref, obj);
1132
   goto err_null;
1133
err_wref_none:
1134
   ERR("There are no weak refs for object %p", obj);
1135
err_null:
1136
   *wref = NULL;
1137
   return;
1138
err_wref_not_obj:
1139
   ERR("Wref is a weak ref to %p, while this function was called on %p.",
1140
       *wref, obj);
1141
   return;
1142
}
1143

1144
EO_API EFL_VOID_FUNC_BODYV(efl_wref_del, EFL_FUNC_CALL(wref), Efl_Object **wref);
1145

1146
static inline void
1147
_wref_destruct(Efl_Object_Data *pd)
1148
{
1149
   Eo ***itr;
1150
   Efl_Object_Extension *ext = pd->ext;
1151

1152
   if ((!ext) || (!ext->wrefs)) return;
1153
   for (itr = ext->wrefs; *itr; itr++) **itr = NULL;
1154
   eina_freeq_ptr_main_add(ext->wrefs, free, 0);
1155
   ext->wrefs = NULL;
1156
}
1157

1158
/* EOF Weak reference. */
1159

1160
/* Event callbacks */
1161

1162
/* Callbacks */
1163

1164
/* XXX: Legacy support, remove when legacy is dead. */
1165
static Eina_Hash *_legacy_events_hash = NULL;
1166

1167
EO_API const Efl_Event_Description *
1168
efl_object_legacy_only_event_description_get(const char *_event_name)
1169
{
1170
   Eina_Stringshare *event_name = eina_stringshare_add(_event_name);
1171
   Efl_Event_Description *event_desc = eina_hash_find(_legacy_events_hash, event_name);
1172
   if (!event_desc)
1173
     {
1174
        event_desc = calloc(1, sizeof(Efl_Event_Description));
1175
        event_desc->name = event_name;
1176
        event_desc->legacy_is = EINA_TRUE;
1177
        event_desc->unfreezable = EINA_TRUE;
1178
        eina_hash_add(_legacy_events_hash, event_name, event_desc);
1179
     }
1180
   else
1181
     {
1182
        eina_stringshare_del(event_name);
1183
     }
1184

1185
   return event_desc;
1186
}
1187

1188
static inline Eina_Bool
1189
_legacy_event_desc_is(const Efl_Event_Description *desc)
1190
{
1191
   return desc->legacy_is;
1192
}
1193

1194
static void
1195
_legacy_events_hash_free_cb(void *_desc)
1196
{
1197
   Efl_Event_Description *desc = _desc;
1198
   eina_stringshare_del(desc->name);
1199
   eina_freeq_ptr_main_add(desc, free, sizeof(*desc));
1200
}
1201

1202
/* EOF Legacy */
1203
struct _Eo_Callback_Description
1204
{
1205
   union
1206
     {
1207
        Efl_Callback_Array_Item item;
1208
        const Efl_Callback_Array_Item *item_array;
1209
     } items;
1210

1211
   void *func_data;
1212
   Efl_Callback_Priority priority;
1213

1214
   unsigned short generation;
1215

1216
   Eina_Bool delete_me : 1;
1217
   Eina_Bool func_array : 1;
1218
};
1219

1220
static Eina_Mempool *_eo_callback_mempool = NULL;
1221
static Eina_Mempool *_efl_pending_future_mempool = NULL;
1222
static Eina_Mempool *_efl_future_scheduler_entry_mempool = NULL;
1223

1224
static void
1225
_eo_callback_free(Eo_Callback_Description *cb)
1226
{
1227
   eina_mempool_free(_eo_callback_mempool, cb);
1228
}
1229

1230
static Eo_Callback_Description *
1231
_eo_callback_new(void)
1232
{
1233
   return eina_mempool_calloc(_eo_callback_mempool,
1234
                              sizeof(Eo_Callback_Description));
1235
}
1236

1237
static void
1238
_efl_pending_future_free(Efl_Future_Pending *pending)
1239
{
1240
   eina_mempool_free(_efl_pending_future_mempool, pending);
1241
}
1242

1243
static Efl_Future_Pending *
1244
_efl_pending_future_new(void)
1245
{
1246
   return eina_mempool_calloc(_efl_pending_future_mempool,
1247
                              sizeof(Efl_Future_Pending));
1248
}
1249

1250
#define CB_COUNT_INC(cnt) do { if ((cnt) != 0xffff) (cnt)++; } while(0)
1251
#define CB_COUNT_DEC(cnt) do { if ((cnt) != 0xffff) (cnt)--; } while(0)
1252

1253
static inline unsigned char
1254
_pointer_hash(const uintptr_t val)
1255
{
1256
   static unsigned char shift = 0;
1257

1258
   /* Sadly LLVM doesn't have log2 in its compile time optimization. So
1259
      we can not use static const here for portability sake. */
1260
   if (EINA_UNLIKELY((!shift)))
1261
     shift = (unsigned char) log2(1 + sizeof (Efl_Event_Description));
1262
#ifdef EFL64
1263
   return (unsigned char)(((val) >> shift) & 0x3F);
1264
#else
1265
   return (unsigned char)(((val) >> shift) & 0x1F);
1266
#endif
1267
}
1268

1269
#define EFL_OBJECT_EVENT_CB_INC(Obj, It, Pd, Event, Update_Hash)        \
1270
  if (It->desc == Event && !Pd->event_cb_##Event)                       \
1271
    {                                                                   \
1272
       Update_Hash = EINA_FALSE;                                        \
1273
       Pd->event_cb_##Event = EINA_TRUE;                                \
1274
    }
1275

1276
#define EFL_OBJECT_EVENT_CB_DEC(Obj, It, Pd, Event)     \
1277
  if (It->desc == Event && Pd->event_cb_##Event)        \
1278
    {                                                   \
1279
       if (!efl_event_callback_count(Obj, Event))       \
1280
         Pd->event_cb_##Event = EINA_FALSE;             \
1281
    }
1282

1283
static inline void
1284
_special_event_count_inc(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Array_Item *it)
1285
{
1286
   Eina_Bool update_hash = EINA_TRUE;
1287

1288
   EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_CALLBACK_ADD, update_hash)
1289
   else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_CALLBACK_DEL, update_hash)
1290
   else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_DEL, update_hash)
1291
   else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_INVALIDATE, update_hash)
1292
   else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_DESTRUCT, update_hash)
1293
   else if (it->desc == EFL_EVENT_NOREF && !pd->event_cb_EFL_EVENT_NOREF)
1294
     {
1295
        update_hash = EINA_FALSE;
1296
        EO_OBJ_POINTER_RETURN(obj_id, obj);
1297
        obj->noref_event = EINA_TRUE;
1298
        EO_OBJ_DONE(obj_id);
1299
        pd->event_cb_EFL_EVENT_NOREF = EINA_TRUE;
1300
     }
1301
   else if (it->desc == EFL_EVENT_OWNERSHIP_SHARED || it->desc == EFL_EVENT_OWNERSHIP_UNIQUE)
1302
     {
1303
        EO_OBJ_POINTER_RETURN(obj_id, obj);
1304
        obj->ownership_track = EINA_TRUE;
1305
        EO_OBJ_DONE(obj_id);
1306
     }
1307

1308
   if (pd->ext && pd->ext->forwarders)
1309
     {
1310
        Efl_Event_Forwarder *forwarder;
1311
        Eina_List *l;
1312

1313
        // Check if some event need to be forwarded now
1314
        EINA_LIST_FOREACH(eina_hash_find(pd->ext->forwarders, it->desc), l, forwarder)
1315
          {
1316
             if (!forwarder->source) continue;
1317
             if (forwarder->inserted) continue;
1318
             efl_event_callback_priority_add(forwarder->source,
1319
                                             forwarder->desc,
1320
                                             forwarder->priority,
1321
                                             _efl_event_forwarder_callback, obj_id);
1322
             forwarder->inserted = EINA_TRUE;
1323
          }
1324
     }
1325

1326
   if (update_hash)
1327
     {
1328
        unsigned char event_hash;
1329

1330
        event_hash = _pointer_hash((uintptr_t) it->desc);
1331

1332
        pd->callbacks_mask |= 1ULL << event_hash;
1333
     }
1334
}
1335

1336
static inline void
1337
_special_event_count_dec(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Array_Item *it)
1338
{
1339
   EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_CALLBACK_ADD)
1340
   else EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_CALLBACK_DEL)
1341
   else EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_DEL)
1342
   else EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_INVALIDATE)
1343
   else if (it->desc == EFL_EVENT_NOREF && pd->event_cb_EFL_EVENT_NOREF)
1344
     {
1345
        if (efl_event_callback_count(obj_id, EFL_EVENT_NOREF) == 0)
1346
          {
1347
             EO_OBJ_POINTER_RETURN(obj_id, obj);
1348
             obj->noref_event = EINA_FALSE;
1349
             EO_OBJ_DONE(obj_id);
1350

1351
             pd->event_cb_EFL_EVENT_NOREF = EINA_FALSE;
1352
          }
1353
     }
1354
}
1355

1356
/* Actually remove, doesn't care about walking list, or delete_me */
1357
static void
1358
_eo_callback_remove(Eo *obj, Efl_Object_Data *pd, Eo_Callback_Description **cb)
1359
{
1360
   Eo_Callback_Description *tmp = *cb;
1361
   unsigned int length;
1362
   const Efl_Callback_Array_Item *it;
1363

1364
   length = pd->callbacks_count - (cb - pd->callbacks);
1365
   if (length > 1)
1366
     memmove(cb, cb + 1, (length - 1) * sizeof(Eo_Callback_Description *));
1367
   pd->callbacks_count--;
1368

1369
   if (_eo_nostep_alloc) pd->callbacks = realloc(pd->callbacks, pd->callbacks_count * sizeof (Eo_Callback_Description*));
1370

1371
   if (pd->callbacks_count == 0)
1372
     {
1373
        free(pd->callbacks);
1374
        pd->callbacks = NULL;
1375
     }
1376

1377
   if (tmp->func_array)
1378
     {
1379
        for (it = tmp->items.item_array; it->func; it++)
1380
          _special_event_count_dec(obj, pd, it);
1381
     }
1382
   else _special_event_count_dec(obj, pd, &(tmp->items.item));
1383

1384
   _eo_callback_free(tmp);
1385
}
1386

1387
/* Actually remove, doesn't care about walking list, or delete_me */
1388
static void
1389
_eo_callback_remove_all(Efl_Object_Data *pd)
1390
{
1391
   unsigned int i;
1392

1393
   for (i = 0; i < pd->callbacks_count; i++)
1394
     _eo_callback_free(pd->callbacks[i]);
1395

1396
   eina_freeq_ptr_main_add(pd->callbacks, free, 0);
1397
   pd->callbacks = NULL;
1398
   pd->callbacks_count = 0;
1399
   pd->event_cb_EFL_EVENT_DESTRUCT = EINA_FALSE;
1400
   pd->event_cb_EFL_EVENT_CALLBACK_ADD = EINA_FALSE;
1401
   pd->event_cb_EFL_EVENT_CALLBACK_DEL = EINA_FALSE;
1402
   pd->event_cb_EFL_EVENT_DEL = EINA_FALSE;
1403
   pd->event_cb_EFL_EVENT_NOREF = EINA_FALSE;
1404
   pd->event_cb_EFL_EVENT_INVALIDATE = EINA_FALSE;
1405
}
1406

1407
static void
1408
_eo_callbacks_clear(Eo *obj, Efl_Object_Data *pd)
1409
{
1410
   Eo_Callback_Description **itr;
1411
   unsigned int i = 0;
1412
   Eina_Bool remove_callbacks;
1413
   unsigned int generation_clamp;
1414

1415
   /* If there are no deletions waiting. */
1416
   if (!pd->need_cleaning) return;
1417

1418

1419
   if (pd->event_frame)
1420
     {
1421
        /* there is still a event emission going on ... do not delete anything! */
1422
        remove_callbacks = EINA_FALSE;
1423
        /* if we are in event subscription we need to clamp the generations at the current frame otherwise we are possiblity not executing that later */
1424
        generation_clamp = pd->event_frame->generation;
1425
     }
1426
   else
1427
     {
1428
        /* no event emission running */
1429
        /* remove deleted callbacks */
1430
        remove_callbacks = EINA_TRUE;
1431
        /* clap to 0 generation */
1432
        generation_clamp = 0;
1433
        /* we dont need to clean later */
1434
        pd->need_cleaning = EINA_FALSE;
1435
     }
1436

1437
   while (i < pd->callbacks_count)
1438
     {
1439
        itr = pd->callbacks + i;
1440
        if (remove_callbacks && (*itr)->delete_me)
1441
          {
1442
             _eo_callback_remove(obj, pd, itr);
1443
          }
1444
        else
1445
          {
1446
             if ((*itr)->generation > generation_clamp)
1447
               (*itr)->generation = generation_clamp;
1448
             i++;
1449
          }
1450
     }
1451
}
1452

1453
static inline unsigned int
1454
_eo_callback_search_sorted_near(const Efl_Object_Data *pd, const Eo_Callback_Description *look)
1455
{
1456
   unsigned int start, last, middle;
1457
   const Eo_Callback_Description *p;
1458
   int cmp;
1459

1460
   if      (pd->callbacks_count == 0) return 0;
1461
   else if (pd->callbacks_count == 1) return 0;
1462

1463
   start = 0;
1464
   last = pd->callbacks_count - 1;
1465
   do
1466
     {
1467
        middle = start + ((last - start) / 2);
1468
        p = pd->callbacks[middle];
1469

1470
        cmp = p->priority - look->priority;
1471
        if      (cmp    == 0) return middle;
1472
        else if (cmp    >  0) start = middle + 1;
1473
        else if (middle >  0) last  = middle - 1;
1474
        else break;
1475
     }
1476
   while (start <= last);
1477
   return middle;
1478
}
1479

1480
static void
1481
_eo_callbacks_sorted_insert(Efl_Object_Data *pd, Eo_Callback_Description *cb)
1482
{
1483
   Eo_Callback_Description **itr;
1484
   unsigned int length, j;
1485
   Efl_Event_Callback_Frame *frame;
1486

1487
   // Do a dichotomic searh
1488
   j = _eo_callback_search_sorted_near(pd, cb);
1489
   // Adjust for both case of length == 0 and when priority is equal.
1490
   while ((j < pd->callbacks_count) &&
1491
          (pd->callbacks[j]->priority >= cb->priority)) j++;
1492

1493
   // Increase the callbacks storage by 16 entries at a time
1494
   if (_eo_nostep_alloc || (pd->callbacks_count & 0xF) == 0x0)
1495
     {
1496
        Eo_Callback_Description **tmp;
1497
        unsigned int new_len = (pd->callbacks_count | 0xF) + 1;
1498

1499
        if (_eo_nostep_alloc) new_len = pd->callbacks_count + 1;
1500

1501
        tmp = realloc(pd->callbacks,
1502
                      new_len * sizeof(Eo_Callback_Description *));
1503
        if (EINA_UNLIKELY(!tmp)) return;
1504
        pd->callbacks = tmp;
1505
     }
1506

1507
   // FIXME: Potential improvement, merge single callback description of the same priority
1508
   // into an array when possible
1509
   itr = pd->callbacks + j;
1510
   length = pd->callbacks_count - j;
1511
   if (length > 0) memmove(itr + 1, itr,
1512
                           length * sizeof(Eo_Callback_Description *));
1513
   *itr = cb;
1514

1515
   pd->callbacks_count++;
1516

1517
   // Update possible event emissions
1518
   for (frame = pd->event_frame; frame; frame = frame->next)
1519
     {
1520
        if ((itr - pd->callbacks) < (ptrdiff_t)frame->idx)
1521
          frame->inserted_before++;
1522
     }
1523
}
1524

1525
static unsigned short
1526
_efl_event_generation(Efl_Object_Data *pd)
1527
{
1528
   if (!pd->event_frame) return 0;
1529

1530
   return ((Efl_Event_Callback_Frame*)pd->event_frame)->generation;
1531
}
1532

1533
EOLIAN static Eina_Bool
1534
_efl_object_event_callback_priority_add(Eo *obj, Efl_Object_Data *pd,
1535
                                        const Efl_Event_Description *desc,
1536
                                        Efl_Callback_Priority priority,
1537
                                        Efl_Event_Cb func,
1538
                                        const void *user_data)
1539
{
1540
   const Efl_Callback_Array_Item_Full arr[] =
1541
     { {desc, priority, func, (void *)user_data}, {NULL, 0, NULL, NULL}};
1542
   Eo_Callback_Description *cb = _eo_callback_new();
1543
#ifdef EO_DEBUG
1544
   unsigned int idx, r = 0, entries = 0;
1545

1546
   for (idx = pd->callbacks_count ; idx > 0; idx--)
1547
     {
1548
        Eo_Callback_Description **cb;
1549

1550
        cb = pd->callbacks + idx - 1;
1551
        if (!(*cb)->func_array)
1552
          {
1553
             if (((*cb)->items.item.desc == desc) &&
1554
                 ((*cb)->items.item.func == func) &&
1555
                 ((*cb)->priority == priority) &&
1556
                 ((*cb)->generation == _efl_event_generation(pd)))
1557
               r++;
1558
          }
1559
        entries++;
1560
     }
1561
   if (r > 1) INF("Object '%s' got %i callback with event '%s' registered.",
1562
                  efl_debug_name_get(obj), r, desc->name);
1563
   if (entries > 10) INF("Object '%s' got %i callbacks.",
1564
                         efl_debug_name_get(obj), entries);
1565
#endif
1566

1567
   // very unlikely so improve l1 instr cache by using goto
1568
   if (EINA_UNLIKELY(!cb || !desc || !func)) goto err;
1569
   cb->items.item.desc = desc;
1570
   cb->items.item.func = func;
1571
   cb->func_data = (void *)user_data;
1572
   cb->priority = priority;
1573
   cb->generation = _efl_event_generation(pd);
1574
   if (cb->generation) pd->need_cleaning = EINA_TRUE;
1575

1576
   _eo_callbacks_sorted_insert(pd, cb);
1577
   _special_event_count_inc(obj, pd, &(cb->items.item));
1578

1579
   if (pd->event_cb_EFL_EVENT_CALLBACK_ADD)
1580
     efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)arr);
1581

1582
   return EINA_TRUE;
1583

1584
err: EINA_COLD
1585
   ERR("Tried adding callback with invalid values: cb: %p desc: %p func: %p", cb, desc, func);
1586
   _eo_callback_free(cb);
1587
   return EINA_FALSE;
1588
}
1589

1590
EO_API EFL_FUNC_BODYV(efl_event_callback_priority_add,
1591
                     Eina_Bool, 0, EFL_FUNC_CALL(desc, priority, cb, data),
1592
                     const Efl_Event_Description *desc,
1593
                     Efl_Callback_Priority priority,
1594
                     Efl_Event_Cb cb, const void *data);
1595

1596
static void
1597
_efl_object_event_callback_clean(Eo *obj, Efl_Object_Data *pd,
1598
                                 const Efl_Callback_Array_Item_Full *array,
1599
                                 Eo_Callback_Description **cb)
1600
{
1601
   (*cb)->delete_me = EINA_TRUE;
1602
   if (pd->event_frame)
1603
     pd->need_cleaning = EINA_TRUE;
1604
   else
1605
     _eo_callback_remove(obj, pd, cb);
1606
   if (pd->event_cb_EFL_EVENT_CALLBACK_DEL)
1607
     efl_event_callback_call(obj, EFL_EVENT_CALLBACK_DEL, (void *)array);
1608
}
1609

1610
EOLIAN static Eina_Bool
1611
_efl_object_event_callback_del(Eo *obj, Efl_Object_Data *pd,
1612
                               const Efl_Event_Description *desc,
1613
                               Efl_Event_Cb func,
1614
                               const void *user_data)
1615
{
1616
   Eo_Callback_Description **cb;
1617
   unsigned int i;
1618

1619
   for (cb = pd->callbacks, i = 0;
1620
        i < pd->callbacks_count;
1621
        cb++, i++)
1622
     {
1623
        if (!(*cb)->delete_me &&
1624
            ((*cb)->items.item.desc == desc) &&
1625
            ((*cb)->items.item.func == func) &&
1626
            ((*cb)->func_data == user_data))
1627
          {
1628
             const Efl_Callback_Array_Item_Full arr[] =
1629
               { {desc, (*cb)->priority, func, (*cb)->func_data}, {NULL, 0, NULL, NULL}};
1630

1631
             _efl_object_event_callback_clean(obj, pd, arr, cb);
1632
             return EINA_TRUE;
1633
          }
1634
     }
1635

1636
   DBG("Callback of object %p with function %p and data %p not found.", obj, func, user_data);
1637
   return EINA_FALSE;
1638
}
1639

1640
EO_API EFL_FUNC_BODYV(efl_event_callback_del,
1641
                     Eina_Bool, 0, EFL_FUNC_CALL(desc, func, user_data),
1642
                     const Efl_Event_Description *desc,
1643
                     Efl_Event_Cb func, const void *user_data);
1644

1645
EOLIAN static Eina_Bool
1646
_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Object_Data *pd,
1647
                                              const Efl_Callback_Array_Item *array,
1648
                                              Efl_Callback_Priority priority,
1649
                                              const void *user_data)
1650
{
1651
   Eo_Callback_Description *cb = _eo_callback_new();
1652
   const Efl_Callback_Array_Item *it;
1653
   unsigned int num, i;
1654
   Efl_Callback_Array_Item_Full *ev_array;
1655
#ifdef EO_DEBUG
1656
   const Efl_Callback_Array_Item *prev;
1657
   unsigned int idx, r = 0, entries = 0;
1658
#endif
1659

1660
   // very unlikely so improve l1 instr cache by using goto
1661
   if (!cb || !array) goto err;
1662
#ifdef EO_DEBUG
1663
   prev = array;
1664
   for (it = prev + 1; prev->func && it->func; it++, prev++)
1665
     {
1666
        if (efl_callbacks_cmp(prev, it) > 0)
1667
          {
1668
             ERR("Trying to insert a non sorted array callbacks (%p).", array);
1669
             _eo_callback_free(cb);
1670
             return EINA_FALSE;
1671
          }
1672
     }
1673
#endif
1674

1675
   cb->func_data = (void *) user_data;
1676
   cb->priority = priority;
1677
   cb->items.item_array = array;
1678
   cb->func_array = EINA_TRUE;
1679
   cb->generation = _efl_event_generation(pd);
1680
   if (!!cb->generation) pd->need_cleaning = EINA_TRUE;
1681

1682
#ifdef EO_DEBUG
1683
   for (idx = pd->callbacks_count ; idx > 0; idx--)
1684
     {
1685
        Eo_Callback_Description **cb;
1686

1687
        cb = pd->callbacks + idx - 1;
1688
        if ((*cb)->func_array)
1689
          {
1690
             if (((*cb)->items.item_array == array) &&
1691
                 ((*cb)->priority == priority) &&
1692
                 ((*cb)->generation == _efl_event_generation(pd)))
1693
               r++;
1694
          }
1695
        entries++;
1696
     }
1697
   if (r > 1)
1698
     {
1699
        Eina_Strbuf *buf = eina_strbuf_new();
1700
        Eina_Bool first = EINA_TRUE;
1701

1702
        for (it = array; it->func; it++)
1703
          {
1704
             if (first) eina_strbuf_append(buf, it->desc->name);
1705
             else eina_strbuf_append_printf(buf, ", %s", it->desc->name);
1706
             first = EINA_FALSE;
1707
          }
1708
        INF("Object '%s' got %i callback with events array %s registered.",
1709
            efl_debug_name_get(obj), r, eina_strbuf_string_get(buf));
1710
        eina_strbuf_free(buf);
1711
     }
1712
   if (entries > 10) INF("Object '%s' got %i callbacks.",
1713
                         efl_debug_name_get(obj), entries);
1714
#endif
1715

1716
   _eo_callbacks_sorted_insert(pd, cb);
1717
   for (it = cb->items.item_array; it->func; it++)
1718
     _special_event_count_inc(obj, pd, it);
1719

1720
   num = 0;
1721
   for (it = cb->items.item_array; it->func; it++) num++;
1722
   ev_array = alloca((num + 1) * sizeof(Efl_Callback_Array_Item_Full));
1723
   for (i = 0, it = cb->items.item_array; it->func; it++, i++)
1724
     {
1725
        ev_array[i].desc = cb->items.item_array[i].desc;
1726
        ev_array[i].priority = cb->priority;
1727
        ev_array[i].func = cb->items.item_array[i].func;
1728
        ev_array[i].user_data = cb->func_data;
1729
     }
1730
   ev_array[i].desc = NULL;
1731
   ev_array[i].priority = 0;
1732
   ev_array[i].func = NULL;
1733
   ev_array[i].user_data = NULL;
1734
   if (pd->event_cb_EFL_EVENT_CALLBACK_ADD)
1735
     efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, ev_array);
1736

1737
   return EINA_TRUE;
1738

1739
err:
1740
   ERR("Tried adding array of callbacks with invalid values: cb: %p array: %p.", cb, array);
1741
   _eo_callback_free(cb);
1742
   return EINA_FALSE;
1743
}
1744

1745
EO_API EFL_FUNC_BODYV(efl_event_callback_array_priority_add,
1746
                     Eina_Bool, 0, EFL_FUNC_CALL(array, priority, data),
1747
                     const Efl_Callback_Array_Item *array,
1748
                     Efl_Callback_Priority priority, const void *data);
1749

1750
EOLIAN static Eina_Bool
1751
_efl_object_event_callback_array_del(Eo *obj, Efl_Object_Data *pd,
1752
                                     const Efl_Callback_Array_Item *array,
1753
                                     const void *user_data)
1754
{
1755
   Eo_Callback_Description **cb;
1756
   unsigned int j;
1757

1758
   for (cb = pd->callbacks, j = 0;
1759
        j < pd->callbacks_count;
1760
        cb++, j++)
1761
     {
1762
        if (!(*cb)->delete_me &&
1763
            ((*cb)->items.item_array == array) &&
1764
            ((*cb)->func_data == user_data))
1765
          {
1766
             const Efl_Callback_Array_Item *it;
1767
             unsigned int num, i;
1768
             Efl_Callback_Array_Item_Full *ev_array;
1769

1770
             num = 0;
1771
             for (it = (*cb)->items.item_array; it->func; it++) num++;
1772
             ev_array = alloca((num + 1) * sizeof(Efl_Callback_Array_Item_Full));
1773
             for (i = 0, it = (*cb)->items.item_array; it->func; it++, i++)
1774
               {
1775
                  ev_array[i].desc = (*cb)->items.item_array[i].desc;
1776
                  ev_array[i].priority = (*cb)->priority;
1777
                  ev_array[i].func = (*cb)->items.item_array[i].func;
1778
                  ev_array[i].user_data = (*cb)->func_data;
1779
               }
1780
             ev_array[i].desc = NULL;
1781
             ev_array[i].priority = 0;
1782
             ev_array[i].func = NULL;
1783
             ev_array[i].user_data = NULL;
1784
             _efl_object_event_callback_clean(obj, pd, ev_array, cb);
1785
             return EINA_TRUE;
1786
          }
1787
     }
1788

1789
   DBG("Callback of object %p with function array %p and data %p not found.", obj, array, user_data);
1790
   return EINA_FALSE;
1791
}
1792

1793
EO_API EFL_FUNC_BODYV(efl_event_callback_array_del,
1794
                     Eina_Bool, 0, EFL_FUNC_CALL(array, user_data),
1795
                     const Efl_Callback_Array_Item *array,
1796
                     const void *user_data);
1797

1798
typedef struct _Efl_Future_Scheduler Efl_Future_Scheduler;
1799
typedef struct _Efl_Future_Scheduler_Entry Efl_Future_Scheduler_Entry;
1800

1801
struct _Efl_Future_Scheduler
1802
{
1803
   Eina_Future_Scheduler scheduler;
1804

1805
   const Efl_Callback_Array_Item *array;
1806
   const Eo *self;
1807

1808
   Eina_List *futures;
1809

1810
   Eina_Bool listener : 1;
1811
};
1812

1813
struct _Efl_Future_Scheduler_Entry
1814
{
1815
   Eina_Future_Schedule_Entry base;
1816
   Eina_Future_Scheduler_Cb cb;
1817
   Eina_Future *future;
1818
   Eina_Value value;
1819
};
1820

1821
static Eina_Trash *schedulers_trash = NULL;
1822
static unsigned char schedulers_count = 0;
1823

1824
static void
1825
_future_scheduler_cleanup(Efl_Object_Data *pd)
1826
{
1827
   if (eina_hash_population(pd->ext->schedulers)) return ;
1828

1829
   eina_hash_free(pd->ext->schedulers);
1830
   pd->ext->schedulers = NULL;
1831
   _efl_object_extension_noneed(pd);
1832
}
1833

1834
static void
1835
_futures_dispatch_cb(void *data, const Efl_Event *ev EINA_UNUSED)
1836
{
1837
   Efl_Future_Scheduler *sched = data;
1838
   Eina_List *entries = sched->futures;
1839
   Efl_Future_Scheduler_Entry *entry;
1840

1841
   sched->futures = NULL;
1842

1843
   efl_event_callback_array_del((Eo *) sched->self, sched->array, sched);
1844
   sched->listener = EINA_FALSE;
1845

1846
   // Now trigger callbacks
1847
   EINA_LIST_FREE(entries, entry)
1848
     {
1849
        entry->cb(entry->future, entry->value);
1850
        eina_mempool_free(_efl_future_scheduler_entry_mempool, entry);
1851
     }
1852
}
1853

1854
static void
1855
_futures_cancel_cb(void *data)
1856
{
1857
   Efl_Future_Scheduler *sched = data;
1858
   Eina_List *entries = sched->futures;
1859
   Efl_Future_Scheduler_Entry *entry;
1860

1861
   efl_event_callback_array_del((Eo *) sched->self, sched->array, sched);
1862
   sched->listener = EINA_FALSE;
1863
   sched->futures = NULL;
1864

1865
   EINA_LIST_FREE(entries, entry)
1866
     {
1867
        eina_future_cancel(entry->future);
1868
        eina_value_flush(&entry->value);
1869
        eina_mempool_free(_efl_future_scheduler_entry_mempool, entry);
1870
     }
1871

1872
   if (schedulers_count > 8)
1873
     {
1874
        free(sched);
1875
     }
1876
   else
1877
     {
1878
        eina_trash_push(&schedulers_trash, sched);
1879
        schedulers_count++;
1880
     }
1881
}
1882

1883
static Eina_Future_Schedule_Entry *
1884
_efl_event_future_scheduler(Eina_Future_Scheduler *s_sched,
1885
                            Eina_Future_Scheduler_Cb cb,
1886
                            Eina_Future *future,
1887
                            Eina_Value value)
1888
{
1889
   Efl_Future_Scheduler *sched = (Efl_Future_Scheduler *)s_sched;
1890
   Efl_Future_Scheduler_Entry *entry;
1891

1892
   entry = eina_mempool_malloc(_efl_future_scheduler_entry_mempool, sizeof(*entry));
1893
   EINA_SAFETY_ON_NULL_RETURN_VAL(entry, NULL);
1894

1895
   entry->base.scheduler = &sched->scheduler;
1896
   entry->cb = cb;
1897
   entry->future = future;
1898
   entry->value = value;
1899

1900
   if (!sched->listener)
1901
     {
1902
        efl_event_callback_array_add((Eo *) sched->self, sched->array, sched);
1903
        sched->listener = EINA_TRUE;
1904
     }
1905

1906
   sched->futures = eina_list_append(sched->futures, entry);
1907
   return &entry->base;
1908
}
1909

1910
static void
1911
_efl_event_future_recall(Eina_Future_Schedule_Entry *s_entry)
1912
{
1913
   Efl_Future_Scheduler_Entry *entry = (Efl_Future_Scheduler_Entry *)s_entry;
1914
   Efl_Future_Scheduler *sched;
1915
   Eina_List *lookup;
1916

1917
   sched = (Efl_Future_Scheduler *) entry->base.scheduler;
1918

1919
   lookup = eina_list_data_find_list(sched->futures, entry);
1920
   if (!lookup) return;
1921

1922
   sched->futures = eina_list_remove_list(sched->futures, lookup);
1923
   if (!sched->futures)
1924
     {
1925
        Efl_Object_Data *pd = efl_data_scope_get(sched->self, EFL_OBJECT_CLASS);
1926

1927
        _future_scheduler_cleanup(pd);
1928
     }
1929

1930
   eina_value_flush(&entry->value);
1931
   eina_mempool_free(_efl_future_scheduler_entry_mempool, entry);
1932
}
1933

1934
EOLIAN static Eina_Future_Scheduler *
1935
_efl_object_event_future_scheduler_get(const Eo *obj, Efl_Object_Data *pd, Efl_Callback_Array_Item *array)
1936
{
1937
   Efl_Object_Extension *ext;
1938
   Efl_Future_Scheduler *sched;
1939
   unsigned int i;
1940

1941
   if (!array) return NULL;
1942

1943
   ext = _efl_object_extension_need(pd);
1944
   EINA_SAFETY_ON_NULL_RETURN_VAL(ext, NULL);
1945

1946
   // First lookup for an existing scheduler that match the provided array
1947
   if (!ext->schedulers) ext->schedulers = eina_hash_pointer_new(_futures_cancel_cb);
1948
   sched = eina_hash_find(ext->schedulers, &array);
1949
   if (sched) return &sched->scheduler;
1950

1951
   // Define all the callback in the array to point to our internal callback,
1952
   // making the array ready to use.
1953
   for (i = 0; array[i].desc; i++)
1954
     array[i].func = _futures_dispatch_cb;
1955

1956
   if (schedulers_count)
1957
     {
1958
        // Take one out of the trash for faster cycling
1959
        sched = eina_trash_pop(&schedulers_trash);
1960
        schedulers_count--;
1961
     }
1962
   else
1963
     {
1964
        // Need to allocate a new scheduler as none are on standby.
1965
        sched = calloc(1, sizeof (Efl_Future_Scheduler));
1966
     }
1967
   sched->scheduler.schedule = _efl_event_future_scheduler;
1968
   sched->scheduler.recall = _efl_event_future_recall;
1969
   sched->array = array;
1970
   sched->self = obj;
1971

1972
   eina_hash_add(ext->schedulers, &array, sched);
1973

1974
   return &sched->scheduler;
1975
}
1976

1977
EO_API EFL_FUNC_BODYV_CONST(efl_event_future_scheduler_get,
1978
                           Eina_Future_Scheduler *, 0, EFL_FUNC_CALL(array),
1979
                           Efl_Callback_Array_Item *array);
1980

1981
EO_API unsigned int
1982
_efl_object_event_callback_count(const Eo *obj EINA_UNUSED,
1983
                                 Efl_Object_Data *pd,
1984
                                 const Efl_Event_Description *desc)
1985
{
1986
   unsigned int r = 0;
1987
   unsigned int idx;
1988

1989
   for (idx = pd->callbacks_count ; idx > 0; idx--)
1990
     {
1991
        Eo_Callback_Description **cb;
1992

1993
        cb = pd->callbacks + idx - 1;
1994

1995
        if ((*cb)->func_array)
1996
          {
1997
             const Efl_Callback_Array_Item *it;
1998

1999
             for (it = (*cb)->items.item_array; it->func; it++)
2000
               {
2001
                  if (it->desc > desc) break;
2002
                  if (it->desc == desc) r++;
2003
               }
2004
          }
2005
        else
2006
          {
2007
             if ((*cb)->items.item.desc == desc) r++;
2008
          }
2009
     }
2010
   return r;
2011
}
2012

2013
EO_API EFL_FUNC_BODYV_CONST(efl_event_callback_count,
2014
                           unsigned int, 0, EFL_FUNC_CALL(desc),
2015
                           const Efl_Event_Description *desc);
2016

2017
static Eina_Bool
2018
_cb_desc_match(const Efl_Event_Description *a, const Efl_Event_Description *b, Eina_Bool legacy_compare)
2019
{
2020
   /* If one is legacy and the other is not, strcmp. Else, pointer compare. */
2021
   if (!EINA_UNLIKELY(legacy_compare && (_legacy_event_desc_is(a) != _legacy_event_desc_is(b))))
2022
     return (a == b);
2023
   return !strcmp(a->name, b->name);
2024
}
2025

2026
#define EFL_OBJECT_EVENT_CALLBACK_BLOCK(Pd, Desc, Event, Need_Hash)     \
2027
  if (Desc == Event)                                                    \
2028
    {                                                                   \
2029
       if (!(Pd->event_cb_##Event)) return EINA_TRUE;                   \
2030
       Need_Hash = EINA_FALSE;                                          \
2031
    }                                                                   \
2032
2033
static inline Eina_Bool
2034
_event_callback_call(Eo *obj_id, Efl_Object_Data *pd,
2035
                     const Efl_Event_Description *desc,
2036
                     void *event_info,
2037
                     Eina_Bool legacy_compare)
2038
{
2039
   Eo_Callback_Description **cb;
2040
   Efl_Event_Callback_Frame *restart_lookup = NULL; //a pointer to a frame, which is high up the stack, which we use to restore
2041
   Efl_Event ev;
2042
   unsigned int idx;
2043
   Eina_Bool callback_already_stopped, ret;
2044
   Efl_Event_Callback_Frame frame = {
2045
      .desc = desc,
2046
      .next = NULL,
2047
      .idx = 0,
2048
      .inserted_before = 0,
2049
      .generation = 1,
2050
   };
2051
   Eina_Bool need_hash = EINA_TRUE;
2052

2053
   if (pd->callbacks_count == 0) return EINA_TRUE;
2054
   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_CALLBACK_ADD, need_hash)
2055
   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_CALLBACK_DEL, need_hash)
2056
   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_DEL, need_hash)
2057
   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_INVALIDATE, need_hash)
2058
   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_NOREF, need_hash)
2059
   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_DESTRUCT, need_hash)
2060

2061
   if (EINA_LIKELY(!legacy_compare && need_hash))
2062
     {
2063
        unsigned char event_hash;
2064

2065
        event_hash = _pointer_hash((uintptr_t) desc);
2066
        if (!(pd->callbacks_mask & (1ULL << event_hash)))
2067
          return EINA_TRUE;
2068
     }
2069

2070
   if (pd->event_frame)
2071
     frame.generation = ((Efl_Event_Callback_Frame*)pd->event_frame)->generation + 1;
2072

2073
   EVENT_STACK_PUSH(pd, &frame);
2074

2075
   callback_already_stopped = pd->callback_stopped;
2076
   pd->callback_stopped = EINA_FALSE;
2077
   ret = EINA_TRUE;
2078

2079
   ev.object = obj_id;
2080
   ev.desc = desc;
2081
   ev.info = event_info;
2082

2083
   // Handle event that require to restart where we were in the nested list walking
2084
   // relatively unlikely so improve l1 instr cache by using goto
2085
   if (desc->restart) goto restart;
2086
   else idx = pd->callbacks_count;
2087
restart_back:
2088

2089
   for (; idx > 0; idx--)
2090
     {
2091
        frame.idx = idx;
2092
        cb = pd->callbacks + idx - 1;
2093
        if (!(*cb)->delete_me)
2094
          {
2095
             if ((*cb)->generation >= frame.generation)
2096
               continue;
2097

2098
             if ((*cb)->func_array)
2099
               {
2100
                  const Efl_Callback_Array_Item *it;
2101

2102
                  for (it = (*cb)->items.item_array; it->func; it++)
2103
                    {
2104
                       // Array callbacks are sorted, break if we are getting to high.
2105
                       if (!legacy_compare &&
2106
                           ((const unsigned char *) desc < (const unsigned char *) it->desc))
2107
                         break;
2108
                       if (!_cb_desc_match(it->desc, desc, legacy_compare))
2109
                          continue;
2110
                       if (!it->desc->unfreezable &&
2111
                           (event_freeze_count || pd->event_freeze_count))
2112
                          continue;
2113

2114
                       it->func((void *) (*cb)->func_data, &ev);
2115
                       /* Abort callback calling if the func says so. */
2116
                       if (pd->callback_stopped)
2117
                         {
2118
                            ret = EINA_FALSE;
2119
                            goto end;
2120
                         }
2121
                    }
2122
               }
2123
             else
2124
               {
2125
                  if (!_cb_desc_match((*cb)->items.item.desc, desc, legacy_compare))
2126
                    continue;
2127
                  if (!(*cb)->items.item.desc->unfreezable &&
2128
                      (event_freeze_count || pd->event_freeze_count))
2129
                    continue;
2130

2131
                  (*cb)->items.item.func((void *) (*cb)->func_data, &ev);
2132
                  /* Abort callback calling if the func says so. */
2133
                  if (pd->callback_stopped)
2134
                    {
2135
                       ret = EINA_FALSE;
2136
                       goto end;
2137
                    }
2138
               }
2139
          }
2140
        /*
2141
         * copy back the idx that might have changed due to restarts, (theoretically only needed with restarts, condition made everything slower)
2142
         * additionally adjust to event subscriptions that have been added in a event callback
2143
         */
2144
        idx = frame.idx + frame.inserted_before;
2145
        frame.inserted_before = 0;
2146
     }
2147

2148
end:
2149
   // Handling restarting list walking complete exit.
2150
   // This must be 1, we copy back the frame idx at the end of the for loop.
2151
   // The next iteration then decrements the idx by 1 which results in the effective running idx of that frame beeing 0
2152
   if (restart_lookup) restart_lookup->idx = 1;
2153

2154
   EVENT_STACK_POP(pd);
2155

2156
   _eo_callbacks_clear(obj_id, pd);
2157

2158
   pd->callback_stopped = callback_already_stopped;
2159

2160
   return ret;
2161
restart:
2162
   // Search for the next frame that has the same event description
2163
   for (restart_lookup = frame.next; restart_lookup; restart_lookup = restart_lookup->next)
2164
     {
2165
        if (restart_lookup->desc == desc) break;
2166
     }
2167

2168
   // Ensure that the idx is the next from the previous run, minimum number 0
2169
   if (restart_lookup) {
2170
     idx = restart_lookup->idx - 1;
2171
   } else {
2172
     idx = 0;
2173
   }
2174
   // If this is 0, then we are restarting
2175
   if (!idx)
2176
     idx = pd->callbacks_count;
2177

2178
   goto restart_back;
2179
}
2180

2181
EOLIAN static Eina_Bool
2182
_efl_object_event_callback_call(Eo *obj_id, Efl_Object_Data *pd,
2183
            const Efl_Event_Description *desc,
2184
            void *event_info)
2185
{
2186
   return _event_callback_call(obj_id, pd, desc, event_info, EINA_FALSE);
2187
}
2188

2189
EO_API EFL_FUNC_BODYV(efl_event_callback_call,
2190
                     Eina_Bool, 0, EFL_FUNC_CALL(desc, event_info),
2191
                     const Efl_Event_Description *desc, void *event_info);
2192

2193
EOLIAN static Eina_Bool
2194
_efl_object_event_callback_legacy_call(Eo *obj_id, Efl_Object_Data *pd,
2195
            const Efl_Event_Description *desc,
2196
            void *event_info)
2197
{
2198
   return _event_callback_call(obj_id, pd, desc, event_info, EINA_TRUE);
2199
}
2200

2201
EO_API EFL_FUNC_BODYV(efl_event_callback_legacy_call,
2202
                     Eina_Bool, 0, EFL_FUNC_CALL(desc, event_info),
2203
                     const Efl_Event_Description *desc, void *event_info);
2204

2205
EOLIAN static void
2206
_efl_object_event_callback_stop(Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
2207
{
2208
   pd->callback_stopped = EINA_TRUE;
2209
}
2210

2211
static void
2212
_efl_event_forwarder_callback(void *data, const Efl_Event *event)
2213
{
2214
   Eo *new_obj = (Eo *) data;
2215
   Eina_Bool ret = EINA_FALSE;
2216

2217
   ret = efl_event_callback_call(new_obj, event->desc, event->info);
2218
   if (!ret)
2219
     {
2220
        efl_event_callback_stop(event->object);
2221
     }
2222
}
2223

2224
static void
2225
_forwarders_list_clean(void *data)
2226
{
2227
   Efl_Event_Forwarder *forwarder;
2228
   Eina_List *l = data;
2229

2230
   EINA_LIST_FREE(l, forwarder)
2231
     {
2232
        if (forwarder->source)
2233
          {
2234
             if (forwarder->inserted)
2235
               efl_event_callback_del(forwarder->source,
2236
                                      forwarder->desc,
2237
                                      _efl_event_forwarder_callback,
2238
                                      forwarder->new_obj);
2239
             efl_wref_del(forwarder->source, &forwarder->source);
2240
          }
2241
        free(forwarder);
2242
     }
2243
}
2244

2245
EOLIAN static void
2246
_efl_object_event_callback_forwarder_priority_add(Eo *obj, Efl_Object_Data *pd EINA_UNUSED,
2247
                                                  const Efl_Event_Description *desc,
2248
                                                  short priority,
2249
                                                  Eo *new_obj)
2250
{
2251
   EO_OBJ_POINTER_RETURN(new_obj, new_data);
2252
   EO_OBJ_DONE(new_obj);
2253
   Efl_Event_Forwarder *forwarder;
2254
   Efl_Object_Extension *ext;
2255
   Efl_Object_Data *dpd;
2256
   Eina_List *l;
2257

2258
   dpd = efl_data_scope_safe_get(new_obj, EFL_OBJECT_CLASS);
2259
   EINA_SAFETY_ON_NULL_RETURN(dpd);
2260

2261
   ext = _efl_object_extension_need(dpd);
2262
   EINA_SAFETY_ON_NULL_RETURN(ext);
2263

2264
   // Prevent double insertion for the same object source and event description
2265
   EINA_LIST_FOREACH(eina_hash_find(ext->forwarders, desc), l, forwarder)
2266
     {
2267
        if (forwarder->desc == desc &&
2268
            forwarder->new_obj == new_obj &&
2269
            forwarder->source == obj)
2270
          {
2271
             ERR("Forwarder added on '%s' for event '%s' toward '%s' has already been set.\n",
2272
                 efl_debug_name_get(obj), desc->name, efl_debug_name_get(new_obj));
2273
             return;
2274
          }
2275
     }
2276

2277
   forwarder = malloc(sizeof (Efl_Event_Forwarder));
2278
   EINA_SAFETY_ON_NULL_RETURN(forwarder);
2279
   forwarder->desc = desc;
2280
   forwarder->priority = priority;
2281
   forwarder->new_obj = new_obj;
2282
   efl_wref_add(obj, &forwarder->source);
2283

2284
   if (efl_event_callback_count(new_obj, desc) > 0)
2285
     {
2286
        efl_event_callback_priority_add(obj, desc, priority, _efl_event_forwarder_callback, new_obj);
2287
        forwarder->inserted = EINA_TRUE;
2288
     }
2289
   else
2290
     {
2291
        forwarder->inserted = EINA_FALSE;
2292
     }
2293

2294
   if (!ext->forwarders)
2295
     ext->forwarders = eina_hash_pointer_new(_forwarders_list_clean);
2296
   eina_hash_list_direct_append(ext->forwarders, forwarder->desc, forwarder);
2297
}
2298

2299
EOLIAN static void
2300
_efl_object_event_callback_forwarder_del(Eo *obj, Efl_Object_Data *pd EINA_UNUSED,
2301
                                         const Efl_Event_Description *desc,
2302
                                         Eo *new_obj)
2303
{
2304
   EO_OBJ_POINTER_RETURN(new_obj, new_data);
2305
   EO_OBJ_DONE(new_obj);
2306
   Efl_Event_Forwarder *forwarder;
2307
   Efl_Object_Extension *ext;
2308
   Efl_Object_Data *dpd;
2309
   Eina_List *l, *tofree = NULL;
2310

2311
   dpd = efl_data_scope_safe_get(new_obj, EFL_OBJECT_CLASS);
2312
   if (!dpd) return ;
2313

2314
   ext = dpd->ext;
2315
   if (!ext) return ;
2316

2317
   EINA_LIST_FOREACH(eina_hash_find(ext->forwarders, desc), l, forwarder)
2318
     {
2319
        // Remove dead source at the same time we remove any forwader
2320
        if (forwarder->source == obj || forwarder->source == NULL)
2321
          tofree = eina_list_append(tofree, forwarder);
2322
     }
2323

2324
   EINA_LIST_FREE(tofree, forwarder)
2325
     {
2326
        if (forwarder->source)
2327
          {
2328
             if (forwarder->inserted)
2329
               efl_event_callback_del(obj, desc, _efl_event_forwarder_callback, new_obj);
2330
             efl_wref_del(obj, &forwarder->source);
2331
          }
2332
        eina_hash_list_remove(ext->forwarders, desc, forwarder);
2333
        free(forwarder);
2334
     }
2335
}
2336

2337
EOLIAN static void
2338
_efl_object_event_freeze(Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
2339
{
2340
   pd->event_freeze_count++;
2341
}
2342

2343
EOLIAN static void
2344
_efl_object_event_thaw(Eo *obj, Efl_Object_Data *pd)
2345
{
2346
   if (pd->event_freeze_count > 0)
2347
     {
2348
        pd->event_freeze_count--;
2349
     }
2350
   else
2351
     {
2352
        ERR("Events for object %p have already been thawed.", obj);
2353
     }
2354
}
2355

2356
EOLIAN static int
2357
_efl_object_event_freeze_count_get(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
2358
{
2359
   return pd->event_freeze_count;
2360
}
2361

2362
EOLIAN static void
2363
_efl_object_event_global_freeze(void)
2364
{
2365
   event_freeze_count++;
2366
}
2367

2368
EOLIAN static void
2369
_efl_object_event_global_thaw(void)
2370
{
2371
   if (event_freeze_count > 0)
2372
     {
2373
        event_freeze_count--;
2374
     }
2375
   else
2376
     {
2377
        ERR("Global events have already been thawed.");
2378
     }
2379
}
2380

2381
EOLIAN static int
2382
_efl_object_event_global_freeze_count_get(void)
2383
{
2384
   return event_freeze_count;
2385
}
2386

2387
EOLIAN static Eina_Bool
2388
_efl_object_composite_attach(Eo *parent_id, Efl_Object_Data *pd EINA_UNUSED, Eo *comp_obj_id)
2389
{
2390
   Efl_Object_Optional *opt;
2391
   Eo *emb_obj_id = NULL;
2392

2393
   EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE);
2394
   EO_OBJ_POINTER_GOTO(parent_id, parent, err_parent);
2395

2396
   /* FIXME: composite should fail if domains are different */
2397

2398
   /* Don't composite if we already have a composite object of this type */
2399
     {
2400
        Eina_List *itr;
2401
        EINA_LIST_FOREACH(parent->opt->composite_objects, itr, emb_obj_id)
2402
          {
2403
             EO_OBJ_POINTER_GOTO(emb_obj_id, emb_obj, err_klass);
2404
             if (EINA_UNLIKELY(emb_obj->klass == comp_obj->klass)) goto err_klass;
2405
          }
2406
        emb_obj_id = NULL;
2407
     }
2408

2409
   Efl_Object_Data *comp_pd = efl_data_scope_get(comp_obj_id, EFL_OBJECT_CLASS);
2410

2411
   if (efl_composite_part_is(comp_obj_id))
2412
     efl_composite_detach(comp_pd->ext->composite_parent, comp_obj_id);
2413

2414
   /* Set the parent comp on the child. */
2415
   _efl_object_extension_need(comp_pd);
2416
   comp_pd->ext->composite_parent = parent_id;
2417

2418
   opt = EO_OPTIONAL_COW_WRITE(parent);
2419
   opt->composite_objects = eina_list_prepend(opt->composite_objects, comp_obj_id);
2420
   EO_OPTIONAL_COW_END(opt, parent);
2421

2422
   if (emb_obj_id) EO_OBJ_DONE(emb_obj_id);
2423
   EO_OBJ_DONE(parent_id);
2424
   EO_OBJ_DONE(comp_obj_id);
2425
   return EINA_TRUE;
2426

2427
err_klass:
2428
   if (emb_obj_id) EO_OBJ_DONE(emb_obj_id);
2429
   EO_OBJ_DONE(parent_id);
2430
err_parent:
2431
   EO_OBJ_DONE(comp_obj_id);
2432
   return EINA_FALSE;
2433
}
2434

2435
EOLIAN static Eina_Bool
2436
_efl_object_composite_detach(Eo *parent_id, Efl_Object_Data *pd EINA_UNUSED, Eo *comp_obj_id)
2437
{
2438
   Efl_Object_Optional *opt;
2439

2440
   EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE);
2441
   EO_OBJ_POINTER_GOTO(parent_id, parent, err_parent);
2442

2443
   // unlikely so improve l1 instr cache by using goto
2444
   if (!efl_composite_part_is(comp_obj_id)) goto err_part;
2445

2446
   opt = EO_OPTIONAL_COW_WRITE(parent);
2447
   opt->composite_objects = eina_list_remove(opt->composite_objects, comp_obj_id);
2448
   EO_OPTIONAL_COW_END(opt, parent);
2449

2450
   /* Clear the comp parent on the child. */
2451
     {
2452
        Efl_Object_Data *comp_pd = efl_data_scope_get(comp_obj_id, EFL_OBJECT_CLASS);
2453
        comp_pd->ext->composite_parent = NULL;
2454
        _efl_object_extension_noneed(comp_pd);
2455
     }
2456

2457
   EO_OBJ_DONE(parent_id);
2458
   EO_OBJ_DONE(comp_obj_id);
2459
   return EINA_TRUE;
2460

2461
err_part:
2462
   EO_OBJ_DONE(parent_id);
2463
err_parent:
2464
   EO_OBJ_DONE(comp_obj_id);
2465
   return EINA_FALSE;
2466
}
2467

2468
EOLIAN static Eina_Bool
2469
_efl_object_composite_part_is(Eo *comp_obj_id EINA_UNUSED, Efl_Object_Data *pd)
2470
{
2471
   return pd->ext && pd->ext->composite_parent;
2472
}
2473

2474
/* Eo_Dbg */
2475
EO_API void
2476
efl_dbg_info_free(Efl_Dbg_Info *info)
2477
{
2478
   eina_value_flush(&(info->value));
2479
   eina_freeq_ptr_main_add(info, free, sizeof(*info));
2480
}
2481

2482
static Eina_Bool
2483
_eo_dbg_info_setup(const Eina_Value_Type *type, void *mem)
2484
{
2485
   memset(mem, 0, type->value_size);
2486
   return EINA_TRUE;
2487
}
2488

2489
static Eina_Bool
2490
_eo_dbg_info_flush(const Eina_Value_Type *type EINA_UNUSED, void *_mem)
2491
{
2492
   Efl_Dbg_Info *mem = *(Efl_Dbg_Info **) _mem;
2493
   eina_stringshare_del(mem->name);
2494
   eina_value_flush(&(mem->value));
2495
   eina_freeq_ptr_main_add(mem, free, sizeof(*mem));
2496
   return EINA_TRUE;
2497
}
2498

2499
static Eina_Bool
2500
_eo_dbg_info_copy(const Eina_Value_Type *type EINA_UNUSED, const void *_src, void *_dst)
2501
{
2502
   const Efl_Dbg_Info **src = (const Efl_Dbg_Info **) _src;
2503
   Efl_Dbg_Info **dst = _dst;
2504

2505
   *dst = calloc(1, sizeof(Efl_Dbg_Info));
2506
   if (!*dst) return EINA_FALSE;
2507
   (*dst)->name = eina_stringshare_ref((*src)->name);
2508
   eina_value_copy(&((*src)->value), &((*dst)->value));
2509
   return EINA_TRUE;
2510
}
2511

2512
static Eina_Bool
2513
_eo_dbg_info_convert_to(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert, const void *type_mem, void *convert_mem)
2514
{
2515
   /* FIXME: For the meanwhile, just use the inner type for the value. */
2516
   const Efl_Dbg_Info **src = (const Efl_Dbg_Info **) type_mem;
2517
   if (convert == EINA_VALUE_TYPE_STRINGSHARE ||
2518
       convert == EINA_VALUE_TYPE_STRING)
2519
     {
2520
        Eina_Bool ret;
2521
        const char *other_mem;
2522
        char *inner_val = eina_value_to_string(&(*src)->value);
2523
        other_mem = inner_val;
2524
        ret = eina_value_type_pset(convert, convert_mem, &other_mem);
2525
        eina_freeq_ptr_main_add(inner_val, free, 0);
2526
        return ret;
2527
     }
2528

2529
   eina_error_set(EINA_ERROR_VALUE_FAILED);
2530
   return EINA_FALSE;
2531
}
2532

2533
static Eina_Bool
2534
_eo_dbg_info_pset(const Eina_Value_Type *type EINA_UNUSED, void *_mem, const void *_ptr)
2535
{
2536
   Efl_Dbg_Info **mem = _mem;
2537
   if (*mem) free(*mem);
2538
   *mem = (void *) _ptr;
2539
   return EINA_TRUE;
2540
}
2541

2542
static Eina_Bool
2543
_eo_dbg_info_pget(const Eina_Value_Type *type EINA_UNUSED, const void *_mem, void *_ptr)
2544
{
2545
   Efl_Dbg_Info **ptr = _ptr;
2546
   *ptr = (void *) _mem;
2547
   return EINA_TRUE;
2548
}
2549

2550
static const Eina_Value_Type _EFL_DBG_INFO_TYPE = {
2551
   EINA_VALUE_TYPE_VERSION,
2552
   sizeof(Efl_Dbg_Info *),
2553
   "Efl_Dbg_Info_Ptr",
2554
   _eo_dbg_info_setup,
2555
   _eo_dbg_info_flush,
2556
   _eo_dbg_info_copy,
2557
   NULL,
2558
   _eo_dbg_info_convert_to,
2559
   NULL,
2560
   NULL,
2561
   _eo_dbg_info_pset,
2562
   _eo_dbg_info_pget
2563
};
2564

2565
EO_API const Eina_Value_Type *EFL_DBG_INFO_TYPE = &_EFL_DBG_INFO_TYPE;
2566

2567

2568
/* EOF event callbacks */
2569

2570
/* EFL_OBJECT_CLASS stuff */
2571
#define MY_CLASS EFL_OBJECT_CLASS
2572

2573
static Eina_Value
2574
_efl_future_cb(void *data, const Eina_Value value, const Eina_Future *dead_future)
2575
{
2576
   Efl_Future_Pending *pending = data;
2577
   Eina_Value ret = value;
2578
   const Eo *o;
2579
   Efl_Object_Data *pd;
2580

2581
   EINA_SAFETY_ON_NULL_GOTO(pending, err);
2582
   o = pending->o;
2583
   pd = efl_data_scope_get(o, EFL_OBJECT_CLASS);
2584
   EINA_SAFETY_ON_NULL_GOTO(pd, err);
2585

2586
   pd->pending_futures = eina_inlist_remove(pd->pending_futures,
2587
                                            EINA_INLIST_GET(pending));
2588
   efl_ref(o);
2589
   EASY_FUTURE_DISPATCH(ret, value, dead_future, &pending->desc, (void*) o, (void*) pending->desc.data);
2590
   efl_unref(o);
2591
   _efl_pending_future_free(pending);
2592

2593
   return ret;
2594

2595
 err:
2596
   eina_value_setup(&ret, EINA_VALUE_TYPE_ERROR);
2597
   eina_value_set(&ret, ENOMEM);
2598
   return ret;
2599
}
2600

2601
EO_API Eina_Future_Desc
2602
efl_future_cb_from_desc(const Eo *o, const Efl_Future_Cb_Desc desc)
2603
{
2604
   Efl_Future_Pending *pending = NULL;
2605
   Eina_Future **storage = NULL;
2606
   Efl_Object_Data *pd;
2607
   Eina_Bool invalidate;
2608

2609
   EINA_SAFETY_ON_NULL_GOTO(o, end);
2610
   pd = efl_data_scope_get(o, EFL_OBJECT_CLASS);
2611
   EINA_SAFETY_ON_NULL_GOTO(pd, end);
2612
   EO_OBJ_POINTER_GOTO(o, eo_obj, end);
2613
   invalidate = eo_obj->invalidate;
2614
   EO_OBJ_DONE(o);
2615
   EINA_SAFETY_ON_TRUE_GOTO(invalidate, end);
2616
   pending = _efl_pending_future_new();
2617
   EINA_SAFETY_ON_NULL_GOTO(pending, end);
2618
   memcpy(&pending->desc, &desc, sizeof(Efl_Future_Cb_Desc));
2619
   pending->o = o;
2620
   pending->future = NULL;
2621
   if (!pending->desc.storage) pending->desc.storage = &pending->future;
2622
   pd->pending_futures = eina_inlist_append(pd->pending_futures,
2623
                                            EINA_INLIST_GET(pending));
2624
   storage = pending->desc.storage;
2625
 end:
2626
   return (Eina_Future_Desc){ .cb = _efl_future_cb, .data = pending, .storage = storage };
2627
}
2628

2629
EO_API Eina_Future *
2630
efl_future_chain_array(Eo *obj,
2631
                       Eina_Future *prev,
2632
                       const Efl_Future_Cb_Desc descs[])
2633
{
2634
   ssize_t i = -1;
2635
   Eina_Future *f = prev;
2636

2637
   for (i = 0; descs[i].success || descs[i].error || descs[i].free || descs[i].success_type; i++)
2638
     {
2639
        Eina_Future_Desc eina_desc = efl_future_cb_from_desc(obj, descs[i]);
2640
        f = eina_future_then_from_desc(f, eina_desc);
2641
        EINA_SAFETY_ON_NULL_GOTO(f, err);
2642
     }
2643

2644
   return f;
2645

2646
 err:
2647
   /*
2648
     There's no need to cancel the futures, since eina_future_then_from_desc()
2649
     will cancel the whole chain in case of failure.
2650
     All we need to do is to free the remaining descs
2651
   */
2652
   for (i = i + 1; descs[i].error || descs[i].free; i++)
2653
     {
2654
        if (descs[i].error)
2655
          {
2656
             Eina_Value r = descs[i].error(obj, (void*) descs[i].data, ENOMEM);
2657
             eina_value_flush(&r);
2658
          }
2659
        if (descs[i].free) descs[i].free(obj, (void*) descs[i].data, NULL);
2660
     }
2661
   return NULL;
2662
}
2663

2664
EOLIAN static Eo *
2665
_efl_object_constructor(Eo *obj, Efl_Object_Data *pd EINA_UNUSED)
2666
{
2667
   DBG("%p - %s.", obj, efl_class_name_get(obj));
2668

2669
   _eo_condtor_done(obj);
2670

2671
   return obj;
2672
}
2673

2674
EOLIAN static void
2675
_efl_object_destructor(Eo *obj, Efl_Object_Data *pd)
2676
{
2677
   _Eo_Object *obj_child;
2678
   Eina_Inlist *l;
2679
   Efl_Object_Extension *ext;
2680
   _Eo_Object *obj_data2 = NULL;
2681

2682
   DBG("%p - %s.", obj, efl_class_name_get(obj));
2683

2684
   // special removal - remove from children list by hand after getting
2685
   // child handle in case unparent method is overridden and does
2686
   // extra things like removes other children too later on in the list
2687
   // this is a goto because more often than not objects do not have children
2688
   // so it's unlikely they will need the child cleanup code to so to have
2689
   // better l1 cache instruction coherency, move this to the end
2690
   if (pd->children) goto children;
2691
children_back:
2692

2693
   // If we are a composite object, detach children. it is quite unlikely
2694
   // we are a composite object, so put the core of this handling
2695
   // at the end out of l1 cache prefetch
2696
     {
2697
        EO_OBJ_POINTER_RETURN(obj, obj_data);
2698
        obj_data2 = obj_data;
2699
        if (obj_data->opt->composite_objects) goto composite_obj;
2700
composite_obj_back:
2701
        EO_OBJ_DONE(obj);
2702
     }
2703

2704
   if (pd->ext && pd->ext->composite_parent)
2705
     efl_composite_detach(pd->ext->composite_parent, obj);
2706

2707
   // parent still being here is unlikely, so move error handling out of the
2708
   // code execution path
2709
   if (pd->parent) goto err_parent;
2710
err_parent_back:
2711

2712
   // this isn't 100% correct, as the object is still "slightly" alive at this
2713
   // point (so efl_destructed_is() returns false), but triggering the
2714
   // "destruct" event here is the simplest, safest solution.
2715
   if (EINA_UNLIKELY(pd->event_cb_EFL_EVENT_DESTRUCT))
2716
     _event_callback_call(obj, pd, EFL_EVENT_DESTRUCT, NULL, EINA_FALSE);
2717

2718
   // remove generic data after this final event, in case they are used in a cb
2719
   _eo_generic_data_del_all(obj, pd);
2720
   _eo_callback_remove_all(pd);
2721

2722
   _wref_destruct(pd);
2723

2724
   ext = pd->ext;
2725
   // it is rather likely we dont have any extension section for most objects
2726
   // so return immediately here to avoid pulling in more instructions to
2727
   // the 1l cache if we can
2728
   if (!ext)
2729
     {
2730
        _eo_condtor_done(obj);
2731
        return;
2732
     }
2733
   eina_stringshare_del(ext->name);
2734
   ext->name = NULL;
2735
   eina_stringshare_del(ext->comment);
2736
   ext->comment = NULL;
2737
   _efl_object_extension_noneed(pd);
2738
   _eo_condtor_done(obj);
2739
   return;
2740

2741
children:
2742
   ERR("Object %p of type '%s' is still holding child at time of destruction.\n",
2743
       obj, efl_class_name_get(obj));
2744
   EINA_INLIST_FOREACH_SAFE(pd->children, l, obj_child)
2745
     {
2746
        Eo *child;
2747

2748
        child = _eo_obj_id_get(obj_child);
2749
        efl_parent_set(child, NULL);
2750
     }
2751
   goto children_back;
2752

2753
composite_obj:
2754
     {
2755
        Eina_List *itr, *next;
2756
        Eo *emb_obj_id;
2757

2758
        EINA_LIST_FOREACH_SAFE(obj_data2->opt->composite_objects, itr, next, emb_obj_id)
2759
          {
2760
             efl_composite_detach(obj, emb_obj_id);
2761
          }
2762
     }
2763
   goto composite_obj_back;
2764

2765
err_parent:
2766
   if (EINA_LIKELY(!pd->allow_parent_unref))
2767
     ERR("Object '%p' of type '%s' still has a parent at the time of destruction.", obj, efl_class_name_get(obj));
2768
   efl_parent_set(obj, NULL);
2769
   goto err_parent_back;
2770
}
2771

2772
EOLIAN static void
2773
_efl_object_allow_parent_unref_set(Eo *obj_id, Efl_Object_Data *pd, Eina_Bool allow)
2774
{
2775
   EO_OBJ_POINTER_RETURN(obj_id, obj);
2776
   obj->allow_parent_unref = !!allow;
2777
   pd->allow_parent_unref = !!allow;
2778
   EO_OBJ_DONE(obj_id);
2779
}
2780

2781
EOLIAN static Eina_Bool
2782
_efl_object_allow_parent_unref_get(const Eo *obj_id EINA_UNUSED, Efl_Object_Data *pd)
2783
{
2784
   return pd->allow_parent_unref;
2785
}
2786

2787
EO_API void
2788
___efl_auto_unref_set(Eo *obj_id, Eina_Bool enable)
2789
{
2790
   // Write-only property
2791
   EO_OBJ_POINTER_RETURN(obj_id, obj);
2792
   obj->auto_unref = enable ? 1 : 0;
2793
   EO_OBJ_DONE(obj_id);
2794
}
2795

2796
EOLIAN static Eo *
2797
_efl_object_finalize(Eo *obj, Efl_Object_Data *pd EINA_UNUSED)
2798
{
2799
   return obj;
2800
}
2801

2802
EOLIAN static void
2803
_efl_object_class_constructor(Efl_Class *klass EINA_UNUSED)
2804
{
2805
   event_freeze_count = 0;
2806
   _legacy_events_hash = eina_hash_stringshared_new(_legacy_events_hash_free_cb);
2807

2808
   _eo_callback_mempool =
2809
      eina_mempool_add("chained_mempool", NULL, NULL,
2810
                       sizeof(Eo_Callback_Description), 256);
2811

2812
   _efl_pending_future_mempool =
2813
      eina_mempool_add("chained_mempool", NULL, NULL,
2814
                       sizeof(Efl_Future_Pending), 256);
2815

2816
   _efl_future_scheduler_entry_mempool =
2817
     eina_mempool_add("chained_mempool", NULL, NULL,
2818
                      sizeof(Efl_Future_Scheduler_Entry), 256);
2819

2820
   _eo_nostep_alloc = !!getenv("EO_NOSTEP_ALLOC");
2821
}
2822

2823
EOLIAN static void
2824
_efl_object_class_destructor(Efl_Class *klass EINA_UNUSED)
2825
{
2826
   eina_mempool_del(_efl_future_scheduler_entry_mempool);
2827
   eina_mempool_del(_efl_pending_future_mempool);
2828
   eina_mempool_del(_eo_callback_mempool);
2829
   eina_hash_free(_legacy_events_hash);
2830
}
2831

2832
#define EFL_OBJECT_EXTRA_OPS \
2833
   EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_object_event_callback_priority_add), \
2834
   EFL_OBJECT_OP_FUNC(efl_event_callback_del, _efl_object_event_callback_del), \
2835
   EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_object_event_callback_array_priority_add), \
2836
   EFL_OBJECT_OP_FUNC(efl_event_callback_array_del, _efl_object_event_callback_array_del), \
2837
   EFL_OBJECT_OP_FUNC(efl_event_callback_call, _efl_object_event_callback_call), \
2838
   EFL_OBJECT_OP_FUNC(efl_event_callback_legacy_call, _efl_object_event_callback_legacy_call), \
2839
   EFL_OBJECT_OP_FUNC(efl_event_future_scheduler_get, _efl_object_event_future_scheduler_get), \
2840
   EFL_OBJECT_OP_FUNC(efl_event_callback_count, _efl_object_event_callback_count), \
2841
   EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _efl_object_dbg_info_get), \
2842
   EFL_OBJECT_OP_FUNC(efl_wref_add, _efl_object_wref_add), \
2843
   EFL_OBJECT_OP_FUNC(efl_wref_del, _efl_object_wref_del), \
2844
   EFL_OBJECT_OP_FUNC(efl_key_data_set, _efl_object_key_data_set), \
2845
   EFL_OBJECT_OP_FUNC(efl_key_data_get, _efl_object_key_data_get), \
2846
   EFL_OBJECT_OP_FUNC(efl_key_ref_set, _efl_object_key_ref_set), \
2847
   EFL_OBJECT_OP_FUNC(efl_key_ref_get, _efl_object_key_ref_get), \
2848
   EFL_OBJECT_OP_FUNC(efl_key_wref_set, _efl_object_key_wref_set), \
2849
   EFL_OBJECT_OP_FUNC(efl_key_wref_get, _efl_object_key_wref_get), \
2850
   EFL_OBJECT_OP_FUNC(efl_key_value_set, _efl_object_key_value_set), \
2851
   EFL_OBJECT_OP_FUNC(efl_key_value_get, _efl_object_key_value_get) \
2852
2853
#include "efl_object.eo.c"
2854

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.