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_wl.h"
22 #include "e_mod_rotation_private.h"
23 #include <wayland-server.h>
24 #include "tizen_policy_ext-server-protocol.h"
26 #ifdef HAVE_AUTO_ROTATION
27 #include "e_mod_sensord.h"
30 #define TIZEN_ROTATION_ANGLE_TO_INT(angle) ((angle == TIZEN_ROTATION_ANGLE_0) ? 0 : \
31 (angle == TIZEN_ROTATION_ANGLE_90) ? 90 : \
32 (angle == TIZEN_ROTATION_ANGLE_180) ? 180 : \
33 (angle == TIZEN_ROTATION_ANGLE_270) ? 270 : -1)
35 #define INT_TO_TIZEN_ROTATION_ANGLE(angle) ((angle == 0) ? TIZEN_ROTATION_ANGLE_0 : \
36 (angle == 90) ? TIZEN_ROTATION_ANGLE_90 : \
37 (angle == 180) ? TIZEN_ROTATION_ANGLE_180 : \
38 (angle == 270) ? TIZEN_ROTATION_ANGLE_270 : TIZEN_ROTATION_ANGLE_NONE)
40 typedef struct _Policy_Ext_Rotation Policy_Ext_Rotation;
41 typedef struct _E_Client_Rotation E_Client_Rotation;
43 struct _Policy_Ext_Rotation
46 E_Vis_Grab *show_grab;
47 uint32_t available_angles, preferred_angle;
48 enum tizen_rotation_angle cur_angle, prev_angle;
49 Eina_List *rotation_list;
50 Eina_Bool angle_change_done;
51 Eina_Bool wait_update;
55 /* WORKAROUND for the client used manual rotation */
61 } wait_update_pending;
64 struct _E_Client_Rotation
67 Eina_List *async_list;
68 Eina_List *force_update_list;
69 Ecore_Timer *done_timer;
70 Eina_Bool screen_lock;
80 /* local subsystem variables */
81 static E_Client_Rotation rot =
94 static Eina_Hash *rot_hash = NULL;
95 static Eina_List *rot_cbs = NULL;
96 static Eina_List *rot_ec_hooks = NULL;
97 static Eina_List *rot_obj_hooks = NULL;
98 static Eina_List *wl_hooks = NULL;
99 static Eina_List *pol_vis_hooks = NULL;
100 static Ecore_Idle_Enterer *rot_idle_enterer = NULL;
101 static E_Client *fg_ec = NULL;
103 /* local subsystem functions */
104 static Policy_Ext_Rotation* _policy_ext_rotation_get(E_Client *ec);
106 /* local subsystem wayland rotation protocol related functions */
107 static void _e_tizen_rotation_destroy_cb(struct wl_client *client, struct wl_resource *resource);
108 static void _e_tizen_rotation_set_available_angles_cb(struct wl_client *client, struct wl_resource *resource, uint32_t angles);
109 static void _e_tizen_rotation_set_preferred_angle_cb(struct wl_client *client, struct wl_resource *resource, uint32_t angle);
110 static void _e_tizen_rotation_ack_angle_change_cb(struct wl_client *client, struct wl_resource *resource, uint32_t serial);
111 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);
112 static void _e_tizen_rotation_destroy(struct wl_resource *resource);
113 static void _e_tizen_rotation_send_angle_change(E_Client *ec, int angle);
114 static void _e_tizen_policy_ext_get_rotation_cb(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface);
115 static void _e_tizen_policy_ext_active_angle_cb(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface);
116 static void _e_tizen_policy_ext_bind_cb(struct wl_client *client, void *data, uint32_t version, uint32_t id);
118 /* local subsystem wayland rotation protocol related variables */
119 static const struct tizen_rotation_interface _e_tizen_rotation_interface =
121 _e_tizen_rotation_destroy_cb,
122 _e_tizen_rotation_set_available_angles_cb,
123 _e_tizen_rotation_set_preferred_angle_cb,
124 _e_tizen_rotation_ack_angle_change_cb,
125 _e_tizen_rotation_set_geometry_hint_cb,
127 static const struct tizen_policy_ext_interface _e_tizen_policy_ext_interface =
129 _e_tizen_policy_ext_get_rotation_cb,
130 _e_tizen_policy_ext_active_angle_cb,
133 /* local subsystem e_client_rotation related functions */
134 static void _e_client_rotation_list_remove(E_Client *ec);
135 static Eina_Bool _e_client_rotation_zone_set(E_Zone *zone, E_Client *include_ec, E_Client *exclude_ec);
136 static void _e_client_rotation_change_done(void);
137 static Eina_Bool _e_client_rotation_change_done_timeout(void *data);
138 static void _e_client_rotation_change_message_send(E_Client *ec);
139 static int _e_client_rotation_curr_next_get(const E_Client *ec);
140 static void _e_client_event_client_rotation_change_begin_send(E_Client *ec);
141 static void _e_client_event_client_rotation_change_begin_free(void *data, void *ev);
142 static void _e_client_event_client_rotation_change_cancel_send(E_Client *ec);
143 static void _e_client_event_client_rotation_change_cancel_free(void *data, void *ev);
144 static void _e_client_event_client_rotation_change_end_free(void *data, void *ev);
145 static void _e_client_event_client_rotation_geometry_set_send(E_Client *ec, unsigned int angle, int x, int y, int w, int h);
146 static void _e_client_event_client_rotation_geometry_set_free(void *data, void *ev);
148 /* local subsystem e_zone_rotation related functions */
149 static void _e_zone_event_rotation_change_begin_free(void *data, void *ev);
150 static void _e_zone_event_rotation_change_end_free(void *data, void *ev);
151 static void _e_zone_event_rotation_change_cancel_free(void *data, void *ev);
153 /* e_client_roation functions */
154 static Eina_Bool e_client_rotation_is_progress(const E_Client *ec);
155 static int e_client_rotation_curr_angle_get(const E_Client *ec);
156 static int e_client_rotation_next_angle_get(const E_Client *ec);
157 static Eina_Bool e_client_rotation_is_available(const E_Client *ec, int ang);
158 static Eina_Bool e_client_rotation_set(E_Client *ec, int rotation);
159 static void e_client_rotation_change_request(E_Client *ec, int rotation);
161 /* e_zone_roation functions */
162 static void e_zone_rotation_update_done(E_Zone *zone);
163 static void e_zone_rotation_update_cancel(E_Zone *zone);
164 static void e_zone_rotation_sub_set(E_Zone *zone, int rotation) EINA_UNUSED;
166 /* e_client event, hook, intercept callbacks */
167 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);
168 static void _rot_hook_new_client(void *d EINA_UNUSED, E_Client *ec);
169 static void _rot_hook_client_del(void *d EINA_UNUSED, E_Client *ec);
170 static void _rot_hook_eval_end(void *d EINA_UNUSED, E_Client *ec);
171 static void _rot_hook_eval_fetch(void *d EINA_UNUSED, E_Client *ec);
172 static Eina_Bool _rot_intercept_hook_show_helper(void *d EINA_UNUSED, E_Client *ec);
173 static Eina_Bool _rot_intercept_hook_hide(void *d EINA_UNUSED, E_Client *ec);
174 static Eina_Bool _rot_cb_idle_enterer(void *data EINA_UNUSED);
177 _browser_check(E_Client *ec)
179 const char *name = e_client_util_name_get(ec);
180 if (!name) return EINA_FALSE;
181 if (!strncmp(name, "browser", 7)) return EINA_TRUE;
186 _camera_check(E_Client *ec)
188 const char *name = e_client_util_name_get(ec);
189 if (!name) return EINA_FALSE;
190 if (!strncmp(name, "camera-app", 10)) return EINA_TRUE;
191 if (!strncmp(name, "com.samsung.camera-app-lite", 27)) return EINA_TRUE;
196 _unlock_rot_for_fg_app(E_Zone *zone)
198 ELOGF("ROTATION", "UNLOCK for app-hint", NULL);
200 e_zone_rotation_unblock_type_set(zone,
201 E_ZONE_ROT_UNBLOCK_TYPE_APP_HINT,
205 e_zone_rotation_set(zone, e_mod_sensord_cur_angle_get());
209 _try_lock_rot_for_fg_app(E_Zone *zone)
211 ELOGF("ROTATION", "LOCK for app-hint", NULL);
213 if (zone->rot.block.sys_auto_rot)
214 e_zone_rotation_set(zone, 0);
216 e_zone_rotation_unblock_type_set(zone,
217 E_ZONE_ROT_UNBLOCK_TYPE_APP_HINT,
223 _no_active_lockscreen_check(E_Client *ec)
225 E_Client *ec2 = NULL;
228 if (!ec) return EINA_FALSE;
230 /* NB: to set fg_ec to lockscreen, return true if given ec is lockscreen itself. */
231 if (e_policy_client_is_lockscreen(ec)) return EINA_TRUE;
234 for (ec2 = ec; ec2; ec2 = e_client_above_get(ec2))
236 if (e_object_is_del(E_OBJECT(ec2))) continue;
237 if (e_policy_client_is_lockscreen(ec2))
239 e_client_geometry_get(ec2, &x, &y, &w, &h);
240 if (E_CONTAINS(ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h,
243 /* lockscreen is shown on top of given ec. */
250 /* there is no lockscreen on top of given ec. */
255 _rot_client_check_will_visible(E_Client *ec)
257 E_Client *above = NULL;
258 Eina_Bool will_visible = EINA_TRUE;
260 for (above = e_client_above_get(ec); above; above = e_client_above_get(above))
262 if (e_client_util_ignored_get(above)) continue;
263 if (!E_CONTAINS(above->x, above->y, above->w, above->h, ec->x, ec->y, ec->w, ec->h)) continue;
265 if (above->visibility.obscured == E_VISIBILITY_UNOBSCURED)
269 will_visible = EINA_FALSE;
274 if (above->visibility.opaque > 0)
276 will_visible = EINA_FALSE;
287 _rot_client_cb_vis_prepare_foreground(void *data, Evas_Object *obj, void *event_info)
289 Policy_Ext_Rotation *rot;
295 EDBG(ec, "Update Foreground Client '%s'(%p)", ec->icccm.name, ec);
296 if (e_policy_visibility_client_is_activity(ec))
298 EDBG(ec, "Check ec %x to set fg_ec", e_client_util_win_get(ec));
299 if (_no_active_lockscreen_check(ec))
301 if (ec->exp_iconify.not_raise)
303 if (_rot_client_check_will_visible(ec))
305 EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
311 EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
315 if (_camera_check(ec))
316 _unlock_rot_for_fg_app(ec->zone);
318 _try_lock_rot_for_fg_app(ec->zone);
322 _e_client_rotation_zone_set(ec->zone, ec, NULL);
323 if (ec->changes.rotation)
325 EDBG(ec, "Postpone foreground: ang %d", ec->e.state.rot.ang.next);
326 e_pixmap_image_clear(ec->pixmap, 1);
327 rot->show_grab = e_policy_visibility_client_grab_get(ec, __func__);
328 /* to be invoked 'eval_end' */
334 _policy_ext_rotation_free(void *data)
336 Policy_Ext_Rotation *rot;
344 evas_object_smart_callback_del(ec->frame,
345 "e,visibility,prepare,foreground",
346 _rot_client_cb_vis_prepare_foreground);
352 /* local subsystem functions */
353 static Policy_Ext_Rotation*
354 _policy_ext_rotation_get(E_Client *ec)
356 Policy_Ext_Rotation *rot;
358 EINA_SAFETY_ON_NULL_RETURN_VAL(rot_hash, NULL);
360 rot = eina_hash_find(rot_hash, &ec);
363 rot = E_NEW(Policy_Ext_Rotation, 1);
364 EINA_SAFETY_ON_NULL_RETURN_VAL(rot, NULL);
367 rot->angle_change_done = EINA_TRUE;
368 eina_hash_add(rot_hash, &ec, rot);
369 evas_object_smart_callback_add(ec->frame,
370 "e,visibility,prepare,foreground",
371 _rot_client_cb_vis_prepare_foreground,
379 _e_tizen_rotation_destroy_cb(struct wl_client *client EINA_UNUSED,
380 struct wl_resource *resource)
382 wl_resource_destroy(resource);
386 _e_tizen_rotation_set_available_angles_cb(struct wl_client *client,
387 struct wl_resource *resource,
391 Policy_Ext_Rotation *rot;
393 rot = wl_resource_get_user_data(resource);
394 EINA_SAFETY_ON_NULL_RETURN(rot);
400 rot->available_angles = angles;
402 ec->e.fetch.rot.available_rots = 1;
407 _e_tizen_rotation_set_preferred_angle_cb(struct wl_client *client,
408 struct wl_resource *resource,
411 Policy_Ext_Rotation *rot;
414 rot = wl_resource_get_user_data(resource);
415 EINA_SAFETY_ON_NULL_RETURN(rot);
421 ELOGF("ROTATION", "Request to set Preferred angle:%d", ec, TIZEN_ROTATION_ANGLE_TO_INT(angle));
422 if ((angle != TIZEN_ROTATION_ANGLE_NONE) &&
423 (!e_mod_pol_conf_rot_enable_get(TIZEN_ROTATION_ANGLE_TO_INT(angle))))
425 ELOGF("ROTATION", "Preferred angle(%d) is not allowed. CONF disabled",
426 ec, TIZEN_ROTATION_ANGLE_TO_INT(angle));
430 rot->preferred_angle = angle;
432 if (TIZEN_ROTATION_ANGLE_TO_INT(angle) == e_client_rotation_curr_angle_get(ec))
434 ec->e.state.rot.preferred_rot = TIZEN_ROTATION_ANGLE_TO_INT(angle);
435 EDBG(ec, "preferred angle is same as current angle (%d). don't need to fetch.", ec->e.state.rot.preferred_rot);
439 /* for clients supporting portrait mode in floating state*/
440 if ((rot->preferred_angle) &&
441 !(rot->preferred_angle & TIZEN_ROTATION_ANGLE_90) &&
442 !(rot->preferred_angle & TIZEN_ROTATION_ANGLE_270))
444 enum tizen_rotation_angle tz_angle = 0;
447 struct wl_resource *res;
449 if ((ec->floating) && (ec->comp_data) && ((ec->comp_data->shell.window.w != ec->w) || (ec->comp_data->shell.window.h != ec->h)))
451 if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_0)
452 tz_angle = TIZEN_ROTATION_ANGLE_0;
453 else if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_180)
454 tz_angle = TIZEN_ROTATION_ANGLE_180;
457 ERR("What's this impossible angle?? : %d", rot->preferred_angle);
463 serial = wl_display_next_serial(e_comp_wl->wl.disp);
465 rot->angle_change_done = EINA_FALSE;
466 rot->prev_angle = rot->cur_angle;
467 rot->cur_angle = tz_angle;
468 rot->serial = serial;
470 EINA_LIST_FOREACH(rot->rotation_list, l, res)
472 int ver = wl_resource_get_version(resource);
474 if ((ver >= 2) && ((tz_angle == TIZEN_ROTATION_ANGLE_0) || (tz_angle == TIZEN_ROTATION_ANGLE_180)))
476 int window_w, window_h;
477 if (!ec->comp_data) continue;
478 window_w = ec->comp_data->shell.window.w;
479 window_h = ec->comp_data->shell.window.h;
480 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",
481 tz_angle, ec->w, ec->h, window_w, window_h, window_w, window_h, window_h, window_w);
482 tizen_rotation_send_angle_change_with_resize(resource, tz_angle, serial, window_h, window_w);
484 ec->e.state.rot.preferred_rot = TIZEN_ROTATION_ANGLE_TO_INT(angle);
491 ec->e.fetch.rot.preferred_rot = 1;
496 _e_tizen_rotation_ack_angle_change_cb(struct wl_client *client,
497 struct wl_resource *resource,
501 Policy_Ext_Rotation *rot;
503 rot = wl_resource_get_user_data(resource);
504 EINA_SAFETY_ON_NULL_RETURN(rot);
509 EDBG(ec, "Rotation Done: prev %d cur %d serial %u",
510 ec->e.state.rot.ang.curr,
511 TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle),
514 if ((serial != 0) && (rot->serial == serial)) // rotation success
516 if (rot->angle_change_done)
518 WRN("Rotation Zone Set: Rotation Done(fail case): %s(%p) Already received change_done for this serial:%u",
519 ec->icccm.name ? ec->icccm.name : "", ec, serial);
523 ec->e.state.rot.ang.prev = ec->e.state.rot.ang.curr;
524 ec->e.state.rot.ang.curr = TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle);
526 if (TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle) == ec->e.state.rot.ang.next)
528 ec->e.state.rot.ang.next = -1;
530 if (ec->e.state.rot.ang.reserve != -1)
532 _e_client_rotation_list_remove(ec);
534 e_client_rotation_set(ec, ec->e.state.rot.ang.reserve);
535 ec->e.state.rot.ang.reserve = -1;
539 /* it means that we need the next buffer commit after rotation ack event.
540 * once we get next buffer commit, policy module attempts to remove
541 * this ec from rotation_list_remove. and then, rotation process is finished.
543 rot->wait_update = EINA_TRUE;
547 * Until now, we have assumed that the buffer commit event after the rotation
548 * ack event informs us of completion of rotation. However this assumption could
549 * be wrong because the rotation ack event is dispatched by main thread of client,
550 * whereas the buffer commit event could be dispatched by other thread.
552 * The ideal solution for resolving this issue is introduction of same protocol
553 * serial number between the rotation ack event and buffer commit event. But this
554 * approach needs much of changes for EFL, E20 and DDK. Thus I have added workaround
555 * code for quick resolving this.
557 * We have to extend EFL, E20 and DDK to support this later.
559 if (_browser_check(ec))
561 if (rot->wait_update_pending.timer)
562 ecore_timer_del(rot->wait_update_pending.timer);
564 rot->wait_update_pending.timer = NULL;
565 rot->wait_update_pending.use = EINA_TRUE;
566 rot->wait_update_pending.count = 2;
571 else // rotation fail
573 WRN("Rotation Zone Set: Rotation Done(fail case): %s(%p) Not matched serial %u != %u",
574 ec->icccm.name ? ec->icccm.name : "", ec, rot->serial, serial);
576 _e_client_rotation_zone_set(ec->zone, ec, NULL);
579 // check angle change serial
580 rot->angle_change_done = EINA_TRUE;
584 _e_tizen_rotation_set_geometry_hint_cb(struct wl_client *client,
585 struct wl_resource *resource,
587 uint32_t x, uint32_t y, uint32_t w, uint32_t h)
590 Policy_Ext_Rotation *rot;
594 rot = wl_resource_get_user_data(resource);
595 EINA_SAFETY_ON_NULL_RETURN(rot);
603 case TIZEN_ROTATION_ANGLE_0:
607 case TIZEN_ROTATION_ANGLE_90:
611 case TIZEN_ROTATION_ANGLE_180:
615 case TIZEN_ROTATION_ANGLE_270:
623 ec->e.state.rot.geom[i].x = x;
624 ec->e.state.rot.geom[i].y = y;
625 ec->e.state.rot.geom[i].w = w;
626 ec->e.state.rot.geom[i].h = h;
628 _e_client_event_client_rotation_geometry_set_send(ec, angle, x, y, w, h);
632 _e_tizen_rotation_destroy(struct wl_resource *resource)
634 Policy_Ext_Rotation *ext_rot;
636 ext_rot = wl_resource_get_user_data(resource);
637 EINA_SAFETY_ON_NULL_RETURN(ext_rot);
639 ext_rot->rotation_list = eina_list_remove(ext_rot->rotation_list, resource);
641 /* if there's no connected client of tizen_rotation */
642 if (!ext_rot->rotation_list)
644 _e_client_rotation_list_remove(ext_rot->ec);
645 if (rot.async_list) rot.async_list = eina_list_remove(rot.async_list, ext_rot->ec);
647 ext_rot->angle_change_done = EINA_TRUE;
652 _e_tizen_policy_ext_get_rotation_cb(struct wl_client *client,
653 struct wl_resource *resource,
655 struct wl_resource *surface)
657 int version = wl_resource_get_version(resource); // resource is tizen_policy_ext resource
658 struct wl_resource *res;
660 Policy_Ext_Rotation *rot;
662 ec = wl_resource_get_user_data(surface);
663 EINA_SAFETY_ON_NULL_RETURN(ec);
666 rot = _policy_ext_rotation_get(ec);
667 EINA_SAFETY_ON_NULL_RETURN(rot);
669 res = wl_resource_create(client, &tizen_rotation_interface, version, id);
672 wl_client_post_no_memory(client);
676 rot->rotation_list = eina_list_append(rot->rotation_list, res);
678 wl_resource_set_implementation(res, &_e_tizen_rotation_interface,
679 rot, _e_tizen_rotation_destroy);
681 ec->e.fetch.rot.support = 1;
686 _e_tizen_policy_ext_active_angle_cb(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface)
691 E_Client *focused_ec;
694 zone = e_zone_current_get();
697 ec = wl_resource_get_user_data(surface);
701 zone = e_zone_current_get();
708 focused_ec = e_client_focused_get();
710 angle = zone->rot.curr;
712 angle = focused_ec->e.state.rot.ang.curr;
715 tizen_policy_ext_send_active_angle(resource, angle);
719 _e_tizen_policy_ext_bind_cb(struct wl_client *client, void *data, uint32_t version, uint32_t id)
721 struct wl_resource *res;
723 if (!(res = wl_resource_create(client, &tizen_policy_ext_interface3, version, id)))
725 ERR("Could not create scaler resource: %m");
726 wl_client_post_no_memory(client);
730 wl_resource_set_implementation(res, &_e_tizen_policy_ext_interface, NULL, NULL);
734 _rot_eval_fetch_preferred_send_angle_change(Policy_Ext_Rotation *rot)
738 EINA_SAFETY_ON_NULL_RETURN_VAL(rot, EINA_FALSE);
744 if (!rot->preferred_angle)
747 /* for clients supporting landscape mode only */
748 if (!(rot->preferred_angle & TIZEN_ROTATION_ANGLE_0) &&
749 !(rot->preferred_angle & TIZEN_ROTATION_ANGLE_180))
751 enum tizen_rotation_angle tz_angle = 0;
754 struct wl_resource *res;
756 if (rot->available_angles & TIZEN_ROTATION_ANGLE_90)
757 tz_angle = TIZEN_ROTATION_ANGLE_90;
758 else if (rot->available_angles & TIZEN_ROTATION_ANGLE_270)
759 tz_angle = TIZEN_ROTATION_ANGLE_270;
762 ERR("What's this impossible angle?? : %d", rot->preferred_angle);
767 serial = wl_display_next_serial(e_comp_wl->wl.disp);
769 rot->angle_change_done = EINA_FALSE;
770 rot->prev_angle = rot->cur_angle;
771 rot->cur_angle = tz_angle;
772 rot->serial = serial;
774 EDBG(ec, "Send Change Rotation: angle %d for rendering preparation of landscape mode only app. mapped:%d serial:%u",
775 tz_angle, ec->first_mapped, serial);
777 ec->e.state.rot.ang.next = TIZEN_ROTATION_ANGLE_TO_INT(tz_angle);
779 EINA_LIST_FOREACH(rot->rotation_list, l, res)
781 tizen_rotation_send_angle_change(res, tz_angle, serial);
791 _rot_eval_fetch_available_send_angle_change(Policy_Ext_Rotation *rot)
793 enum tizen_rotation_angle cur_tz_angle;
796 EINA_SAFETY_ON_NULL_RETURN_VAL(rot, EINA_FALSE);
802 if (!rot->available_angles)
805 cur_tz_angle = INT_TO_TIZEN_ROTATION_ANGLE(ec->e.state.rot.ang.curr);
806 if (rot->available_angles & cur_tz_angle)
808 EDBG(ec, "Ignore it. current angle(%d) is one of available angles.", cur_tz_angle);
812 /* for clients supporting landscape mode only */
813 if (!(rot->available_angles & TIZEN_ROTATION_ANGLE_0) &&
814 !(rot->available_angles & TIZEN_ROTATION_ANGLE_180))
816 enum tizen_rotation_angle tz_angle = 0;
819 struct wl_resource *res;
821 if (rot->available_angles & TIZEN_ROTATION_ANGLE_90)
822 tz_angle = TIZEN_ROTATION_ANGLE_90;
823 else if (rot->available_angles & TIZEN_ROTATION_ANGLE_270)
824 tz_angle = TIZEN_ROTATION_ANGLE_270;
827 ERR("What's this impossible angle?? : %d", rot->available_angles);
832 /* if the client requests a window rotation with the same value as the current angle, just ignore it. */
833 if ((ec->first_mapped) &&
834 (ec->e.state.rot.ang.curr == TIZEN_ROTATION_ANGLE_TO_INT(tz_angle)))
836 EDBG(ec, "Ignore it. given angle %d is same as the current angle for landscape only app.",
841 serial = wl_display_next_serial(e_comp_wl->wl.disp);
843 rot->angle_change_done = EINA_FALSE;
844 rot->prev_angle = rot->cur_angle;
845 rot->cur_angle = tz_angle;
846 rot->serial = serial;
848 EDBG(ec, "Send Change Rotation: angle %d for redering preparation of landscape only app. mapped:%d serial:%u",
849 tz_angle, ec->first_mapped, serial);
851 ec->e.state.rot.ang.next = TIZEN_ROTATION_ANGLE_TO_INT(tz_angle);
853 EINA_LIST_FOREACH(rot->rotation_list, l, res)
855 tizen_rotation_send_angle_change(res, tz_angle, serial);
864 _e_tizen_rotation_send_angle_change(E_Client *ec, int angle)
867 Policy_Ext_Rotation *rot;
869 struct wl_resource *resource;
870 enum tizen_rotation_angle tz_angle = TIZEN_ROTATION_ANGLE_0;
874 EINA_SAFETY_ON_NULL_RETURN(ec);
875 EINA_SAFETY_ON_NULL_RETURN(rot_hash);
877 rot_diff = ec->e.state.rot.ang.curr - angle;
878 if (rot_diff < 0) rot_diff = -rot_diff;
880 rot = eina_hash_find(rot_hash, &ec);
886 tz_angle = TIZEN_ROTATION_ANGLE_0;
889 tz_angle = TIZEN_ROTATION_ANGLE_90;
892 tz_angle = TIZEN_ROTATION_ANGLE_180;
895 tz_angle = TIZEN_ROTATION_ANGLE_270;
901 serial = wl_display_next_serial(e_comp_wl->wl.disp);
903 rot->angle_change_done = EINA_FALSE;
904 rot->prev_angle = rot->cur_angle;
905 rot->cur_angle = tz_angle;
906 rot->serial = serial;
908 EINA_LIST_FOREACH(rot->rotation_list, l, resource)
910 ver = wl_resource_get_version(resource); // resource is type of tizen_rotation_interface
912 if ((ver >= 2) && (ec->floating))
916 EDBG(ec, "Send Change Rotation: angle %d mapped:%d serial:%u Resize:%dx%d",
917 tz_angle, ec->first_mapped, serial, ec->w, ec->h);
919 tizen_rotation_send_angle_change_with_resize(resource, tz_angle, serial, ec->w, ec->h);
923 EDBG(ec, "Send Change Rotation: angle %d mapped:%d serial:%u Resize:%dx%d -> %dx%d",
924 tz_angle, ec->first_mapped, serial, ec->w, ec->h, ec->h, ec->w);
926 tizen_rotation_send_angle_change_with_resize(resource, tz_angle, serial, ec->h, ec->w);
931 EDBG(ec, "Send Change Rotation: angle %d mapped:%d serial:%u",
932 tz_angle, ec->first_mapped, serial);
934 tizen_rotation_send_angle_change(resource, tz_angle, serial);
939 /* local subsystem e_client_rotation related functions */
941 _e_client_rotation_list_remove(E_Client *ec)
943 E_Event_Client_Rotation_Change_End *ev = NULL;
944 Eina_Bool found = EINA_FALSE;
946 if (eina_list_data_find(rot.list, ec) == ec)
949 rot.list = eina_list_remove(rot.list, ec);
952 if (ec->e.state.rot.wait_for_done)
954 ec->e.state.rot.wait_for_done = 0;
956 /* if we make the e_client event in the _e_client_free function,
957 * then we may meet a crash problem, only work this at least e_client_hide.
959 if (!e_object_is_del(E_OBJECT(ec)))
961 ev = E_NEW(E_Event_Client_Rotation_Change_End, 1);
965 e_object_ref(E_OBJECT(ec));
966 EDBG(ec, "Rotation Event: Client Rotation END");
967 ecore_event_add(E_EVENT_CLIENT_ROTATION_CHANGE_END,
969 _e_client_event_client_rotation_change_end_free,
975 (eina_list_count(rot.list) == 0))
977 _e_client_rotation_change_done();
979 /* handling pending zone rotation job */
980 else if ((eina_list_count(rot.list) == 0) &&
981 (ec->zone->rot.wait_for_done) &&
982 (ec->zone->rot.pending))
984 e_zone_rotation_update_done(ec->zone);
987 ec->e.state.rot.ang.next = -1;
988 ec->changes.rotation = 0;
992 _e_client_rotation_angle_is_allowed(E_Client *ec, int angle)
994 if ((!_camera_check(ec)) &&
995 (!e_mod_pol_conf_rot_enable_get(angle)))
997 EDBG(ec, "CHECK dependent '%s'(%p) ang:%d rot.type:%d dependent:%d",
998 ec->icccm.name, ec, angle,
999 ec->e.state.rot.type,
1000 E_CLIENT_ROTATION_TYPE_DEPENDENT);
1002 /* check whether the window is 32bit and has the dependent rotation type.
1003 * if true, then it can be rotated according to below normal window
1004 * even if current zone angle is not allowed by configuration value.
1006 if (!((ec->argb) && (e_client_rotation_is_available(ec, angle))))
1012 /* TODO need to optimize */
1014 _e_client_rotation_zone_set(E_Zone *zone, E_Client *include_ec, E_Client *exclude_ec)
1016 E_Client *ec, *bg_ec = NULL;
1017 Eina_List *target_list = NULL, *l, *ll;
1018 int angle, cur_angle, top_win_angle;
1019 Eina_Bool can_rotate = EINA_TRUE, ret = EINA_FALSE;
1021 TRACE_DS_BEGIN(CLIENT ROTATION ZONE SET);
1023 if (zone->rot.unknown_state)
1024 cur_angle = zone->rot.act;
1026 cur_angle = zone->rot.curr;
1030 DBG("<<< Try to set zone rotation | fg_ec '%s'(%p) cur_angle:%d zone(unknown_state:%d act:%d curr:%d)",
1031 fg_ec ? fg_ec->icccm.name : "",
1034 zone->rot.unknown_state,
1038 E_CLIENT_REVERSE_FOREACH(ec)
1040 if (ec->zone != zone) continue;
1041 if (ec == exclude_ec) continue;
1042 if ((ec != include_ec) && (!evas_object_visible_get(ec->frame))) continue;
1043 if (e_object_is_del(E_OBJECT(ec))) continue;
1044 if ((ec->comp_data) && (ec->comp_data->sub.data)) continue;
1045 if (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role))
1047 e_client_cursor_map_apply(ec, cur_angle, ec->x, ec->y);
1054 ((include_ec == ec) &&
1055 (evas_object_layer_get(ec->frame) >= evas_object_layer_get(bg_ec->frame))))
1057 if (_e_client_rotation_angle_is_allowed(ec, cur_angle))
1059 EDBG(ec, "Append to rotation target list");
1060 target_list = eina_list_append(target_list, ec);
1065 e_client_rotation_set(ec, cur_angle);
1069 if ((ec->x == zone->x) && (ec->y == zone->y) &&
1070 (ec->w == zone->w) && (ec->h == zone->h) &&
1071 (ec->e.state.rot.type == E_CLIENT_ROTATION_TYPE_NORMAL))
1075 EDBG(ec, "Found Topmost Fullscreen Window");
1080 if ((ec->visibility.opaque > 0) &&
1083 EDBG(ec, "Found Topmost Fullscreen Window");
1091 ELOGF("ROTATION", " fg_ec:%x, bg_ec:%p CHECK %s(%p) parent:%p vis:%d argb:%d opaque:%d",
1092 ec, e_client_util_win_get(fg_ec), bg_ec, ec->icccm.name, ec, ec->parent,
1093 ec->visibility.obscured, ec->argb, ec->visibility.opaque);
1094 /* if already found background client,
1095 * that means this client is placed under background client */
1098 /* if this client don't have parent, rotate */
1101 /* 1. rotate window only if auto-rotation is enabled.
1102 * it can show wrong rotated window if we don't check auto-rot value.
1104 * assuming that auto-rotation is disabled and window A is 0 degree.
1105 * in this case, when we attempt to run the camera-app which can be
1106 * always rotated, window A is changed to 270 degrees before showing
1107 * camera-app window. to prevent this we should check whether auto
1108 * rotation is enabled.
1110 * 2. also need to check this ec is visible before rotating it.
1112 * e.g. camera -> image-viewer launching case
1114 * image-viewer: bg_ec is set to image-viewer ec at the previous phase of this loop
1117 * if we decide to rotate camera ec which is obscured by image-viewer window,
1118 * then camera app will not send rotation done event. thus it occurrs rotation time
1119 * out error. to resolve this issue we should exclude obscured camera ec from
1122 if ((!zone->rot.block.sys_auto_rot) &&
1123 (e_mod_pol_conf_rot_enable_get(cur_angle)) &&
1124 (ec->visibility.obscured != E_VISIBILITY_FULLY_OBSCURED))
1126 ELOGF("ROTATION", "Do rotation of below ec under bg_ec %s(%p)",
1127 NULL, ec->icccm.name, ec);
1129 e_client_rotation_set(ec, cur_angle);
1135 * activity clients placed above background client should not be
1136 * rotated. that's because this is deactivated sometime later by
1137 * visibility's deiconify rendering logic.
1139 else if ((fg_ec != ec) &&
1140 (ec->x == zone->x) && (ec->y == zone->y) &&
1141 (ec->w == zone->w) && (ec->h == zone->h) &&
1142 (ec->e.state.rot.type == E_CLIENT_ROTATION_TYPE_NORMAL))
1148 if ((ec->visibility.opaque > 0) &&
1154 if (_e_client_rotation_angle_is_allowed(ec, cur_angle))
1156 EDBG(ec, "Append Rotation List '%s'(%p)", ec->icccm.name, ec);
1157 target_list = eina_list_append(target_list, ec);
1166 if (!target_list || (target_list && eina_list_count(target_list) == 0))
1168 DBG("Failed to set rotation with zone: target_list is empty. angle: %d", angle);
1170 angle = _e_client_rotation_curr_next_get(fg_ec);
1171 can_rotate = EINA_FALSE;
1174 EINA_LIST_FOREACH(target_list, l, ec)
1176 if (!e_client_rotation_is_available(ec, angle))
1178 EDBG(ec, "Failed to set rotation with zone: not able to rotate given angle %d", angle);
1179 angle = _e_client_rotation_curr_next_get(ec);
1180 can_rotate = EINA_FALSE;
1185 if (top_win_angle == -1)
1187 if (e_policy_client_is_keyboard(ec) ||
1188 e_policy_client_is_keyboard_sub(ec))
1191 EDBG(ec, "Set top_win_angle: %d", angle);
1192 top_win_angle = angle;
1199 can_rotate = EINA_TRUE;
1200 EINA_LIST_FOREACH(target_list, l, ec)
1202 if (!e_client_rotation_is_available(ec, angle))
1204 EDBG(ec, "Failed to set with exist client: not able to rotate given angle %d", angle);
1205 can_rotate = EINA_FALSE;
1210 if (top_win_angle == -1)
1212 if (e_policy_client_is_keyboard(ec) ||
1213 e_policy_client_is_keyboard_sub(ec))
1216 EDBG(ec, "Set top_win_angle: %d", angle);
1217 top_win_angle = angle;
1224 DBG("Set rotation of zone according to angle of zone: %d", angle);
1230 /* support more than one client with fixed angle value */
1231 if (eina_list_count(target_list) > 0)
1236 if (top_win_angle == -1)
1238 EINA_LIST_FOREACH_SAFE(target_list, l, ll, ec)
1240 DBG("Find top most window angle");
1241 // 1. check preferred
1242 if (ec->e.state.rot.preferred_rot != -1)
1244 EDBG(ec, "Set top_win_angle(preferred angle): %d", ec->e.state.rot.preferred_rot);
1245 top_win_angle = ec->e.state.rot.preferred_rot;
1249 // 2. check available angle
1250 for (i = 0; i < 4; i++)
1252 ang = (cur_angle + (i * 90)) % 360;
1253 if (e_client_rotation_is_available(ec, ang))
1255 EDBG(ec, "Set top_win_angle: %d", ang);
1256 top_win_angle = ang;
1261 if (top_win_angle == -1)
1263 // 3. couldn't find available angle
1264 EDBG(ec, "Cannot find any available angle. Set top_win_angle to 0");
1272 angle = top_win_angle;
1274 EINA_LIST_FOREACH_SAFE(target_list, l, ll, ec)
1276 EDBG(ec, "Attempt to rotate client with given angle %d", top_win_angle);
1277 if (e_client_rotation_is_available(ec, top_win_angle))
1279 res = e_client_rotation_set(ec, top_win_angle);
1280 if (!res) ret = EINA_FALSE;
1284 EDBG(ec, "Failed to set given angle %d, Keep current angle %d", top_win_angle, ec->e.state.rot.ang.curr);
1288 EINA_LIST_FOREACH(rot.force_update_list, l, ec)
1290 if (!eina_list_data_find(target_list, ec))
1292 EDBG(ec, "Rotate ec of force_update_list '%s'(%p)", ec->icccm.name, ec);
1293 res = e_client_rotation_set(ec, top_win_angle);
1294 if (!res) ret = EINA_FALSE;
1303 DBG("Set rotation of zone according to angle of exist clients: %d", angle);
1308 EINA_LIST_FOREACH(rot.force_update_list, l, ec)
1310 if (!eina_list_data_find(target_list, ec))
1312 EDBG(ec, "Append Rotation List from force_update_list '%s'(%p)", ec->icccm.name, ec);
1313 target_list = eina_list_append(target_list, ec);
1317 EINA_LIST_FOREACH(target_list, l, ec)
1318 ret = e_client_rotation_set(ec, angle);
1322 eina_list_free(target_list);
1324 zone->rot.act = angle;
1328 ELOGF("ROTATION", "zone active angle %d", NULL, zone->rot.act);
1329 DBG("End to set zone rotation: %s >>>", ret ? "Change" : "Stay");
1334 _e_client_rotation_change_done(void)
1336 Policy_Ext_Rotation *er;
1341 DBG("Remove rotation Timer by changing done");
1342 ecore_timer_del(rot.done_timer);
1344 rot.done_timer = NULL;
1346 EINA_LIST_FREE(rot.list, ec)
1348 if (ec->e.state.rot.pending_show)
1350 ec->e.state.rot.pending_show = 0;
1351 evas_object_show(ec->frame); // e_client_show(ec);
1352 e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
1354 er = eina_hash_find(rot_hash, &ec);
1355 if ((er) && (er->show_grab))
1356 E_FREE_FUNC(er->show_grab, e_policy_visibility_client_grab_release);
1357 ec->e.state.rot.ang.next = -1;
1358 ec->e.state.rot.wait_for_done = 0;
1361 EINA_LIST_FREE(rot.async_list, ec)
1363 _e_client_rotation_change_message_send(ec);
1367 rot.async_list = NULL;
1369 if (rot.screen_lock)
1371 // do call comp_wl's screen unlock
1372 ELOGF("ROTATION", "RENDERING resume", NULL);
1373 e_comp_canvas_norender_pop();
1374 rot.screen_lock = EINA_FALSE;
1376 e_zone_rotation_update_done(e_zone_current_get());
1380 _e_client_rotation_change_done_timeout(void *data)
1382 E_Client *ec = (E_Client *)data;
1384 if ((ec) && (!e_object_is_del(E_OBJECT(ec))))
1385 WRN("Timeout ROTATION_DONE %s(%p)",
1386 ec->icccm.name ? ec->icccm.name : "", ec);
1388 WRN("Timeout ROTATION_DONE (%p)", ec);
1390 _e_client_rotation_change_done();
1391 return ECORE_CALLBACK_CANCEL;
1395 _e_client_rotation_change_message_send(E_Client *ec)
1401 rotation = ec->e.state.rot.ang.next;
1402 if (rotation == -1) return;
1403 if (ec->e.state.rot.wait_for_done) return;
1405 e_client_rotation_change_request(ec, rotation);
1409 _e_client_rotation_curr_next_get(const E_Client *ec)
1413 return ((ec->e.state.rot.ang.next == -1) ?
1414 ec->e.state.rot.ang.curr : ec->e.state.rot.ang.next);
1418 _e_client_event_client_rotation_change_begin_send(E_Client *ec)
1420 E_Event_Client_Rotation_Change_Begin *ev = NULL;
1421 ev = E_NEW(E_Event_Client_Rotation_Change_Begin, 1);
1425 e_object_ref(E_OBJECT(ec));
1426 EDBG(ec, "Rotation Event: Client Rotation BEGIN");
1427 ecore_event_add(E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN,
1429 _e_client_event_client_rotation_change_begin_free,
1435 _e_client_event_client_rotation_change_cancel_send(E_Client *ec)
1437 E_Event_Client_Rotation_Change_Cancel *ev = NULL;
1438 ev = E_NEW(E_Event_Client_Rotation_Change_Cancel, 1);
1442 e_object_ref(E_OBJECT(ec));
1443 EDBG(ec, "Rotation Event: Client Rotation CANCEL");
1444 ecore_event_add(E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL,
1446 _e_client_event_client_rotation_change_cancel_free,
1452 _e_client_event_client_rotation_change_begin_free(void *data __UNUSED__,
1455 E_Event_Client_Rotation_Change_Begin *e;
1457 e_object_unref(E_OBJECT(e->ec));
1462 _e_client_event_client_rotation_change_cancel_free(void *data __UNUSED__,
1465 E_Event_Client_Rotation_Change_Cancel *e;
1467 e_object_unref(E_OBJECT(e->ec));
1472 _e_client_event_client_rotation_change_end_free(void *data __UNUSED__,
1475 E_Event_Client_Rotation_Change_End *e;
1477 e_object_unref(E_OBJECT(e->ec));
1482 _e_client_event_client_rotation_geometry_set_send(E_Client *ec, unsigned int angle, int x, int y, int w, int h)
1484 E_Event_Client_Rotation_Geometry_Set *ev = NULL;
1485 ev = E_NEW(E_Event_Client_Rotation_Geometry_Set, 1);
1494 e_object_ref(E_OBJECT(ec));
1495 ecore_event_add(E_EVENT_CLIENT_ROTATION_GEOMETRY_SET,
1497 _e_client_event_client_rotation_geometry_set_free,
1503 _e_client_event_client_rotation_geometry_set_free(void *data __UNUSED__,
1506 E_Event_Client_Rotation_Geometry_Set *e;
1508 e_object_unref(E_OBJECT(e->ec));
1513 _e_zone_event_rotation_change_begin_free(void *data __UNUSED__,
1516 E_Event_Zone_Rotation_Change_Begin *e = ev;
1517 e_object_unref(E_OBJECT(e->zone));
1522 _e_zone_event_rotation_change_end_free(void *data __UNUSED__,
1525 E_Event_Zone_Rotation_Change_End *e = ev;
1526 e_object_unref(E_OBJECT(e->zone));
1531 _e_zone_event_rotation_change_cancel_free(void *data __UNUSED__,
1534 E_Event_Zone_Rotation_Change_Cancel *e = ev;
1535 e_object_unref(E_OBJECT(e->zone));
1539 /* e_client_roation functions */
1542 * Get current rotoation state.
1543 * @param ec e_client
1544 * @return EINA_FALSE the state that does not rotating.
1545 * EINA_TRUE the state that rotating.
1548 e_client_rotation_is_progress(const E_Client *ec)
1550 if (!ec) return EINA_FALSE;
1552 if (ec->e.state.rot.ang.next == -1)
1560 * Get current rotation angle.
1561 * @param ec e_client
1562 * @return int current angle
1565 e_client_rotation_curr_angle_get(const E_Client *ec)
1567 E_OBJECT_CHECK_RETURN(ec, -1);
1568 E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, -1);
1570 return ec->e.state.rot.ang.curr;
1575 * Get being replaced rotation angle.
1576 * @param ec e_client
1577 * @return int be replaced angle.
1580 e_client_rotation_next_angle_get(const E_Client *ec)
1582 E_OBJECT_CHECK_RETURN(ec, -1);
1583 E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, -1);
1585 return ec->e.state.rot.ang.next;
1589 e_client_rotation_find_below(const E_Client *ec)
1595 E_OBJECT_CHECK_RETURN(ec, NULL);
1596 E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
1598 EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
1599 if (EINA_INLIST_GET(ec)->prev) //check current layer
1601 for (l = EINA_INLIST_GET(ec)->prev; l; l = l->prev)
1603 ec2 = EINA_INLIST_CONTAINER_GET(l, E_Client);
1605 if ((ec2->comp_data && ec2->comp_data->mapped) &&
1606 (!e_object_is_del(E_OBJECT(ec2))) &&
1607 (!e_client_util_ignored_get(ec2)) &&
1608 (!ec2->exp_iconify.by_client))
1613 /* go down the layers until we find one */
1614 if (e_comp_canvas_layer_map(ec->layer) > e_comp_canvas_layer_map(E_LAYER_MAX)) return NULL;
1615 x = e_comp_canvas_layer_map(ec->layer);
1618 for (; x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
1620 if (e_comp->layers[x].clients)
1622 EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2)
1624 if (ec2 == ec) continue;
1625 if ((ec2->comp_data && ec2->comp_data->mapped) &&
1626 (!e_object_is_del(E_OBJECT(ec2))) &&
1627 (!e_client_util_ignored_get(ec2)) &&
1628 (!ec2->exp_iconify.by_client))
1641 * Check if this e_client is rotatable to given angle.
1642 * @param ec e_client
1643 * @param ang test angle.
1644 * @return EINA_FALSE can't be rotated.
1645 * EINA_TRUE can be rotated.
1648 e_client_rotation_is_available(const E_Client *ec, int ang)
1650 Eina_Bool ret = EINA_FALSE;
1652 E_Client *below = NULL;
1653 Eina_Bool below_rot = EINA_TRUE;
1655 if (ang < 0) return EINA_FALSE;
1656 if (!ec->e.state.rot.support)
1659 if (ec->e.state.rot.type == E_CLIENT_ROTATION_TYPE_DEPENDENT)
1661 // check below fullsize window's angle
1662 if ((ec->x == ec->zone->x) && (ec->y == ec->zone->y) &&
1663 (ec->w == ec->zone->w) && (ec->h == ec->zone->h))
1665 below = e_client_rotation_find_below(ec);
1668 below_rot = e_client_rotation_is_available(below, ang);
1671 EDBG(ec, "ec's below(ec:%p, win:%x) can not rotate to angle [%d]", below, e_client_util_win_get(below), ang);
1678 if (ec->e.state.rot.preferred_rot == -1)
1680 if (ec->e.state.rot.available_rots &&
1681 ec->e.state.rot.count)
1683 for (i = 0; i < ec->e.state.rot.count; i++)
1685 if (ec->e.state.rot.available_rots[i] == ang)
1695 else if (ec->e.state.rot.preferred_rot == ang)
1705 * Set the rotation of the e_client given angle.
1706 * @param ec e_client
1707 * *param rotation angle
1708 * @return EINA_TRUE rotation starts or is already in progress.
1712 e_client_rotation_set(E_Client *ec, int rotation)
1714 Eina_List *list, *l;
1717 Policy_Ext_Rotation *ext_rot;
1719 if (!ec) return EINA_FALSE;
1721 if (rotation < 0) return EINA_FALSE;
1722 if (!e_client_rotation_is_available(ec, rotation)) return EINA_FALSE;
1724 TRACE_DS_BEGIN(CLIENT ROTATION SET);
1725 TRACE_DS_BEGIN(CLINET CURRENT ANGLE SET);
1727 // in case same with current angle.
1728 curr_rot = e_client_rotation_curr_angle_get(ec);
1729 EDBG(ec, "Client Rotation name:%s, curr_rot:%d, rotation:%d", ec->icccm.name?:"NULL", curr_rot, rotation);
1730 if (curr_rot == rotation)
1732 if (e_client_rotation_is_progress(ec))
1734 // cancel the changes in case only doesn't send request.
1735 if ((!ec->e.state.rot.pending_change_request) &&
1736 (!ec->e.state.rot.wait_for_done))
1738 EDBG(ec, "Client Rotation Canceled (curr_rot == rot %d)", rotation);
1739 _e_client_rotation_list_remove(ec);
1740 if (ec->e.state.rot.pending_show)
1742 ec->e.state.rot.pending_show = 0;
1743 if (!e_object_is_del(E_OBJECT(ec)))
1745 evas_object_show(ec->frame); // e_client_show(ec);
1746 e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
1750 _e_client_event_client_rotation_change_cancel_send(ec);
1766 ext_rot = eina_hash_find(rot_hash, &ec);
1769 if (ext_rot->wait_update_pending.timer)
1770 ecore_timer_del(ext_rot->wait_update_pending.timer);
1771 ext_rot->wait_update_pending.timer = NULL;
1774 // in case same with next angle.
1775 curr_rot = e_client_rotation_next_angle_get(ec);
1776 if (curr_rot == rotation)
1778 // if there is reserve angle, remove it.
1779 if (ec->e.state.rot.ang.reserve != -1)
1781 ec->e.state.rot.ang.reserve = -1;
1786 /* if this e_client is rotating now,
1787 * it will be rotated to this angle after rotation done.
1789 if ((ec->e.state.rot.pending_change_request) ||
1790 (ec->e.state.rot.wait_for_done))
1792 ec->e.state.rot.ang.reserve = rotation;
1796 /* search rotatable window in this window's child */
1797 list = eina_list_clone(ec->transients);
1798 EINA_LIST_FOREACH(list, l, child)
1800 // the window which type is "E_WINDOW_TYPE_NORMAL" will be rotated itself.
1801 // it shouldn't be rotated by rotation state of parent window.
1802 if (child->netwm.type == E_WINDOW_TYPE_NORMAL) continue;
1803 if (child->comp_data && !child->comp_data->mapped) continue;
1805 ELOGF("ROTATION", "Do rotation of child win %s(%p)",
1806 NULL, child->icccm.name, child);
1808 e_client_rotation_set(child, rotation);
1810 eina_list_free(list);
1812 if (!e_client_rotation_is_progress(ec))
1814 _e_client_event_client_rotation_change_begin_send(ec);
1817 ec->e.state.rot.pending_change_request = 0;
1818 ec->e.state.rot.ang.next = rotation;
1819 ec->changes.rotation = 1;
1823 /* Now the WM has a rotatable window thus we unset variables about zone rotation cancel */
1824 if (rot.cancel.state)
1826 rot.cancel.state = EINA_FALSE;
1827 rot.cancel.zone = NULL;
1835 e_client_rotation_change_request(E_Client *ec, int rotation)
1838 if (rotation < 0) return;
1840 // if this window is in withdrawn state, change the state to NORMAL.
1841 // that's because the window in withdrawn state can't render its canvas.
1842 // eventually, this window will not send the message of rotation done,
1843 // even if e request to rotation this window.
1845 //TODO: e_hint set is really neeed?.
1846 e_hints_window_visible_set(ec);
1848 _e_tizen_rotation_send_angle_change(ec, rotation);
1850 ec->e.state.rot.wait_for_done = 1;
1852 if ((!rot.async_list) ||
1853 (!eina_list_data_find(rot.async_list, ec)))
1856 ecore_timer_del(rot.done_timer);
1857 rot.done_timer = ecore_timer_add(4.0f,
1858 _e_client_rotation_change_done_timeout,
1863 /* e_zone_roation functions */
1865 _e_zone_rotation_set_internal(E_Zone *zone, int rot)
1867 E_Event_Zone_Rotation_Change_Begin *ev;
1869 E_OBJECT_CHECK(zone);
1870 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1872 if (zone->rot.wait_for_done)
1874 INF("Pending Zone Rotation: wait_for_done %d block_count %d",
1875 zone->rot.wait_for_done, zone->rot.block.mod_count);
1876 zone->rot.next = rot;
1877 zone->rot.pending = EINA_TRUE;
1881 if (!e_config->wm_win_rotation) return;
1883 ELOGF("ROTATION", "ZONE_ROT |zone:%d|rot curr:%d, active:%d, rot:%d",
1884 NULL, zone->num, zone->rot.curr, zone->rot.act, rot);
1886 if ((zone->rot.curr == rot) &&
1887 (zone->rot.act == rot))
1890 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->1",
1891 NULL, zone->rot.wait_for_done);
1893 zone->rot.prev = zone->rot.act;
1894 zone->rot.curr = rot;
1895 zone->rot.wait_for_done = EINA_TRUE;
1897 ev = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
1901 e_object_ref(E_OBJECT(ev->zone));
1902 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
1903 ev, _e_zone_event_rotation_change_begin_free, NULL);
1908 e_zone_rotation_set(E_Zone *zone, int rotation)
1910 E_OBJECT_CHECK(zone);
1911 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1913 TRACE_DS_BEGIN(ZONE ROTATION SET);
1915 zone->rot.unknown_state = EINA_TRUE;
1919 ELOGF("ROTATION", "ZONE_ROT |UNKNOWN SET|zone:%d|rot curr:%d, rot:%d",
1920 NULL, zone->num, zone->rot.curr, rotation);
1924 if (e_zone_rotation_block_get(zone, rotation))
1926 if ((zone->rot.wait_for_done) ||
1927 (zone->rot.block.mod_count > 0))
1929 if ((!zone->rot.unblock.app_hint) &&
1930 (!e_mod_pol_conf_rot_enable_get(rotation)))
1932 ELOGF("ROTATION", "ZONE_ROT |SKIP|zone:%d curr:%d rotation:%d config is not allowed",
1933 NULL, zone->num, zone->rot.curr, rotation);
1934 zone->rot.unknown_state = EINA_FALSE;
1938 INF("Pending Zone Rotation: wait_for_done %d block_count %d",
1939 zone->rot.wait_for_done, zone->rot.block.mod_count);
1940 zone->rot.next = rotation;
1941 zone->rot.pending = EINA_TRUE;
1945 if (zone->rot.block.sys_auto_rot)
1947 ELOGF("ROTATION", "ZONE_ROT |SKIP|zone:%d curr:%d rotation:%d. auto rotation is locked",
1948 NULL, zone->num, zone->rot.curr, rotation);
1949 zone->rot.unknown_state = EINA_FALSE;
1953 ELOGF("ROTATION", "ZONE_ROT |UNKNOWN SET|zone:%d|rot curr:%d, rot:%d",
1954 NULL, zone->num, zone->rot.curr, rotation);
1958 zone->rot.unknown_state = EINA_FALSE;
1960 _e_zone_rotation_set_internal(zone, rotation);
1965 e_zone_rotation_sub_set(E_Zone *zone, int rotation)
1967 E_OBJECT_CHECK(zone);
1968 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1970 ELOGF("ROTATION", "SUB_SET |zone:%d|rot curr:%d, rot:%d",
1971 NULL, zone->num, zone->rot.curr, rotation);
1973 zone->rot.sub = rotation;
1975 if ((zone->rot.unknown_state) &&
1976 (zone->rot.curr != rotation))
1977 _e_zone_rotation_set_internal(zone, rotation);
1980 /* This function has the policy of window rotation LOCK which is
1981 * determined according to the UX or the system order of priority.
1984 e_zone_rotation_block_get(E_Zone *zone, int rot)
1986 /* 1. specific app which set special hint such as camera */
1987 if (zone->rot.unblock.app_hint)
1989 ELOGF("ROTATION", "BLOCK Get. unblocked by app_hint", NULL);
1993 /* 2. not supported angle in wm-policy configuration */
1994 if (!e_mod_pol_conf_rot_enable_get(rot))
1996 ELOGF("ROTATION", "BLOCK Get. CONF disabled", NULL);
2000 /* 3. auto-rotation through vconf */
2001 if (zone->rot.block.sys_auto_rot)
2003 ELOGF("ROTATION", "BLOCK Get. AUTO_ROT disabled", NULL);
2007 /* 4. temporary block count for the E sub-modules */
2008 if (zone->rot.block.mod_count > 0)
2010 ELOGF("ROTATION", "BLOCK Get. E internal block. %d", NULL,
2011 zone->rot.block.mod_count);
2019 e_zone_rotation_block_type_set(E_Zone *zone, E_Zone_Rot_Block_Type type, const char *name_hint, Eina_Bool block)
2021 E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
2022 E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
2026 case E_ZONE_ROT_BLOCK_TYPE_SYSTEM_AUTO_ROTATION:
2027 zone->rot.block.sys_auto_rot = block;
2028 ELOGF("ROTATION", "BLOCK_SET. sys_auto_rot:%s", NULL,
2029 block ? "true" : "false");
2031 case E_ZONE_ROT_BLOCK_TYPE_E_MODULE:
2032 if (block) zone->rot.block.mod_count++;
2033 else zone->rot.block.mod_count--;
2034 if (zone->rot.block.mod_count <= 0) zone->rot.block.mod_count = 0;
2035 ELOGF("ROTATION", "BLOCK_SET. e modules:%s count:%d", NULL,
2036 block ? "true" : "false", zone->rot.block.mod_count);
2046 e_zone_rotation_unblock_type_set(E_Zone *zone, E_Zone_Rot_Unblock_Type type, const char *name_hint, Eina_Bool unblock)
2048 E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
2049 E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
2053 case E_ZONE_ROT_UNBLOCK_TYPE_APP_HINT:
2054 zone->rot.unblock.app_hint = unblock;
2055 ELOGF("ROTATION", "UnBLOCK_SET app hint:%s", NULL,
2056 unblock ? "true" : "false");
2066 e_zone_rotation_block_set(E_Zone *zone, const char *name_hint, Eina_Bool block)
2068 E_Event_Zone_Rotation_Change_Begin *ev;
2070 E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
2071 E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
2073 e_zone_rotation_block_type_set(zone,
2074 E_ZONE_ROT_BLOCK_TYPE_E_MODULE,
2077 if (block) return EINA_TRUE;
2079 ELOGF("ROTATION", "ROT_BLOCK|RESUME|zone:%d|count:%d|from:%s|rot.pending:%d|next:%d",
2082 zone->rot.block.mod_count,
2087 if (zone->rot.pending)
2089 zone->rot.pending = EINA_FALSE;
2090 if (zone->rot.curr != zone->rot.next)
2092 if (e_zone_rotation_block_get(zone, zone->rot.next))
2094 zone->rot.pending = EINA_TRUE;
2095 ELOGF("ROTATION", "ROT_BLOCK|PAUSE|zone:%d|count:%d|from:%s", NULL,
2096 zone->num, zone->rot.block.mod_count, name_hint);
2100 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->1",
2101 NULL, zone->rot.wait_for_done);
2103 zone->rot.prev = zone->rot.curr;
2104 zone->rot.curr = zone->rot.next;
2105 zone->rot.wait_for_done = EINA_TRUE;
2106 zone->rot.pending = EINA_FALSE;
2108 ev = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
2112 e_object_ref(E_OBJECT(ev->zone));
2113 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
2114 ev, _e_zone_event_rotation_change_begin_free, NULL);
2116 ELOGF("ROTATION", "ROT_SET(P|zone:%d|rot:%d",
2117 NULL, zone->num, zone->rot.curr);
2126 e_zone_rotation_update_done(E_Zone *zone)
2128 E_Event_Zone_Rotation_Change_End *ev;
2130 E_OBJECT_CHECK(zone);
2131 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
2133 ELOGF("ROTATION", "ROT_DONE |zone:%d|rot:%d",
2134 NULL, zone->num, zone->rot.curr);
2136 ev = E_NEW(E_Event_Zone_Rotation_Change_End, 1);
2140 e_object_ref(E_OBJECT(ev->zone));
2141 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_END,
2142 ev, _e_zone_event_rotation_change_end_free, NULL);
2145 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->0",
2146 NULL, zone->rot.wait_for_done);
2148 zone->rot.wait_for_done = EINA_FALSE;
2149 if ((zone->rot.block.mod_count == 0) && (zone->rot.pending))
2151 zone->rot.pending = EINA_FALSE;
2152 if (zone->rot.curr != zone->rot.next)
2154 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->1",
2155 NULL, zone->rot.wait_for_done);
2157 zone->rot.prev = zone->rot.curr;
2158 zone->rot.curr = zone->rot.next;
2159 zone->rot.wait_for_done = EINA_TRUE;
2160 zone->rot.pending = EINA_FALSE;
2162 E_Event_Zone_Rotation_Change_Begin *ev2;
2163 ev2 = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
2167 e_object_ref(E_OBJECT(ev2->zone));
2168 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
2169 ev2, _e_zone_event_rotation_change_begin_free, NULL);
2171 ELOGF("ROTATION", "ROT_SET(P|zone:%d|rot:%d",
2172 NULL, zone->num, zone->rot.curr);
2180 e_zone_rotation_update_cancel(E_Zone *zone)
2182 E_Event_Zone_Rotation_Change_Cancel *ev;
2184 E_OBJECT_CHECK(zone);
2185 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
2187 ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->0",
2188 NULL, zone->rot.wait_for_done);
2190 zone->rot.wait_for_done = EINA_FALSE;
2191 if (zone->rot.pending)
2193 zone->rot.prev = zone->rot.curr;
2194 zone->rot.curr = zone->rot.next;
2195 zone->rot.pending = EINA_FALSE;
2198 ev = E_NEW(E_Event_Zone_Rotation_Change_Cancel, 1);
2202 e_object_ref(E_OBJECT(ev->zone));
2203 ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_CANCEL,
2204 ev, _e_zone_event_rotation_change_cancel_free, NULL);
2209 _rot_cb_zone_rotation_change_begin(void *data EINA_UNUSED, int ev_type EINA_UNUSED, E_Event_Zone_Rotation_Change_Begin *ev)
2211 if ((!ev) || (!ev->zone)) return ECORE_CALLBACK_PASS_ON;
2213 DBG("Rotation Zone Set: Rotation Change Begin");
2214 if (!_e_client_rotation_zone_set(ev->zone, NULL, NULL))
2216 /* The WM will decide to cancel zone rotation at idle time.
2217 * Because, the policy module can make list of rotation windows
2219 rot.cancel.state = EINA_TRUE;
2220 rot.cancel.zone = ev->zone;
2223 return ECORE_CALLBACK_RENEW;
2227 _e_client_rotation_wait_update_clear(E_Client *ec)
2229 Policy_Ext_Rotation *rot;
2231 rot = eina_hash_find(rot_hash, &ec);
2234 rot->wait_update_pending.timer = NULL;
2236 _e_client_rotation_list_remove(ec);
2237 if (ec->e.state.rot.pending_show)
2239 ec->e.state.rot.pending_show = 0;
2240 evas_object_show(ec->frame);
2241 e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
2245 E_FREE_FUNC(rot->show_grab, e_policy_visibility_client_grab_release);
2247 rot->wait_update = EINA_FALSE;
2251 _e_client_rotation_wait_update_pending_timeout(void *data)
2253 E_Client *ec = (E_Client *)data;
2255 if ((ec) && (!e_object_is_del(E_OBJECT(ec))))
2256 WRN("Timeout Wait Update Pending %s(%p)",
2257 ec->icccm.name ? ec->icccm.name : "", ec);
2259 WRN("Timeout Wait Update Pending (%p)", ec);
2262 _e_client_rotation_wait_update_clear(ec);
2264 return ECORE_CALLBACK_CANCEL;
2268 _rot_cb_wl_buffer_change(void *d EINA_UNUSED, E_Client *ec)
2270 Policy_Ext_Rotation *rot;
2272 rot = eina_hash_find(rot_hash, &ec);
2274 if (ec->e.state.rot.nopending_render) return;
2276 if (!rot->angle_change_done)
2278 DBG("Update Buffer in progress of rotation ec '%s'(%p) HOOK",
2279 ec->icccm.name ? ec->icccm.name : "", ec);
2281 e_pixmap_image_clear(ec->pixmap, EINA_TRUE);
2282 e_pixmap_resource_set(ec->pixmap, NULL);
2287 _rot_cb_buffer_change(void *data EINA_UNUSED, int ev_type EINA_UNUSED, E_Event_Client *ev)
2289 Policy_Ext_Rotation *rot;
2291 if (EINA_UNLIKELY(!ev))
2294 if (EINA_UNLIKELY(!ev->ec))
2297 rot = eina_hash_find(rot_hash, &ev->ec);
2302 * wl_buffer can be destroyed after attach/damage/frame/commit to wl_surface.
2303 * we have to handle this case.
2305 if ((!rot->angle_change_done) || (!e_pixmap_resource_get(ev->ec->pixmap)))
2307 DBG("Update Buffer in progress of rotation ec '%s'(%p) EVENT nopending_render:%d",
2308 ev->ec->icccm.name ? ev->ec->icccm.name : "", ev->ec,
2309 ev->ec->e.state.rot.nopending_render);
2311 if (!ev->ec->e.state.rot.nopending_render)
2313 e_pixmap_image_clear(ev->ec->pixmap, EINA_TRUE);
2314 e_pixmap_resource_set(ev->ec->pixmap, NULL);
2317 else if (rot->wait_update)
2319 DBG("Update Buffer After Rotation Done ec '%s'(%p) b %p pending:%d count:%d",
2320 ev->ec->icccm.name ? ev->ec->icccm.name : "",
2322 e_pixmap_resource_get(ev->ec->pixmap),
2323 rot->wait_update_pending.use,
2324 rot->wait_update_pending.count);
2326 if (rot->wait_update_pending.use)
2328 if (rot->wait_update_pending.count > 0)
2330 if (rot->wait_update_pending.count == 2)
2332 if (rot->wait_update_pending.timer)
2333 ecore_timer_del(rot->wait_update_pending.timer);
2335 rot->wait_update_pending.timer = ecore_timer_add(0.1f,
2336 _e_client_rotation_wait_update_pending_timeout,
2340 rot->wait_update_pending.count--;
2341 return ECORE_CALLBACK_RENEW;
2345 if (rot->wait_update_pending.timer)
2346 ecore_timer_del(rot->wait_update_pending.timer);
2347 rot->wait_update_pending.timer = NULL;
2351 _e_client_rotation_wait_update_clear(ev->ec);
2354 if (ev->ec->e.state.rot.pending_show)
2356 DBG("Buffer Changed: force add update list to send frame until pending show");
2357 /* consider e_pixmap_image_clear() instead of update_add() */
2358 e_pixmap_image_clear(ev->ec->pixmap, EINA_TRUE);
2362 return ECORE_CALLBACK_RENEW;
2366 _rot_hook_new_client(void *d EINA_UNUSED, E_Client *ec)
2368 Policy_Ext_Rotation *rot;
2370 ec->e.state.rot.preferred_rot = -1;
2371 ec->e.state.rot.type = E_CLIENT_ROTATION_TYPE_NORMAL;
2372 ec->e.state.rot.ang.next = -1;
2373 ec->e.state.rot.ang.reserve = -1;
2374 ec->e.state.rot.pending_show = 0;
2375 ec->e.state.rot.ang.curr = 0;
2376 ec->e.state.rot.ang.prev = 0;
2378 EINA_SAFETY_ON_NULL_RETURN(rot_hash);
2380 rot = eina_hash_find(rot_hash, &ec);
2383 if (rot->preferred_angle)
2384 ec->e.fetch.rot.preferred_rot = 1;
2386 if (rot->available_angles)
2387 ec->e.fetch.rot.available_rots = 1;
2391 _rot_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
2393 Policy_Ext_Rotation *ext_rot;
2394 struct wl_resource *res;
2396 _e_client_rotation_list_remove(ec);
2397 if (rot.async_list) rot.async_list = eina_list_remove(rot.async_list, ec);
2399 ec->e.state.rot.preferred_rot = -1;
2401 if (ec->e.state.rot.available_rots)
2402 E_FREE(ec->e.state.rot.available_rots);
2404 ext_rot = eina_hash_find(rot_hash, &ec);
2407 if (ext_rot->wait_update_pending.timer)
2408 ecore_timer_del(ext_rot->wait_update_pending.timer);
2409 ext_rot->wait_update_pending.timer = NULL;
2411 EINA_LIST_FREE(ext_rot->rotation_list, res)
2412 wl_resource_set_user_data(res, NULL);
2414 eina_hash_del_by_key(rot_hash, &ec);
2419 EDBG(ec, "Set the fg_ec to NULL");
2422 if (_camera_check(ec))
2423 _try_lock_rot_for_fg_app(ec->zone);
2428 _rot_hook_eval_end(void *d EINA_UNUSED, E_Client *ec)
2430 if (ec->changes.rotation)
2432 E_Zone *zone = ec->zone;
2434 if (ec->moving) e_client_act_move_end(ec, NULL);
2436 if ((!zone->rot.block.mod_count) &&
2437 ((!evas_object_visible_get(ec->frame)) ||
2438 (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zone->x, zone->y, zone->w, zone->h))))
2441 rot.async_list = eina_list_append(rot.async_list, ec);
2446 rot.list = eina_list_append(rot.list, ec);
2447 _e_client_rotation_change_message_send(ec);
2449 rot.fetch = EINA_TRUE;
2450 ec->changes.rotation = 0;
2455 _rot_hook_eval_fetch(void *d EINA_UNUSED, E_Client *ec)
2457 Policy_Ext_Rotation *rot;
2459 Eina_Bool early_angle_change = EINA_FALSE;
2463 rot = eina_hash_find(rot_hash, &ec);
2466 if(ec->e.fetch.rot.support)
2468 ec->e.state.rot.support = 1;
2470 ec->e.fetch.rot.need_rotation = EINA_TRUE;
2471 ec->e.fetch.rot.support = 0;
2473 if (ec->e.fetch.rot.preferred_rot)
2475 int _prev_preferred_rot;
2476 _prev_preferred_rot = ec->e.state.rot.preferred_rot;
2477 ec->e.state.rot.preferred_rot = -1;
2479 switch (rot->preferred_angle)
2481 case TIZEN_ROTATION_ANGLE_0:
2482 ec->e.state.rot.preferred_rot = 0;
2484 case TIZEN_ROTATION_ANGLE_90:
2485 ec->e.state.rot.preferred_rot = 90;
2487 case TIZEN_ROTATION_ANGLE_180:
2488 ec->e.state.rot.preferred_rot = 180;
2490 case TIZEN_ROTATION_ANGLE_270:
2491 ec->e.state.rot.preferred_rot = 270;
2497 if (_prev_preferred_rot != ec->e.state.rot.preferred_rot)
2498 ec->e.fetch.rot.need_rotation = EINA_TRUE;
2500 EDBG(ec, "Fetch Preferred: preferred (prev %d cur %d)",
2501 _prev_preferred_rot, ec->e.state.rot.preferred_rot);
2503 early_angle_change = _rot_eval_fetch_preferred_send_angle_change(rot);
2505 ec->e.fetch.rot.preferred_rot = 0;
2507 if (ec->e.fetch.rot.available_rots)
2509 Eina_Bool diff = EINA_FALSE;
2511 unsigned int _prev_count = 0, count = 0, i = 0;
2512 int _prev_rots[4] = { -1, };
2513 uint32_t available_angles = 0;
2515 if (ec->e.state.rot.available_rots)
2518 ec->e.state.rot.available_rots,
2519 (sizeof(int) * ec->e.state.rot.count));
2522 _prev_count = ec->e.state.rot.count;
2523 ec->e.state.rot.count = 0;
2525 /* check avilable_angles */
2526 if (rot->available_angles & TIZEN_ROTATION_ANGLE_0) count++;
2527 if (rot->available_angles & TIZEN_ROTATION_ANGLE_90) count++;
2528 if (rot->available_angles & TIZEN_ROTATION_ANGLE_180) count++;
2529 if (rot->available_angles & TIZEN_ROTATION_ANGLE_270) count++;
2532 rots = (int*)E_NEW(int, count);
2536 if (ec->e.state.rot.available_rots)
2538 /* restore previous rotation hints */
2539 memcpy(ec->e.state.rot.available_rots, _prev_rots, (sizeof(int) * _prev_count));
2544 if (ec->e.state.rot.available_rots)
2545 E_FREE(ec->e.state.rot.available_rots);
2547 available_angles = rot->available_angles;
2549 if ((count > 0) && (rots))
2551 for (i = 0; i < count; i++)
2553 if (available_angles & TIZEN_ROTATION_ANGLE_0)
2556 available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_0;
2558 else if (available_angles & TIZEN_ROTATION_ANGLE_90)
2561 available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_90;
2563 else if (available_angles & TIZEN_ROTATION_ANGLE_180)
2566 available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_180;
2568 else if (available_angles & TIZEN_ROTATION_ANGLE_270)
2571 available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_270;
2575 ec->e.state.rot.available_rots = rots;
2576 ec->e.state.rot.count = count;
2578 if (_prev_count != count) diff = EINA_TRUE;
2580 for (i = 0; i < count; i++)
2582 if ((!diff) && (_prev_rots[i] != rots[i]))
2589 /* check avilable_angles end*/
2591 /* Print fetch information */
2593 Eina_Strbuf *b = eina_strbuf_new();
2595 EINF(ec, "Fetch Available");
2596 if (_prev_count > 0)
2598 for (i = 0; i < _prev_count; i++)
2599 eina_strbuf_append_printf(b, "%d ", _prev_rots[i]);
2600 INF("\tprev %s", eina_strbuf_string_get(b));
2601 eina_strbuf_reset(b);
2604 for (i = 0; i < count; i++)
2605 eina_strbuf_append_printf(b, "%d ", rots[i]);
2606 INF("\tcur %s", eina_strbuf_string_get(b));
2608 eina_strbuf_free(b);
2611 if (diff) ec->e.fetch.rot.need_rotation = EINA_TRUE;
2612 ec->e.fetch.rot.available_rots = 0;
2614 // after preferred calc., if there were no early event, check available angle again
2615 if (!early_angle_change)
2616 early_angle_change = _rot_eval_fetch_available_send_angle_change(rot);
2620 rot->hint_fetch = 1;
2621 if (early_angle_change)
2623 EDBG(ec, "Send angle_change early for ec %x, Wait ack and next surface commit after ack", e_client_util_win_get(ec));
2625 else if ((ec->new_client) && (ec->e.state.rot.pending_show))
2627 ec->e.state.rot.pending_show = 0;
2628 evas_object_show(ec->frame);
2629 if (!ec->changes.rotation)
2630 e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
2632 else if ((evas_object_visible_get(ec->frame) && (ec->e.fetch.rot.need_rotation)))
2634 DBG("Rotation Zone Set: Fetch Hint");
2635 _e_client_rotation_zone_set(ec->zone, NULL, NULL);
2638 if (ec->e.fetch.rot.need_rotation)
2639 ec->e.fetch.rot.need_rotation = EINA_FALSE;
2642 /* Occasionally, some client destroys only the xdg_surface and keeps the wl_surface.
2643 * In this case, E20 has the zombie ec for maintaining of this kind of client.
2644 * If the zombie ec is going to be alive again (it means that client tries to show window),
2645 * then the zombie ec has the unmap state on the E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER handler.
2646 * So fg_ec of rotation module can not be changed to activated ec even if it is shown on the screen.
2648 * Thus, we need to use a new hook for changing to right fg_ec of rotation module in this case.
2649 * E_POL_VIS_HOOK_TYPE_FG_SET is good point to be called after E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER
2650 * hook and given ec has always mapped state.
2653 _rot_hook_fg_set(void *d EINA_UNUSED, E_Client *ec)
2655 Policy_Ext_Rotation *rot;
2657 rot = eina_hash_find(rot_hash, &ec);
2661 if (e_pixmap_type_get(ec->pixmap) == E_PIXMAP_TYPE_EXT_OBJECT)
2664 if (!rot->hint_fetch)
2666 /* need to fetch rotation hint. */
2667 ec->e.state.rot.pending_show = 1;
2672 if (ec->e.state.rot.pending_show)
2675 if (e_policy_visibility_client_is_activity(ec))
2677 EDBG(ec, "Check ec %x to set fg_ec", e_client_util_win_get(ec));
2678 if (_no_active_lockscreen_check(ec))
2680 /* don't need to check visibility of given foreground ec
2681 * it will have E_VISIBILITY_UNOBSCURED soon
2683 EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
2686 if (_camera_check(ec))
2687 _unlock_rot_for_fg_app(ec->zone);
2689 _try_lock_rot_for_fg_app(ec->zone);
2693 _e_client_rotation_zone_set(ec->zone, ec, NULL);
2694 if (ec->changes.rotation)
2696 EDBG(ec, "Postpone show: ang %d", ec->e.state.rot.ang.next);
2697 e_pixmap_image_clear(ec->pixmap, 1);
2698 ec->e.state.rot.pending_show = 1;
2699 /* to be invoked 'eval_end' */
2708 _rot_intercept_hook_show_helper(void *d EINA_UNUSED, E_Client *ec)
2710 Policy_Ext_Rotation *rot;
2712 rot = eina_hash_find(rot_hash, &ec);
2716 if (e_pixmap_type_get(ec->pixmap) == E_PIXMAP_TYPE_EXT_OBJECT)
2719 if (!rot->hint_fetch)
2721 /* need to fetch rotation hint. */
2722 ec->e.state.rot.pending_show = 1;
2727 if (ec->e.state.rot.pending_show)
2730 if (e_policy_visibility_client_is_activity(ec))
2732 EDBG(ec, "Check ec %x to set fg_ec", e_client_util_win_get(ec));
2733 if (_no_active_lockscreen_check(ec))
2735 if (ec->visibility.obscured != E_VISIBILITY_FULLY_OBSCURED)
2737 EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
2741 if (_camera_check(ec))
2742 _unlock_rot_for_fg_app(ec->zone);
2744 _try_lock_rot_for_fg_app(ec->zone);
2748 _e_client_rotation_zone_set(ec->zone, ec, NULL);
2749 if (ec->changes.rotation)
2751 EDBG(ec, "Postpone show: ang %d", ec->e.state.rot.ang.next);
2752 e_pixmap_image_clear(ec->pixmap, 1);
2753 ec->e.state.rot.pending_show = 1;
2754 /* to be invoked 'eval_end' */
2763 _rot_intercept_hook_hide(void *d EINA_UNUSED, E_Client *ec)
2765 // TODO: Add VKBD Hide, VKBD Parent Hide routine.
2766 // clear pending_show, because this window is hidden now.
2767 ec->e.state.rot.pending_show = 0;
2771 EDBG(ec, "Set the fg_ec to NULL");
2774 if (_camera_check(ec))
2775 _try_lock_rot_for_fg_app(ec->zone);
2778 // for rotating ec in the force_update_list
2779 _e_client_rotation_zone_set(ec->zone, fg_ec, ec);
2785 _rot_cb_idle_enterer(void *data EINA_UNUSED)
2791 if (rot.cancel.state)
2793 /* there is no border which supports window manager rotation */
2794 e_zone_rotation_update_cancel(rot.cancel.zone);
2795 rot.cancel.state = EINA_FALSE;
2796 rot.cancel.zone = NULL;
2801 n = eina_list_count(rot.list);
2805 ec = eina_list_data_get(rot.list);
2806 if (ec->e.state.rot.nopending_render == 0)
2808 if (!rot.screen_lock)
2810 ELOGF("ROTATION", "RENDERING pause", NULL);
2812 e_pixmap_image_clear(ec->pixmap, 1);
2813 e_comp_canvas_norender_push();
2814 rot.screen_lock = EINA_TRUE;
2819 if (rot.screen_lock)
2821 ELOGF("ROTATION", "RENDERING resume", NULL);
2822 e_comp_canvas_norender_pop();
2823 rot.screen_lock = EINA_FALSE;
2827 // if there is windows over 2 that has to be rotated or is existed window needs resizing,
2829 // but, DO NOT lock the screen when block state by E module
2832 Eina_Bool rot_block = EINA_FALSE;
2834 EINA_LIST_FOREACH(rot.list, l, ec)
2836 if (!ec->zone) continue;
2837 if (ec->zone->rot.block.mod_count)
2839 rot_block = EINA_TRUE;
2842 if ((!rot.screen_lock) && (!rot_block))
2844 ELOGF("ROTATION", "RENDERING pause", NULL);
2846 EINA_LIST_FOREACH(rot.list, l, ec)
2847 e_pixmap_image_clear(ec->pixmap, 1);
2849 e_comp_canvas_norender_push();
2850 rot.screen_lock = EINA_TRUE;
2856 Eina_List *zlist = NULL;
2857 E_Zone *zone = NULL;
2861 EINA_LIST_FREE(rot.async_list, ec)
2863 if (!eina_list_data_find(zlist, ec->zone))
2864 zlist = eina_list_append(zlist, ec->zone);
2865 _e_client_rotation_change_message_send(ec);
2868 EINA_LIST_FOREACH(zlist, l, zone)
2869 e_zone_rotation_update_cancel(zone);
2871 eina_list_free(zlist);
2875 rot.fetch = EINA_FALSE;
2878 return ECORE_CALLBACK_RENEW;
2882 e_mod_rot_wl_init(void)
2884 EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, EINA_FALSE);
2885 EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->wl.disp, EINA_FALSE);
2887 if (!wl_global_create(e_comp_wl->wl.disp, &tizen_policy_ext_interface3, 3,
2888 NULL, _e_tizen_policy_ext_bind_cb))
2890 ERR("Could not add tizen_policy_ext to wayland globals: %m");
2894 rot_hash = eina_hash_pointer_new(_policy_ext_rotation_free);
2896 E_LIST_HANDLER_APPEND(rot_cbs, E_EVENT_ZONE_ROTATION_CHANGE_BEGIN, _rot_cb_zone_rotation_change_begin, NULL);
2897 E_LIST_HANDLER_APPEND(rot_cbs, E_EVENT_CLIENT_BUFFER_CHANGE, _rot_cb_buffer_change, NULL);
2898 E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_NEW_CLIENT, _rot_hook_new_client, NULL);
2899 E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_DEL, _rot_hook_client_del, NULL);
2900 E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_EVAL_END, _rot_hook_eval_end, NULL);
2901 E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_EVAL_FETCH, _rot_hook_eval_fetch, NULL);
2902 E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(rot_obj_hooks, E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER, _rot_intercept_hook_show_helper, NULL);
2903 E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(rot_obj_hooks, E_COMP_OBJECT_INTERCEPT_HOOK_HIDE, _rot_intercept_hook_hide, NULL);
2904 E_COMP_WL_HOOK_APPEND(wl_hooks, E_COMP_WL_HOOK_BUFFER_CHANGE, _rot_cb_wl_buffer_change, NULL);
2906 E_Pol_Vis_Hook *h = e_policy_visibility_hook_add(E_POL_VIS_HOOK_TYPE_FG_SET, _rot_hook_fg_set, NULL);
2907 pol_vis_hooks = eina_list_append(pol_vis_hooks, h);
2909 rot_idle_enterer = ecore_idle_enterer_add(_rot_cb_idle_enterer, NULL);
2915 e_mod_rot_wl_shutdown(void)
2917 E_FREE_FUNC(rot_hash, eina_hash_free);
2918 E_FREE_FUNC(rot.force_update_list, eina_list_free);
2920 E_FREE_LIST(pol_vis_hooks, e_policy_visibility_hook_del);
2921 E_FREE_LIST(wl_hooks, e_comp_wl_hook_del);
2922 E_FREE_LIST(rot_ec_hooks, e_client_hook_del);
2923 E_FREE_LIST(rot_cbs, ecore_event_handler_del);
2924 E_FREE_LIST(rot_obj_hooks, e_comp_object_intercept_hook_del);
2926 if (rot_idle_enterer)
2928 ecore_idle_enterer_del(rot_idle_enterer);
2929 rot_idle_enterer = NULL;
2934 e_mod_pol_rotation_force_update_add(E_Zone *zone EINA_UNUSED, E_Client *ec)
2936 rot.force_update_list = eina_list_append(rot.force_update_list, ec);
2940 e_mod_pol_rotation_force_update_del(E_Zone *zone EINA_UNUSED, E_Client *ec)
2942 rot.force_update_list = eina_list_remove(rot.force_update_list, ec);