1 #include "e_mod_effect_rotation.h"
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>
10 #define e_util_size_debug_set(x, y)
13 typedef struct _Rotation_Effect_Object
18 struct wl_shm_pool *data_pool;
20 } Rotation_Effect_Object;
22 typedef struct _Rotation_Effect_Begin_Context
29 } Rotation_Effect_Begin_Context;
31 typedef struct _Rotation_Effect_End_Context
38 } Rotation_Effect_End_Context;
40 typedef struct _Rotation_Effect
46 Eina_List *waiting_list;
48 Rotation_Effect_Begin_Context *ctx_begin;
49 Rotation_Effect_End_Context *ctx_end;
51 Ecore_Animator *animator;
54 Eina_Bool wait_for_buffer;
57 typedef struct _Rotation_Zone
60 Eina_List *event_hdlrs;
62 Rotation_Effect *effect;
68 static Rotation_Zone *_rotation_zone = NULL;
71 _rotation_effect_available(const E_Client *ec, int ang)
73 Eina_Bool ret = EINA_FALSE;
76 if (ang < 0) return EINA_FALSE;
77 if (!ec->e.state.rot.support)
80 if (ec->e.state.rot.preferred_rot == -1)
82 if (ec->e.state.rot.available_rots &&
83 ec->e.state.rot.count)
85 for (i = 0; i < ec->e.state.rot.count; i++)
87 if (ec->e.state.rot.available_rots[i] == ang)
97 else if (ec->e.state.rot.preferred_rot == ang)
106 _rotation_effect_targets_get(Rotation_Effect *effect)
116 if (!effect) return NULL;
120 t = eina_tiler_new(effect->zone->w + edge, effect->zone->h + edge);
121 eina_tiler_tile_size_set(t, 1, 1);
123 if (effect->zone->display_state == E_ZONE_DISPLAY_STATE_OFF)
126 EINA_RECTANGLE_SET(&r, effect->zone->x, effect->zone->y, effect->zone->w, effect->zone->h);
127 eina_tiler_rect_add(t, &r);
129 o = evas_object_top_get(e_comp->evas);
130 for (; o; o = evas_object_below_get(o))
132 if (!evas_object_visible_get(o)) continue;
133 if (o == effect->zone->over) continue;
134 if (o == effect->bg) continue;
135 if (evas_object_layer_get(o) > E_LAYER_EFFECT) continue;
136 if (!e_util_strcmp(evas_object_name_get(o), "layer_obj")) continue;
138 evas_object_geometry_get(o, &x, &y, &w, &h);
139 ec = evas_object_data_get(o, "E_Client");
142 if (e_object_is_del(E_OBJECT(ec))) continue;
143 if (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED) continue;
145 if ((!ec->animatable) ||
146 (!_rotation_effect_available(ec, effect->zone->rot.curr)) ||
147 (ec->e.state.rot.ang.curr == effect->zone->rot.curr))
149 if (l) eina_list_free(l);
154 l = eina_list_append(l, o);
156 if ((ec) && (ec->argb) && (ec->visibility.opaque <= 0))
159 EINA_RECTANGLE_SET(&r, x, y, w + edge, h + edge);
160 eina_tiler_rect_del(t, &r);
162 if (eina_tiler_empty(t)) break;
169 _rotation_effect_object_free(Rotation_Effect_Object *eobj)
175 evas_object_image_data_set(eobj->img, NULL);
178 if (eobj->img) evas_object_del(eobj->img);
179 if (eobj->data_pool) wl_shm_pool_unref(eobj->data_pool);
184 static Rotation_Effect_Object *
185 _rotation_effect_object_create(Evas_Object *o)
187 Rotation_Effect_Object *eobj;
188 E_Comp_Wl_Buffer *buffer = NULL;
189 Evas_Object *img = NULL;
193 void *data = NULL, *pix = NULL;
195 if (!evas_object_visible_get(o)) return NULL;
197 ec = evas_object_data_get(o, "E_Client");
200 if (e_object_is_del(E_OBJECT(ec))) return NULL;
202 eobj = E_NEW(Rotation_Effect_Object, 1);
203 if (!eobj) goto fail;
207 buffer = e_pixmap_resource_get(ec->pixmap);
208 if (!buffer) goto fail;
210 img = evas_object_image_filled_add(e_comp->evas);
211 e_util_size_debug_set(img, 1);
212 evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888);
213 evas_object_image_smooth_scale_set(img, e_comp_config_get()->smooth_windows);
215 if (buffer->type == E_COMP_WL_BUFFER_TYPE_SHM)
217 if (!buffer->shm_buffer) goto fail;
221 pix = wl_shm_buffer_get_data(buffer->shm_buffer);
224 wl_shm_pool_unref(eobj->data_pool);
225 eobj->data_pool = wl_shm_buffer_ref_pool(buffer->shm_buffer);
227 else if (buffer->type == E_COMP_WL_BUFFER_TYPE_NATIVE)
229 tbm_surface_info_s surface_info;
230 tbm_surface_h tbm_surface = wayland_tbm_server_get_surface(NULL, buffer->resource);
231 memset(&surface_info, 0, sizeof(tbm_surface_info_s));
232 tbm_surface_map(tbm_surface, TBM_SURF_OPTION_READ, &surface_info);
234 data = surface_info.planes[0].ptr;
235 w = surface_info.width;
236 h = surface_info.height;
238 pix = eobj->data = malloc(w * h * 4);
239 for (i = 0; i < h; i++)
241 memcpy(pix, data, surface_info.width * 4);
242 pix += surface_info.width * 4;
243 data += surface_info.planes[0].stride;
247 tbm_surface_unmap(tbm_surface);
249 else if (buffer->type == E_COMP_WL_BUFFER_TYPE_TBM)
251 tbm_surface_info_s surface_info;
252 tbm_surface_h tbm_surface = buffer->tbm_surface;
254 memset(&surface_info, 0, sizeof(tbm_surface_info_s));
255 tbm_surface_map(tbm_surface, TBM_SURF_OPTION_READ, &surface_info);
257 data = surface_info.planes[0].ptr;
258 w = surface_info.width;
259 h = surface_info.height;
261 pix = eobj->data = malloc(w * h * 4);
262 for (i = 0; i < h; i++)
264 memcpy(pix, data, surface_info.width * 4);
265 pix += surface_info.width * 4;
266 data += surface_info.planes[0].stride;
270 tbm_surface_unmap(tbm_surface);
277 evas_object_image_alpha_set(img, 1);
278 evas_object_image_size_set(img, w, h);
279 evas_object_image_data_set(img, pix);
280 evas_object_image_data_update_add(img, 0, 0, w, h);
282 evas_object_name_set(img, "rotation-effect-image");
283 evas_object_move(img, ec->x, ec->y);
284 evas_object_resize(img, ec->w, ec->h);
289 EFFINF("Rotation EFFECT Object Created E_Client:%p",
297 eobj = E_NEW(Rotation_Effect_Object, 1);
298 if (!eobj) return NULL;
302 evas_object_geometry_get(o, &x, &y, &w, &h);
304 img = evas_object_image_filled_add(e_comp->evas);
305 e_util_size_debug_set(img, 1);
307 evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888);
308 evas_object_image_smooth_scale_set(img, e_comp_config_get()->smooth_windows);
309 evas_object_image_alpha_set(img, 1);
310 evas_object_image_size_set(img, w, h);
311 evas_object_image_source_set(img, o);
313 evas_object_name_set(img, "rotation-effect-image");
314 evas_object_move(img, x, y);
315 evas_object_resize(img, w, h);
319 EFFINF("Rotation EFFECT Object Created Object:%p",
328 evas_object_image_data_set(img, NULL);
329 evas_object_del(img);
335 wl_shm_pool_unref(eobj->data_pool);
343 static Rotation_Effect_Begin_Context *
344 _rotation_effect_begin_create(Rotation_Effect *effect, Eina_List *targets)
346 Rotation_Effect_Begin_Context *ctx_begin = NULL;
347 Rotation_Effect_Object *eobj = NULL;
352 ctx_begin = E_NEW(Rotation_Effect_Begin_Context, 1);
353 if (!ctx_begin) return NULL;
355 ctx_begin->layout = e_layout_add(e_comp->evas);
356 e_util_size_debug_set(ctx_begin->layout, 1);
357 evas_object_name_set(ctx_begin->layout, "rotation-begin-effect-layout");
358 e_layout_virtual_size_set(ctx_begin->layout, effect->zone->w, effect->zone->h);
359 evas_object_move(ctx_begin->layout, effect->zone->x, effect->zone->y);
360 evas_object_resize(ctx_begin->layout, effect->zone->w, effect->zone->h);
361 evas_object_layer_set(ctx_begin->layout, E_LAYER_EFFECT);
363 EINA_LIST_REVERSE_FOREACH(targets, l, target)
365 eobj = _rotation_effect_object_create(target);
368 ctx_begin->objects = eina_list_append(ctx_begin->objects, eobj);
370 effect->waiting_list = eina_list_append(effect->waiting_list, eobj->ec);
372 evas_object_geometry_get(target, &x, &y, &w, &h);
374 e_layout_pack(ctx_begin->layout, eobj->img);
375 e_layout_child_move(eobj->img, x, y);
376 e_layout_child_resize(eobj->img, w, h);
377 e_layout_child_raise(eobj->img);
378 evas_object_show(eobj->img);
381 if (!ctx_begin->objects)
383 evas_object_del(ctx_begin->layout);
388 EFFINF("Rotation Begin Created", NULL, NULL);
390 int diff = effect->zone->rot.prev - effect->zone->rot.curr;
391 if (diff == 270) diff = - 90;
392 else if (diff == -270) diff = 90;
393 ctx_begin->src = 0.0;
394 ctx_begin->dest = diff;
400 static Rotation_Effect_End_Context *
401 _rotation_effect_end_create(Rotation_Effect *effect, Eina_List *targets)
403 Rotation_Effect_End_Context *ctx_end = NULL;
404 Rotation_Effect_Object *eobj = NULL;
409 ctx_end = E_NEW(Rotation_Effect_End_Context, 1);
410 if (!ctx_end) return NULL;
412 ctx_end->layout = e_layout_add(e_comp->evas);
413 e_util_size_debug_set(ctx_end->layout, 1);
414 evas_object_name_set(ctx_end->layout, "rotation-end-effect-layout");
415 e_layout_virtual_size_set(ctx_end->layout, effect->zone->w, effect->zone->h);
416 evas_object_move(ctx_end->layout, effect->zone->x, effect->zone->y);
417 evas_object_resize(ctx_end->layout, effect->zone->w, effect->zone->h);
418 evas_object_layer_set(ctx_end->layout, E_LAYER_EFFECT);
420 EINA_LIST_REVERSE_FOREACH(targets, l, target)
422 eobj = _rotation_effect_object_create(target);
425 evas_object_geometry_get(target, &x, &y, &w, &h);
427 ctx_end->objects = eina_list_append(ctx_end->objects, eobj);
429 e_layout_pack(ctx_end->layout, eobj->img);
430 e_layout_child_move(eobj->img, x, y);
431 e_layout_child_resize(eobj->img, w, h);
432 e_layout_child_raise(eobj->img);
433 evas_object_show(eobj->img);
436 if (!ctx_end->objects)
438 evas_object_del(ctx_end->layout);
443 EFFINF("Rotation End Created", NULL, NULL);
445 int diff = _rotation_zone->curr_angle - _rotation_zone->prev_angle;
446 if (diff == 270) diff = - 90;
447 else if (diff == -270) diff = 90;
455 _rotation_effect_animator_begin_context_free(Rotation_Effect_Begin_Context *ctx_begin)
457 Rotation_Effect_Object *eobj;
459 if (!ctx_begin) return;
461 EFFINF("Rotation Begin Free", NULL, NULL);
463 if (ctx_begin->layout)
464 evas_object_hide(ctx_begin->layout);
466 EINA_LIST_FREE(ctx_begin->objects, eobj)
468 e_layout_unpack(eobj->img);
469 _rotation_effect_object_free(eobj);
472 if (ctx_begin->layout)
473 evas_object_del(ctx_begin->layout);
479 _rotation_effect_animator_end_context_free(Rotation_Effect_End_Context *ctx_end)
481 Rotation_Effect_Object *eobj;
483 if (!ctx_end) return;
485 EFFINF("Rotation End Free", NULL, NULL);
488 evas_object_hide(ctx_end->layout);
490 EINA_LIST_FREE(ctx_end->objects, eobj)
492 e_layout_unpack(eobj->img);
493 _rotation_effect_object_free(eobj);
497 evas_object_del(ctx_end->layout);
503 _rotation_effect_clear(Rotation_Effect *effect)
507 EFFINF("Rotation Effect Clear", NULL, NULL);
509 effect->targets = eina_list_free(effect->targets);
510 effect->waiting_list = eina_list_free(effect->waiting_list);
512 if (effect->animator)
513 ecore_animator_del(effect->animator);
515 evas_object_hide(effect->bg);
517 if (effect->ctx_begin)
519 _rotation_effect_animator_begin_context_free(effect->ctx_begin);
520 if (!effect->ctx_end)
521 e_comp_override_del();
525 _rotation_effect_animator_end_context_free(effect->ctx_end);
527 effect->running = EINA_FALSE;
528 effect->wait_for_buffer = EINA_FALSE;
529 effect->animator = NULL;
530 effect->ctx_begin = NULL;
531 effect->ctx_end = NULL;
535 _rotation_effect_animator_cb_update(void *data, double pos)
537 Rotation_Effect *effect;
538 Rotation_Effect_Begin_Context *ctx_begin;
539 Rotation_Effect_End_Context *ctx_end;
541 double curr, col, progress;
542 Evas_Coord x, y, w, h;
544 effect = (Rotation_Effect *)data;
545 ctx_begin = effect->ctx_begin;
546 ctx_end = effect->ctx_end;
550 ecore_animator_del(effect->animator);
551 effect->animator = NULL;
553 _rotation_effect_animator_begin_context_free(effect->ctx_begin);
554 effect->ctx_begin = NULL;
556 _rotation_effect_animator_end_context_free(effect->ctx_end);
557 effect->ctx_end = NULL;
559 effect->wait_for_buffer = EINA_FALSE;
560 effect->running = EINA_FALSE;
561 evas_object_hide(effect->bg);
563 e_comp_override_del();
565 return ECORE_CALLBACK_CANCEL;
568 progress = ecore_animator_pos_map(pos, ECORE_POS_MAP_DECELERATE, 0, 0);
570 if (progress < 0.0) progress = 0.0;
573 curr = (progress * ctx_begin->dest);
574 col = 255 - (255 * progress);
576 evas_object_geometry_get(ctx_begin->layout, &x, &y, &w, &h);
578 Evas_Map *m = evas_map_new(4);
579 evas_map_util_points_populate_from_object(m, ctx_begin->layout);
580 evas_map_util_rotate(m, curr, x + (w/2), y + (h/2));
581 evas_map_alpha_set(m, EINA_TRUE);
582 evas_map_util_points_color_set(m, col, col, col, col);
583 evas_object_map_set(ctx_begin->layout, m);
584 evas_object_map_enable_set(ctx_begin->layout, EINA_TRUE);
588 curr = ((-1.0f * progress * ctx_end->src) + ctx_end->src);
590 evas_object_geometry_get(ctx_end->layout, &x, &y, &w, &h);
593 evas_map_util_points_populate_from_object(m, ctx_end->layout);
594 evas_map_util_rotate(m, curr, x + (w/2), y + (h/2));
595 evas_object_map_set(ctx_end->layout, m);
596 evas_object_map_enable_set(ctx_end->layout, EINA_TRUE);
599 return ECORE_CALLBACK_RENEW;
603 _rotation_effect_start(Rotation_Effect *effect)
605 if ((!effect->ctx_begin) || (!effect->ctx_end)) return;
606 if (effect->running) return;
608 EFFINF("Rotation Effect Start", NULL, NULL);
610 effect->running = EINA_TRUE;
612 evas_object_raise(effect->ctx_begin->layout);
613 evas_object_show(effect->ctx_begin->layout);
614 evas_object_show(effect->ctx_end->layout);
616 evas_object_move(effect->bg, 0, 0);
617 evas_object_resize(effect->bg, effect->zone->w, effect->zone->h);
618 evas_object_lower(effect->bg);
619 evas_object_show(effect->bg);
621 effect->animator = ecore_animator_timeline_add(0.3f,
622 _rotation_effect_animator_cb_update,
627 _rotation_effect_animator_begin_prepare(Rotation_Effect *effect)
631 _rotation_effect_clear(effect);
633 effect->targets = _rotation_effect_targets_get(effect);
634 if (!effect->targets) return;
636 effect->ctx_begin = _rotation_effect_begin_create(effect, effect->targets);
637 if (!effect->ctx_begin)
639 _rotation_effect_clear(effect);
643 EFFINF("Rotation Begin Prepared", NULL, NULL);
645 /* add hwc override */
646 e_comp_override_add();
650 _rotation_effect_animator_end_prepare(Rotation_Effect *effect)
653 if (!effect->targets) return;
654 if (!effect->ctx_begin) return;
656 /* clear previous context */
658 _rotation_effect_animator_end_context_free(effect->ctx_end);
659 effect->ctx_end = NULL;
661 effect->ctx_end = _rotation_effect_end_create(effect, effect->targets);
662 if (!effect->ctx_end) return;
664 EFFINF("Rotation End Prepared", NULL, NULL);
666 effect->targets = eina_list_free(effect->targets);
670 _rotation_effect_cb_zone_rotation_begin(void *data, int type, void *event)
672 Rotation_Effect *effect;
673 E_Event_Zone_Rotation_Change_Begin *ev = event;
676 effect = (Rotation_Effect *)data;
677 if (!effect) return ECORE_CALLBACK_PASS_ON;
680 if (!zone) return ECORE_CALLBACK_PASS_ON;
682 EFFINF("Zone rotation begin zone(prev:%d cur:%d)",
684 zone->rot.prev, zone->rot.curr);
686 if (zone->rot.prev == zone->rot.curr) return ECORE_CALLBACK_PASS_ON;
688 _rotation_zone->curr_angle = zone->rot.curr;
689 _rotation_zone->prev_angle = zone->rot.prev;
691 _rotation_effect_animator_begin_prepare(effect);
693 return ECORE_CALLBACK_PASS_ON;
697 _rotation_effect_cb_zone_rotation_end(void *data, int type, void *event)
699 Rotation_Effect *effect;
700 E_Event_Zone_Rotation_Change_End *ev = event;
703 effect = (Rotation_Effect *)data;
704 if (!effect) return ECORE_CALLBACK_PASS_ON;
707 if (!zone) return ECORE_CALLBACK_PASS_ON;
709 EFFINF("Zone rotation end angle(prev:%d cur:%d)", NULL, NULL,
710 zone->rot.prev, zone->rot.curr);
712 if (effect->running) return ECORE_CALLBACK_PASS_ON;
713 if (effect->waiting_list)
715 effect->wait_for_buffer = EINA_TRUE;
716 return ECORE_CALLBACK_PASS_ON;
719 if (!effect->ctx_end) _rotation_effect_animator_end_prepare(effect);
720 if (effect->ctx_end) _rotation_effect_start(effect);
722 return ECORE_CALLBACK_PASS_ON;
726 _rotation_effect_cb_zone_rotation_cancel(void *data, int type, void *event)
728 Rotation_Effect *effect;
730 EFFINF("Zone Rotation Canceld", NULL, NULL);
732 effect = (Rotation_Effect *)data;
733 if (!effect) return ECORE_CALLBACK_PASS_ON;
734 if (effect->running) return ECORE_CALLBACK_PASS_ON;
736 _rotation_effect_clear(effect);
738 return ECORE_CALLBACK_PASS_ON;
742 _rotation_effect_cb_buffer_change(void *data, int ev_type, void *event)
744 E_Event_Client *ev = event;
746 Rotation_Effect *effect;
749 if (!ec) return ECORE_CALLBACK_PASS_ON;
751 effect = (Rotation_Effect *)data;
752 if (!effect) return ECORE_CALLBACK_PASS_ON;
753 if (!effect->ctx_begin) return ECORE_CALLBACK_PASS_ON;
754 if (!effect->waiting_list) return ECORE_CALLBACK_PASS_ON;
756 effect->waiting_list = eina_list_remove(effect->waiting_list, ec);
757 if (effect->waiting_list) return ECORE_CALLBACK_PASS_ON;
759 if (!effect->wait_for_buffer) return ECORE_CALLBACK_PASS_ON;
761 if (!effect->ctx_end) _rotation_effect_animator_end_prepare(effect);
762 if (effect->ctx_end) _rotation_effect_start(effect);
764 return ECORE_CALLBACK_PASS_ON;
768 _rotation_effect_free(Rotation_Effect *effect)
772 _rotation_effect_clear(effect);
773 evas_object_del(effect->bg);
777 static Rotation_Effect *
778 _rotation_effect_create(E_Zone *zone)
780 Rotation_Effect *rotation_effect;
782 rotation_effect = E_NEW(Rotation_Effect, 1);
783 if (!rotation_effect) return NULL;
785 rotation_effect->zone = zone;
787 rotation_effect->bg = evas_object_rectangle_add(e_comp->evas);
788 e_util_size_debug_set(rotation_effect->bg, 1);
789 evas_object_color_set(rotation_effect->bg, 0, 0, 0, 255);
790 evas_object_layer_set(rotation_effect->bg, E_LAYER_EFFECT);
791 evas_object_name_set(rotation_effect->bg, "rotation-bg");
793 return rotation_effect;
797 _rotation_zone_free(Rotation_Zone *rotation_zone)
799 if (!rotation_zone) return;
801 E_FREE_LIST(rotation_zone->event_hdlrs, ecore_event_handler_del);
803 _rotation_effect_free(rotation_zone->effect);
805 E_FREE(rotation_zone);
810 static Rotation_Zone *
811 _rotation_zone_create(E_Zone *zone)
813 Rotation_Zone *rotation_zone = NULL;
815 if (!zone) return NULL;
816 if ((zone->w == 0) || (zone->h == 0)) return NULL;
818 rotation_zone = E_NEW(Rotation_Zone, 1);
819 if (!rotation_zone) return NULL;
821 /* create rotation effect data */
822 rotation_zone->effect = _rotation_effect_create(zone);
823 if (!rotation_zone->effect)
825 E_FREE(rotation_zone);
829 rotation_zone->zone = zone;
830 rotation_zone->curr_angle = zone->rot.curr;
831 rotation_zone->prev_angle = zone->rot.prev;
833 E_LIST_HANDLER_APPEND(rotation_zone->event_hdlrs,
834 E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
835 _rotation_effect_cb_zone_rotation_begin, rotation_zone->effect);
837 E_LIST_HANDLER_APPEND(rotation_zone->event_hdlrs,
838 E_EVENT_ZONE_ROTATION_CHANGE_END,
839 _rotation_effect_cb_zone_rotation_end, rotation_zone->effect);
841 E_LIST_HANDLER_APPEND(rotation_zone->event_hdlrs,
842 E_EVENT_ZONE_ROTATION_CHANGE_CANCEL,
843 _rotation_effect_cb_zone_rotation_cancel, rotation_zone->effect);
845 E_LIST_HANDLER_APPEND(rotation_zone->event_hdlrs,
846 E_EVENT_CLIENT_BUFFER_CHANGE,
847 _rotation_effect_cb_buffer_change, rotation_zone->effect);
850 return rotation_zone;
854 e_mod_effect_rotation_init(void)
856 _rotation_zone = _rotation_zone_create(e_zone_current_get());
857 if (!_rotation_zone) return EINA_FALSE;
863 e_mod_effect_rotation_shutdown(void)
866 _rotation_zone_free(_rotation_zone);
868 _rotation_zone = NULL;