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