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