Revert "rotation: Packing effect objects to the desk's smart object."
[platform/core/uifw/e-mod-tizen-effect.git] / src / e_mod_effect_rotation.c
1 #include "e_mod_effect_rotation.h"
2
3 #include <tbm_bufmgr.h>
4 #include <tbm_surface.h>
5 #include <tbm_surface_internal.h>
6 #include <tdm_helper.h>
7 #include <wayland-tbm-server.h>
8
9 #if 1
10 #define e_util_size_debug_set(x, y)
11 #endif
12
13 typedef struct _Rotation_Effect_Object
14 {
15    E_Client *ec;
16    Evas_Object *img;
17
18    struct wl_shm_pool *data_pool;
19    void *data;
20 } Rotation_Effect_Object;
21
22 typedef struct _Rotation_Effect_Begin_Context
23 {
24    Evas_Object *layout;
25    Eina_List *objects;
26
27    double src;
28    double dest;
29 } Rotation_Effect_Begin_Context;
30
31 typedef struct _Rotation_Effect_End_Context
32 {
33    Evas_Object *layout;
34    Eina_List *objects;
35
36    double src;
37    double dest;
38 } Rotation_Effect_End_Context;
39
40 typedef struct _Rotation_Effect
41 {
42    E_Zone *zone;
43
44    Evas_Object *bg;
45    Eina_List *targets;
46    Eina_List *waiting_list;
47
48    Rotation_Effect_Begin_Context *ctx_begin;
49    Rotation_Effect_End_Context *ctx_end;
50
51    Ecore_Animator *animator;
52
53    Eina_Bool running;
54    Eina_Bool wait_for_buffer;
55 } Rotation_Effect;
56
57 typedef struct _Rotation_Zone
58 {
59    E_Zone *zone;
60    Eina_List *event_hdlrs;
61
62    Rotation_Effect *effect;
63
64    int curr_angle;
65    int prev_angle;
66 } Rotation_Zone;
67
68 static Rotation_Zone *_rotation_zone = NULL;
69
70 static void
71 _rotation_effect_ready_send(E_Zone *zone)
72 {
73    E_Event_Zone_Rotation_Effect_Ready *ev;
74
75    ev = E_NEW(E_Event_Zone_Rotation_Effect_Ready, 1);
76    if (!ev) return;
77
78    ev->zone = zone;
79    ecore_event_add(E_EVENT_ZONE_ROTATION_EFFECT_READY, ev, NULL, NULL);
80
81    EFFINF("Rotation Effect Event Ready", NULL, NULL);
82 }
83
84 static void
85 _rotation_effect_cancel_send(E_Zone *zone)
86 {
87    E_Event_Zone_Rotation_Effect_Cancel *ev;
88
89    ev = E_NEW(E_Event_Zone_Rotation_Effect_Cancel, 1);
90    if (!ev) return;
91
92    ev->zone = zone;
93    ecore_event_add(E_EVENT_ZONE_ROTATION_EFFECT_CANCEL, ev, NULL, NULL);
94
95    EFFINF("Rotation Effect Event Cancel", NULL, NULL);
96 }
97
98 static void
99 _rotation_effect_done_send(E_Zone *zone)
100 {
101    E_Event_Zone_Rotation_Effect_Done *ev;
102
103    ev = E_NEW(E_Event_Zone_Rotation_Effect_Done, 1);
104    if (!ev) return;
105
106    ev->zone = zone;
107    ecore_event_add(E_EVENT_ZONE_ROTATION_EFFECT_DONE, ev, NULL, NULL);
108
109    EFFINF("Rotation Effect Event Done", NULL, NULL);
110 }
111
112 static Eina_Bool
113 _rotation_effect_available(const E_Client *ec, int ang)
114 {
115    Eina_Bool ret = EINA_FALSE;
116    unsigned int i;
117
118    if (ang < 0) return EINA_FALSE;
119    if (!ec->e.state.rot.support)
120      goto no_hint;
121
122    if (ec->e.state.rot.preferred_rot == -1)
123      {
124         if (ec->e.state.rot.available_rots &&
125             ec->e.state.rot.count)
126           {
127              for (i = 0; i < ec->e.state.rot.count; i++)
128                {
129                   if (ec->e.state.rot.available_rots[i] == ang)
130                     {
131                        ret = EINA_TRUE;
132                        break;
133                     }
134                }
135           }
136         else
137           goto no_hint;
138      }
139    else if (ec->e.state.rot.preferred_rot == ang)
140      ret = EINA_TRUE;
141
142    return ret;
143 no_hint:
144    return (ang == 0);
145 }
146
147 static Eina_List *
148 _rotation_effect_targets_get(Rotation_Effect *effect)
149 {
150    Evas_Object *o;
151    Eina_Tiler *t;
152    Eina_Rectangle r;
153    int x , y, w, h;
154    const int edge = 1;
155    Eina_List *l = NULL;
156    E_Client *ec;
157
158    if (!effect) return NULL;
159
160    if (effect->zone->display_state == E_ZONE_DISPLAY_STATE_OFF)
161      return NULL;
162
163    x = y = w = h = 0;
164
165    t = eina_tiler_new(effect->zone->w + edge, effect->zone->h + edge);
166    eina_tiler_tile_size_set(t, 1, 1);
167
168    EINA_RECTANGLE_SET(&r, effect->zone->x, effect->zone->y, effect->zone->w, effect->zone->h);
169    eina_tiler_rect_add(t, &r);
170
171    o = evas_object_top_get(e_comp->evas);
172    for (; o; o = evas_object_below_get(o))
173      {
174         if (!evas_object_visible_get(o)) continue;
175         if (o == effect->zone->over) continue;
176         if (o == effect->bg) continue;
177         if (evas_object_layer_get(o) > E_LAYER_EFFECT) continue;
178         if (!e_util_strcmp(evas_object_name_get(o), "layer_obj")) continue;
179
180         evas_object_geometry_get(o, &x, &y, &w, &h);
181         ec = evas_object_data_get(o, "E_Client");
182         if (ec)
183           {
184              if (e_object_is_del(E_OBJECT(ec))) continue;
185              if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h))
186                continue;
187              if ((ec->visibility.obscured != E_VISIBILITY_UNOBSCURED) &&
188                  (ec->iconic))
189                continue;
190
191              if ((!ec->animatable) ||
192                  (e_client_video_client_has(ec)) ||
193                  (!_rotation_effect_available(ec, effect->zone->rot.curr)) ||
194                  (ec->e.state.rot.ang.curr == effect->zone->rot.curr))
195                {
196                   if (l) eina_list_free(l);
197                   eina_tiler_free(t);
198                   return NULL;
199                }
200           }
201
202         l = eina_list_append(l, o);
203
204         if ((ec) && (ec->argb))
205           {
206              if (ec->visibility.opaque <= 0) continue;
207              else
208                {
209                   if (ec->parent) continue;
210                }
211           }
212
213         EINA_RECTANGLE_SET(&r, x, y, w + edge, h + edge);
214         eina_tiler_rect_del(t, &r);
215
216         if (eina_tiler_empty(t)) break;
217      }
218    eina_tiler_free(t);
219
220    return l;
221 }
222
223 static void
224 _rotation_effect_object_free(Rotation_Effect_Object *eobj)
225 {
226    if (!eobj) return;
227
228    if (eobj->data)
229      {
230         evas_object_image_data_set(eobj->img, NULL);
231         free(eobj->data);
232      }
233    if (eobj->img) evas_object_del(eobj->img);
234    if (eobj->data_pool) wl_shm_pool_unref(eobj->data_pool);
235
236    E_FREE(eobj);
237 }
238
239 static Rotation_Effect_Object *
240 _rotation_effect_object_create(Evas_Object *o)
241 {
242    Rotation_Effect_Object *eobj;
243    E_Comp_Wl_Buffer *buffer = NULL;
244    Evas_Object *img = NULL;
245    int x, y, w, h;
246    int i;
247    E_Client *ec;
248    void *data = NULL, *pix = NULL;
249
250    if (!evas_object_visible_get(o)) return NULL;
251
252    ec = evas_object_data_get(o, "E_Client");
253    if (ec)
254      {
255         if (e_object_is_del(E_OBJECT(ec))) return NULL;
256
257         eobj = E_NEW(Rotation_Effect_Object, 1);
258         if (!eobj) goto fail;
259
260         eobj->ec = ec;
261
262         buffer = e_pixmap_resource_get(ec->pixmap);
263         if (!buffer) goto fail;
264
265         img = evas_object_image_filled_add(e_comp->evas);
266         e_util_size_debug_set(img, 1);
267         evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888);
268         evas_object_image_smooth_scale_set(img, e_comp_config_get()->smooth_windows);
269
270         if (buffer->type == E_COMP_WL_BUFFER_TYPE_SHM)
271           {
272              if (!buffer->shm_buffer) goto fail;
273
274              w = buffer->w;
275              h = buffer->h;
276
277              pix = wl_shm_buffer_get_data(buffer->shm_buffer);
278              if (!pix) goto fail;
279
280              if (eobj->data_pool)
281                wl_shm_pool_unref(eobj->data_pool);
282              eobj->data_pool = wl_shm_buffer_ref_pool(buffer->shm_buffer);
283           }
284         else if  (buffer->type == E_COMP_WL_BUFFER_TYPE_NATIVE)
285           {
286              tbm_surface_info_s surface_info;
287              tbm_surface_h tbm_surface = wayland_tbm_server_get_surface(NULL, buffer->resource);
288              memset(&surface_info, 0, sizeof(tbm_surface_info_s));
289              tbm_surface_map(tbm_surface, TBM_SURF_OPTION_READ, &surface_info);
290
291              data = surface_info.planes[0].ptr;
292              if (!data) goto fail;
293
294              w = surface_info.width;
295              h = surface_info.height;
296
297              pix = eobj->data = malloc(w * h * 4);
298              for (i = 0; i < h; i++)
299                {
300                   memcpy(pix, data, surface_info.width * 4);
301                   pix += surface_info.width * 4;
302                   data += surface_info.planes[0].stride;
303                }
304              pix = eobj->data;
305
306              tbm_surface_unmap(tbm_surface);
307           }
308         else if (buffer->type == E_COMP_WL_BUFFER_TYPE_TBM)
309           {
310              tbm_surface_info_s surface_info;
311              tbm_surface_h tbm_surface = buffer->tbm_surface;
312
313              memset(&surface_info, 0, sizeof(tbm_surface_info_s));
314              tbm_surface_map(tbm_surface, TBM_SURF_OPTION_READ, &surface_info);
315
316              data = surface_info.planes[0].ptr;
317              if (!data) goto fail;
318
319              w = surface_info.width;
320              h = surface_info.height;
321
322              pix = eobj->data = malloc(w * h * 4);
323              for (i = 0; i < h; i++)
324                {
325                   memcpy(pix, data, surface_info.width * 4);
326                   pix += surface_info.width * 4;
327                   data += surface_info.planes[0].stride;
328                }
329              pix = eobj->data;
330
331              tbm_surface_unmap(tbm_surface);
332           }
333         else
334           goto fail;
335
336         if (pix)
337           {
338              evas_object_image_alpha_set(img, 1);
339              evas_object_image_size_set(img, w, h);
340              evas_object_image_data_set(img, pix);
341              evas_object_image_data_update_add(img, 0, 0, w, h);
342
343              evas_object_name_set(img, "rotation-effect-image");
344              evas_object_move(img, ec->x, ec->y);
345              evas_object_resize(img, ec->w, ec->h);
346           }
347         else
348           goto fail;
349
350         EFFINF("Rotation EFFECT Object Created E_Client:%p",
351                NULL, NULL, ec);
352
353         eobj->img = img;
354         return eobj;
355      }
356    else
357      {
358         eobj = E_NEW(Rotation_Effect_Object, 1);
359         if (!eobj) return NULL;
360
361         eobj->ec = NULL;
362
363         evas_object_geometry_get(o, &x, &y, &w, &h);
364
365         img = evas_object_image_filled_add(e_comp->evas);
366         e_util_size_debug_set(img, 1);
367
368         evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888);
369         evas_object_image_smooth_scale_set(img, e_comp_config_get()->smooth_windows);
370         evas_object_image_alpha_set(img, 1);
371         evas_object_image_size_set(img, w, h);
372         evas_object_image_source_set(img, o);
373
374         evas_object_name_set(img, "rotation-effect-image");
375         evas_object_move(img, x, y);
376         evas_object_resize(img, w, h);
377
378         eobj->img = img;
379
380         EFFINF("Rotation EFFECT Object Created Object:%p",
381                NULL, NULL, o);
382
383         return eobj;
384      }
385
386 fail:
387    if (eobj)
388      {
389         evas_object_image_data_set(img, NULL);
390         evas_object_del(img);
391
392         if (eobj->data)
393           free(eobj->data);
394
395         if (eobj->data_pool)
396           wl_shm_pool_unref(eobj->data_pool);
397
398         E_FREE(eobj);
399      }
400
401    return NULL;
402 }
403
404 static Rotation_Effect_Begin_Context *
405 _rotation_effect_begin_create(Rotation_Effect *effect, Eina_List *targets)
406 {
407    Rotation_Effect_Begin_Context *ctx_begin = NULL;
408    Rotation_Effect_Object *eobj = NULL;
409    Evas_Object *target;
410    Eina_List *l;
411    int x, y, w, h;
412
413    ctx_begin = E_NEW(Rotation_Effect_Begin_Context, 1);
414    if (!ctx_begin) return NULL;
415
416    ctx_begin->layout = e_layout_add(e_comp->evas);
417    e_util_size_debug_set(ctx_begin->layout, 1);
418    evas_object_name_set(ctx_begin->layout, "rotation-begin-effect-layout");
419    e_layout_virtual_size_set(ctx_begin->layout, effect->zone->w, effect->zone->h);
420    evas_object_move(ctx_begin->layout, effect->zone->x, effect->zone->y);
421    evas_object_resize(ctx_begin->layout, effect->zone->w, effect->zone->h);
422    evas_object_layer_set(ctx_begin->layout, E_LAYER_EFFECT);
423
424    EINA_LIST_REVERSE_FOREACH(targets, l, target)
425      {
426         eobj = _rotation_effect_object_create(target);
427         if (!eobj) continue;
428
429         ctx_begin->objects = eina_list_append(ctx_begin->objects, eobj);
430         if (eobj->ec)
431           effect->waiting_list = eina_list_append(effect->waiting_list, eobj->ec);
432
433         evas_object_geometry_get(target, &x, &y, &w, &h);
434
435         e_layout_pack(ctx_begin->layout, eobj->img);
436         e_layout_child_move(eobj->img, x, y);
437         e_layout_child_resize(eobj->img, w, h);
438         e_layout_child_raise(eobj->img);
439         evas_object_show(eobj->img);
440      }
441
442    if (!ctx_begin->objects)
443      {
444         evas_object_del(ctx_begin->layout);
445         E_FREE(ctx_begin);
446         return NULL;
447      }
448
449    EFFINF("Rotation Begin Created", NULL, NULL);
450
451    int diff = effect->zone->rot.prev - effect->zone->rot.curr;
452    if (diff == 270) diff = - 90;
453    else if (diff == -270) diff = 90;
454    ctx_begin->src = 0.0;
455    ctx_begin->dest = diff;
456
457    return ctx_begin;
458 }
459
460
461 static Rotation_Effect_End_Context *
462 _rotation_effect_end_create(Rotation_Effect *effect, Eina_List *targets)
463 {
464    Rotation_Effect_End_Context *ctx_end = NULL;
465    Rotation_Effect_Object *eobj = NULL;
466    Eina_List *l;
467    Evas_Object *target;
468    int x, y, w, h;
469
470    ctx_end = E_NEW(Rotation_Effect_End_Context, 1);
471    if (!ctx_end) return NULL;
472
473    ctx_end->layout = e_layout_add(e_comp->evas);
474    e_util_size_debug_set(ctx_end->layout, 1);
475    evas_object_name_set(ctx_end->layout, "rotation-end-effect-layout");
476    e_layout_virtual_size_set(ctx_end->layout, effect->zone->w, effect->zone->h);
477    evas_object_move(ctx_end->layout, effect->zone->x, effect->zone->y);
478    evas_object_resize(ctx_end->layout, effect->zone->w, effect->zone->h);
479    evas_object_layer_set(ctx_end->layout, E_LAYER_EFFECT);
480
481    EINA_LIST_REVERSE_FOREACH(targets, l, target)
482      {
483         eobj = _rotation_effect_object_create(target);
484         if (!eobj) continue;
485
486         evas_object_geometry_get(target, &x, &y, &w, &h);
487
488         ctx_end->objects = eina_list_append(ctx_end->objects, eobj);
489
490         e_layout_pack(ctx_end->layout, eobj->img);
491         e_layout_child_move(eobj->img, x, y);
492         e_layout_child_resize(eobj->img, w, h);
493         e_layout_child_raise(eobj->img);
494         evas_object_show(eobj->img);
495      }
496
497    if (!ctx_end->objects)
498      {
499         evas_object_del(ctx_end->layout);
500         E_FREE(ctx_end);
501         return NULL;
502      }
503
504    EFFINF("Rotation End Created", NULL, NULL);
505
506    int diff = _rotation_zone->curr_angle - _rotation_zone->prev_angle;
507    if (diff == 270) diff = - 90;
508    else if (diff == -270) diff = 90;
509    ctx_end->src = diff;
510    ctx_end->dest = 0.0;
511
512    return ctx_end;
513 }
514
515 static void
516 _rotation_effect_animator_begin_context_free(Rotation_Effect_Begin_Context *ctx_begin)
517 {
518    Rotation_Effect_Object *eobj;
519
520    if (!ctx_begin) return;
521
522    EFFINF("Rotation Begin Free", NULL, NULL);
523
524    if (ctx_begin->layout)
525      evas_object_hide(ctx_begin->layout);
526
527    EINA_LIST_FREE(ctx_begin->objects, eobj)
528      {
529         e_layout_unpack(eobj->img);
530         _rotation_effect_object_free(eobj);
531      }
532
533    if (ctx_begin->layout)
534      evas_object_del(ctx_begin->layout);
535
536    E_FREE(ctx_begin);
537 }
538
539 static void
540 _rotation_effect_animator_end_context_free(Rotation_Effect_End_Context *ctx_end)
541 {
542    Rotation_Effect_Object *eobj;
543
544    if (!ctx_end) return;
545
546    EFFINF("Rotation End Free", NULL, NULL);
547
548    if (ctx_end->layout)
549      evas_object_hide(ctx_end->layout);
550
551    EINA_LIST_FREE(ctx_end->objects, eobj)
552      {
553         e_layout_unpack(eobj->img);
554         _rotation_effect_object_free(eobj);
555      }
556
557    if (ctx_end->layout)
558      evas_object_del(ctx_end->layout);
559
560    E_FREE(ctx_end);
561 }
562
563 static void
564 _rotation_effect_clear(Rotation_Effect *effect)
565 {
566    if (!effect) return;
567
568    EFFINF("Rotation Effect Clear", NULL, NULL);
569
570    effect->targets = eina_list_free(effect->targets);
571    effect->waiting_list = eina_list_free(effect->waiting_list);
572
573    if (effect->animator)
574      ecore_animator_del(effect->animator);
575
576    evas_object_hide(effect->bg);
577
578    if (effect->ctx_begin)
579      {
580         _rotation_effect_animator_begin_context_free(effect->ctx_begin);
581         e_comp_override_del();
582      }
583
584    if (effect->ctx_end)
585      {
586         _rotation_effect_animator_end_context_free(effect->ctx_end);
587         _rotation_effect_done_send(effect->zone);
588      }
589
590    effect->running = EINA_FALSE;
591    effect->wait_for_buffer = EINA_FALSE;
592    effect->animator = NULL;
593    effect->ctx_begin = NULL;
594    effect->ctx_end = NULL;
595 }
596
597 static Eina_Bool
598 _rotation_effect_animator_cb_update(void *data, double pos)
599 {
600    Rotation_Effect *effect;
601    Rotation_Effect_Begin_Context *ctx_begin;
602    Rotation_Effect_End_Context *ctx_end;
603
604    double curr, col, progress;
605    Evas_Coord x, y, w, h;
606
607    effect = (Rotation_Effect *)data;
608    ctx_begin = effect->ctx_begin;
609    ctx_end = effect->ctx_end;
610
611    if (pos == 1.0)
612      {
613         ecore_animator_del(effect->animator);
614         effect->animator = NULL;
615
616         _rotation_effect_animator_begin_context_free(effect->ctx_begin);
617         effect->ctx_begin = NULL;
618
619         _rotation_effect_animator_end_context_free(effect->ctx_end);
620         effect->ctx_end = NULL;
621
622         effect->wait_for_buffer = EINA_FALSE;
623         effect->running = EINA_FALSE;
624         evas_object_hide(effect->bg);
625
626         e_comp_override_del();
627         _rotation_effect_done_send(effect->zone);
628
629         return ECORE_CALLBACK_CANCEL;
630      }
631
632    progress = ecore_animator_pos_map(pos, ECORE_POS_MAP_DECELERATE, 0, 0);
633
634    if (progress < 0.0) progress = 0.0;
635
636    /* rotation begin */
637    curr = (progress * ctx_begin->dest);
638    col = 255 - (255 * progress);
639
640    evas_object_geometry_get(ctx_begin->layout, &x, &y, &w, &h);
641
642    Evas_Map *m = evas_map_new(4);
643    evas_map_util_points_populate_from_object(m, ctx_begin->layout);
644    evas_map_util_rotate(m, curr, x + (w/2), y + (h/2));
645    evas_map_alpha_set(m, EINA_TRUE);
646    evas_map_util_points_color_set(m, col, col, col, col);
647    evas_object_map_set(ctx_begin->layout, m);
648    evas_object_map_enable_set(ctx_begin->layout, EINA_TRUE);
649    evas_map_free(m);
650
651    /* rotation end */
652    curr = ((-1.0f * progress * ctx_end->src) + ctx_end->src);
653
654    evas_object_geometry_get(ctx_end->layout, &x, &y, &w, &h);
655
656    m = evas_map_new(4);
657    evas_map_util_points_populate_from_object(m, ctx_end->layout);
658    evas_map_util_rotate(m, curr, x + (w/2), y + (h/2));
659    evas_object_map_set(ctx_end->layout, m);
660    evas_object_map_enable_set(ctx_end->layout, EINA_TRUE);
661    evas_map_free(m);
662
663    return ECORE_CALLBACK_RENEW;
664 }
665
666 static void
667 _rotation_effect_start(Rotation_Effect *effect)
668 {
669    if ((!effect->ctx_begin) || (!effect->ctx_end)) return;
670    if (effect->running) return;
671
672    EFFINF("Rotation Effect Start", NULL, NULL);
673
674    effect->running = EINA_TRUE;
675
676    evas_object_raise(effect->ctx_begin->layout);
677    evas_object_show(effect->ctx_begin->layout);
678    evas_object_show(effect->ctx_end->layout);
679
680    evas_object_move(effect->bg, 0, 0);
681    evas_object_resize(effect->bg, effect->zone->w, effect->zone->h);
682    evas_object_lower(effect->bg);
683    evas_object_show(effect->bg);
684
685    effect->animator = ecore_animator_timeline_add(0.3f,
686                                                   _rotation_effect_animator_cb_update,
687                                                   effect);
688 }
689
690 static void
691 _rotation_effect_animator_begin_prepare(Rotation_Effect *effect)
692 {
693    if (!effect) return;
694
695    _rotation_effect_clear(effect);
696
697    effect->targets = _rotation_effect_targets_get(effect);
698    if (!effect->targets) return;
699
700    effect->ctx_begin = _rotation_effect_begin_create(effect, effect->targets);
701    if (!effect->ctx_begin)
702      {
703         _rotation_effect_clear(effect);
704         return;
705      }
706
707    EFFINF("Rotation Begin Prepared", NULL, NULL);
708
709    /* add hwc override */
710    e_comp_override_add();
711 }
712
713 static void
714 _rotation_effect_animator_end_prepare(Rotation_Effect *effect)
715 {
716    if (!effect) return;
717    if (!effect->targets) return;
718    if (!effect->ctx_begin) return;
719
720    /* clear previous context */
721    if (effect->ctx_end)
722      _rotation_effect_animator_end_context_free(effect->ctx_end);
723    effect->ctx_end = NULL;
724
725    effect->ctx_end = _rotation_effect_end_create(effect, effect->targets);
726    if (!effect->ctx_end) return;
727
728    EFFINF("Rotation End Prepared", NULL, NULL);
729
730    effect->targets = eina_list_free(effect->targets);
731 }
732
733 static Eina_Bool
734 _rotation_effect_cb_zone_rotation_begin(void *data, int type, void *event)
735 {
736    Rotation_Effect *effect;
737    E_Event_Zone_Rotation_Change_Begin *ev = event;
738    E_Zone *zone;
739
740    effect = (Rotation_Effect *)data;
741    if (!effect) return ECORE_CALLBACK_PASS_ON;
742
743    zone = ev->zone;
744    if (!zone) return ECORE_CALLBACK_PASS_ON;
745
746    EFFINF("Zone rotation begin zone(prev:%d cur:%d)",
747           NULL, NULL,
748           zone->rot.prev, zone->rot.curr);
749
750    if (zone->rot.prev == zone->rot.curr) return ECORE_CALLBACK_PASS_ON;
751
752    _rotation_zone->curr_angle = zone->rot.curr;
753    _rotation_zone->prev_angle = zone->rot.prev;
754
755    _rotation_effect_animator_begin_prepare(effect);
756
757    if (effect->targets)
758      _rotation_effect_ready_send(zone);
759
760    return ECORE_CALLBACK_PASS_ON;
761 }
762
763 static Eina_Bool
764 _rotation_effect_cb_zone_rotation_end(void *data, int type, void *event)
765 {
766    Rotation_Effect *effect;
767    E_Event_Zone_Rotation_Change_End *ev = event;
768    E_Zone *zone;
769
770    effect = (Rotation_Effect *)data;
771    if (!effect) return ECORE_CALLBACK_PASS_ON;
772
773    zone = ev->zone;
774    if (!zone) return ECORE_CALLBACK_PASS_ON;
775
776    EFFINF("Zone rotation end angle(prev:%d cur:%d)", NULL, NULL,
777           zone->rot.prev, zone->rot.curr);
778
779    if (effect->running) return ECORE_CALLBACK_PASS_ON;
780    if (effect->waiting_list)
781      {
782         effect->wait_for_buffer = EINA_TRUE;
783         return ECORE_CALLBACK_PASS_ON;
784      }
785
786    if (!effect->ctx_end)
787      {
788         _rotation_effect_animator_end_prepare(effect);
789
790         if (!effect->ctx_end)
791           _rotation_effect_clear(effect);
792      }
793    if (effect->ctx_end) _rotation_effect_start(effect);
794
795    return ECORE_CALLBACK_PASS_ON;
796 }
797
798 static Eina_Bool
799 _rotation_effect_cb_zone_rotation_cancel(void *data, int type, void *event)
800 {
801    E_Event_Zone_Rotation_Change_Cancel *ev = event;
802    Rotation_Effect *effect;
803    E_Zone *zone;
804
805    zone = ev->zone;
806    if (!zone) return ECORE_CALLBACK_PASS_ON;
807
808    effect = (Rotation_Effect *)data;
809    if (!effect) return ECORE_CALLBACK_PASS_ON;
810
811    EFFINF("Zone Rotation Cancelled", NULL, NULL);
812
813    if (effect->running) return ECORE_CALLBACK_PASS_ON;
814    if (effect->targets) _rotation_effect_cancel_send(zone);
815    _rotation_effect_clear(effect);
816
817    return ECORE_CALLBACK_PASS_ON;
818 }
819
820 static Eina_Bool
821 _rotation_effect_cb_buffer_change(void *data, int ev_type, void *event)
822 {
823    E_Event_Client *ev = event;
824    E_Client *ec;
825    Rotation_Effect *effect;
826
827    ec = ev->ec;
828    if (!ec) return ECORE_CALLBACK_PASS_ON;
829
830    effect = (Rotation_Effect *)data;
831    if (!effect) return ECORE_CALLBACK_PASS_ON;
832    if (!effect->ctx_begin) return ECORE_CALLBACK_PASS_ON;
833    if (!effect->waiting_list) return ECORE_CALLBACK_PASS_ON;
834
835    effect->waiting_list = eina_list_remove(effect->waiting_list, ec);
836    if (effect->waiting_list) return ECORE_CALLBACK_PASS_ON;
837
838    if (!effect->wait_for_buffer) return ECORE_CALLBACK_PASS_ON;
839
840    if (!effect->ctx_end) _rotation_effect_animator_end_prepare(effect);
841    if (effect->ctx_end) _rotation_effect_start(effect);
842
843    return ECORE_CALLBACK_PASS_ON;
844 }
845
846 static Eina_Bool
847 _rotation_effect_cb_client_remove(void *data, int ev_type, void *event)
848 {
849    E_Event_Client *ev = event;
850    E_Client *ec;
851    Rotation_Effect *effect;
852    Rotation_Effect_Object *eobj;
853    Eina_List *l;
854    Eina_Bool clear = EINA_FALSE;
855
856    ec = ev->ec;
857    if (!ec) return ECORE_CALLBACK_PASS_ON;
858
859    effect = (Rotation_Effect *)data;
860    if (!effect) return ECORE_CALLBACK_PASS_ON;
861    if (effect->ctx_begin)
862      {
863         EINA_LIST_FOREACH(effect->ctx_begin->objects, l, eobj)
864           {
865              if (ec == eobj->ec)
866                {
867                   clear = EINA_TRUE;
868                   break;
869                }
870           }
871
872         if (clear)
873           _rotation_effect_clear(effect);
874      }
875
876    return ECORE_CALLBACK_PASS_ON;
877 }
878
879 static void
880 _rotation_effect_free(Rotation_Effect *effect)
881 {
882    if (!effect) return;
883
884    _rotation_effect_clear(effect);
885    evas_object_del(effect->bg);
886    E_FREE(effect);
887 }
888
889 static Rotation_Effect *
890 _rotation_effect_create(E_Zone *zone)
891 {
892    Rotation_Effect *rotation_effect;
893
894    rotation_effect = E_NEW(Rotation_Effect, 1);
895    if (!rotation_effect) return NULL;
896
897    rotation_effect->zone = zone;
898
899    rotation_effect->bg = evas_object_rectangle_add(e_comp->evas);
900    e_util_size_debug_set(rotation_effect->bg, 1);
901    evas_object_color_set(rotation_effect->bg, 0, 0, 0, 255);
902    evas_object_layer_set(rotation_effect->bg, E_LAYER_EFFECT);
903    evas_object_name_set(rotation_effect->bg, "rotation-bg");
904
905    return rotation_effect;
906 }
907
908 static void
909 _rotation_zone_free(Rotation_Zone *rotation_zone)
910 {
911    if (!rotation_zone) return;
912
913    E_FREE_LIST(rotation_zone->event_hdlrs, ecore_event_handler_del);
914
915    _rotation_effect_free(rotation_zone->effect);
916
917    E_FREE(rotation_zone);
918
919    return;
920 }
921
922 static Rotation_Zone *
923 _rotation_zone_create(E_Zone *zone)
924 {
925    Rotation_Zone *rotation_zone = NULL;
926
927    if (!zone) return NULL;
928    if ((zone->w == 0) || (zone->h == 0)) return NULL;
929
930    rotation_zone = E_NEW(Rotation_Zone, 1);
931    if (!rotation_zone) return NULL;
932
933    /* create rotation effect data */
934    rotation_zone->effect = _rotation_effect_create(zone);
935    if (!rotation_zone->effect)
936      {
937         E_FREE(rotation_zone);
938         return NULL;
939      }
940
941    rotation_zone->zone = zone;
942    rotation_zone->curr_angle = zone->rot.curr;
943    rotation_zone->prev_angle = zone->rot.prev;
944
945    E_LIST_HANDLER_APPEND(rotation_zone->event_hdlrs,
946                          E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
947                          _rotation_effect_cb_zone_rotation_begin, rotation_zone->effect);
948
949    E_LIST_HANDLER_APPEND(rotation_zone->event_hdlrs,
950                          E_EVENT_ZONE_ROTATION_CHANGE_END,
951                          _rotation_effect_cb_zone_rotation_end, rotation_zone->effect);
952
953    E_LIST_HANDLER_APPEND(rotation_zone->event_hdlrs,
954                          E_EVENT_ZONE_ROTATION_CHANGE_CANCEL,
955                          _rotation_effect_cb_zone_rotation_cancel, rotation_zone->effect);
956
957    E_LIST_HANDLER_APPEND(rotation_zone->event_hdlrs,
958                          E_EVENT_CLIENT_BUFFER_CHANGE,
959                          _rotation_effect_cb_buffer_change, rotation_zone->effect);
960
961    E_LIST_HANDLER_APPEND(rotation_zone->event_hdlrs,
962                          E_EVENT_CLIENT_REMOVE,
963                          _rotation_effect_cb_client_remove, rotation_zone->effect);
964
965    return rotation_zone;
966 }
967
968 EAPI Eina_Bool
969 e_mod_effect_rotation_init(void)
970 {
971    _rotation_zone = _rotation_zone_create(e_zone_current_get());
972    if (!_rotation_zone) return EINA_FALSE;
973
974    return EINA_TRUE;
975 }
976
977 EAPI void
978 e_mod_effect_rotation_shutdown(void)
979 {
980    if (_rotation_zone)
981      _rotation_zone_free(_rotation_zone);
982
983    _rotation_zone = NULL;
984 }