2 * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
4 * This file is a modified version of BSD licensed file and
5 * licensed under the Flora License, Version 1.1 (the License);
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://floralicense.org/license/
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an AS IS BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * Please, see the COPYING file for the original copyright owner and
20 #include "e_mod_main.h"
21 #include "e_mod_rotation.h"
22 #include "e_mod_rotation_wl.h"
23 #include "e_mod_rotation_private.h"
24 #include <wayland-server.h>
25 #include "tizen-policy-ext-server-protocol.h"
27 #ifdef HAVE_AUTO_ROTATION
28 #include "e_mod_sensord.h"
31 #define TIZEN_ROTATION_ANGLE_TO_INT(angle) ((angle == TIZEN_ROTATION_ANGLE_0) ? 0 : \
32 (angle == TIZEN_ROTATION_ANGLE_90) ? 90 : \
33 (angle == TIZEN_ROTATION_ANGLE_180) ? 180 : \
34 (angle == TIZEN_ROTATION_ANGLE_270) ? 270 : -1)
36 #define INT_TO_TIZEN_ROTATION_ANGLE(angle) ((angle == 0) ? TIZEN_ROTATION_ANGLE_0 : \
37 (angle == 90) ? TIZEN_ROTATION_ANGLE_90 : \
38 (angle == 180) ? TIZEN_ROTATION_ANGLE_180 : \
39 (angle == 270) ? TIZEN_ROTATION_ANGLE_270 : TIZEN_ROTATION_ANGLE_NONE)
41 typedef struct _Policy_Ext_Rotation Policy_Ext_Rotation;
42 typedef struct _E_Client_Rotation E_Client_Rotation;
44 struct _Policy_Ext_Rotation
47 E_Vis_Grab *show_grab;
48 uint32_t available_angles, preferred_angle;
49 enum tizen_rotation_angle cur_angle, prev_angle;
50 Eina_List *rotation_list;
51 Eina_Bool angle_change_done;
52 Eina_Bool wait_update;
55 Ecore_Timer *wait_update_done_timer;
57 /* WORKAROUND for the client used manual rotation */
63 } wait_update_pending;
66 struct _E_Client_Rotation
69 Eina_List *async_list;
70 Eina_List *force_update_list;
71 Ecore_Timer *done_timer;
72 Eina_Bool screen_lock;
82 /* local subsystem variables */
83 static E_Client_Rotation rot =
96 static Eina_Hash *rot_hash = NULL;
97 static Eina_List *rot_cbs = NULL;
98 static Eina_List *rot_ec_hooks = NULL;
99 static Eina_List *rot_obj_hooks = NULL;
100 static Eina_List *rot_pixmap_hooks = NULL;
101 static Eina_List *wl_hooks = NULL;
102 static Eina_List *pol_vis_hooks = NULL;
103 static Ecore_Idle_Enterer *rot_idle_enterer = NULL;
104 static E_Client *fg_ec = NULL;
105 static struct wl_global *rot_global;
107 /* local subsystem functions */
108 static Policy_Ext_Rotation* _policy_ext_rotation_get(E_Client *ec);
110 /* local subsystem wayland rotation protocol related functions */
111 static void _e_tizen_rotation_destroy_cb(struct wl_client *client, struct wl_resource *resource);
112 static void _e_tizen_rotation_set_available_angles_cb(struct wl_client *client, struct wl_resource *resource, uint32_t angles);
113 static void _e_tizen_rotation_set_preferred_angle_cb(struct wl_client *client, struct wl_resource *resource, uint32_t angle);
114 static void _e_tizen_rotation_ack_angle_change_cb(struct wl_client *client, struct wl_resource *resource, uint32_t serial);
115 static void _e_tizen_rotation_set_geometry_hint_cb(struct wl_client *client, struct wl_resource *resource, uint32_t angle, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
116 static void _e_tizen_rotation_destroy(struct wl_resource *resource);
117 static void _e_tizen_rotation_send_angle_change(E_Client *ec, int angle);
118 static void _e_tizen_policy_ext_get_rotation_cb(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface);
119 static void _e_tizen_policy_ext_active_angle_cb(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface);
120 static void _e_tizen_policy_ext_bind_cb(struct wl_client *client, void *data, uint32_t version, uint32_t id);
122 /* local subsystem wayland rotation protocol related variables */
123 static const struct tizen_rotation_interface _e_tizen_rotation_interface =
125 _e_tizen_rotation_destroy_cb,
126 _e_tizen_rotation_set_available_angles_cb,
127 _e_tizen_rotation_set_preferred_angle_cb,
128 _e_tizen_rotation_ack_angle_change_cb,
129 _e_tizen_rotation_set_geometry_hint_cb,
131 static const struct tizen_policy_ext_interface _e_tizen_policy_ext_interface =
133 _e_tizen_policy_ext_get_rotation_cb,
134 _e_tizen_policy_ext_active_angle_cb,
137 /* local subsystem e_client_rotation related functions */
138 static void _e_client_rotation_list_remove(E_Client *ec);
139 static Eina_Bool _e_client_rotation_zone_set(E_Zone *zone, E_Client *include_ec, E_Client *exclude_ec);
140 static void _e_client_rotation_change_done(void);
141 static Eina_Bool _e_client_rotation_change_done_timeout(void *data);
142 static void _e_client_rotation_change_message_send(E_Client *ec);
143 static int _e_client_rotation_curr_next_get(const E_Client *ec);
144 static void _e_client_event_client_rotation_change_begin_send(E_Client *ec);
145 static void _e_client_event_client_rotation_change_begin_free(void *data, void *ev);
146 static void _e_client_event_client_rotation_change_cancel_send(E_Client *ec);
147 static void _e_client_event_client_rotation_change_cancel_free(void *data, void *ev);
148 static void _e_client_event_client_rotation_change_end_free(void *data, void *ev);
149 static void _e_client_event_client_rotation_geometry_set_send(E_Client *ec, unsigned int angle, int x, int y, int w, int h);
150 static void _e_client_event_client_rotation_geometry_set_free(void *data, void *ev);
151 static void _e_client_rotation_wait_update_clear(E_Client *ec);
153 /* local subsystem e_zone_rotation related functions */
154 static void _e_zone_event_rotation_change_begin_free(void *data, void *ev);
155 static void _e_zone_event_rotation_change_end_free(void *data, void *ev);
156 static void _e_zone_event_rotation_change_cancel_free(void *data, void *ev);
158 /* e_client_roation functions */
159 static Eina_Bool e_client_rotation_is_progress(E_Client *ec);
160 static int e_client_rotation_curr_angle_get(E_Client *ec);
161 static int e_client_rotation_next_angle_get(E_Client *ec);
162 static Eina_Bool e_client_rotation_is_available(E_Client *ec, int ang);
163 static Eina_Bool e_client_rotation_set(E_Client *ec, int rotation);
164 static void e_client_rotation_change_request(E_Client *ec, int rotation);
166 /* e_zone_roation functions */
167 static void e_zone_rotation_update_done(E_Zone *zone);
168 static void e_zone_rotation_update_cancel(E_Zone *zone);
169 static void e_zone_rotation_sub_set(E_Zone *zone, int rotation) EINA_UNUSED;
171 /* e_client event, hook, intercept callbacks */
172 static Eina_Bool _rot_cb_zone_rotation_change_begin(void *data EINA_UNUSED, int ev_type EINA_UNUSED, E_Event_Zone_Rotation_Change_Begin *ev);
173 static void _rot_hook_new_client(void *d EINA_UNUSED, E_Client *ec);
174 static void _rot_hook_client_del(void *d EINA_UNUSED, E_Client *ec);
175 static void _rot_hook_eval_end(void *d EINA_UNUSED, E_Client *ec);
176 static void _rot_hook_eval_fetch(void *d EINA_UNUSED, E_Client *ec);
177 static Eina_Bool _rot_intercept_hook_show_helper(void *d EINA_UNUSED, E_Client *ec);
178 static Eina_Bool _rot_intercept_hook_hide(void *d EINA_UNUSED, E_Client *ec);
179 static Eina_Bool _rot_cb_idle_enterer(void *data EINA_UNUSED);
182 _browser_check(E_Client *ec)
184 const char *name = e_client_util_name_get(ec);
185 if (!name) return EINA_FALSE;
186 if (!strncmp(name, "browser", 7)) return EINA_TRUE;
191 _camera_check(E_Client *ec)
193 const char *name = e_client_util_name_get(ec);
194 if (!name) return EINA_FALSE;
195 if (!strncmp(name, "camera-app", 10)) return EINA_TRUE;
196 if (!strncmp(name, "com.samsung.camera-app-lite", 27)) return EINA_TRUE;
201 _unlock_rot_for_fg_app(E_Zone *zone)
203 ELOGF("ROTATION", "UNLOCK for app-hint", NULL);
205 e_zone_rotation_unblock_type_set(zone,
206 E_ZONE_ROT_UNBLOCK_TYPE_APP_HINT,
210 e_zone_rotation_set(zone, e_mod_sensord_cur_angle_get());
214 _try_lock_rot_for_fg_app(E_Zone *zone)
216 ELOGF("ROTATION", "LOCK for app-hint", NULL);
218 if (zone->rot.block.sys_auto_rot)
219 e_zone_rotation_set(zone, 0);
221 e_zone_rotation_unblock_type_set(zone,
222 E_ZONE_ROT_UNBLOCK_TYPE_APP_HINT,
228 _no_active_lockscreen_check(E_Client *ec)
230 E_Client *ec2 = NULL;
234 if (!ec) return EINA_FALSE;
236 zone = e_comp_zone_find_by_ec(ec);
237 EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
239 /* NB: to set fg_ec to lockscreen, return true if given ec is lockscreen itself. */
240 if (e_policy_client_is_lockscreen(ec)) return EINA_TRUE;
243 for (ec2 = ec; ec2; ec2 = e_client_above_get(ec2))
245 if (e_object_is_del(E_OBJECT(ec2))) continue;
246 if (e_policy_client_is_lockscreen(ec2))
248 e_client_geometry_get(ec2, &x, &y, &w, &h);
249 if (E_CONTAINS(zone->x, zone->y, zone->w, zone->h, x, y, w, h))
251 /* lockscreen is shown on top of given ec. */
258 /* there is no lockscreen on top of given ec. */
263 _rot_client_check_will_visible(E_Client *ec)
265 E_Client *above = NULL;
266 Eina_Bool will_visible = EINA_TRUE;
268 int ec_x, ec_y, ec_w, ec_h;
269 int above_x, above_y, above_w, above_h;
275 e_client_geometry_get(ec, &ec_x, &ec_y, &ec_w, &ec_h);
277 for (above = e_client_above_get(ec); above; above = e_client_above_get(above))
279 if (e_client_util_ignored_get(above)) continue;
285 e_client_geometry_get(above, &above_x, &above_y, &above_w, &above_h);
286 if (!E_CONTAINS(above_x, above_y, above_w, above_h, ec_x, ec_y, ec_w, ec_h)) continue;
288 if (above->visibility.obscured == E_VISIBILITY_UNOBSCURED)
292 will_visible = EINA_FALSE;
297 if (above->visibility.opaque > 0)
299 will_visible = EINA_FALSE;
310 _rot_client_cb_vis_prepare_foreground(void *data, Evas_Object *obj, void *event_info)
312 Policy_Ext_Rotation *rot;
319 zone = e_comp_zone_find_by_ec(ec);
320 EINA_SAFETY_ON_NULL_RETURN(zone);
322 EDBG(ec, "Update Foreground Client '%s'(%p)", ec->icccm.name, ec);
323 if (e_policy_visibility_client_is_activity(ec))
325 EDBG(ec, "Check ec %x to set fg_ec", e_client_util_win_get(ec));
326 if (_no_active_lockscreen_check(ec))
328 if (ec->exp_iconify.not_raise)
330 if (_rot_client_check_will_visible(ec))
332 EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
338 EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
342 if (_camera_check(ec))
343 _unlock_rot_for_fg_app(zone);
345 _try_lock_rot_for_fg_app(zone);
349 _e_client_rotation_zone_set(zone, ec, NULL);
350 if (ec->changes.rotation)
352 EDBG(ec, "Postpone foreground: ang %d", ec->e.state.rot.ang.next);
353 e_pixmap_image_clear(ec->pixmap, 1);
354 rot->show_grab = e_policy_visibility_client_grab_get(ec, __func__);
355 /* to be invoked 'eval_end' */
361 _policy_ext_rotation_free(void *data)
363 Policy_Ext_Rotation *rot;
371 evas_object_smart_callback_del(ec->frame,
372 "e,visibility,prepare,foreground",
373 _rot_client_cb_vis_prepare_foreground);
379 /* local subsystem functions */
380 static Policy_Ext_Rotation*
381 _policy_ext_rotation_get(E_Client *ec)
383 Policy_Ext_Rotation *rot;
385 EINA_SAFETY_ON_NULL_RETURN_VAL(rot_hash, NULL);
387 rot = eina_hash_find(rot_hash, &ec);
390 rot = E_NEW(Policy_Ext_Rotation, 1);
391 EINA_SAFETY_ON_NULL_RETURN_VAL(rot, NULL);
394 rot->angle_change_done = EINA_TRUE;
395 eina_hash_add(rot_hash, &ec, rot);
396 evas_object_smart_callback_add(ec->frame,
397 "e,visibility,prepare,foreground",
398 _rot_client_cb_vis_prepare_foreground,
406 _e_tizen_rotation_destroy_cb(struct wl_client *client EINA_UNUSED,
407 struct wl_resource *resource)
409 wl_resource_destroy(resource);
413 _e_tizen_rotation_set_available_angles_cb(struct wl_client *client,
414 struct wl_resource *resource,
418 Policy_Ext_Rotation *rot;
420 rot = wl_resource_get_user_data(resource);
421 EINA_SAFETY_ON_NULL_RETURN(rot);
427 rot->available_angles = angles;
429 ec->e.fetch.rot.available_rots = 1;
434 _e_tizen_rotation_set_preferred_angle_cb(struct wl_client *client,
435 struct wl_resource *resource,
438 Policy_Ext_Rotation *rot;
441 rot = wl_resource_get_user_data(resource);
442 EINA_SAFETY_ON_NULL_RETURN(rot);
448 ELOGF("ROTATION", "Request to set Preferred angle:%d", ec, TIZEN_ROTATION_ANGLE_TO_INT(angle));
449 if ((angle != TIZEN_ROTATION_ANGLE_NONE) &&
450 (!e_mod_pol_rotation_is_conf_enable_angle(TIZEN_ROTATION_ANGLE_TO_INT(angle))))
452 ELOGF("ROTATION", "Preferred angle(%d) is not allowed. CONF disabled",
453 ec, TIZEN_ROTATION_ANGLE_TO_INT(angle));
457 rot->preferred_angle = angle;
459 if (TIZEN_ROTATION_ANGLE_TO_INT(angle) == e_client_rotation_curr_angle_get(ec))
461 ec->e.state.rot.preferred_rot = TIZEN_ROTATION_ANGLE_TO_INT(angle);
462 EDBG(ec, "preferred angle is same as current angle (%d). don't need to fetch.", ec->e.state.rot.preferred_rot);
466 /* for clients supporting portrait mode in floating state*/
467 if ((rot->preferred_angle) &&
468 !(rot->preferred_angle & TIZEN_ROTATION_ANGLE_90) &&
469 !(rot->preferred_angle & TIZEN_ROTATION_ANGLE_270))
471 enum tizen_rotation_angle tz_angle = 0;
474 struct wl_resource *res;
476 if ((ec->floating) && (ec->comp_data) && ((ec->comp_data->shell.window.w != ec->w) || (ec->comp_data->shell.window.h != ec->h)))
478 if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_0)
479 tz_angle = TIZEN_ROTATION_ANGLE_0;
480 else if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_180)
481 tz_angle = TIZEN_ROTATION_ANGLE_180;
484 ERR("What's this impossible angle?? : %d", rot->preferred_angle);
490 serial = wl_display_next_serial(e_comp_wl->wl.disp);
492 rot->angle_change_done = EINA_FALSE;
493 rot->prev_angle = rot->cur_angle;
494 rot->cur_angle = tz_angle;
495 rot->serial = serial;
497 EINA_LIST_FOREACH(rot->rotation_list, l, res)
499 int ver = wl_resource_get_version(res);
501 if ((ver >= 2) && ((tz_angle == TIZEN_ROTATION_ANGLE_0) || (tz_angle == TIZEN_ROTATION_ANGLE_180)))
503 int window_w, window_h;
504 if (!ec->comp_data) continue;
505 window_w = ec->comp_data->shell.window.w;
506 window_h = ec->comp_data->shell.window.h;
507 EDBG(ec, "Send Change Rotation: angle %d for rendering preparation of portrait mode in floating w/h:%dx%d, shell.w/h:%dx%d, Resize:%dx%d -> %dx%d",
508 tz_angle, ec->w, ec->h, window_w, window_h, window_w, window_h, window_h, window_w);
509 tizen_rotation_send_angle_change_with_resize(res, tz_angle, serial, window_h, window_w);
511 ec->e.state.rot.preferred_rot = TIZEN_ROTATION_ANGLE_TO_INT(angle);
518 ec->e.fetch.rot.preferred_rot = 1;
523 _wait_update_done_timer_cb(void *data)
525 Policy_Ext_Rotation *rot;
528 rot = (Policy_Ext_Rotation *)data;
529 if (!rot) return ECORE_CALLBACK_CANCEL;
531 rot->wait_update_done_timer = NULL;
536 if (!e_object_is_del(E_OBJECT(ec)))
538 EINF(ec, "Rotation Timeout... Force update rotation");
539 _e_client_rotation_wait_update_clear(ec);
543 return ECORE_CALLBACK_CANCEL;
547 _remove_rotation_wait_update_done_timer(Policy_Ext_Rotation *rot)
551 if (rot->wait_update_done_timer)
553 ecore_timer_del(rot->wait_update_done_timer);
554 rot->wait_update_done_timer = NULL;
559 _create_rotation_wait_update_done_timer(Policy_Ext_Rotation *rot)
563 _remove_rotation_wait_update_done_timer(rot);
565 rot->wait_update_done_timer = ecore_timer_add(5.0f, _wait_update_done_timer_cb, rot);
569 _e_tizen_rotation_angle_change(Policy_Ext_Rotation *rot)
574 if (!rot->ec) return;
575 if (rot->angle_change_done) return;
579 ec->e.state.rot.ang.prev = ec->e.state.rot.ang.curr;
580 ec->e.state.rot.ang.curr = TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle);
582 if (TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle) == ec->e.state.rot.ang.next)
584 ec->e.state.rot.ang.next = -1;
586 if (ec->e.state.rot.ang.reserve != -1)
588 _e_client_rotation_list_remove(ec);
590 e_client_rotation_set(ec, ec->e.state.rot.ang.reserve);
591 ec->e.state.rot.ang.reserve = -1;
595 /* it means that we need the next buffer commit after rotation ack event.
596 * once we get next buffer commit, policy module attempts to remove
597 * this ec from rotation_list_remove. and then, rotation process is finished.
599 rot->wait_update = EINA_TRUE;
603 * Until now, we have assumed that the buffer commit event after the rotation
604 * ack event informs us of completion of rotation. However this assumption could
605 * be wrong because the rotation ack event is dispatched by main thread of client,
606 * whereas the buffer commit event could be dispatched by other thread.
608 * The ideal solution for resolving this issue is introduction of same protocol
609 * serial number between the rotation ack event and buffer commit event. But this
610 * approach needs much of changes for EFL, E20 and DDK. Thus I have added workaround
611 * code for quick resolving this.
613 * We have to extend EFL, E20 and DDK to support this later.
615 if (_browser_check(ec))
617 if (rot->wait_update_pending.timer)
618 ecore_timer_del(rot->wait_update_pending.timer);
620 rot->wait_update_pending.timer = NULL;
621 rot->wait_update_pending.use = EINA_TRUE;
622 rot->wait_update_pending.count = 2;
627 // check angle change serial
628 rot->angle_change_done = EINA_TRUE;
632 _e_tizen_rotation_ack_angle_change_cb(struct wl_client *client,
633 struct wl_resource *resource,
637 Policy_Ext_Rotation *rot;
640 rot = wl_resource_get_user_data(resource);
641 EINA_SAFETY_ON_NULL_RETURN(rot);
646 EDBG(ec, "Rotation Done: prev %d cur %d serial %u",
647 ec->e.state.rot.ang.curr,
648 TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle),
651 zone = e_comp_zone_find_by_ec(ec);
652 EINA_SAFETY_ON_NULL_RETURN(zone);
654 if ((serial != 0) && (rot->serial == serial)) // rotation success
656 if (rot->angle_change_done)
658 WRN("Rotation Zone Set: Rotation Done(fail case): %s(%p) Already received change_done for this serial:%u",
659 ec->icccm.name ? ec->icccm.name : "", ec, serial);
663 _e_tizen_rotation_angle_change(rot);
665 else // rotation fail
667 WRN("Rotation Zone Set: Rotation Done(fail case): %s(%p) Not matched serial %u != %u",
668 ec->icccm.name ? ec->icccm.name : "", ec, rot->serial, serial);
670 _e_client_rotation_zone_set(zone, ec, NULL);
673 // check angle change serial
674 rot->angle_change_done = EINA_TRUE;
678 _e_tizen_rotation_set_geometry_hint_cb(struct wl_client *client,
679 struct wl_resource *resource,
681 uint32_t x, uint32_t y, uint32_t w, uint32_t h)
684 Policy_Ext_Rotation *rot;
688 rot = wl_resource_get_user_data(resource);
689 EINA_SAFETY_ON_NULL_RETURN(rot);
697 case TIZEN_ROTATION_ANGLE_0:
701 case TIZEN_ROTATION_ANGLE_90:
705 case TIZEN_ROTATION_ANGLE_180:
709 case TIZEN_ROTATION_ANGLE_270:
717 ec->e.state.rot.geom[i].x = x;
718 ec->e.state.rot.geom[i].y = y;
719 ec->e.state.rot.geom[i].w = w;
720 ec->e.state.rot.geom[i].h = h;
722 e_policy_hook_call(E_POLICY_HOOK_CLIENT_ROTATION_GEOMETRY_SET, ec);
723 _e_client_event_client_rotation_geometry_set_send(ec, angle, x, y, w, h);
727 _e_tizen_rotation_destroy(struct wl_resource *resource)
729 Policy_Ext_Rotation *ext_rot;
731 ext_rot = wl_resource_get_user_data(resource);
732 EINA_SAFETY_ON_NULL_RETURN(ext_rot);
734 ext_rot->rotation_list = eina_list_remove(ext_rot->rotation_list, resource);
736 /* if there's no connected client of tizen_rotation */
737 if (!ext_rot->rotation_list)
739 _e_client_rotation_list_remove(ext_rot->ec);
740 if (rot.async_list) rot.async_list = eina_list_remove(rot.async_list, ext_rot->ec);
742 ext_rot->angle_change_done = EINA_TRUE;
747 _e_tizen_policy_ext_get_rotation_cb(struct wl_client *client,
748 struct wl_resource *resource,
750 struct wl_resource *surface)
752 int version = wl_resource_get_version(resource); // resource is tizen_policy_ext resource
753 struct wl_resource *res;
755 Policy_Ext_Rotation *rot;
757 ec = e_client_from_surface_resource(surface);
758 EINA_SAFETY_ON_NULL_RETURN(ec);
761 rot = _policy_ext_rotation_get(ec);
762 EINA_SAFETY_ON_NULL_RETURN(rot);
764 res = wl_resource_create(client, &tizen_rotation_interface, version, id);
767 wl_client_post_no_memory(client);
771 rot->rotation_list = eina_list_append(rot->rotation_list, res);
773 wl_resource_set_implementation(res, &_e_tizen_rotation_interface,
774 rot, _e_tizen_rotation_destroy);
776 ec->e.fetch.rot.support = 1;
781 _e_tizen_policy_ext_active_angle_cb(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface)
786 E_Client *focused_ec;
789 zone = e_zone_current_get();
792 ec = e_client_from_surface_resource(surface);
794 zone = e_comp_zone_find_by_ec(ec);
796 zone = e_zone_current_get();
803 focused_ec = e_client_focused_get();
805 angle = zone->rot.curr;
807 angle = focused_ec->e.state.rot.ang.curr;
810 tizen_policy_ext_send_active_angle(resource, angle);
814 _e_tizen_policy_ext_bind_cb(struct wl_client *client, void *data, uint32_t version, uint32_t id)
816 struct wl_resource *res;
818 if (!(res = wl_resource_create(client, &tizen_policy_ext_interface, version, id)))
820 ERR("Could not create scaler resource: %m");
821 wl_client_post_no_memory(client);
825 wl_resource_set_implementation(res, &_e_tizen_policy_ext_interface, NULL, NULL);
829 _rot_eval_fetch_preferred_send_angle_change(Policy_Ext_Rotation *rot)
833 EINA_SAFETY_ON_NULL_RETURN_VAL(rot, EINA_FALSE);
839 if (!rot->preferred_angle)
842 /* for clients supporting landscape mode only */
843 if (!(rot->preferred_angle & TIZEN_ROTATION_ANGLE_0) &&
844 !(rot->preferred_angle & TIZEN_ROTATION_ANGLE_180))
846 enum tizen_rotation_angle tz_angle = 0;
849 struct wl_resource *res;
851 if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_90)
852 tz_angle = TIZEN_ROTATION_ANGLE_90;
853 else if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_270)
854 tz_angle = TIZEN_ROTATION_ANGLE_270;
857 ERR("What's this impossible angle?? : %d", rot->preferred_angle);
862 serial = wl_display_next_serial(e_comp_wl->wl.disp);
864 rot->angle_change_done = EINA_FALSE;
865 rot->prev_angle = rot->cur_angle;
866 rot->cur_angle = tz_angle;
867 rot->serial = serial;
869 EDBG(ec, "Send Change Rotation: angle %d for rendering preparation of landscape mode only app. mapped:%d serial:%u",
870 tz_angle, ec->first_mapped, serial);
872 ec->e.state.rot.ang.next = TIZEN_ROTATION_ANGLE_TO_INT(tz_angle);
874 EINA_LIST_FOREACH(rot->rotation_list, l, res)
876 tizen_rotation_send_angle_change(res, tz_angle, serial);
886 _rot_eval_fetch_available_send_angle_change(Policy_Ext_Rotation *rot)
888 enum tizen_rotation_angle cur_tz_angle;
891 EINA_SAFETY_ON_NULL_RETURN_VAL(rot, EINA_FALSE);
897 if (!rot->available_angles)
900 cur_tz_angle = INT_TO_TIZEN_ROTATION_ANGLE(ec->e.state.rot.ang.curr);
901 if (rot->available_angles & cur_tz_angle)
903 EDBG(ec, "Ignore it. current angle(%d) is one of available angles.", cur_tz_angle);
907 /* for clients supporting landscape mode only */
908 if (!(rot->available_angles & TIZEN_ROTATION_ANGLE_0) &&
909 !(rot->available_angles & TIZEN_ROTATION_ANGLE_180))
911 enum tizen_rotation_angle tz_angle = 0, zone_tz_angle = 0;
914 struct wl_resource *res;
918 zone = e_comp_zone_find_by_ec(ec);
921 if (zone->rot.unknown_state)
922 ang_zone = zone->rot.act;
924 ang_zone = zone->rot.curr;
926 zone_tz_angle = INT_TO_TIZEN_ROTATION_ANGLE(ang_zone);
929 if (rot->available_angles & zone_tz_angle)
930 tz_angle = zone_tz_angle;
931 else if (rot->available_angles & TIZEN_ROTATION_ANGLE_90)
932 tz_angle = TIZEN_ROTATION_ANGLE_90;
933 else if (rot->available_angles & TIZEN_ROTATION_ANGLE_270)
934 tz_angle = TIZEN_ROTATION_ANGLE_270;
937 ERR("What's this impossible angle?? : %d", rot->available_angles);
942 /* if the client requests a window rotation with the same value as the current angle, just ignore it. */
943 if ((ec->first_mapped) &&
944 (ec->e.state.rot.ang.curr == TIZEN_ROTATION_ANGLE_TO_INT(tz_angle)))
946 EDBG(ec, "Ignore it. given angle %d is same as the current angle for landscape only app.",
951 serial = wl_display_next_serial(e_comp_wl->wl.disp);
953 rot->angle_change_done = EINA_FALSE;
954 rot->prev_angle = rot->cur_angle;
955 rot->cur_angle = tz_angle;
956 rot->serial = serial;
958 EDBG(ec, "Send Change Rotation: angle %d for redering preparation of landscape only app. mapped:%d serial:%u",
959 tz_angle, ec->first_mapped, serial);
961 ec->e.state.rot.ang.next = TIZEN_ROTATION_ANGLE_TO_INT(tz_angle);
963 EINA_LIST_FOREACH(rot->rotation_list, l, res)
965 tizen_rotation_send_angle_change(res, tz_angle, serial);
974 _e_client_rotation_swap_check(E_Client *ec)
976 // Check whether the width and height of ec are swapped or not.
977 // If you want to make your swap policy, then you can modify this function.
981 if (!e_config->wm_win_rotation_swap_size)
986 if (e_policy_client_is_keyboard(ec) ||
987 e_policy_client_is_keyboard_sub(ec))
990 zone = e_comp_zone_find_by_ec(ec);
991 EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
993 e_client_geometry_get(ec, &x, &y, &w, &h);
994 if ((x != zone->x) ||
1004 _e_tizen_rotation_send_angle_change(E_Client *ec, int angle)
1007 Policy_Ext_Rotation *rot;
1009 struct wl_resource *resource;
1010 enum tizen_rotation_angle tz_angle = TIZEN_ROTATION_ANGLE_0;
1014 EINA_SAFETY_ON_NULL_RETURN(ec);
1015 EINA_SAFETY_ON_NULL_RETURN(rot_hash);
1017 rot_diff = ec->e.state.rot.ang.curr - angle;
1018 if (rot_diff < 0) rot_diff = -rot_diff;
1020 rot = eina_hash_find(rot_hash, &ec);
1026 tz_angle = TIZEN_ROTATION_ANGLE_0;
1029 tz_angle = TIZEN_ROTATION_ANGLE_90;
1032 tz_angle = TIZEN_ROTATION_ANGLE_180;
1035 tz_angle = TIZEN_ROTATION_ANGLE_270;
1041 serial = wl_display_next_serial(e_comp_wl->wl.disp);
1043 rot->angle_change_done = EINA_FALSE;
1044 rot->prev_angle = rot->cur_angle;
1045 rot->cur_angle = tz_angle;
1046 rot->serial = serial;
1048 EINA_LIST_FOREACH(rot->rotation_list, l, resource)
1050 ver = wl_resource_get_version(resource); // resource is type of tizen_rotation_interface
1052 Eina_Bool need_swap = EINA_FALSE;
1053 need_swap = _e_client_rotation_swap_check(ec);
1055 if ((ver >= 2) && (need_swap))
1057 if (rot_diff == 180)
1059 EDBG(ec, "Send Change Rotation: angle %d mapped:%d serial:%u Resize:%dx%d",
1060 tz_angle, ec->first_mapped, serial, ec->w, ec->h);
1062 tizen_rotation_send_angle_change_with_resize(resource, tz_angle, serial, ec->w, ec->h);
1066 EDBG(ec, "Send Change Rotation: angle %d mapped:%d serial:%u Resize:%dx%d -> %dx%d",
1067 tz_angle, ec->first_mapped, serial, ec->w, ec->h, ec->h, ec->w);
1069 tizen_rotation_send_angle_change_with_resize(resource, tz_angle, serial, ec->h, ec->w);
1074 EDBG(ec, "Send Change Rotation: angle %d mapped:%d serial:%u",
1075 tz_angle, ec->first_mapped, serial);
1077 tizen_rotation_send_angle_change(resource, tz_angle, serial);
1082 /* local subsystem e_client_rotation related functions */
1084 _e_client_rotation_list_remove(E_Client *ec)
1086 E_Event_Client_Rotation_Change_End *ev = NULL;
1087 Eina_Bool found = EINA_FALSE;
1090 zone = e_comp_zone_find_by_ec(ec);
1091 EINA_SAFETY_ON_NULL_RETURN(zone);
1093 if (eina_list_data_find(rot.list, ec) == ec)
1096 rot.list = eina_list_remove(rot.list, ec);
1099 if (ec->e.state.rot.wait_for_done)
1101 ec->e.state.rot.wait_for_done = 0;
1103 /* if we make the e_client event in the _e_client_free function,
1104 * then we may meet a crash problem, only work this at least e_client_hide.
1106 if (!e_object_is_del(E_OBJECT(ec)))
1108 ev = E_NEW(E_Event_Client_Rotation_Change_End, 1);
1112 e_object_ref(E_OBJECT(ec));
1113 EDBG(ec, "Rotation Event: Client Rotation END");
1114 ecore_event_add(E_EVENT_CLIENT_ROTATION_CHANGE_END,
1116 _e_client_event_client_rotation_change_end_free,
1122 (eina_list_count(rot.list) == 0))
1124 _e_client_rotation_change_done();
1126 /* handling pending zone rotation job */
1127 else if ((eina_list_count(rot.list) == 0) &&
1128 (zone->rot.wait_for_done) &&
1129 (zone->rot.pending))
1131 e_zone_rotation_update_done(zone);
1134 ec->e.state.rot.ang.next = -1;
1135 ec->changes.rotation = 0;
1139 _e_client_rotation_angle_is_allowed(E_Client *ec, int angle)
1141 if ((!_camera_check(ec)) &&
1142 (!e_mod_pol_rotation_is_conf_enable_angle(angle)))
1144 EDBG(ec, "CHECK dependent '%s'(%p) ang:%d rot.type:%d dependent:%d",
1145 ec->icccm.name, ec, angle,
1146 ec->e.state.rot.type,
1147 E_CLIENT_ROTATION_TYPE_DEPENDENT);
1149 /* check whether the window is 32bit and has the dependent rotation type.
1150 * if true, then it can be rotated according to below normal window
1151 * even if current zone angle is not allowed by configuration value.
1153 if (!((ec->argb) && (e_client_rotation_is_available(ec, angle))))
1160 _e_client_rotation_check_ec_size_and_type(E_Zone *zone, E_Client *ec)
1162 int ec_x, ec_y, ec_w, ec_h;
1164 if (!zone) return EINA_FALSE;
1165 if (!ec) return EINA_FALSE;
1172 e_client_geometry_get(ec, &ec_x, &ec_y, &ec_w, &ec_h);
1174 if ((ec_x == zone->x) && (ec_y == zone->y) &&
1175 (ec_w == zone->w) && (ec_h == zone->h) &&
1176 (ec->e.state.rot.type == E_CLIENT_ROTATION_TYPE_NORMAL))
1184 /* TODO need to optimize */
1186 _e_client_rotation_zone_set(E_Zone *zone, E_Client *include_ec, E_Client *exclude_ec)
1188 E_Client *ec, *bg_ec = NULL;
1189 Eina_List *target_list = NULL, *l, *ll;
1190 int angle, cur_angle, top_win_angle;
1191 Eina_Bool can_rotate = EINA_TRUE, ret = EINA_FALSE;
1193 TRACE_DS_BEGIN(CLIENT ROTATION ZONE SET);
1195 if (zone->rot.unknown_state)
1196 cur_angle = zone->rot.act;
1198 cur_angle = zone->rot.curr;
1202 DBG("<<< Try to set zone rotation | fg_ec '%s'(win:%x, ec:%p) cur_angle:%d zone(unknown_state:%d act:%d curr:%d)",
1203 fg_ec ? fg_ec->icccm.name : "",
1204 e_client_util_win_get(fg_ec),
1207 zone->rot.unknown_state,
1211 E_CLIENT_REVERSE_FOREACH(ec)
1213 if (zone != e_comp_zone_find_by_ec(ec)) continue;
1214 if (ec == exclude_ec) continue;
1215 if ((ec != include_ec) && (!evas_object_visible_get(ec->frame))) continue;
1216 if (e_object_is_del(E_OBJECT(ec))) continue;
1217 if (e_client_util_ignored_get(ec)) continue;
1218 if (evas_object_data_get(ec->frame, "comp_skip")) continue;
1219 if ((ec->comp_data) && (ec->comp_data->sub.data)) continue;
1220 if (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role))
1222 e_client_cursor_map_apply(ec, cur_angle, ec->x, ec->y);
1229 ((include_ec == ec) &&
1230 (evas_object_layer_get(ec->frame) >= evas_object_layer_get(bg_ec->frame))))
1232 if (_e_client_rotation_angle_is_allowed(ec, cur_angle))
1234 EDBG(ec, "Append to rotation target list");
1235 target_list = eina_list_append(target_list, ec);
1240 e_client_rotation_set(ec, cur_angle);
1244 if (_e_client_rotation_check_ec_size_and_type(zone, ec))
1248 EDBG(ec, "Found Topmost Fullscreen Window");
1253 if ((ec->visibility.opaque > 0) &&
1256 EDBG(ec, "Found Topmost Fullscreen Window");
1264 ELOGF("ROTATION", " fg_ec:%x, bg_ec:%p CHECK %s(%p) parent:%p vis:%d argb:%d opaque:%d",
1265 ec, e_client_util_win_get(fg_ec), bg_ec, ec->icccm.name, ec, ec->parent,
1266 ec->visibility.obscured, ec->argb, ec->visibility.opaque);
1267 /* if already found background client,
1268 * that means this client is placed under background client */
1271 /* if this client don't have parent, rotate */
1274 /* 1. rotate window only if auto-rotation is enabled.
1275 * it can show wrong rotated window if we don't check auto-rot value.
1277 * assuming that auto-rotation is disabled and window A is 0 degree.
1278 * in this case, when we attempt to run the camera-app which can be
1279 * always rotated, window A is changed to 270 degrees before showing
1280 * camera-app window. to prevent this we should check whether auto
1281 * rotation is enabled.
1283 * 2. also need to check this ec is visible before rotating it.
1285 * e.g. camera -> image-viewer launching case
1287 * image-viewer: bg_ec is set to image-viewer ec at the previous phase of this loop
1290 * if we decide to rotate camera ec which is obscured by image-viewer window,
1291 * then camera app will not send rotation done event. thus it occurrs rotation time
1292 * out error. to resolve this issue we should exclude obscured camera ec from
1295 * 2-1. Even if the ec is obscured by above, the ec can rotate if the ec is uniconic state.
1297 * e.g. fully obscured by 32bit opaque window, or parent window that obscured by their child.
1299 if ((!zone->rot.block.sys_auto_rot) &&
1300 (e_mod_pol_rotation_is_conf_enable_angle(cur_angle)) &&
1301 (ec->comp_data && ec->comp_data->mapped) &&
1302 ((ec->visibility.obscured != E_VISIBILITY_FULLY_OBSCURED) || !ec->iconic))
1304 ELOGF("ROTATION", "Do rotation of below ec under bg_ec %s(%p)",
1305 NULL, ec->icccm.name, ec);
1307 e_client_rotation_set(ec, cur_angle);
1313 * activity clients placed above background client should not be
1314 * rotated. that's because this is deactivated sometime later by
1315 * visibility's deiconify rendering logic.
1317 else if ((fg_ec != ec) && (include_ec != ec) &&
1318 _e_client_rotation_check_ec_size_and_type(zone, ec))
1324 if ((ec->visibility.opaque > 0) &&
1330 if (_e_client_rotation_angle_is_allowed(ec, cur_angle))
1332 EDBG(ec, "Append Rotation List '%s'(%p)", ec->icccm.name, ec);
1333 target_list = eina_list_append(target_list, ec);
1342 if (!target_list || (target_list && eina_list_count(target_list) == 0))
1344 DBG("Failed to set rotation with zone: target_list is empty. angle: %d", angle);
1346 angle = _e_client_rotation_curr_next_get(fg_ec);
1347 can_rotate = EINA_FALSE;
1350 EINA_LIST_FOREACH(target_list, l, ec)
1352 if (!e_client_rotation_is_available(ec, angle))
1354 EDBG(ec, "Failed to set rotation with zone: not able to rotate given angle %d", angle);
1355 angle = _e_client_rotation_curr_next_get(ec);
1356 can_rotate = EINA_FALSE;
1361 if (top_win_angle == -1)
1363 if (e_policy_client_is_keyboard(ec) ||
1364 e_policy_client_is_keyboard_sub(ec))
1367 EDBG(ec, "Set top_win_angle: %d", angle);
1368 top_win_angle = angle;
1375 can_rotate = EINA_TRUE;
1376 EINA_LIST_FOREACH(target_list, l, ec)
1378 if (!e_client_rotation_is_available(ec, angle))
1380 EDBG(ec, "Failed to set with exist client: not able to rotate given angle %d", angle);
1381 can_rotate = EINA_FALSE;
1386 if (top_win_angle == -1)
1388 if (e_policy_client_is_keyboard(ec) ||
1389 e_policy_client_is_keyboard_sub(ec))
1392 EDBG(ec, "Set top_win_angle: %d", angle);
1393 top_win_angle = angle;
1400 DBG("Set rotation of zone according to angle of zone: %d", angle);
1406 /* support more than one client with fixed angle value */
1407 if (eina_list_count(target_list) > 0)
1412 if (top_win_angle == -1)
1414 EINA_LIST_FOREACH_SAFE(target_list, l, ll, ec)
1416 DBG("Find top most window angle");
1417 // 1. check preferred
1418 if (ec->e.state.rot.preferred_rot != -1)
1420 EDBG(ec, "Set top_win_angle(preferred angle): %d", ec->e.state.rot.preferred_rot);
1421 top_win_angle = ec->e.state.rot.preferred_rot;
1425 // 2. check available angle
1426 for (i = 0; i < 4; i++)
1428 ang = (cur_angle + (i * 90)) % 360;
1429 if (e_client_rotation_is_available(ec, ang))
1431 EDBG(ec, "Set top_win_angle: %d", ang);
1432 top_win_angle = ang;
1437 if (top_win_angle == -1)
1439 // 3. couldn't find available angle
1440 EDBG(ec, "Cannot find any available angle. Set top_win_angle to 0");
1448 angle = top_win_angle;
1450 EINA_LIST_FOREACH_SAFE(target_list, l, ll, ec)
1452 EDBG(ec, "Attempt to rotate client with given angle %d", top_win_angle);
1453 if (e_client_rotation_is_available(ec, top_win_angle))
1455 res = e_client_rotation_set(ec, top_win_angle);
1456 if (!res) ret = EINA_FALSE;
1460 EDBG(ec, "Failed to set given angle %d, Keep current angle %d", top_win_angle, ec->e.state.rot.ang.curr);
1464 EINA_LIST_FOREACH(rot.force_update_list, l, ec)
1466 if (!eina_list_data_find(target_list, ec))
1468 EDBG(ec, "Rotate ec of force_update_list '%s'(%p)", ec->icccm.name, ec);
1469 res = e_client_rotation_set(ec, top_win_angle);
1470 if (!res) ret = EINA_FALSE;
1479 DBG("Set rotation of zone according to angle of exist clients: %d", angle);
1484 EINA_LIST_FOREACH(rot.force_update_list, l, ec)
1486 if (!eina_list_data_find(target_list, ec))
1488 EDBG(ec, "Append Rotation List from force_update_list '%s'(%p)", ec->icccm.name, ec);
1489 target_list = eina_list_append(target_list, ec);
1493 EINA_LIST_FOREACH(target_list, l, ec)
1494 ret = e_client_rotation_set(ec, angle);
1498 eina_list_free(target_list);
1500 zone->rot.act = angle;
1504 ELOGF("ROTATION", "zone active angle %d", NULL, zone->rot.act);
1505 DBG("End to set zone rotation: %s >>>", ret ? "Change" : "Stay");
1510 _e_client_rotation_change_done(void)
1512 Policy_Ext_Rotation *er;
1517 DBG("Remove rotation Timer by changing done");
1518 ecore_timer_del(rot.done_timer);
1520 rot.done_timer = NULL;
1522 EINA_LIST_FREE(rot.list, ec)
1524 if (ec->e.state.rot.pending_show)
1526 ec->e.state.rot.pending_show = 0;
1527 evas_object_show(ec->frame); // e_client_show(ec);
1528 e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
1530 er = eina_hash_find(rot_hash, &ec);
1531 if ((er) && (er->show_grab))
1532 E_FREE_FUNC(er->show_grab, e_policy_visibility_client_grab_release);
1533 ec->e.state.rot.ang.next = -1;
1534 ec->e.state.rot.wait_for_done = 0;
1537 EINA_LIST_FREE(rot.async_list, ec)
1539 _e_client_rotation_change_message_send(ec);
1543 rot.async_list = NULL;
1545 if (rot.screen_lock)
1547 // do call comp_wl's screen unlock
1548 ELOGF("ROTATION", "RENDERING resume", NULL);
1549 e_comp_canvas_norender_pop();
1550 rot.screen_lock = EINA_FALSE;
1552 e_zone_rotation_update_done(e_zone_current_get());
1556 _e_client_rotation_change_done_timeout(void *data)
1558 E_Client *ec = (E_Client *)data;
1560 if ((ec) && (!e_object_is_del(E_OBJECT(ec))))
1561 WRN("Timeout ROTATION_DONE %s(%p)",
1562 ec->icccm.name ? ec->icccm.name : "", ec);
1564 WRN("Timeout ROTATION_DONE (%p)", ec);
1566 _e_client_rotation_change_done();
1567 return ECORE_CALLBACK_CANCEL;
1571 _e_client_rotation_change_message_send(E_Client *ec)
1577 rotation = ec->e.state.rot.ang.next;
1578 if (rotation == -1) return;
1579 if (ec->e.state.rot.wait_for_done) return;
1581 e_client_rotation_change_request(ec, rotation);
1585 _e_client_rotation_curr_next_get(const E_Client *ec)
1589 return ((ec->e.state.rot.ang.next == -1) ?
1590 ec->e.state.rot.ang.curr : ec->e.state.rot.ang.next);
1594 _e_client_event_client_rotation_change_begin_send(E_Client *ec)
1596 E_Event_Client_Rotation_Change_Begin *ev = NULL;
1597 ev = E_NEW(E_Event_Client_Rotation_Change_Begin, 1);
1601 e_object_ref(E_OBJECT(ec));
1602 EDBG(ec, "Rotation Event: Client Rotation BEGIN");
1603 ecore_event_add(E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN,
1605 _e_client_event_client_rotation_change_begin_free,
1611 _e_client_event_client_rotation_change_cancel_send(E_Client *ec)
1613 E_Event_Client_Rotation_Change_Cancel *ev = NULL;
1614 ev = E_NEW(E_Event_Client_Rotation_Change_Cancel, 1);
1618 e_object_ref(E_OBJECT(ec));
1619 EDBG(ec, "Rotation Event: Client Rotation CANCEL");
1620 ecore_event_add(E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL,
1622 _e_client_event_client_rotation_change_cancel_free,
1628 _e_client_event_client_rotation_change_begin_free(void *data __UNUSED__,
1631 E_Event_Client_Rotation_Change_Begin *e;
1633 e_object_unref(E_OBJECT(e->ec));
1638 _e_client_event_client_rotation_change_cancel_free(void *data __UNUSED__,
1641 E_Event_Client_Rotation_Change_Cancel *e;
1643 e_object_unref(E_OBJECT(e->ec));
1648 _e_client_event_client_rotation_change_end_free(void *data __UNUSED__,
1651 E_Event_Client_Rotation_Change_End *e;
1653 e_object_unref(E_OBJECT(e->ec));
1658 _e_client_event_client_rotation_geometry_set_send(E_Client *ec, unsigned int angle, int x, int y, int w, int h)
1660 E_Event_Client_Rotation_Geometry_Set *ev = NULL;
1661 ev = E_NEW(E_Event_Client_Rotation_Geometry_Set, 1);
1670 e_object_ref(E_OBJECT(ec));
1671 ecore_event_add(E_EVENT_CLIENT_ROTATION_GEOMETRY_SET,
1673 _e_client_event_client_rotation_geometry_set_free,
1679 _e_client_event_client_rotation_geometry_set_free(void *data __UNUSED__,
1682 E_Event_Client_Rotation_Geometry_Set *e;
1684 e_object_unref(E_OBJECT(e->ec));
1689 _e_zone_event_rotation_change_begin_free(void *data __UNUSED__,
1692 E_Event_Zone_Rotation_Change_Begin *e = ev;
1693 e_object_unref(E_OBJECT(e->zone));
1698 _e_zone_event_rotation_change_end_free(void *data __UNUSED__,
1701 E_Event_Zone_Rotation_Change_End *e = ev;
1702 e_object_unref(E_OBJECT(e->zone));
1707 _e_zone_event_rotation_change_cancel_free(void *data __UNUSED__,
1710 E_Event_Zone_Rotation_Change_Cancel *e = ev;
1711 e_object_unref(E_OBJECT(e->zone));
1715 /* e_client_roation functions */
1718 * Get current rotoation state.
1719 * @param ec e_client
1720 * @return EINA_FALSE the state that does not rotating.
1721 * EINA_TRUE the state that rotating.
1724 e_client_rotation_is_progress(E_Client *ec)
1726 if (!ec) return EINA_FALSE;
1728 if (ec->e.state.rot.ang.next == -1)
1736 * Get current rotation angle.
1737 * @param ec e_client
1738 * @return int current angle
1741 e_client_rotation_curr_angle_get(E_Client *ec)
1743 E_OBJECT_CHECK_RETURN(ec, -1);
1744 E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, -1);
1746 return ec->e.state.rot.ang.curr;
1751 * Get being replaced rotation angle.
1752 * @param ec e_client
1753 * @return int be replaced angle.
1756 e_client_rotation_next_angle_get(E_Client *ec)
1758 E_OBJECT_CHECK_RETURN(ec, -1);
1759 E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, -1);
1761 return ec->e.state.rot.ang.next;
1765 e_client_rotation_find_below(E_Client *ec)
1767 E_Client *below_ec = NULL;
1769 for (below_ec = e_client_below_get(ec);
1771 below_ec = e_client_below_get(ec))
1773 if ((below_ec->comp_data && below_ec->comp_data->mapped) &&
1774 (!e_client_util_ignored_get(below_ec)) &&
1775 (!e_client_is_iconified_by_client(below_ec)))
1784 * Check if this e_client is rotatable to given angle.
1785 * @param ec e_client
1786 * @param ang test angle.
1787 * @return EINA_FALSE can't be rotated.
1788 * EINA_TRUE can be rotated.
1791 e_client_rotation_is_available(E_Client *ec, int ang)
1793 Eina_Bool ret = EINA_FALSE;
1795 E_Client *below = NULL;
1796 Eina_Bool below_rot = EINA_TRUE;
1797 int ec_x, ec_y, ec_w, ec_h;
1800 if (ang < 0) return EINA_FALSE;
1801 if (!ec->e.state.rot.support)
1804 zone = e_comp_zone_find_by_ec(ec);
1805 EINA_SAFETY_ON_NULL_GOTO(zone, no_hint);
1807 if (ec->e.state.rot.type == E_CLIENT_ROTATION_TYPE_DEPENDENT)
1809 // check below fullsize window's angle
1814 e_client_geometry_get(ec, &ec_x, &ec_y, &ec_w, &ec_h);
1816 if ((ec_x == zone->x) && (ec_y == zone->y) &&
1817 (ec_w == zone->w) && (ec_h == zone->h))
1819 below = e_client_rotation_find_below(ec);
1822 below_rot = e_client_rotation_is_available(below, ang);
1825 EDBG(ec, "ec's below(ec:%p, win:%x) can not rotate to angle [%d]", below, e_client_util_win_get(below), ang);
1832 if (ec->e.state.rot.preferred_rot == -1)
1834 if (ec->e.state.rot.available_rots &&
1835 ec->e.state.rot.count)
1837 for (i = 0; i < ec->e.state.rot.count; i++)
1839 if (ec->e.state.rot.available_rots[i] == ang)
1849 else if (ec->e.state.rot.preferred_rot == ang)
1859 * Set the rotation of the e_client given angle.
1860 * @param ec e_client
1861 * *param rotation angle
1862 * @return EINA_TRUE rotation starts or is already in progress.
1866 e_client_rotation_set(E_Client *ec, int rotation)
1868 Eina_List *list, *l;
1871 Policy_Ext_Rotation *ext_rot;
1873 if (!ec) return EINA_FALSE;
1875 if (rotation < 0) return EINA_FALSE;
1876 if (!e_client_rotation_is_available(ec, rotation)) return EINA_FALSE;
1878 TRACE_DS_BEGIN(CLIENT ROTATION SET);
1879 TRACE_DS_BEGIN(CLINET CURRENT ANGLE SET);
1881 // in case same with current angle.
1882 curr_rot = e_client_rotation_curr_angle_get(ec);
1883 EDBG(ec, "Client Rotation name:%s, curr_rot:%d, rotation:%d", ec->icccm.name?:"NULL", curr_rot, rotation);
1884 if (curr_rot == rotation)
1886 if (e_client_rotation_is_progress(ec))
1888 // cancel the changes in case only doesn't send request.
1889 if ((!ec->e.state.rot.pending_change_request) &&
1890 (!ec->e.state.rot.wait_for_done))
1892 EDBG(ec, "Client Rotation Canceled (curr_rot == rot %d)", rotation);
1893 _e_client_rotation_list_remove(ec);
1894 if (ec->e.state.rot.pending_show)
1896 ec->e.state.rot.pending_show = 0;
1897 if (!e_object_is_del(E_OBJECT(ec)))
1899 evas_object_show(ec->frame); // e_client_show(ec);
1900 e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
1904 _e_client_event_client_rotation_change_cancel_send(ec);
1920 ext_rot = eina_hash_find(rot_hash, &ec);
1923 if (ext_rot->wait_update_pending.timer)
1924 ecore_timer_del(ext_rot->wait_update_pending.timer);
1925 ext_rot->wait_update_pending.timer = NULL;
1928 // in case same with next angle.
1929 curr_rot = e_client_rotation_next_angle_get(ec);
1930 if (curr_rot == rotation)
1932 // if there is reserve angle, remove it.
1933 if (ec->e.state.rot.ang.reserve != -1)
1935 ec->e.state.rot.ang.reserve = -1;
1940 /* if this e_client is rotating now,
1941 * it will be rotated to this angle after rotation done.
1943 if ((ec->e.state.rot.pending_change_request) ||
1944 (ec->e.state.rot.wait_for_done))
1946 ec->e.state.rot.ang.reserve = rotation;
1950 /* search rotatable window in this window's child */
1951 list = eina_list_clone(ec->transients);
1952 EINA_LIST_FOREACH(list, l, child)
1954 // the window which type is "E_WINDOW_TYPE_NORMAL" will be rotated itself.
1955 // it shouldn't be rotated by rotation state of parent window.
1956 if (child->netwm.type == E_WINDOW_TYPE_NORMAL) continue;
1957 if (child->comp_data && !child->comp_data->mapped) continue;
1959 ELOGF("ROTATION", "Do rotation of child win %s(%p)",
1960 NULL, child->icccm.name, child);
1962 e_client_rotation_set(child, rotation);
1964 eina_list_free(list);
1966 if (!e_client_rotation_is_progress(ec))
1968 _e_client_event_client_rotation_change_begin_send(ec);
1971 ec->e.state.rot.pending_change_request = 0;
1972 ec->e.state.rot.ang.next = rotation;
1973 ec->changes.rotation = 1;
1977 /* Now the WM has a rotatable window thus we unset variables about zone rotation cancel */
1978 if (rot.cancel.state)
1980 rot.cancel.state = EINA_FALSE;
1981 rot.cancel.zone = NULL;
1989 e_client_rotation_change_request(E_Client *ec, int rotation)
1992 if (rotation < 0) return;
1994 // if this window is in withdrawn state, change the state to NORMAL.
1995 // that's because the window in withdrawn state can't render its canvas.
1996 // eventually, this window will not send the message of rotation done,
1997 // even if e request to rotation this window.
1999 //TODO: e_hint set is really neeed?.
2000 e_hints_window_visible_set(ec);
2002 _e_tizen_rotation_send_angle_change(ec, rotation);
2004 ec->e.state.rot.wait_for_done = 1;
2006 Policy_Ext_Rotation *ext_rot;
2007 ext_rot = _policy_ext_rotation_get(ec);
2010 _create_rotation_wait_update_done_timer(ext_rot);
2013 if ((!rot.async_list) ||
2014 (!eina_list_data_find(rot.async_list, ec)))
2017 ecore_timer_del(rot.done_timer);
2018 rot.done_timer = ecore_timer_add(4.0f,
2019 _e_client_rotation_change_done_timeout,
2024 /* e_zone_roation functions */
2026 _e_zone_rotation_set_internal(E_Zone *zone, int rot)
2028 E_Event_Zone_Rotation_Change_Begin *ev;
2030 E_OBJECT_CHECK(zone);
2031 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
2033 if (zone->rot.wait_for_done)
2035 INF("Pending Zone Rotation: wait_for_done %d block_count %d",
2036 zone->rot.wait_for_done, zone->rot.block.mod_count);
2037 zone->rot.next = rot;
2038 zone->rot.pending = EINA_TRUE;
2042 if (!e_config->wm_win_rotation) return;
2044 ELOGF("ROTATION", "ZONE_ROT |zone:%d|rot curr:%d, active:%d, rot:%d",
2045 NULL, zone->num, zone->rot.curr, zone->rot.act, rot);
2047 if ((zone->rot.curr == rot) &&
2048 (zone->rot.act == rot))
2051 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->1",
2052 NULL, zone->rot.wait_for_done);
2054 zone->rot.prev = zone->rot.act;
2055 zone->rot.curr = rot;
2056 zone->rot.wait_for_done = EINA_TRUE;
2058 ev = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
2062 e_object_ref(E_OBJECT(ev->zone));
2063 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
2064 ev, _e_zone_event_rotation_change_begin_free, NULL);
2069 e_zone_rotation_set(E_Zone *zone, int rotation)
2071 E_OBJECT_CHECK(zone);
2072 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
2074 TRACE_DS_BEGIN(ZONE ROTATION SET);
2076 zone->rot.unknown_state = EINA_TRUE;
2080 ELOGF("ROTATION", "ZONE_ROT |UNKNOWN SET|zone:%d|rot curr:%d, rot:%d",
2081 NULL, zone->num, zone->rot.curr, rotation);
2085 if (e_zone_rotation_block_get(zone, rotation))
2087 if ((zone->rot.wait_for_done) ||
2088 (zone->rot.block.mod_count > 0))
2090 if ((!zone->rot.unblock.app_hint) &&
2091 (!e_mod_pol_rotation_is_conf_enable_angle(rotation)))
2093 ELOGF("ROTATION", "ZONE_ROT |SKIP|zone:%d curr:%d rotation:%d config is not allowed",
2094 NULL, zone->num, zone->rot.curr, rotation);
2095 zone->rot.unknown_state = EINA_FALSE;
2099 INF("Pending Zone Rotation: wait_for_done %d block_count %d",
2100 zone->rot.wait_for_done, zone->rot.block.mod_count);
2101 zone->rot.next = rotation;
2102 zone->rot.pending = EINA_TRUE;
2106 if (zone->rot.block.sys_auto_rot)
2108 ELOGF("ROTATION", "ZONE_ROT |SKIP|zone:%d curr:%d rotation:%d. auto rotation is locked",
2109 NULL, zone->num, zone->rot.curr, rotation);
2110 zone->rot.unknown_state = EINA_FALSE;
2114 ELOGF("ROTATION", "ZONE_ROT |UNKNOWN SET|zone:%d|rot curr:%d, rot:%d",
2115 NULL, zone->num, zone->rot.curr, rotation);
2119 zone->rot.unknown_state = EINA_FALSE;
2121 _e_zone_rotation_set_internal(zone, rotation);
2126 e_zone_rotation_sub_set(E_Zone *zone, int rotation)
2128 E_OBJECT_CHECK(zone);
2129 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
2131 ELOGF("ROTATION", "SUB_SET |zone:%d|rot curr:%d, rot:%d",
2132 NULL, zone->num, zone->rot.curr, rotation);
2134 zone->rot.sub = rotation;
2136 if ((zone->rot.unknown_state) &&
2137 (zone->rot.curr != rotation))
2138 _e_zone_rotation_set_internal(zone, rotation);
2141 /* This function has the policy of window rotation LOCK which is
2142 * determined according to the UX or the system order of priority.
2145 e_zone_rotation_block_get(E_Zone *zone, int rot)
2147 /* 1. specific app which set special hint such as camera */
2148 if (zone->rot.unblock.app_hint)
2150 ELOGF("ROTATION", "BLOCK Get. unblocked by app_hint", NULL);
2154 /* 2. not supported angle in wm-policy configuration */
2155 if (!e_mod_pol_rotation_is_conf_enable_angle(rot))
2157 ELOGF("ROTATION", "BLOCK Get. CONF disabled", NULL);
2161 /* 3. auto-rotation through vconf */
2162 if (zone->rot.block.sys_auto_rot)
2164 ELOGF("ROTATION", "BLOCK Get. AUTO_ROT disabled", NULL);
2168 /* 4. temporary block count for the E sub-modules */
2169 if (zone->rot.block.mod_count > 0)
2171 ELOGF("ROTATION", "BLOCK Get. E internal block. %d", NULL,
2172 zone->rot.block.mod_count);
2180 e_zone_rotation_block_type_set(E_Zone *zone, E_Zone_Rot_Block_Type type, const char *name_hint, Eina_Bool block)
2182 E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
2183 E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
2187 case E_ZONE_ROT_BLOCK_TYPE_SYSTEM_AUTO_ROTATION:
2188 zone->rot.block.sys_auto_rot = block;
2189 ELOGF("ROTATION", "BLOCK_SET. sys_auto_rot:%s", NULL,
2190 block ? "true" : "false");
2192 case E_ZONE_ROT_BLOCK_TYPE_E_MODULE:
2193 if (block) zone->rot.block.mod_count++;
2194 else zone->rot.block.mod_count--;
2195 if (zone->rot.block.mod_count <= 0) zone->rot.block.mod_count = 0;
2196 ELOGF("ROTATION", "BLOCK_SET. e modules:%s count:%d", NULL,
2197 block ? "true" : "false", zone->rot.block.mod_count);
2207 e_zone_rotation_unblock_type_set(E_Zone *zone, E_Zone_Rot_Unblock_Type type, const char *name_hint, Eina_Bool unblock)
2209 E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
2210 E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
2214 case E_ZONE_ROT_UNBLOCK_TYPE_APP_HINT:
2215 zone->rot.unblock.app_hint = unblock;
2216 ELOGF("ROTATION", "UnBLOCK_SET app hint:%s", NULL,
2217 unblock ? "true" : "false");
2227 e_zone_rotation_block_set(E_Zone *zone, const char *name_hint, Eina_Bool block)
2229 E_Event_Zone_Rotation_Change_Begin *ev;
2231 E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
2232 E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
2234 e_zone_rotation_block_type_set(zone,
2235 E_ZONE_ROT_BLOCK_TYPE_E_MODULE,
2238 if (block) return EINA_TRUE;
2240 ELOGF("ROTATION", "ROT_BLOCK|RESUME|zone:%d|count:%d|from:%s|rot.pending:%d|next:%d",
2243 zone->rot.block.mod_count,
2248 if (zone->rot.pending)
2250 zone->rot.pending = EINA_FALSE;
2251 if (zone->rot.curr != zone->rot.next)
2253 if (e_zone_rotation_block_get(zone, zone->rot.next))
2255 zone->rot.pending = EINA_TRUE;
2256 ELOGF("ROTATION", "ROT_BLOCK|PAUSE|zone:%d|count:%d|from:%s", NULL,
2257 zone->num, zone->rot.block.mod_count, name_hint);
2261 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->1",
2262 NULL, zone->rot.wait_for_done);
2264 zone->rot.prev = zone->rot.curr;
2265 zone->rot.curr = zone->rot.next;
2266 zone->rot.wait_for_done = EINA_TRUE;
2267 zone->rot.pending = EINA_FALSE;
2269 ev = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
2273 e_object_ref(E_OBJECT(ev->zone));
2274 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
2275 ev, _e_zone_event_rotation_change_begin_free, NULL);
2277 ELOGF("ROTATION", "ROT_SET(P|zone:%d|rot:%d",
2278 NULL, zone->num, zone->rot.curr);
2287 e_zone_rotation_update_done(E_Zone *zone)
2289 E_Event_Zone_Rotation_Change_End *ev;
2291 E_OBJECT_CHECK(zone);
2292 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
2294 ELOGF("ROTATION", "ROT_DONE |zone:%d|rot:%d",
2295 NULL, zone->num, zone->rot.curr);
2297 ev = E_NEW(E_Event_Zone_Rotation_Change_End, 1);
2301 e_object_ref(E_OBJECT(ev->zone));
2302 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_END,
2303 ev, _e_zone_event_rotation_change_end_free, NULL);
2306 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->0",
2307 NULL, zone->rot.wait_for_done);
2309 zone->rot.wait_for_done = EINA_FALSE;
2310 if ((zone->rot.block.mod_count == 0) && (zone->rot.pending))
2312 zone->rot.pending = EINA_FALSE;
2313 if (zone->rot.curr != zone->rot.next)
2315 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->1",
2316 NULL, zone->rot.wait_for_done);
2318 zone->rot.prev = zone->rot.curr;
2319 zone->rot.curr = zone->rot.next;
2320 zone->rot.wait_for_done = EINA_TRUE;
2321 zone->rot.pending = EINA_FALSE;
2323 E_Event_Zone_Rotation_Change_Begin *ev2;
2324 ev2 = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
2328 e_object_ref(E_OBJECT(ev2->zone));
2329 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
2330 ev2, _e_zone_event_rotation_change_begin_free, NULL);
2332 ELOGF("ROTATION", "ROT_SET(P|zone:%d|rot:%d",
2333 NULL, zone->num, zone->rot.curr);
2341 e_zone_rotation_update_cancel(E_Zone *zone)
2343 E_Event_Zone_Rotation_Change_Cancel *ev;
2345 E_OBJECT_CHECK(zone);
2346 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
2348 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->0",
2349 NULL, zone->rot.wait_for_done);
2351 zone->rot.wait_for_done = EINA_FALSE;
2352 if (zone->rot.pending)
2354 zone->rot.prev = zone->rot.curr;
2355 zone->rot.curr = zone->rot.next;
2356 zone->rot.pending = EINA_FALSE;
2359 ev = E_NEW(E_Event_Zone_Rotation_Change_Cancel, 1);
2363 e_object_ref(E_OBJECT(ev->zone));
2364 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_CANCEL,
2365 ev, _e_zone_event_rotation_change_cancel_free, NULL);
2370 _rot_cb_zone_rotation_change_begin(void *data EINA_UNUSED, int ev_type EINA_UNUSED, E_Event_Zone_Rotation_Change_Begin *ev)
2372 if ((!ev) || (!ev->zone)) return ECORE_CALLBACK_PASS_ON;
2374 DBG("Rotation Zone Set: Rotation Change Begin");
2375 if (!_e_client_rotation_zone_set(ev->zone, NULL, NULL))
2377 /* The WM will decide to cancel zone rotation at idle time.
2378 * Because, the policy module can make list of rotation windows
2380 rot.cancel.state = EINA_TRUE;
2381 rot.cancel.zone = ev->zone;
2384 return ECORE_CALLBACK_RENEW;
2388 _e_tizen_rotation_smart_placement_apply(E_Client *ec)
2397 zone = e_comp_zone_find_by_ec(ec);
2398 EINA_SAFETY_ON_NULL_RETURN(zone);
2400 angle = zone->rot.curr;
2402 e_client_geometry_get(ec, &x, &y, &w, &h);
2416 // calculate x position
2429 else if (x2 > zx + zw)
2439 new_x = zx + zw - w;
2446 // calculate y position
2459 else if (y2 > zy + zh)
2469 new_y = zy + zh - h;
2476 if ((x != new_x) || (y != new_y))
2478 ELOGF("ROTATION", "APPLY placement policy. old(%d,%d) -> new(%d,%d), angle:%d", ec, x, y, new_x, new_y, angle);
2479 e_client_util_move_without_frame(ec, new_x, new_y);
2484 _e_client_rotation_wait_update_clear(E_Client *ec)
2486 Policy_Ext_Rotation *rot;
2488 rot = eina_hash_find(rot_hash, &ec);
2491 rot->wait_update_pending.timer = NULL;
2492 _remove_rotation_wait_update_done_timer(rot);
2494 if (!rot->angle_change_done)
2496 ELOGF("ROTATION", "TIMEOUT... waiting for rotation_ack_done... angle change by force", ec);
2497 _e_tizen_rotation_angle_change(rot);
2500 _e_client_rotation_list_remove(ec);
2501 if (ec->e.state.rot.pending_show)
2503 ec->e.state.rot.pending_show = 0;
2504 evas_object_show(ec->frame);
2505 e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
2509 E_FREE_FUNC(rot->show_grab, e_policy_visibility_client_grab_release);
2511 rot->wait_update = EINA_FALSE;
2513 _e_tizen_rotation_smart_placement_apply(ec);
2517 _e_client_rotation_wait_update_pending_timeout(void *data)
2519 E_Client *ec = (E_Client *)data;
2521 if ((ec) && (!e_object_is_del(E_OBJECT(ec))))
2522 WRN("Timeout Wait Update Pending %s(%p)",
2523 ec->icccm.name ? ec->icccm.name : "", ec);
2525 WRN("Timeout Wait Update Pending (%p)", ec);
2528 _e_client_rotation_wait_update_clear(ec);
2530 return ECORE_CALLBACK_CANCEL;
2534 _rot_cb_wl_buffer_change(void *d EINA_UNUSED, E_Client *ec)
2536 Policy_Ext_Rotation *rot;
2538 rot = eina_hash_find(rot_hash, &ec);
2540 if (ec->e.state.rot.nopending_render) return;
2542 if (!rot->angle_change_done)
2544 DBG("Update Buffer in progress of rotation ec '%s'(%p) HOOK",
2545 ec->icccm.name ? ec->icccm.name : "", ec);
2547 e_pixmap_image_clear(ec->pixmap, EINA_TRUE);
2548 e_pixmap_resource_set(ec->pixmap, NULL);
2553 _rot_cb_buffer_change(void *data EINA_UNUSED, int ev_type EINA_UNUSED, E_Event_Client *ev)
2555 Policy_Ext_Rotation *rot;
2557 if (EINA_UNLIKELY(!ev))
2560 if (EINA_UNLIKELY(!ev->ec))
2563 rot = eina_hash_find(rot_hash, &ev->ec);
2568 * wl_buffer can be destroyed after attach/damage/frame/commit to wl_surface.
2569 * we have to handle this case.
2571 if ((!rot->angle_change_done) || (!e_pixmap_resource_get(ev->ec->pixmap)))
2573 DBG("Update Buffer in progress of rotation ec '%s'(%p) EVENT nopending_render:%d",
2574 ev->ec->icccm.name ? ev->ec->icccm.name : "", ev->ec,
2575 ev->ec->e.state.rot.nopending_render);
2577 if (!ev->ec->e.state.rot.nopending_render)
2579 e_pixmap_image_clear(ev->ec->pixmap, EINA_TRUE);
2580 e_pixmap_resource_set(ev->ec->pixmap, NULL);
2583 else if (rot->wait_update)
2585 DBG("Update Buffer After Rotation Done ec '%s'(%p) b %p pending:%d count:%d",
2586 ev->ec->icccm.name ? ev->ec->icccm.name : "",
2588 e_pixmap_resource_get(ev->ec->pixmap),
2589 rot->wait_update_pending.use,
2590 rot->wait_update_pending.count);
2592 if (rot->wait_update_pending.use)
2594 if (rot->wait_update_pending.count > 0)
2596 if (rot->wait_update_pending.count == 2)
2598 if (rot->wait_update_pending.timer)
2599 ecore_timer_del(rot->wait_update_pending.timer);
2601 rot->wait_update_pending.timer = ecore_timer_add(0.1f,
2602 _e_client_rotation_wait_update_pending_timeout,
2606 rot->wait_update_pending.count--;
2607 return ECORE_CALLBACK_RENEW;
2611 if (rot->wait_update_pending.timer)
2612 ecore_timer_del(rot->wait_update_pending.timer);
2613 rot->wait_update_pending.timer = NULL;
2617 _e_client_rotation_wait_update_clear(ev->ec);
2620 if (ev->ec->e.state.rot.pending_show)
2622 DBG("Buffer Changed: force add update list to send frame until pending show");
2623 /* consider e_pixmap_image_clear() instead of update_add() */
2624 e_pixmap_image_clear(ev->ec->pixmap, EINA_TRUE);
2628 return ECORE_CALLBACK_RENEW;
2632 _rot_hook_new_client(void *d EINA_UNUSED, E_Client *ec)
2634 Policy_Ext_Rotation *rot;
2636 ec->e.state.rot.preferred_rot = -1;
2637 ec->e.state.rot.type = E_CLIENT_ROTATION_TYPE_NORMAL;
2638 ec->e.state.rot.ang.next = -1;
2639 ec->e.state.rot.ang.reserve = -1;
2640 ec->e.state.rot.pending_show = 0;
2641 ec->e.state.rot.ang.curr = 0;
2642 ec->e.state.rot.ang.prev = 0;
2644 EINA_SAFETY_ON_NULL_RETURN(rot_hash);
2646 rot = eina_hash_find(rot_hash, &ec);
2649 if (rot->preferred_angle)
2650 ec->e.fetch.rot.preferred_rot = 1;
2652 if (rot->available_angles)
2653 ec->e.fetch.rot.available_rots = 1;
2657 _rot_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
2659 Policy_Ext_Rotation *ext_rot;
2660 struct wl_resource *res;
2663 _e_client_rotation_list_remove(ec);
2664 if (rot.async_list) rot.async_list = eina_list_remove(rot.async_list, ec);
2666 ec->e.state.rot.preferred_rot = -1;
2668 if (ec->e.state.rot.available_rots)
2669 E_FREE(ec->e.state.rot.available_rots);
2671 ext_rot = eina_hash_find(rot_hash, &ec);
2674 if (ext_rot->wait_update_pending.timer)
2675 ecore_timer_del(ext_rot->wait_update_pending.timer);
2676 ext_rot->wait_update_pending.timer = NULL;
2678 _remove_rotation_wait_update_done_timer(ext_rot);
2680 EINA_LIST_FREE(ext_rot->rotation_list, res)
2681 wl_resource_set_user_data(res, NULL);
2683 if (ext_rot->show_grab)
2684 E_FREE_FUNC(ext_rot->show_grab, e_policy_visibility_client_grab_release);
2686 eina_hash_del_by_key(rot_hash, &ec);
2691 EDBG(ec, "Set the fg_ec to NULL");
2694 if (_camera_check(ec))
2696 zone = e_comp_zone_find_by_ec(ec);
2697 if (zone) _try_lock_rot_for_fg_app(zone);
2703 _rot_hook_eval_end(void *d EINA_UNUSED, E_Client *ec)
2707 zone = e_comp_zone_find_by_ec(ec);
2708 EINA_SAFETY_ON_NULL_RETURN(zone);
2710 if (ec->changes.rotation)
2712 int ec_x, ec_y, ec_w, ec_h;
2714 if (ec->moving) e_client_act_move_end(ec, NULL);
2720 e_client_geometry_get(ec, &ec_x, &ec_y, &ec_w, &ec_h);
2722 if ((!zone->rot.block.mod_count) &&
2723 ((!evas_object_visible_get(ec->frame)) ||
2724 (!E_INTERSECTS(ec_x, ec_y, ec_w, ec_h, zone->x, zone->y, zone->w, zone->h))))
2727 rot.async_list = eina_list_append(rot.async_list, ec);
2732 rot.list = eina_list_append(rot.list, ec);
2733 _e_client_rotation_change_message_send(ec);
2735 rot.fetch = EINA_TRUE;
2736 ec->changes.rotation = 0;
2741 _rot_hook_eval_fetch(void *d EINA_UNUSED, E_Client *ec)
2743 Policy_Ext_Rotation *rot;
2745 Eina_Bool early_angle_change = EINA_FALSE;
2749 rot = eina_hash_find(rot_hash, &ec);
2752 if(ec->e.fetch.rot.support)
2754 ec->e.state.rot.support = 1;
2756 ec->e.fetch.rot.need_rotation = EINA_TRUE;
2757 ec->e.fetch.rot.support = 0;
2759 if (ec->e.fetch.rot.preferred_rot)
2761 int _prev_preferred_rot;
2762 _prev_preferred_rot = ec->e.state.rot.preferred_rot;
2763 ec->e.state.rot.preferred_rot = -1;
2765 switch (rot->preferred_angle)
2767 case TIZEN_ROTATION_ANGLE_0:
2768 ec->e.state.rot.preferred_rot = 0;
2770 case TIZEN_ROTATION_ANGLE_90:
2771 ec->e.state.rot.preferred_rot = 90;
2773 case TIZEN_ROTATION_ANGLE_180:
2774 ec->e.state.rot.preferred_rot = 180;
2776 case TIZEN_ROTATION_ANGLE_270:
2777 ec->e.state.rot.preferred_rot = 270;
2783 if (_prev_preferred_rot != ec->e.state.rot.preferred_rot)
2784 ec->e.fetch.rot.need_rotation = EINA_TRUE;
2786 EDBG(ec, "Fetch Preferred: preferred (prev %d cur %d)",
2787 _prev_preferred_rot, ec->e.state.rot.preferred_rot);
2789 early_angle_change = _rot_eval_fetch_preferred_send_angle_change(rot);
2791 ec->e.fetch.rot.preferred_rot = 0;
2793 if (ec->e.fetch.rot.available_rots)
2795 Eina_Bool diff = EINA_FALSE;
2797 unsigned int _prev_count = 0, count = 0, i = 0;
2798 int _prev_rots[4] = { -1, };
2799 uint32_t available_angles = 0;
2801 if (ec->e.state.rot.available_rots)
2804 ec->e.state.rot.available_rots,
2805 (sizeof(int) * ec->e.state.rot.count));
2808 _prev_count = ec->e.state.rot.count;
2809 ec->e.state.rot.count = 0;
2811 /* check avilable_angles */
2812 if (rot->available_angles & TIZEN_ROTATION_ANGLE_0) count++;
2813 if (rot->available_angles & TIZEN_ROTATION_ANGLE_90) count++;
2814 if (rot->available_angles & TIZEN_ROTATION_ANGLE_180) count++;
2815 if (rot->available_angles & TIZEN_ROTATION_ANGLE_270) count++;
2818 rots = (int*)E_NEW(int, count);
2822 if (ec->e.state.rot.available_rots)
2824 /* restore previous rotation hints */
2825 memcpy(ec->e.state.rot.available_rots, _prev_rots, (sizeof(int) * _prev_count));
2830 if (ec->e.state.rot.available_rots)
2831 E_FREE(ec->e.state.rot.available_rots);
2833 available_angles = rot->available_angles;
2835 if ((count > 0) && (rots))
2837 for (i = 0; i < count; i++)
2839 if (available_angles & TIZEN_ROTATION_ANGLE_0)
2842 available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_0;
2844 else if (available_angles & TIZEN_ROTATION_ANGLE_90)
2847 available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_90;
2849 else if (available_angles & TIZEN_ROTATION_ANGLE_180)
2852 available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_180;
2854 else if (available_angles & TIZEN_ROTATION_ANGLE_270)
2857 available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_270;
2861 ec->e.state.rot.available_rots = rots;
2862 ec->e.state.rot.count = count;
2864 if (_prev_count != count) diff = EINA_TRUE;
2866 for (i = 0; i < count; i++)
2868 if ((!diff) && (_prev_rots[i] != rots[i]))
2875 /* check avilable_angles end*/
2877 /* Print fetch information */
2879 Eina_Strbuf *b = eina_strbuf_new();
2881 EINF(ec, "Fetch Available");
2882 if (_prev_count > 0)
2884 for (i = 0; i < _prev_count; i++)
2885 eina_strbuf_append_printf(b, "%d ", _prev_rots[i]);
2886 INF("\tprev %s", eina_strbuf_string_get(b));
2887 eina_strbuf_reset(b);
2890 for (i = 0; i < count; i++)
2891 eina_strbuf_append_printf(b, "%d ", rots[i]);
2892 INF("\tcur %s", eina_strbuf_string_get(b));
2894 eina_strbuf_free(b);
2897 if (diff) ec->e.fetch.rot.need_rotation = EINA_TRUE;
2898 ec->e.fetch.rot.available_rots = 0;
2900 // after preferred calc., if there were no early event, check available angle again
2901 if (!early_angle_change)
2902 early_angle_change = _rot_eval_fetch_available_send_angle_change(rot);
2906 rot->hint_fetch = 1;
2907 if (early_angle_change)
2909 EDBG(ec, "Send angle_change early for ec %x, Wait ack and next surface commit after ack", e_client_util_win_get(ec));
2911 else if ((ec->new_client) && (ec->e.state.rot.pending_show))
2913 ec->e.state.rot.pending_show = 0;
2914 evas_object_show(ec->frame);
2915 if (!ec->changes.rotation)
2916 e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
2918 else if ((evas_object_visible_get(ec->frame) && (ec->e.fetch.rot.need_rotation)))
2920 DBG("Rotation Zone Set: Fetch Hint");
2922 zone = e_comp_zone_find_by_ec(ec);
2923 if (zone) _e_client_rotation_zone_set(zone, NULL, NULL);
2926 if (ec->e.fetch.rot.need_rotation)
2927 ec->e.fetch.rot.need_rotation = EINA_FALSE;
2930 /* Occasionally, some client destroys only the xdg_surface and keeps the wl_surface.
2931 * In this case, E20 has the zombie ec for maintaining of this kind of client.
2932 * If the zombie ec is going to be alive again (it means that client tries to show window),
2933 * then the zombie ec has the unmap state on the E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER handler.
2934 * So fg_ec of rotation module can not be changed to activated ec even if it is shown on the screen.
2936 * Thus, we need to use a new hook for changing to right fg_ec of rotation module in this case.
2937 * E_POL_VIS_HOOK_TYPE_FG_SET is good point to be called after E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER
2938 * hook and given ec has always mapped state.
2941 _rot_fg_set(E_Client *ec, Eina_Bool check_obscured)
2943 Policy_Ext_Rotation *rot;
2946 rot = eina_hash_find(rot_hash, &ec);
2950 if (e_pixmap_type_get(ec->pixmap) == E_PIXMAP_TYPE_EXT_OBJECT)
2953 if (!rot->hint_fetch)
2955 /* need to fetch rotation hint. */
2956 ec->e.state.rot.pending_show = 1;
2961 if (ec->e.state.rot.pending_show)
2964 zone = e_comp_zone_find_by_ec(ec);
2965 EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
2967 if (e_policy_visibility_client_is_activity(ec))
2969 EDBG(ec, "Check ec %x to set fg_ec", e_client_util_win_get(ec));
2970 if (_no_active_lockscreen_check(ec))
2974 if (ec->visibility.obscured != E_VISIBILITY_FULLY_OBSCURED)
2976 EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
2982 /* don't need to check visibility of given foreground ec
2983 * it will have E_VISIBILITY_UNOBSCURED soon
2985 EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
2989 if (_camera_check(ec))
2990 _unlock_rot_for_fg_app(zone);
2992 _try_lock_rot_for_fg_app(zone);
2996 _e_client_rotation_zone_set(zone, ec, NULL);
2997 if (ec->changes.rotation)
2999 EDBG(ec, "Postpone show: ang %d", ec->e.state.rot.ang.next);
3000 e_pixmap_image_clear(ec->pixmap, 1);
3001 ec->e.state.rot.pending_show = 1;
3002 /* to be invoked 'eval_end' */
3011 _rot_hook_fg_set(void *d EINA_UNUSED, E_Client *ec)
3013 return _rot_fg_set(ec, EINA_FALSE);
3017 _rot_intercept_hook_show_helper(void *d EINA_UNUSED, E_Client *ec)
3019 return _rot_fg_set(ec, EINA_TRUE);
3023 _rot_intercept_hook_hide(void *d EINA_UNUSED, E_Client *ec)
3027 // TODO: Add VKBD Hide, VKBD Parent Hide routine.
3028 // clear pending_show, because this window is hidden now.
3029 ec->e.state.rot.pending_show = 0;
3031 zone = e_comp_zone_find_by_ec(ec);
3032 EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_TRUE);
3036 EDBG(ec, "Set the fg_ec to NULL");
3039 if (_camera_check(ec))
3040 _try_lock_rot_for_fg_app(zone);
3043 // for rotating ec in the force_update_list
3044 _e_client_rotation_zone_set(zone, fg_ec, ec);
3050 _rot_cb_idle_enterer(void *data EINA_UNUSED)
3056 if (rot.cancel.state)
3058 /* there is no border which supports window manager rotation */
3059 e_zone_rotation_update_cancel(rot.cancel.zone);
3060 rot.cancel.state = EINA_FALSE;
3061 rot.cancel.zone = NULL;
3066 n = eina_list_count(rot.list);
3070 ec = eina_list_data_get(rot.list);
3071 if (ec->e.state.rot.nopending_render == 0)
3073 if (!rot.screen_lock)
3075 ELOGF("ROTATION", "RENDERING pause", NULL);
3077 e_pixmap_image_clear(ec->pixmap, 1);
3078 e_comp_canvas_norender_push();
3079 rot.screen_lock = EINA_TRUE;
3084 if (rot.screen_lock)
3086 ELOGF("ROTATION", "RENDERING resume", NULL);
3087 e_comp_canvas_norender_pop();
3088 rot.screen_lock = EINA_FALSE;
3092 // if there is windows over 2 that has to be rotated or is existed window needs resizing,
3094 // but, DO NOT lock the screen when block state by E module
3097 Eina_Bool rot_block = EINA_FALSE;
3100 EINA_LIST_FOREACH(rot.list, l, ec)
3102 zone = e_comp_zone_find_by_ec(ec);
3103 if (!zone) continue;
3105 if (zone->rot.block.mod_count)
3107 rot_block = EINA_TRUE;
3110 if ((!rot.screen_lock) && (!rot_block))
3112 ELOGF("ROTATION", "RENDERING pause", NULL);
3114 EINA_LIST_FOREACH(rot.list, l, ec)
3115 e_pixmap_image_clear(ec->pixmap, 1);
3117 e_comp_canvas_norender_push();
3118 rot.screen_lock = EINA_TRUE;
3124 Eina_List *zlist = NULL;
3125 E_Zone *zone = NULL;
3129 EINA_LIST_FREE(rot.async_list, ec)
3131 zone = e_comp_zone_find_by_ec(ec);
3134 if (!eina_list_data_find(zlist, zone))
3135 zlist = eina_list_append(zlist, zone);
3136 _e_client_rotation_change_message_send(ec);
3140 EINA_LIST_FOREACH(zlist, l, zone)
3141 e_zone_rotation_update_cancel(zone);
3143 eina_list_free(zlist);
3147 rot.fetch = EINA_FALSE;
3150 return ECORE_CALLBACK_RENEW;
3154 _rot_hook_pixmap_unusable(void *data EINA_UNUSED, E_Pixmap *cp)
3156 E_Client *ec = (E_Client *)e_pixmap_client_get(cp);
3159 if (ec->e.state.rot.pending_show)
3161 ELOGF("ROTATION", "Unset Postpone show", ec);
3162 ec->e.state.rot.pending_show = 0;
3167 e_mod_rot_wl_init(void)
3169 EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, EINA_FALSE);
3170 EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->wl.disp, EINA_FALSE);
3172 rot_global = wl_global_create(e_comp_wl->wl.disp, &tizen_policy_ext_interface, 3,
3173 NULL, _e_tizen_policy_ext_bind_cb);
3176 ERR("Could not add tizen_policy_ext to wayland globals: %m");
3180 rot_hash = eina_hash_pointer_new(_policy_ext_rotation_free);
3182 E_LIST_HANDLER_APPEND(rot_cbs, E_EVENT_ZONE_ROTATION_CHANGE_BEGIN, _rot_cb_zone_rotation_change_begin, NULL);
3183 E_LIST_HANDLER_APPEND(rot_cbs, E_EVENT_CLIENT_BUFFER_CHANGE, _rot_cb_buffer_change, NULL);
3184 E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_NEW_CLIENT, _rot_hook_new_client, NULL);
3185 E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_DEL, _rot_hook_client_del, NULL);
3186 E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_EVAL_END, _rot_hook_eval_end, NULL);
3187 E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_EVAL_FETCH, _rot_hook_eval_fetch, NULL);
3188 E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(rot_obj_hooks, E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER, _rot_intercept_hook_show_helper, NULL);
3189 E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(rot_obj_hooks, E_COMP_OBJECT_INTERCEPT_HOOK_HIDE, _rot_intercept_hook_hide, NULL);
3190 E_COMP_WL_HOOK_APPEND(wl_hooks, E_COMP_WL_HOOK_BUFFER_CHANGE, _rot_cb_wl_buffer_change, NULL);
3191 E_PIXMAP_HOOK_APPEND(rot_pixmap_hooks, E_PIXMAP_HOOK_UNUSABLE, _rot_hook_pixmap_unusable, NULL);
3193 E_Pol_Vis_Hook *h = e_policy_visibility_hook_add(E_POL_VIS_HOOK_TYPE_FG_SET, _rot_hook_fg_set, NULL);
3194 pol_vis_hooks = eina_list_append(pol_vis_hooks, h);
3196 rot_idle_enterer = ecore_idle_enterer_add(_rot_cb_idle_enterer, NULL);
3202 e_mod_rot_wl_shutdown(void)
3204 E_FREE_FUNC(rot_hash, eina_hash_free);
3205 E_FREE_FUNC(rot.force_update_list, eina_list_free);
3207 E_FREE_LIST(pol_vis_hooks, e_policy_visibility_hook_del);
3208 E_FREE_LIST(wl_hooks, e_comp_wl_hook_del);
3209 E_FREE_LIST(rot_ec_hooks, e_client_hook_del);
3210 E_FREE_LIST(rot_cbs, ecore_event_handler_del);
3211 E_FREE_LIST(rot_obj_hooks, e_comp_object_intercept_hook_del);
3212 E_FREE_LIST(rot_pixmap_hooks, e_pixmap_hook_del);
3216 wl_global_destroy(rot_global);
3220 if (rot_idle_enterer)
3222 ecore_idle_enterer_del(rot_idle_enterer);
3223 rot_idle_enterer = NULL;
3228 e_mod_pol_rotation_force_update_add(E_Zone *zone EINA_UNUSED, E_Client *ec)
3230 rot.force_update_list = eina_list_append(rot.force_update_list, ec);
3234 e_mod_pol_rotation_force_update_del(E_Zone *zone EINA_UNUSED, E_Client *ec)
3236 rot.force_update_list = eina_list_remove(rot.force_update_list, ec);