the repository of RSA merge with private repository.
[platform/core/uifw/e17.git] / src / bin / e_border.c
index c94f0c8..551b461 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is a modified version of BSD licensed file and
- * licensed under the Flora License, Version 1.0 (the License);
+ * licensed under the Flora License, Version 1.1 (the License);
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
@@ -149,11 +149,14 @@ static Eina_Bool _e_border_cb_desk_window_profile_change(void *data,
                                                          void *ev);
 #endif
 #ifdef _F_ZONE_WINDOW_ROTATION_
-static Eina_Bool _e_border_cb_zone_rotation_change(void *data,
-                                                   int   ev_type,
-                                                   void *ev);
+static Eina_Bool _e_border_cb_zone_rotation_change_begin(void *data,
+                                                         int   ev_type,
+                                                         void *ev);
+static void _e_border_cb_rotation_sync_job(void *data);
+static void _e_border_cb_rotation_async_job(void *data);
 static Eina_Bool _e_border_rotation_change_prepare_timeout(void *data);
 static void      _e_border_rotation_change_request(E_Zone *zone);
+static void      _e_border_rotation_list_flush(Eina_List *list, Eina_Bool flush);
 static Eina_Bool _e_border_rotation_change_done_timeout(void *data);
 static void      _e_border_rotation_change_done(void);
 static Eina_Bool _e_border_rotation_geom_get(E_Border  *bd,
@@ -164,14 +167,12 @@ static Eina_Bool _e_border_rotation_geom_get(E_Border  *bd,
                                              int       *w,
                                              int       *h,
                                              Eina_Bool *move);
-static Eina_Bool _e_border_rotation_list_add(E_Zone *zone, Eina_Bool without_vkbd);
 static void      _e_border_rotation_list_remove(E_Border *bd);
-static Eina_Bool _e_border_rotation_check(E_Border *bd);
-static Eina_Bool _e_border_rotation_zone_check(E_Zone *zone);
-static Eina_Bool _e_border_rotation_border_check(E_Border *bd, int ang);
-static Eina_Bool _e_border_rotation_zone_vkbd_check(E_Zone *zone);
-static Eina_Bool _e_border_rotation_vkbd_transient_for_check(E_Border *bd);
-static Eina_Bool _e_border_rotation_transient_for_check(E_Border *bd, int ang);
+static Eina_Bool _e_border_rotation_pre_resize(E_Border *bd, int rotation, int *x, int *y, int *w, int *h);
+static int       _e_border_rotation_angle_get(E_Border *bd);
+static Eina_Bool _e_border_rotation_zone_set(E_Zone *zone);
+static Eina_Bool _e_border_rotatable_check(E_Border *bd, int ang);
+static Eina_Bool _e_border_is_vkbd(E_Border *bd);
 static Eina_Bool _e_border_cb_window_configure(void *data,
                                                int   ev_type,
                                                void *ev);
@@ -239,8 +240,13 @@ static void      _e_border_event_border_fullscreen_free(void *data,
 static void      _e_border_event_border_unfullscreen_free(void *data,
                                                           void *ev);
 #ifdef _F_ZONE_WINDOW_ROTATION_
-static void      _e_border_event_border_rotation_free(void *data,
-                                                      void *ev);
+static void      _e_border_event_border_rotation_change_begin_free(void *data,
+                                                                   void *ev);
+static void      _e_border_event_border_rotation_change_cancel_free(void *data,
+                                                                    void *ev);
+static void      _e_border_event_border_rotation_change_end_free(void *data,
+                                                                 void *ev);
+static void      _e_border_event_border_rotation_change_begin_send(E_Border *bd);
 #endif
 
 static void      _e_border_zone_update(E_Border *bd);
@@ -320,10 +326,13 @@ typedef struct _E_Border_Rotation_Info E_Border_Rotation_Info;
 struct _E_Border_Rotation
 {
    Eina_List     *list;
+   Eina_List     *async_list;
 
    Eina_Bool      wait_prepare_done;
    Ecore_Timer   *prepare_timer;
    Ecore_Timer   *done_timer;
+   Ecore_Job     *sync_job;
+   Ecore_Job     *async_job;
 
    Ecore_X_Window vkbd_ctrl_win;
    E_Border      *vkbd;
@@ -353,9 +362,12 @@ struct _E_Border_Rotation_Info
 static E_Border_Rotation rot =
 {
    NULL,
+   NULL,
    EINA_FALSE,
    NULL,
    NULL,
+   NULL,
+   NULL,
    0,
    NULL,
    NULL,
@@ -391,7 +403,10 @@ EAPI int E_EVENT_BORDER_PROPERTY = 0;
 EAPI int E_EVENT_BORDER_FULLSCREEN = 0;
 EAPI int E_EVENT_BORDER_UNFULLSCREEN = 0;
 #ifdef _F_ZONE_WINDOW_ROTATION_
-EAPI int E_EVENT_BORDER_ROTATION = 0;
+EAPI int E_EVENT_BORDER_ROTATION = 0; /* deprecated */
+EAPI int E_EVENT_BORDER_ROTATION_CHANGE_BEGIN = 0;
+EAPI int E_EVENT_BORDER_ROTATION_CHANGE_CANCEL = 0;
+EAPI int E_EVENT_BORDER_ROTATION_CHANGE_END = 0;
 #endif
 
 #define GRAV_SET(bd, grav)                                \
@@ -469,7 +484,7 @@ e_border_init(void)
    handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_DESK_WINDOW_PROFILE_CHANGE, _e_border_cb_desk_window_profile_change, NULL));
 #endif
 #ifdef _F_ZONE_WINDOW_ROTATION_
-   handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_ZONE_ROTATION_CHANGE, _e_border_cb_zone_rotation_change, NULL));
+   handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN, _e_border_cb_zone_rotation_change_begin, NULL));
 #endif
 
    if (!borders_hash) borders_hash = eina_hash_string_superfast_new(NULL);
@@ -495,7 +510,10 @@ e_border_init(void)
    E_EVENT_BORDER_FULLSCREEN = ecore_event_type_new();
    E_EVENT_BORDER_UNFULLSCREEN = ecore_event_type_new();
 #ifdef _F_ZONE_WINDOW_ROTATION_
-   E_EVENT_BORDER_ROTATION = ecore_event_type_new();
+   E_EVENT_BORDER_ROTATION = ecore_event_type_new(); /* deprecated */
+   E_EVENT_BORDER_ROTATION_CHANGE_BEGIN = ecore_event_type_new();
+   E_EVENT_BORDER_ROTATION_CHANGE_CANCEL = ecore_event_type_new();
+   E_EVENT_BORDER_ROTATION_CHANGE_END = ecore_event_type_new();
 #endif
 
 //   e_init_undone();
@@ -868,6 +886,11 @@ e_border_new(E_Container   *con,
    bd->changed = 1;
 #ifdef _F_ZONE_WINDOW_ROTATION_
    bd->client.e.state.rot.preferred_rot = -1;
+   bd->client.e.state.rot.type = E_BORDER_ROTATION_TYPE_NORMAL;
+   bd->client.e.state.rot.changes = -1;
+   bd->client.e.state.rot.pending_show = 0;
+   bd->client.e.state.rot.curr = 0;
+   bd->client.e.state.rot.prev = 0;
 #endif
 
 //   bd->zone = e_zone_current_get(con);
@@ -1315,7 +1338,13 @@ _e_border_vkbd_hide(E_Border *bd)
    rot.vkbd_hide_timer = NULL;
    if ((bd) && ((E_OBJECT(bd)->type) == (E_BORDER_TYPE)))
      {
+        ELB(ELBT_BD, "HIDE VKBD", bd->client.win);
         e_border_hide(bd, 0);
+        if (!e_object_is_del(E_OBJECT(bd)))
+          {
+             ELB(ELBT_BD, "DEL VKBD", bd->client.win);
+             e_object_del(E_OBJECT(bd));
+          }
         rot.vkbd_hide_timer = ecore_timer_add(0.03f, _e_border_vkbd_hide_timeout, bd);
      }
 }
@@ -1357,6 +1386,21 @@ e_border_show(E_Border *bd)
    E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
    if (bd->visible) return;
 #ifdef _F_ZONE_WINDOW_ROTATION_
+   // newly created window that has to be rotated will be show after rotation done.
+   // so, skip at this time. it will be called again after GETTING ROT_DONE.
+   if ((bd->new_client) &&
+       (bd->client.e.state.rot.changes != -1))
+     {
+        // if this window is in withdrawn state, show this window right now.
+        // that's because the window in withdrawn state can't render its canvas.
+        // eventually, this window will not send the message of rotation done,
+        // even if e17 request to rotation this window.
+        if (bd->client.icccm.state != ECORE_X_WINDOW_STATE_HINT_NORMAL)
+          e_hints_window_visible_set(bd);
+
+        bd->client.e.state.rot.pending_show = 1;
+        return;
+     }
    if ((e_config->wm_win_rotation) &&
        (rot.vkbd_ctrl_win) && (rot.vkbd) &&
        (bd == rot.vkbd) &&
@@ -1398,7 +1442,8 @@ e_border_show(E_Border *bd)
         (bd->client.e.state.rot.app_set)))
      {
         ELB(ELBT_ROT, "CHECK", bd->client.win);
-        _e_border_rotation_check(bd);
+        int rotation = _e_border_rotation_angle_get(bd);
+        if (rotation != -1) e_border_rotation_set(bd, rotation);
      }
 #endif
 }
@@ -1498,7 +1543,8 @@ e_border_hide(E_Border *bd,
 
    if (!bd->need_reparent)
      {
-        if (bd->focused)
+        if ((bd->focused) ||
+            (e_grabinput_last_focus_win_get() == bd->client.win))
           {
              e_border_focus_set(bd, 0, 1);
              if (manage != 2)
@@ -1562,6 +1608,10 @@ e_border_hide(E_Border *bd,
 send_event:
    if (!stopping)
      {
+#ifdef _F_ZONE_WINDOW_ROTATION_
+        _e_border_rotation_list_remove(bd);
+#endif
+
         E_Event_Border_Hide *ev;
 
         ev = E_NEW(E_Event_Border_Hide, 1);
@@ -3676,17 +3726,110 @@ static Eina_Bool
 _e_border_uniconify_timeout(void *data)
 {
    E_Border *bd;
+   E_Border *child_bd;
+
    bd = data;
 
    if (!e_object_is_del(E_OBJECT(bd)))
      {
+        ELB(ELBT_BD, "TIMEOUT UNICONIFY_APPROVE", bd->client.win);
         bd->client.e.state.deiconify_approve.render_done = 1;
-        e_border_uniconify(bd);
+        if (bd->client.e.state.deiconify_approve.req_list)
+          {
+             EINA_LIST_FREE(bd->client.e.state.deiconify_approve.req_list, child_bd)
+               {
+                  child_bd->client.e.state.deiconify_approve.render_done = 1;
+                  child_bd->client.e.state.deiconify_approve.ancestor = NULL;
+               }
+          }
+        bd->client.e.state.deiconify_approve.req_list = NULL;
         bd->client.e.state.deiconify_approve.wait_timer = NULL;
+        e_border_uniconify(bd);
      }
 
    return ECORE_CALLBACK_CANCEL;
 }
+
+static void
+_e_border_deiconify_approve_send(E_Border *bd, E_Border *bd_ancestor)
+{
+   if (!bd || !bd_ancestor) return;
+
+   if (e_config->deiconify_approve)
+     {
+        if (e_config->transient.iconify)
+          {
+             Eina_List *l;
+             E_Border *child;
+             Eina_List *list = _e_border_sub_borders_new(bd);
+             EINA_LIST_FOREACH(list, l, child)
+               {
+#ifdef _F_ZONE_WINDOW_ROTATION_
+                  if ((e_config->wm_win_rotation) &&
+                      ((child->client.e.state.rot.support) ||
+                       (child->client.e.state.rot.app_set)))
+                    {
+                       ELB(ELBT_ROT, "CHECK_DEICONIFY CHILD", child->client.win);
+                       int rotation = _e_border_rotation_angle_get(bd);
+                       if (rotation != -1) e_border_rotation_set(bd, rotation);
+                    }
+#endif
+                  _e_border_deiconify_approve_send(child, bd_ancestor);
+                  if (child->client.e.state.deiconify_approve.support)
+                    {
+                       ELBF(ELBT_BD, 0, child->client.win,
+                            "SEND DEICONIFY_APPROVE. ancestor:%x", bd_ancestor->client.win);
+
+                       ecore_x_client_message32_send(child->client.win,
+                                                     ECORE_X_ATOM_E_DEICONIFY_APPROVE,
+                                                     ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+                                                     child->client.win, 0, 0, 0, 0);
+                       child->client.e.state.deiconify_approve.ancestor = bd_ancestor;
+                       bd_ancestor->client.e.state.deiconify_approve.req_list = eina_list_append(bd_ancestor->client.e.state.deiconify_approve.req_list, child);
+                    }
+               }
+             eina_list_free(list);
+          }
+     }
+}
+
+static void
+_e_border_deiconify_approve_send_all_transient(E_Border *bd)
+{
+   E_Border *bd_ancestor;
+   bd_ancestor = bd;
+
+   if (e_config->deiconify_approve)
+     {
+#ifdef _F_ZONE_WINDOW_ROTATION_
+        if ((e_config->wm_win_rotation) &&
+            ((bd->client.e.state.rot.support) ||
+             (bd->client.e.state.rot.app_set)))
+          {
+             ELB(ELBT_ROT, "CHECK_DEICONIFY", bd->client.win);
+             int rotation = _e_border_rotation_angle_get(bd);
+             if (rotation != -1) e_border_rotation_set(bd, rotation);
+          }
+#endif
+
+        if (e_config->transient.iconify)
+          {
+             _e_border_deiconify_approve_send(bd, bd_ancestor);
+          }
+
+        if (bd->client.e.state.deiconify_approve.support)
+          {
+             ELBF(ELBT_BD, 0, bd->client.win,
+                  "SEND DEICONIFY_APPROVE.. ancestor:%x", bd_ancestor->client.win);
+
+             ecore_x_client_message32_send(bd->client.win,
+                                           ECORE_X_ATOM_E_DEICONIFY_APPROVE,
+                                           ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+                                           bd->client.win, 0, 0, 0, 0);
+             bd->client.e.state.deiconify_approve.wait_timer = ecore_timer_add(e_config->deiconify_timeout, _e_border_uniconify_timeout, bd);
+          }
+     }
+}
 #endif
 
 EAPI void
@@ -3704,18 +3847,18 @@ e_border_uniconify(E_Border *bd)
      {
         if (bd->client.e.state.deiconify_approve.support)
           {
-             if (bd->client.e.state.deiconify_approve.wait_timer) return;
+             if (bd->client.e.state.deiconify_approve.wait_timer)
+               {
+                  ELB(ELBT_BD, "DEICONIFY_APPROVE WAIT_TIMER is already running", bd->client.win);
+                  return;
+               }
              if (bd->client.e.state.deiconify_approve.render_done == 0)
                {
-                  ecore_x_client_message32_send(bd->client.win,
-                                                ECORE_X_ATOM_E_DEICONIFY_APPROVE,
-                                                ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
-                                                bd->client.win, 0, 0, 0, 0);
-                  bd->client.e.state.deiconify_approve.wait_timer = ecore_timer_add(e_config->deiconify_timeout, _e_border_uniconify_timeout, bd);
+                  ELB(ELBT_BD, "DEICONIFY_APPROVE to all transient", bd->client.win);
+                  _e_border_deiconify_approve_send_all_transient(bd);
                   return;
                }
           }
-
         bd->client.e.state.deiconify_approve.render_done = 0;
      }
 #endif
@@ -4184,14 +4327,14 @@ e_border_idler_before(void)
                        if (m) zone = e_util_zone_current_get(m);
                        if ((zone) && (rot.wait_prepare_done))
                          {
-                            if (_e_border_rotation_list_add(zone, EINA_FALSE))
-                              _e_border_rotation_change_request(zone);
-                            else
+                            if (rot.list)
                               {
+                                 _e_border_rotation_change_request(zone);
                                  if (rot.prepare_timer)
                                    ecore_timer_del(rot.prepare_timer);
                                  rot.prepare_timer = NULL;
                                  rot.wait_prepare_done = EINA_FALSE;
+
                               }
                          }
                     }
@@ -5639,14 +5782,6 @@ _e_border_del(E_Border *bd)
         ecore_event_add(E_EVENT_BORDER_REMOVE, ev, _e_border_event_border_remove_free, NULL);
      }
 
-#ifdef _F_DEICONIFY_APPROVE_
-   if (bd->client.e.state.deiconify_approve.wait_timer)
-     {
-        ecore_timer_del(bd->client.e.state.deiconify_approve.wait_timer);
-        bd->client.e.state.deiconify_approve.wait_timer = NULL;
-     }
-#endif
-
    if (bd->parent)
      {
         bd->parent->transients = eina_list_remove(bd->parent->transients, bd);
@@ -5665,6 +5800,61 @@ _e_border_del(E_Border *bd)
         child->parent = NULL;
      }
 
+#ifdef _F_DEICONIFY_APPROVE_
+   bd->client.e.state.deiconify_approve.render_done = 0;
+
+   E_Border *ancestor_bd;
+   ancestor_bd = bd->client.e.state.deiconify_approve.ancestor;
+   if ((ancestor_bd) &&
+       (!e_object_is_del(E_OBJECT(ancestor_bd))))
+     {
+        ancestor_bd->client.e.state.deiconify_approve.req_list = eina_list_remove(ancestor_bd->client.e.state.deiconify_approve.req_list, bd);
+        bd->client.e.state.deiconify_approve.ancestor = NULL;
+
+        if ((ancestor_bd->client.e.state.deiconify_approve.req_list == NULL) &&
+            (ancestor_bd->client.e.state.deiconify_approve.render_done))
+          {
+             if (ancestor_bd->client.e.state.deiconify_approve.wait_timer)
+               {
+                  ecore_timer_del(ancestor_bd->client.e.state.deiconify_approve.wait_timer);
+                  ancestor_bd->client.e.state.deiconify_approve.wait_timer = NULL;
+                  e_border_uniconify(ancestor_bd);
+               }
+          }
+     }
+
+   if (bd->client.e.state.deiconify_approve.wait_timer)
+     {
+        ecore_timer_del(bd->client.e.state.deiconify_approve.wait_timer);
+        bd->client.e.state.deiconify_approve.wait_timer = NULL;
+     }
+
+   if (bd->client.e.state.deiconify_approve.req_list)
+     {
+        EINA_LIST_FREE(bd->client.e.state.deiconify_approve.req_list, child)
+          {
+             child->client.e.state.deiconify_approve.render_done = 0;
+             child->client.e.state.deiconify_approve.ancestor = NULL;
+          }
+     }
+#endif
+
+#ifdef _F_ZONE_WINDOW_ROTATION_
+   if (rot.list) _e_border_rotation_list_remove(bd);
+   if (rot.async_list)
+     {
+        Eina_List *l;
+        E_Border_Rotation_Info *info = NULL;
+
+        EINA_LIST_FOREACH(rot.async_list, l, info)
+           if (info->bd == bd)
+             {
+                rot.async_list = eina_list_remove(rot.async_list, info);
+                E_FREE(info);
+             }
+     }
+#endif
+
    if (bd->leader)
      {
         bd->leader->group = eina_list_remove(bd->leader->group, bd);
@@ -5702,11 +5892,22 @@ _e_border_cb_window_show_request(void *data  __UNUSED__,
                                  void       *ev)
 {
    E_Border *bd;
+   E_Container *con;
    Ecore_X_Event_Window_Show_Request *e;
 
    e = ev;
    bd = e_border_find_by_client_window(e->win);
    if (!bd) return ECORE_CALLBACK_PASS_ON;
+
+   if ((e_config->wm_win_rotation) &&
+       (rot.vkbd_ctrl_win) && (rot.vkbd) &&
+       (bd == rot.vkbd) &&
+       (rot.vkbd_hide_prepare_timer))
+     {
+        con = bd->zone->container;
+        bd = e_border_new(con, e->win, 0, 0);
+     }
+
    if (bd->iconic)
      {
         if (!bd->lock_client_iconify)
@@ -5733,6 +5934,27 @@ _e_border_cb_window_destroy(void *data  __UNUSED__,
    e = ev;
    bd = e_border_find_by_client_window(e->win);
    if (!bd) return ECORE_CALLBACK_PASS_ON;
+   ELB(ELBT_BD, "X_WIN_DEL", bd->client.win);
+#ifdef _F_ZONE_WINDOW_ROTATION_
+   if (e_config->wm_win_rotation)
+     {
+        if (bd->client.vkbd.win_type == E_VIRTUAL_KEYBOARD_WINDOW_TYPE_KEYPAD)
+          {
+             ELB(ELBT_BD, "X_DEL_NOTIFY", bd->client.win);
+             if (!rot.vkbd_hide_prepare_timer)
+               {
+                  ELB(ELBT_BD, "HIDE VKBD", bd->client.win);
+                  e_border_hide(bd, 0);
+                  if (!rot.vkbd_hide_prepare_timer)
+                    {
+                       ELB(ELBT_BD, "DEL VKBD", bd->client.win);
+                       e_object_del(E_OBJECT(bd));
+                    }
+               }
+             return ECORE_CALLBACK_PASS_ON;
+          }
+     }
+#endif
    e_border_hide(bd, 0);
    e_object_del(E_OBJECT(bd));
    return ECORE_CALLBACK_PASS_ON;
@@ -5763,7 +5985,16 @@ _e_border_cb_window_hide(void *data  __UNUSED__,
      }
    if (!bd) bd = e_border_find_by_client_window(e->win);
 //   printf("  bd = %p\n", bd);
-   if (!bd) return ECORE_CALLBACK_PASS_ON;
+   if (!bd)
+     {
+        if (ecore_x_window_visible_get(e->win))
+          {
+             ELB(ELBT_BD, "FORCE UNMAP client window", e->win);
+             ecore_x_window_hide(e->win);
+          }
+        return ECORE_CALLBACK_PASS_ON;
+     }
+
 //   printf("  bd->ignore_first_unmap = %i\n", bd->ignore_first_unmap);
    if (bd->ignore_first_unmap > 0)
      {
@@ -5801,6 +6032,27 @@ _e_border_cb_window_hide(void *data  __UNUSED__,
              bd->visible = 1;
           }
 #endif
+
+#ifdef _F_ZONE_WINDOW_ROTATION_
+        if (e_config->wm_win_rotation)
+          {
+             if (bd->client.vkbd.win_type == E_VIRTUAL_KEYBOARD_WINDOW_TYPE_KEYPAD)
+               {
+                  ELB(ELBT_BD, "X_UNMAP_NOTIFY", bd->client.win);
+                  if (!rot.vkbd_hide_prepare_timer)
+                    {
+                       ELB(ELBT_BD, "HIDE VKBD", bd->client.win);
+                       e_border_hide(bd, 0);
+                       if (!rot.vkbd_hide_prepare_timer)
+                         {
+                            ELB(ELBT_BD, "DEL VKBD", bd->client.win);
+                            e_object_del(E_OBJECT(bd));
+                         }
+                    }
+                  return ECORE_CALLBACK_PASS_ON;
+               }
+          }
+#endif
         e_border_hide(bd, 0);
         e_object_del(E_OBJECT(bd));
      }
@@ -6721,13 +6973,38 @@ _e_border_cb_client_message(void *data  __UNUSED__,
              if (bd->client.e.state.deiconify_approve.support)
                {
                   if (e->data.l[1] != 1) return ECORE_CALLBACK_PASS_ON;
-                  if (bd->client.e.state.deiconify_approve.wait_timer)
+                  bd->client.e.state.deiconify_approve.render_done = 1;
+
+                  E_Border *ancestor_bd;
+                  ancestor_bd = bd->client.e.state.deiconify_approve.ancestor;
+                  if (ancestor_bd)
                     {
-                       ecore_timer_del(bd->client.e.state.deiconify_approve.wait_timer);
-                       bd->client.e.state.deiconify_approve.wait_timer = NULL;
+                       ancestor_bd->client.e.state.deiconify_approve.req_list = eina_list_remove(ancestor_bd->client.e.state.deiconify_approve.req_list, bd);
+                       bd->client.e.state.deiconify_approve.ancestor = NULL;
+                    }
+                  else
+                    {
+                       ancestor_bd = bd;
+                    }
+
+                  ELBF(ELBT_BD, 0, bd->client.win,
+                       "RECEIVE DEICONIFY_APPROVE.. ancestor:%x", ancestor_bd->client.win);
+
+                  if ((ancestor_bd->client.e.state.deiconify_approve.req_list == NULL) &&
+                      (ancestor_bd->client.e.state.deiconify_approve.render_done))
+                    {
+                       if (ancestor_bd->client.e.state.deiconify_approve.wait_timer)
+                         {
+                            ecore_timer_del(ancestor_bd->client.e.state.deiconify_approve.wait_timer);
+                            ancestor_bd->client.e.state.deiconify_approve.wait_timer = NULL;
+                            e_border_uniconify(ancestor_bd);
+                         }
+                       else
+                         {
+                            ELB(ELBT_BD, "Unset DEICONIFY_APPROVE render_done", ancestor_bd->client.win);
+                            ancestor_bd->client.e.state.deiconify_approve.render_done = 0;
+                         }
                     }
-                  bd->client.e.state.deiconify_approve.render_done = 1;
-                  e_border_uniconify(bd);
                }
           }
         return ECORE_CALLBACK_PASS_ON;
@@ -6775,7 +7052,15 @@ _e_border_cb_client_message(void *data  __UNUSED__,
         if (e_config->wm_win_rotation)
           {
              if ((int)e->data.l[1] == bd->client.e.state.rot.curr)
-               _e_border_rotation_list_remove(bd);
+               {
+                  _e_border_rotation_list_remove(bd);
+                  if (bd->client.e.state.rot.pending_show)
+                    {
+                       ELB(ELBT_BD, "SHOW_BD (PEND)", bd->client.win);
+                       e_border_show(bd);
+                       bd->client.e.state.rot.pending_show = 0;
+                    }
+               }
           }
      }
 #endif
@@ -7653,61 +7938,71 @@ _e_border_cb_desk_window_profile_change(void *data  __UNUSED__,
 
 #ifdef _F_ZONE_WINDOW_ROTATION_
 static Eina_Bool
-_e_border_cb_zone_rotation_change(void *data  __UNUSED__,
-                                  int ev_type __UNUSED__,
-                                  void       *ev)
+_e_border_cb_zone_rotation_change_begin(void *data  __UNUSED__,
+                                        int ev_type __UNUSED__,
+                                        void       *ev)
 {
-   E_Event_Zone_Rotation_Change *e = ev;
-   Eina_Bool res = EINA_FALSE;
+   E_Event_Zone_Rotation_Change_Begin *e = ev;
 
    if (!e_config->wm_win_rotation) return ECORE_CALLBACK_PASS_ON;
    if ((!e) || (!e->zone)) return ECORE_CALLBACK_PASS_ON;
 
-   res = _e_border_rotation_zone_check(e->zone);
-   ELBF(ELBT_ROT, 0, e->zone->id, "ZONE ROT CHECK: result:%d (%d)", res, e->zone->rot.curr);
-   if (res)
+   if (!_e_border_rotation_zone_set(e->zone))
      {
-        e_manager_comp_screen_lock(e_manager_current_get());
-        res = _e_border_rotation_zone_vkbd_check(e->zone);
-        ELBF(ELBT_ROT, 0, e->zone->id, "ZONE ROT CHECK: vkbd result:%d (%d)", res, e->zone->rot.curr);
-        if (res)
-          {
-             res = _e_border_rotation_transient_for_check(rot.vkbd,
-                                                          e->zone->rot.curr);
-             ELBF(ELBT_ROT, 0, e->zone->id, "ZONE ROT CHECK: vkbd transient_for result:%d (%d)", res, e->zone->rot.curr);
-          }
+        /* there is no border which supports window manager rotation */
+        e_zone_rotation_update_cancel(e->zone);
+     }
+   return ECORE_CALLBACK_PASS_ON;
+}
 
-        if (res)
-          {
-             if (rot.prepare_timer)
-               ecore_timer_del(rot.prepare_timer);
-             rot.prepare_timer = NULL;
+static void
+_e_border_cb_rotation_sync_job(void *data)
+{
+   E_Zone *zone = data;
+   Eina_List *l;
+   E_Border_Rotation_Info *info = NULL;
 
-             if (rot.done_timer)
-               ecore_timer_del(rot.done_timer);
-             rot.done_timer = NULL;
+   ELB(ELBT_ROT, "DO ROTATION SYNC_JOB", zone->id);
 
-             ELB(ELBT_ROT, "SEND ROT_CHANGE_PREPARE", rot.vkbd_ctrl_win);
-             ecore_x_e_window_rotation_change_prepare_send(rot.vkbd_ctrl_win,
-                                                           e->zone->rot.curr,
-                                                           EINA_FALSE, 1, 1);
-             rot.prepare_timer = ecore_timer_add(4.0f,
-                                                 _e_border_rotation_change_prepare_timeout,
-                                                 NULL);
-             rot.wait_prepare_done = EINA_TRUE;
-          }
-        else
+   if (rot.list)
+     {
+        EINA_LIST_FOREACH(rot.list, l, info)
+           _e_border_hook_call(E_BORDER_HOOK_ROTATION_LIST_ADD, info->bd);
+        if (!rot.wait_prepare_done)
           {
-             _e_border_rotation_list_add(e->zone, EINA_TRUE);
-             _e_border_rotation_change_request(e->zone);
+             _e_border_rotation_change_request(zone);
           }
      }
-   else
+
+   // clear job
+   if (rot.sync_job)
      {
-        /* there is no border which supports window manager rotation */
-        e_zone_rotation_update_cancel(e->zone);
+        ELB(ELBT_ROT, "DEL SYNC_JOB", zone->id);
+        ecore_job_del(rot.sync_job);
+        rot.sync_job = NULL;
+     }
+}
+
+static void
+_e_border_cb_rotation_async_job(void *data)
+{
+   E_Zone *zone = data;
+
+   if (rot.list) goto end;
+
+   ELB(ELBT_ROT, "FLUSH ASYNC LIST TO ROT_CHANGE_REQ", zone->id);
+
+   _e_border_rotation_list_flush(rot.async_list, EINA_TRUE);
+   rot.async_list = NULL;
+
+end:
+   // clear async job
+   if (rot.async_job)
+     {
+        ELB(ELBT_ROT, "DEL ASYNC_JOB", zone->id);
+        ecore_job_del(rot.async_job);
+        rot.async_job = NULL;
      }
-   return ECORE_CALLBACK_PASS_ON;
 }
 
 static Eina_Bool
@@ -7718,56 +8013,101 @@ _e_border_rotation_change_prepare_timeout(void *data)
 
    ELB(ELBT_ROT, "TIMEOUT ROT_CHANGE_PREPARE", 0);
 
-   if ((rot.wait_prepare_done) &&
-       (zone) &&
-       (_e_border_rotation_list_add(zone, EINA_FALSE)))
-     {
-        _e_border_rotation_change_request(zone);
-     }
-   else
+   if ((zone) && (rot.wait_prepare_done))
      {
-        if (rot.prepare_timer)
-          ecore_timer_del(rot.prepare_timer);
-        rot.prepare_timer = NULL;
-        rot.wait_prepare_done = EINA_FALSE;
+        if (rot.list)
+          {
+             _e_border_rotation_change_request(zone);
+             if (rot.prepare_timer)
+               ecore_timer_del(rot.prepare_timer);
+             rot.prepare_timer = NULL;
+             rot.wait_prepare_done = EINA_FALSE;
+          }
      }
    return ECORE_CALLBACK_CANCEL;
 }
 
 static void
-_e_border_rotation_change_request(E_Zone *zone __UNUSED__)
+_e_border_rotation_change_request(E_Zone *zone)
 {
-   Eina_List *l = NULL;
-   E_Border_Rotation_Info *info = NULL;
-
    if (!e_config->wm_win_rotation) return;
+   if (!rot.list) return;
+   if (eina_list_count(rot.list) <= 0) return;
+   if (zone->rot.block_count) return;
+
    if (rot.prepare_timer) ecore_timer_del(rot.prepare_timer);
    rot.prepare_timer = NULL;
    rot.wait_prepare_done = EINA_FALSE;
 
-   EINA_LIST_FOREACH(rot.list, l, info)
+   _e_border_rotation_list_flush(rot.list, EINA_FALSE);
+
+   if (rot.done_timer)
+     ecore_timer_del(rot.done_timer);
+   ELB(ELBT_ROT, "ADD TIMEOUT ROT_DONE", zone->id);
+   rot.done_timer = ecore_timer_add(5.0f,
+                                    _e_border_rotation_change_done_timeout,
+                                    NULL);
+}
+
+static void
+_e_border_rotation_list_flush(Eina_List *list, Eina_Bool flush)
+{
+   Eina_List *l;
+   E_Border_Rotation_Info *info =NULL;
+   int x, y, w, h;
+
+   EINA_LIST_FOREACH (list, l, info)
      {
+        if (!info->bd) continue;
+        if ((info->bd->client.e.state.rot.wait_for_done) &&
+            (info->bd->client.e.state.rot.wait_done_ang == info->ang)) continue;
+
+        _e_border_event_border_rotation_change_begin_send(info->bd);
+
+        /* resize border */
+        info->win_resize = _e_border_rotation_pre_resize(info->bd, info->ang, &x, &y, &w, &h);
+        info->bd->client.e.state.rot.pending_change_request = info->win_resize;
+
+        info->x = x; info->y = y;
+        info->w = w; info->h = h;
+
         ELBF(ELBT_ROT, 1, info->bd->client.win,
              "SEND ROT_CHANGE_PREPARE a%d res%d %dx%d",
              info->ang, info->win_resize, info->w, info->h);
 
         ecore_x_e_window_rotation_change_prepare_send
-          (info->bd->client.win, info->ang,
-          info->win_resize, info->w, info->h);
+           (info->bd->client.win, info->ang,
+            info->win_resize, info->w, info->h);
 
         if (!info->bd->client.e.state.rot.pending_change_request)
           {
              ELBF(ELBT_ROT, 1, 0, "SEND ROT_CHANGE_REQUEST");
              ecore_x_e_window_rotation_change_request_send(info->bd->client.win,
                                                            info->ang);
+             info->bd->client.e.state.rot.wait_for_done = 1;
+             info->bd->client.e.state.rot.wait_done_ang = info->ang;
           }
      }
 
-   if (rot.done_timer)
-     ecore_timer_del(rot.done_timer);
-   rot.done_timer = ecore_timer_add(4.0f,
-                                    _e_border_rotation_change_done_timeout,
-                                    NULL);
+   if (flush)
+     {
+        EINA_LIST_FREE(list, info)
+           E_FREE(info);
+     }
+}
+
+EAPI void
+e_border_rotation_list_clear(E_Zone *zone, Eina_Bool send_request)
+{
+   E_Border_Rotation_Info *info = NULL;
+
+   if (send_request) _e_border_rotation_change_request(zone);
+   else
+     {
+        EINA_LIST_FREE(rot.list, info)
+           E_FREE(info);
+        rot.list = NULL;
+     }
 }
 
 static void
@@ -7775,6 +8115,9 @@ _e_border_rotation_list_remove(E_Border *bd)
 {
    Eina_List *l = NULL;
    E_Border_Rotation_Info *info = NULL;
+   E_Event_Border_Rotation_Change_End *ev = NULL;
+   Eina_Bool found = EINA_FALSE;
+
    if (!e_config->wm_win_rotation) return;
 
    EINA_LIST_FOREACH(rot.list, l, info)
@@ -7783,13 +8126,33 @@ _e_border_rotation_list_remove(E_Border *bd)
           {
              rot.list = eina_list_remove(rot.list, info);
              E_FREE(info);
+             found = EINA_TRUE;
           }
      }
 
    if (bd->client.e.state.rot.wait_for_done)
      {
         bd->client.e.state.rot.wait_for_done = 0;
-        if (eina_list_count(rot.list) == 0)
+
+        /* if we make the border event in the _e_border_free function,
+         * then we may meet a crash problem, only work this at least e_border_hide.
+         */
+        if (!e_object_is_del(E_OBJECT(bd)))
+          {
+             ev = E_NEW(E_Event_Border_Rotation_Change_End, 1);
+             if (ev)
+               {
+                  ev->border = bd;
+                  e_object_ref(E_OBJECT(bd));
+                  ecore_event_add(E_EVENT_BORDER_ROTATION_CHANGE_END,
+                                  ev,
+                                  _e_border_event_border_rotation_change_end_free,
+                                  NULL);
+               }
+          }
+
+        if ((found) &&
+            (eina_list_count(rot.list) == 0))
           {
              _e_border_rotation_change_done();
           }
@@ -7813,27 +8176,34 @@ _e_border_rotation_change_done(void)
 
    if (!e_config->wm_win_rotation) return;
 
-   if (rot.prepare_timer)
-     ecore_timer_del(rot.prepare_timer);
+   if (rot.prepare_timer) ecore_timer_del(rot.prepare_timer);
    rot.prepare_timer = NULL;
 
    rot.wait_prepare_done = EINA_FALSE;
 
-   if (rot.done_timer)
-     ecore_timer_del(rot.done_timer);
+   if (rot.done_timer) ecore_timer_del(rot.done_timer);
    rot.done_timer = NULL;
 
    EINA_LIST_FREE(rot.list, info)
      {
         if (info->bd)
           {
-             info->bd->client.e.state.rot.wait_for_done = 0;
              ELB(ELBT_ROT, "TIMEOUT ROT_DONE", info->bd->client.win);
+             if (info->bd->client.e.state.rot.pending_show)
+               {
+                  ELB(ELBT_ROT, "SHOW PEND(TIMEOUT)", info->bd->client.win);
+                  e_border_show(info->bd);
+                  info->bd->client.e.state.rot.pending_show = 0;
+               }
+             info->bd->client.e.state.rot.wait_for_done = 0;
           }
         E_FREE(info);
      }
 
+   _e_border_rotation_list_flush(rot.async_list, EINA_TRUE);
+
    rot.list = NULL;
+   rot.async_list = NULL;
 
    m = e_manager_current_get();
    e_manager_comp_screen_unlock(m);
@@ -7862,8 +8232,10 @@ _e_border_rotation_get(E_Border *bd,
                        int       base_ang)
 {
    int ang = -1;
+   int current_ang = bd->client.e.state.rot.curr;
    unsigned int i;
    Eina_Bool found = EINA_FALSE;
+   Eina_Bool found_curr_ang = EINA_FALSE;
 
    if (!e_config->wm_win_rotation) return ang;
    if (!bd->client.e.state.rot.app_set) return ang;
@@ -7884,6 +8256,8 @@ _e_border_rotation_get(E_Border *bd,
                   found = EINA_TRUE;
                   break;
                }
+             if (bd->client.e.state.rot.available_rots[i] == current_ang)
+               found_curr_ang = EINA_TRUE;
           }
 
         /* do nothing. this window wants to maintain current state.
@@ -7893,7 +8267,7 @@ _e_border_rotation_get(E_Border *bd,
          */
         if (!found)
           {
-             if (bd->client.e.state.rot.curr != -1)
+             if ((bd->client.e.state.rot.curr != -1) && (found_curr_ang))
                ang = bd->client.e.state.rot.curr;
              else
                ang = bd->client.e.state.rot.available_rots[0];
@@ -7911,30 +8285,23 @@ _e_border_rotation_get(E_Border *bd,
    return ang;
 }
 
-#define REGION_EQUAL_TO_ZONE(a, z) \
-   ((((a)->x) == ((z)->x)) &&      \
-    (((a)->y) == ((z)->y)) &&      \
-    (((a)->w) == ((z)->w)) &&      \
-    (((a)->h) == ((z)->h)))
-
-static Eina_Bool
-_e_border_rotation_check(E_Border *bd)
+static int
+_e_border_rotation_angle_get(E_Border *bd)
 {
    E_Zone *zone = bd->zone;
-   int x, y, w, h, ang = 0;
-   int diff = 0, _ang = 0;
-   Eina_Bool resize = EINA_TRUE;
-   Eina_Bool hint = EINA_FALSE;
-   Eina_Bool move = EINA_TRUE;
+   int will_ang = 0;
+   int _ang = 0;
+   int ret = -1;
 
-   if (!e_config->wm_win_rotation) return EINA_FALSE;
+   if (!e_config->wm_win_rotation) return ret;
+   if (bd->client.e.state.rot.type != E_BORDER_ROTATION_TYPE_NORMAL) return ret;
 
    ELB(ELBT_ROT, "CHECK ROT", bd->client.win);
 
-   ang = zone->rot.curr;
+   if (bd->parent) will_ang = bd->parent->client.e.state.rot.curr;
+   else will_ang = zone->rot.curr;
 
-   if (((rot.vkbd) && (rot.vkbd == bd)) ||
-       ((rot.vkbd_prediction) && (rot.vkbd_prediction == bd)))
+   if (bd->client.vkbd.win_type != E_VIRTUAL_KEYBOARD_WINDOW_TYPE_NONE)
      {
         ELBF(ELBT_ROT, 1, bd->client.win,
              "%s->parent:0x%08x (support:%d app_set:%d ang:%d)",
@@ -7946,11 +8313,11 @@ _e_border_rotation_check(E_Border *bd)
 
         if (bd->parent)
           {
-             ang = bd->parent->client.e.state.rot.curr;
+             will_ang = bd->parent->client.e.state.rot.curr;
              if ((!bd->parent->client.e.state.rot.support) &&
                  (!bd->parent->client.e.state.rot.app_set))
                {
-                  ang = 0;
+                  will_ang = 0;
                }
           }
      }
@@ -7963,16 +8330,9 @@ _e_border_rotation_check(E_Border *bd)
             (bd->client.vkbd.win_type == E_VIRTUAL_KEYBOARD_WINDOW_TYPE_POPUP))
           {
              ELB(ELBT_BD, "MAG", bd->client.win);
-             ang = 0;
+             will_ang = 0;
              if ((rot.vkbd) && (rot.vkbd->visible))
-               ang = rot.vkbd->client.e.state.rot.curr;
-             hint = _e_border_rotation_geom_get(bd, zone, ang, &x, &y, &w, &h, &move);
-             if (hint)
-               {
-                  ELBF(ELBT_ROT, 1, bd->client.win, "MAG %d,%d %dx%d m:%d", x, y, w, h, move);
-                  _e_border_move_resize_internal(bd, x, y, w, h, EINA_TRUE, move);
-               }
-             return EINA_FALSE;
+               will_ang = rot.vkbd->client.e.state.rot.curr;
           }
      }
 
@@ -7984,7 +8344,7 @@ _e_border_rotation_check(E_Border *bd)
         if ((bd->parent) &&
             (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_UTILITY))
           {
-             ang = bd->parent->client.e.state.rot.curr;
+             will_ang = bd->parent->client.e.state.rot.curr;
              if ((!bd->parent->client.e.state.rot.support) &&
                  (!bd->parent->client.e.state.rot.app_set))
                {
@@ -7992,38 +8352,29 @@ _e_border_rotation_check(E_Border *bd)
                    * then this window should't be rotated.
                    * TODO: need to check whether window supports '0' degree or not.
                    */
-                  ang = 0;
+                  will_ang = 0;
                   ELBF(ELBT_ROT, 0, bd->client.win,
                        "GET ROT ang:%d Transient_For:0x%08x Not support rot",
-                       ang, bd->parent->client.win);
+                       will_ang, bd->parent->client.win);
                }
              else
                {
-                  ang = _e_border_rotation_get(bd->parent, ang);
+                  will_ang = _e_border_rotation_get(bd->parent, will_ang);
                   ELBF(ELBT_ROT, 0, bd->client.win,
                        "GET ROT ang:%d Transient_For:0x%08x",
-                       ang, bd->parent->client.win);
+                       will_ang, bd->parent->client.win);
                }
           }
         else
           {
-             ang = _e_border_rotation_get(bd, ang);
+             will_ang = _e_border_rotation_get(bd, will_ang);
              ELBF(ELBT_ROT, 0, bd->client.win, "GET ROT ang:%d bd->parent:0x%08x type:%d",
-                  ang, bd->parent ? bd->parent->client.win : 0,
+                  will_ang, bd->parent ? bd->parent->client.win : 0,
                   bd->client.netwm.type);
           }
      }
 
-   hint = _e_border_rotation_geom_get(bd, zone, ang, &x, &y, &w, &h, &move);
-   if (hint)
-     _e_border_move_resize_internal(bd, x, y, w, h, EINA_TRUE, move);
-
-   /* need to check previous rotation angle, this may be because
-    * the window was unmapped with non-0 rotation degree.
-    * and now, the window wants to show on the 0 degree zone,
-    * thus the wm should request to rotate the window to 0 degree.
-    */
-   if (!bd->visible)
+   if (bd->new_client)
      {
         _ang = _prev_angle_get(bd->client.win);
         if (_ang != -1)
@@ -8031,166 +8382,175 @@ _e_border_rotation_check(E_Border *bd)
         ELBF(ELBT_ROT, 1, bd->client.win, "prev_ang:%d", _ang);
      }
 
-   if (bd->client.e.state.rot.curr != ang)
-     {
-        Eina_Bool is_screen_locked = EINA_FALSE;
-
-        if ((rot.vkbd != bd) && (rot.vkbd_prediction != bd) &&
-            /* check whether virtual keyboard is visible on the zone */
-            (_e_border_rotation_zone_vkbd_check(bd->zone)) &&
-            /* check whether virtual keyboard belongs to this border (transient_for) */
-            (_e_border_rotation_vkbd_transient_for_check(bd)) &&
-            /* check rotation of the virtual keyboard */
-            (((rot.vkbd) && (rot.vkbd->client.e.state.rot.curr != ang)) ||
-             ((rot.vkbd_prediction) && (rot.vkbd_prediction->client.e.state.rot.curr != ang))) &&
-            (!rot.wait_prepare_done))
-          {
-             ELB(ELBT_ROT, "DO VKBD ROT", bd->client.win);
-             e_manager_comp_screen_lock(e_manager_current_get());
-             is_screen_locked = EINA_TRUE;
+   if (bd->client.e.state.rot.curr != will_ang)
+     ret = will_ang;
 
-             if (rot.prepare_timer) ecore_timer_del(rot.prepare_timer);
-             rot.prepare_timer = NULL;
+   return ret;
+}
 
-             if (rot.done_timer) ecore_timer_del(rot.done_timer);
-             rot.done_timer = NULL;
 
-             ELB(ELBT_ROT, "send rot_change_prepare", rot.vkbd_ctrl_win);
-             ecore_x_e_window_rotation_change_prepare_send(rot.vkbd_ctrl_win,
-                                                           bd->zone->rot.curr,
-                                                           EINA_FALSE, 1, 1);
-             rot.prepare_timer = ecore_timer_add(4.0f,
-                                                 _e_border_rotation_change_prepare_timeout,
-                                                 NULL);
-             rot.wait_prepare_done = EINA_TRUE;
-          }
+static Eina_Bool
+_e_border_rotation_zone_set(E_Zone *zone)
+{
+   E_Border_List *l = NULL;
+   E_Border *bd = NULL;
+   Eina_Bool ret = EINA_FALSE;
 
-        bd->client.e.state.rot.prev = bd->client.e.state.rot.curr;
-        bd->client.e.state.rot.curr = ang;
-        bd->client.e.state.rot.wait_for_done = 1;
+   if (!e_config->wm_win_rotation) return EINA_FALSE;
 
-        diff = bd->client.e.state.rot.curr - bd->client.e.state.rot.prev;
-        if ((diff == 180) || (diff == -180))
-          resize = EINA_FALSE;
+   l = e_container_border_list_last(zone->container);
+   if (!l) return ret;
 
-        /* Check if it has size hint, full size or not, and needs to resize.
-         * Under the below condition, replace width value with height.
-         */
-        if ((!hint) && (!REGION_EQUAL_TO_ZONE(bd, bd->zone)) && (resize))
-          {
-             x = bd->x;  y = bd->y;
-             w = bd->w;  h = bd->h;
+   /* step 1. make the list needs to be rotated. */
+   while ((bd = e_container_border_list_prev(l)))
+     {
+        if (!bd) continue;
 
-             if (w == h)
-               resize = EINA_FALSE;
-             else
-               {
-                  w = bd->h;
-                  h = bd->w;
+        // if this window have parent,
+        // it will be rotated when parent do rotate itself.
+        // so skip here.
+        if (bd->parent) continue;
 
-                  _e_border_move_resize_internal(bd, x, y, w, h,
-                                                 EINA_TRUE, EINA_FALSE);
-               }
-          }
+        // this type is set by illume.
+        // if it's not normal type window, will be rotated by illume.
+        // so skip here.
+        if (bd->client.e.state.rot.type != E_BORDER_ROTATION_TYPE_NORMAL) continue;
 
-        /* hack ... */
-        if (bd->client.e.state.rot.app_set) resize = EINA_FALSE;
+        if ((!bd->visible) ||
+            (!E_INTERSECTS(bd->zone->x, bd->zone->y, bd->zone->w, bd->zone->h,
+                           bd->x, bd->y, bd->w, bd->h))) continue;
 
-        E_Border_Rotation_Info *info = NULL;
-        info = E_NEW(E_Border_Rotation_Info, 1);
-        if (info)
+        if (_e_border_rotatable_check(bd, zone->rot.curr))
           {
-             if (!is_screen_locked)
-               e_manager_comp_screen_lock(e_manager_current_get());
+             ELBF(ELBT_ROT, 0, bd->client.win, "ROT_SET(main) curr:%d != TOBE:%d",
+                  bd->client.e.state.rot.curr, zone->rot.curr);
+
+             ret = e_border_rotation_set(bd, zone->rot.curr);
+          }
+     }
+   if (l) e_container_border_list_free(l);
+
+   return ret;
+}
 
-             info->bd = bd;
-             info->ang = ang;
-             info->x = x; info->y = y;
-             info->w = w; info->h = h;
-             info->win_resize = resize;
-             rot.list = eina_list_append(rot.list, info);
+EAPI Eina_Bool
+e_border_rotation_set(E_Border *bd, int rotation)
+{
+   E_Zone *zone = bd->zone;
+   E_Border_Rotation_Info *info = NULL;
+   Eina_List *list, *l;
+   E_Border *child;
 
-             if (info->win_resize)
-               bd->client.e.state.rot.pending_change_request = 1;
+   if (rotation < 0) return EINA_FALSE;
 
-             ELBF(ELBT_ROT, 1, info->bd->client.win,
-                  "SEND ROT_CHANGE_PREPARE a%d res%d %dx%d",
-                  info->ang, info->win_resize, info->w, info->h);
+   /* step 1. check if rotation */
+   if (!_e_border_rotatable_check(bd, rotation)) return EINA_FALSE;
 
-             ecore_x_e_window_rotation_change_prepare_send
-                (info->bd->client.win, info->ang,
-                 info->win_resize, info->w, info->h);
+   /* step 2. add to async/sync list */
+   if ((!zone->rot.block_count) &&
+       ((!bd->visible) ||
+        (!E_INTERSECTS(bd->x, bd->y, bd->w, bd->h, zone->x, zone->y, zone->w, zone->h))))
+     {
+        // send rotation change request later.
+        // and no need to wait message of rotation done.
 
-             if (!info->bd->client.e.state.rot.pending_change_request)
-               {
-                  ELBF(ELBT_ROT, 1, 0, "SEND ROT_CHANGE_REQUEST");
-                  ecore_x_e_window_rotation_change_request_send(info->bd->client.win,
-                                                                info->ang);
-               }
+        // async list add
+        info = E_NEW(E_Border_Rotation_Info, 1);
+        if (!info) return EINA_FALSE;
+        ELB(ELBT_ROT, "ADD ASYNC LIST", 0);
+        info->bd = bd;
+        info->ang = rotation;
+        rot.async_list = eina_list_append(rot.async_list, info);
 
-             if (rot.done_timer)
-               ecore_timer_del(rot.done_timer);
-             rot.done_timer = ecore_timer_add(4.0f,
-                                              _e_border_rotation_change_done_timeout,
-                                              NULL);
+        // add job for sending event.
+        if (!rot.async_job)
+          {
+             ELB(ELBT_ROT, "ADD ASYNC_JOB", bd->client.win);
+             rot.async_job = ecore_job_add(_e_border_cb_rotation_async_job, zone);
           }
      }
-   return EINA_TRUE;
-}
+   else
+     {
+        // sync list add
+        info = E_NEW(E_Border_Rotation_Info, 1);
+        if (!info) return EINA_FALSE;
+        ELB(ELBT_ROT, "ADD SYNC LIST", 0);
+        info->bd = bd;
+        info->ang = rotation;
+        rot.list = eina_list_append(rot.list, info);
 
-static Eina_Bool
-_e_border_rotation_zone_check(E_Zone *zone)
-{
-   Eina_Bool wait = EINA_FALSE;
-   E_Border_List *l = NULL;
-   E_Border *bd = NULL;
+        // add job for sending event.
+        if (!rot.sync_job)
+          {
+             ELB(ELBT_ROT, "ADD SYNC_JOB", bd->client.win);
+             rot.sync_job = ecore_job_add(_e_border_cb_rotation_sync_job, zone);
+          }
 
-   if (!e_config->wm_win_rotation) return EINA_FALSE;
+        // if there is windows over 2 that has to be rotated or is existed window needs resizing,
+        // lock the screen.
+        // but, DO NOT lock the screen when rotation block state.
+        if ((!zone->rot.block_count) &&
+            ((eina_list_count(rot.list) == 2)))
+          e_manager_comp_screen_lock(e_manager_current_get());
+     }
 
-   l = e_container_border_list_last(zone->container);
-   if (!l) return EINA_FALSE;
-   while ((bd = e_container_border_list_prev(l)))
+   /* step 3. search rotatable window in this window's child */
+   list = _e_border_sub_borders_new(bd);
+   EINA_LIST_FOREACH(list, l, child)
      {
-        if ((!bd) || (e_object_is_del(E_OBJECT(bd))) ||
-            (!bd->visible) || (bd->zone != zone) ||
-            (!E_INTERSECTS(zone->x, zone->y, zone->w, zone->h,
-                           bd->x, bd->y, bd->w, bd->h))) continue;
-
-        if (((rot.vkbd) && (rot.vkbd == bd)) ||
-            ((rot.vkbd_prediction) && (rot.vkbd_prediction == bd)) ||
-            ((REGION_EQUAL_TO_ZONE(bd, zone)) &&
-             (bd->client.e.state.rot.preferred_rot != -1))) continue;
-
-        if (_e_border_rotation_border_check(bd, zone->rot.curr))
+        if (_e_border_rotatable_check(child, rotation))
           {
-             wait = EINA_TRUE;
-             break;
+             ELBF(ELBT_ROT, 0, child->client.win, "ROT_SET(child) curr:%d != TOBE:%d",
+                  bd->client.e.state.rot.curr, rotation);
+             e_border_rotation_set(child, rotation);
           }
      }
-   if (l) e_container_border_list_free(l);
 
-   return wait;
+   /* step 4. if there is vkbd window, send message to prepare rotation */
+   if (_e_border_is_vkbd(bd))
+     {
+        ELB(ELBT_ROT, "PENDING ROT_REQ UNTIL GET PREP_DONE", rot.vkbd_ctrl_win);
+        if (rot.prepare_timer)
+          ecore_timer_del(rot.prepare_timer);
+        rot.prepare_timer = NULL;
+
+        if (rot.done_timer)
+          ecore_timer_del(rot.done_timer);
+        rot.done_timer = NULL;
+
+        ELB(ELBT_ROT, "SEND ROT_CHANGE_PREPARE", rot.vkbd_ctrl_win);
+        ecore_x_e_window_rotation_change_prepare_send(rot.vkbd_ctrl_win,
+                                                      zone->rot.curr,
+                                                      EINA_FALSE, 1, 1);
+        rot.prepare_timer = ecore_timer_add(4.0f,
+                                            _e_border_rotation_change_prepare_timeout,
+                                            NULL);
+
+        rot.wait_prepare_done = EINA_TRUE;
+     }
+
+   bd->client.e.state.rot.prev = bd->client.e.state.rot.curr;
+   bd->client.e.state.rot.curr = rotation;
+
+   return EINA_TRUE;
 }
 
 // check if border is rotatable in ang.
 static Eina_Bool
-_e_border_rotation_border_check(E_Border *bd, int ang)
+_e_border_rotatable_check(E_Border *bd, int ang)
 {
-   Eina_Bool wait = EINA_FALSE;
+   Eina_Bool ret = EINA_FALSE;
 
-   if (!bd) return wait;
+   if (!bd) return ret;
+   if (ang < 0) return ret;
+   if ((!bd->client.e.state.rot.support) && (!bd->client.e.state.rot.app_set)) return ret;
+   if (e_object_is_del(E_OBJECT(bd))) return ret;
 
-   if (((bd->client.e.state.rot.support) || (bd->client.e.state.rot.app_set)) &&
-       /* basically WM allows only fullscreen window to rotate */
-       ((REGION_EQUAL_TO_ZONE(bd, bd->zone)) ||
-        /* we don't like this kind of code.
-         * it means that the WM also allows non-fullscreen window to rotate if it sets geom hint.
-         * such as large editable window.
-         */
-        ((bd->client.vkbd.win_type == E_VIRTUAL_KEYBOARD_WINDOW_TYPE_NONE) && (bd->client.e.state.rot.geom_hint)) ||
-        /* and floating mode window is also rotatable */
-        (bd->client.illume.win_state.state == ECORE_X_ILLUME_WINDOW_STATE_FLOATING)) &&
-       (bd->client.e.state.rot.preferred_rot == -1))
+   // same with current angle of window, then false return.
+   if (ang == bd->client.e.state.rot.curr) return ret;
+
+   /* basically WM allows only fullscreen window to rotate */
+   if (bd->client.e.state.rot.preferred_rot == -1)
      {
         unsigned int i;
 
@@ -8207,40 +8567,36 @@ _e_border_rotation_border_check(E_Border *bd, int ang)
                             found = EINA_TRUE;
                          }
                     }
-                  if ((found) && (ang != bd->client.e.state.rot.curr))
-                    {
-                       wait = EINA_TRUE;
-                    }
-                  else
-                    {
-                       ELB(ELBT_ROT, "ROT CANCEL for preferred rot", bd->client.win);
-                       wait = EINA_FALSE;
-                    }
+                  if (found) ret = EINA_TRUE;
                }
           }
         else
           {
              ELB(ELBT_ROT, "DO ROT", 0);
-             wait = EINA_TRUE;
+             ret = EINA_TRUE;
           }
      }
+   // if it has preferred rotation angle,
+   // it will be rotated at border's evaluation time.
+   // so skip it.
+   else if (bd->client.e.state.rot.preferred_rot == ang) ret = EINA_TRUE;
 
-   return wait;
+   return ret;
 }
 
 /* check whether virtual keyboard is visible on the zone */
 static Eina_Bool
-_e_border_rotation_zone_vkbd_check(E_Zone *zone)
+_e_border_is_vkbd(E_Border *bd)
 {
    if (!e_config->wm_win_rotation) return EINA_FALSE;
 
    if ((rot.vkbd_ctrl_win) &&
-       (rot.vkbd) &&
+       (rot.vkbd == bd) &&
        (!e_object_is_del(E_OBJECT(rot.vkbd))) &&
        (rot.vkbd->visible) &&
-       (rot.vkbd->zone == zone) &&
-       (E_INTERSECTS(zone->x, zone->y,
-                     zone->w, zone->h,
+       (rot.vkbd->zone == bd->zone) &&
+       (E_INTERSECTS(bd->zone->x, bd->zone->y,
+                     bd->zone->w, bd->zone->h,
                      rot.vkbd->x, rot.vkbd->y,
                      rot.vkbd->w, rot.vkbd->h)))
      {
@@ -8249,182 +8605,225 @@ _e_border_rotation_zone_vkbd_check(E_Zone *zone)
    return EINA_FALSE;
 }
 
-/* check whether border is parent of the virtual keyboard */
 static Eina_Bool
-_e_border_rotation_vkbd_transient_for_check(E_Border *bd)
+_e_border_rotation_change_floating_pos(E_Border *bd, int *x, int *y)
 {
-   if (!e_config->wm_win_rotation) return EINA_FALSE;
+   int new_x, new_y;
+   int min_title_width=96;
+
+   if (!bd) return EINA_FALSE;
+   if (!x || !y) return EINA_FALSE;
+
+   new_x = bd->x;
+   new_y = bd->y;
 
-   if (rot.vkbd_ctrl_win)
+   // Portrait -> Landscape,  x= pre_x*2, y=pre_y/2
+   // Landscape -> Portrait,  x= pre_x/2, y=pre_y*2
+   // guaranteeing the minimum size of titlebar shown, min_title_width
+   // so user can initiate drag&drop action after rotation changed.
+   if (bd->client.e.state.rot.curr == 0)
      {
-        if ((rot.vkbd) && (!e_object_is_del(E_OBJECT(rot.vkbd))) &&
-            (rot.vkbd != bd))
+        if (bd->client.e.state.rot.prev == 90)
           {
-             if (rot.vkbd->parent == bd)
-               return EINA_TRUE;
+             new_x = (bd->zone->h - bd->h - bd->y) / 2;
+             new_y = 2 * bd->x;
+          }
+        else if (bd->client.e.state.rot.prev == 270)
+          {
+             new_x = bd->y / 2;
+             new_y = (bd->zone->w - bd->w - bd->x) * 2;
+          }
+        else if (bd->client.e.state.rot.prev == 180)
+          {
+             new_x = bd->zone->w - bd->x - bd->w;
+             new_y = bd->zone->h - bd->y - bd->h;
           }
 
-        if ((rot.vkbd_prediction) && (!e_object_is_del(E_OBJECT(rot.vkbd_prediction))) &&
-            (rot.vkbd_prediction != bd))
+        if(new_x + bd->w < min_title_width)
           {
-             if (rot.vkbd_prediction == bd)
-               return EINA_TRUE;
+             new_x = min_title_width - bd->w;
+          }
+        else if(new_x > bd->zone->w - min_title_width)
+          {
+             new_x = bd->zone->w - min_title_width;
           }
      }
+   else if (bd->client.e.state.rot.curr == 90)
+     {
+        if (bd->client.e.state.rot.prev == 0)
+          {
+             new_x = bd->y / 2;
+             new_y = bd->zone->h - (2 * bd->x) - bd->w;
+          }
+        else if (bd->client.e.state.rot.prev == 270)
+          {
+             new_x = bd->zone->w - bd->x - bd->w;
+             new_y = bd->zone->h - bd->y - bd->h;
+          }
+        else if (bd->client.e.state.rot.prev == 180)
+          {
+             new_x = (bd->zone->h - bd->y - bd->h) / 2;
+             new_y = bd->zone->h - (2 * (bd->zone->w - bd->x - bd->w)) - bd->w;
+          }
 
-   return EINA_FALSE;
-}
+        if(new_y > bd->zone->h - min_title_width)
+          {
+             new_y = bd->zone->h - min_title_width;
+          }
+        else if(new_y < min_title_width - bd->w)
+          {
+             new_y = min_title_width - bd->w;
+          }
+     }
+   else if (bd->client.e.state.rot.curr == 270)
+     {
+        if (bd->client.e.state.rot.prev == 0)
+          {
+             new_x = bd->zone->w - bd->h - (bd->y / 2);
+             new_y = bd->x * 2;
+          }
+        else if (bd->client.e.state.rot.prev == 90)
+          {
+             new_x = bd->zone->w - bd->x - bd->w;
+             new_y = bd->zone->h - bd->y - bd->h;
+          }
+        else if (bd->client.e.state.rot.prev == 180)
+          {
+             new_x = bd->zone->w - bd->x - bd->w;
+             new_y = bd->zone->h - bd->y - bd->h;
 
-// check if bd's parent is rotatable.
-static Eina_Bool
-_e_border_rotation_transient_for_check(E_Border *bd, int ang)
-{
-   Eina_Bool ret = EINA_FALSE;
+             new_x = bd->zone->w - bd->h - ((bd->zone->h - bd->y - bd->h) / 2);
+             new_y = (bd->zone->w - bd->x - bd->w) * 2;
+          }
 
-   if (!e_config->wm_win_rotation) return EINA_FALSE;
-   if (!bd) return EINA_FALSE;
+        if(new_y >  bd->zone->h - min_title_width)
+          {
+             new_y = bd->zone->h - min_title_width;
+          }
+        else if( new_y + bd->w < min_title_width)
+          {
+             new_y = min_title_width - bd->w ;
+          }
+     }
+   else if (bd->client.e.state.rot.curr == 180)
+     {
+        if (bd->client.e.state.rot.prev == 0)
+          {
+             new_x = bd->zone->w - bd->x - bd->w;
+             new_y = bd->zone->h - bd->y - bd->h;
+          }
+        else if (bd->client.e.state.rot.prev == 90)
+          {
+             new_x = bd->zone->w - ((bd->zone->h - bd->h - bd->y) / 2) - bd->h;
+             new_y = bd->zone->h - (2 * bd->x) - bd->w;
+          }
+        else if (bd->client.e.state.rot.prev == 270)
+          {
+             new_x = bd->zone->w - (bd->y / 2) - bd->h;
+             new_y = bd->zone->h - ((bd->zone->w - bd->w - bd->x) * 2) - bd->w;
+          }
 
-   if (!bd->parent) ret = EINA_TRUE;
-   else
+        if(new_x + bd->w < min_title_width)
+          {
+             new_x = min_title_width - bd->w;
+          }
+        else if(new_x > bd->zone->w - min_title_width)
+          {
+             new_x = bd->zone->w - min_title_width;
+          }
+     }
+
+   ELBF(ELBT_ROT, 0, bd->client.win,
+        "Floating Mode. ANGLE (%d->%d), POS (%d,%d) -> (%d,%d)",
+        bd->client.e.state.rot.prev, bd->client.e.state.rot.curr,
+        bd->x, bd->y, new_x, new_y);
+
+   if ((new_x == *x) &&
+       (new_y == *y))
      {
-        if (_e_border_rotation_border_check(bd->parent, ang))
-          ret = EINA_TRUE;
+        return EINA_FALSE;
      }
 
-   return ret;
+   *x = new_x;
+   *y = new_y;
+
+   return EINA_TRUE;
 }
 
+#define SIZE_EQUAL_TO_ZONE(a, z) \
+   ((((a)->w) == ((z)->w)) &&    \
+    (((a)->h) == ((z)->h)))
 static Eina_Bool
-_e_border_rotation_list_add(E_Zone *zone, Eina_Bool without_vkbd)
+_e_border_rotation_pre_resize(E_Border *bd, int rotation, int *x, int *y, int *w, int *h)
 {
-   Eina_Bool wait = EINA_FALSE;
-   E_Border_List *l = NULL;
-   Eina_List *nl = NULL;
-   E_Border *bd = NULL;
-   E_Border_Rotation_Info *info = NULL;
-
-   if (!e_config->wm_win_rotation) return EINA_FALSE;
-
-   l = e_container_border_list_last(zone->container);
-   if (!l) return EINA_FALSE;
-   while ((bd = e_container_border_list_prev(l)))
-     {
-        if ((!bd) || (e_object_is_del(E_OBJECT(bd)))) continue;
-
-        if ((without_vkbd) &&
-            (((rot.vkbd) && (rot.vkbd == bd)) ||
-             ((rot.vkbd_prediction) && (rot.vkbd_prediction == bd)))) continue;
+   E_Zone *zone = bd->zone;
+   int rot_dif;
+   int _x, _y, _w, _h;
+   Eina_Bool move = EINA_FALSE;
+   Eina_Bool hint = EINA_FALSE;
+   Eina_Bool resize = EINA_FALSE;
 
-        if ((bd->visible) &&
-            ((bd->client.e.state.rot.support) || (bd->client.e.state.rot.app_set)) &&
-            (bd->zone == zone) &&
-            (E_INTERSECTS(zone->x, zone->y, zone->w, zone->h,
-                          bd->x, bd->y, bd->w, bd->h)))
-          {
-             // check if this window is available to be rotate.
-             if ((bd->client.e.state.rot.app_set) &&
-                 (bd->client.e.state.rot.preferred_rot != -1)) continue;
+   if (x) *x = bd->x;
+   if (y) *y = bd->y;
+   if (w) *w = bd->w;
+   if (h) *h = bd->h;
 
-             /* check list of available rotations */
-             int ang = zone->rot.curr;
-             if (bd->client.e.state.rot.app_set)
-               {
-                  ang = _e_border_rotation_get(bd, ang);
-                  ELBF(ELBT_ROT, 0, bd->client.win, "returned ang:%d", ang);
-               }
+   if (SIZE_EQUAL_TO_ZONE(bd, zone)) return resize;
 
-             /* skip same angle */
-             if (bd->client.e.state.rot.curr == ang)
-               {
-                  ELBF(ELBT_ROT, 0, bd->client.win, "SKIP ang:%d", ang);
-                  continue;
-               }
-             else
-               {
-                  ELBF(ELBT_ROT, 0, bd->client.win, "ADD ROT_LIST curr:%d != ang:%d",
-                       bd->client.e.state.rot.curr, ang);
-               }
+   ELB(ELBT_ROT, "SIZE DIFF WITH ZONE", 0);
+   ELBF(ELBT_ROT, 0, bd->client.win, "ORIGIN_SIZE name:%s (%d,%d) %dx%d",
+        bd->client.icccm.name, bd->x, bd->y, bd->w, bd->h);
 
-             bd->client.e.state.rot.prev = bd->client.e.state.rot.curr;
-             bd->client.e.state.rot.curr = ang;
-             bd->client.e.state.rot.wait_for_done = 1;
+   hint = _e_border_rotation_geom_get(bd, bd->zone, rotation,
+                                      &_x, &_y, &_w, &_h, &move);
+   if (hint)
+     {
+        _e_border_move_resize_internal(bd, _x, _y, _w, _h, EINA_TRUE, move);
+        resize = EINA_TRUE;
+        ELBF(ELBT_ROT, 0, bd->client.win, "RESIZE_BY_HINT name:%s (%d,%d) %dx%d",
+             bd->client.icccm.name, _x, _y, _w, _h);
+     }
+   else
+     {
+        _x = bd->x; _y = bd->y;
+        _w = bd->w; _h = bd->h;
 
-             info = E_NEW(E_Border_Rotation_Info, 1);
-             if (info)
-               {
-                  info->bd = bd;
-                  info->ang = ang;
-                  info->x = bd->x; info->y = bd->y;
-                  info->w = bd->w; info->h = bd->h;
-                  info->win_resize = EINA_FALSE;
-                  nl = eina_list_append(nl, info);
-               }
+        if (bd->client.illume.win_state.state == ECORE_X_ILLUME_WINDOW_STATE_FLOATING)
+          move = _e_border_rotation_change_floating_pos(bd, &_x, &_y);
+        else
+          move = EINA_FALSE;
 
-             if (REGION_EQUAL_TO_ZONE(bd, zone))
-               {
-                  wait = EINA_TRUE; // for the maximized window
-               }
-             else
+        rot_dif = bd->client.e.state.rot.prev - rotation;
+        if (rot_dif < 0) rot_dif = -rot_dif;
+        if (rot_dif != 180)
+          {
+             if (w != h)
                {
-                  int diff = bd->client.e.state.rot.curr - bd->client.e.state.rot.prev;
-                  int x, y, w, h;
-                  Eina_Bool resize = EINA_TRUE;
-                  if ((diff == 180) || (diff == -180))
-                    resize = EINA_FALSE;
-
-                  Eina_Bool move = EINA_TRUE;
-                  Eina_Bool hint = EINA_FALSE;
-                  hint = _e_border_rotation_geom_get(bd, zone, zone->rot.curr, &x, &y, &w, &h, &move);
-                  if (hint)
-                    _e_border_move_resize_internal(bd, x, y, w, h, EINA_TRUE, move);
-                  else
-                    {
-                       x = bd->x; y = bd->y;
-                       w = bd->w; h = bd->h;
-                       if (resize)
-                         {
-                            if (w == h)
-                              resize = EINA_FALSE;
-                            else
-                              {
-                                 // swap width and height and resize border
-                                 w = bd->h;
-                                 h = bd->w;
-
-                                 _e_border_move_resize_internal(bd, x, y, w, h,
-                                                                EINA_TRUE, EINA_TRUE);
-                              }
-                         }
-                    }
-
-                  if (info)
-                    {
-                       info->x = x; info->y = y;
-                       info->w = w; info->h = h;
-                       info->win_resize = resize;
-                    }
+                  _w = bd->h;
+                  _h = bd->w;
+                  resize = EINA_TRUE;
 
-                  if (resize)
-                    bd->client.e.state.rot.pending_change_request = 1;
+                  _e_border_move_resize_internal(bd, _x, _y, _w, _h,
+                                                 EINA_TRUE, EINA_TRUE);
+                  ELBF(ELBT_ROT, 0, bd->client.win, "MANUAL_RESIZE name:%s (%d,%d) %dx%d",
+                       bd->client.icccm.name, _x, _y, _w, _h);
 
-                  wait = EINA_TRUE;
                }
           }
-     }
 
-   if (l) e_container_border_list_free(l);
+        if (!resize && move)
+          _e_border_move_internal(bd, _x, _y, EINA_TRUE);
+     }
 
-   if (nl)
+   if (resize)
      {
-        // clear previous list
-        EINA_LIST_FREE(rot.list, info)
-          {
-             E_FREE(info);
-          }
-        rot.list = nl;
+        if (x) *x = _x;
+        if (y) *y = _y;
+        if (w) *w = _w;
+        if (h) *h = _h;
      }
 
-   return wait;
+   return resize;
 }
 
 static Eina_Bool
@@ -8433,6 +8832,10 @@ _e_border_cb_window_configure(void *data    __UNUSED__,
                               void         *ev)
 {
    Ecore_X_Event_Window_Configure *e = ev;
+   E_Border_Rotation_Info *info = NULL;
+   Eina_List *l;
+   Eina_Bool found = EINA_FALSE;
+
    if (!e) return ECORE_CALLBACK_PASS_ON;
    if (!e_config->wm_win_rotation) return ECORE_CALLBACK_PASS_ON;
 
@@ -8443,17 +8846,35 @@ _e_border_cb_window_configure(void *data    __UNUSED__,
      {
         if ((e->w == bd->w) && (e->h == bd->h))
           {
+             ELB(ELBT_BD, "GET CONFIGURE_NOTI (ROTATION)", bd->client.win);
+             bd->client.e.state.rot.pending_change_request = 0;
+
+             if ((bd->client.e.state.rot.wait_for_done) &&
+                 (bd->client.e.state.rot.wait_done_ang == bd->client.e.state.rot.curr)) goto end;
+
+             // if this window is rotation dependent window and zone is blocked to rotate,
+             // then skip here, request will be sent after cancel block.
+             if ((bd->client.e.state.rot.type == E_BORDER_ROTATION_TYPE_DEPENDENT) &&
+                 (bd->zone->rot.block_count)) goto end;
+
+             EINA_LIST_FOREACH(rot.list, l, info)
+                if (info->bd == bd) found = EINA_TRUE;
+             // send request message if it's async rotation window,
+             // even if wait prepare done.
+             if ((found) && (rot.wait_prepare_done)) goto end;
+
              ELBF(ELBT_ROT, 0, bd->client.win,
                   "SEND ROT_CHANGE_REQUEST a%d %dx%d",
                   bd->client.e.state.rot.curr,
                   bd->w, bd->h);
-
-             bd->client.e.state.rot.pending_change_request = 0;
-
              ecore_x_e_window_rotation_change_request_send(bd->client.win,
                                                            bd->client.e.state.rot.curr);
+             bd->client.e.state.rot.wait_for_done = 1;
+             bd->client.e.state.rot.wait_done_ang = bd->client.e.state.rot.curr;
           }
      }
+
+end:
    return ECORE_CALLBACK_PASS_ON;
 }
 
@@ -8827,7 +9248,7 @@ _e_border_eval0(E_Border *bd)
      {
         const char **profiles = NULL;
         const char *str;
-        int num, i;
+        int num = 0, i;
 
         if (bd->client.e.state.profile)
           eina_stringshare_del(bd->client.e.state.profile);
@@ -8865,7 +9286,11 @@ _e_border_eval0(E_Border *bd)
           }
 
         if (profiles)
-          free(profiles);
+          {
+             for (i = 0; i < num; i++)
+                if (profiles[i]) free(profiles[i]);
+             free(profiles);
+          }
 
         bd->client.e.fetch.profile_list = 0;
      }
@@ -9195,6 +9620,9 @@ _e_border_eval0(E_Border *bd)
      {
         /* TODO: What do to if the transient for isn't mapped yet? */
         E_Border *bd_parent = NULL;
+#ifdef _F_DEICONIFY_APPROVE_
+        Eina_Bool change_parent = EINA_FALSE;
+#endif
 
         bd->client.icccm.transient_for = ecore_x_icccm_transient_for_get(bd->client.win);
         if (bd->client.icccm.transient_for)
@@ -9216,6 +9644,9 @@ _e_border_eval0(E_Border *bd)
           {
              bd_parent->transients = eina_list_append(bd_parent->transients, bd);
              bd->parent = bd_parent;
+#ifdef _F_DEICONIFY_APPROVE_
+             change_parent = EINA_TRUE;
+#endif
           }
         if (bd->parent)
           {
@@ -9235,6 +9666,33 @@ _e_border_eval0(E_Border *bd)
                  (bd->parent->focused && (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))
                bd->take_focus = 1;
           }
+
+#ifdef _F_DEICONIFY_APPROVE_
+        if (change_parent)
+          {
+             bd->client.e.state.deiconify_approve.render_done = 0;
+
+             E_Border *ancestor_bd;
+             ancestor_bd = bd->client.e.state.deiconify_approve.ancestor;
+             if ((ancestor_bd) &&
+                 (!e_object_is_del(E_OBJECT(ancestor_bd))))
+               {
+                  ancestor_bd->client.e.state.deiconify_approve.req_list = eina_list_remove(ancestor_bd->client.e.state.deiconify_approve.req_list, bd);
+                  bd->client.e.state.deiconify_approve.ancestor = NULL;
+
+                  if ((ancestor_bd->client.e.state.deiconify_approve.req_list == NULL) &&
+                      (ancestor_bd->client.e.state.deiconify_approve.render_done))
+                    {
+                       if (ancestor_bd->client.e.state.deiconify_approve.wait_timer)
+                         {
+                            ecore_timer_del(ancestor_bd->client.e.state.deiconify_approve.wait_timer);
+                            ancestor_bd->client.e.state.deiconify_approve.wait_timer = NULL;
+                            e_border_uniconify(ancestor_bd);
+                         }
+                    }
+               }
+          }
+#endif
         bd->client.icccm.fetch.transient_for = 0;
         rem_change = 1;
      }
@@ -9765,20 +10223,42 @@ _e_border_eval0(E_Border *bd)
           }
      }
 #endif
-#ifdef _F_ZONE_WINDOW_ROTATION_
-   if ((e_config->wm_win_rotation) &&
-       (need_rotation_set))
-     {
-        ELB(ELBT_ROT, "NEED ROT", bd->client.win);
-        _e_border_rotation_check(bd);
-     }
-#endif
 
    /* PRE_POST_FETCH calls e_remember apply for new client */
    _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_POST_FETCH, bd);
    _e_border_hook_call(E_BORDER_HOOK_EVAL_POST_FETCH, bd);
    _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_BORDER_ASSIGN, bd);
 
+#ifdef _F_ZONE_WINDOW_ROTATION_
+   if (e_config->wm_win_rotation)
+     {
+        if (need_rotation_set)
+          {
+             Eina_Bool hint = EINA_FALSE;
+             int ang = 0;
+             int x, y, w, h, move;
+
+             ELB(ELBT_ROT, "NEED ROT", bd->client.win);
+             bd->client.e.state.rot.changes = _e_border_rotation_angle_get(bd);
+
+             if (bd->client.e.state.rot.changes != -1)
+               {
+                  ang = bd->client.e.state.rot.changes;
+                  bd->changed = 1;
+               }
+             else ang = bd->client.e.state.rot.curr;
+
+             hint = _e_border_rotation_geom_get(bd, bd->zone, ang, &x, &y, &w, &h, &move);
+             if (hint)
+               {
+                  _e_border_move_resize_internal(bd, x, y, w, h, EINA_TRUE, move);
+                  ELBF(ELBT_ROT, 0, bd->client.win, "RESIZE_BY_HINT name:%s (%d,%d) %dx%d",
+                       bd->client.icccm.name, x, y, w, h);
+               }
+          }
+     }
+#endif
+
    if (bd->need_reparent)
      {
         if (!bd->internal)
@@ -10952,6 +11432,12 @@ _e_border_eval(E_Border *bd)
    bd->changes.stack = 0;
    bd->changes.prop = 0;
 
+   if (bd->client.e.state.rot.changes != -1)
+     {
+        e_border_rotation_set(bd, bd->client.e.state.rot.changes);
+        bd->client.e.state.rot.changes = -1;
+     }
+
    if ((bd->take_focus) || (bd->want_focus))
      {
         bd->take_focus = 0;
@@ -11528,15 +12014,50 @@ _e_border_event_border_unfullscreen_free(void *data __UNUSED__,
 
 #ifdef _F_ZONE_WINDOW_ROTATION_
 static void
-_e_border_event_border_rotation_free(void *data __UNUSED__,
-                                     void      *ev)
+_e_border_event_border_rotation_change_begin_free(void *data __UNUSED__,
+                                                  void      *ev)
 {
-   E_Event_Border_Rotation *e;
+   E_Event_Border_Rotation_Change_Begin *e;
+   e = ev;
+   e_object_unref(E_OBJECT(e->border));
+   E_FREE(e);
+}
 
+static void
+_e_border_event_border_rotation_change_cancel_free(void *data __UNUSED__,
+                                                   void      *ev)
+{
+   E_Event_Border_Rotation_Change_Cancel *e;
    e = ev;
    e_object_unref(E_OBJECT(e->border));
    E_FREE(e);
 }
+
+static void
+_e_border_event_border_rotation_change_end_free(void *data __UNUSED__,
+                                                void      *ev)
+{
+   E_Event_Border_Rotation_Change_End *e;
+   e = ev;
+   e_object_unref(E_OBJECT(e->border));
+   E_FREE(e);
+}
+
+static void
+_e_border_event_border_rotation_change_begin_send(E_Border *bd)
+{
+   E_Event_Border_Rotation_Change_Begin *ev = NULL;
+   ev = E_NEW(E_Event_Border_Rotation_Change_End, 1);
+   if (ev)
+     {
+        ev->border = bd;
+        e_object_ref(E_OBJECT(bd));
+        ecore_event_add(E_EVENT_BORDER_ROTATION_CHANGE_BEGIN,
+                        ev,
+                        _e_border_event_border_rotation_change_begin_free,
+                        NULL);
+     }
+}
 #endif
 
 static void
@@ -11576,6 +12097,8 @@ _e_border_zone_update(E_Border *bd)
 static int
 _e_border_resize_begin(E_Border *bd)
 {
+   int ret;
+
    if (!bd->lock_user_stacking)
      {
         if (e_config->border_raise_on_mouse_action)
@@ -11585,7 +12108,12 @@ _e_border_resize_begin(E_Border *bd)
        (bd->fullscreen) || (bd->lock_user_size))
      return 0;
 
-   if (grabbed && !e_grabinput_get(bd->win, 0, bd->win))
+   if (bd->client.icccm.accepts_focus || bd->client.icccm.take_focus)
+     ret = e_grabinput_get(bd->win, 0, bd->win);
+   else
+     ret = e_grabinput_get(bd->win, 0, 0);
+
+   if (grabbed && !ret)
      {
         grabbed = 0;
         return 0;
@@ -11653,6 +12181,7 @@ _e_border_resize_update(E_Border *bd)
 static int
 _e_border_move_begin(E_Border *bd)
 {
+   int ret;
    if (!bd->lock_user_stacking)
      {
         if (e_config->border_raise_on_mouse_action)
@@ -11661,7 +12190,12 @@ _e_border_move_begin(E_Border *bd)
    if ((bd->fullscreen) || (bd->lock_user_location))
      return 0;
 
-   if (grabbed && !e_grabinput_get(bd->win, 0, bd->win))
+   if (bd->client.icccm.accepts_focus || bd->client.icccm.take_focus)
+     ret = e_grabinput_get(bd->win, 0, bd->win);
+   else
+     ret = e_grabinput_get(bd->win, 0, 0);
+
+   if (grabbed && !ret)
      {
         grabbed = 0;
         return 0;