rotation: WORKAROUND for avoiding wrong rotation complete UI. 40/117240/1
authorGwanglim Lee <gl77.lee@samsung.com>
Fri, 3 Mar 2017 10:13:27 +0000 (19:13 +0900)
committerGwanglim Lee <gl77.lee@samsung.com>
Fri, 3 Mar 2017 10:13:27 +0000 (19:13 +0900)
Until now, we have assumed that the buffer commit event after the rotation
ack event informs us of completion of rotation. However this assumption could
be wrong because the rotation ack event is dispatched by main thread of client,
whereas the buffer commit event could be dispatched by other thread.

The ideal solution for resolving this issue is introduction of same protocol
serial number between the rotation ack event and buffer commit event. But this
approach needs much of changes for EFL, E20 and DDK. Thus I have added workaround
code for quick resolving this.

We have to extend EFL, E20 and DDK to support this later.

Change-Id: I0630ce5d2e801d0fd995141e4c20f43df9aa362e

src/rotation/e_mod_rotation_wl.c

index b1fd249..6748a5e 100644 (file)
@@ -46,6 +46,14 @@ struct _Policy_Ext_Rotation
    Eina_Bool wait_update;
    Eina_Bool hint_fetch;
    uint32_t serial;
+
+   /* WORKAROUND for the client used manual rotation */
+   struct
+   {
+      Eina_Bool    use;
+      int          count;
+      Ecore_Timer *timer;
+   } wait_update_pending;
 };
 
 struct _E_Client_Rotation
@@ -159,6 +167,15 @@ static Eina_Bool _rot_intercept_hook_hide(void *d EINA_UNUSED, E_Client *ec);
 static Eina_Bool _rot_cb_idle_enterer(void *data EINA_UNUSED);
 
 static Eina_Bool
+_browser_check(E_Client *ec)
+{
+   const char *name = e_client_util_name_get(ec);
+   if (!name) return EINA_FALSE;
+   if (!strncmp(name, "browser", 7)) return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+static Eina_Bool
 _camera_check(E_Client *ec)
 {
    const char *name = e_client_util_name_get(ec);
@@ -500,8 +517,7 @@ _e_tizen_rotation_ack_angle_change_cb(struct wl_client *client,
    EINA_SAFETY_ON_NULL_RETURN(rot);
 
    ec = rot->ec;
-   if (!ec)
-     return;
+   if (!ec) return;
 
    EDBG(ec, "Rotation Done: prev %d cur %d serial %u",
         ec->e.state.rot.ang.curr,
@@ -520,9 +536,6 @@ _e_tizen_rotation_ack_angle_change_cb(struct wl_client *client,
         ec->e.state.rot.ang.prev = ec->e.state.rot.ang.curr;
         ec->e.state.rot.ang.curr = TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle);
 
-        EDBG(ec, "Rotation Done: prev %d cur %d",
-             ec->e.state.rot.ang.prev, ec->e.state.rot.ang.curr);
-
         if (TIZEN_ROTATION_ANGLE_TO_INT(rot->cur_angle) == ec->e.state.rot.ang.next)
           {
              ec->e.state.rot.ang.next = -1;
@@ -536,7 +549,35 @@ _e_tizen_rotation_ack_angle_change_cb(struct wl_client *client,
                }
              else
                {
+                  /* it means that we need the next buffer commit after rotation ack event.
+                   * once we get next buffer commit, policy module attempts to remove
+                   * this ec from rotation_list_remove. and then, rotation process is finished.
+                   */
                   rot->wait_update = EINA_TRUE;
+
+                  /* WORKAROUND
+                   *
+                   * Until now, we have assumed that the buffer commit event after the rotation
+                   * ack event informs us of completion of rotation. However this assumption could
+                   * be wrong because the rotation ack event is dispatched by main thread of client,
+                   * whereas the buffer commit event could be dispatched by other thread.
+                   *
+                   * The ideal solution for resolving this issue is introduction of same protocol
+                   * serial number between the rotation ack event and buffer commit event. But this
+                   * approach needs much of changes for EFL, E20 and DDK. Thus I have added workaround
+                   * code for quick resolving this.
+                   *
+                   * We have to extend EFL, E20 and DDK to support this later.
+                   */
+                  if (_browser_check(ec))
+                    {
+                       if (rot->wait_update_pending.timer)
+                         ecore_timer_del(rot->wait_update_pending.timer);
+
+                       rot->wait_update_pending.timer = NULL;
+                       rot->wait_update_pending.use = EINA_TRUE;
+                       rot->wait_update_pending.count = 2;
+                    }
                }
           }
      }
@@ -1418,6 +1459,7 @@ e_client_rotation_set(E_Client *ec, int rotation)
    Eina_List *list, *l;
    E_Client *child;
    int curr_rot;
+   Policy_Ext_Rotation *ext_rot;
 
    if (!ec) return EINA_FALSE;
 
@@ -1455,8 +1497,6 @@ e_client_rotation_set(E_Client *ec, int rotation)
                   TRACE_DS_END();
                   return EINA_FALSE;
                }
-             else
-               ;
           }
         else
           {
@@ -1467,6 +1507,14 @@ e_client_rotation_set(E_Client *ec, int rotation)
      }
    TRACE_DS_END();
 
+   ext_rot = eina_hash_find(rot_hash, &ec);
+   if (ext_rot)
+     {
+        if (ext_rot->wait_update_pending.timer)
+          ecore_timer_del(ext_rot->wait_update_pending.timer);
+        ext_rot->wait_update_pending.timer = NULL;
+     }
+
    // in case same with next angle.
    curr_rot = e_client_rotation_next_angle_get(ec);
    if (curr_rot == rotation)
@@ -1500,14 +1548,7 @@ e_client_rotation_set(E_Client *ec, int rotation)
         ELOGF("ROTATION", "Do rotation of child win %s(%p)",
               NULL, NULL, child->icccm.name, child);
 
-        if (e_client_rotation_set(child, rotation))
-          {
-             ;
-          }
-        else
-          {
-             ;
-          }
+        e_client_rotation_set(child, rotation);
      }
    eina_list_free(list);
 
@@ -1906,6 +1947,46 @@ _rot_cb_zone_rotation_change_begin(void *data EINA_UNUSED, int ev_type EINA_UNUS
 }
 
 static void
+_e_client_rotation_wait_update_clear(E_Client *ec)
+{
+   Policy_Ext_Rotation *rot;
+
+   rot = eina_hash_find(rot_hash, &ec);
+   if (!rot) return;
+
+   rot->wait_update_pending.timer = NULL;
+
+   _e_client_rotation_list_remove(ec);
+   if (ec->e.state.rot.pending_show)
+     {
+        ec->e.state.rot.pending_show = 0;
+        evas_object_show(ec->frame);
+        e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
+     }
+
+   if (rot->show_grab)
+     E_FREE_FUNC(rot->show_grab, e_policy_visibility_client_grab_release);
+
+   rot->wait_update = EINA_FALSE;
+}
+
+static Eina_Bool
+_e_client_rotation_wait_update_pending_timeout(void *data)
+{
+   E_Client *ec = (E_Client *)data;
+
+   if ((ec) && (!e_object_is_del(E_OBJECT(ec))))
+     WRN("Timeout Wait Update Pending %s(%p)",
+         ec->icccm.name ? ec->icccm.name : "", ec);
+   else
+     WRN("Timeout Wait Update Pending (%p)", ec);
+
+   _e_client_rotation_wait_update_clear(ec);
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
 _rot_cb_wl_buffer_change(void *d EINA_UNUSED, E_Client *ec)
 {
    Policy_Ext_Rotation *rot;
@@ -1957,20 +2038,39 @@ _rot_cb_buffer_change(void *data EINA_UNUSED, int ev_type EINA_UNUSED, E_Event_C
      }
    else if (rot->wait_update)
      {
-        DBG("Update Buffer After Rotation Done ec '%s'(%p) b %p",
-            ev->ec->icccm.name ? ev->ec->icccm.name : "", ev->ec, e_pixmap_resource_get(ev->ec->pixmap));
-        _e_client_rotation_list_remove(ev->ec);
-        if (ev->ec->e.state.rot.pending_show)
+        DBG("Update Buffer After Rotation Done ec '%s'(%p) b %p pending:%d count:%d",
+            ev->ec->icccm.name ? ev->ec->icccm.name : "",
+            ev->ec,
+            e_pixmap_resource_get(ev->ec->pixmap),
+            rot->wait_update_pending.use,
+            rot->wait_update_pending.count);
+
+        if (rot->wait_update_pending.use)
           {
-             ev->ec->e.state.rot.pending_show = 0;
-             evas_object_show(ev->ec->frame);
-             e_comp_object_damage(ev->ec->frame, 0, 0, ev->ec->w, ev->ec->h);
-          }
+             if (rot->wait_update_pending.count > 0)
+               {
+                  if (rot->wait_update_pending.count == 2)
+                    {
+                       if (rot->wait_update_pending.timer)
+                         ecore_timer_del(rot->wait_update_pending.timer);
 
-        if (rot->show_grab)
-          E_FREE_FUNC(rot->show_grab, e_policy_visibility_client_grab_release);
+                       rot->wait_update_pending.timer = ecore_timer_add(0.1f,
+                                                                        _e_client_rotation_wait_update_pending_timeout,
+                                                                        ev->ec);
+                    }
 
-        rot->wait_update = EINA_FALSE;
+                  rot->wait_update_pending.count--;
+                  return ECORE_CALLBACK_RENEW;
+               }
+             else
+               {
+                  if (rot->wait_update_pending.timer)
+                    ecore_timer_del(rot->wait_update_pending.timer);
+                  rot->wait_update_pending.timer = NULL;
+               }
+          }
+
+        _e_client_rotation_wait_update_clear(ev->ec);
      }
 
    if (ev->ec->e.state.rot.pending_show)
@@ -2026,6 +2126,10 @@ _rot_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
    ext_rot = eina_hash_find(rot_hash, &ec);
    if (ext_rot)
      {
+        if (ext_rot->wait_update_pending.timer)
+          ecore_timer_del(ext_rot->wait_update_pending.timer);
+        ext_rot->wait_update_pending.timer = NULL;
+
         EINA_LIST_FREE(ext_rot->rotation_list, res)
            wl_resource_set_user_data(res, NULL);