Do not layer up for restack_show effect
[platform/core/uifw/e-mod-tizen-effect.git] / src / e_mod_effect.c
1 #include "e_mod_effect.h"
2
3 static E_Effect *_eff = NULL;
4
5 typedef struct _E_Effect_Client
6 {
7    E_Client *ec;
8    unsigned int animating;
9    E_Comp_Wl_Buffer_Ref buffer_ref;
10    E_Pixmap *ep;
11    E_Client *reverse_ec;
12 } E_Effect_Client;
13
14 static void
15 _eff_event_send(E_Client *ec, Eina_Bool start, E_Effect_Type type)
16 {
17    struct wl_resource *res_surf;
18    struct wl_resource *res_eff;
19    struct wl_client *wc;
20    unsigned int tizen_effect_type = TIZEN_EFFECT_TYPE_NONE;
21
22    if (!_eff) return;
23    if ((!ec) || (!ec->comp_data)) return;
24    if (e_object_is_del(E_OBJECT(ec))) return;
25
26    res_surf = ec->comp_data->surface;
27    if (!res_surf) return;
28
29    wc = wl_resource_get_client(res_surf);
30    if (!wc) return;
31
32    res_eff = eina_hash_find(_eff->resources, &wc);
33    if (!res_eff) return;
34
35    switch(type)
36      {
37       case E_EFFECT_TYPE_SHOW:
38          tizen_effect_type = TIZEN_EFFECT_TYPE_SHOW;
39          break;
40       case E_EFFECT_TYPE_HIDE:
41          tizen_effect_type = TIZEN_EFFECT_TYPE_HIDE;
42          break;
43       case E_EFFECT_TYPE_RESTACK_SHOW:
44       case E_EFFECT_TYPE_RESTACK_HIDE:
45          tizen_effect_type = TIZEN_EFFECT_TYPE_RESTACK;
46          break;
47       default:
48          ERR("Unsupported effect type: %d for %p", type, ec);
49          return;
50      }
51
52    EFFINF("SEND %.5s|type:%d|win:0x%08x|tz_effect:0x%08x",
53           ec->pixmap, ec,
54           start ? "START" : "END", type,
55           (unsigned int)e_client_util_win_get(ec),
56           (unsigned int)res_eff);
57
58    if (start)
59      tizen_effect_send_start(res_eff, res_surf, tizen_effect_type);
60    else
61      {
62         tizen_effect_send_end(res_eff, res_surf, tizen_effect_type);
63
64         EFFINF("Un-SET EXTRA_ANIMATING...", ec->pixmap, ec);
65         ec->extra_animating = EINA_FALSE;
66         if (ec->launching == EINA_TRUE)
67           {
68              ec->launching = EINA_FALSE;
69              e_comp_object_signal_emit(ec->frame, "e,action,launch,done", "e");
70           }
71      }
72 }
73
74 static E_Effect_Client*
75 _eff_client_new(E_Client *ec)
76 {
77    E_Effect_Client *efc;
78
79    efc = E_NEW(E_Effect_Client, 1);
80    efc->ec = ec;
81    efc->animating = 0;
82    efc->ep = NULL;
83
84    return efc;
85 }
86
87 static E_Effect_Client *
88 _eff_client_get(E_Client *ec)
89 {
90    if (!_eff) return NULL;
91    return eina_hash_find(_eff->clients, &ec);
92 }
93
94 static E_Effect_Group
95 _eff_group_get(E_Client *ec)
96 {
97    E_Effect_Group group = E_EFFECT_GROUP_NORMAL;
98
99    /* animatable setting by aux_hint */
100    if (!ec->animatable) return E_EFFECT_GROUP_NONE;
101
102    /* client_type */
103    switch (ec->client_type)
104      {
105       case 1: //homescreen
106          group = E_EFFECT_GROUP_HOME;
107          break;
108       case 2: //lockscreen
109          group = E_EFFECT_GROUP_LOCKSCREEN;
110          break;
111       default:
112          break;
113      }
114
115    /* client layer */
116    if (group == E_EFFECT_GROUP_NORMAL)
117      {
118         if (ec->layer > E_LAYER_CLIENT_NORMAL)
119           group = E_EFFECT_GROUP_NONE;
120      }
121
122    /* window_role */
123
124    /* etc */
125    if (ec->vkbd.vkbd)
126      group = E_EFFECT_GROUP_KEYBOARD;
127
128    return group;
129 }
130
131 static int
132 _eff_group_angle_get(E_Client *ec, E_Effect_Group group)
133 {
134    if (group == E_EFFECT_GROUP_KEYBOARD)
135      {
136         if (ec->parent)
137           return ec->parent->e.state.rot.ang.curr;
138      }
139
140    return ec->e.state.rot.ang.curr;
141 }
142
143 static Eina_Bool
144 _eff_ref(E_Client *ec)
145 {
146    E_Effect_Client *efc;
147
148    if (!_eff) return EINA_FALSE;
149
150    if (e_object_is_del(E_OBJECT(ec)))
151      {
152         ERR("Client is deleted already! ec(%p)", ec);
153         eina_hash_del_by_key(_eff->clients, &ec);
154         return EINA_FALSE;
155      }
156
157    efc = _eff_client_get(ec);
158    if (!efc) return EINA_FALSE;
159
160    if (!ec->pixmap) return EINA_FALSE;
161    if ((e_comp_object_content_type_get(ec->frame) == E_COMP_OBJECT_CONTENT_TYPE_INT_IMAGE) &&
162        (!e_pixmap_usable_get(ec->pixmap)))
163      return EINA_FALSE;
164
165    efc->animating++;
166    e_object_ref(E_OBJECT(ec));
167    efc->ep = e_pixmap_ref(ec->pixmap);
168
169    EFFINF("effect ref efc(%p) animating:%d",
170           efc->ep, efc->ec, efc, efc->animating);
171
172    return EINA_TRUE;
173 }
174
175 static E_Client *
176 _eff_unref(E_Client *ec)
177 {
178    E_Effect_Client *efc;
179    int do_unref = 1;
180
181    if (!_eff) return NULL;
182    if (!ec) return NULL;
183
184    efc = _eff_client_get(ec);
185    if (!efc) return NULL;
186
187    if (e_object_is_del(E_OBJECT(ec)))
188      do_unref = efc->animating;
189
190    efc->animating -= do_unref;
191    while (do_unref)
192      {
193         e_pixmap_free(efc->ep);
194         if (!e_object_unref(E_OBJECT(ec)))
195           {
196              EFFINF("eff unref ec(%p) ep(%p) efc(%p) Client free'd",
197                     NULL, NULL, ec, efc->ep, efc);
198
199              efc->ec = NULL;
200              efc = NULL;
201              eina_hash_del_by_key(_eff->clients, &ec);
202              return NULL;
203           }
204         do_unref --;
205      }
206
207    EFFINF("eff Unref efc(%p) animating:%d",
208           ec->pixmap, ec, efc, efc->animating);
209
210    /* The reference count of wl_buffer will get decremented
211     * immediately after window effect.
212     */
213    if ((efc) && (efc->buffer_ref.buffer))
214      e_comp_wl_buffer_reference(&efc->buffer_ref, NULL);
215
216    return ec;
217 }
218
219 static void
220 _eff_object_setup(E_Client *ec, E_Effect_Group group)
221 {
222    E_Comp_Config *cfg;
223    cfg = e_comp_config_get();
224
225    if (group == E_EFFECT_GROUP_KEYBOARD)
226      e_comp_object_effect_set(ec->frame, "keyboard");
227    else
228      {
229         if ((cfg) && (cfg->effect_style))
230           e_comp_object_effect_set(ec->frame, cfg->effect_style);
231         else
232           e_comp_object_effect_set(ec->frame, "no-effect");
233      }
234 }
235
236 static void
237 _eff_object_layer_up(E_Client *ec)
238 {
239    int map_ly;
240
241    map_ly = e_comp_canvas_client_layer_map(ec->layer);
242    if (map_ly == 9999) return;
243
244    if (!_eff->layers[map_ly].obj)
245      {
246         _eff->layers[map_ly].obj = evas_object_rectangle_add(e_comp->evas);
247         evas_object_layer_set(_eff->layers[map_ly].obj, ec->layer + 1);
248         evas_object_name_set(_eff->layers[map_ly].obj, "layer_obj(effect)");
249      }
250
251    ec->layer_pending = 1;
252    evas_object_layer_set(ec->frame, ec->layer + 1);
253 }
254
255 static void
256 _eff_object_layer_down(E_Client *ec)
257 {
258    evas_object_layer_set(ec->frame, ec->layer);
259    ec->layer_pending = 0;
260 }
261
262 static void
263 _eff_pending_effect_start(void)
264 {
265    E_Client *ec;
266
267    ec = _eff->next_done.ec;
268    if (!ec) return;
269
270    EFFINF("Pending eff Start type(%d)",
271           ec->pixmap, ec, _eff->next_done.type);
272
273    if (_eff->next_done.cb)
274      {
275         _eff_event_send(ec, EINA_TRUE, _eff->next_done.type);
276         e_comp_object_effect_start(ec->frame,
277                                    _eff->next_done.cb,
278                                    _eff->next_done.data);
279      }
280
281    memset(&_eff->next_done, 0, sizeof(_eff->next_done));
282 }
283
284 static void
285 _eff_pending_effect_set(E_Client *ec, void *data, E_Effect_Type type, Edje_Signal_Cb done_cb)
286 {
287    _eff_pending_effect_start();
288
289    EFFINF("Pending eff Set type(%d)",
290           ec->pixmap, ec, type);
291
292    _eff->next_done.cb = done_cb;
293    _eff->next_done.ec = ec;
294    _eff->next_done.data = data;
295    _eff->next_done.type = type;
296 }
297
298 static void
299 _eff_stack_update(void)
300 {
301    E_Client *ec;
302    Evas_Object *o;
303
304    if (!_eff) return;
305
306    _eff->stack.old = eina_list_free(_eff->stack.old);
307    _eff->stack.old = eina_list_clone(_eff->stack.cur);
308
309    for (o = evas_object_top_get(e_comp->evas); o; o = evas_object_below_get(o))
310      {
311         ec = evas_object_data_get(o, "E_Client");
312         if (!ec) continue;
313         if (e_client_util_ignored_get(ec)) continue;
314         if (e_object_is_del(E_OBJECT(ec))) continue;
315
316         _eff->stack.cur = eina_list_remove(_eff->stack.cur, ec);
317         _eff->stack.cur = eina_list_append(_eff->stack.cur, ec);
318      }
319 }
320
321 static Eina_Bool
322 _eff_visibility_stack_check(E_Client *ec, Eina_List *stack)
323 {
324    Eina_List *l;
325    E_Client *_ec;
326    Eina_Tiler *tiler;
327    Eina_Rectangle r;
328    Eina_Bool vis = EINA_TRUE;
329    int x, y, w, h;
330
331    if (!stack) return EINA_FALSE;
332
333    tiler = eina_tiler_new(ec->desk->geom.w, ec->desk->geom.h);
334    eina_tiler_tile_size_set(tiler, 1, 1);
335    EINA_RECTANGLE_SET(&r, ec->desk->geom.x, ec->desk->geom.y, ec->desk->geom.w, ec->desk->geom.h);
336    eina_tiler_rect_add(tiler, &r);
337
338    EINA_LIST_FOREACH(stack, l, _ec)
339      {
340         if (_ec == ec) break;
341         if (!_ec->visible) continue;
342         if (!evas_object_visible_get(_ec->frame))
343           {
344              if (!_ec->iconic) continue;
345              if (_ec->iconic && _ec->exp_iconify.by_client) continue;
346           }
347         if (!e_pixmap_resource_get(_ec->pixmap)) continue;
348
349         e_client_geometry_get(_ec, &x, &y, &w, &h);
350
351         EINA_RECTANGLE_SET(&r, x, y, w, h);
352         eina_tiler_rect_del(tiler, &r);
353
354         if (eina_tiler_empty(tiler))
355           {
356              vis = EINA_FALSE;
357              break;
358           }
359      }
360    eina_tiler_free(tiler);
361
362    return vis;
363 }
364
365 static const char *
366 _eff_restack_effect_check(E_Client *ec)
367 {
368    const char *emission = NULL;
369    Eina_Bool v1, v2;
370    E_Effect_Client *efc;
371
372    if (!evas_object_visible_get(ec->frame)) return NULL;
373    if (ec->new_client) return NULL;
374
375    v1 = _eff_visibility_stack_check(ec, _eff->stack.old);
376    v2 = _eff_visibility_stack_check(ec, _eff->stack.cur);
377
378    if (v1 != v2)
379      {
380         if ((v2) && (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED))
381           emission = "e,action,restack,show";
382         else if ((!v2) && (ec->visibility.obscured == E_VISIBILITY_UNOBSCURED))
383           emission = "e,action,restack,hide";
384      }
385    else
386      {
387         efc = _eff_client_get(ec);
388
389         // TODO : it's for transients windows. wish using other check */
390         if ((efc) && (!efc->animating))
391           {
392              if ((v2) && (!ec->iconic) &&
393                  (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED))
394                emission = "e,action,restack,show";
395              else if ((!v2) && (ec->iconic) &&
396                       (ec->visibility.obscured == E_VISIBILITY_UNOBSCURED))
397                emission = "e,action,restack,hide";
398           }
399      }
400
401    EFFINF("Restack eff Check v1(%d) -> v2(%d) iconic:%d "
402           "obscured:%d(%d) emission:%s",
403           ec->pixmap, ec,
404           v1, v2, ec->iconic,
405           ec->visibility.obscured, ec->visibility.changed, emission);
406
407    return emission;
408 }
409
410 static void
411 _eff_cb_visible_done(void *data, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
412 {
413    E_Client *ec = (E_Client *)data;
414
415    if (ec)
416      {
417         _eff_event_send(ec, EINA_FALSE, E_EFFECT_TYPE_SHOW);
418         _eff_unref(ec);
419      }
420
421    _eff_stack_update();
422    e_comp_override_del();
423 }
424
425 static Eina_Bool
426 _eff_cb_visible(void *data, Evas_Object *obj, const char *signal)
427 {
428    E_Client *ec;
429    E_Effect_Group group;
430    int ang = -1;
431
432    if (!_eff) return EINA_FALSE;
433
434    ec = e_comp_object_client_get(obj);
435    if (!ec) return EINA_FALSE;
436    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
437
438    group = _eff_group_get(ec);
439    if ((group != E_EFFECT_GROUP_NORMAL) &&
440        (group != E_EFFECT_GROUP_KEYBOARD)) return EINA_FALSE;
441
442    if (evas_object_visible_get(obj)) return EINA_FALSE;
443    if (!_eff_ref(ec)) return EINA_FALSE;
444
445    e_comp_override_add();
446
447    EFFINF("SET EXTRA_ANIMATING...", ec->pixmap, ec);
448    ec->extra_animating = EINA_TRUE;
449
450    _eff_object_setup(ec, group);
451    ang = _eff_group_angle_get(ec, group);
452    e_comp_object_effect_params_set(ec->frame, 0, (int[]){0, ang}, 2);
453    if (e_comp->nocomp)
454      {
455         _eff_pending_effect_set(ec,
456                                 (void *)ec,
457                                 E_EFFECT_TYPE_SHOW,
458                                 _eff_cb_visible_done);
459         return EINA_TRUE;
460      }
461
462    _eff_event_send(ec, EINA_TRUE, E_EFFECT_TYPE_SHOW);
463
464    e_comp_object_effect_start(ec->frame, _eff_cb_visible_done, ec);
465
466    return EINA_TRUE;
467 }
468
469 static void
470 _eff_cb_hidden_done(void *data, Evas_Object *obj, const char *sig, const char *src)
471 {
472    E_Client *ec = (E_Client *)data;
473
474    if (ec)
475      {
476         _eff_event_send(ec, EINA_FALSE, E_EFFECT_TYPE_HIDE);
477         if (_eff_unref(ec))
478           {
479              if (_eff_client_get(ec))
480                {
481                   _eff_object_layer_down(ec);
482                   evas_object_hide(ec->frame);
483                }
484           }
485      }
486
487    e_comp_override_del();
488 }
489
490 static Eina_Bool
491 _eff_cb_hidden(void *data, Evas_Object *obj, const char *signal)
492 {
493    E_Client *ec;
494    E_Effect_Group group;
495    Eina_Bool lowered = 0;
496    Evas_Object *below;
497    int map_ly;
498    int ang = -1;
499
500    if (!_eff) return EINA_FALSE;
501
502    ec = e_comp_object_client_get(obj);
503    if (!ec) return EINA_FALSE;
504    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
505
506    /* check for effect group */
507    group = _eff_group_get(ec);
508    if ((group != E_EFFECT_GROUP_NORMAL) &&
509        (group != E_EFFECT_GROUP_KEYBOARD)) return EINA_FALSE;
510
511    if (group == E_EFFECT_GROUP_KEYBOARD)
512      {
513         if (ec->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED)
514           return EINA_FALSE;
515      }
516
517    if (!evas_object_visible_get(obj)) return EINA_FALSE;
518    if (!_eff_ref(ec)) return EINA_FALSE;
519
520    e_comp_override_add();
521
522    // check if client was lowered
523    below = evas_object_below_get(obj);
524    map_ly = e_comp_canvas_layer_map(evas_object_layer_get(obj));
525    if ((below) && (map_ly != 9999) &&
526        (evas_object_layer_get(below) != evas_object_layer_get(obj)) &&
527        (evas_object_above_get(obj) != e_comp->layers[map_ly].obj))
528      lowered = 1;
529
530    if (lowered)
531      _eff_object_layer_up(ec);
532
533    _eff_object_setup(ec, group);
534    ang = _eff_group_angle_get(ec, group);
535    e_comp_object_effect_params_set(ec->frame, 0, (int[]){1, ang}, 2);
536
537    if (e_comp->nocomp)
538      {
539         _eff_pending_effect_set(ec,
540                                 (void *)ec,
541                                 E_EFFECT_TYPE_HIDE,
542                                 _eff_cb_hidden_done);
543         return EINA_TRUE;
544      }
545
546    _eff_event_send(ec, EINA_TRUE, E_EFFECT_TYPE_HIDE);
547    e_comp_object_effect_start(ec->frame, _eff_cb_hidden_done, ec);
548
549    return EINA_TRUE;
550 }
551
552 static void
553 _eff_cb_uniconify_done(void *data, Evas_Object *obj, const char *sig, const char *src)
554 {
555    E_Client *ec = (E_Client *)data;
556
557    if (ec)
558      {
559         _eff_event_send(ec, EINA_FALSE, E_EFFECT_TYPE_SHOW);
560         _eff_unref(ec);
561      }
562
563    e_comp_override_del();
564 }
565
566 static Eina_Bool
567 _eff_cb_uniconify(void *data, Evas_Object *obj, const char *signal)
568 {
569    E_Client *ec;
570    E_Effect_Group group;
571    Eina_Bool v1, v2;
572    int ang = -1;
573
574    if (!_eff) return EINA_FALSE;
575
576    ec = e_comp_object_client_get(obj);
577    if (!ec) return EINA_FALSE;
578    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
579
580    if (evas_object_visible_get(obj)) return EINA_FALSE;
581
582    group = _eff_group_get(ec);
583
584    /* for HOME group */
585    if (group == E_EFFECT_GROUP_HOME)
586      {
587         E_Client *below;
588
589         v1 = _eff_visibility_stack_check(ec, _eff->stack.old);
590         v2 = _eff_visibility_stack_check(ec, _eff->stack.cur);
591
592         EFFINF("Uniconify eff Check v1(%d) -> v2(%d) obscured:%d changed:%d",
593                ec->pixmap, ec,
594                v1, v2, ec->visibility.obscured, ec->visibility.changed);
595
596         if (v1 == v2) return EINA_FALSE;
597         if ((v2) && (ec->visibility.obscured == E_VISIBILITY_UNOBSCURED)) return EINA_FALSE;
598         if ((!v2) && (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED)) return EINA_FALSE;
599
600         below = e_client_below_get(ec);
601         while (below)
602           {
603              if ((evas_object_visible_get(below->frame)) &&
604                  (below->layer == ec->layer) &&
605                  ((below->visibility.obscured == E_VISIBILITY_UNOBSCURED) ||
606                   (below->visibility.changed)))
607                break;
608
609              below = e_client_below_get(below);
610           }
611
612         if (!below) return EINA_FALSE;
613         group = _eff_group_get(below);
614         if (group != E_EFFECT_GROUP_NORMAL) return EINA_FALSE;
615
616         EFFINF("Uniconify HOME group do hide eff of %p",
617                ec->pixmap, ec, below);
618
619         e_comp_object_signal_emit(below->frame, "e,action,restack,hide", "e");
620         return EINA_TRUE;
621      }
622    /* for NORMAL and KEYBOARD group */
623    else if ((group == E_EFFECT_GROUP_NORMAL) ||
624             (group == E_EFFECT_GROUP_KEYBOARD))
625      {
626         v1 = _eff_visibility_stack_check(ec, _eff->stack.old);
627         v2 = _eff_visibility_stack_check(ec, _eff->stack.cur);
628
629         EFFINF("Uniconify eff Check v1(%d) -> v2(%d) obscured:%d changed:%d",
630                ec->pixmap, ec,
631                v1, v2, ec->visibility.obscured, ec->visibility.changed);
632
633         if (v1 == v2) return EINA_FALSE;
634         if ((v2) && (ec->visibility.obscured == E_VISIBILITY_UNOBSCURED)) return EINA_FALSE;
635         if ((!v2) && (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED)) return EINA_FALSE;
636
637         if (!_eff_ref(ec)) return EINA_FALSE;
638
639         e_comp_override_add();
640
641         _eff_object_setup(ec, group);
642         ang = _eff_group_angle_get(ec, group);
643         e_comp_object_effect_params_set(ec->frame, 0, (int[]){0, ang}, 2);
644
645         if (e_comp->nocomp)
646           {
647              _eff_pending_effect_set(ec,
648                                      (void *)ec,
649                                      E_EFFECT_TYPE_SHOW,
650                                      _eff_cb_uniconify_done);
651              return EINA_TRUE;
652           }
653
654         _eff_event_send(ec, EINA_TRUE, E_EFFECT_TYPE_SHOW);
655         e_comp_object_effect_start(ec->frame, _eff_cb_uniconify_done, ec);
656         return EINA_TRUE;
657      }
658
659    return EINA_FALSE;
660 }
661
662 static void
663 _eff_cb_iconify_done(void *data, Evas_Object *obj, const char *sig, const char *src)
664 {
665    E_Client *ec = (E_Client *)data;
666
667    if (ec)
668      {
669         _eff_event_send(ec, EINA_FALSE, E_EFFECT_TYPE_HIDE);
670         if (_eff_unref(ec))
671           {
672              if (_eff_client_get(ec))
673                evas_object_hide(ec->frame);
674           }
675      }
676
677    e_comp_override_del();
678 }
679
680 static Eina_Bool
681 _eff_cb_iconify(void *data, Evas_Object *obj, const char *signal)
682 {
683    E_Client *ec;
684    E_Effect_Group group;
685    Eina_Bool v1, v2;
686    int ang = -1;
687
688    if (!_eff) return EINA_FALSE;
689
690    ec = e_comp_object_client_get(obj);
691    if (!ec) return EINA_FALSE;
692    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
693
694    group = _eff_group_get(ec);
695    if ((group != E_EFFECT_GROUP_NORMAL) &&
696        (group != E_EFFECT_GROUP_KEYBOARD)) return EINA_FALSE;
697
698    if (!evas_object_visible_get(obj)) return EINA_FALSE;
699
700    v1 = _eff_visibility_stack_check(ec, _eff->stack.old);
701    v2 = _eff_visibility_stack_check(ec, _eff->stack.cur);
702
703    EFFINF("Iconify eff Check v1(%d) -> v2(%d) obscured:%d changed:%d",
704           ec->pixmap, ec,
705           v1, v2, ec->visibility.obscured, ec->visibility.changed);
706
707    if (v1 == v2) return EINA_FALSE;
708    if ((v2) && (ec->visibility.obscured == E_VISIBILITY_UNOBSCURED)) return EINA_FALSE;
709    if ((!v2) && (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED)) return EINA_FALSE;
710
711    if (!_eff_ref(ec)) return EINA_FALSE;
712
713    e_comp_override_add();
714
715    _eff_object_setup(ec, group);
716    ang = _eff_group_angle_get(ec, group);
717    e_comp_object_effect_params_set(ec->frame, 0, (int[]){1, ang}, 2);
718
719    if (e_comp->nocomp)
720      {
721         _eff_pending_effect_set(ec,
722                                 (void *)ec,
723                                 E_EFFECT_TYPE_HIDE,
724                                 _eff_cb_iconify_done);
725         return EINA_TRUE;
726      }
727
728    _eff_event_send(ec, EINA_TRUE, E_EFFECT_TYPE_HIDE);
729    e_comp_object_effect_start(ec->frame, _eff_cb_iconify_done, ec);
730
731    return EINA_TRUE;
732 }
733
734 static void
735 _eff_cb_restack_show_done(void *data, Evas_Object *obj, const char *sig, const char *src)
736 {
737    E_Client *ec = (E_Client *)data;
738
739    if (ec)
740      {
741         _eff_event_send(ec, EINA_FALSE, E_EFFECT_TYPE_RESTACK_SHOW);
742         _eff_unref(ec);
743      }
744
745    _eff_stack_update();
746    e_comp_override_del();
747 }
748
749 static void
750 _eff_cb_restack_hide_done(void *data, Evas_Object *obj, const char *sig, const char *src)
751 {
752    E_Client *ec = (E_Client *)data;
753
754    if (ec)
755      {
756         if (_eff_unref(ec))
757           {
758              if (_eff_client_get(ec))
759                {
760                   _eff_object_layer_down(ec);
761                   e_comp_object_signal_emit(ec->frame,
762                                             "e,action,restack,finish",
763                                             "e");
764                }
765           }
766      }
767
768    _eff_stack_update();
769    e_comp_override_del();
770 }
771
772 static void
773 _eff_cb_restack_finish_done(void *data, Evas_Object *obj, const char *sig, const char *src)
774 {
775    E_Client *ec = (E_Client *)data;
776    E_Effect_Client *efc = NULL;
777
778    if (ec)
779      {
780         _eff_event_send(ec, EINA_FALSE, E_EFFECT_TYPE_RESTACK_HIDE);
781         efc = _eff_client_get(ec);
782         if (efc && efc->reverse_ec)
783           {
784              E_Client *ec_home = efc->reverse_ec;
785              if (ec_home->extra_animating)
786                {
787                   ec_home->extra_animating = EINA_FALSE;
788                   if (ec_home->launching == EINA_TRUE)
789                     {
790                        ec_home->launching = EINA_FALSE;
791                        e_comp_object_signal_emit(ec_home->frame, "e,action,launch,done", "e");
792                     }
793                   _eff_unref(ec_home);
794                }
795           }
796
797         _eff_unref(ec);
798      }
799
800    e_comp_override_del();
801 }
802
803 static Eina_Bool
804 _eff_cb_restack(void *data, Evas_Object *obj, const char *signal)
805 {
806    E_Client *ec;
807    E_Effect_Group group;
808    const char *emission;
809    E_Client *ec_home = NULL;
810    int ang = -1;
811
812    if (!_eff) return EINA_FALSE;
813
814    ec = e_comp_object_client_get(obj);
815    if (!ec) return EINA_FALSE;
816    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
817
818    group = _eff_group_get(ec);
819    emission = eina_stringshare_add(signal);
820
821    /* for HOME group: replace eff target client */
822    if (group == E_EFFECT_GROUP_HOME)
823      {
824         E_Client *below;
825
826         below = e_client_below_get(ec);
827         while (below)
828           {
829              if ((!e_object_is_del(E_OBJECT(below))) &&
830                  (evas_object_visible_get(below->frame)) &&
831                  (below->visibility.obscured == E_VISIBILITY_UNOBSCURED) &&
832                  (below->layer == ec->layer))
833                break;
834
835              below = e_client_below_get(below);
836           }
837
838         if (!below) return EINA_FALSE;
839         if (e_util_strcmp(signal, "e,action,restack,show")) return EINA_FALSE;
840
841         ec_home = ec;
842         ec = below;
843         group = _eff_group_get(ec);
844         if (group != E_EFFECT_GROUP_NORMAL) return EINA_FALSE;
845
846         if (emission) eina_stringshare_del(emission);
847         emission = eina_stringshare_add("e,action,restack,hide");
848      }
849
850    if ((group != E_EFFECT_GROUP_NORMAL) &&
851        (group != E_EFFECT_GROUP_KEYBOARD)) return EINA_FALSE;
852
853    if ((!e_util_strcmp(emission, "e,action,restack,show")))
854      {
855         if (!_eff_ref(ec)) return EINA_FALSE;
856
857         EFFINF("SET EXTRA_ANIMATING...", ec->pixmap, ec);
858         ec->extra_animating = EINA_TRUE;
859
860         e_comp_override_add();
861
862         _eff_object_setup(ec, group);
863         ang = _eff_group_angle_get(ec, group);
864         e_comp_object_effect_params_set(ec->frame, 0, (int[]){2, ang}, 2);
865
866         if (e_comp->nocomp)
867           {
868              _eff_pending_effect_set(ec,
869                                      (void *)ec,
870                                      E_EFFECT_TYPE_SHOW,
871                                      _eff_cb_restack_show_done);
872              return EINA_TRUE;
873           }
874
875         _eff_event_send(ec, EINA_TRUE, E_EFFECT_TYPE_RESTACK_SHOW);
876         e_comp_object_effect_start(ec->frame, _eff_cb_restack_show_done, ec);
877      }
878    else if (!e_util_strcmp(emission, "e,action,restack,hide"))
879      {
880         if (!_eff_ref(ec)) return EINA_FALSE;
881
882         if (ec_home)
883           {
884              E_Effect_Client *efc = NULL;
885              efc = _eff_client_get(ec);
886              if (efc)
887                {
888                   if (_eff_ref(ec_home))
889                     {
890                        EFFINF("SET EXTRA_ANIMATING...", ec_home->pixmap, ec_home);
891                        ec_home->extra_animating = EINA_TRUE;
892
893                        efc->reverse_ec = ec_home;
894
895                        EFFINF("SET EXTRA_ANIMATING...", ec->pixmap, ec);
896                        ec->extra_animating = EINA_TRUE;
897                     }
898                }
899           }
900
901         e_comp_override_add();
902
903         _eff_object_layer_up(ec);
904
905         _eff_object_setup(ec, group);
906         ang = _eff_group_angle_get(ec, group);
907         e_comp_object_effect_params_set(ec->frame, 0, (int[]){3, ang}, 2);
908
909         if (e_comp->nocomp)
910           {
911              _eff_pending_effect_set(ec,
912                                      (void *)ec,
913                                      E_EFFECT_TYPE_HIDE,
914                                      _eff_cb_restack_hide_done);
915              return EINA_TRUE;
916           }
917
918         _eff_event_send(ec, EINA_TRUE, E_EFFECT_TYPE_RESTACK_HIDE);
919         e_comp_object_effect_start(ec->frame, _eff_cb_restack_hide_done, ec);
920      }
921    else if (!e_util_strcmp(emission, "e,action,restack,finish"))
922      {
923         if (!_eff_ref(ec)) return EINA_FALSE;
924
925         e_comp_override_add();
926
927         _eff_object_setup(ec, group);
928         ang = _eff_group_angle_get(ec, group);
929         e_comp_object_effect_params_set(ec->frame, 0, (int[]){4, ang}, 2);
930
931         if (e_comp->nocomp)
932           {
933              _eff_pending_effect_set(ec,
934                                      (void *)ec,
935                                      E_EFFECT_TYPE_HIDE,
936                                      _eff_cb_restack_finish_done);
937              return EINA_TRUE;
938           }
939
940         e_comp_object_effect_start(ec->frame, _eff_cb_restack_finish_done, ec);
941      }
942
943    return EINA_TRUE;
944 }
945
946 static Eina_Bool
947 _eff_cb_launch(void *data, Evas_Object *obj, const char *signal)
948 {
949    E_Client *ec;
950    struct wl_resource *res_surf;
951    struct wl_resource *res_eff;
952    struct wl_client *wc;
953    unsigned int tizen_effect_type = 4;
954
955    if (!_eff) return EINA_FALSE;
956
957    ec = e_comp_object_client_get(obj);
958    if ((!ec) || (!ec->comp_data)) return EINA_FALSE;
959    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
960
961    res_surf = ec->comp_data->surface;
962    if (!res_surf) return EINA_FALSE;
963
964    wc = wl_resource_get_client(res_surf);
965    if (!wc) return EINA_FALSE;
966
967    res_eff = eina_hash_find(_eff->resources, &wc);
968    if (!res_eff) return EINA_FALSE;
969
970    EFFINF("SEND END  |type:LAUNCH|win:0x%08x|tz_effect:0x%08x",
971           ec->pixmap, ec,
972           (unsigned int)e_client_util_win_get(ec),
973           (unsigned int)res_eff);
974
975    tizen_effect_send_end(res_eff, res_surf, tizen_effect_type);
976
977    return EINA_TRUE;
978 }
979
980 static void
981 _eff_cb_hook_client_new(void *d EINA_UNUSED, E_Client *ec)
982 {
983    E_Effect_Client *efc;
984
985    if (!_eff) return;
986
987    efc = _eff_client_get(ec);
988    if (efc) return;
989
990    efc = _eff_client_new(ec);
991    if (efc)
992      eina_hash_add(_eff->clients, &ec, efc);
993 }
994
995 static void
996 _eff_cb_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
997 {
998    E_Effect_Client *efc = NULL;
999
1000    if (!_eff) return;
1001
1002    _eff->stack.old = eina_list_remove(_eff->stack.old, ec);
1003    _eff->stack.cur = eina_list_remove(_eff->stack.cur, ec);
1004
1005    if (_eff->next_done.ec == ec)
1006      memset(&_eff->next_done, 0, sizeof(_eff->next_done));
1007
1008    if ((efc = _eff_client_get(ec)))
1009      {
1010         if (!efc->animating)
1011           eina_hash_del_by_key(_eff->clients, &ec);
1012      }
1013 }
1014
1015 static Eina_Bool
1016 _eff_cb_client_restack(void *data, int type, void *event)
1017 {
1018    E_Client *ec;
1019    E_Event_Client *ev = event;
1020    const char *emission = NULL;
1021
1022    if (!_eff) return ECORE_CALLBACK_PASS_ON;
1023
1024    ec = ev->ec;
1025    if (!ec) return ECORE_CALLBACK_PASS_ON;
1026    if (e_object_is_del(E_OBJECT(ec))) return ECORE_CALLBACK_PASS_ON;
1027
1028    EFFINF("Client restacked", ec->pixmap, ec);
1029
1030    _eff_stack_update();
1031
1032    if (!_eff_client_get(ec)) return ECORE_CALLBACK_PASS_ON;
1033
1034    if ((emission = _eff_restack_effect_check(ec)))
1035      e_comp_object_signal_emit(ec->frame, emission, "e");
1036
1037    return ECORE_CALLBACK_PASS_ON;
1038 }
1039
1040 static Eina_Bool
1041 _eff_cb_comp_enabled(void *data, int ev_type, void *event)
1042 {
1043    if (!_eff) return ECORE_CALLBACK_PASS_ON;
1044
1045    _eff_pending_effect_start();
1046
1047    return ECORE_CALLBACK_PASS_ON;
1048 }
1049
1050 static Eina_Bool
1051 _eff_cb_client_buffer_change(void *data, int ev_type, void *event)
1052 {
1053    E_Event_Client *ev = event;
1054    E_Client *ec;
1055    E_Effect_Client *efc;
1056    E_Comp_Wl_Buffer *buffer = NULL;
1057
1058    if (!_eff) return ECORE_CALLBACK_PASS_ON;
1059
1060    ec = ev->ec;
1061    if (!ec) return ECORE_CALLBACK_PASS_ON;
1062
1063    efc = _eff_client_get(ec);
1064    if (!efc) return ECORE_CALLBACK_PASS_ON;
1065
1066    if (ec->pixmap)
1067      {
1068         buffer = e_pixmap_resource_get(ec->pixmap);
1069         if (buffer != efc->buffer_ref.buffer)
1070           {
1071              e_comp_wl_buffer_reference(&efc->buffer_ref, buffer);
1072           }
1073      }
1074
1075    return ECORE_CALLBACK_PASS_ON;
1076 }
1077
1078 static void
1079 _tz_effect_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *tz_res_eff)
1080 {
1081    wl_resource_destroy(tz_res_eff);
1082 }
1083
1084 static const struct tizen_effect_interface _tz_effect_interface =
1085 {
1086    _tz_effect_cb_destroy,
1087 };
1088
1089 static void
1090 _tz_effect_cb_effect_destroy(struct wl_resource *tz_res_eff)
1091 {
1092    if ((!_eff) || (!_eff->resources)) return;
1093
1094    eina_hash_del_by_data(_eff->resources, tz_res_eff);
1095 }
1096
1097 static void
1098 _eff_cb_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id)
1099 {
1100    struct wl_resource *res;
1101
1102    if (!(res = wl_resource_create(client, &tizen_effect_interface, 1, id)))
1103      {
1104         ERR("Could not create tizen_effect interface");
1105         wl_client_post_no_memory(client);
1106         return;
1107      }
1108
1109    wl_resource_set_implementation(res,
1110                                   &_tz_effect_interface,
1111                                   NULL,
1112                                   _tz_effect_cb_effect_destroy);
1113
1114    eina_hash_add(_eff->resources, &client, res);
1115 }
1116
1117 static void
1118 _eff_cb_client_data_free(void *data)
1119 {
1120    E_Effect_Client *efc = data;
1121
1122    if (!efc) return;
1123
1124    if (efc->buffer_ref.buffer)
1125      e_comp_wl_buffer_reference(&efc->buffer_ref, NULL);
1126
1127    free(efc);
1128 }
1129
1130 #undef E_CLIENT_HOOK_APPEND
1131 #define E_CLIENT_HOOK_APPEND(l, t, cb, d) \
1132   do                                      \
1133     {                                     \
1134        E_Client_Hook *_h;                 \
1135        _h = e_client_hook_add(t, cb, d);  \
1136        assert(_h);                        \
1137        l = eina_list_append(l, _h);       \
1138     }                                     \
1139   while (0)
1140
1141 #undef E_COMP_OBJ_EFF_MOVER_APPEND
1142 #define E_COMP_OBJ_EFF_MOVER_APPEND(l, i, s, p, d)      \
1143   do                                                    \
1144     {                                                   \
1145        E_Comp_Object_Mover *_m;                         \
1146        _m = e_comp_object_effect_mover_add(i, s, p, d); \
1147        assert(_m);                                      \
1148        l = eina_list_append(l, _m);                     \
1149     }                                                   \
1150   while (0)
1151
1152 EAPI Eina_Bool
1153 e_mod_effect_init(void)
1154 {
1155    E_Effect *eff;
1156    E_Comp_Config *cfg;
1157    Eina_List *l;
1158    E_Client *ec;
1159    E_Effect_Client *efc;
1160
1161    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, EINA_FALSE);
1162    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->evas, EINA_FALSE);
1163
1164    eff = E_NEW(E_Effect, 1);
1165    EINA_SAFETY_ON_NULL_RETURN_VAL(eff, EINA_FALSE);
1166
1167    if ((cfg = e_comp_config_get()))
1168      {
1169         eff->file = eina_stringshare_add(cfg->effect_file);
1170         eff->style = eina_stringshare_add(cfg->effect_style);
1171      }
1172    else
1173      {
1174         eff->file = "";
1175         eff->style = "no-effect";
1176      }
1177
1178    eff->clients = eina_hash_pointer_new(_eff_cb_client_data_free);
1179    EINA_SAFETY_ON_NULL_GOTO(eff->clients, err);
1180
1181    EINA_LIST_FOREACH(e_comp->clients, l, ec)
1182      {
1183         if (ec->ignored) continue;
1184
1185         efc = _eff_client_get(ec);
1186         if (!efc)
1187           efc = _eff_client_new(ec);
1188         if (efc)
1189           eina_hash_add(eff->clients, &ec, efc);
1190      }
1191
1192    eff->resources = eina_hash_pointer_new(NULL);
1193    EINA_SAFETY_ON_NULL_GOTO(eff->resources, err);
1194
1195    eff->global = wl_global_create(e_comp_wl->wl.disp,
1196                                   &tizen_effect_interface,
1197                                   1,
1198                                   eff,
1199                                   _eff_cb_bind);
1200    if (!eff->global)
1201      {
1202         ERR("Could not add tizen_efffect wayland globals: %m");
1203         goto err;
1204      }
1205
1206    E_LIST_HANDLER_APPEND(eff->event_hdlrs,          E_EVENT_COMPOSITOR_ENABLE,    _eff_cb_comp_enabled,         eff);
1207    E_LIST_HANDLER_APPEND(eff->event_hdlrs,          E_EVENT_CLIENT_BUFFER_CHANGE, _eff_cb_client_buffer_change, eff);
1208    E_LIST_HANDLER_APPEND(eff->event_hdlrs,          E_EVENT_CLIENT_STACK,         _eff_cb_client_restack,       eff);
1209    E_CLIENT_HOOK_APPEND(eff->hooks_ec,              E_CLIENT_HOOK_NEW_CLIENT,     _eff_cb_hook_client_new,      eff);
1210    E_CLIENT_HOOK_APPEND(eff->hooks_ec,              E_CLIENT_HOOK_DEL,            _eff_cb_hook_client_del,      eff);
1211    E_COMP_OBJ_EFF_MOVER_APPEND(eff->providers, 100, "e,state,visible",            _eff_cb_visible,              eff);
1212    E_COMP_OBJ_EFF_MOVER_APPEND(eff->providers, 100, "e,state,hidden",             _eff_cb_hidden,               eff);
1213    E_COMP_OBJ_EFF_MOVER_APPEND(eff->providers, 100, "e,action,iconify",           _eff_cb_iconify,              eff);
1214    E_COMP_OBJ_EFF_MOVER_APPEND(eff->providers, 100, "e,action,uniconify",         _eff_cb_uniconify,            eff);
1215    E_COMP_OBJ_EFF_MOVER_APPEND(eff->providers, 100, "e,action,restack*",          _eff_cb_restack,              eff);
1216    E_COMP_OBJ_EFF_MOVER_APPEND(eff->providers, 100, "e,action,launch,done",       _eff_cb_launch,               eff);
1217
1218    _eff = eff;
1219
1220    return EINA_TRUE;
1221
1222 err:
1223    e_mod_effect_shutdown();
1224    return EINA_FALSE;
1225 }
1226
1227 EAPI void
1228 e_mod_effect_shutdown()
1229 {
1230    if (!_eff) return;
1231
1232    E_FREE_FUNC(_eff->stack.old, eina_list_free);
1233    E_FREE_FUNC(_eff->stack.cur, eina_list_free);
1234
1235    E_FREE_LIST(_eff->providers, e_comp_object_effect_mover_del);
1236    E_FREE_LIST(_eff->event_hdlrs, ecore_event_handler_del);
1237    E_FREE_LIST(_eff->hooks_ec, e_client_hook_del);
1238
1239    if (_eff->global)
1240      wl_global_destroy(_eff->global);
1241
1242    E_FREE_FUNC(_eff->resources, eina_hash_free);
1243    E_FREE_FUNC(_eff->clients, eina_hash_free);
1244
1245    E_FREE(_eff);
1246 }