src/bin/e_win.h \
src/bin/e_xinerama.h \
src/bin/e_zoomap.h \
-src/bin/e_zone.h
+src/bin/e_zone.h \
+src/bin/e_util_transform.h
if HAVE_WAYLAND
ENLIGHTENMENTHEADERS += \
src/bin/e_xinerama.c \
src/bin/e_zoomap.c \
src/bin/e_zone.c \
+src/bin/e_util_transform.c \
$(ENLIGHTENMENTHEADERS)
if HAVE_WAYLAND
e_pixmap_client_set(ec->pixmap, NULL);
ec->pixmap = NULL;
+ if (ec->transform_core.transform_list)
+ {
+ E_Util_Transform *transform;
+
+ EINA_LIST_FREE(ec->transform_core.transform_list, transform)
+ {
+ e_util_transform_unref(transform);
+ }
+ }
+
+ ec->transform_core.result.enable = EINA_FALSE;
+
e_client_visibility_calculate();
}
}
#endif
+ e_client_transform_core_update(ec);
_e_client_hook_call(E_CLIENT_HOOK_EVAL_END, ec);
TRACE_DS_END();
Eina_Iterator *it;
Eina_Bool canvas_vis = EINA_TRUE;
Eina_Bool ec_vis, ec_opaque, changed;
+ int x = 0;
+ int y = 0;
+ int w = 0;
+ int h = 0;
const int edge = 1;
if (!zone) return;
/* check if external animation is running */
if (evas_object_data_get(ec->frame, "effect_running")) continue;
+ e_client_geometry_get(ec, &x, &y, &w, &h);
ec_vis = ec_opaque = changed = EINA_FALSE;
////////////////////////////////////////////////////////////////////////
it = eina_tiler_iterator_new(t);
EINA_ITERATOR_FOREACH(it, _r)
{
- if (E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
+ if (E_INTERSECTS(x, y, w, h,
_r->x, _r->y, _r->w, _r->h))
{
ec_vis = EINA_TRUE;
if ((!ec->argb) || (ec_opaque))
{
EINA_RECTANGLE_SET(&r,
- ec->x,
- ec->y,
- ec->w + edge,
- ec->h + edge);
+ x,
+ y,
+ w + edge,
+ h + edge);
eina_tiler_rect_del(t, &r);
if (eina_tiler_empty(t))
TRACE_DS_END();
}
+
+static Eina_Bool
+_e_client_transform_core_check_change(E_Client *ec)
+{
+ Eina_Bool check = EINA_FALSE;
+
+ if (!ec) return EINA_FALSE;
+
+ // check client position or size change
+ if (ec->x != ec->transform_core.backup.client_x ||
+ ec->y != ec->transform_core.backup.client_y ||
+ ec->w != ec->transform_core.backup.client_w ||
+ ec->h != ec->transform_core.backup.client_h)
+ {
+ check = EINA_TRUE;
+ ec->transform_core.backup.client_x = ec->x;
+ ec->transform_core.backup.client_y = ec->y;
+ ec->transform_core.backup.client_w = ec->w;
+ ec->transform_core.backup.client_h = ec->h;
+ }
+
+ // check new transform or del transform
+ if (ec->transform_core.changed)
+ {
+ check = EINA_TRUE;
+ ec->transform_core.changed = EINA_FALSE;
+ }
+
+ // check each transform change
+ if (ec->transform_core.transform_list)
+ {
+ Eina_List *l;
+ Eina_List *l_next;
+ E_Util_Transform *transform;
+
+ EINA_LIST_FOREACH_SAFE(ec->transform_core.transform_list, l, l_next, transform)
+ {
+ // del transform check
+ if (e_util_transform_ref_count_get(transform) <= 1)
+ {
+ ec->transform_core.transform_list = eina_list_remove(ec->transform_core.transform_list, transform);
+ e_util_transform_unref(transform);
+ check = EINA_TRUE;
+ continue;
+ }
+
+ // transform change test
+ if (e_util_transform_change_get(transform))
+ {
+ check = EINA_TRUE;
+ e_util_transform_change_unset(transform);
+ }
+ }
+ }
+
+ // check parent matrix change
+#ifdef HAVE_WAYLAND_ONLY
+ if (ec->comp_data)
+ {
+ E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data;
+
+ if (cdata->sub.data)
+ {
+ E_Client *parent = cdata->sub.data->parent;
+
+ if (parent && parent->transform_core.result.enable)
+ {
+ ec->transform_core.parent.enable = EINA_TRUE;
+
+ if (!e_util_transform_matrix_equal_check(&ec->transform_core.parent.matrix,
+ &parent->transform_core.result.matrix))
+ {
+ check = EINA_TRUE;
+ ec->transform_core.parent.matrix = parent->transform_core.result.matrix;
+ }
+ }
+ else if (ec->transform_core.parent.enable)
+ {
+ ec->transform_core.parent.enable = EINA_FALSE;
+ e_util_transform_matrix_load_identity(&ec->transform_core.parent.matrix);
+ check = EINA_TRUE;
+ }
+ }
+ }
+#endif
+
+ return check;
+}
+
+static void
+_e_client_transform_core_boundary_update(E_Client *ec, E_Util_Transform_Rect_Vertex *vertices)
+{
+ double minx, miny;
+ double maxx, maxy;
+ double initValue = 99999;
+ int i;
+
+ if (!ec) return;
+ if (!ec->frame) return;
+ if (!ec->transform_core.result.enable) return;
+ if (!vertices) return;
+
+ minx = initValue;
+ miny = initValue;
+ maxx = -initValue;
+ maxy = -initValue;
+
+ for (i = 0 ; i < 4 ; ++i)
+ {
+ double x = 0.0;
+ double y = 0.0;
+ e_util_transform_vertices_pos_get(vertices, i, &x, &y, 0, 0);
+
+ if (x < minx) minx = x;
+ if (y < miny) miny = y;
+ if (x > maxx) maxx = x;
+ if (y > maxy) maxy = y;
+ }
+
+ ec->transform_core.result.boundary.x = (int)(minx + 0.5);
+ ec->transform_core.result.boundary.y = (int)(miny + 0.5);
+ ec->transform_core.result.boundary.w = (int)(maxx - minx + 0.5);
+ ec->transform_core.result.boundary.h = (int)(maxy - miny + 0.5);
+
+ ELOGF("COMP", "[Transform][boundary][%d %d %d %d]", ec->pixmap, ec,
+ ec->transform_core.result.boundary.x, ec->transform_core.result.boundary.y,
+ ec->transform_core.result.boundary.w, ec->transform_core.result.boundary.h);
+}
+
+static void
+_e_client_transform_core_vertices_apply(E_Client *ec EINA_UNUSED, Evas_Object *obj, E_Util_Transform_Rect_Vertex *vertices)
+{
+ if (!obj) return;
+
+ if (vertices)
+ {
+ Evas_Map *map = evas_map_new(4);
+
+ if (map)
+ {
+ int i;
+ evas_map_util_points_populate_from_object_full(map, obj, 0);
+ evas_map_util_points_color_set(map, 255, 255, 255, 255);
+
+ for (i = 0 ; i < 4 ; ++i)
+ {
+ double dx = 0.0;
+ double dy = 0.0;
+ int x = 0;
+ int y = 0;
+
+ e_util_transform_vertices_pos_get(vertices, i, &dx, &dy, 0, 0);
+
+ x = (int)(dx + 0.5);
+ y = (int)(dy + 0.5);
+
+ evas_map_point_coord_set(map, i, x, y, 1.0);
+ }
+
+ evas_object_map_set(obj, map);
+ evas_object_map_enable_set(obj, EINA_TRUE);
+
+ evas_map_free(map);
+ }
+ }
+ else
+ evas_object_map_enable_set(obj, EINA_FALSE);
+}
+
+static void
+_e_client_transform_core_sub_update(E_Client *ec, E_Util_Transform_Rect_Vertex *vertices)
+{
+#ifdef HAVE_WAYLAND_ONLY
+ Eina_List *l;
+ E_Client *subc;
+ E_Comp_Wl_Client_Data *cdata;
+
+ if (!ec) return;
+ if (!ec->comp_data) return;
+
+ cdata = (E_Comp_Wl_Client_Data*)ec->comp_data;
+
+ if (cdata->sub.below_obj)
+ _e_client_transform_core_vertices_apply(ec, cdata->sub.below_obj, vertices);
+
+ EINA_LIST_FOREACH(cdata->sub.list, l, subc)
+ e_client_transform_core_update(subc);
+
+ EINA_LIST_FOREACH(cdata->sub.below_list, l, subc)
+ e_client_transform_core_update(subc);
+#endif
+}
+
E_API void
e_client_visibility_calculate(void)
{
E_API void
e_client_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h)
{
+ int gx = 0;
+ int gy = 0;
+ int gw = 0;
+ int gh = 0;
+
E_OBJECT_CHECK(ec);
E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
- if (ec->frame)
- evas_object_geometry_get(ec->frame, x, y, w, h);
+ if (e_client_transform_core_enable_get(ec))
+ {
+ gx = ec->transform_core.result.boundary.x;
+ gy = ec->transform_core.result.boundary.y;
+ gw = ec->transform_core.result.boundary.w;
+ gh = ec->transform_core.result.boundary.h;
+ }
else
{
- if (x) *x = ec->x;
- if (y) *y = ec->y;
- if (w) *w = ec->w;
- if (h) *h = ec->h;
+ if (ec->frame)
+ {
+ evas_object_geometry_get(ec->frame, &gx, &gy, &gw, &gh);
+ }
+ else
+ {
+ gx = ec->x;
+ gy = ec->y;
+ gw = ec->w;
+ gh = ec->h;
+ }
}
+
+ if (x) *x = gx;
+ if (y) *y = gy;
+ if (w) *w = gw;
+ if (h) *h = gh;
}
E_API E_Client *
ec->transform.angle = 0.0;
ec->transformed = EINA_FALSE;
}
+
+E_API Eina_Bool e_client_transform_core_enable_get(E_Client *ec)
+{
+ if (!ec) return EINA_FALSE;
+ return ec->transform_core.result.enable;
+}
+
+E_API void e_client_transform_core_add(E_Client *ec, E_Util_Transform *transform)
+{
+ if (!ec) return;
+ if (!transform) return;
+
+ // duplication check
+ if (ec->transform_core.transform_list &&
+ eina_list_data_find(ec->transform_core.transform_list, transform) == transform)
+ {
+ return;
+ }
+
+ ec->transform_core.transform_list = eina_list_append(ec->transform_core.transform_list, transform);
+ ec->transform_core.changed = EINA_TRUE;
+ e_util_transform_ref(transform);
+ e_client_transform_core_update(ec);
+}
+
+E_API void e_client_transform_core_remove(E_Client *ec, E_Util_Transform *transform)
+{
+ if (!ec) return;
+ if (!transform) return;
+
+ if (ec->transform_core.transform_list &&
+ eina_list_data_find(ec->transform_core.transform_list, transform) == transform)
+ {
+ ec->transform_core.transform_list = eina_list_remove(ec->transform_core.transform_list, transform);
+ e_util_transform_unref(transform);
+ ec->transform_core.changed = EINA_TRUE;
+ }
+
+ e_client_transform_core_update(ec);
+}
+
+E_API void e_client_transform_core_update(E_Client *ec)
+{
+ if (!ec) return;
+ if (ec->new_client) return;
+ if (!_e_client_transform_core_check_change(ec)) return;
+
+ if (ec->transform_core.transform_list || ec->transform_core.parent.enable)
+ {
+ E_Util_Transform_Rect source_rect;
+ E_Util_Transform_Matrix matrix, boundary_matrix;
+ Eina_List *l;
+ Eina_Bool keep_ratio = EINA_FALSE;
+ E_Util_Transform *temp_trans;
+
+ // 1. init state
+ ec->transform_core.result.enable = EINA_TRUE;
+ e_util_transform_rect_client_rect_get(&source_rect, ec);
+ e_util_transform_init(&ec->transform_core.result.transform);
+
+ // 2. merge transform
+ EINA_LIST_FOREACH(ec->transform_core.transform_list, l, temp_trans)
+ {
+ ec->transform_core.result.transform = e_util_transform_merge(&ec->transform_core.result.transform, temp_trans);
+ }
+
+ // 3. covert to matrix and apply keep_ratio
+ boundary_matrix = e_util_transform_convert_to_matrix(&ec->transform_core.result.transform, &source_rect);
+ keep_ratio = e_util_transform_keep_ratio_get(&ec->transform_core.result.transform);
+
+ if (keep_ratio)
+ {
+ ec->transform_core.result.transform = e_util_transform_keep_ratio_apply(&ec->transform_core.result.transform, ec->w, ec->h);
+ matrix = e_util_transform_convert_to_matrix(&ec->transform_core.result.transform, &source_rect);
+ }
+ else
+ matrix = boundary_matrix;
+
+ if (keep_ratio != ec->transform_core.keep_ratio)
+ {
+ if (keep_ratio)
+ {
+ e_comp_object_transform_bg_set(ec->frame, EINA_TRUE);
+ }
+ else
+ {
+ e_comp_object_transform_bg_set(ec->frame, EINA_FALSE);
+ }
+
+ ec->transform_core.keep_ratio = keep_ratio;
+ }
+
+ // 3.5 parent matrix multiply
+ if (ec->transform_core.parent.enable)
+ {
+ matrix = e_util_transform_matrix_multiply(&ec->transform_core.parent.matrix,
+ &matrix);
+ boundary_matrix = e_util_transform_matrix_multiply(&ec->transform_core.parent.matrix,
+ &boundary_matrix);
+ }
+
+ // 4. apply matrix to vertices
+ ec->transform_core.result.matrix = matrix;
+ ec->transform_core.result.vertices = e_util_transform_rect_to_vertices(&source_rect);
+ ec->transform_core.result.boundary.vertices = e_util_transform_rect_to_vertices(&source_rect);
+ ec->transform_core.result.vertices = e_util_transform_matrix_multiply_rect_vertex(&matrix,
+ &ec->transform_core.result.vertices);
+ ec->transform_core.result.boundary.vertices = e_util_transform_matrix_multiply_rect_vertex(&boundary_matrix,
+ &ec->transform_core.result.boundary.vertices);
+
+ // 5. apply vertices
+ e_comp_object_transform_bg_vertices_set(ec->frame, &ec->transform_core.result.boundary.vertices);
+ _e_client_transform_core_boundary_update(ec, &ec->transform_core.result.boundary.vertices);
+ _e_client_transform_core_vertices_apply(ec, ec->frame, &ec->transform_core.result.vertices);
+
+ // 6. subsurface update'
+ _e_client_transform_core_sub_update(ec, &ec->transform_core.result.vertices);
+ }
+ else
+ {
+ ec->transform_core.result.enable = EINA_FALSE;
+ _e_client_transform_core_vertices_apply(ec, ec->frame, NULL);
+ _e_client_transform_core_sub_update(ec, NULL);
+ }
+
+ e_client_visibility_calculate();
+}
+
+E_API int
+e_client_transform_core_transform_count_get(E_Client *ec)
+{
+ if (!ec) return 0;
+ if (!ec->transform_core.transform_list) return 0;
+ return eina_list_count(ec->transform_core.transform_list);
+}
+
+E_API E_Util_Transform*
+e_client_transform_core_transform_get(E_Client *ec, int index)
+{
+ if (!ec) return NULL;
+ if (!ec->transform_core.transform_list) return NULL;
+ if (index < 0 || index >= e_client_transform_core_transform_count_get(ec))
+ return NULL;
+
+ return (E_Util_Transform*)eina_list_nth(ec->transform_core.transform_list, index);
+}
Eina_Bool saved;
E_Layer saved_layer; // original layer
} changable_layer[E_CHANGABLE_LAYER_TYPE_MAX];
+
+ struct
+ {
+ Eina_List *transform_list;
+ Eina_Bool keep_ratio;
+ Eina_Bool changed;
+
+ struct
+ {
+ int client_x, client_y, client_w, client_h;
+ } backup;
+
+ struct
+ {
+ Eina_Bool enable;
+ E_Util_Transform_Matrix matrix;
+ E_Util_Transform_Rect_Vertex vertices;
+ E_Util_Transform transform;
+
+ struct
+ {
+ E_Util_Transform_Rect_Vertex vertices;
+ int x, y, w, h;
+ } boundary;
+
+ } result;
+
+ struct
+ {
+ Eina_Bool enable;
+ E_Util_Transform_Matrix matrix;
+ } parent;
+ } transform_core;
};
#define e_client_focus_policy_click(ec) \
YOLO E_API void e_client_focus_stack_set(Eina_List *l);
+E_API Eina_Bool e_client_transform_core_enable_get(E_Client *ec);
+E_API void e_client_transform_core_add(E_Client *ec, E_Util_Transform *transform);
+E_API void e_client_transform_core_remove(E_Client *ec, E_Util_Transform *transform);
+E_API void e_client_transform_core_update(E_Client *ec);
+E_API int e_client_transform_core_transform_count_get(E_Client *ec);
+E_API E_Util_Transform *e_client_transform_core_transform_get(E_Client *ec, int index);
+
/**
* Move window to coordinates that do not account client decorations yet.
*
Evas_Object *shobj; // shadow object
Evas_Object *effect_obj; // effects object
Evas_Object *mask_obj; // mask object: transparent parts of this comp object allow to copy the alpha to current H/W plane.
+ Evas_Object *transform_bg_obj; // transform backgroung with keep_ratio option
unsigned int layer; //e_comp_canvas_layer_map(cw->ec->layer)
Eina_List *obj_mirror; // extra mirror objects
Eina_Tiler *updates; //render update regions
/////////////////////////////////////
+static void
+_e_comp_object_transform_bg_stack_update(Evas_Object *obj)
+{
+ API_ENTRY;
+ EINA_SAFETY_ON_NULL_RETURN(cw->ec);
+ if (cw->ec->input_only) return;
+ if (!cw->transform_bg_obj) return;
+
+ if (evas_object_layer_get(obj) != evas_object_layer_get(cw->transform_bg_obj))
+ {
+ int layer = evas_object_layer_get(obj);
+ evas_object_layer_set(cw->transform_bg_obj, layer);
+ }
+ evas_object_stack_below(cw->transform_bg_obj, obj);
+}
+
+/////////////////////////////////////
+
static inline Eina_Bool
_e_comp_shaped_check(int w, int h, const Eina_Rectangle *rects, int num)
{
TRACE_DS_BEGIN(COMP:INTERCEPT STACK ABOVE);
_e_comp_intercept_stack_helper(data, above, evas_object_stack_above);
+ _e_comp_object_transform_bg_stack_update(obj);
TRACE_DS_END();
}
TRACE_DS_BEGIN(COMP:INTERCEPT STACK BELOW);
_e_comp_intercept_stack_helper(data, below, evas_object_stack_below);
+ _e_comp_object_transform_bg_stack_update(obj);
TRACE_DS_END();
}
if (e_comp->hwc &&e_comp->nocomp_ec == cw->ec) e_comp_nocomp_end(__FUNCTION__);
e_comp_render_queue();
e_comp_shape_queue();
+ _e_comp_object_transform_bg_stack_update(obj);
end:
TRACE_DS_END();
e_comp_nocomp_end(__FUNCTION__);
e_comp_render_queue();
e_comp_shape_queue();
+ _e_comp_object_transform_bg_stack_update(obj);
end:
TRACE_DS_END();
if (cw->mask_obj)
evas_object_resize(cw->mask_obj, cw->w, cw->h);
+ if (cw->transform_bg_obj)
+ evas_object_resize(cw->transform_bg_obj, cw->w, cw->h);
+
_e_comp_intercept_show_helper(cw);
}
evas_object_hide(cw->clip);
if (cw->input_obj) evas_object_hide(cw->input_obj);
evas_object_hide(cw->effect_obj);
+ if (cw->transform_bg_obj) evas_object_hide(cw->transform_bg_obj);
if (cw->ec->dead)
{
Evas_Object *o;
if (cw->ec->internal_elm_win && (!evas_object_visible_get(cw->ec->internal_elm_win)))
evas_object_show(cw->ec->internal_elm_win);
if (cw->mask_obj) evas_object_show(cw->mask_obj);
+ if (cw->transform_bg_obj) evas_object_show(cw->transform_bg_obj);
e_comp_render_queue();
if (cw->ec->input_only)
{
evas_object_del(cw->input_obj);
evas_object_del(cw->obj);
evas_object_del(cw->mask_obj);
+ evas_object_del(cw->transform_bg_obj);
e_comp_shape_queue();
eina_stringshare_del(cw->frame_theme);
eina_stringshare_del(cw->frame_name);
cw->input_rect.w, cw->input_rect.h);
if (cw->mask_obj)
evas_object_resize(cw->mask_obj, w, h);
+ if (cw->transform_bg_obj)
+ evas_object_resize(cw->transform_bg_obj, w, h);
/* resize render update tiler */
if (!first)
{
evas_object_image_data_set(cw->obj, NULL);
evas_object_image_size_set(cw->obj, w, h);
if (cw->mask_obj) evas_object_resize(cw->mask_obj, w, h);
+ if (cw->transform_bg_obj) evas_object_resize(cw->transform_bg_obj, w, h);
RENDER_DEBUG("SIZE [%p]: %dx%d", cw->ec, w, h);
if (cw->pending_updates)
evas_object_image_size_set(cw->obj, w, h);
}
+
+E_API void
+e_comp_object_transform_bg_set(Evas_Object *obj, Eina_Bool set)
+{
+ Eina_Bool transform_set = EINA_FALSE;
+ API_ENTRY;
+ EINA_SAFETY_ON_NULL_RETURN(cw->ec);
+ if (cw->ec->input_only) return;
+
+ transform_set = !!set;
+
+ if (transform_set)
+ {
+ if (!cw->transform_bg_obj)
+ {
+ Evas_Object *o = evas_object_rectangle_add(e_comp->evas);
+ evas_object_move(o, 0, 0);
+ evas_object_resize(o, cw->w, cw->h);
+ evas_object_render_op_set(o, EVAS_RENDER_COPY);
+ evas_object_color_set(o, 0, 0, 0, 255);
+ if (cw->visible) evas_object_show(o);
+
+ cw->transform_bg_obj = o;
+ }
+ _e_comp_object_transform_bg_stack_update(obj);
+ }
+ else
+ {
+ if (cw->transform_bg_obj)
+ {
+ evas_object_smart_member_del(cw->transform_bg_obj);
+ E_FREE_FUNC(cw->transform_bg_obj, evas_object_del);
+ }
+ }
+}
+
+E_API void
+e_comp_object_transform_bg_vertices_set(Evas_Object *obj, E_Util_Transform_Rect_Vertex *vertices)
+{
+ API_ENTRY;
+ EINA_SAFETY_ON_NULL_RETURN(cw->ec);
+ if (cw->ec->input_only) return;
+ if (!cw->transform_bg_obj) return;
+
+ if (vertices)
+ {
+ Evas_Map *map = evas_map_new(4);
+
+ if (map)
+ {
+ int i;
+ evas_map_util_points_populate_from_object_full(map, cw->transform_bg_obj, 0);
+ evas_map_util_points_color_set(map, 255, 255, 255, 255);
+
+ for (i = 0 ; i < 4 ; ++i)
+ {
+ double dx, dy;
+ int x, y;
+
+ e_util_transform_vertices_pos_get(vertices, i, &dx, &dy, 0, 0);
+
+ x = (int)(dx + 0.5);
+ y = (int)(dy + 0.5);
+
+ evas_map_point_coord_set(map, i, x, y, 1.0);
+ }
+
+ evas_object_map_set(cw->transform_bg_obj, map);
+ evas_object_map_enable_set(cw->transform_bg_obj, EINA_TRUE);
+
+ evas_map_free(map);
+ }
+ }
+ else
+ {
+ evas_object_map_enable_set(cw->transform_bg_obj, EINA_FALSE);
+ }
+}
E_API void e_comp_object_alpha_set(Evas_Object *obj, Eina_Bool alpha);
E_API void e_comp_object_mask_set(Evas_Object *obj, Eina_Bool set);
E_API void e_comp_object_size_update(Evas_Object *obj, int w, int h);
-
+E_API void e_comp_object_transform_bg_set(Evas_Object *obj, Eina_Bool set);
+E_API void e_comp_object_transform_bg_vertices_set(Evas_Object *obj, E_Util_Transform_Rect_Vertex *vertices);
#endif
#endif
#include "e_randr2.h"
#include "e_pixmap.h"
#include "e_comp_object.h"
+#include "e_util_transform.h"
#include "e_client.h"
#include "e_pointer.h"
#include "e_config.h"
while (keepRunning);
}
+static void
+_e_info_client_proc_transform_set(int argc, char **argv)
+{
+ int32_t id_enable_xy_sxsy_angle[8];
+ int i;
+
+ if (argc < 5)
+ {
+ printf("Error Check Args: enlightenment_info -transform [windowID] [transform id] [enable] [x] [y] [scale_x(percent)] [scale_y(percent)] [degree] [keep_ratio]\n");
+ return;
+ }
+
+ id_enable_xy_sxsy_angle[0] = 0; // transform id
+ id_enable_xy_sxsy_angle[1] = 1; // enable
+ id_enable_xy_sxsy_angle[2] = 0; // move x
+ id_enable_xy_sxsy_angle[3] = 0; // move y
+ id_enable_xy_sxsy_angle[4] = 100; // scale x percent
+ id_enable_xy_sxsy_angle[5] = 100; // scale y percent
+ id_enable_xy_sxsy_angle[6] = 0; // rotation degree
+ id_enable_xy_sxsy_angle[7] = 0; // keep ratio
+
+ for (i = 0 ; i < 8 && i+3 < argc; ++i)
+ id_enable_xy_sxsy_angle[i] = atoi(argv[i+3]);
+
+ if (!_e_info_client_eldbus_message_with_args("transform_message", NULL, "siiiiiiii",
+ argv[2], id_enable_xy_sxsy_angle[0] , id_enable_xy_sxsy_angle[1], id_enable_xy_sxsy_angle[2],
+ id_enable_xy_sxsy_angle[3], id_enable_xy_sxsy_angle[4], id_enable_xy_sxsy_angle[5],
+ id_enable_xy_sxsy_angle[6], id_enable_xy_sxsy_angle[7]))
+ {
+ printf("_e_info_client_eldbus_message_with_args error");
+ return;
+ }
+}
static struct
{
const char *option;
"fps", NULL,
"Print FPS in every sec",
_e_info_client_proc_fps_info
- }
+ },
+ {
+ "transform",
+ "[id enable x y w h angle keep_ratio]",
+ "Set transform in runtime",
+ _e_info_client_proc_transform_set
+ },
};
static void
Eldbus_Service_Interface *iface;
} E_Info_Server;
+typedef struct _E_Info_Transform
+{
+ E_Client *ec;
+ E_Util_Transform *transform;
+ int id;
+ int enable;
+} E_Info_Transform;
+
static E_Info_Server e_info_server;
+static Eina_List *e_info_transform_list = NULL;
#define VALUE_TYPE_FOR_TOPVWINS "uuisiiiiibbiibbis"
#define VALUE_TYPE_REQUEST_RESLIST "ui"
#define VALUE_TYPE_REPLY_RESLIST "ssi"
#define VALUE_TYPE_FOR_INPUTDEV "ssi"
+static E_Info_Transform *_e_info_transform_new(E_Client *ec, int id, int enable, int x, int y, int sx, int sy, int degree, int keep_ratio);
+static E_Info_Transform *_e_info_transform_find(E_Client *ec, int id);
+static void _e_info_transform_set(E_Info_Transform *transform, int enable, int x, int y, int sx, int sy, int degree, int keep_ratio);
+static void _e_info_transform_del(E_Info_Transform *transform);
+static void _e_info_transform_del_with_id(E_Client *ec, int id);
+
static void
_msg_clients_append(Eldbus_Message_Iter *iter)
{
__WINDOW_PROP_ARG_APPEND("Maximize_override", target_ec->maximize_override ? char_True : char_False);
__WINDOW_PROP_ARG_APPEND("Transformed", target_ec->transformed ? char_True : char_False);
__WINDOW_PROP_ARG_APPEND_TYPE("Ignore_first_unmap", "%c", target_ec->ignore_first_unmap);
+ __WINDOW_PROP_ARG_APPEND_TYPE("Transform_count", "%d", e_client_transform_core_transform_count_get(target_ec));
+ if (e_client_transform_core_transform_count_get(target_ec) > 0)
+ {
+ int i;
+ int count = e_client_transform_core_transform_count_get(target_ec);
+
+ __WINDOW_PROP_ARG_APPEND(" ", "[id] [move] [scale] [rotation] [keep_ratio]");
+ for (i = 0 ; i < count ; ++i)
+ {
+ double dx, dy, dsx, dsy, drz;
+ int x, y, rz;
+ int keep_ratio;
+ E_Util_Transform *transform = e_client_transform_core_transform_get(target_ec, i);
+ if (!transform) continue;
+
+ e_util_transform_move_get(transform, &dx, &dy, NULL);
+ e_util_transform_scale_get(transform, &dsx, &dsy, NULL);
+ e_util_transform_rotation_get(transform, NULL, NULL, &drz);
+ keep_ratio = e_util_transform_keep_ratio_get(transform);
+
+ x = (int)(dx + 0.5);
+ y = (int)(dy + 0.5);
+ rz = (int)(drz + 0.5);
+
+ __WINDOW_PROP_ARG_APPEND_TYPE("Transform", "[%d] [%d, %d] [%2.1f, %2.1f] [%d] [%d]", i, x, y, dsx, dsy, rz, keep_ratio);
+ }
+ }
#undef __WINDOW_PROP_ARG_APPEND
#undef __WINDOW_PROP_ARG_APPEND_TYPE
}
return reply;
}
+static Eldbus_Message *
+e_info_server_cb_transform_message(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
+{
+ Eldbus_Message *reply = eldbus_message_method_return_new(msg);
+ uint32_t enable, transform_id;
+ uint32_t x, y, sx, sy, degree;
+ uint32_t keep_ratio;
+ const char *value = NULL;
+ int32_t value_number;
+ Evas_Object *o;
+ E_Client *ec;
+
+ if (!eldbus_message_arguments_get(msg, "siiiiiiii", &value, &transform_id, &enable, &x, &y, &sx, &sy, °ree, &keep_ratio))
+ {
+ ERR("Error getting arguments.");
+ return reply;
+ }
+
+ if (strlen(value) >= 2 && value[0] == '0' && value[1] == 'x')
+ sscanf(value, "%x", &value_number);
+ else
+ sscanf(value, "%d", &value_number);
+
+ for (o = evas_object_top_get(e_comp->evas); o; o = evas_object_below_get(o))
+ {
+ ec = evas_object_data_get(o, "E_Client");
+ Ecore_Window win;
+ E_Info_Transform *transform_info;
+
+ if (!ec) continue;
+
+ win = e_client_util_win_get(ec);
+
+ if (win != value_number) continue;
+ transform_info = _e_info_transform_find(ec, transform_id);
+
+ if (transform_info)
+ {
+ _e_info_transform_set(transform_info, enable, x, y, sx, sy, degree, keep_ratio);
+
+ if (!enable)
+ _e_info_transform_del_with_id(ec, transform_id);
+ }
+ else
+ {
+ if (enable)
+ {
+ _e_info_transform_new(ec, transform_id, enable, x, y, sx, sy, degree, keep_ratio);
+ }
+ }
+
+ break;
+ }
+
+ return reply;
+}
+
static const Eldbus_Method methods[] = {
{ "get_window_info", NULL, ELDBUS_ARGS({"a("VALUE_TYPE_FOR_TOPVWINS")", "array of ec"}), _e_info_server_cb_window_info_get, 0 },
{ "dump_topvwins", ELDBUS_ARGS({"s", "directory"}), NULL, _e_info_server_cb_topvwins_dump, 0 },
{ "get_res_lists", ELDBUS_ARGS({VALUE_TYPE_REQUEST_RESLIST, "client resource"}), ELDBUS_ARGS({"a("VALUE_TYPE_REPLY_RESLIST")", "array of client resources"}), _e_info_server_cb_res_lists_get, 0 },
{ "get_input_devices", NULL, ELDBUS_ARGS({"a("VALUE_TYPE_FOR_INPUTDEV")", "array of input"}), _e_info_server_cb_input_device_info_get, 0},
{ "get_fps_info", NULL, ELDBUS_ARGS({"s", "fps request"}), _e_info_server_cb_fps_info_get, 0},
+ { "transform_message", ELDBUS_ARGS({"siiiiiiii", "transform_message"}), NULL, e_info_server_cb_transform_message, 0},
{ NULL, NULL, NULL, NULL, 0 }
};
e_info_server.conn = NULL;
}
+ if (e_info_transform_list)
+ {
+ E_Info_Transform *info;
+ Eina_List *l, *l_next;
+
+ EINA_LIST_FOREACH_SAFE(e_info_transform_list, l, l_next, info)
+ {
+ _e_info_transform_del(info);
+ }
+
+ eina_list_free(e_info_transform_list);
+ e_info_transform_list = NULL;
+ }
+
eldbus_shutdown();
return 1;
if (img) evas_object_del(img);
if (ee) ecore_evas_free(ee);
}
+
+
+static E_Info_Transform*
+_e_info_transform_new(E_Client *ec, int id, int enable, int x, int y, int sx, int sy, int degree, int keep_ratio)
+{
+ E_Info_Transform *result = NULL;
+ result = _e_info_transform_find(ec, id);
+
+ if (!result)
+ {
+ result = (E_Info_Transform*)malloc(sizeof(E_Info_Transform));
+ memset(result, 0, sizeof(E_Info_Transform));
+ result->id = id;
+ result->ec = ec;
+ result->transform = e_util_transform_new();
+ _e_info_transform_set(result, enable, x, y, sx, sy, degree, keep_ratio);
+ e_info_transform_list = eina_list_append(e_info_transform_list, result);
+
+ }
+
+ return result;
+}
+
+static E_Info_Transform*
+_e_info_transform_find(E_Client *ec, int id)
+{
+ Eina_List *l;
+ E_Info_Transform *transform;
+ E_Info_Transform *result = NULL;
+
+ EINA_LIST_FOREACH(e_info_transform_list, l, transform)
+ {
+ if (transform->ec == ec && transform->id == id)
+ {
+ result = transform;
+ break;
+ }
+ }
+
+ return result;
+}
+
+static void
+_e_info_transform_set(E_Info_Transform *transform, int enable, int x, int y, int sx, int sy, int degree, int keep_ratio)
+{
+ if (!transform) return;
+ if (!transform->transform) return;
+
+ e_util_transform_move(transform->transform, (double)x, (double)y, 0.0);
+ e_util_transform_scale(transform->transform, (double)sx / 100.0, (double)sy / 100.0, 1.0);
+ e_util_transform_rotation(transform->transform, 0.0, 0.0, degree);
+ e_util_transform_keep_ratio_set(transform->transform, keep_ratio);
+
+ if (enable)
+ e_client_transform_core_add(transform->ec, transform->transform);
+ else
+ e_client_transform_core_remove(transform->ec, transform->transform);
+
+ e_client_transform_core_update(transform->ec);
+}
+
+static void
+_e_info_transform_del(E_Info_Transform *transform)
+{
+ if (!transform) return;
+
+ e_info_transform_list = eina_list_remove(e_info_transform_list, transform);
+ e_client_transform_core_remove(transform->ec, transform->transform);
+ e_util_transform_del(transform->transform);
+ free(transform);
+}
+
+static void
+_e_info_transform_del_with_id(E_Client *ec, int id)
+{
+ E_Info_Transform *transform = NULL;
+ if (!ec) return;
+
+ transform = _e_info_transform_find(ec, id);
+
+ if (transform)
+ _e_info_transform_del(transform);
+}
--- /dev/null
+#include "e.h"
+#define E_UTIL_TRANSFORM_IS_ZERO(p) ((p) > -1e-21 && (p) < 1e-21)
+
+E_API E_Util_Transform*
+e_util_transform_new(void)
+{
+ E_Util_Transform *transform = (E_Util_Transform*)malloc(sizeof(E_Util_Transform));
+ if (transform)
+ {
+ transform->ref_count = 0;
+ e_util_transform_init(transform);
+ e_util_transform_ref(transform);
+ }
+ return transform;
+}
+
+E_API void
+e_util_transform_del(E_Util_Transform *transform)
+{
+ if (!transform) return;
+ e_util_transform_unref(transform);
+}
+
+E_API void
+e_util_transform_init(E_Util_Transform *transform)
+{
+ int back_ref_count = 0;
+ if (!transform) return;
+
+ back_ref_count = transform->ref_count;
+ memset(transform, 0, sizeof(E_Util_Transform));
+ transform->scale.value[0] = 1.0;
+ transform->scale.value[1] = 1.0;
+ transform->scale.value[2] = 1.0;
+ transform->changed = EINA_TRUE;
+ transform->ref_count = back_ref_count;
+}
+
+E_API void
+e_util_transform_ref(E_Util_Transform *transform)
+{
+ if (!transform) return;
+ transform->ref_count += 1;
+}
+
+E_API void
+e_util_transform_unref(E_Util_Transform *transform)
+{
+ if (!transform) return;
+ transform->ref_count -= 1;
+ if (transform->ref_count <= 0)
+ free(transform);
+}
+
+E_API int
+e_util_transform_ref_count_get(E_Util_Transform *transform)
+{
+ if (!transform) return 0;
+ return transform->ref_count;
+}
+
+E_API void
+e_util_transform_move(E_Util_Transform *transform, double x, double y, double z)
+{
+ if (!transform) return;
+
+ transform->move.value[0] = x;
+ transform->move.value[1] = y;
+ transform->move.value[2] = z;
+ transform->changed = EINA_TRUE;
+}
+
+E_API void
+e_util_transform_scale(E_Util_Transform *transform, double sx, double sy, double sz)
+{
+ if (!transform) return;
+
+ transform->scale.value[0] = sx;
+ transform->scale.value[1] = sy;
+ transform->scale.value[2] = sz;
+ transform->changed = EINA_TRUE;
+}
+
+E_API void
+e_util_transform_rotation(E_Util_Transform *transform, double rx, double ry, double rz)
+{
+ if (!transform) return;
+
+ transform->rotation.value[0] = rx;
+ transform->rotation.value[1] = ry;
+ transform->rotation.value[2] = rz;
+ transform->changed = EINA_TRUE;
+}
+
+E_API void
+e_util_transform_source_to_target(E_Util_Transform *transform,
+ E_Util_Transform_Rect *dest,
+ E_Util_Transform_Rect *source)
+{
+ if (!transform) return;
+ if (!dest || !source) return;
+
+ e_util_transform_init(transform);
+
+ if ((dest->x != source->x) || (dest->y != source->y))
+ e_util_transform_move(transform, dest->x - source->x, dest->y - source->y, 0.0);
+
+ if ((dest->w != source->w) || (dest->w != source->w))
+ {
+ if (!E_UTIL_TRANSFORM_IS_ZERO(source->w) &&
+ !E_UTIL_TRANSFORM_IS_ZERO(source->h))
+ {
+ e_util_transform_scale(transform, dest->w / source->w, dest->h / source->h, 1.0);
+ }
+ }
+
+ transform->changed = EINA_TRUE;
+}
+
+E_API E_Util_Transform
+e_util_transform_merge(E_Util_Transform *trans1, E_Util_Transform *trans2)
+{
+ E_Util_Transform result;
+ int i;
+
+ e_util_transform_init(&result);
+
+ if (!trans1) return result;
+ if (!trans2) return result;
+
+ for (i = 0 ; i < 3 ; ++i)
+ result.move.value[i] = trans1->move.value[i] + trans2->move.value[i];
+
+ for (i = 0 ; i < 3 ; ++i)
+ result.scale.value[i] = trans1->scale.value[i] * trans2->scale.value[i];
+
+ for (i = 0 ; i < 3 ; ++i)
+ result.rotation.value[i] = trans1->rotation.value[i] + trans2->rotation.value[i];
+
+ if (trans1->keep_ratio || trans2->keep_ratio)
+ result.keep_ratio = EINA_TRUE;
+
+ result.changed = EINA_TRUE;
+
+ return result;
+}
+
+E_API E_Util_Transform_Matrix
+e_util_transform_convert_to_matrix(E_Util_Transform *transform, E_Util_Transform_Rect *source_rect)
+{
+ E_Util_Transform_Matrix result;
+ e_util_transform_matrix_load_identity(&result);
+
+ if (!transform) return result;
+ if (!source_rect) return result;
+
+ double dest_w = source_rect->w * transform->scale.value[0];
+ double dest_h = source_rect->h * transform->scale.value[1];
+
+ e_util_transform_matrix_translate(&result, -source_rect->x - source_rect->w / 2.0, -source_rect->y - source_rect->h / 2.0, 0.0);
+ e_util_transform_matrix_scale(&result, transform->scale.value[0], transform->scale.value[1], transform->scale.value[2]);
+
+ if (!E_UTIL_TRANSFORM_IS_ZERO(transform->rotation.value[0]))
+ e_util_transform_matrix_rotation_x(&result, transform->rotation.value[0]);
+ if (!E_UTIL_TRANSFORM_IS_ZERO(transform->rotation.value[1]))
+ e_util_transform_matrix_rotation_y(&result, transform->rotation.value[1]);
+ if (!E_UTIL_TRANSFORM_IS_ZERO(transform->rotation.value[2]))
+ e_util_transform_matrix_rotation_z(&result, transform->rotation.value[2]);
+
+ e_util_transform_matrix_translate(&result, source_rect->x + transform->move.value[0] + (dest_w / 2.0),
+ source_rect->y + transform->move.value[1] + (dest_h / 2.0), 0.0);
+
+ return result;
+}
+
+E_API Eina_Bool
+e_util_transform_change_get(E_Util_Transform *transform)
+{
+ if (!transform) return EINA_FALSE;
+ return transform->changed;
+}
+
+E_API void
+e_util_transform_change_unset(E_Util_Transform *transform)
+{
+ if (!transform) return;
+ transform->changed = EINA_FALSE;
+}
+
+E_API void
+e_util_transform_keep_ratio_set(E_Util_Transform *transform, Eina_Bool enable)
+{
+ if (!transform) return;
+ if (transform->keep_ratio == enable) return;
+ transform->keep_ratio = enable;
+ transform->changed = EINA_TRUE;
+}
+
+E_API Eina_Bool
+e_util_transform_keep_ratio_get(E_Util_Transform *transform)
+{
+ if (!transform) return EINA_FALSE;
+ return transform->keep_ratio;
+}
+
+E_API E_Util_Transform
+e_util_transform_keep_ratio_apply(E_Util_Transform *transform, int origin_w, int origin_h)
+{
+ int i;
+ E_Util_Transform result;
+ E_Util_Transform_Vertex move_ver;
+ E_Util_Transform_Matrix matrix;
+
+ e_util_transform_vertex_init(&move_ver, 0.0, 0.0, 0.0, 1.0);
+ e_util_transform_matrix_load_identity(&matrix);
+
+ if (!transform) return result;
+
+ memcpy(&result, transform, sizeof(E_Util_Transform));
+
+ if (transform->scale.value[0] > transform->scale.value[1])
+ result.scale.value[0] = result.scale.value[1] = transform->scale.value[1];
+ else
+ result.scale.value[0] = result.scale.value[1] = transform->scale.value[0];
+
+ move_ver.vertex[0] += (transform->scale.value[0] - result.scale.value[0]) * origin_w * 0.5;
+ move_ver.vertex[1] += (transform->scale.value[1] - result.scale.value[1]) * origin_h * 0.5;
+
+ for(i = 0 ; i < 3 ; ++i)
+ result.move.value[i] += move_ver.vertex[i];
+
+ return result;
+}
+
+E_API void
+e_util_transform_move_get(E_Util_Transform *transform, double *x, double *y, double *z)
+{
+ if (!transform) return;
+ if (x) *x = transform->move.value[0];
+ if (y) *y = transform->move.value[1];
+ if (z) *z = transform->move.value[2];
+}
+
+E_API void
+e_util_transform_scale_get(E_Util_Transform *transform, double *x, double *y, double *z)
+{
+ if (!transform) return;
+ if (x) *x = transform->scale.value[0];
+ if (y) *y = transform->scale.value[1];
+ if (z) *z = transform->scale.value[2];
+}
+
+E_API void
+e_util_transform_rotation_get(E_Util_Transform *transform, double *x, double *y, double *z)
+{
+ if (!transform) return;
+ if (x) *x = transform->rotation.value[0];
+ if (y) *y = transform->rotation.value[1];
+ if (z) *z = transform->rotation.value[2];
+}
+
+E_API void
+e_util_transform_log(E_Util_Transform *transform, const char *str)
+{
+ if (!transform) return;
+ if (!str) return;
+
+ printf("[e_util_transform_log : %s\n", str);
+ printf("[move : %2.1f, %2.1f, %2.1f]\n", transform->move.value[0], transform->move.value[1], transform->move.value[2]);
+ printf("[scale : %2.1f, %2.1f, %2.1f]\n", transform->scale.value[0], transform->scale.value[1], transform->scale.value[2]);
+ printf("[rotation : %2.1f, %2.1f, %2.1f]\n", transform->rotation.value[0], transform->rotation.value[1], transform->rotation.value[2]);
+
+}
+
+E_API void
+e_util_transform_rect_init(E_Util_Transform_Rect *rect, int x, int y, int w, int h)
+{
+ if (!rect) return;
+
+ rect->x = x;
+ rect->y = y;
+ rect->w = w;
+ rect->h = h;
+}
+
+E_API void
+e_util_transform_rect_client_rect_get(E_Util_Transform_Rect *rect, E_Client *ec)
+{
+ if (!rect || !ec) return;
+ e_util_transform_rect_init(rect, ec->x, ec->y, ec->w, ec->h);
+}
+
+E_API E_Util_Transform_Rect_Vertex
+e_util_transform_rect_to_vertices(E_Util_Transform_Rect *rect)
+{
+ E_Util_Transform_Rect_Vertex result;
+ int i;
+
+ e_util_transform_vertices_init(&result);
+
+ if (!rect) return result;
+
+ // LT, RT, RB, LB
+ result.vertices[0].vertex[0] = rect->x;
+ result.vertices[0].vertex[1] = rect->y;
+
+ result.vertices[1].vertex[0] = rect->x + rect->w;
+ result.vertices[1].vertex[1] = rect->y;
+
+ result.vertices[2].vertex[0] = rect->x + rect->w;
+ result.vertices[2].vertex[1] = rect->y + rect->h;
+
+ result.vertices[3].vertex[0] = rect->x;
+ result.vertices[3].vertex[1] = rect->y + rect->h;
+
+ for (i = 0 ; i < 4 ; ++i)
+ {
+ result.vertices[i].vertex[2] = 1.0;
+ result.vertices[i].vertex[3] = 1.0;
+ }
+
+ return result;
+}
+
+
+E_API void
+e_util_transform_vertex_init(E_Util_Transform_Vertex *vertex, double x, double y, double z, double w)
+{
+ if (!vertex) return;
+
+ vertex->vertex[0] = x;
+ vertex->vertex[1] = y;
+ vertex->vertex[2] = z;
+ vertex->vertex[3] = w;
+}
+
+E_API void
+e_util_transform_vertex_pos_get(E_Util_Transform_Vertex *vertex, double *x, double *y, double *z, double *w)
+{
+ if (!vertex) return;
+
+ if (x) *x = vertex->vertex[0];
+ if (y) *y = vertex->vertex[1];
+ if (z) *z = vertex->vertex[2];
+ if (w) *w = vertex->vertex[3];
+}
+
+E_API void
+e_util_transform_vertices_init(E_Util_Transform_Rect_Vertex *vertices)
+{
+ int i;
+ if (!vertices) return;
+
+ for (i = 0 ; i < 4 ; ++i)
+ e_util_transform_vertex_init(&vertices->vertices[i], 0.0, 0.0, 0.0, 1.0);
+}
+
+E_API E_Util_Transform_Rect
+e_util_transform_vertices_to_rect(E_Util_Transform_Rect_Vertex *vertices)
+{
+ E_Util_Transform_Rect result;
+ e_util_transform_rect_init(&result, 0, 0, 0, 0);
+
+ if (vertices)
+ {
+ result.x = (int)(vertices->vertices[0].vertex[0] + 0.5);
+ result.y = (int)(vertices->vertices[0].vertex[1] + 0.5);
+ result.w = (int)(vertices->vertices[2].vertex[0] - vertices->vertices[0].vertex[0] + 0.5);
+ result.h = (int)(vertices->vertices[2].vertex[1] - vertices->vertices[0].vertex[1] + 0.5);
+ }
+
+ return result;
+}
+
+E_API void
+e_util_transform_vertices_pos_get(E_Util_Transform_Rect_Vertex *vertices, int index,
+ double *x, double *y, double *z, double *w)
+{
+ if (!vertices) return;
+ if (index < 0 || index >= 4) return;
+
+ e_util_transform_vertex_pos_get(&vertices->vertices[index], x, y, z, w);
+}
+
+E_API void
+e_util_transform_matrix_load_identity(E_Util_Transform_Matrix *matrix)
+{
+ if (!matrix) return;
+
+ matrix->mat[0][0] = 1; matrix->mat[0][1] = 0; matrix->mat[0][2] = 0; matrix->mat[0][3] = 0;
+ matrix->mat[1][0] = 0; matrix->mat[1][1] = 1; matrix->mat[1][2] = 0; matrix->mat[1][3] = 0;
+ matrix->mat[2][0] = 0; matrix->mat[2][1] = 0; matrix->mat[2][2] = 1; matrix->mat[2][3] = 0;
+ matrix->mat[3][0] = 0; matrix->mat[3][1] = 0; matrix->mat[3][2] = 0; matrix->mat[3][3] = 1;
+}
+
+E_API void
+e_util_transform_matrix_translate(E_Util_Transform_Matrix *matrix, double x, double y, double z)
+{
+ E_Util_Transform_Matrix source;
+
+ if (!matrix) return;
+
+ source = *matrix;
+
+ // | 1 0 0 dx| |m00 m01 m02 m03|
+ // | 0 1 0 dy| |m10 m11 m12 m13|
+ // | 0 0 1 dz| * |m20 m21 m22 m23|
+ // | 0 0 0 1 | |m30 m31 m32 m33|
+
+ matrix->mat[0][0] = source.mat[0][0] + x * source.mat[3][0];
+ matrix->mat[0][1] = source.mat[0][1] + x * source.mat[3][1];
+ matrix->mat[0][2] = source.mat[0][2] + x * source.mat[3][2];
+ matrix->mat[0][3] = source.mat[0][3] + x * source.mat[3][3];
+
+ matrix->mat[1][0] = source.mat[1][0] + y * source.mat[3][0];
+ matrix->mat[1][1] = source.mat[1][1] + y * source.mat[3][1];
+ matrix->mat[1][2] = source.mat[1][2] + y * source.mat[3][2];
+ matrix->mat[1][3] = source.mat[1][3] + y * source.mat[3][3];
+
+ matrix->mat[2][0] = source.mat[2][0] + z * source.mat[3][0];
+ matrix->mat[2][1] = source.mat[2][1] + z * source.mat[3][1];
+ matrix->mat[2][2] = source.mat[2][2] + z * source.mat[3][2];
+ matrix->mat[2][3] = source.mat[2][3] + z * source.mat[3][3];
+}
+
+E_API void
+e_util_transform_matrix_rotation_x(E_Util_Transform_Matrix *matrix, double degree)
+{
+ E_Util_Transform_Matrix source;
+ double radian = 0.0;
+ double s, c;
+
+ if (!matrix) return;
+
+ source = *matrix;
+ radian = degree * M_PI / 180.0;
+ s = sin(radian);
+ c = cos(radian);
+
+ // | 1 0 0 0 | |m00 m01 m02 m03|
+ // | 0 c -s 0 | |m10 m11 m12 m13|
+ // | 0 s c 0 | * |m20 m21 m22 m23|
+ // | 0 0 0 1 | |m30 m31 m32 m33|
+
+ matrix->mat[1][0] = c * source.mat[1][0] + (-s) * source.mat[2][0];
+ matrix->mat[1][1] = c * source.mat[1][1] + (-s) * source.mat[2][1];
+ matrix->mat[1][2] = c * source.mat[1][2] + (-s) * source.mat[2][2];
+ matrix->mat[1][3] = c * source.mat[1][3] + (-s) * source.mat[2][3];
+
+ matrix->mat[2][0] = s * source.mat[1][0] + c * source.mat[2][0];
+ matrix->mat[2][1] = s * source.mat[1][1] + c * source.mat[2][1];
+ matrix->mat[2][2] = s * source.mat[1][2] + c * source.mat[2][2];
+ matrix->mat[2][3] = s * source.mat[1][3] + c * source.mat[2][3];
+}
+
+E_API void
+e_util_transform_matrix_rotation_y(E_Util_Transform_Matrix *matrix, double degree)
+{
+ E_Util_Transform_Matrix source;
+ double radian = 0.0;
+ double s, c;
+
+ if (!matrix) return;
+
+ source = *matrix;
+ radian = degree * M_PI / 180.0;
+ s = sin(radian);
+ c = cos(radian);
+
+ // | c 0 s 0 | |m00 m01 m02 m03|
+ // | 0 1 0 0 | |m10 m11 m12 m13|
+ // |-s 0 c 0 | * |m20 m21 m22 m23|
+ // | 0 0 0 1 | |m30 m31 m32 m33|
+
+ matrix->mat[0][0] = c * source.mat[0][0] + s * source.mat[2][0];
+ matrix->mat[0][1] = c * source.mat[0][1] + s * source.mat[2][1];
+ matrix->mat[0][2] = c * source.mat[0][2] + s * source.mat[2][2];
+ matrix->mat[0][3] = c * source.mat[0][3] + s * source.mat[2][3];
+
+ matrix->mat[2][0] = (-s) * source.mat[0][0] + c * source.mat[2][0];
+ matrix->mat[2][0] = (-s) * source.mat[0][1] + c * source.mat[2][1];
+ matrix->mat[2][0] = (-s) * source.mat[0][2] + c * source.mat[2][2];
+ matrix->mat[2][0] = (-s) * source.mat[0][3] + c * source.mat[2][3];
+}
+
+E_API void
+e_util_transform_matrix_rotation_z(E_Util_Transform_Matrix *matrix, double degree)
+{
+ E_Util_Transform_Matrix source;
+ double radian = 0.0;
+ double s, c;
+
+ if (!matrix) return;
+
+ source = *matrix;
+ radian = degree * M_PI / 180.0;
+ s = sin(radian);
+ c = cos(radian);
+
+ // | c -s 0 0 | |m00 m01 m02 m03|
+ // | s c 0 0 | |m10 m11 m12 m13|
+ // | 0 0 1 0 | * |m20 m21 m22 m23|
+ // | 0 0 0 1 | |m30 m31 m32 m33|
+
+ matrix->mat[0][0] = c * source.mat[0][0] + (-s) * source.mat[1][0];
+ matrix->mat[0][1] = c * source.mat[0][1] + (-s) * source.mat[1][1];
+ matrix->mat[0][2] = c * source.mat[0][2] + (-s) * source.mat[1][2];
+ matrix->mat[0][3] = c * source.mat[0][3] + (-s) * source.mat[1][3];
+
+ matrix->mat[1][0] = s * source.mat[0][0] + c * source.mat[1][0];
+ matrix->mat[1][1] = s * source.mat[0][1] + c * source.mat[1][1];
+ matrix->mat[1][2] = s * source.mat[0][2] + c * source.mat[1][2];
+ matrix->mat[1][3] = s * source.mat[0][3] + c * source.mat[1][3];
+}
+
+E_API void
+e_util_transform_matrix_scale(E_Util_Transform_Matrix *matrix, double sx, double sy, double sz)
+{
+ E_Util_Transform_Matrix source;
+
+ if (!matrix) return;
+
+ source = *matrix;
+
+ // | sx 0 0 0| |m00 m01 m02 m03|
+ // | 0 sy 0 0| |m10 m11 m12 m13|
+ // | 0 0 sz 0| * |m20 m21 m22 m23|
+ // | 0 0 0 1| |m30 m31 m32 m33|
+
+ matrix->mat[0][0] = sx * source.mat[0][0];
+ matrix->mat[0][1] = sx * source.mat[0][1];
+ matrix->mat[0][2] = sx * source.mat[0][2];
+ matrix->mat[0][3] = sx * source.mat[0][3];
+
+ matrix->mat[1][0] = sy * source.mat[1][0];
+ matrix->mat[1][1] = sy * source.mat[1][1];
+ matrix->mat[1][2] = sy * source.mat[1][2];
+ matrix->mat[1][3] = sy * source.mat[1][3];
+
+ matrix->mat[2][0] = sz * source.mat[2][0];
+ matrix->mat[2][1] = sz * source.mat[2][1];
+ matrix->mat[2][2] = sz * source.mat[2][2];
+ matrix->mat[2][3] = sz * source.mat[2][3];
+}
+
+E_API E_Util_Transform_Matrix
+e_util_transform_matrix_multiply(E_Util_Transform_Matrix *matrix1,
+ E_Util_Transform_Matrix *matrix2)
+{
+ E_Util_Transform_Matrix result;
+ int row, col, i;
+ e_util_transform_matrix_load_identity(&result);
+
+ if (!matrix1) return result;
+ if (!matrix2) return result;
+ // |m00 m01 m02 m03| |m00 m01 m02 m03|
+ // |m10 m11 m12 m13| |m10 m11 m12 m13|
+ // |m20 m21 m22 m23| * |m20 m21 m22 m23|
+ // |m30 m31 m32 m33| |m30 m31 m32 m33|
+
+ for (row = 0 ; row < 4 ; ++row)
+ {
+ for (col = 0 ; col < 4; ++col)
+ {
+ double sum = 0.0;
+
+ for (i = 0 ; i < 4 ; ++i)
+ {
+ sum += matrix1->mat[row][i] * matrix2->mat[i][col];
+ }
+
+ result.mat[row][col] = sum;
+ }
+ }
+
+ return result;
+}
+
+E_API E_Util_Transform_Vertex
+e_util_transform_matrix_multiply_vertex(E_Util_Transform_Matrix *matrix,
+ E_Util_Transform_Vertex *vertex)
+{
+ E_Util_Transform_Vertex result;
+ int row, col;
+
+ e_util_transform_vertex_init(&result, 0.0, 0.0, 0.0, 1.0);
+ if (!vertex) return result;
+ if (!matrix) return result;
+
+ // |m00 m01 m02 m03| |x|
+ // |m10 m11 m12 m13| |y|
+ // |m20 m21 m22 m23| * |z|
+ // |m30 m31 m32 m33| |w|
+
+ for (row = 0 ; row < 4 ; ++row)
+ {
+ double sum = 0.0;
+
+ for (col = 0 ; col < 4; ++col)
+ {
+ sum += matrix->mat[row][col] * vertex->vertex[col];
+ }
+
+ result.vertex[row] = sum;
+ }
+
+ return result;
+}
+
+E_API E_Util_Transform_Rect_Vertex
+e_util_transform_matrix_multiply_rect_vertex(E_Util_Transform_Matrix *matrix,
+ E_Util_Transform_Rect_Vertex *vertices)
+{
+ E_Util_Transform_Rect_Vertex result;
+ int i;
+ e_util_transform_vertices_init(&result);
+
+ if (!matrix) return result;
+ if (!vertices) return result;
+
+ for (i = 0 ; i < 4 ; ++i)
+ result.vertices[i] = e_util_transform_matrix_multiply_vertex(matrix, &vertices->vertices[i]);
+
+ return result;
+}
+
+E_API Eina_Bool
+e_util_transform_matrix_equal_check(E_Util_Transform_Matrix *matrix,
+ E_Util_Transform_Matrix *matrix2)
+{
+ int row, col;
+ Eina_Bool result = EINA_TRUE;
+ if (!matrix || !matrix2) return EINA_FALSE;
+
+ for (row = 0 ; row < 4 && result ; ++row)
+ {
+ for (col = 0 ; col < 4 ; ++col)
+ {
+ if (matrix->mat[row][col] != matrix2->mat[row][col])
+ {
+ result = EINA_FALSE;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
--- /dev/null
+#ifdef E_TYPEDEFS
+
+typedef struct _E_Util_Transform_Value E_Util_Transform_Value;
+typedef struct _E_Util_Transform E_Util_Transform;
+typedef struct _E_Util_Transform_Rect E_Util_Transform_Rect;
+typedef struct _E_Util_Transform_Vertex E_Util_Transform_Vertex;
+typedef struct _E_Util_Transform_Rect_Vertex E_Util_Transform_Rect_Vertex;
+typedef struct _E_Util_Transform_Matrix E_Util_Transform_Matrix;
+
+#else
+#ifndef E_UTIL_TRANSFORM_H_
+#define E_UTIL_TRANSFORM_H_
+
+struct _E_Util_Transform_Value
+{
+ double value[3];
+};
+
+struct _E_Util_Transform
+{
+ E_Util_Transform_Value scale;
+ E_Util_Transform_Value move;
+ E_Util_Transform_Value rotation;
+ int ref_count;
+ Eina_Bool keep_ratio;
+ Eina_Bool changed;
+};
+
+struct _E_Util_Transform_Rect
+{
+ int x;
+ int y;
+ int w;
+ int h;
+};
+
+struct _E_Util_Transform_Vertex
+{
+ double vertex[4];
+};
+
+struct _E_Util_Transform_Rect_Vertex
+{
+ E_Util_Transform_Vertex vertices[4];
+};
+
+struct _E_Util_Transform_Matrix
+{
+ double mat[4][4];
+};
+
+E_API E_Util_Transform *e_util_transform_new(void);
+E_API void e_util_transform_del(E_Util_Transform *transform);
+E_API void e_util_transform_ref(E_Util_Transform *transform);
+E_API void e_util_transform_unref(E_Util_Transform *transform);
+E_API int e_util_transform_ref_count_get(E_Util_Transform *transform);
+E_API void e_util_transform_init(E_Util_Transform *transform);
+E_API void e_util_transform_move(E_Util_Transform *transform, double x, double y, double z);
+E_API void e_util_transform_scale(E_Util_Transform *transform, double sx, double sy, double sz);
+E_API void e_util_transform_rotation(E_Util_Transform *transform, double rx, double ry, double rz);
+E_API void e_util_transform_source_to_target(E_Util_Transform *transform,
+ E_Util_Transform_Rect *dest,
+ E_Util_Transform_Rect *source);
+E_API E_Util_Transform e_util_transform_merge(E_Util_Transform *trans1, E_Util_Transform *trans2);
+E_API E_Util_Transform_Matrix e_util_transform_convert_to_matrix(E_Util_Transform *transform, E_Util_Transform_Rect *source_rect);
+E_API Eina_Bool e_util_transform_change_get(E_Util_Transform *transform);
+E_API void e_util_transform_change_unset(E_Util_Transform *transform);
+E_API void e_util_transform_keep_ratio_set(E_Util_Transform *transform, Eina_Bool enable);
+E_API Eina_Bool e_util_transform_keep_ratio_get(E_Util_Transform *transform);
+E_API E_Util_Transform e_util_transform_keep_ratio_apply(E_Util_Transform *transform, int origin_w, int origin_h);
+E_API void e_util_transform_move_get(E_Util_Transform *transform, double *x, double *y, double *z);
+E_API void e_util_transform_scale_get(E_Util_Transform *transform, double *x, double *y, double *z);
+E_API void e_util_transform_rotation_get(E_Util_Transform *transform, double *x, double *y, double *z);
+E_API void e_util_transform_log(E_Util_Transform *transform, const char *str);
+
+E_API void e_util_transform_rect_init(E_Util_Transform_Rect *rect, int x, int y, int w, int h);
+E_API void e_util_transform_rect_client_rect_get(E_Util_Transform_Rect *rect, E_Client *ec);
+E_API E_Util_Transform_Rect_Vertex e_util_transform_rect_to_vertices(E_Util_Transform_Rect *rect);
+
+E_API void e_util_transform_vertex_init(E_Util_Transform_Vertex *vertex, double x, double y, double z, double w);
+E_API void e_util_transform_vertex_pos_get(E_Util_Transform_Vertex *vertex, double *x, double *y, double *z, double *w);
+
+E_API void e_util_transform_vertices_init(E_Util_Transform_Rect_Vertex *vertices);
+E_API E_Util_Transform_Rect e_util_transform_vertices_to_rect(E_Util_Transform_Rect_Vertex *vertex);
+E_API void e_util_transform_vertices_pos_get(E_Util_Transform_Rect_Vertex *vertices, int index,
+ double *x, double *y, double *z, double *w);
+
+E_API void e_util_transform_matrix_load_identity(E_Util_Transform_Matrix *matrix);
+E_API void e_util_transform_matrix_translate(E_Util_Transform_Matrix *matrix, double x, double y, double z);
+E_API void e_util_transform_matrix_rotation_x(E_Util_Transform_Matrix *matrix, double degree);
+E_API void e_util_transform_matrix_rotation_y(E_Util_Transform_Matrix *matrix, double degree);
+E_API void e_util_transform_matrix_rotation_z(E_Util_Transform_Matrix *matrix, double degree);
+E_API void e_util_transform_matrix_scale(E_Util_Transform_Matrix *matrix, double sx, double sy, double sz);
+E_API E_Util_Transform_Matrix e_util_transform_matrix_multiply(E_Util_Transform_Matrix *matrix1,
+ E_Util_Transform_Matrix *matrix2);
+E_API E_Util_Transform_Vertex e_util_transform_matrix_multiply_vertex(E_Util_Transform_Matrix *matrix,
+ E_Util_Transform_Vertex *vertex);
+E_API E_Util_Transform_Rect_Vertex e_util_transform_matrix_multiply_rect_vertex(E_Util_Transform_Matrix *matrix,
+ E_Util_Transform_Rect_Vertex *vertices);
+E_API Eina_Bool e_util_transform_matrix_equal_check(E_Util_Transform_Matrix *matrix,
+ E_Util_Transform_Matrix *matrix2);
+#endif
+#endif