6128422f30e14096dd2240183ddcd8af53ee1f5b
[framework/uifw/edje.git] / src / lib / edje_program.c
1 #include "edje_private.h"
2
3 static void _edje_emit_cb(Edje *ed, const char *sig, const char *src, Edje_Message_Signal_Data *data, Eina_Bool prop);
4 static void _edje_param_copy(Edje_Real_Part *src_part, const char *src_param, Edje_Real_Part *dst_part, const char *dst_param);
5 static void _edje_param_set(Edje_Real_Part *part, const char *param, const char *value);
6
7 int             _edje_anim_count = 0;
8 Ecore_Animator *_edje_timer = NULL;
9 Eina_List      *_edje_animators = NULL;
10
11
12 /*============================================================================*
13  *                                   API                                      *
14  *============================================================================*/
15
16 EAPI void
17 edje_frametime_set(double t)
18 {
19    ecore_animator_frametime_set(t);
20 }
21
22 EAPI double
23 edje_frametime_get(void)
24 {
25    return ecore_animator_frametime_get();
26 }
27
28 void
29 edje_object_propagate_callback_add(Evas_Object *obj, void (*func) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
30 {
31    Edje *ed;
32    Edje_Signal_Callback *escb;
33
34    ed = _edje_fetch(obj);
35    if (!ed) return;
36    if (ed->delete_me) return;
37    escb = calloc(1, sizeof(Edje_Signal_Callback));
38    escb->propagate = EINA_TRUE;
39    escb->signal = eina_stringshare_add("*");
40    escb->source = eina_stringshare_add("*");
41    escb->func = func;
42    escb->data = data;
43    ed->callbacks = eina_list_append(ed->callbacks, escb);
44    if (ed->walking_callbacks)
45      {
46         escb->just_added = 1;
47         ed->just_added_callbacks = EINA_TRUE;
48      }
49    else
50      _edje_callbacks_patterns_clean(ed);
51 }
52
53 EAPI void
54 edje_object_signal_callback_add(Evas_Object *obj, const char *emission, const char *source, void (*func) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
55 {
56    Edje *ed;
57    Edje_Signal_Callback *escb;
58
59    if ((!emission) || (!source) || (!func)) return;
60    ed = _edje_fetch(obj);
61    if (!ed) return;
62    if (ed->delete_me) return;
63    escb = calloc(1, sizeof(Edje_Signal_Callback));
64    if (emission[0])
65      escb->signal = eina_stringshare_add(emission);
66    if (source[0])
67      escb->source = eina_stringshare_add(source);
68    escb->func = func;
69    escb->data = data;
70    ed->callbacks = eina_list_append(ed->callbacks, escb);
71    if (ed->walking_callbacks)
72      {
73         escb->just_added = 1;
74         ed->just_added_callbacks = EINA_TRUE;
75      }
76    else
77      _edje_callbacks_patterns_clean(ed);
78 }
79
80 EAPI void *
81 edje_object_signal_callback_del(Evas_Object *obj, const char *emission, const char *source, void (*func) (void *data, Evas_Object *o, const char *emission, const char *source))
82 {
83    Edje *ed;
84    Eina_List *l;
85    Edje_Signal_Callback *escb;
86
87    if ((!emission) || (!source) || (!func)) return NULL;
88    ed = _edje_fetch(obj);
89    if (!ed) return NULL;
90    if (ed->delete_me) return NULL;
91    EINA_LIST_FOREACH(ed->callbacks, l, escb)
92      {
93         if ((escb->func == func) &&
94             ((!escb->signal && !emission[0]) ||
95              (escb->signal && !strcmp(escb->signal, emission))) &&
96             ((!escb->source && !source[0]) ||
97              (escb->source && !strcmp(escb->source, source))))
98           {
99              void *data;
100
101              data = escb->data;
102              if (ed->walking_callbacks)
103                {
104                   escb->delete_me = EINA_TRUE;
105                   ed->delete_callbacks = EINA_TRUE;
106                }
107              else
108                {
109                   _edje_callbacks_patterns_clean(ed);
110
111                   ed->callbacks = eina_list_remove_list(ed->callbacks, l);
112                   if (escb->signal) eina_stringshare_del(escb->signal);
113                   if (escb->source) eina_stringshare_del(escb->source);
114                   free(escb);
115                }
116              return data;
117           }
118      }
119    return NULL;
120 }
121
122 EAPI void *
123 edje_object_signal_callback_del_full(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func, void *data)
124 {
125    Edje *ed;
126    Eina_List *l;
127    Edje_Signal_Callback *escb;
128
129    if ((!emission) || (!source) || (!func)) return NULL;
130    ed = _edje_fetch(obj);
131    if (!ed) return NULL;
132    if (ed->delete_me) return NULL;
133    EINA_LIST_FOREACH(ed->callbacks, l, escb)
134      {
135         if ((escb->func == func) && (escb->data == data) &&
136             ((!escb->signal && !emission[0]) ||
137              (escb->signal && !strcmp(escb->signal, emission))) &&
138             ((!escb->source && !source[0]) ||
139              (escb->source && !strcmp(escb->source, source))))
140           {
141              void *data2;
142
143              data2 = escb->data;
144              if (ed->walking_callbacks)
145                {
146                   escb->delete_me = EINA_TRUE;
147                   ed->delete_callbacks = EINA_TRUE;
148                }
149              else
150                {
151                   _edje_callbacks_patterns_clean(ed);
152
153                   ed->callbacks = eina_list_remove_list(ed->callbacks, l);
154                   if (escb->signal) eina_stringshare_del(escb->signal);
155                   if (escb->source) eina_stringshare_del(escb->source);
156                   free(escb);
157                }
158              return data2;
159           }
160      }
161    return NULL;
162 }
163
164 EAPI void
165 edje_object_signal_emit(Evas_Object *obj, const char *emission, const char *source)
166 {
167    Edje *ed;
168
169    if ((!emission) || (!source)) return;
170    ed = _edje_fetch(obj);
171    if (!ed) return;
172    if (ed->delete_me) return;
173    _edje_emit(ed, (char *)emission, (char *)source);
174 }
175
176 /* FIXDOC: Verify/Expand */
177 EAPI void
178 edje_object_play_set(Evas_Object *obj, Eina_Bool play)
179 {
180    Edje *ed;
181    double t;
182    Eina_List *l;
183    Edje_Running_Program *runp;
184    unsigned int i;
185
186    ed = _edje_fetch(obj);
187    if (!ed) return;
188    if (ed->delete_me) return;
189    if (play)
190      {
191         if (!ed->paused) return;
192         ed->paused = EINA_FALSE;
193         t = ecore_time_get() - ed->paused_at;
194         EINA_LIST_FOREACH(ed->actions, l, runp)
195           runp->start_time += t;
196      }
197    else
198      {
199         if (ed->paused) return;
200         ed->paused = EINA_TRUE;
201         ed->paused_at = ecore_time_get();
202      }
203
204    for (i = 0; i < ed->table_parts_size; i++)
205      {
206         Edje_Real_Part *rp;
207         rp = ed->table_parts[i];
208         if ((rp->part->type == EDJE_PART_TYPE_GROUP) && 
209             ((rp->type == EDJE_RP_TYPE_SWALLOW) &&
210                 (rp->typedata.swallow)) &&
211             (rp->typedata.swallow->swallowed_object))
212           edje_object_play_set(rp->typedata.swallow->swallowed_object, play);
213      }
214 }
215
216 EAPI Eina_Bool
217 edje_object_play_get(const Evas_Object *obj)
218 {
219    Edje *ed;
220
221    ed = _edje_fetch(obj);
222    if (!ed) return EINA_FALSE;
223    if (ed->delete_me) return EINA_FALSE;
224    if (ed->paused) return EINA_FALSE;
225    return EINA_TRUE;
226 }
227
228 /* FIXDOC: Verify/Expand */
229 EAPI void
230 edje_object_animation_set(Evas_Object *obj, Eina_Bool on)
231 {
232    Edje *ed;
233    Eina_List *l;
234    unsigned int i;
235
236    ed = _edje_fetch(obj);
237    if (!ed) return;
238    if (ed->delete_me) return;
239    _edje_block(ed);
240    ed->no_anim = !on;
241    _edje_freeze(ed);
242    if (!on)
243      {
244         Eina_List *newl = NULL;
245         const void *data;
246
247         EINA_LIST_FOREACH(ed->actions, l, data)
248           newl = eina_list_append(newl, data);
249         while (newl)
250           {
251              Edje_Running_Program *runp;
252
253              runp = eina_list_data_get(newl);
254              newl = eina_list_remove(newl, eina_list_data_get(newl));
255              _edje_program_run_iterate(runp, runp->start_time + TO_DOUBLE(runp->program->tween.time));
256              if (_edje_block_break(ed))
257                {
258                   eina_list_free(newl);
259                   goto break_prog;
260                }
261           }
262      }
263    else
264      {
265         _edje_emit(ed, "load", NULL);
266         if (evas_object_visible_get(obj))
267           {
268              evas_object_hide(obj);
269              evas_object_show(obj);
270           }
271      }
272    break_prog:
273
274    for (i = 0; i < ed->table_parts_size; i++)
275      {
276         Edje_Real_Part *rp;
277         rp = ed->table_parts[i];
278         if ((rp->part->type == EDJE_PART_TYPE_GROUP) && 
279             ((rp->type == EDJE_RP_TYPE_SWALLOW) &&
280                 (rp->typedata.swallow)) &&
281             (rp->typedata.swallow->swallowed_object))
282           edje_object_animation_set(rp->typedata.swallow->swallowed_object, on);
283      }
284
285    _edje_thaw(ed);
286    _edje_unblock(ed);
287 }
288
289
290 EAPI Eina_Bool
291 edje_object_animation_get(const Evas_Object *obj)
292 {
293    Edje *ed;
294
295    ed = _edje_fetch(obj);
296    if (!ed) return EINA_FALSE;
297    if (ed->delete_me) return EINA_FALSE;
298    if (ed->no_anim) return EINA_FALSE;
299    return EINA_TRUE;
300 }
301
302 /* Private Routines */
303
304 Eina_Bool
305 _edje_program_run_iterate(Edje_Running_Program *runp, double tim)
306 {
307    FLOAT_T t, total;
308    Eina_List *l;
309    Edje *ed;
310    Edje_Program_Target *pt;
311    Edje_Real_Part *rp;
312
313    ed = runp->edje;
314    if (ed->delete_me) return EINA_FALSE;
315    _edje_block(ed);
316    _edje_ref(ed);
317    _edje_freeze(ed);
318    t = FROM_DOUBLE(tim - runp->start_time);
319    total = runp->program->tween.time;
320    t = DIV(t, total);
321    if (t > FROM_INT(1)) t = FROM_INT(1);
322    EINA_LIST_FOREACH(runp->program->targets, l, pt)
323      {
324         if (pt->id >= 0)
325           {
326              rp = ed->table_parts[pt->id % ed->table_parts_size];
327              if (rp) _edje_part_pos_set(ed, rp,
328                                         runp->program->tween.mode, t,
329                                         runp->program->tween.v1,
330                                         runp->program->tween.v2);
331           }
332      }
333    if (t >= FROM_INT(1))
334      {
335         Edje_Program_After *pa;
336
337         EINA_LIST_FOREACH(runp->program->targets, l, pt)
338           {
339              if (pt->id >= 0)
340                {
341                   rp = ed->table_parts[pt->id % ed->table_parts_size];
342                   if (rp)
343                     {
344                        _edje_part_description_apply(ed, rp,
345                                                     runp->program->state,
346                                                     runp->program->value,
347                                                     NULL,
348                                                     0.0);
349                        _edje_part_pos_set(ed, rp,
350                                           runp->program->tween.mode, ZERO,
351                                           runp->program->tween.v1,
352                                           runp->program->tween.v2);
353                        rp->program = NULL;
354                     }
355                }
356           }
357         _edje_recalc(ed);
358         runp->delete_me = EINA_TRUE;
359         if (!ed->walking_actions)
360           {
361              _edje_anim_count--;
362              ed->actions = eina_list_remove(ed->actions, runp);
363              if (!ed->actions)
364                _edje_animators = eina_list_remove(_edje_animators, ed);
365           }
366 //      _edje_emit(ed, "program,stop", runp->program->name);
367         if (_edje_block_break(ed))
368           {
369              if (!ed->walking_actions) free(runp);
370              goto break_prog;
371           }
372         EINA_LIST_FOREACH(runp->program->after, l, pa)
373           {
374              Edje_Program *pr;
375
376              if (pa->id >= 0)
377                {
378                   pr = ed->table_programs[pa->id % ed->table_programs_size];
379                   if (pr) _edje_program_run(ed, pr, 0, "", "");
380                   if (_edje_block_break(ed))
381                     {
382                        if (!ed->walking_actions) free(runp);
383                        goto break_prog;
384                     }
385                }
386           }
387         _edje_thaw(ed);
388         _edje_unref(ed);
389         if (!ed->walking_actions) free(runp);
390         _edje_unblock(ed);
391         return  EINA_FALSE;
392      }
393    break_prog:
394    _edje_recalc(ed);
395    _edje_thaw(ed);
396    _edje_unref(ed);
397    _edje_unblock(ed);
398    return EINA_TRUE;
399 }
400
401 void
402 _edje_program_end(Edje *ed, Edje_Running_Program *runp)
403 {
404    Eina_List *l;
405    Edje_Program_Target *pt;
406 //   const char *pname = NULL;
407    int free_runp = 0;
408
409    if (ed->delete_me) return;
410    _edje_ref(ed);
411    _edje_freeze(ed);
412    EINA_LIST_FOREACH(runp->program->targets, l, pt)
413      {
414         Edje_Real_Part *rp;
415
416         if (pt->id >= 0)
417           {
418              rp = ed->table_parts[pt->id % ed->table_parts_size];
419              if (rp)
420                {
421                   _edje_part_description_apply(ed, rp,
422                                                runp->program->state,
423                                                runp->program->value,
424                                                NULL,
425                                                0.0);
426                   _edje_part_pos_set(ed, rp,
427                                      runp->program->tween.mode, ZERO,
428                                      runp->program->tween.v1,
429                                      runp->program->tween.v2);
430                   rp->program = NULL;
431                }
432           }
433      }
434    _edje_recalc(ed);
435    runp->delete_me = EINA_TRUE;
436 //   pname = runp->program->name;
437    if (!ed->walking_actions)
438      {
439         _edje_anim_count--;
440         ed->actions = eina_list_remove(ed->actions, runp);
441         free_runp = 1;
442         if (!ed->actions)
443           {
444              _edje_animators = eina_list_remove(_edje_animators, ed);
445           }
446      }
447 //   _edje_emit(ed, "program,stop", pname);
448    _edje_thaw(ed);
449    _edje_unref(ed);
450    if (free_runp) free(runp);
451 }
452
453 void
454 _edje_program_run(Edje *ed, Edje_Program *pr, Eina_Bool force, const char *ssig, const char *ssrc)
455 {
456    Eina_List *l;
457    Edje_Real_Part *rp;
458    Edje_Program_Target *pt;
459    Edje_Program *pr2;
460    Edje_Program_After *pa;
461    /* limit self-feeding loops in programs to 64 levels */
462    static int recursions = 0;
463    static int recursion_limit = 0;
464
465    if (ed->delete_me) return;
466    if ((pr->in.from > 0.0) && (pr->in.range >= 0.0) && (!force))
467      {
468         Edje_Pending_Program *pp;
469         double r = 0.0;
470
471         pp = calloc(1, sizeof(Edje_Pending_Program));
472         if (!pp) return;
473         if (pr->in.range > 0.0) r = ((double)rand() / RAND_MAX);
474         pp->timer = ecore_timer_add(pr->in.from + (pr->in.range * r),
475                                     _edje_pending_timer_cb, pp);
476         if (!pp->timer)
477           {
478              free(pp);
479              return;
480           }
481         pp->edje = ed;
482         pp->program = pr;
483         ed->pending_actions = eina_list_append(ed->pending_actions, pp);
484         return;
485      }
486    if ((recursions >= 64) || (recursion_limit))
487      {
488         ERR("Programs recursing up to recursion limit of %i in '%s' with '%s', '%s' from '%s', '%s'. Disabled.",
489             64, pr->name, ssig, ssrc, ed->path, ed->group);
490         recursion_limit = 1;
491         return;
492      }
493    recursions++;
494    _edje_block(ed);
495    _edje_ref(ed);
496    _edje_freeze(ed);
497    switch (pr->action)
498      {
499      case EDJE_ACTION_TYPE_STATE_SET:
500         if ((pr->tween.time > ZERO) && (!ed->no_anim))
501           {
502              Edje_Running_Program *runp;
503
504              runp = calloc(1, sizeof(Edje_Running_Program));
505              EINA_LIST_FOREACH(pr->targets, l, pt)
506                {
507                   if (pt->id >= 0)
508                     {
509                        rp = ed->table_parts[pt->id % ed->table_parts_size];
510                        if (rp)
511                          {
512                             if ((rp->object) && (pr->tween.mode & EDJE_TWEEN_MODE_OPT_FROM_CURRENT))
513                               {
514                                  Edje_Calc_Params *tmp;
515
516                                  tmp = calloc(1, sizeof(Edje_Calc_Params));
517                                  if (!tmp) goto low_mem_current;
518                                  _edje_part_recalc(ed, rp, FLAG_XY, tmp);
519
520                                  if (rp->current) free(rp->current);
521                                  rp->current = tmp;
522
523                                  rp->current->x -= ed->x;
524                                  rp->current->y -= ed->y;
525                                  rp->current->map.center.x -= ed->x;
526                                  rp->current->map.center.y -= ed->y;
527                                  rp->current->map.light.x -= ed->x;
528                                  rp->current->map.light.y -= ed->y;
529                                  rp->current->map.persp.x -= ed->x;
530                                  rp->current->map.persp.y -= ed->y;
531                               }
532                             else
533                               {
534                               low_mem_current:
535                                  if (rp->current) free(rp->current);
536                                  rp->current = NULL;
537                               }
538
539                             if (rp->program)
540                               _edje_program_end(ed, rp->program);
541                             _edje_part_description_apply(ed, rp,
542                                                          rp->param1.description->state.name,
543                                                          rp->param1.description->state.value,
544                                                          pr->state,
545                                                          pr->value);
546                             _edje_part_pos_set(ed, rp, pr->tween.mode, ZERO,
547                                                pr->tween.v1,
548                                                pr->tween.v2);
549                             rp->program = runp;
550                          }
551                     }
552                }
553              // _edje_emit(ed, "program,start", pr->name);
554              if (_edje_block_break(ed))
555                {
556                   ed->actions = eina_list_append(ed->actions, runp);
557                   goto break_prog;
558                }
559              if (!ed->actions)
560                _edje_animators = eina_list_append(_edje_animators, ed);
561              ed->actions = eina_list_append(ed->actions, runp);
562              runp->start_time = ecore_loop_time_get();
563              runp->edje = ed;
564              runp->program = pr;
565              if (!_edje_timer)
566                _edje_timer = ecore_animator_add(_edje_timer_cb, NULL);
567              _edje_anim_count++;
568           }
569         else
570           {
571              EINA_LIST_FOREACH(pr->targets, l, pt)
572                {
573                   if (pt->id >= 0)
574                     {
575                        rp = ed->table_parts[pt->id % ed->table_parts_size];
576                        if (rp)
577                          {
578                             if (rp->program)
579                               _edje_program_end(ed, rp->program);
580                             _edje_part_description_apply(ed, rp,
581                                                          pr->state,
582                                                          pr->value,
583                                                          NULL,
584                                                          0.0);
585                             _edje_part_pos_set(ed, rp, pr->tween.mode, ZERO,
586                                                pr->tween.v1,
587                                                pr->tween.v2);
588                          }
589                     }
590                }
591              // _edje_emit(ed, "program,start", pr->name);
592              if (_edje_block_break(ed)) goto break_prog;
593              // _edje_emit(ed, "program,stop", pr->name);
594              if (_edje_block_break(ed)) goto break_prog;
595
596              EINA_LIST_FOREACH(pr->after, l, pa)
597                {
598                   if (pa->id >= 0)
599                     {
600                        pr2 = ed->table_programs[pa->id % ed->table_programs_size];
601                        if (pr2) _edje_program_run(ed, pr2, 0, "", "");
602                        if (_edje_block_break(ed)) goto break_prog;
603                     }
604                }
605              _edje_recalc(ed);
606           }
607         break;
608      case EDJE_ACTION_TYPE_ACTION_STOP:
609         // _edje_emit(ed, "program,start", pr->name);
610         EINA_LIST_FOREACH(pr->targets, l, pt)
611           {
612              Eina_List *ll;
613              Edje_Running_Program *runp;
614              Edje_Pending_Program *pp;
615
616              for (ll = ed->actions; ll; )
617                {
618                   runp = ll->data;
619                   ll = ll->next;
620                   if (pt->id == runp->program->id)
621                     {
622                        _edje_program_end(ed, runp);
623 //                     goto done;
624                     }
625                }
626              for (ll = ed->pending_actions; ll; )
627               {
628                   pp = ll->data;
629                   ll = ll->next;
630                   if (pt->id == pp->program->id)
631                     {
632                        ed->pending_actions = eina_list_remove(ed->pending_actions, pp);
633                        ecore_timer_del(pp->timer);
634                        free(pp);
635 //                     goto done;
636                     }
637                }
638 //           done:
639 //              continue;
640           }
641         // _edje_emit(ed, "program,stop", pr->name);
642         if (_edje_block_break(ed)) goto break_prog;
643         break;
644      case EDJE_ACTION_TYPE_SIGNAL_EMIT:
645         // _edje_emit(ed, "program,start", pr->name);
646         if (_edje_block_break(ed)) goto break_prog;
647         _edje_emit(ed, pr->state, pr->state2);
648         if (_edje_block_break(ed)) goto break_prog;
649         // _edje_emit(ed, "program,stop", pr->name);
650         if (_edje_block_break(ed)) goto break_prog;
651         break;
652      case EDJE_ACTION_TYPE_DRAG_VAL_SET:
653         // _edje_emit(ed, "program,start", pr->name);
654         if (_edje_block_break(ed)) goto break_prog;
655         EINA_LIST_FOREACH(pr->targets, l, pt)
656           {
657              if (pt->id >= 0)
658                {
659                   rp = ed->table_parts[pt->id % ed->table_parts_size];
660                   if ((rp) && (rp->drag) && (rp->drag->down.count == 0))
661                     {
662                        rp->drag->val.x = pr->value;
663                        rp->drag->val.y = pr->value2;
664                        if      (rp->drag->val.x < 0.0) rp->drag->val.x = 0.0;
665                        else if (rp->drag->val.x > 1.0) rp->drag->val.x = 1.0;
666                        if      (rp->drag->val.y < 0.0) rp->drag->val.y = 0.0;
667                        else if (rp->drag->val.y > 1.0) rp->drag->val.y = 1.0;
668                        _edje_dragable_pos_set(ed, rp, rp->drag->val.x, rp->drag->val.y);
669                        _edje_emit(ed, "drag,set", rp->part->name);
670                        if (_edje_block_break(ed)) goto break_prog;
671                     }
672                }
673           }
674         // _edje_emit(ed, "program,stop", pr->name);
675         if (_edje_block_break(ed)) goto break_prog;
676         break;
677      case EDJE_ACTION_TYPE_DRAG_VAL_STEP:
678         // _edje_emit(ed, "program,start", pr->name);
679         if (_edje_block_break(ed)) goto break_prog;
680         EINA_LIST_FOREACH(pr->targets, l, pt)
681           {
682              if (pt->id >= 0)
683                {
684                   rp = ed->table_parts[pt->id % ed->table_parts_size];
685                   if ((rp) && (rp->drag) && (rp->drag->down.count == 0))
686                     {
687                        rp->drag->val.x += pr->value * rp->drag->step.x * rp->part->dragable.x;
688                        rp->drag->val.y += pr->value2 * rp->drag->step.y * rp->part->dragable.y;
689                        if      (rp->drag->val.x < 0.0) rp->drag->val.x = 0.0;
690                        else if (rp->drag->val.x > 1.0) rp->drag->val.x = 1.0;
691                        if      (rp->drag->val.y < 0.0) rp->drag->val.y = 0.0;
692                        else if (rp->drag->val.y > 1.0) rp->drag->val.y = 1.0;
693                        _edje_dragable_pos_set(ed, rp, rp->drag->val.x, rp->drag->val.y);
694                        _edje_emit(ed, "drag,step", rp->part->name);
695                        if (_edje_block_break(ed)) goto break_prog;
696                     }
697                }
698           }
699         // _edje_emit(ed, "program,stop", pr->name);
700         if (_edje_block_break(ed)) goto break_prog;
701         break;
702      case EDJE_ACTION_TYPE_DRAG_VAL_PAGE:
703         // _edje_emit(ed, "program,start", pr->name);
704         if (_edje_block_break(ed)) goto break_prog;
705         EINA_LIST_FOREACH(pr->targets, l, pt)
706           {
707              if (pt->id >= 0)
708                {
709                   rp = ed->table_parts[pt->id % ed->table_parts_size];
710                   if ((rp) && (rp->drag) && (rp->drag->down.count == 0))
711                     {
712                        rp->drag->val.x += pr->value * rp->drag->page.x * rp->part->dragable.x;
713                        rp->drag->val.y += pr->value2 * rp->drag->page.y * rp->part->dragable.y;
714                        if      (rp->drag->val.x < 0.0) rp->drag->val.x = 0.0;
715                        else if (rp->drag->val.x > 1.0) rp->drag->val.x = 1.0;
716                        if      (rp->drag->val.y < 0.0) rp->drag->val.y = 0.0;
717                        else if (rp->drag->val.y > 1.0) rp->drag->val.y = 1.0;
718                        _edje_dragable_pos_set(ed, rp, rp->drag->val.x, rp->drag->val.y);
719                        _edje_emit(ed, "drag,page", rp->part->name);
720                        if (_edje_block_break(ed)) goto break_prog;
721                     }
722                }
723           }
724         // _edje_emit(ed, "program,stop", pr->name);
725         if (_edje_block_break(ed)) goto break_prog;
726         break;
727      case EDJE_ACTION_TYPE_SCRIPT:
728           {
729              char fname[128];
730
731              // _edje_emit(ed, "program,start", pr->name);
732              if (_edje_block_break(ed)) goto break_prog;
733              snprintf(fname, sizeof(fname), "_p%i", pr->id);
734              _edje_embryo_test_run(ed, fname, ssig, ssrc);
735              // _edje_emit(ed, "program,stop", pr->name);
736              if (_edje_block_break(ed)) goto break_prog;
737              _edje_recalc_do(ed);
738           }
739         break;
740      case EDJE_ACTION_TYPE_FOCUS_SET:
741         if (!pr->targets)
742            ed->focused_part = NULL;
743         else
744           {
745              EINA_LIST_FOREACH(pr->targets, l, pt)
746                {
747                   if (pt->id >= 0)
748                     {
749                        rp = ed->table_parts[pt->id % ed->table_parts_size];
750                        if (rp)
751                          {
752                             if (ed->focused_part != rp)
753                               {
754                                  if (ed->focused_part)
755                                    _edje_emit(ed, "focus,part,out", 
756                                               ed->focused_part->part->name);
757                                  ed->focused_part = rp;
758                                  _edje_emit(ed, "focus,part,in",
759                                             ed->focused_part->part->name);
760                               }
761                          }
762                     }
763                }
764           }
765         break;
766      case EDJE_ACTION_TYPE_FOCUS_OBJECT:
767         if (!pr->targets)
768           {
769              Evas_Object *focused;
770
771              focused = evas_focus_get(evas_object_evas_get(ed->obj));
772              if (focused)
773                {
774                   unsigned int i;
775
776                   /* Check if the current swallowed object is one of my child. */
777                   for (i = 0; i < ed->table_parts_size; ++i)
778                     {
779                        rp = ed->table_parts[i];
780                        if ((rp) && 
781                            ((rp->type == EDJE_RP_TYPE_SWALLOW) &&
782                                (rp->typedata.swallow)) &&
783                            (rp->typedata.swallow->swallowed_object == focused))
784                          {
785                             evas_object_focus_set(focused, EINA_FALSE);
786                             break;
787                          }
788                     }
789                }
790           }
791         else
792           {
793              EINA_LIST_FOREACH(pr->targets, l, pt)
794                {
795                   if (pt->id >= 0)
796                     {
797                        rp = ed->table_parts[pt->id % ed->table_parts_size];
798                        if (rp && 
799                            ((rp->type == EDJE_RP_TYPE_SWALLOW) &&
800                                (rp->typedata.swallow)) &&
801                            (rp->typedata.swallow->swallowed_object))
802                          evas_object_focus_set(rp->typedata.swallow->swallowed_object, EINA_TRUE);
803                     }
804                }
805           }
806         break;
807      case EDJE_ACTION_TYPE_SOUND_SAMPLE:
808         if (_edje_block_break(ed))
809           goto break_prog;
810         if (!multisense_init) _edje_multisense_init();
811         _edje_multisense_internal_sound_sample_play(ed, pr->sample_name, pr->speed);
812         break;
813      case EDJE_ACTION_TYPE_SOUND_TONE:
814         if (_edje_block_break(ed))
815           goto break_prog;
816         if (!multisense_init) _edje_multisense_init();
817         _edje_multisense_internal_sound_tone_play(ed, pr->tone_name, pr->duration);
818         break;
819      case EDJE_ACTION_TYPE_PARAM_COPY:
820           {
821              Edje_Real_Part *src_part, *dst_part;
822
823              // _edje_emit(ed, "program,start", pr->name);
824              if (_edje_block_break(ed)) goto break_prog;
825              
826              src_part = ed->table_parts[pr->param.src % ed->table_parts_size];
827              dst_part = ed->table_parts[pr->param.dst % ed->table_parts_size];
828              _edje_param_copy(src_part, pr->state, dst_part, pr->state2);
829              
830              if (_edje_block_break(ed)) goto break_prog;
831              // _edje_emit(ed, "program,stop", pr->name);
832              if (_edje_block_break(ed)) goto break_prog;
833           }
834         break;
835      case EDJE_ACTION_TYPE_PARAM_SET:
836           {
837              Edje_Real_Part *part;
838
839              // _edje_emit(ed, "program,start", pr->name);
840              if (_edje_block_break(ed)) goto break_prog;
841              
842              part = ed->table_parts[pr->param.dst % ed->table_parts_size];
843              _edje_param_set(part, pr->state, pr->state2);
844              
845              if (_edje_block_break(ed)) goto break_prog;
846              // _edje_emit(ed, "program,stop", pr->name);
847              if (_edje_block_break(ed)) goto break_prog;
848           }
849         break;
850      default:
851         // _edje_emit(ed, "program,start", pr->name);
852         // _edje_emit(ed, "program,stop", pr->name);
853         break;
854      }
855    if (!((pr->action == EDJE_ACTION_TYPE_STATE_SET)
856          /* hmm this fucks somethgin up. must look into it later */
857          /* && (pr->tween.time > ZERO) && (!ed->no_anim))) */
858          ))
859      {
860         EINA_LIST_FOREACH(pr->after, l, pa)
861           {
862              if (pa->id >= 0)
863                {
864                   pr2 = ed->table_programs[pa->id % ed->table_programs_size];
865                   if (pr2) _edje_program_run(ed, pr2, 0, "", "");
866                   if (_edje_block_break(ed)) goto break_prog;
867                }
868           }
869      }
870    break_prog:
871    _edje_thaw(ed);
872    _edje_unref(ed);
873    recursions--;
874    if (recursions == 0) recursion_limit = 0;
875    _edje_unblock(ed);
876 }
877
878 void
879 _edje_emit(Edje *ed, const char *sig, const char *src)
880 {
881    _edje_emit_full(ed, sig, src, NULL, NULL);
882 }
883
884 /* data should either be NULL or a malloc allocated data */
885 void
886 _edje_emit_full(Edje *ed, const char *sig, const char *src, void *data, void (*free_func)(void *))
887 {
888    Edje_Message_Signal emsg;
889    const char *sep;
890
891    if (ed->delete_me) return;
892
893    sep = strchr(sig, EDJE_PART_PATH_SEPARATOR);
894
895    /* If we are not sending the signal to a part of the child, the
896     * signal if for ourself
897     */
898    if (sep)
899      {
900         Edje_Real_Part *rp = NULL;
901         const char *newsig;
902         Edje *ed2;
903         char *part;
904         char *idx;
905         size_t length;
906
907         /* the signal contains a colon, split the signal into "parts:signal" */
908         length = sep - sig + 1;
909         part = alloca(length);
910         memcpy(part, sig, length - 1);
911         part[length - 1] = '\0';
912
913         newsig = sep + 1;
914
915         /* lookup for alias */
916         if (ed->collection && ed->collection->alias)
917           {
918              char *alias;
919
920              alias = eina_hash_find(ed->collection->alias, part);
921              if (alias) {
922                 char *aliased;
923                 int alien;
924                 int nslen;
925
926                 alien = strlen(alias);
927                 nslen = strlen(newsig);
928                 length = alien + nslen + 2;
929
930                 aliased = alloca(length);
931                 memcpy(aliased, alias, alien);
932                 aliased[alien] = EDJE_PART_PATH_SEPARATOR;
933                 memcpy(aliased + alien + 1, newsig, nslen + 1);
934
935                 _edje_emit(ed, aliased, src);
936                 return;
937              }
938           }
939
940         /* search for the index if present and remove it from the part */
941         idx = strchr(part, EDJE_PART_PATH_SEPARATOR_INDEXL);
942         if (idx)
943           {
944              char *end;
945
946              end = strchr(idx + 1, EDJE_PART_PATH_SEPARATOR_INDEXR);
947              if (end && end != idx + 1)
948                {
949                   char *tmp;
950
951                   tmp = alloca(end - idx - 1);
952                   memcpy(tmp, idx + 1, end - idx - 1);
953                   tmp[end - idx - 1] = '\0';
954                   *idx = '\0';
955                   idx = tmp;
956                }
957              else
958                {
959                   idx = NULL;
960                }
961           }
962
963         /* search for the right part now */
964         rp = _edje_real_part_get(ed, part);
965         if (!rp) goto end;
966
967         switch (rp->part->type)
968           {
969            case EDJE_PART_TYPE_GROUP:
970               if (((rp->type != EDJE_RP_TYPE_SWALLOW) ||
971                    (!rp->typedata.swallow)) ||
972                   (!rp->typedata.swallow->swallowed_object))
973                 goto end;
974               ed2 = _edje_fetch(rp->typedata.swallow->swallowed_object);
975               if (!ed2) goto end;
976
977               _edje_emit(ed2, newsig, src);
978               break;
979
980            case EDJE_PART_TYPE_EXTERNAL:
981               if (((rp->type != EDJE_RP_TYPE_SWALLOW) ||
982                    (!rp->typedata.swallow)) ||
983                   (!rp->typedata.swallow->swallowed_object))
984                break;
985
986               if (!idx)
987                 {
988                    _edje_external_signal_emit(rp->typedata.swallow->swallowed_object, newsig, src);
989                 }
990               else
991                 {
992                    Evas_Object *child;
993
994                    child = _edje_children_get(rp, idx);
995                    ed2 = _edje_fetch(child);
996                    if (!ed2) goto end;
997                    _edje_emit(ed2, newsig, src);
998                 }
999               break ;
1000
1001            case EDJE_PART_TYPE_BOX:
1002            case EDJE_PART_TYPE_TABLE:
1003               if (idx)
1004                 {
1005                    Evas_Object *child;
1006
1007                    child = _edje_children_get(rp, idx);
1008                    ed2 = _edje_fetch(child);
1009                    if (!ed2) goto end;
1010                    _edje_emit(ed2, newsig, src);
1011                 }
1012               break ;
1013
1014            default:
1015 //              ERR("SPANK SPANK SPANK !!!\nYou should never be here !");
1016               break;
1017           }
1018      }
1019
1020  end:
1021    emsg.sig = sig;
1022    emsg.src = src;
1023    if (data)
1024      {
1025         emsg.data = calloc(1, sizeof(*(emsg.data)));
1026         emsg.data->ref = 1;
1027         emsg.data->data = data;
1028         emsg.data->free_func = free_func;
1029      }
1030    else
1031      {
1032         emsg.data = NULL;
1033      }
1034 /* new sends code */
1035    edje_object_message_send(ed->obj, EDJE_MESSAGE_SIGNAL, 0, &emsg);
1036 /* old send code - use api now
1037    _edje_message_send(ed, EDJE_QUEUE_SCRIPT, EDJE_MESSAGE_SIGNAL, 0, &emsg);
1038    EINA_LIST_FOREACH(ed->subobjs, l, obj)
1039      {
1040         Edje *ed2;
1041
1042         ed2 = _edje_fetch(obj);
1043         if (!ed2) continue;
1044         if (ed2->delete_me) continue;
1045         _edje_message_send(ed2, EDJE_QUEUE_SCRIPT, EDJE_MESSAGE_SIGNAL, 0, &emsg);
1046      }
1047  */
1048    if (emsg.data && (--(emsg.data->ref) == 0))
1049      {
1050         if (emsg.data->free_func)
1051           {
1052              emsg.data->free_func(emsg.data->data);
1053           }
1054         free(emsg.data);
1055      }
1056 }
1057
1058 struct _Edje_Program_Data
1059 {
1060   Eina_List     *matches;
1061   Edje          *ed;
1062   const char    *source;
1063 };
1064
1065 static Eina_Bool _edje_glob_callback(Edje_Program *pr, void *dt)
1066 {
1067    struct _Edje_Program_Data *data = dt;
1068    Edje_Real_Part *rp = NULL;
1069    Eina_Bool exec = EINA_TRUE;
1070
1071    if (pr->filter.state)
1072      {
1073         rp = _edje_real_part_get(data->ed, pr->filter.part ? pr->filter.part : data->source);
1074         if (rp)
1075           exec = (rp->chosen_description->state.name == pr->filter.state);
1076      }
1077
1078    pr->exec = exec;
1079
1080    data->matches = eina_list_append(data->matches, pr);
1081
1082    return EINA_FALSE;
1083 }
1084
1085 void
1086 _edje_callbacks_patterns_clean(Edje *ed)
1087 {
1088    if (ed->walking_callbacks > 0) return;
1089
1090    _edje_signals_sources_patterns_clean(&ed->patterns.callbacks);
1091
1092    eina_rbtree_delete(ed->patterns.callbacks.exact_match,
1093                       EINA_RBTREE_FREE_CB(edje_match_signal_source_free),
1094                       NULL);
1095    ed->patterns.callbacks.exact_match = NULL;
1096
1097    ed->patterns.callbacks.u.callbacks.globing = eina_list_free(ed->patterns.callbacks.u.callbacks.globing);
1098 }
1099
1100 static void
1101 _edje_callbacks_patterns_init(Edje *ed)
1102 {
1103    Edje_Signals_Sources_Patterns *ssp = &ed->patterns.callbacks;
1104
1105    if ((ssp->signals_patterns) || (ssp->sources_patterns) ||
1106        (ssp->u.callbacks.globing) || (ssp->exact_match))
1107      return;
1108
1109    ssp->u.callbacks.globing = edje_match_callback_hash_build(ed->callbacks,
1110                                                              &ssp->exact_match);
1111
1112    ssp->signals_patterns = edje_match_callback_signal_init(ssp->u.callbacks.globing);
1113    ssp->sources_patterns = edje_match_callback_source_init(ssp->u.callbacks.globing);
1114 }
1115
1116 /* FIXME: what if we delete the evas object??? */
1117 void
1118 _edje_emit_handle(Edje *ed, const char *sig, const char *src,
1119                   Edje_Message_Signal_Data *sdata, Eina_Bool prop)
1120 {
1121    if (ed->delete_me) return;
1122    if (!sig) sig = "";
1123    if (!src) src = "";
1124 //   printf("EDJE EMIT: (%p) signal: \"%s\" source: \"%s\"\n", ed, sig, src);
1125    _edje_block(ed);
1126    _edje_ref(ed);
1127    _edje_freeze(ed);
1128    
1129    if (ed->collection && ed->L)
1130      _edje_lua2_script_func_signal(ed, sig, src);
1131
1132    if (ed->collection)
1133      {
1134 #ifdef EDJE_PROGRAM_CACHE
1135         Edje_Part_Collection *ec;
1136         char *tmps;
1137         int l1, l2;
1138 #endif
1139         int done;
1140
1141 #ifdef EDJE_PROGRAM_CACHE
1142         ec = ed->collection;
1143         l1 = strlen(sig);
1144         l2 = strlen(src);
1145         tmps = alloca(l1 + l2 + 3); /* \0, \337, \0 */
1146         strcpy(tmps, sig);
1147         tmps[l1] = '\377';
1148         strcpy(&(tmps[l1 + 1]), src);
1149 #endif
1150         done = 0;
1151
1152 #ifdef EDJE_PROGRAM_CACHE
1153           {
1154              Eina_List *matches;
1155              Eina_List *l;
1156              Edje_Program *pr;
1157
1158              if (eina_hash_find(ec->prog_cache.no_matches, tmps))
1159                {
1160                   done = 1;
1161                }
1162              else if ((matches = eina_hash_find(ec->prog_cache.matches, tmps)))
1163                {
1164                   EINA_LIST_FOREACH(matches, l, pr)
1165                     {
1166                        Eina_Bool exec = EINA_TRUE;
1167
1168                        if (pr->filter.state)
1169                          {
1170                             Edje_Real_Part *rp;
1171
1172                             rp = _edje_real_part_get(ed, pr->filter.part ? pr->filter.part : src);
1173                             if (rp)
1174                               {
1175                                  if (rp->program)
1176                                    exec = EINA_FALSE;
1177                                  else
1178                                    exec = (rp->chosen_description->state.name == pr->filter.state);
1179                               }
1180                          }
1181
1182                        pr->exec = exec;
1183                     }
1184
1185                   EINA_LIST_FOREACH(matches, l, pr)
1186                     if (pr->exec)
1187                       {
1188                          _edje_program_run(ed, pr, 0, sig, src);
1189                          if (_edje_block_break(ed))
1190                            {
1191                               goto break_prog;
1192                            }
1193                       }
1194
1195                   done = 1;
1196                }
1197           }
1198 #endif
1199         if (!done)
1200           {
1201              struct _Edje_Program_Data  data;
1202
1203              data.ed = ed;
1204              data.source = src;
1205              data.matches = NULL;
1206
1207              if (ed->table_programs_size > 0)
1208                {
1209                   const Eina_Array *match;
1210 #ifdef EDJE_PROGRAM_CACHE
1211                   const Eina_List *l;
1212 #endif
1213                   Edje_Program *pr;
1214                   Eina_Array_Iterator iterator;
1215                   unsigned int i;       
1216
1217                   if (ed->patterns.programs.u.programs.globing)
1218                     if (edje_match_programs_exec(ed->patterns.programs.signals_patterns,
1219                                                  ed->patterns.programs.sources_patterns,
1220                                                  sig,
1221                                                  src,
1222                                                  ed->patterns.programs.u.programs.globing,
1223                                                  _edje_glob_callback,
1224                                                  &data,
1225                                                  prop) == 0)
1226                       goto break_prog;
1227
1228                   match = edje_match_signal_source_hash_get(sig, src,
1229                                                             ed->patterns.programs.exact_match);
1230                   if (match)
1231                     EINA_ARRAY_ITER_NEXT(match, i, pr, iterator)
1232                       _edje_glob_callback(pr, &data);
1233
1234 #ifdef EDJE_PROGRAM_CACHE
1235                   EINA_LIST_FOREACH(data.matches, l, pr)
1236 #else
1237                   EINA_LIST_FREE(data.matches, pr)
1238 #endif
1239                     {
1240                        if (pr->exec)
1241                          _edje_program_run(ed, pr, 0, sig, src);
1242
1243                        if (_edje_block_break(ed))
1244                          {
1245                             eina_list_free(data.matches);
1246                             data.matches = NULL;
1247                             goto break_prog;
1248                          }
1249                     }
1250                }
1251
1252 #ifdef EDJE_PROGRAM_CACHE
1253              if (tmps)
1254                {
1255                   if (data.matches == NULL)
1256                     {
1257                       if (!ec->prog_cache.no_matches)
1258                         ec->prog_cache.no_matches = eina_hash_string_superfast_new(NULL);
1259                       eina_hash_add(ec->prog_cache.no_matches, tmps, ed);
1260                     }
1261                   else
1262                     {
1263                       if (!ec->prog_cache.matches)
1264                         ec->prog_cache.matches = eina_hash_string_superfast_new(NULL);
1265                       eina_hash_add(ec->prog_cache.matches, tmps, data.matches);
1266                     }
1267                }
1268 #endif
1269           }
1270         _edje_emit_cb(ed, sig, src, sdata, prop);
1271         if (_edje_block_break(ed))
1272           {
1273              goto break_prog;
1274           }
1275      }
1276    break_prog:
1277    _edje_thaw(ed);
1278    _edje_unref(ed);
1279    _edje_unblock(ed);
1280 }
1281
1282 /* Extra data for callbacks */
1283 static void *callback_extra_data = NULL;
1284
1285 EAPI void *
1286 edje_object_signal_callback_extra_data_get(void)
1287 {
1288    return callback_extra_data;
1289 }
1290
1291 /* FIXME: what if we delete the evas object??? */
1292 static void
1293 _edje_emit_cb(Edje *ed, const char *sig, const char *src, Edje_Message_Signal_Data *data, Eina_Bool prop)
1294 {
1295    Eina_List            *l;
1296
1297    if (ed->delete_me) return;
1298    _edje_ref(ed);
1299    _edje_freeze(ed);
1300    _edje_block(ed);
1301
1302    if (ed->just_added_callbacks)
1303      _edje_callbacks_patterns_clean(ed);
1304
1305    ed->walking_callbacks++;
1306
1307    if (ed->callbacks)
1308      {
1309         Edje_Signal_Callback *escb;
1310         const Eina_Array *match;
1311         Eina_Array_Iterator iterator;
1312         unsigned int i;
1313         int r = 1;
1314         callback_extra_data = (data) ? data->data : NULL;
1315
1316         _edje_callbacks_patterns_init(ed);
1317         if (ed->patterns.callbacks.u.callbacks.globing)
1318           r = edje_match_callback_exec(ed->patterns.callbacks.signals_patterns,
1319                                        ed->patterns.callbacks.sources_patterns,
1320                                        sig,
1321                                        src,
1322                                        ed->patterns.callbacks.u.callbacks.globing,
1323                                        ed,
1324                                        prop);
1325
1326         if (!r)
1327           goto break_prog;
1328
1329         match = edje_match_signal_source_hash_get(sig, src,
1330                                                   ed->patterns.callbacks.exact_match);
1331         if (match)
1332           EINA_ARRAY_ITER_NEXT(match, i, escb, iterator)
1333             {
1334                if ((prop) && (escb->propagate)) continue;
1335                if ((!escb->just_added) && (!escb->delete_me))
1336                  {
1337                     escb->func(escb->data, ed->obj, sig, src);
1338                     if (_edje_block_break(ed))
1339                       break;
1340                  }
1341             }
1342      }
1343    break_prog:
1344
1345    ed->walking_callbacks--;
1346    if (!ed->walking_callbacks &&
1347        ((ed->delete_callbacks) || (ed->just_added_callbacks)))
1348      {
1349         ed->delete_callbacks = EINA_FALSE;
1350         ed->just_added_callbacks = EINA_FALSE;
1351         l = ed->callbacks;
1352         while (l)
1353           {
1354              Edje_Signal_Callback *escb = l->data;
1355              Eina_List *next_l = l->next;
1356
1357              if (escb->just_added)
1358                escb->just_added = 0;
1359              if (escb->delete_me)
1360                {
1361                   ed->callbacks = eina_list_remove_list(ed->callbacks, l);
1362                   if (escb->signal) eina_stringshare_del(escb->signal);
1363                   if (escb->source) eina_stringshare_del(escb->source);
1364                   free(escb);
1365                }
1366              l = next_l;
1367           }
1368
1369         _edje_callbacks_patterns_clean(ed);
1370      }
1371    _edje_unblock(ed);
1372    _edje_thaw(ed);
1373    _edje_unref(ed);
1374 }
1375
1376 static const Edje_External_Param_Info *
1377 _edje_external_param_info_get(const Evas_Object *obj, const char *name)
1378 {
1379    const Edje_External_Type *type;
1380    const Edje_External_Param_Info *info;
1381
1382    type = evas_object_data_get(obj, "Edje_External_Type");
1383    if (!type) return NULL;
1384    for (info = type->parameters_info; info->name; info++)
1385      if (!strcmp(info->name, name)) return info;
1386
1387    return NULL;
1388 }
1389
1390 static Edje_External_Param *
1391 _edje_param_external_get(Edje_Real_Part *rp, const char *name, Edje_External_Param *param)
1392 {
1393    Evas_Object *swallowed_object;
1394    const Edje_External_Param_Info *info;
1395    
1396    if ((rp->type != EDJE_RP_TYPE_SWALLOW) ||
1397        (!rp->typedata.swallow)) return NULL;
1398    swallowed_object = rp->typedata.swallow->swallowed_object;
1399
1400    info = _edje_external_param_info_get(swallowed_object, name);
1401    if (!info) return NULL;
1402
1403    memset(param, 0, sizeof(*param));
1404    param->name = info->name;
1405    param->type = info->type;
1406    if (!_edje_external_param_get(NULL, rp, param)) return NULL;
1407    return param;
1408 }
1409
1410 /* simulate external properties for native objects */
1411 static Edje_External_Param *
1412 _edje_param_native_get(Edje_Real_Part *rp, const char *name, Edje_External_Param *param, void **free_ptr)
1413 {
1414    *free_ptr = NULL;
1415    if ((rp->part->type == EDJE_PART_TYPE_TEXT) ||
1416        (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK))
1417      {
1418         if (!strcmp(name, "text"))
1419           {
1420              param->name = name;
1421              param->type = EDJE_EXTERNAL_PARAM_TYPE_STRING;
1422
1423              _edje_recalc_do(rp->edje);
1424              if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1425                param->s = _edje_entry_text_get(rp);
1426              else if ((rp->part->type == EDJE_PART_TYPE_TEXT) &&
1427                       ((rp->type == EDJE_RP_TYPE_TEXT) &&
1428                           (rp->typedata.text)))
1429                param->s = rp->typedata.text->text;
1430              else
1431                param->s = evas_object_textblock_text_markup_get(rp->object);
1432              return param;
1433           }
1434         if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
1435           {
1436              if (!strcmp(name, "text_unescaped"))
1437                {
1438                   param->name = name;
1439                   param->type = EDJE_EXTERNAL_PARAM_TYPE_STRING;
1440
1441                   _edje_recalc_do(rp->edje);
1442                   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1443                     {
1444                        const char *tmp = _edje_entry_text_get(rp);
1445                        char *unescaped = _edje_text_unescape(tmp);
1446                        *free_ptr = unescaped;
1447                        param->s = unescaped;
1448                     }
1449                   else if ((rp->part->type == EDJE_PART_TYPE_TEXT) &&
1450                            ((rp->type == EDJE_RP_TYPE_TEXT) &&
1451                                (rp->typedata.text)))
1452                     param->s = rp->typedata.text->text;
1453                   else
1454                     {
1455                        const char *tmp;
1456                        char *unescaped;
1457
1458                        tmp = evas_object_textblock_text_markup_get(rp->object);
1459                        unescaped = _edje_text_unescape(tmp);
1460                        *free_ptr = unescaped;
1461                        param->s = unescaped;
1462                     }
1463
1464                   return param;
1465                }
1466
1467              if (((rp->type == EDJE_RP_TYPE_TEXT) &&
1468                   (rp->typedata.text)) &&
1469                  ((rp->typedata.text->entry_data) &&
1470                      (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE) &&
1471                      (!strcmp(name, "select_allow"))))
1472                {
1473                   param->name = name;
1474                   param->type = EDJE_EXTERNAL_PARAM_TYPE_BOOL;
1475                   param->i = _edje_entry_select_allow_get(rp);
1476                   return param;
1477                }
1478           }
1479      }
1480
1481    if ((rp->drag) && (rp->drag->down.count == 0))
1482      {
1483         if (!strncmp(name, "drag_", sizeof("drag_") - 1))
1484           {
1485              const char *sub_name = name + sizeof("drag_") - 1;
1486              if (!strcmp(sub_name, "value_x"))
1487                {
1488                   double d;
1489
1490                   _edje_recalc_do(rp->edje);
1491                   d = TO_DOUBLE(rp->drag->val.x);
1492                   if (rp->part->dragable.x < 0) d = 1.0 - d;
1493                   param->name = name;
1494                   param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
1495                   param->d = d;
1496                   return param;
1497                }
1498              if (!strcmp(sub_name, "value_y"))
1499                {
1500                   double d;
1501
1502                   _edje_recalc_do(rp->edje);
1503                   d = TO_DOUBLE(rp->drag->val.y);
1504                   if (rp->part->dragable.y < 0) d = 1.0 - d;
1505                   param->name = name;
1506                   param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
1507                   param->d = d;
1508                   return param;
1509                }
1510
1511              if (!strcmp(sub_name, "size_w"))
1512                {
1513                   _edje_recalc_do(rp->edje);
1514                   param->name = name;
1515                   param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
1516                   param->d = TO_DOUBLE(rp->drag->size.x);
1517                   return param;
1518                }
1519              if (!strcmp(sub_name, "size_h"))
1520                {
1521                   _edje_recalc_do(rp->edje);
1522                   param->name = name;
1523                   param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
1524                   param->d = TO_DOUBLE(rp->drag->size.y);
1525                   return param;
1526                }
1527
1528              if (!strcmp(sub_name, "step_x"))
1529                {
1530                   _edje_recalc_do(rp->edje);
1531                   param->name = name;
1532                   param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
1533                   param->d = TO_DOUBLE(rp->drag->step.x);
1534                   return param;
1535                }
1536              if (!strcmp(sub_name, "step_y"))
1537                {
1538                   _edje_recalc_do(rp->edje);
1539                   param->name = name;
1540                   param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
1541                   param->d = TO_DOUBLE(rp->drag->step.y);
1542                   return param;
1543                }
1544
1545              if (!strcmp(sub_name, "page_x"))
1546                {
1547                   _edje_recalc_do(rp->edje);
1548                   param->name = name;
1549                   param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
1550                   param->d = TO_DOUBLE(rp->drag->page.x);
1551                   return param;
1552                }
1553              if (!strcmp(sub_name, "page_y"))
1554                {
1555                   _edje_recalc_do(rp->edje);
1556                   param->name = name;
1557                   param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
1558                   param->d = TO_DOUBLE(rp->drag->page.y);
1559                   return param;
1560                }
1561
1562              return NULL;
1563           }
1564      }
1565
1566    return NULL;
1567 }
1568
1569 static Eina_Bool
1570 _edje_param_native_set(Edje_Real_Part *rp, const char *name, const Edje_External_Param *param)
1571 {
1572    if ((rp->part->type == EDJE_PART_TYPE_TEXT) ||
1573        (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK))
1574      {
1575         if (!strcmp(name, "text"))
1576           {
1577              if (param->type != EDJE_EXTERNAL_PARAM_TYPE_STRING)
1578                return EINA_FALSE;
1579
1580              _edje_object_part_text_raw_set
1581                (rp->edje->obj, rp, rp->part->name, param->s);
1582              return EINA_TRUE;
1583           }
1584         if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
1585           {
1586              if (!strcmp(name, "text_unescaped"))
1587                {
1588                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_STRING)
1589                     return EINA_FALSE;
1590
1591                   if (rp->part->type == EDJE_PART_TYPE_TEXT)
1592                     _edje_object_part_text_raw_set
1593                       (rp->edje->obj, rp, rp->part->name, param->s);
1594                   else
1595                     {
1596                        char *escaped = _edje_text_escape(param->s);
1597                       _edje_object_part_text_raw_set
1598                          (rp->edje->obj, rp, rp->part->name, escaped);
1599                        free(escaped);
1600                     }
1601
1602                   return EINA_TRUE;
1603                }
1604
1605              if (((rp->type == EDJE_RP_TYPE_TEXT) &&
1606                   (rp->typedata.text)) &&
1607                  ((rp->typedata.text->entry_data) &&
1608                      (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE) &&
1609                      (!strcmp(name, "select_allow"))))
1610                {
1611                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_BOOL)
1612                     return EINA_FALSE;
1613                   _edje_entry_select_allow_set(rp, param->i);
1614                   return EINA_TRUE;
1615                }
1616           }
1617      }
1618
1619    if ((rp->drag) && (rp->drag->down.count == 0))
1620      {
1621         if (!strncmp(name, "drag_", sizeof("drag_") - 1))
1622           {
1623              const char *sub_name = name + sizeof("drag_") - 1;
1624              if (!strcmp(sub_name, "value_x"))
1625                {
1626                   double d;
1627                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
1628                     return EINA_FALSE;
1629                   d = param->d;
1630                   if (rp->part->dragable.confine_id != -1)
1631                     d = CLAMP(d, 0.0, 1.0);
1632                   if (rp->part->dragable.x < 0) d = 1.0 - d;
1633                   if (rp->drag->val.x == FROM_DOUBLE(d)) return EINA_TRUE;
1634                   rp->drag->val.x = FROM_DOUBLE(d);
1635 #ifdef EDJE_CALC_CACHE
1636                   rp->invalidate = 1;
1637 #endif
1638                   _edje_dragable_pos_set
1639                     (rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
1640                   _edje_emit(rp->edje, "drag,set", rp->part->name);
1641                   return EINA_TRUE;
1642                }
1643              if (!strcmp(sub_name, "value_y"))
1644                {
1645                   double d;
1646                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
1647                     return EINA_FALSE;
1648                   d = param->d;
1649                   if (rp->part->dragable.confine_id != -1)
1650                     d = CLAMP(d, 0.0, 1.0);
1651                   if (rp->part->dragable.y < 0) d = 1.0 - d;
1652                   if (rp->drag->val.y == FROM_DOUBLE(d)) return EINA_TRUE;
1653                   rp->drag->val.y = FROM_DOUBLE(d);
1654 #ifdef EDJE_CALC_CACHE
1655                   rp->invalidate = 1;
1656 #endif
1657                   _edje_dragable_pos_set
1658                     (rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
1659                   _edje_emit(rp->edje, "drag,set", rp->part->name);
1660                   return EINA_TRUE;
1661                }
1662
1663              if (!strcmp(sub_name, "size_w"))
1664                {
1665                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
1666                     return EINA_FALSE;
1667                   rp->drag->size.x = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
1668                   rp->edje->recalc_call = EINA_TRUE;
1669                   rp->edje->dirty = EINA_TRUE;
1670 #ifdef EDJE_CALC_CACHE
1671                   rp->invalidate = 1;
1672 #endif
1673                   _edje_recalc(rp->edje);
1674                   return EINA_TRUE;
1675                }
1676              if (!strcmp(sub_name, "size_h"))
1677                {
1678                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
1679                     return EINA_FALSE;
1680                   rp->drag->size.y = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
1681                   rp->edje->recalc_call = EINA_TRUE;
1682                   rp->edje->dirty = EINA_TRUE;
1683 #ifdef EDJE_CALC_CACHE
1684                   rp->invalidate = 1;
1685 #endif
1686                   _edje_recalc(rp->edje);
1687                   return EINA_TRUE;
1688                }
1689
1690              if (!strcmp(sub_name, "step_x"))
1691                {
1692                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
1693                     return EINA_FALSE;
1694                   rp->drag->step.x = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
1695 #ifdef EDJE_CALC_CACHE
1696                   rp->invalidate = 1;
1697 #endif
1698                   return EINA_TRUE;
1699                }
1700              if (!strcmp(sub_name, "step_y"))
1701                {
1702                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
1703                     return EINA_FALSE;
1704                   rp->drag->step.y = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
1705 #ifdef EDJE_CALC_CACHE
1706                   rp->invalidate = 1;
1707 #endif
1708                   return EINA_TRUE;
1709                }
1710
1711              if (!strcmp(sub_name, "page_x"))
1712                {
1713                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
1714                     return EINA_FALSE;
1715                   rp->drag->page.x = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
1716 #ifdef EDJE_CALC_CACHE
1717                   rp->invalidate = 1;
1718 #endif
1719                   return EINA_TRUE;
1720                }
1721              if (!strcmp(sub_name, "page_y"))
1722                {
1723                   if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
1724                     return EINA_FALSE;
1725                   rp->drag->page.y = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
1726 #ifdef EDJE_CALC_CACHE
1727                   rp->invalidate = 1;
1728 #endif
1729                   return EINA_TRUE;
1730                }
1731
1732              return EINA_FALSE;
1733           }
1734      }
1735
1736    return EINA_FALSE;
1737 }
1738
1739 static const Edje_External_Param_Info *
1740 _edje_native_param_info_get(const Edje_Real_Part *rp, const char *name)
1741 {
1742    if ((rp->part->type == EDJE_PART_TYPE_TEXT) ||
1743        (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK))
1744      {
1745         if (!strcmp(name, "text"))
1746           {
1747              static const Edje_External_Param_Info pi =
1748                EDJE_EXTERNAL_PARAM_INFO_STRING("text");
1749              return &pi;
1750           }
1751         if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
1752           {
1753              if (!strcmp(name, "text_unescaped"))
1754                {
1755                   static const Edje_External_Param_Info pi =
1756                     EDJE_EXTERNAL_PARAM_INFO_STRING("text_unescaped");
1757                   return &pi;
1758                }
1759              if (!strcmp(name, "select_allow"))
1760                {
1761                   static const Edje_External_Param_Info pi =
1762                     EDJE_EXTERNAL_PARAM_INFO_BOOL("text_unescaped");
1763                   return &pi;
1764                }
1765           }
1766      }
1767
1768    if ((rp->drag) && (rp->drag->down.count == 0))
1769      {
1770         if (!strncmp(name, "drag_", sizeof("drag_") - 1))
1771           {
1772              name += sizeof("drag_") - 1;
1773              if (!strcmp(name, "value_x"))
1774                {
1775                   static const Edje_External_Param_Info pi =
1776                     EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_value_x");
1777                   return &pi;
1778                }
1779              if (!strcmp(name, "value_y"))
1780                {
1781                   static const Edje_External_Param_Info pi =
1782                     EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_value_y");
1783                   return &pi;
1784                }
1785              if (!strcmp(name, "size_w"))
1786                {
1787                   static const Edje_External_Param_Info pi =
1788                     EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_size_w");
1789                   return &pi;
1790                }
1791              if (!strcmp(name, "size_h"))
1792                {
1793                   static const Edje_External_Param_Info pi =
1794                     EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_size_h");
1795                   return &pi;
1796                }
1797              if (!strcmp(name, "step_x"))
1798                {
1799                   static const Edje_External_Param_Info pi =
1800                     EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_step_x");
1801                   return &pi;
1802                }
1803              if (!strcmp(name, "step_y"))
1804                {
1805                   static const Edje_External_Param_Info pi =
1806                     EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_step_y");
1807                   return &pi;
1808                }
1809              if (!strcmp(name, "page_x"))
1810                {
1811                   static const Edje_External_Param_Info pi =
1812                     EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_page_x");
1813                   return &pi;
1814                }
1815              if (!strcmp(name, "page_y"))
1816                {
1817                   static const Edje_External_Param_Info pi =
1818                     EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_page_y");
1819                   return &pi;
1820                }
1821
1822              return NULL;
1823           }
1824      }
1825
1826    return NULL;
1827 }
1828
1829 static Edje_External_Param *
1830 _edje_param_convert(Edje_External_Param *param, const Edje_External_Param_Info *dst_info)
1831 {
1832    if (param->type == dst_info->type) return param;
1833
1834    switch (dst_info->type)
1835      {
1836       case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
1837       case EDJE_EXTERNAL_PARAM_TYPE_INT:
1838         {
1839            int i;
1840            switch (param->type)
1841              {
1842               case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
1843                  i = (int)param->d;
1844                  break;
1845               case EDJE_EXTERNAL_PARAM_TYPE_STRING:
1846               case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
1847                  i = (param->s) ? atoi(param->s) : 0;
1848                  break;
1849               case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
1850               case EDJE_EXTERNAL_PARAM_TYPE_INT:
1851                  i = param->i;
1852                  break;
1853               default:
1854                  return NULL;
1855              }
1856            if (dst_info->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL)
1857              i = !!i;
1858            param->type = dst_info->type;
1859            param->i = i;
1860            return param;
1861         }
1862
1863       case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
1864         {
1865            double d;
1866            switch (param->type)
1867              {
1868               case EDJE_EXTERNAL_PARAM_TYPE_INT:
1869                  d = (double)param->i;
1870                  break;
1871               case EDJE_EXTERNAL_PARAM_TYPE_STRING:
1872               case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
1873                  d = (param->s) ? atof(param->s) : 0.0;
1874                  break;
1875               case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
1876                  d = (double)param->i;
1877                  break;
1878               default:
1879                  return NULL;
1880              }
1881            param->type = dst_info->type;
1882            param->d = d;
1883            return param;
1884         }
1885
1886       case EDJE_EXTERNAL_PARAM_TYPE_STRING:
1887         {
1888            static char s[64];
1889            switch (param->type)
1890              {
1891               case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
1892               case EDJE_EXTERNAL_PARAM_TYPE_INT:
1893                  if (!snprintf(s, sizeof(s), "%i", param->i)) return NULL;
1894                  break;
1895               case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
1896                  if (!snprintf(s, sizeof(s), "%f", param->d)) return NULL;
1897                  break;
1898               case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
1899                  param->type = dst_info->type;
1900                  return param;
1901               default:
1902                  return NULL;
1903              }
1904            param->type = dst_info->type;
1905            param->s = s;
1906            return param;
1907         }
1908
1909       case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
1910         {
1911            static char s[64];
1912            const char *val;
1913            switch (param->type)
1914              {
1915               case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
1916               case EDJE_EXTERNAL_PARAM_TYPE_INT:
1917                  if (!snprintf(s, sizeof(s), "%i", param->i)) return NULL;
1918                  val = s;
1919                  break;
1920               case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
1921                  if (!snprintf(s, sizeof(s), "%f", param->d)) return NULL;
1922                  val = s;
1923                  break;
1924               case EDJE_EXTERNAL_PARAM_TYPE_STRING:
1925                  val = param->s;
1926                  break;
1927               default:
1928                  return NULL;
1929              }
1930
1931            param->type = dst_info->type;
1932            if (param->s != val) param->s = val;
1933            return param;
1934         }
1935
1936       default: return NULL;
1937      }
1938 }
1939
1940 static Eina_Bool
1941 _edje_param_validate(const Edje_External_Param *param, const Edje_External_Param_Info *info)
1942 {
1943    switch (info->type)
1944      {
1945       case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
1946          return ((param->i == 0) || (param->i == 1));
1947
1948       case EDJE_EXTERNAL_PARAM_TYPE_INT:
1949          if ((info->info.i.min != EDJE_EXTERNAL_INT_UNSET) &&
1950              (info->info.i.min > param->i))
1951            return EINA_FALSE;
1952
1953          if ((info->info.i.max != EDJE_EXTERNAL_INT_UNSET) &&
1954              (info->info.i.max < param->i))
1955            return EINA_FALSE;
1956
1957          return EINA_TRUE;
1958
1959       case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
1960          if ((info->info.d.min != EDJE_EXTERNAL_DOUBLE_UNSET) &&
1961              (info->info.d.min > param->d))
1962            return EINA_FALSE;
1963
1964          if ((info->info.d.max != EDJE_EXTERNAL_DOUBLE_UNSET) &&
1965              (info->info.d.max < param->d))
1966            return EINA_FALSE;
1967
1968          return EINA_TRUE;
1969
1970       case EDJE_EXTERNAL_PARAM_TYPE_STRING:
1971          if (!param->s) return EINA_FALSE;
1972          if (info->info.s.accept_fmt)
1973            INF("string 'accept_fmt' validation not implemented.");
1974          if (info->info.s.deny_fmt)
1975            INF("string 'deny_fmt' validation not implemented.");
1976          return EINA_TRUE;
1977
1978       case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
1979         {
1980            const char **itr = info->info.c.choices;
1981            if (!itr) return EINA_FALSE;
1982            for (; *itr; itr++)
1983              if (!strcmp(*itr, param->s))
1984                return EINA_TRUE;
1985            return EINA_FALSE;
1986         }
1987
1988       default: return EINA_FALSE;
1989      }
1990 }
1991
1992 static void
1993 _edje_param_copy(Edje_Real_Part *src_part, const char *src_param, Edje_Real_Part *dst_part, const char *dst_param)
1994 {
1995    Edje_External_Param val;
1996    const Edje_External_Param_Info *dst_info;
1997    void *free_ptr = NULL;
1998
1999    if ((!src_part) || (!src_param) || (!dst_part) || (!dst_param))
2000      return;
2001
2002    if ((dst_part->part->type == EDJE_PART_TYPE_EXTERNAL) &&
2003        (dst_part->type == EDJE_RP_TYPE_SWALLOW) &&
2004        (dst_part->typedata.swallow))
2005      dst_info = _edje_external_param_info_get
2006        (dst_part->typedata.swallow->swallowed_object, dst_param);
2007    else
2008      dst_info = _edje_native_param_info_get(dst_part, dst_param);
2009
2010    if (!dst_info)
2011      {
2012         ERR("cannot copy, invalid destination parameter '%s' of part '%s'",
2013             dst_param, dst_part->part->name);
2014         return;
2015      }
2016
2017    if (src_part->part->type == EDJE_PART_TYPE_EXTERNAL)
2018      {
2019         if (!_edje_param_external_get
2020             (src_part, src_param, &val))
2021           {
2022              ERR("cannot get parameter '%s' of part '%s'",
2023                  src_param, src_part->part->name);
2024              return;
2025           }
2026      }
2027    else
2028      {
2029         if (!_edje_param_native_get(src_part, src_param, &val, &free_ptr))
2030           {
2031              ERR("cannot get parameter '%s' of part '%s'",
2032                  src_param, src_part->part->name);
2033              return;
2034           }
2035      }
2036
2037    if (!_edje_param_convert(&val, dst_info))
2038      {
2039         ERR("cannot convert parameter type %s to requested type %s",
2040             edje_external_param_type_str(val.type),
2041             edje_external_param_type_str(dst_info->type));
2042         goto end;
2043      }
2044
2045    if (!_edje_param_validate(&val, dst_info))
2046      {
2047         ERR("incorrect parameter value failed validation for type %s",
2048             edje_external_param_type_str(dst_info->type));
2049         goto end;
2050      }
2051
2052    if (dst_part->part->type == EDJE_PART_TYPE_EXTERNAL)
2053      {
2054         val.name = dst_param;
2055         if (!_edje_external_param_set(NULL, dst_part, &val))
2056           {
2057              ERR("failed to set parameter '%s' (%s) of part '%s'",
2058                  dst_param, edje_external_param_type_str(dst_info->type),
2059                  dst_part->part->name);
2060              goto end;
2061           }
2062      }
2063    else
2064      {
2065         if (!_edje_param_native_set(dst_part, dst_param, &val))
2066           {
2067              ERR("failed to set parameter '%s' (%s) of part '%s'",
2068                  dst_param, edje_external_param_type_str(dst_info->type),
2069                  dst_part->part->name);
2070              goto end;
2071           }
2072      }
2073
2074  end:
2075    free(free_ptr);
2076 }
2077
2078 static void
2079 _edje_param_set(Edje_Real_Part *part, const char *param, const char *value)
2080 {
2081    Edje_External_Param val;
2082    const Edje_External_Param_Info *info;
2083
2084    if ((!part) || (!param) || (!value))
2085      return;
2086
2087    if ((part->part->type == EDJE_PART_TYPE_EXTERNAL) &&
2088        (part->type == EDJE_RP_TYPE_SWALLOW) &&
2089        (part->typedata.swallow))
2090      info = _edje_external_param_info_get(part->typedata.swallow->swallowed_object, param);
2091    else
2092      info = _edje_native_param_info_get(part, param);
2093
2094    if (!info)
2095      {
2096         ERR("cannot copy, invalid destination parameter '%s' of part '%s'",
2097             param, part->part->name);
2098         return;
2099      }
2100
2101    val.name = "(temp)";
2102    val.type = EDJE_EXTERNAL_PARAM_TYPE_STRING;
2103    val.s = value;
2104
2105    if (!_edje_param_convert(&val, info))
2106      {
2107         ERR("cannot convert parameter type STRING to requested type %s",
2108             edje_external_param_type_str(info->type));
2109         return;
2110      }
2111
2112    if (!_edje_param_validate(&val, info))
2113      {
2114         ERR("incorrect parameter value failed validation for type %s",
2115             edje_external_param_type_str(info->type));
2116         return;
2117      }
2118
2119    if (part->part->type == EDJE_PART_TYPE_EXTERNAL)
2120      {
2121         val.name = param;
2122         if (!_edje_external_param_set(NULL, part, &val))
2123           {
2124              ERR("failed to set parameter '%s' (%s) of part '%s'",
2125                  param, edje_external_param_type_str(info->type),
2126                  part->part->name);
2127              return;
2128           }
2129      }
2130    else
2131      {
2132         if (!_edje_param_native_set(part, param, &val))
2133           {
2134              ERR("failed to set parameter '%s' (%s) of part '%s'",
2135                  param, edje_external_param_type_str(info->type),
2136                  part->part->name);
2137              return;
2138           }
2139      }
2140 }