c1855f5745a07521999911215c978cda8957c9a3
[platform/core/uifw/e-mod-tizen-wm-policy.git] / src / rotation / e_mod_rotation_wl.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
3  *
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
8  *
9  *     http://floralicense.org/license/
10  *
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.
16  *
17  * Please, see the COPYING file for the original copyright owner and
18  * license.
19  */
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"
25
26 #ifdef HAVE_AUTO_ROTATION
27 #include "e_mod_sensord.h"
28 #endif
29
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)
34
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)
39
40 typedef struct _Policy_Ext_Rotation Policy_Ext_Rotation;
41 typedef struct _E_Client_Rotation E_Client_Rotation;
42
43 struct _Policy_Ext_Rotation
44 {
45    E_Client *ec;
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;
52    Eina_Bool hint_fetch;
53    uint32_t serial;
54
55    /* WORKAROUND for the client used manual rotation */
56    struct
57    {
58       Eina_Bool    use;
59       int          count;
60       Ecore_Timer *timer;
61    } wait_update_pending;
62 };
63
64 struct _E_Client_Rotation
65 {
66    Eina_List     *list;
67    Eina_List     *async_list;
68    Eina_List     *force_update_list;
69    Ecore_Timer   *done_timer;
70    Eina_Bool      screen_lock;
71    Eina_Bool      fetch;
72
73    struct
74    {
75       Eina_Bool    state;
76       E_Zone      *zone;
77    } cancel;
78 };
79
80 /* local subsystem variables */
81 static E_Client_Rotation rot =
82 {
83    NULL,
84    NULL,
85    NULL,
86    NULL,
87    EINA_FALSE,
88    EINA_FALSE,
89    {
90       EINA_FALSE,
91       NULL,
92    }
93 };
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;
102
103 /* local subsystem functions */
104 static Policy_Ext_Rotation* _policy_ext_rotation_get(E_Client *ec);
105
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);
117
118 /* local subsystem wayland rotation protocol related variables */
119 static const struct tizen_rotation_interface _e_tizen_rotation_interface =
120 {
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,
126 };
127 static const struct tizen_policy_ext_interface _e_tizen_policy_ext_interface =
128 {
129    _e_tizen_policy_ext_get_rotation_cb,
130    _e_tizen_policy_ext_active_angle_cb,
131 };
132
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);
147
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);
152
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);
160
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;
165
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);
175
176 static Eina_Bool
177 _browser_check(E_Client *ec)
178 {
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;
182    return EINA_FALSE;
183 }
184
185 static Eina_Bool
186 _camera_check(E_Client *ec)
187 {
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;
192    return EINA_FALSE;
193 }
194
195 static void
196 _unlock_rot_for_fg_app(E_Zone *zone)
197 {
198    ELOGF("ROTATION", "UNLOCK for app-hint", NULL);
199
200    e_zone_rotation_unblock_type_set(zone,
201                                     E_ZONE_ROT_UNBLOCK_TYPE_APP_HINT,
202                                     "camera",
203                                     EINA_TRUE);
204
205    e_zone_rotation_set(zone, e_mod_sensord_cur_angle_get());
206 }
207
208 static void
209 _try_lock_rot_for_fg_app(E_Zone *zone)
210 {
211    ELOGF("ROTATION", "LOCK for app-hint", NULL);
212
213    if (zone->rot.block.sys_auto_rot)
214      e_zone_rotation_set(zone, 0);
215
216    e_zone_rotation_unblock_type_set(zone,
217                                     E_ZONE_ROT_UNBLOCK_TYPE_APP_HINT,
218                                     "camera",
219                                     EINA_FALSE);
220 }
221
222 static Eina_Bool
223 _no_active_lockscreen_check(E_Client *ec)
224 {
225    E_Client *ec2 = NULL;
226    int x, y, w, h;
227
228    if (!ec) return EINA_FALSE;
229
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;
232
233    /* bottom to top */
234    for (ec2 = ec; ec2; ec2 = e_client_above_get(ec2))
235      {
236         if (e_object_is_del(E_OBJECT(ec2))) continue;
237         if (e_policy_client_is_lockscreen(ec2))
238           {
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,
241                             x, y, w, h))
242                {
243                   /* lockscreen is shown on top of given ec. */
244                   return EINA_FALSE;
245                }
246              break;
247           }
248      }
249
250    /* there is no lockscreen on top of given ec. */
251    return EINA_TRUE;
252 }
253
254 static Eina_Bool
255 _rot_client_check_will_visible(E_Client *ec)
256 {
257    E_Client *above = NULL;
258    Eina_Bool will_visible = EINA_TRUE;
259
260    for (above = e_client_above_get(ec); above; above = e_client_above_get(above))
261      {
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;
264
265         if (above->visibility.obscured == E_VISIBILITY_UNOBSCURED)
266           {
267              if (!above->argb)
268                {
269                   will_visible = EINA_FALSE;
270                   break;
271                }
272              else
273                {
274                   if (above->visibility.opaque > 0)
275                     {
276                        will_visible = EINA_FALSE;
277                        break;
278                     }
279                }
280           }
281      }
282
283    return will_visible;
284 }
285
286 static void
287 _rot_client_cb_vis_prepare_foreground(void *data, Evas_Object *obj, void *event_info)
288 {
289    Policy_Ext_Rotation *rot;
290    E_Client *ec;
291
292    rot = data;
293    ec = rot->ec;
294
295    EDBG(ec, "Update Foreground Client '%s'(%p)", ec->icccm.name, ec);
296    if (e_policy_visibility_client_is_activity(ec))
297      {
298         EDBG(ec, "Check ec %x to set fg_ec", e_client_util_win_get(ec));
299         if (_no_active_lockscreen_check(ec))
300           {
301              if (ec->exp_iconify.not_raise)
302                {
303                   if (_rot_client_check_will_visible(ec))
304                     {
305                        EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
306                        fg_ec = ec;
307                     }
308                }
309              else
310                {
311                   EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
312                   fg_ec = ec;
313                }
314
315              if (_camera_check(ec))
316                _unlock_rot_for_fg_app(ec->zone);
317              else
318                _try_lock_rot_for_fg_app(ec->zone);
319           }
320      }
321
322    _e_client_rotation_zone_set(ec->zone, ec, NULL);
323    if (ec->changes.rotation)
324      {
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' */
329         EC_CHANGED(ec);
330      }
331 }
332
333 static void
334 _policy_ext_rotation_free(void *data)
335 {
336    Policy_Ext_Rotation *rot;
337    E_Client *ec;
338
339    rot = data;
340    ec = rot->ec;
341
342    if (ec->frame)
343      {
344         evas_object_smart_callback_del(ec->frame,
345                                        "e,visibility,prepare,foreground",
346                                        _rot_client_cb_vis_prepare_foreground);
347      }
348
349    free(rot);
350 }
351
352 /* local subsystem functions */
353 static Policy_Ext_Rotation*
354 _policy_ext_rotation_get(E_Client *ec)
355 {
356    Policy_Ext_Rotation *rot;
357
358    EINA_SAFETY_ON_NULL_RETURN_VAL(rot_hash, NULL);
359
360    rot = eina_hash_find(rot_hash, &ec);
361    if (!rot)
362      {
363         rot = E_NEW(Policy_Ext_Rotation, 1);
364         EINA_SAFETY_ON_NULL_RETURN_VAL(rot, NULL);
365
366         rot->ec = ec;
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,
372                                        rot);
373      }
374
375    return rot;
376 }
377
378 static void
379 _e_tizen_rotation_destroy_cb(struct wl_client *client EINA_UNUSED,
380                              struct wl_resource *resource)
381 {
382    wl_resource_destroy(resource);
383 }
384
385 static void
386 _e_tizen_rotation_set_available_angles_cb(struct wl_client *client,
387                                           struct wl_resource *resource,
388                                           uint32_t angles)
389 {
390    E_Client *ec;
391    Policy_Ext_Rotation *rot;
392    enum tizen_rotation_angle cur_tz_angle;
393
394    rot = wl_resource_get_user_data(resource);
395    EINA_SAFETY_ON_NULL_RETURN(rot);
396
397    ec = rot->ec;
398    if (!ec)
399      return;
400
401    rot->available_angles = angles;
402
403    ec->e.fetch.rot.available_rots = 1;
404    EC_CHANGED(ec);
405
406    cur_tz_angle = INT_TO_TIZEN_ROTATION_ANGLE(ec->e.state.rot.ang.curr);
407    if (rot->available_angles & cur_tz_angle)
408      {
409         EDBG(ec, "Ignore it. current angle(%d) is one of available angles.", cur_tz_angle);
410         return;
411      }
412
413    /* for clients supporting landscape mode only */
414    if ((rot->available_angles) &&
415        !(rot->available_angles & TIZEN_ROTATION_ANGLE_0) &&
416        !(rot->available_angles & TIZEN_ROTATION_ANGLE_180))
417      {
418         enum tizen_rotation_angle tz_angle = 0;
419         uint32_t serial;
420         Eina_List *l;
421         struct wl_resource *res;
422
423         if (rot->available_angles & TIZEN_ROTATION_ANGLE_90)
424           tz_angle = TIZEN_ROTATION_ANGLE_90;
425         else if (rot->available_angles & TIZEN_ROTATION_ANGLE_270)
426           tz_angle = TIZEN_ROTATION_ANGLE_270;
427         else
428           {
429              ERR("What's this impossible angle?? : %d", rot->available_angles);
430           }
431
432         if (tz_angle)
433           {
434              /* if the client requests a window rotation with the same value as the current angle, just ignore it. */
435              if ((ec->first_mapped) &&
436                  (ec->e.state.rot.ang.curr == TIZEN_ROTATION_ANGLE_TO_INT(tz_angle)))
437                {
438                   EDBG(ec, "Ignore it. given angle %d is same as the current angle for landscape only app.",
439                        tz_angle);
440                   return;
441                }
442
443              serial = wl_display_next_serial(e_comp_wl->wl.disp);
444
445              EDBG(ec, "Send Change Rotation: angle %d for redering preparation of landscape only app. mapped:%d serial:%u",
446                   tz_angle, ec->first_mapped, serial);
447
448              rot->angle_change_done = EINA_FALSE;
449              rot->prev_angle = rot->cur_angle;
450              rot->cur_angle = tz_angle;
451              rot->serial = serial;
452
453              EINA_LIST_FOREACH(rot->rotation_list, l, res)
454                {
455                   tizen_rotation_send_angle_change(res, tz_angle, serial);
456                }
457           }
458      }
459 }
460
461 static void
462 _e_tizen_rotation_set_preferred_angle_cb(struct wl_client *client,
463                                          struct wl_resource *resource,
464                                          uint32_t angle)
465 {
466    Policy_Ext_Rotation *rot;
467    E_Client *ec;
468
469    rot = wl_resource_get_user_data(resource);
470    EINA_SAFETY_ON_NULL_RETURN(rot);
471
472    ec = rot->ec;
473    if (!ec)
474      return;
475
476    ELOGF("ROTATION", "Request to set Preferred angle:%d", ec, TIZEN_ROTATION_ANGLE_TO_INT(angle));
477    if ((angle != TIZEN_ROTATION_ANGLE_NONE) &&
478        (!e_mod_pol_conf_rot_enable_get(TIZEN_ROTATION_ANGLE_TO_INT(angle))))
479      {
480         ELOGF("ROTATION", "Preferred angle(%d) is not allowed. CONF disabled",
481               ec, TIZEN_ROTATION_ANGLE_TO_INT(angle));
482         return;
483      }
484
485    rot->preferred_angle = angle;
486
487    if (TIZEN_ROTATION_ANGLE_TO_INT(angle) == e_client_rotation_curr_angle_get(ec))
488      {
489         ec->e.state.rot.preferred_rot = TIZEN_ROTATION_ANGLE_TO_INT(angle);
490         EDBG(ec, "preferred angle is same as current angle (%d). don't need to fetch.", ec->e.state.rot.preferred_rot);
491         return;
492      }
493
494    /* for clients supporting landscape mode only and clients supporting portrait mode in floating state*/
495    if (rot->preferred_angle)
496      {
497         enum tizen_rotation_angle tz_angle = 0;
498         uint32_t serial;
499         Eina_List *l;
500         struct wl_resource *res;
501
502         if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_90)
503           tz_angle = TIZEN_ROTATION_ANGLE_90;
504         else if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_270)
505           tz_angle = TIZEN_ROTATION_ANGLE_270;
506         else
507           {
508              if ((ec->floating) && (ec->comp_data) && ((ec->comp_data->shell.window.w != ec->w) || (ec->comp_data->shell.window.h != ec->h)))
509                {
510                   if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_0)
511                     tz_angle = TIZEN_ROTATION_ANGLE_0;
512                   else if (rot->preferred_angle & TIZEN_ROTATION_ANGLE_180)
513                     tz_angle = TIZEN_ROTATION_ANGLE_180;
514                   else
515                     {
516                        ERR("What's this impossible angle?? : %d", rot->preferred_angle);
517                     }
518                }
519           }
520
521         if (tz_angle)
522           {
523              serial = wl_display_next_serial(e_comp_wl->wl.disp);
524
525              rot->angle_change_done = EINA_FALSE;
526              rot->prev_angle = rot->cur_angle;
527              rot->cur_angle = tz_angle;
528              rot->serial = serial;
529
530              EINA_LIST_FOREACH(rot->rotation_list, l, res)
531                {
532                   int ver = wl_resource_get_version(resource);
533
534                   if ((ver >= 2) && ((tz_angle == TIZEN_ROTATION_ANGLE_0) || (tz_angle == TIZEN_ROTATION_ANGLE_180)))
535                     {
536                        int window_w, window_h;
537                        if (!ec->comp_data) continue;
538                        window_w = ec->comp_data->shell.window.w;
539                        window_h = ec->comp_data->shell.window.h;
540                        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",
541                             tz_angle, ec->w, ec->h, window_w, window_h, window_w, window_h, window_h, window_w);
542                        tizen_rotation_send_angle_change_with_resize(resource, tz_angle, serial, window_h, window_w);
543
544                        ec->e.state.rot.preferred_rot = TIZEN_ROTATION_ANGLE_TO_INT(angle);
545                        return;
546                     }
547                   else if ((tz_angle == TIZEN_ROTATION_ANGLE_90) || (tz_angle == TIZEN_ROTATION_ANGLE_270))
548                     {
549                        EDBG(ec, "Send Change Rotation: angle %d for rendering preparation of landscape mode only app. mapped:%d serial:%u",
550                             tz_angle, ec->first_mapped, serial);
551
552                        tizen_rotation_send_angle_change(res, tz_angle, serial);
553                     }
554                }
555           }
556      }
557
558    ec->e.fetch.rot.preferred_rot = 1;
559    EC_CHANGED(ec);
560 }
561
562 static void
563 _e_tizen_rotation_ack_angle_change_cb(struct wl_client *client,
564                                       struct wl_resource *resource,
565                                       uint32_t serial)
566 {
567    E_Client *ec;
568    Policy_Ext_Rotation *rot;
569
570    rot = wl_resource_get_user_data(resource);
571    EINA_SAFETY_ON_NULL_RETURN(rot);
572
573    ec = rot->ec;
574    if (!ec) return;
575
576    EDBG(ec, "Rotation Done: prev %d cur %d serial %u",
577         ec->e.state.rot.ang.curr,
578         TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle),
579         serial);
580
581    if ((serial != 0) && (rot->serial == serial)) // rotation success
582      {
583         if (rot->angle_change_done)
584           {
585              WRN("Rotation Zone Set: Rotation Done(fail case): %s(%p) Already received change_done for this serial:%u",
586                  ec->icccm.name ? ec->icccm.name : "", ec, serial);
587              return;
588           }
589
590         ec->e.state.rot.ang.prev = ec->e.state.rot.ang.curr;
591         ec->e.state.rot.ang.curr = TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle);
592
593         if (TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle) == ec->e.state.rot.ang.next)
594           {
595              ec->e.state.rot.ang.next = -1;
596
597              if (ec->e.state.rot.ang.reserve != -1)
598                {
599                   _e_client_rotation_list_remove(ec);
600
601                   e_client_rotation_set(ec, ec->e.state.rot.ang.reserve);
602                   ec->e.state.rot.ang.reserve = -1;
603                }
604              else
605                {
606                   /* it means that we need the next buffer commit after rotation ack event.
607                    * once we get next buffer commit, policy module attempts to remove
608                    * this ec from rotation_list_remove. and then, rotation process is finished.
609                    */
610                   rot->wait_update = EINA_TRUE;
611
612                   /* WORKAROUND
613                    *
614                    * Until now, we have assumed that the buffer commit event after the rotation
615                    * ack event informs us of completion of rotation. However this assumption could
616                    * be wrong because the rotation ack event is dispatched by main thread of client,
617                    * whereas the buffer commit event could be dispatched by other thread.
618                    *
619                    * The ideal solution for resolving this issue is introduction of same protocol
620                    * serial number between the rotation ack event and buffer commit event. But this
621                    * approach needs much of changes for EFL, E20 and DDK. Thus I have added workaround
622                    * code for quick resolving this.
623                    *
624                    * We have to extend EFL, E20 and DDK to support this later.
625                    */
626                   if (_browser_check(ec))
627                     {
628                        if (rot->wait_update_pending.timer)
629                          ecore_timer_del(rot->wait_update_pending.timer);
630
631                        rot->wait_update_pending.timer = NULL;
632                        rot->wait_update_pending.use = EINA_TRUE;
633                        rot->wait_update_pending.count = 2;
634                     }
635                }
636           }
637      }
638    else // rotation fail
639      {
640         WRN("Rotation Zone Set: Rotation Done(fail case): %s(%p) Not matched serial %u != %u",
641             ec->icccm.name ? ec->icccm.name : "", ec, rot->serial, serial);
642
643         _e_client_rotation_zone_set(ec->zone, ec, NULL);
644      }
645
646    // check angle change serial
647    rot->angle_change_done = EINA_TRUE;
648 }
649
650 static void
651 _e_tizen_rotation_set_geometry_hint_cb(struct wl_client *client,
652                                       struct wl_resource *resource,
653                                       uint32_t tz_angle,
654                                       uint32_t x, uint32_t y, uint32_t w, uint32_t h)
655 {
656    E_Client *ec;
657    Policy_Ext_Rotation *rot;
658    int i = -1;
659    int angle = 0;
660
661    rot = wl_resource_get_user_data(resource);
662    EINA_SAFETY_ON_NULL_RETURN(rot);
663
664    ec = rot->ec;
665    if (!ec)
666      return;
667
668    switch (tz_angle)
669      {
670         case TIZEN_ROTATION_ANGLE_0:
671           i = 0;
672           angle = 0;
673           break;
674         case TIZEN_ROTATION_ANGLE_90:
675           i = 1;
676           angle = 90;
677           break;
678         case TIZEN_ROTATION_ANGLE_180:
679           i = 2;
680           angle = 180;
681           break;
682         case TIZEN_ROTATION_ANGLE_270:
683           i = 3;
684           angle = 270;
685           break;
686         default:
687           return;
688      }
689
690    ec->e.state.rot.geom[i].x = x;
691    ec->e.state.rot.geom[i].y = y;
692    ec->e.state.rot.geom[i].w = w;
693    ec->e.state.rot.geom[i].h = h;
694
695    _e_client_event_client_rotation_geometry_set_send(ec, angle, x, y, w, h);
696 }
697
698 static void
699 _e_tizen_rotation_destroy(struct wl_resource *resource)
700 {
701    Policy_Ext_Rotation *ext_rot;
702
703    ext_rot = wl_resource_get_user_data(resource);
704    EINA_SAFETY_ON_NULL_RETURN(ext_rot);
705
706    ext_rot->rotation_list = eina_list_remove(ext_rot->rotation_list, resource);
707
708    /* if there's no connected client of tizen_rotation */
709    if (!ext_rot->rotation_list)
710      {
711         _e_client_rotation_list_remove(ext_rot->ec);
712         if (rot.async_list) rot.async_list = eina_list_remove(rot.async_list, ext_rot->ec);
713
714         ext_rot->angle_change_done = EINA_TRUE;
715      }
716 }
717
718 static void
719 _e_tizen_policy_ext_get_rotation_cb(struct wl_client *client,
720                                     struct wl_resource *resource,
721                                     uint32_t id,
722                                     struct wl_resource *surface)
723 {
724    int version = wl_resource_get_version(resource); // resource is tizen_policy_ext resource
725    struct wl_resource *res;
726    E_Client *ec;
727    Policy_Ext_Rotation *rot;
728
729    ec = wl_resource_get_user_data(surface);
730    EINA_SAFETY_ON_NULL_RETURN(ec);
731
732    // Add rotation info
733    rot = _policy_ext_rotation_get(ec);
734    EINA_SAFETY_ON_NULL_RETURN(rot);
735
736    res = wl_resource_create(client, &tizen_rotation_interface, version, id);
737    if (res == NULL)
738      {
739         wl_client_post_no_memory(client);
740         return;
741      }
742
743    rot->rotation_list = eina_list_append(rot->rotation_list, res);
744
745    wl_resource_set_implementation(res, &_e_tizen_rotation_interface,
746                                   rot, _e_tizen_rotation_destroy);
747
748    ec->e.fetch.rot.support = 1;
749    EC_CHANGED(ec);
750 }
751
752 static void
753 _e_tizen_policy_ext_active_angle_cb(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface)
754 {
755    int angle;
756    E_Zone *zone;
757    E_Client *ec;
758    E_Client *focused_ec;
759
760    if (!surface)
761      zone = e_zone_current_get();
762    else
763      {
764         ec = wl_resource_get_user_data(surface);
765         if (ec)
766           zone = ec->zone;
767         else
768           zone = e_zone_current_get();
769      }
770
771    if (!zone)
772      angle = -1;
773    else
774      {
775         focused_ec = e_client_focused_get();
776         if (!focused_ec)
777           angle = zone->rot.curr;
778         else
779           angle = focused_ec->e.state.rot.ang.curr;
780      }
781
782    tizen_policy_ext_send_active_angle(resource, angle);
783 }
784
785 static void
786 _e_tizen_policy_ext_bind_cb(struct wl_client *client, void *data, uint32_t version, uint32_t id)
787 {
788    struct wl_resource *res;
789
790    if (!(res = wl_resource_create(client, &tizen_policy_ext_interface3, version, id)))
791      {
792         ERR("Could not create scaler resource: %m");
793         wl_client_post_no_memory(client);
794         return;
795      }
796
797    wl_resource_set_implementation(res, &_e_tizen_policy_ext_interface, NULL, NULL);
798 }
799
800 static void
801 _e_tizen_rotation_send_angle_change(E_Client *ec, int angle)
802 {
803    Eina_List *l;
804    Policy_Ext_Rotation *rot;
805    uint32_t serial;
806    struct wl_resource *resource;
807    enum tizen_rotation_angle tz_angle = TIZEN_ROTATION_ANGLE_0;
808    int ver;
809    int rot_diff;
810
811    EINA_SAFETY_ON_NULL_RETURN(ec);
812    EINA_SAFETY_ON_NULL_RETURN(rot_hash);
813
814    rot_diff = ec->e.state.rot.ang.curr - angle;
815    if (rot_diff < 0) rot_diff = -rot_diff;
816
817    rot = eina_hash_find(rot_hash, &ec);
818    if (!rot) return;
819
820    switch (angle)
821      {
822         case 0:
823           tz_angle = TIZEN_ROTATION_ANGLE_0;
824           break;
825         case 90:
826           tz_angle = TIZEN_ROTATION_ANGLE_90;
827           break;
828         case 180:
829           tz_angle = TIZEN_ROTATION_ANGLE_180;
830           break;
831         case 270:
832           tz_angle = TIZEN_ROTATION_ANGLE_270;
833           break;
834         default:
835           break;
836      }
837
838    serial = wl_display_next_serial(e_comp_wl->wl.disp);
839
840    rot->angle_change_done = EINA_FALSE;
841    rot->prev_angle = rot->cur_angle;
842    rot->cur_angle = tz_angle;
843    rot->serial = serial;
844
845    EINA_LIST_FOREACH(rot->rotation_list, l, resource)
846      {
847         ver = wl_resource_get_version(resource); // resource is type of tizen_rotation_interface
848
849         if ((ver >= 2) && (ec->floating))
850           {
851              if (rot_diff == 180)
852                {
853                   EDBG(ec, "Send Change Rotation: angle %d mapped:%d serial:%u Resize:%dx%d",
854                        tz_angle, ec->first_mapped, serial, ec->w, ec->h);
855
856                   tizen_rotation_send_angle_change_with_resize(resource, tz_angle, serial, ec->w, ec->h);
857                }
858              else
859                {
860                   EDBG(ec, "Send Change Rotation: angle %d mapped:%d serial:%u Resize:%dx%d -> %dx%d",
861                        tz_angle, ec->first_mapped, serial, ec->w, ec->h, ec->h, ec->w);
862
863                   tizen_rotation_send_angle_change_with_resize(resource, tz_angle, serial, ec->h, ec->w);
864                }
865           }
866         else
867           {
868              EDBG(ec, "Send Change Rotation: angle %d mapped:%d serial:%u",
869                   tz_angle, ec->first_mapped, serial);
870
871              tizen_rotation_send_angle_change(resource, tz_angle, serial);
872           }
873      }
874 }
875
876 /* local subsystem e_client_rotation related functions */
877 static void
878 _e_client_rotation_list_remove(E_Client *ec)
879 {
880    E_Event_Client_Rotation_Change_End *ev = NULL;
881    Eina_Bool found = EINA_FALSE;
882
883    if (eina_list_data_find(rot.list, ec) == ec)
884      {
885         found = EINA_TRUE;
886         rot.list = eina_list_remove(rot.list, ec);
887      }
888
889    if (ec->e.state.rot.wait_for_done)
890      {
891         ec->e.state.rot.wait_for_done = 0;
892
893         /* if we make the e_client event in the _e_client_free function,
894          * then we may meet a crash problem, only work this at least e_client_hide.
895          */
896         if (!e_object_is_del(E_OBJECT(ec)))
897           {
898              ev = E_NEW(E_Event_Client_Rotation_Change_End, 1);
899              if (ev)
900                {
901                   ev->ec = ec;
902                   e_object_ref(E_OBJECT(ec));
903                   EDBG(ec, "Rotation Event: Client Rotation END");
904                   ecore_event_add(E_EVENT_CLIENT_ROTATION_CHANGE_END,
905                                   ev,
906                                   _e_client_event_client_rotation_change_end_free,
907                                   NULL);
908                }
909           }
910
911         if ((found) &&
912             (eina_list_count(rot.list) == 0))
913           {
914              _e_client_rotation_change_done();
915           }
916         /* handling pending zone rotation job */
917         else if ((eina_list_count(rot.list) == 0) &&
918                  (ec->zone->rot.wait_for_done) &&
919                  (ec->zone->rot.pending))
920           {
921              e_zone_rotation_update_done(ec->zone);
922           }
923      }
924    ec->e.state.rot.ang.next = -1;
925    ec->changes.rotation = 0;
926 }
927
928 static Eina_Bool
929 _e_client_rotation_angle_is_allowed(E_Client *ec, int angle)
930 {
931    if ((!_camera_check(ec)) &&
932        (!e_mod_pol_conf_rot_enable_get(angle)))
933      {
934         EDBG(ec, "CHECK dependent '%s'(%p) ang:%d rot.type:%d dependent:%d",
935              ec->icccm.name, ec, angle,
936              ec->e.state.rot.type,
937              E_CLIENT_ROTATION_TYPE_DEPENDENT);
938
939         /* check whether the window is 32bit and has the dependent rotation type.
940         * if true, then it can be rotated according to below normal window
941         * even if current zone angle is not allowed by configuration value.
942         */
943         if (!((ec->argb) && (e_client_rotation_is_available(ec, angle))))
944           return EINA_FALSE;
945      }
946    return EINA_TRUE;
947 }
948
949 /* TODO need to optimize */
950 static Eina_Bool
951 _e_client_rotation_zone_set(E_Zone *zone, E_Client *include_ec, E_Client *exclude_ec)
952 {
953    E_Client *ec, *bg_ec = NULL;
954    Eina_List *target_list = NULL, *l, *ll;
955    int angle, cur_angle, top_win_angle;
956    Eina_Bool can_rotate = EINA_TRUE, ret = EINA_FALSE;
957
958    TRACE_DS_BEGIN(CLIENT ROTATION ZONE SET);
959
960    if (zone->rot.unknown_state)
961      cur_angle = zone->rot.act;
962    else
963      cur_angle = zone->rot.curr;
964
965    top_win_angle = -1;
966
967    DBG("<<< Try to set zone rotation | fg_ec '%s'(%p) cur_angle:%d zone(unknown_state:%d act:%d curr:%d)",
968        fg_ec ? fg_ec->icccm.name : "",
969        fg_ec,
970        cur_angle,
971        zone->rot.unknown_state,
972        zone->rot.act,
973        zone->rot.curr);
974
975    E_CLIENT_REVERSE_FOREACH(ec)
976      {
977         if (ec->zone != zone) continue;
978         if (ec == exclude_ec) continue;
979         if ((ec != include_ec) && (!evas_object_visible_get(ec->frame))) continue;
980         if (e_object_is_del(E_OBJECT(ec))) continue;
981         if ((ec->comp_data) && (ec->comp_data->sub.data)) continue;
982         if (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role))
983           {
984              e_client_cursor_map_apply(ec, cur_angle, ec->x, ec->y);
985              continue;
986           }
987
988         if (!fg_ec)
989           {
990              if ((!bg_ec) ||
991                  ((include_ec == ec) &&
992                   (evas_object_layer_get(ec->frame) >= evas_object_layer_get(bg_ec->frame))))
993                {
994                   if (_e_client_rotation_angle_is_allowed(ec, cur_angle))
995                     {
996                        EDBG(ec, "Append to rotation target list");
997                        target_list = eina_list_append(target_list, ec);
998                     }
999                }
1000              else
1001                {
1002                   e_client_rotation_set(ec, cur_angle);
1003                   continue;
1004                }
1005
1006              if ((ec->x == zone->x) && (ec->y == zone->y) &&
1007                  (ec->w == zone->w) && (ec->h == zone->h) &&
1008                  (ec->e.state.rot.type == E_CLIENT_ROTATION_TYPE_NORMAL))
1009                {
1010                   if (!ec->argb)
1011                     {
1012                        EDBG(ec, "Found Topmost Fullscreen Window");
1013                        bg_ec = ec;
1014                     }
1015                   else
1016                     {
1017                        if ((ec->visibility.opaque > 0) &&
1018                            (!ec->parent))
1019                          {
1020                             EDBG(ec, "Found Topmost Fullscreen Window");
1021                             bg_ec = ec;
1022                          }
1023                     }
1024                }
1025           }
1026         else
1027           {
1028              ELOGF("ROTATION", "   fg_ec:%x, bg_ec:%p CHECK %s(%p) parent:%p vis:%d argb:%d opaque:%d",
1029                    ec, e_client_util_win_get(fg_ec), bg_ec, ec->icccm.name, ec, ec->parent,
1030                    ec->visibility.obscured, ec->argb, ec->visibility.opaque);
1031              /* if already found background client,
1032               * that means this client is placed under background client */
1033              if (bg_ec)
1034                {
1035                   /* if this client don't have parent, rotate */
1036                   if (!ec->parent)
1037                     {
1038                        /* 1. rotate window only if auto-rotation is enabled.
1039                         * it can show wrong rotated window if we don't check auto-rot value.
1040                         *
1041                         * assuming that auto-rotation is disabled and window A is 0 degree.
1042                         * in this case, when we attempt to run the camera-app which can be
1043                         * always rotated, window A is changed to 270 degrees before showing
1044                         * camera-app window. to prevent this we should check whether auto
1045                         * rotation is enabled.
1046                         *
1047                         * 2. also need to check this ec is visible before rotating it.
1048                         *
1049                         * e.g. camera -> image-viewer launching case
1050                         *
1051                         *  image-viewer: bg_ec is set to image-viewer ec at the previous phase of this loop
1052                         *  ec: camera
1053                         *
1054                         *  if we decide to rotate camera ec which is obscured by image-viewer window,
1055                         *  then camera app will not send rotation done event. thus it occurrs rotation time
1056                         *  out error. to resolve this issue we should exclude obscured camera ec from
1057                         *  rotation list.
1058                         */
1059                        if ((!zone->rot.block.sys_auto_rot) &&
1060                            (e_mod_pol_conf_rot_enable_get(cur_angle)) &&
1061                            (ec->visibility.obscured != E_VISIBILITY_FULLY_OBSCURED))
1062                          {
1063                             ELOGF("ROTATION", "Do rotation of below ec under bg_ec %s(%p)",
1064                                   NULL, ec->icccm.name, ec);
1065
1066                             e_client_rotation_set(ec, cur_angle);
1067                          }
1068                     }
1069                   continue;
1070                }
1071              /*
1072               * activity clients placed above background client should not be
1073               * rotated. that's because this is deactivated sometime later by
1074               * visibility's deiconify rendering logic.
1075               */
1076              else if ((fg_ec != ec) &&
1077                  (ec->x == zone->x) && (ec->y == zone->y) &&
1078                  (ec->w == zone->w) && (ec->h == zone->h) &&
1079                  (ec->e.state.rot.type == E_CLIENT_ROTATION_TYPE_NORMAL))
1080                {
1081                   if (!ec->argb)
1082                     continue;
1083                   else
1084                     {
1085                        if ((ec->visibility.opaque > 0) &&
1086                            (!ec->parent))
1087                          continue;
1088                     }
1089                }
1090
1091              if (_e_client_rotation_angle_is_allowed(ec, cur_angle))
1092                {
1093                   EDBG(ec, "Append Rotation List '%s'(%p)", ec->icccm.name, ec);
1094                   target_list = eina_list_append(target_list, ec);
1095                }
1096              if (ec == fg_ec)
1097                bg_ec = ec;
1098           }
1099      }
1100
1101    angle = cur_angle;
1102
1103    if (!target_list || (target_list && eina_list_count(target_list) == 0))
1104      {
1105         DBG("Failed to set rotation with zone: target_list is empty. angle: %d", angle);
1106         if (fg_ec)
1107           angle = _e_client_rotation_curr_next_get(fg_ec);
1108         can_rotate = EINA_FALSE;
1109      }
1110
1111    EINA_LIST_FOREACH(target_list, l, ec)
1112      {
1113         if (!e_client_rotation_is_available(ec, angle))
1114           {
1115              EDBG(ec, "Failed to set rotation with zone: not able to rotate given angle %d", angle);
1116              angle = _e_client_rotation_curr_next_get(ec);
1117              can_rotate = EINA_FALSE;
1118              break;
1119           }
1120         else
1121           {
1122              if (top_win_angle == -1)
1123                {
1124                   if (e_policy_client_is_keyboard(ec) ||
1125                       e_policy_client_is_keyboard_sub(ec))
1126                     continue;
1127
1128                   EDBG(ec, "Set top_win_angle: %d", angle);
1129                   top_win_angle = angle;
1130                }
1131           }
1132      }
1133
1134    if (!can_rotate)
1135      {
1136         can_rotate = EINA_TRUE;
1137         EINA_LIST_FOREACH(target_list, l, ec)
1138           {
1139              if (!e_client_rotation_is_available(ec, angle))
1140                {
1141                   EDBG(ec, "Failed to set with exist client: not able to rotate given angle %d", angle);
1142                   can_rotate = EINA_FALSE;
1143                   break;
1144                }
1145              else
1146                {
1147                   if (top_win_angle == -1)
1148                     {
1149                        if (e_policy_client_is_keyboard(ec) ||
1150                            e_policy_client_is_keyboard_sub(ec))
1151                          continue;
1152
1153                        EDBG(ec, "Set top_win_angle: %d", angle);
1154                        top_win_angle = angle;
1155                     }
1156                }
1157           }
1158      }
1159    else
1160      {
1161         DBG("Set rotation of zone according to angle of zone: %d", angle);
1162         goto do_rotate;
1163      }
1164
1165    if (!can_rotate)
1166      {
1167         /* support more than one client with fixed angle value */
1168         if (eina_list_count(target_list) > 0)
1169           {
1170              Eina_Bool res;
1171              int i, ang;
1172
1173              if (top_win_angle == -1)
1174                {
1175                   EINA_LIST_FOREACH_SAFE(target_list, l, ll, ec)
1176                     {
1177                        DBG("Find top most window angle");
1178                        // 1. check preferred
1179                        if (ec->e.state.rot.preferred_rot != -1)
1180                          {
1181                             EDBG(ec, "Set top_win_angle(preferred angle): %d", ec->e.state.rot.preferred_rot);
1182                             top_win_angle = ec->e.state.rot.preferred_rot;
1183                             break;
1184                          }
1185
1186                        // 2. check available angle
1187                        for (i = 0; i < 4; i++)
1188                          {
1189                             ang = (cur_angle + (i * 90)) % 360;
1190                             if (e_client_rotation_is_available(ec, ang))
1191                               {
1192                                  EDBG(ec, "Set top_win_angle: %d", ang);
1193                                  top_win_angle = ang;
1194                                  break;
1195                               }
1196                          }
1197
1198                        if (top_win_angle == -1)
1199                          {
1200                             // 3. couldn't find available angle
1201                             EDBG(ec, "Cannot find any available angle. Set top_win_angle to 0");
1202                             top_win_angle = 0;
1203                          }
1204
1205                        break;
1206                     }
1207                }
1208
1209              angle = top_win_angle;
1210
1211              EINA_LIST_FOREACH_SAFE(target_list, l, ll, ec)
1212                {
1213                   EDBG(ec, "Attempt to rotate client with given angle %d", top_win_angle);
1214                   if (e_client_rotation_is_available(ec, top_win_angle))
1215                     {
1216                        res = e_client_rotation_set(ec, top_win_angle);
1217                        if (!res) ret = EINA_FALSE;
1218                     }
1219                   else
1220                     {
1221                        EDBG(ec, "Failed to set given angle %d, Keep current angle %d", top_win_angle, ec->e.state.rot.ang.curr);
1222                     }
1223                }
1224
1225              EINA_LIST_FOREACH(rot.force_update_list, l, ec)
1226                {
1227                   if (!eina_list_data_find(target_list, ec))
1228                     {
1229                        EDBG(ec, "Rotate ec of force_update_list '%s'(%p)", ec->icccm.name, ec);
1230                        res = e_client_rotation_set(ec, top_win_angle);
1231                        if (!res) ret = EINA_FALSE;
1232                     }
1233                }
1234           }
1235
1236         goto end;
1237      }
1238    else
1239      {
1240         DBG("Set rotation of zone according to angle of exist clients: %d", angle);
1241         goto do_rotate;
1242      }
1243
1244 do_rotate:
1245    EINA_LIST_FOREACH(rot.force_update_list, l, ec)
1246      {
1247         if (!eina_list_data_find(target_list, ec))
1248           {
1249              EDBG(ec, "Append Rotation List from force_update_list '%s'(%p)", ec->icccm.name, ec);
1250              target_list = eina_list_append(target_list, ec);
1251           }
1252      }
1253
1254    EINA_LIST_FOREACH(target_list, l, ec)
1255       ret = e_client_rotation_set(ec, angle);
1256
1257 end:
1258    if (target_list)
1259      eina_list_free(target_list);
1260
1261    zone->rot.act = angle;
1262
1263    TRACE_DS_END();
1264
1265    ELOGF("ROTATION", "zone active angle %d", NULL, zone->rot.act);
1266    DBG("End to set zone rotation: %s >>>", ret ? "Change" : "Stay");
1267    return ret;
1268 }
1269
1270 static void
1271 _e_client_rotation_change_done(void)
1272 {
1273    Policy_Ext_Rotation *er;
1274    E_Client *ec;
1275
1276    if (rot.done_timer)
1277      {
1278         DBG("Remove rotation Timer by changing done");
1279         ecore_timer_del(rot.done_timer);
1280      }
1281    rot.done_timer = NULL;
1282
1283    EINA_LIST_FREE(rot.list, ec)
1284      {
1285         if (ec->e.state.rot.pending_show)
1286           {
1287              ec->e.state.rot.pending_show = 0;
1288              evas_object_show(ec->frame); // e_client_show(ec);
1289              e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
1290           }
1291         er = eina_hash_find(rot_hash, &ec);
1292         if ((er) && (er->show_grab))
1293           E_FREE_FUNC(er->show_grab, e_policy_visibility_client_grab_release);
1294         ec->e.state.rot.ang.next = -1;
1295         ec->e.state.rot.wait_for_done = 0;
1296      }
1297
1298    EINA_LIST_FREE(rot.async_list, ec)
1299      {
1300         _e_client_rotation_change_message_send(ec);
1301      }
1302
1303    rot.list = NULL;
1304    rot.async_list = NULL;
1305
1306    if (rot.screen_lock)
1307      {
1308         // do call comp_wl's screen unlock
1309         ELOGF("ROTATION", "RENDERING resume", NULL);
1310         e_comp_canvas_norender_pop();
1311         rot.screen_lock = EINA_FALSE;
1312      }
1313    e_zone_rotation_update_done(e_zone_current_get());
1314 }
1315
1316 static Eina_Bool
1317 _e_client_rotation_change_done_timeout(void *data)
1318 {
1319    E_Client *ec = (E_Client *)data;
1320
1321    if ((ec) && (!e_object_is_del(E_OBJECT(ec))))
1322      WRN("Timeout ROTATION_DONE %s(%p)",
1323          ec->icccm.name ? ec->icccm.name : "", ec);
1324    else
1325      WRN("Timeout ROTATION_DONE (%p)", ec);
1326
1327    _e_client_rotation_change_done();
1328    return ECORE_CALLBACK_CANCEL;
1329 }
1330
1331 static void
1332 _e_client_rotation_change_message_send(E_Client *ec)
1333 {
1334    int rotation;
1335
1336    if (!ec) return;
1337
1338    rotation = ec->e.state.rot.ang.next;
1339    if (rotation == -1) return;
1340    if (ec->e.state.rot.wait_for_done) return;
1341
1342    e_client_rotation_change_request(ec, rotation);
1343 }
1344
1345 static int
1346 _e_client_rotation_curr_next_get(const E_Client *ec)
1347 {
1348    if (!ec) return -1;
1349
1350    return ((ec->e.state.rot.ang.next == -1) ?
1351            ec->e.state.rot.ang.curr : ec->e.state.rot.ang.next);
1352 }
1353
1354 static void
1355 _e_client_event_client_rotation_change_begin_send(E_Client *ec)
1356 {
1357    E_Event_Client_Rotation_Change_Begin *ev = NULL;
1358    ev = E_NEW(E_Event_Client_Rotation_Change_Begin, 1);
1359    if (ev)
1360      {
1361         ev->ec = ec;
1362         e_object_ref(E_OBJECT(ec));
1363         EDBG(ec, "Rotation Event: Client Rotation BEGIN");
1364         ecore_event_add(E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN,
1365                         ev,
1366                         _e_client_event_client_rotation_change_begin_free,
1367                         NULL);
1368      }
1369 }
1370
1371 static void
1372 _e_client_event_client_rotation_change_cancel_send(E_Client *ec)
1373 {
1374    E_Event_Client_Rotation_Change_Cancel *ev = NULL;
1375    ev = E_NEW(E_Event_Client_Rotation_Change_Cancel, 1);
1376    if (ev)
1377      {
1378         ev->ec = ec;
1379         e_object_ref(E_OBJECT(ec));
1380         EDBG(ec, "Rotation Event: Client Rotation CANCEL");
1381         ecore_event_add(E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL,
1382                         ev,
1383                         _e_client_event_client_rotation_change_cancel_free,
1384                         NULL);
1385      }
1386 }
1387
1388 static void
1389 _e_client_event_client_rotation_change_begin_free(void *data __UNUSED__,
1390                                                   void      *ev)
1391 {
1392    E_Event_Client_Rotation_Change_Begin *e;
1393    e = ev;
1394    e_object_unref(E_OBJECT(e->ec));
1395    E_FREE(e);
1396 }
1397
1398 static void
1399 _e_client_event_client_rotation_change_cancel_free(void *data __UNUSED__,
1400                                                    void      *ev)
1401 {
1402    E_Event_Client_Rotation_Change_Cancel *e;
1403    e = ev;
1404    e_object_unref(E_OBJECT(e->ec));
1405    E_FREE(e);
1406 }
1407
1408 static void
1409 _e_client_event_client_rotation_change_end_free(void *data __UNUSED__,
1410                                                 void      *ev)
1411 {
1412    E_Event_Client_Rotation_Change_End *e;
1413    e = ev;
1414    e_object_unref(E_OBJECT(e->ec));
1415    E_FREE(e);
1416 }
1417
1418 static void
1419 _e_client_event_client_rotation_geometry_set_send(E_Client *ec, unsigned int angle, int x, int y, int w, int h)
1420 {
1421    E_Event_Client_Rotation_Geometry_Set *ev = NULL;
1422    ev = E_NEW(E_Event_Client_Rotation_Geometry_Set, 1);
1423    if (ev)
1424      {
1425         ev->ec = ec;
1426         ev->angle = angle;
1427         ev->x = x;
1428         ev->y = y;
1429         ev->w = w;
1430         ev->h = h;
1431         e_object_ref(E_OBJECT(ec));
1432         ecore_event_add(E_EVENT_CLIENT_ROTATION_GEOMETRY_SET,
1433                         ev,
1434                         _e_client_event_client_rotation_geometry_set_free,
1435                         NULL);
1436      }
1437 }
1438
1439 static void
1440 _e_client_event_client_rotation_geometry_set_free(void *data __UNUSED__,
1441                                                   void *ev)
1442 {
1443    E_Event_Client_Rotation_Geometry_Set *e;
1444    e = ev;
1445    e_object_unref(E_OBJECT(e->ec));
1446    E_FREE(e);
1447 }
1448
1449 static void
1450 _e_zone_event_rotation_change_begin_free(void *data __UNUSED__,
1451                                          void      *ev)
1452 {
1453    E_Event_Zone_Rotation_Change_Begin *e = ev;
1454    e_object_unref(E_OBJECT(e->zone));
1455    E_FREE(e);
1456 }
1457
1458 static void
1459 _e_zone_event_rotation_change_end_free(void *data __UNUSED__,
1460                                        void      *ev)
1461 {
1462    E_Event_Zone_Rotation_Change_End *e = ev;
1463    e_object_unref(E_OBJECT(e->zone));
1464    E_FREE(e);
1465 }
1466
1467 static void
1468 _e_zone_event_rotation_change_cancel_free(void *data __UNUSED__,
1469                                           void      *ev)
1470 {
1471    E_Event_Zone_Rotation_Change_Cancel *e = ev;
1472    e_object_unref(E_OBJECT(e->zone));
1473    E_FREE(e);
1474 }
1475
1476 /* e_client_roation functions */
1477 /**
1478  * @describe
1479  *  Get current rotoation state.
1480  * @param      ec             e_client
1481  * @return     EINA_FALSE     the state that does not rotating.
1482  *             EINA_TRUE      the state that rotating.
1483  */
1484 static Eina_Bool
1485 e_client_rotation_is_progress(const E_Client *ec)
1486 {
1487    if (!ec) return EINA_FALSE;
1488
1489    if (ec->e.state.rot.ang.next == -1)
1490      return EINA_FALSE;
1491    else
1492      return EINA_TRUE;
1493 }
1494
1495 /**
1496  * @describe
1497  *  Get current rotation angle.
1498  * @param      ec             e_client
1499  * @return     int            current angle
1500  */
1501 static int
1502 e_client_rotation_curr_angle_get(const E_Client *ec)
1503 {
1504    E_OBJECT_CHECK_RETURN(ec, -1);
1505    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, -1);
1506
1507    return ec->e.state.rot.ang.curr;
1508 }
1509
1510 /**
1511  * @describe
1512  *  Get being replaced rotation angle.
1513  * @param      ec             e_client
1514  * @return     int            be replaced angle.
1515  */
1516 static int
1517 e_client_rotation_next_angle_get(const E_Client *ec)
1518 {
1519    E_OBJECT_CHECK_RETURN(ec, -1);
1520    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, -1);
1521
1522    return ec->e.state.rot.ang.next;
1523 }
1524
1525 static E_Client *
1526 e_client_rotation_find_below(const E_Client *ec)
1527 {
1528    unsigned int x;
1529    E_Client *ec2;
1530    Eina_Inlist *l;
1531
1532    E_OBJECT_CHECK_RETURN(ec, NULL);
1533    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
1534
1535    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
1536    if (EINA_INLIST_GET(ec)->prev) //check current layer
1537      {
1538         for (l = EINA_INLIST_GET(ec)->prev; l; l = l->prev)
1539           {
1540              ec2 = EINA_INLIST_CONTAINER_GET(l, E_Client);
1541
1542              if ((ec2->comp_data && ec2->comp_data->mapped) &&
1543                  (!e_object_is_del(E_OBJECT(ec2))) &&
1544                  (!e_client_util_ignored_get(ec2)) &&
1545                  (!ec2->exp_iconify.by_client))
1546                return ec2;
1547           }
1548      }
1549
1550    /* go down the layers until we find one */
1551    if (e_comp_canvas_layer_map(ec->layer) > e_comp_canvas_layer_map(E_LAYER_MAX)) return NULL;
1552    x = e_comp_canvas_layer_map(ec->layer);
1553    if (x > 0) x--;
1554
1555    for (; x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
1556      {
1557         if (e_comp->layers[x].clients)
1558           {
1559              EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2)
1560                {
1561                   if (ec2 == ec) continue;
1562                   if ((ec2->comp_data && ec2->comp_data->mapped) &&
1563                       (!e_object_is_del(E_OBJECT(ec2))) &&
1564                       (!e_client_util_ignored_get(ec2)) &&
1565                       (!ec2->exp_iconify.by_client))
1566                     return ec2;
1567                }
1568           }
1569
1570         if (x == 0)
1571           break;
1572      }
1573    return NULL;
1574 }
1575
1576 /**
1577  * @describe
1578  *  Check if this e_client is rotatable to given angle.
1579  * @param      ec             e_client
1580  * @param      ang            test angle.
1581  * @return     EINA_FALSE     can't be rotated.
1582  *             EINA_TRUE      can be rotated.
1583  */
1584 static Eina_Bool
1585 e_client_rotation_is_available(const E_Client *ec, int ang)
1586 {
1587    Eina_Bool ret = EINA_FALSE;
1588    unsigned int i;
1589    E_Client *below = NULL;
1590    Eina_Bool below_rot = EINA_TRUE;
1591
1592    if (ang < 0) return EINA_FALSE;
1593    if (!ec->e.state.rot.support)
1594      goto no_hint;
1595
1596    if (ec->e.state.rot.type == E_CLIENT_ROTATION_TYPE_DEPENDENT)
1597      {
1598         // check below fullsize window's angle
1599         if ((ec->x == ec->zone->x) && (ec->y == ec->zone->y) &&
1600             (ec->w == ec->zone->w) && (ec->h == ec->zone->h))
1601           {
1602              below = e_client_rotation_find_below(ec);
1603              if (below)
1604                {
1605                   below_rot = e_client_rotation_is_available(below, ang);
1606                   if (!below_rot)
1607                     {
1608                        EDBG(ec, "ec's below(ec:%p, win:%x) can not rotate to angle [%d]", below, e_client_util_win_get(below), ang);
1609                        goto no_hint;
1610                     }
1611                }
1612           }
1613      }
1614
1615    if (ec->e.state.rot.preferred_rot == -1)
1616      {
1617         if (ec->e.state.rot.available_rots &&
1618             ec->e.state.rot.count)
1619           {
1620              for (i = 0; i < ec->e.state.rot.count; i++)
1621                {
1622                   if (ec->e.state.rot.available_rots[i] == ang)
1623                     {
1624                        ret = EINA_TRUE;
1625                        break;
1626                     }
1627                }
1628           }
1629         else
1630           goto no_hint;
1631      }
1632    else if (ec->e.state.rot.preferred_rot == ang)
1633      ret = EINA_TRUE;
1634
1635    return ret;
1636 no_hint:
1637    return (ang == 0);
1638 }
1639
1640 /**
1641  * @describe
1642  *  Set the rotation of the e_client given angle.
1643  * @param      ec             e_client
1644  * *param      rotation       angle
1645  * @return     EINA_TRUE      rotation starts or is already in progress.
1646  *             EINA_FALSE     fail
1647  */
1648 static Eina_Bool
1649 e_client_rotation_set(E_Client *ec, int rotation)
1650 {
1651    Eina_List *list, *l;
1652    E_Client *child;
1653    int curr_rot;
1654    Policy_Ext_Rotation *ext_rot;
1655
1656    if (!ec) return EINA_FALSE;
1657
1658    if (rotation < 0) return EINA_FALSE;
1659    if (!e_client_rotation_is_available(ec, rotation)) return EINA_FALSE;
1660
1661    TRACE_DS_BEGIN(CLIENT ROTATION SET);
1662    TRACE_DS_BEGIN(CLINET CURRENT ANGLE SET);
1663
1664    // in case same with current angle.
1665    curr_rot = e_client_rotation_curr_angle_get(ec);
1666    EDBG(ec, "Client Rotation name:%s, curr_rot:%d, rotation:%d", ec->icccm.name?:"NULL", curr_rot, rotation);
1667    if (curr_rot == rotation)
1668      {
1669         if (e_client_rotation_is_progress(ec))
1670           {
1671              // cancel the changes in case only doesn't send request.
1672              if ((!ec->e.state.rot.pending_change_request) &&
1673                  (!ec->e.state.rot.wait_for_done))
1674                {
1675                   EDBG(ec, "Client Rotation Canceled (curr_rot == rot %d)", rotation);
1676                   _e_client_rotation_list_remove(ec);
1677                   if (ec->e.state.rot.pending_show)
1678                     {
1679                        ec->e.state.rot.pending_show = 0;
1680                        if (!e_object_is_del(E_OBJECT(ec)))
1681                          {
1682                             evas_object_show(ec->frame); // e_client_show(ec);
1683                             e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
1684                          }
1685                     }
1686
1687                   _e_client_event_client_rotation_change_cancel_send(ec);
1688
1689                   TRACE_DS_END();
1690                   TRACE_DS_END();
1691                   return EINA_FALSE;
1692                }
1693           }
1694         else
1695           {
1696              TRACE_DS_END();
1697              TRACE_DS_END();
1698              return EINA_FALSE;
1699           }
1700      }
1701    TRACE_DS_END();
1702
1703    ext_rot = eina_hash_find(rot_hash, &ec);
1704    if (ext_rot)
1705      {
1706         if (ext_rot->wait_update_pending.timer)
1707           ecore_timer_del(ext_rot->wait_update_pending.timer);
1708         ext_rot->wait_update_pending.timer = NULL;
1709      }
1710
1711    // in case same with next angle.
1712    curr_rot = e_client_rotation_next_angle_get(ec);
1713    if (curr_rot == rotation)
1714      {
1715         // if there is reserve angle, remove it.
1716         if (ec->e.state.rot.ang.reserve != -1)
1717           {
1718              ec->e.state.rot.ang.reserve = -1;
1719           }
1720         goto finish;
1721      }
1722
1723    /* if this e_client is rotating now,
1724     * it will be rotated to this angle after rotation done.
1725     */
1726    if ((ec->e.state.rot.pending_change_request) ||
1727        (ec->e.state.rot.wait_for_done))
1728      {
1729         ec->e.state.rot.ang.reserve = rotation;
1730         goto finish;
1731      }
1732
1733    /* search rotatable window in this window's child */
1734    list = eina_list_clone(ec->transients);
1735    EINA_LIST_FOREACH(list, l, child)
1736      {
1737         // the window which type is "E_WINDOW_TYPE_NORMAL" will be rotated itself.
1738         // it shouldn't be rotated by rotation state of parent window.
1739         if (child->netwm.type == E_WINDOW_TYPE_NORMAL) continue;
1740         if (child->comp_data && !child->comp_data->mapped) continue;
1741
1742         ELOGF("ROTATION", "Do rotation of child win %s(%p)",
1743               NULL, child->icccm.name, child);
1744
1745         e_client_rotation_set(child, rotation);
1746      }
1747    eina_list_free(list);
1748
1749    if (!e_client_rotation_is_progress(ec))
1750      {
1751         _e_client_event_client_rotation_change_begin_send(ec);
1752      }
1753
1754    ec->e.state.rot.pending_change_request = 0;
1755    ec->e.state.rot.ang.next = rotation;
1756    ec->changes.rotation = 1;
1757    EC_CHANGED(ec);
1758
1759 finish:
1760    /* Now the WM has a rotatable window thus we unset variables about zone rotation cancel */
1761    if (rot.cancel.state)
1762      {
1763         rot.cancel.state = EINA_FALSE;
1764         rot.cancel.zone = NULL;
1765      }
1766
1767    TRACE_DS_END();
1768    return EINA_TRUE;
1769 }
1770
1771 static void
1772 e_client_rotation_change_request(E_Client *ec, int rotation)
1773 {
1774    if (!ec) return;
1775    if (rotation < 0) return;
1776
1777    // if this window is in withdrawn state, change the state to NORMAL.
1778    // that's because the window in withdrawn state can't render its canvas.
1779    // eventually, this window will not send the message of rotation done,
1780    // even if e request to rotation this window.
1781
1782    //TODO: e_hint set is really neeed?.
1783    e_hints_window_visible_set(ec);
1784
1785    _e_tizen_rotation_send_angle_change(ec, rotation);
1786
1787    ec->e.state.rot.wait_for_done = 1;
1788
1789    if ((!rot.async_list) ||
1790        (!eina_list_data_find(rot.async_list, ec)))
1791      {
1792         if (rot.done_timer)
1793           ecore_timer_del(rot.done_timer);
1794         rot.done_timer = ecore_timer_add(4.0f,
1795                                          _e_client_rotation_change_done_timeout,
1796                                          ec);
1797      }
1798 }
1799
1800 /* e_zone_roation functions */
1801 static void
1802 _e_zone_rotation_set_internal(E_Zone *zone, int rot)
1803 {
1804    E_Event_Zone_Rotation_Change_Begin *ev;
1805
1806    E_OBJECT_CHECK(zone);
1807    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1808
1809    if (zone->rot.wait_for_done)
1810      {
1811         INF("Pending Zone Rotation: wait_for_done %d block_count %d",
1812             zone->rot.wait_for_done, zone->rot.block.mod_count);
1813         zone->rot.next = rot;
1814         zone->rot.pending = EINA_TRUE;
1815         return;
1816      }
1817
1818    if (!e_config->wm_win_rotation) return;
1819
1820    ELOGF("ROTATION", "ZONE_ROT |zone:%d|rot curr:%d, active:%d, rot:%d",
1821          NULL, zone->num, zone->rot.curr, zone->rot.act, rot);
1822
1823    if ((zone->rot.curr == rot) &&
1824        (zone->rot.act == rot))
1825      return;
1826
1827    ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->1",
1828          NULL, zone->rot.wait_for_done);
1829
1830    zone->rot.prev = zone->rot.act;
1831    zone->rot.curr = rot;
1832    zone->rot.wait_for_done = EINA_TRUE;
1833
1834    ev = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
1835    if (ev)
1836      {
1837         ev->zone = zone;
1838         e_object_ref(E_OBJECT(ev->zone));
1839         ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
1840                         ev, _e_zone_event_rotation_change_begin_free, NULL);
1841      }
1842 }
1843
1844 EINTERN void
1845 e_zone_rotation_set(E_Zone *zone, int rotation)
1846 {
1847    E_OBJECT_CHECK(zone);
1848    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1849
1850    TRACE_DS_BEGIN(ZONE ROTATION SET);
1851
1852    zone->rot.unknown_state = EINA_TRUE;
1853
1854    if (rotation == -1)
1855      {
1856         ELOGF("ROTATION", "ZONE_ROT |UNKNOWN SET|zone:%d|rot curr:%d, rot:%d",
1857               NULL, zone->num, zone->rot.curr, rotation);
1858         return;
1859      }
1860
1861    if (e_zone_rotation_block_get(zone, rotation))
1862      {
1863         if ((zone->rot.wait_for_done) ||
1864             (zone->rot.block.mod_count > 0))
1865           {
1866              if ((!zone->rot.unblock.app_hint) &&
1867                  (!e_mod_pol_conf_rot_enable_get(rotation)))
1868                {
1869                   ELOGF("ROTATION", "ZONE_ROT |SKIP|zone:%d curr:%d rotation:%d config is not allowed",
1870                         NULL, zone->num, zone->rot.curr, rotation);
1871                   zone->rot.unknown_state = EINA_FALSE;
1872                   return;
1873                }
1874
1875              INF("Pending Zone Rotation: wait_for_done %d block_count %d",
1876                  zone->rot.wait_for_done, zone->rot.block.mod_count);
1877              zone->rot.next = rotation;
1878              zone->rot.pending = EINA_TRUE;
1879              return;
1880           }
1881
1882         if (zone->rot.block.sys_auto_rot)
1883           {
1884              ELOGF("ROTATION", "ZONE_ROT |SKIP|zone:%d curr:%d rotation:%d. auto rotation is locked",
1885                    NULL, zone->num, zone->rot.curr, rotation);
1886              zone->rot.unknown_state = EINA_FALSE;
1887              return;
1888           }
1889
1890         ELOGF("ROTATION", "ZONE_ROT |UNKNOWN SET|zone:%d|rot curr:%d, rot:%d",
1891               NULL, zone->num, zone->rot.curr, rotation);
1892         return;
1893      }
1894
1895    zone->rot.unknown_state = EINA_FALSE;
1896
1897    _e_zone_rotation_set_internal(zone, rotation);
1898    TRACE_DS_END();
1899 }
1900
1901 static void
1902 e_zone_rotation_sub_set(E_Zone *zone, int rotation)
1903 {
1904    E_OBJECT_CHECK(zone);
1905    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1906
1907    ELOGF("ROTATION", "SUB_SET  |zone:%d|rot curr:%d, rot:%d",
1908          NULL, zone->num, zone->rot.curr, rotation);
1909
1910    zone->rot.sub = rotation;
1911
1912    if ((zone->rot.unknown_state) &&
1913        (zone->rot.curr != rotation))
1914      _e_zone_rotation_set_internal(zone, rotation);
1915 }
1916
1917 /* This function has the policy of window rotation LOCK which is
1918  * determined according to the UX or the system order of priority.
1919  */
1920 EINTERN Eina_Bool
1921 e_zone_rotation_block_get(E_Zone *zone, int rot)
1922 {
1923    /* 1. specific app which set special hint such as camera */
1924    if (zone->rot.unblock.app_hint)
1925      {
1926         ELOGF("ROTATION", "BLOCK Get. unblocked by app_hint", NULL);
1927         return EINA_FALSE;
1928      }
1929
1930    /* 2. not supported angle in wm-policy configuration */
1931    if (!e_mod_pol_conf_rot_enable_get(rot))
1932      {
1933         ELOGF("ROTATION", "BLOCK Get. CONF disabled", NULL);
1934         return EINA_TRUE;
1935      }
1936
1937    /* 3. auto-rotation through vconf */
1938    if (zone->rot.block.sys_auto_rot)
1939      {
1940         ELOGF("ROTATION", "BLOCK Get. AUTO_ROT disabled", NULL);
1941         return EINA_TRUE;
1942      }
1943
1944    /* 4. temporary block count for the E sub-modules */
1945    if (zone->rot.block.mod_count > 0)
1946      {
1947         ELOGF("ROTATION", "BLOCK Get. E internal block. %d", NULL,
1948               zone->rot.block.mod_count);
1949         return EINA_TRUE;
1950      }
1951
1952    return EINA_FALSE;
1953 }
1954
1955 EINTERN Eina_Bool
1956 e_zone_rotation_block_type_set(E_Zone *zone, E_Zone_Rot_Block_Type type, const char *name_hint, Eina_Bool block)
1957 {
1958    E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
1959    E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
1960
1961    switch (type)
1962      {
1963       case E_ZONE_ROT_BLOCK_TYPE_SYSTEM_AUTO_ROTATION:
1964          zone->rot.block.sys_auto_rot = block;
1965          ELOGF("ROTATION", "BLOCK_SET. sys_auto_rot:%s", NULL,
1966                block ? "true" : "false");
1967          break;
1968       case E_ZONE_ROT_BLOCK_TYPE_E_MODULE:
1969          if (block) zone->rot.block.mod_count++;
1970          else       zone->rot.block.mod_count--;
1971          if (zone->rot.block.mod_count <= 0) zone->rot.block.mod_count = 0;
1972          ELOGF("ROTATION", "BLOCK_SET. e modules:%s count:%d", NULL,
1973                block ? "true" : "false", zone->rot.block.mod_count);
1974          break;
1975       default:
1976          break;
1977      }
1978
1979    return EINA_TRUE;
1980 }
1981
1982 EINTERN Eina_Bool
1983 e_zone_rotation_unblock_type_set(E_Zone *zone, E_Zone_Rot_Unblock_Type type, const char *name_hint, Eina_Bool unblock)
1984 {
1985    E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
1986    E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
1987
1988    switch (type)
1989      {
1990       case E_ZONE_ROT_UNBLOCK_TYPE_APP_HINT:
1991          zone->rot.unblock.app_hint = unblock;
1992          ELOGF("ROTATION", "UnBLOCK_SET app hint:%s", NULL,
1993                unblock ? "true" : "false");
1994          break;
1995       default:
1996          break;
1997      }
1998
1999    return EINA_TRUE;
2000 }
2001
2002 EINTERN Eina_Bool
2003 e_zone_rotation_block_set(E_Zone *zone, const char *name_hint, Eina_Bool block)
2004 {
2005    E_Event_Zone_Rotation_Change_Begin *ev;
2006
2007    E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
2008    E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
2009
2010    e_zone_rotation_block_type_set(zone,
2011                                   E_ZONE_ROT_BLOCK_TYPE_E_MODULE,
2012                                   name_hint,
2013                                   block);
2014    if (block) return EINA_TRUE;
2015
2016    ELOGF("ROTATION", "ROT_BLOCK|RESUME|zone:%d|count:%d|from:%s|rot.pending:%d|next:%d",
2017          NULL,
2018          zone->num,
2019          zone->rot.block.mod_count,
2020          name_hint,
2021          zone->rot.pending,
2022          zone->rot.next);
2023
2024    if (zone->rot.pending)
2025      {
2026         zone->rot.pending = EINA_FALSE;
2027         if (zone->rot.curr != zone->rot.next)
2028           {
2029              if (e_zone_rotation_block_get(zone, zone->rot.next))
2030                {
2031                   zone->rot.pending = EINA_TRUE;
2032                   ELOGF("ROTATION", "ROT_BLOCK|PAUSE|zone:%d|count:%d|from:%s", NULL,
2033                         zone->num, zone->rot.block.mod_count, name_hint);
2034                   return EINA_TRUE;
2035                }
2036
2037              ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->1",
2038                    NULL, zone->rot.wait_for_done);
2039
2040              zone->rot.prev = zone->rot.curr;
2041              zone->rot.curr = zone->rot.next;
2042              zone->rot.wait_for_done = EINA_TRUE;
2043              zone->rot.pending = EINA_FALSE;
2044
2045              ev = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
2046              if (ev)
2047                {
2048                   ev->zone = zone;
2049                   e_object_ref(E_OBJECT(ev->zone));
2050                   ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
2051                                   ev, _e_zone_event_rotation_change_begin_free, NULL);
2052
2053                   ELOGF("ROTATION", "ROT_SET(P|zone:%d|rot:%d",
2054                         NULL, zone->num, zone->rot.curr);
2055                }
2056           }
2057      }
2058
2059    return EINA_TRUE;
2060 }
2061
2062 static void
2063 e_zone_rotation_update_done(E_Zone *zone)
2064 {
2065    E_Event_Zone_Rotation_Change_End *ev;
2066
2067    E_OBJECT_CHECK(zone);
2068    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
2069
2070    ELOGF("ROTATION", "ROT_DONE |zone:%d|rot:%d",
2071          NULL, zone->num, zone->rot.curr);
2072
2073    ev = E_NEW(E_Event_Zone_Rotation_Change_End, 1);
2074    if (ev)
2075      {
2076         ev->zone = zone;
2077         e_object_ref(E_OBJECT(ev->zone));
2078         ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_END,
2079                         ev, _e_zone_event_rotation_change_end_free, NULL);
2080      }
2081
2082    ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->0",
2083          NULL, zone->rot.wait_for_done);
2084
2085    zone->rot.wait_for_done = EINA_FALSE;
2086    if ((zone->rot.block.mod_count == 0) && (zone->rot.pending))
2087      {
2088         zone->rot.pending = EINA_FALSE;
2089         if (zone->rot.curr != zone->rot.next)
2090           {
2091              ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->1",
2092                    NULL, zone->rot.wait_for_done);
2093
2094              zone->rot.prev = zone->rot.curr;
2095              zone->rot.curr = zone->rot.next;
2096              zone->rot.wait_for_done = EINA_TRUE;
2097              zone->rot.pending = EINA_FALSE;
2098
2099              E_Event_Zone_Rotation_Change_Begin *ev2;
2100              ev2 = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
2101              if (ev2)
2102                {
2103                   ev2->zone = zone;
2104                   e_object_ref(E_OBJECT(ev2->zone));
2105                   ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
2106                                   ev2, _e_zone_event_rotation_change_begin_free, NULL);
2107
2108                   ELOGF("ROTATION", "ROT_SET(P|zone:%d|rot:%d",
2109                         NULL, zone->num, zone->rot.curr);
2110
2111                }
2112           }
2113      }
2114 }
2115
2116 static void
2117 e_zone_rotation_update_cancel(E_Zone *zone)
2118 {
2119    E_Event_Zone_Rotation_Change_Cancel *ev;
2120
2121    E_OBJECT_CHECK(zone);
2122    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
2123
2124    ELOGF("ROTATION", "ZONE_ROT |wait_for_done:%d->0",
2125          NULL, zone->rot.wait_for_done);
2126
2127    zone->rot.wait_for_done = EINA_FALSE;
2128    if (zone->rot.pending)
2129      {
2130         zone->rot.prev = zone->rot.curr;
2131         zone->rot.curr = zone->rot.next;
2132         zone->rot.pending = EINA_FALSE;
2133      }
2134
2135    ev = E_NEW(E_Event_Zone_Rotation_Change_Cancel, 1);
2136    if (ev)
2137      {
2138         ev->zone = zone;
2139         e_object_ref(E_OBJECT(ev->zone));
2140         ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_CANCEL,
2141                         ev, _e_zone_event_rotation_change_cancel_free, NULL);
2142      }
2143 }
2144
2145 static Eina_Bool
2146 _rot_cb_zone_rotation_change_begin(void *data EINA_UNUSED, int ev_type EINA_UNUSED, E_Event_Zone_Rotation_Change_Begin *ev)
2147 {
2148    if ((!ev) || (!ev->zone)) return ECORE_CALLBACK_PASS_ON;
2149
2150    DBG("Rotation Zone Set: Rotation Change Begin");
2151    if (!_e_client_rotation_zone_set(ev->zone, NULL, NULL))
2152      {
2153         /* The WM will decide to cancel zone rotation at idle time.
2154          * Because, the policy module can make list of rotation windows
2155          */
2156         rot.cancel.state = EINA_TRUE;
2157         rot.cancel.zone = ev->zone;
2158      }
2159
2160    return ECORE_CALLBACK_RENEW;
2161 }
2162
2163 static void
2164 _e_client_rotation_wait_update_clear(E_Client *ec)
2165 {
2166    Policy_Ext_Rotation *rot;
2167
2168    rot = eina_hash_find(rot_hash, &ec);
2169    if (!rot) return;
2170
2171    rot->wait_update_pending.timer = NULL;
2172
2173    _e_client_rotation_list_remove(ec);
2174    if (ec->e.state.rot.pending_show)
2175      {
2176         ec->e.state.rot.pending_show = 0;
2177         evas_object_show(ec->frame);
2178         e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
2179      }
2180
2181    if (rot->show_grab)
2182      E_FREE_FUNC(rot->show_grab, e_policy_visibility_client_grab_release);
2183
2184    rot->wait_update = EINA_FALSE;
2185 }
2186
2187 static Eina_Bool
2188 _e_client_rotation_wait_update_pending_timeout(void *data)
2189 {
2190    E_Client *ec = (E_Client *)data;
2191
2192    if ((ec) && (!e_object_is_del(E_OBJECT(ec))))
2193      WRN("Timeout Wait Update Pending %s(%p)",
2194          ec->icccm.name ? ec->icccm.name : "", ec);
2195    else
2196      WRN("Timeout Wait Update Pending (%p)", ec);
2197
2198    if (ec)
2199      _e_client_rotation_wait_update_clear(ec);
2200
2201    return ECORE_CALLBACK_CANCEL;
2202 }
2203
2204 static void
2205 _rot_cb_wl_buffer_change(void *d EINA_UNUSED, E_Client *ec)
2206 {
2207    Policy_Ext_Rotation *rot;
2208
2209    rot = eina_hash_find(rot_hash, &ec);
2210    if (!rot) return;
2211    if (ec->e.state.rot.nopending_render) return;
2212
2213    if (!rot->angle_change_done)
2214      {
2215         DBG("Update Buffer in progress of rotation ec '%s'(%p) HOOK",
2216             ec->icccm.name ? ec->icccm.name : "", ec);
2217
2218         e_pixmap_image_clear(ec->pixmap, EINA_TRUE);
2219         e_pixmap_resource_set(ec->pixmap, NULL);
2220      }
2221 }
2222
2223 static Eina_Bool
2224 _rot_cb_buffer_change(void *data EINA_UNUSED, int ev_type EINA_UNUSED, E_Event_Client *ev)
2225 {
2226    Policy_Ext_Rotation *rot;
2227
2228    if (EINA_UNLIKELY(!ev))
2229      goto end;
2230
2231    if (EINA_UNLIKELY(!ev->ec))
2232      goto end;
2233
2234    rot = eina_hash_find(rot_hash, &ev->ec);
2235    if (!rot)
2236      goto end;
2237
2238    /* WORKAROUND
2239     * wl_buffer can be destroyed after attach/damage/frame/commit to wl_surface.
2240     * we have to handle this case.
2241     */
2242    if ((!rot->angle_change_done) || (!e_pixmap_resource_get(ev->ec->pixmap)))
2243      {
2244         DBG("Update Buffer in progress of rotation ec '%s'(%p) EVENT nopending_render:%d",
2245             ev->ec->icccm.name ? ev->ec->icccm.name : "", ev->ec,
2246             ev->ec->e.state.rot.nopending_render);
2247
2248         if (!ev->ec->e.state.rot.nopending_render)
2249           {
2250              e_pixmap_image_clear(ev->ec->pixmap, EINA_TRUE);
2251              e_pixmap_resource_set(ev->ec->pixmap, NULL);
2252           }
2253      }
2254    else if (rot->wait_update)
2255      {
2256         DBG("Update Buffer After Rotation Done ec '%s'(%p) b %p pending:%d count:%d",
2257             ev->ec->icccm.name ? ev->ec->icccm.name : "",
2258             ev->ec,
2259             e_pixmap_resource_get(ev->ec->pixmap),
2260             rot->wait_update_pending.use,
2261             rot->wait_update_pending.count);
2262
2263         if (rot->wait_update_pending.use)
2264           {
2265              if (rot->wait_update_pending.count > 0)
2266                {
2267                   if (rot->wait_update_pending.count == 2)
2268                     {
2269                        if (rot->wait_update_pending.timer)
2270                          ecore_timer_del(rot->wait_update_pending.timer);
2271
2272                        rot->wait_update_pending.timer = ecore_timer_add(0.1f,
2273                                                                         _e_client_rotation_wait_update_pending_timeout,
2274                                                                         ev->ec);
2275                     }
2276
2277                   rot->wait_update_pending.count--;
2278                   return ECORE_CALLBACK_RENEW;
2279                }
2280              else
2281                {
2282                   if (rot->wait_update_pending.timer)
2283                     ecore_timer_del(rot->wait_update_pending.timer);
2284                   rot->wait_update_pending.timer = NULL;
2285                }
2286           }
2287
2288         _e_client_rotation_wait_update_clear(ev->ec);
2289      }
2290
2291    if (ev->ec->e.state.rot.pending_show)
2292      {
2293         DBG("Buffer Changed: force add update list to send frame until pending show");
2294         /* consider e_pixmap_image_clear() instead of update_add() */
2295         e_pixmap_image_clear(ev->ec->pixmap, EINA_TRUE);
2296      }
2297
2298 end:
2299    return ECORE_CALLBACK_RENEW;
2300 }
2301
2302 static void
2303 _rot_hook_new_client(void *d EINA_UNUSED, E_Client *ec)
2304 {
2305    Policy_Ext_Rotation *rot;
2306
2307    ec->e.state.rot.preferred_rot = -1;
2308    ec->e.state.rot.type = E_CLIENT_ROTATION_TYPE_NORMAL;
2309    ec->e.state.rot.ang.next = -1;
2310    ec->e.state.rot.ang.reserve = -1;
2311    ec->e.state.rot.pending_show = 0;
2312    ec->e.state.rot.ang.curr = 0;
2313    ec->e.state.rot.ang.prev = 0;
2314
2315    EINA_SAFETY_ON_NULL_RETURN(rot_hash);
2316
2317    rot = eina_hash_find(rot_hash, &ec);
2318    if (!rot) return;
2319
2320    if (rot->preferred_angle)
2321      ec->e.fetch.rot.preferred_rot = 1;
2322
2323    if (rot->available_angles)
2324      ec->e.fetch.rot.available_rots = 1;
2325 }
2326
2327 static void
2328 _rot_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
2329 {
2330    Policy_Ext_Rotation *ext_rot;
2331    struct wl_resource *res;
2332
2333    _e_client_rotation_list_remove(ec);
2334    if (rot.async_list) rot.async_list = eina_list_remove(rot.async_list, ec);
2335
2336    ec->e.state.rot.preferred_rot = -1;
2337
2338    if (ec->e.state.rot.available_rots)
2339      E_FREE(ec->e.state.rot.available_rots);
2340
2341    ext_rot = eina_hash_find(rot_hash, &ec);
2342    if (ext_rot)
2343      {
2344         if (ext_rot->wait_update_pending.timer)
2345           ecore_timer_del(ext_rot->wait_update_pending.timer);
2346         ext_rot->wait_update_pending.timer = NULL;
2347
2348         EINA_LIST_FREE(ext_rot->rotation_list, res)
2349            wl_resource_set_user_data(res, NULL);
2350
2351         eina_hash_del_by_key(rot_hash, &ec);
2352      }
2353
2354    if (fg_ec == ec)
2355      {
2356         EDBG(ec, "Set the fg_ec to NULL");
2357         fg_ec = NULL;
2358
2359         if (_camera_check(ec))
2360           _try_lock_rot_for_fg_app(ec->zone);
2361      }
2362 }
2363
2364 static void
2365 _rot_hook_eval_end(void *d EINA_UNUSED, E_Client *ec)
2366 {
2367    if (ec->changes.rotation)
2368      {
2369         E_Zone *zone = ec->zone;
2370
2371         if (ec->moving) e_client_act_move_end(ec, NULL);
2372
2373         if ((!zone->rot.block.mod_count) &&
2374             ((!evas_object_visible_get(ec->frame)) ||
2375              (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zone->x, zone->y, zone->w, zone->h))))
2376           {
2377              // async list add
2378              rot.async_list = eina_list_append(rot.async_list, ec);
2379           }
2380         else
2381           {
2382              // sync list add
2383              rot.list = eina_list_append(rot.list, ec);
2384              _e_client_rotation_change_message_send(ec);
2385           }
2386         rot.fetch = EINA_TRUE;
2387         ec->changes.rotation = 0;
2388      }
2389 }
2390
2391 static void
2392 _rot_hook_eval_fetch(void *d EINA_UNUSED, E_Client *ec)
2393 {
2394    Policy_Ext_Rotation *rot;
2395
2396    if (!ec) return;
2397
2398    rot = eina_hash_find(rot_hash, &ec);
2399    if (!rot) return;
2400
2401    if(ec->e.fetch.rot.support)
2402      {
2403         ec->e.state.rot.support = 1;
2404
2405         ec->e.fetch.rot.need_rotation = EINA_TRUE;
2406         ec->e.fetch.rot.support = 0;
2407      }
2408    if (ec->e.fetch.rot.preferred_rot)
2409      {
2410         int _prev_preferred_rot;
2411         _prev_preferred_rot = ec->e.state.rot.preferred_rot;
2412         ec->e.state.rot.preferred_rot = -1;
2413
2414         switch (rot->preferred_angle)
2415           {
2416              case TIZEN_ROTATION_ANGLE_0:
2417                 ec->e.state.rot.preferred_rot = 0;
2418                 break;
2419              case TIZEN_ROTATION_ANGLE_90:
2420                 ec->e.state.rot.preferred_rot = 90;
2421                 break;
2422              case TIZEN_ROTATION_ANGLE_180:
2423                 ec->e.state.rot.preferred_rot = 180;
2424                 break;
2425              case TIZEN_ROTATION_ANGLE_270:
2426                 ec->e.state.rot.preferred_rot = 270;
2427                 break;
2428              default:
2429                 break;
2430           }
2431
2432         if (_prev_preferred_rot != ec->e.state.rot.preferred_rot)
2433           ec->e.fetch.rot.need_rotation = EINA_TRUE;
2434
2435         EDBG(ec, "Fetch Preferred: preferred (prev %d cur %d)",
2436             _prev_preferred_rot, ec->e.state.rot.preferred_rot);
2437
2438         ec->e.fetch.rot.preferred_rot = 0;
2439      }
2440    if (ec->e.fetch.rot.available_rots)
2441      {
2442         Eina_Bool diff = EINA_FALSE;
2443         int *rots = NULL;
2444         unsigned int _prev_count = 0, count = 0, i = 0;
2445         int _prev_rots[4] = { -1, };
2446         uint32_t available_angles = 0;
2447
2448         if (ec->e.state.rot.available_rots)
2449           {
2450              memcpy(_prev_rots,
2451                     ec->e.state.rot.available_rots,
2452                     (sizeof(int) * ec->e.state.rot.count));
2453           }
2454
2455         _prev_count = ec->e.state.rot.count;
2456         ec->e.state.rot.count = 0;
2457
2458         /* check avilable_angles */
2459         if (rot->available_angles & TIZEN_ROTATION_ANGLE_0) count++;
2460         if (rot->available_angles & TIZEN_ROTATION_ANGLE_90) count++;
2461         if (rot->available_angles & TIZEN_ROTATION_ANGLE_180) count++;
2462         if (rot->available_angles & TIZEN_ROTATION_ANGLE_270) count++;
2463
2464         if (count != 0)
2465           rots = (int*)E_NEW(int, count);
2466
2467         if (!rots)
2468           {
2469              if (ec->e.state.rot.available_rots)
2470                {
2471                   /* restore previous rotation hints */
2472                   memcpy(ec->e.state.rot.available_rots, _prev_rots, (sizeof(int) * _prev_count));
2473                }
2474              goto end_fetch_rot;
2475           }
2476
2477         if (ec->e.state.rot.available_rots)
2478           E_FREE(ec->e.state.rot.available_rots);
2479
2480         available_angles = rot->available_angles;
2481
2482         if ((count > 0) && (rots))
2483           {
2484              for (i = 0; i < count; i++)
2485               {
2486                   if (available_angles & TIZEN_ROTATION_ANGLE_0)
2487                     {
2488                        rots[i] = 0;
2489                        available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_0;
2490                     }
2491                   else if (available_angles & TIZEN_ROTATION_ANGLE_90)
2492                     {
2493                        rots[i] = 90;
2494                        available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_90;
2495                     }
2496                   else if (available_angles & TIZEN_ROTATION_ANGLE_180)
2497                     {
2498                        rots[i] = 180;
2499                        available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_180;
2500                     }
2501                   else if (available_angles & TIZEN_ROTATION_ANGLE_270)
2502                     {
2503                        rots[i] = 270;
2504                        available_angles = available_angles & ~TIZEN_ROTATION_ANGLE_270;
2505                     }
2506                }
2507
2508              ec->e.state.rot.available_rots = rots;
2509              ec->e.state.rot.count = count;
2510
2511              if (_prev_count != count) diff = EINA_TRUE;
2512
2513              for (i = 0; i < count; i++)
2514                {
2515                   if ((!diff) && (_prev_rots[i] != rots[i]))
2516                     {
2517                        diff = EINA_TRUE;
2518                        break;
2519                     }
2520                }
2521            }
2522         /* check avilable_angles end*/
2523
2524         /* Print fetch information */
2525           {
2526              Eina_Strbuf *b = eina_strbuf_new();
2527
2528              EINF(ec, "Fetch Available");
2529              if (_prev_count > 0)
2530                {
2531                   for (i = 0; i < _prev_count; i++)
2532                     eina_strbuf_append_printf(b, "%d ", _prev_rots[i]);
2533                   INF("\tprev %s", eina_strbuf_string_get(b));
2534                   eina_strbuf_reset(b);
2535                }
2536
2537              for (i = 0; i < count; i++)
2538                eina_strbuf_append_printf(b, "%d ", rots[i]);
2539              INF("\tcur %s", eina_strbuf_string_get(b));
2540
2541              eina_strbuf_free(b);
2542           }
2543
2544         if (diff) ec->e.fetch.rot.need_rotation = EINA_TRUE;
2545         ec->e.fetch.rot.available_rots = 0;
2546      }
2547 end_fetch_rot:
2548
2549    rot->hint_fetch = 1;
2550    if ((ec->new_client) && (ec->e.state.rot.pending_show))
2551      {
2552         ec->e.state.rot.pending_show = 0;
2553         evas_object_show(ec->frame);
2554         if (!ec->changes.rotation)
2555           e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
2556      }
2557    else if ((evas_object_visible_get(ec->frame) && (ec->e.fetch.rot.need_rotation)))
2558      {
2559         DBG("Rotation Zone Set: Fetch Hint");
2560         _e_client_rotation_zone_set(ec->zone, NULL, NULL);
2561      }
2562
2563    if (ec->e.fetch.rot.need_rotation)
2564      ec->e.fetch.rot.need_rotation = EINA_FALSE;
2565 }
2566
2567 /* Occasionally, some client destroys only the xdg_surface and keeps the wl_surface.
2568  * In this case, E20 has the zombie ec for maintaining of this kind of client.
2569  * If the zombie ec is going to be alive again (it means that client tries to show window),
2570  * then the zombie ec has the unmap state on the E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER handler.
2571  * So fg_ec of rotation module can not be changed to activated ec even if it is shown on the screen.
2572  *
2573  * Thus, we need to use a new hook for changing to right fg_ec of rotation module in this case.
2574  * E_POL_VIS_HOOK_TYPE_FG_SET is good point to be called after E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER
2575  * hook and given ec has always mapped state.
2576  */
2577 static Eina_Bool
2578 _rot_hook_fg_set(void *d EINA_UNUSED, E_Client *ec)
2579 {
2580    Policy_Ext_Rotation *rot;
2581
2582    rot = eina_hash_find(rot_hash, &ec);
2583    if (!rot)
2584      return EINA_TRUE;
2585
2586    if (e_pixmap_type_get(ec->pixmap) == E_PIXMAP_TYPE_EXT_OBJECT)
2587      return EINA_TRUE;
2588
2589    if (!rot->hint_fetch)
2590      {
2591         /* need to fetch rotation hint. */
2592         ec->e.state.rot.pending_show = 1;
2593         EC_CHANGED(ec);
2594         return EINA_FALSE;
2595      }
2596
2597    if (ec->e.state.rot.pending_show)
2598      return EINA_FALSE;
2599
2600    if (e_policy_visibility_client_is_activity(ec))
2601      {
2602         EDBG(ec, "Check ec %x to set fg_ec", e_client_util_win_get(ec));
2603         if (_no_active_lockscreen_check(ec))
2604           {
2605              /* don't need to check visibility of given foreground ec
2606               * it will have E_VISIBILITY_UNOBSCURED soon
2607               */
2608              EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
2609              fg_ec = ec;
2610
2611              if (_camera_check(ec))
2612                _unlock_rot_for_fg_app(ec->zone);
2613              else
2614                _try_lock_rot_for_fg_app(ec->zone);
2615           }
2616      }
2617
2618    _e_client_rotation_zone_set(ec->zone, ec, NULL);
2619    if (ec->changes.rotation)
2620      {
2621         EDBG(ec, "Postpone show: ang %d", ec->e.state.rot.ang.next);
2622         e_pixmap_image_clear(ec->pixmap, 1);
2623         ec->e.state.rot.pending_show = 1;
2624         /* to be invoked 'eval_end' */
2625         EC_CHANGED(ec);
2626         return EINA_FALSE;
2627      }
2628
2629    return EINA_TRUE;
2630 }
2631
2632 static Eina_Bool
2633 _rot_intercept_hook_show_helper(void *d EINA_UNUSED, E_Client *ec)
2634 {
2635    Policy_Ext_Rotation *rot;
2636
2637    rot = eina_hash_find(rot_hash, &ec);
2638    if (!rot)
2639      return EINA_TRUE;
2640
2641    if (e_pixmap_type_get(ec->pixmap) == E_PIXMAP_TYPE_EXT_OBJECT)
2642      return EINA_TRUE;
2643
2644    if (!rot->hint_fetch)
2645      {
2646         /* need to fetch rotation hint. */
2647         ec->e.state.rot.pending_show = 1;
2648         EC_CHANGED(ec);
2649         return EINA_FALSE;
2650      }
2651
2652    if (ec->e.state.rot.pending_show)
2653      return EINA_FALSE;
2654
2655    if (e_policy_visibility_client_is_activity(ec))
2656      {
2657         EDBG(ec, "Check ec %x to set fg_ec", e_client_util_win_get(ec));
2658         if (_no_active_lockscreen_check(ec))
2659           {
2660              if (ec->visibility.obscured != E_VISIBILITY_FULLY_OBSCURED)
2661                {
2662                   EDBG(ec, "Set the fg_ec to %x", e_client_util_win_get(ec));
2663                   fg_ec = ec;
2664                }
2665
2666              if (_camera_check(ec))
2667                _unlock_rot_for_fg_app(ec->zone);
2668              else
2669                _try_lock_rot_for_fg_app(ec->zone);
2670           }
2671      }
2672
2673    _e_client_rotation_zone_set(ec->zone, ec, NULL);
2674    if (ec->changes.rotation)
2675      {
2676         EDBG(ec, "Postpone show: ang %d", ec->e.state.rot.ang.next);
2677         e_pixmap_image_clear(ec->pixmap, 1);
2678         ec->e.state.rot.pending_show = 1;
2679         /* to be invoked 'eval_end' */
2680         EC_CHANGED(ec);
2681         return EINA_FALSE;
2682      }
2683
2684     return EINA_TRUE;
2685 }
2686
2687 static Eina_Bool
2688 _rot_intercept_hook_hide(void *d EINA_UNUSED, E_Client *ec)
2689 {
2690    // TODO: Add VKBD Hide, VKBD Parent Hide routine.
2691    // clear pending_show, because this window is hidden now.
2692    ec->e.state.rot.pending_show = 0;
2693
2694    if (fg_ec == ec)
2695      {
2696         EDBG(ec, "Set the fg_ec to NULL");
2697         fg_ec = NULL;
2698
2699         if (_camera_check(ec))
2700           _try_lock_rot_for_fg_app(ec->zone);
2701      }
2702
2703    // for rotating ec in the force_update_list
2704    _e_client_rotation_zone_set(ec->zone, fg_ec, ec);
2705
2706    return EINA_TRUE;
2707 }
2708
2709 static Eina_Bool
2710 _rot_cb_idle_enterer(void *data EINA_UNUSED)
2711 {
2712    Eina_List *l;
2713    E_Client *ec;
2714    int n;
2715
2716    if (rot.cancel.state)
2717      {
2718         /* there is no border which supports window manager rotation */
2719         e_zone_rotation_update_cancel(rot.cancel.zone);
2720         rot.cancel.state = EINA_FALSE;
2721         rot.cancel.zone = NULL;
2722      }
2723
2724    if (rot.fetch)
2725      {
2726         n = eina_list_count(rot.list);
2727
2728         if (n == 1)
2729           {
2730              ec = eina_list_data_get(rot.list);
2731              if (ec->e.state.rot.nopending_render == 0)
2732                {
2733                   if (!rot.screen_lock)
2734                     {
2735                        ELOGF("ROTATION", "RENDERING pause", NULL);
2736
2737                        e_pixmap_image_clear(ec->pixmap, 1);
2738                        e_comp_canvas_norender_push();
2739                        rot.screen_lock = EINA_TRUE;
2740                     }
2741                }
2742              else
2743                {
2744                   if (rot.screen_lock)
2745                     {
2746                        ELOGF("ROTATION", "RENDERING resume", NULL);
2747                        e_comp_canvas_norender_pop();
2748                        rot.screen_lock = EINA_FALSE;
2749                     }
2750                }
2751           }
2752         // if there is windows over 2 that has to be rotated or is existed window needs resizing,
2753         // lock the screen.
2754         // but, DO NOT lock the screen when block state by E module
2755         else if (n > 1)
2756           {
2757              Eina_Bool rot_block = EINA_FALSE;
2758
2759              EINA_LIST_FOREACH(rot.list, l, ec)
2760                {
2761                   if (!ec->zone) continue;
2762                   if (ec->zone->rot.block.mod_count)
2763                     {
2764                        rot_block = EINA_TRUE;
2765                     }
2766                }
2767              if ((!rot.screen_lock) && (!rot_block))
2768                {
2769                   ELOGF("ROTATION", "RENDERING pause", NULL);
2770
2771                   EINA_LIST_FOREACH(rot.list, l, ec)
2772                      e_pixmap_image_clear(ec->pixmap, 1);
2773
2774                   e_comp_canvas_norender_push();
2775                   rot.screen_lock = EINA_TRUE;
2776                }
2777           }
2778         else
2779           {
2780              /* n == 0 */
2781              Eina_List *zlist = NULL;
2782              E_Zone *zone = NULL;
2783
2784              if (rot.async_list)
2785                {
2786                   EINA_LIST_FREE(rot.async_list, ec)
2787                     {
2788                        if (!eina_list_data_find(zlist, ec->zone))
2789                          zlist = eina_list_append(zlist, ec->zone);
2790                        _e_client_rotation_change_message_send(ec);
2791                     }
2792
2793                   EINA_LIST_FOREACH(zlist, l, zone)
2794                     e_zone_rotation_update_cancel(zone);
2795                   if (zlist)
2796                     eina_list_free(zlist);
2797                }
2798           }
2799
2800         rot.fetch = EINA_FALSE;
2801      }
2802
2803    return ECORE_CALLBACK_RENEW;
2804 }
2805
2806 Eina_Bool
2807 e_mod_rot_wl_init(void)
2808 {
2809    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, EINA_FALSE);
2810    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->wl.disp, EINA_FALSE);
2811
2812    if (!wl_global_create(e_comp_wl->wl.disp, &tizen_policy_ext_interface3, 3,
2813                          NULL, _e_tizen_policy_ext_bind_cb))
2814      {
2815         ERR("Could not add tizen_policy_ext to wayland globals: %m");
2816         return EINA_FALSE;
2817      }
2818
2819    rot_hash = eina_hash_pointer_new(_policy_ext_rotation_free);
2820
2821    E_LIST_HANDLER_APPEND(rot_cbs,     E_EVENT_ZONE_ROTATION_CHANGE_BEGIN, _rot_cb_zone_rotation_change_begin, NULL);
2822    E_LIST_HANDLER_APPEND(rot_cbs,     E_EVENT_CLIENT_BUFFER_CHANGE,       _rot_cb_buffer_change,              NULL);
2823    E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_NEW_CLIENT,           _rot_hook_new_client,               NULL);
2824    E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_DEL,                  _rot_hook_client_del,               NULL);
2825    E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_EVAL_END,             _rot_hook_eval_end,                 NULL);
2826    E_CLIENT_HOOK_APPEND(rot_ec_hooks, E_CLIENT_HOOK_EVAL_FETCH,           _rot_hook_eval_fetch,               NULL);
2827    E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(rot_obj_hooks, E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER, _rot_intercept_hook_show_helper, NULL);
2828    E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(rot_obj_hooks, E_COMP_OBJECT_INTERCEPT_HOOK_HIDE,        _rot_intercept_hook_hide,        NULL);
2829    E_COMP_WL_HOOK_APPEND(wl_hooks,                    E_COMP_WL_HOOK_BUFFER_CHANGE,             _rot_cb_wl_buffer_change,        NULL);
2830
2831    E_Pol_Vis_Hook *h = e_policy_visibility_hook_add(E_POL_VIS_HOOK_TYPE_FG_SET, _rot_hook_fg_set, NULL);
2832    pol_vis_hooks = eina_list_append(pol_vis_hooks, h);
2833
2834    rot_idle_enterer = ecore_idle_enterer_add(_rot_cb_idle_enterer, NULL);
2835
2836    return EINA_TRUE;
2837 }
2838
2839 void
2840 e_mod_rot_wl_shutdown(void)
2841 {
2842    E_FREE_FUNC(rot_hash, eina_hash_free);
2843    E_FREE_FUNC(rot.force_update_list, eina_list_free);
2844
2845    E_FREE_LIST(pol_vis_hooks, e_policy_visibility_hook_del);
2846    E_FREE_LIST(wl_hooks, e_comp_wl_hook_del);
2847    E_FREE_LIST(rot_ec_hooks, e_client_hook_del);
2848    E_FREE_LIST(rot_cbs, ecore_event_handler_del);
2849    E_FREE_LIST(rot_obj_hooks, e_comp_object_intercept_hook_del);
2850
2851    if (rot_idle_enterer)
2852      {
2853          ecore_idle_enterer_del(rot_idle_enterer);
2854          rot_idle_enterer = NULL;
2855      }
2856 }
2857
2858 EINTERN void
2859 e_mod_pol_rotation_force_update_add(E_Zone *zone EINA_UNUSED, E_Client *ec)
2860 {
2861    rot.force_update_list = eina_list_append(rot.force_update_list, ec);
2862 }
2863
2864 EINTERN void
2865 e_mod_pol_rotation_force_update_del(E_Zone *zone EINA_UNUSED, E_Client *ec)
2866 {
2867    rot.force_update_list = eina_list_remove(rot.force_update_list, ec);
2868 }