e_mod_main: Get non-rotated and transform coordinates when gets input panel geometry 58/315658/1
authorJunseok Kim <juns.kim@samsung.com>
Tue, 6 Aug 2024 04:18:52 +0000 (13:18 +0900)
committerJunseok Kim <juns.kim@samsung.com>
Tue, 6 Aug 2024 04:18:52 +0000 (13:18 +0900)
There were problems with the previous code as below.

 - The problem that geometry argument of _e_text_input_send_input_panel_geometry
   uses client coordinate system instead of coordinate system of display server.

 - In case of moving coordinates using transform, the e_client_transform_core_input_transform returns unexpected values

To fix these issues, makes geometry arguments to match the coordinate system of geometry, and
The module directly calculate the transform core value of the client ec showing the IME to get the correct geometry of input panel.

Change-Id: I41b8251f69affd776ae63349e3f76baeb7bdda74

src/e_mod_main.c

index f05179b2e8aee44443446def16ece6075db32a98..9e595d4b73fc248a1fe7fa163e827b0002f28ef1 100644 (file)
@@ -196,6 +196,77 @@ _e_text_input_log_show(struct wl_resource *resource, uint32_t code, const char *
    LOGE("%s() is failed. msg : %s\n", warning_msg, msg);
 }
 
+static void
+_e_text_input_transform_core_move_scale_get(E_Client *ec, int *move_x, int *move_y, double *scale_x, double *scale_y, int *angle)
+{
+   int i, count;
+   double sx = 1.0, sy = 1.0;
+   int mx = 0, my = 0;
+   int ang = 0;
+
+   if (!ec) return;
+
+   count = e_client_transform_core_transform_count_get((E_Client *)ec);
+
+   if (count <= 0) return;
+
+   for (i = 0; i < count; ++i)
+     {
+        double dsx, dsy;
+        int x = 0, y = 0, rz = 0;
+        E_Util_Transform *transform = NULL;
+
+        transform = e_client_transform_core_transform_get((E_Client *)ec, i);
+        if (!transform) continue;
+
+        e_util_transform_move_round_get(transform, &x, &y, NULL);
+        e_util_transform_scale_get(transform, &dsx, &dsy, NULL);
+        e_util_transform_rotation_round_get(transform, NULL, NULL, &rz);
+
+        mx += x;
+        my += y;
+        sx *= dsx;
+        sy *= dsy;
+        ang += rz;
+        ang = ang % 360;
+     }
+
+   if (move_x) *move_x = mx;
+   if (move_y) *move_y = my;
+   if (scale_x) *scale_x = sx;
+   if (scale_y) *scale_y = sy;
+   if (angle) *angle = ang;
+}
+
+static void
+_e_text_input_transform_core_scale_adjust(E_Client *ec, int in_x, int in_y, int in_w, int in_h, int *out_x, int *out_y, int *out_w, int *out_h, Eina_Bool reverse)
+{
+   double scale_x = 1.0, scale_y = 1.0;
+   int move_x = 0, move_y = 0;
+   int rotation_angle = 0;
+
+   if (!ec) return;
+
+   _e_text_input_transform_core_move_scale_get(ec, &move_x, &move_y, &scale_x, &scale_y, &rotation_angle);
+
+   if (!reverse)
+     {
+        if (out_x) *out_x = in_x + move_x;
+        if (out_y) *out_y = in_y + move_y;
+        if (out_w) *out_w = in_w * scale_x;
+        if (out_h) *out_h = in_h * scale_y;
+     }
+   else
+     {
+        if (out_x) *out_x = (in_x - move_x) / scale_x;
+        if (out_y) *out_y = (in_y - move_y) / scale_y;
+        if (out_w) *out_w = in_w / scale_x;
+        if (out_h) *out_h = in_h / scale_y;
+     }
+
+   // TODO: need rotation
+}
+
 static void
 _e_text_input_send_input_panel_geometry(struct wl_resource *resource, int x, int y, int w, int h)
 {
@@ -205,61 +276,176 @@ _e_text_input_send_input_panel_geometry(struct wl_resource *resource, int x, int
    int new_y = y;
    int new_w = w;
    int new_h = h;
-
+   int zx, zy, zw, zh;
+   int old_x, old_y, old_w, old_h;
+   int rot_x, rot_y, rot_w, rot_h;
    E_Client *ips_ec = NULL;
    Eina_List *l;
 
+   /* FIXME: The input geometry be changed to match the display server's coordinate system.
+      The input geometry (x, y, w, h) is given in coordinates as the input panel (keyboard) client's angle considering rotation.
+      Because this value differs from the display server's coordinate system,
+      it should be adapt to the display server's coordinate system and calculated.
+      When delivering back to the client, it must be converted to a coordinate system suitable for the client before delivery.
+      (Consider rotation and transformation.)
+
+      Accordingly, this function performs the following steps as a workaround:
+
+      1. Modify the incoming client coordinate system to match the display server's coordinate system according to the keyboard's rotation angle.
+      2. Calculate the geometry suitable for the output scale by applying the opposite values ​​of the keyboard's transform core scale and move.
+      3. Apply the transform core scale and move values ​​of client_surface_ec to calculate the geometry matching the client scale.
+      4. Change the geometry to fit the client coordinate system according to the client_surface_ec's rotation angle.
+      5. Pass the value to client_surface_ec. */
+
    if (client_surface_ec)
      {
-        angle = client_surface_ec->e.state.rot.ang.next < 0 ?
-                client_surface_ec->e.state.rot.ang.curr :
-                client_surface_ec->e.state.rot.ang.next;
-
         // find input panel
         EINA_LIST_FOREACH(client_surface_ec->transients, l, ips_ec)
           {
              if (e_input_panel_client_find(ips_ec)) break;
           }
+     }
+
+   if (!ips_ec)
+     {
+        LOGI("couldn't find input panel of client surface ec:%p", client_surface_ec);
+        E_CLIENT_REVERSE_FOREACH(ips_ec)
+          {
+             if (e_input_panel_client_find(ips_ec)) break;
+          }
+     }
+
+   // 1. Modify the incoming client coordinate system to match the display server's coordinate system according to the keyboard's rotation angle.
+   if (ips_ec)
+     {
+        angle = ips_ec->e.state.rot.ang.next < 0 ?
+            ips_ec->e.state.rot.ang.curr :
+            ips_ec->e.state.rot.ang.next;
+
+        e_client_base_output_resolution_desk_useful_geometry_get(ips_ec, &zx, &zy, &zw, &zh, EINA_TRUE);
+        LOGI("ips_ec(%p) zx(%d) zy(%d) zw(%d) zh(%d)", ips_ec, zx, zy, zw, zh);
+
+        switch (angle)
+          {
+            case 90:
+                new_x = y;
+                new_y = zh - x - w;
+                new_w = h;
+                new_h = w;
+                break;
+            case 180:
+                new_x = zw - y - h;
+                new_y = zh - x - w;
+                new_w = w;
+                new_h = h;
+                break;
+            case 270:
+                new_x = zw - y - h;
+                new_y = x;
+                new_w = h;
+                new_h = w;
+                break;
+            case 0:
+            default:
+                new_x = x;
+                new_y = y;
+                new_w = w;
+                new_h = h;
+                break;
+          }
+
+        LOGI("ips_ec(%p): angle:%d, geom(%d, %d, %dx%d) -> angle:0, geom(%d, %d, %dx%d)", ips_ec, angle, x, y, w, h, new_x, new_y, new_w, new_h);
+        x = new_x;
+        y = new_y;
+        w = new_w;
+        h = new_h;
+     }
+
+
+   if (client_surface_ec)
+     {
+        angle = client_surface_ec->e.state.rot.ang.next < 0 ?
+            client_surface_ec->e.state.rot.ang.curr :
+            client_surface_ec->e.state.rot.ang.next;
 
         LOGI("curr : %d, next : %d, angle : %d\n", client_surface_ec->e.state.rot.ang.curr,
              client_surface_ec->e.state.rot.ang.next, angle);
+     }
 
-        if (ips_ec && !(e_input_panel_floating_mode_get()))
+   // 2. Calculate the geometry suitable for the output scale by applying the opposite values ​​of the keyboard's transform core scale and move.
+   if (ips_ec && !(e_input_panel_floating_mode_get()))
+     {
+        if (e_client_transform_core_enable_get(ips_ec))
           {
-             if (e_client_transform_core_enable_get(ips_ec))
-               {
-                  e_client_transform_core_input_inv_transform(ips_ec, x, y, &new_x, &new_y);
-                  e_client_transform_core_input_inv_transform(ips_ec, w, h, &new_w, &new_h);
-                  LOGI("input panel using transform. (%d, %d, %dx%d) -> (%d, %d, %dx%d)", x, y, w, h, new_x, new_y, new_w, new_h);
-
-                  if (e_client_transform_core_enable_get(client_surface_ec))
-                    {
-                       e_client_transform_core_input_transform(client_surface_ec, new_x, new_y, &new_x, &new_y);
-                       e_client_transform_core_input_transform(client_surface_ec, new_w, new_h, &new_w, &new_h);
-                       LOGI("client_surface_ec using transform. (%d, %d, %dx%d) -> (%d, %d, %dx%d)", x, y, w, h, new_x, new_y, new_w, new_h);
-                    }
-               }
+             e_client_transform_core_input_inv_transform(ips_ec, x, y, &new_x, &new_y);
+             e_client_transform_core_input_inv_transform(ips_ec, x + w, y + h, &new_w, &new_h);
+             new_w = new_w - new_x;
+             new_h = new_h - new_y;
+             LOGI("input panel(%p) using transform. (%d, %d, %dx%d) -> (%d, %d, %dx%d)", ips_ec, x, y, w, h, new_x, new_y, new_w, new_h);
           }
-        else if (!ips_ec)
-          LOGI("couldn't find input panel client");
      }
-
-   snprintf(geometry, sizeof(geometry), "%d,%d,%d,%d", new_x, y, w, h);
+   else if (!ips_ec)
+     LOGI("couldn't find input panel client");
+
+   // 3. Apply the transform core scale and move values ​​of client_surface_ec to calculate the geometry matching the client scale.
+   if (e_client_transform_core_enable_get(client_surface_ec))
+     {
+        old_x = new_x;
+        old_y = new_y;
+        old_w = new_w;
+        old_h = new_h;
+        _e_text_input_transform_core_scale_adjust(client_surface_ec, old_x, old_y, old_w, old_h, &new_x, &new_y, &new_w, &new_h, EINA_TRUE);
+        LOGI("client_surface_ec(%p) using transform. (%d, %d, %dx%d) -> (%d, %d, %dx%d)", client_surface_ec, old_x, old_y, old_w, old_h, new_x, new_y, new_w, new_h);
+     }
+
+   // 4. Change the geometry to fit the client coordinate system according to the client_surface_ec's rotation angle.
+   e_client_base_output_resolution_desk_useful_geometry_get(client_surface_ec, &zx, &zy, &zw, &zh, EINA_TRUE);
+   LOGI("client surface ec(%p) zx(%d) zy(%d) zw(%d) zh(%d)", client_surface_ec, zx, zy, zw, zh);
+   switch (angle)
+     {
+       case 90:
+           rot_x = zh - new_y - new_h;
+           rot_y = new_x;
+           rot_w = new_h;
+           rot_h = new_w;
+           break;
+       case 180:
+           rot_x = zh - new_y - new_h;
+           rot_y = zw - new_x - new_w;
+           rot_w = new_w;
+           rot_h = new_h;
+           break;
+       case 270:
+           rot_x = new_y;
+           rot_y = zw - new_x - new_w;
+           rot_w = new_h;
+           rot_h = new_w;
+           break;
+       case 0:
+       default:
+           rot_x = new_x;
+           rot_y = new_y;
+           rot_w = new_w;
+           rot_h = new_h;
+           break;
+       LOGI("ips_ec(%p): angle:0, geom(%d, %d, %dx%d) -> angle:%d, geom(%d, %d, %dx%d)", ips_ec, new_x, new_y, new_w, new_h, angle, rot_x, rot_y, rot_w, rot_h);
+     }
+
+   // 5. Pass the value to client_surface_ec
+   snprintf(geometry, sizeof(geometry), "%d,%d,%d,%d", rot_x, rot_y, rot_w, rot_h);
 
    switch(angle)
      {
-      case 90:
-      case 270:
-         vconf_set_str(VCONFKEY_ISF_IME_RECENT_LAND_GEOMETRY, geometry);
-         break;
-      default:
-         vconf_set_str(VCONFKEY_ISF_IME_RECENT_PORT_GEOMETRY, geometry);
-         break;
+       case 90:
+       case 270:
+           vconf_set_str(VCONFKEY_ISF_IME_RECENT_LAND_GEOMETRY, geometry);
+           break;
+       default:
+           vconf_set_str(VCONFKEY_ISF_IME_RECENT_PORT_GEOMETRY, geometry);
+           break;
      }
 
-   LOGI("angle : %d, x : %d, y : %d, w : %d, h : %d\n", angle, new_x, y, w, h);
-
-   wl_text_input_send_input_panel_geometry(resource, new_x, y, w, h);
+   wl_text_input_send_input_panel_geometry(resource, rot_x, rot_y, rot_w, rot_h);
 }
 
 static gboolean