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