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