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