Support tizen_move_resize iface 19/186619/11
authorJuyeon Lee <juyeonne.lee@samsung.com>
Mon, 13 Aug 2018 02:01:49 +0000 (11:01 +0900)
committerJuyeon Lee <juyeonne.lee@samsung.com>
Mon, 10 Sep 2018 11:29:45 +0000 (11:29 +0000)
Client window is driven its move,resize by display server using xdg_shell.
btw some tizen application wants to make its position and size while they're shown
server received tz_position, and resized buffer in consequence so far.
but client's position, and buffer delivery does not always come to server at the
same idler loop. In that case, user could see move first, and resize after a sec.
here, added new wl protocol and make the move and resize happen at the sametime.

Change-Id: Idfa4c08fe63dae58c597f9d9076d66bba569c8c5

src/bin/e_client.c
src/bin/e_client.h
src/bin/e_comp_object.c
src/bin/e_comp_wl.c
src/bin/e_comp_wl.h
src/bin/e_policy.c
src/bin/e_policy_wl.c

index a64aed3266eb448b140fa5ec9864a87635c03c58..c83a906b7b4e8597056b55354656d2f5e783b422 100644 (file)
@@ -6921,3 +6921,29 @@ e_client_visibility_force_obscured_set(E_Client *ec, Eina_Bool set)
    ec->visibility.force_obscured = set;
    e_client_visibility_calculate();
 }
+
+/* tizen_move_resize */
+EINTERN Eina_Bool
+e_client_pending_geometry_has(E_Client *ec)
+{
+   if (!eina_list_count(ec->surface_sync.pending_geometry))
+     return EINA_FALSE;
+
+   return ec->surface_sync.wait_commit;
+}
+
+EINTERN void
+e_client_pending_geometry_flush(E_Client *ec)
+{
+   E_Client_Pending_Geometry *geo;
+
+   if (!eina_list_count(ec->surface_sync.pending_geometry))
+     {
+        EINA_LIST_FREE(ec->surface_sync.pending_geometry, geo)
+          {
+             E_FREE(geo);
+          }
+        ec->surface_sync.wait_commit = EINA_FALSE;
+        ELOGF("POSSIZE", "pending geometry has flushed", ec->pixmap, ec);
+     }
+}
index 3fe06a8f4136f5ecc8dd2c7a4006e3edf52d9244..8a55df96ae603d359c57426d3382c5c97719cd9c 100644 (file)
@@ -203,6 +203,7 @@ typedef struct E_Client E_Client;
 typedef struct E_Event_Client E_Event_Client;
 typedef struct _E_Event_Client_Property E_Event_Client_Property;
 typedef struct _E_Client_Pending_Resize E_Client_Pending_Resize;
+typedef struct _E_Client_Pending_Geometry E_Client_Pending_Geometry;
 typedef struct E_Event_Client_Zone_Set E_Event_Client_Zone_Set;
 typedef struct E_Event_Client_Desk_Set E_Event_Client_Desk_Set;
 typedef struct _E_Client_Hook E_Client_Hook;
@@ -313,6 +314,20 @@ struct _E_Client_Pending_Resize
    unsigned int  serial;
 };
 
+typedef enum
+{
+   E_GEOMETRY_NONE = 0,
+   E_GEOMETRY_POS  = (1 << 0),
+   E_GEOMETRY_SIZE = (1 << 1)
+} E_Client_Demand_Geometry;
+
+struct _E_Client_Pending_Geometry
+{
+   E_Client_Demand_Geometry      mode;
+   int                           x, y, w, h;
+   unsigned int                  serial;
+};
+
 struct E_Client
 {
    E_Object e_obj_inherit;
@@ -943,6 +958,13 @@ struct E_Client
    Eina_Bool skip_save_img: 1; // indicates that window doesn't want to save its image file
 
    E_Hwc_Window *hwc_window; // hwc window for the tdm_hwc.
+
+   struct
+     {
+        Eina_Bool    wait_commit;
+        unsigned int serial : 1;
+        Eina_List    *pending_geometry; // E_Client_Pending_Geometry
+     } surface_sync;
 };
 
 #define e_client_focus_policy_click(ec) \
@@ -1127,6 +1149,9 @@ E_API void e_client_stay_within_canvas_margin(E_Client *ec);
 
 EINTERN void e_client_revert_focus(E_Client *ec);
 
+EINTERN void      e_client_pending_geometry_flush(E_Client *ec);
+EINTERN Eina_Bool e_client_pending_geometry_has(E_Client *ec);
+
 /**
  * Move window to coordinates that do not account client decorations yet.
  *
index 1d78443ed460aa9269be1e502a86da8bc775afb1..31533f3a9681ade418db3548f315b504bbf8b984 100644 (file)
@@ -1322,6 +1322,14 @@ _e_comp_intercept_move(void *data, Evas_Object *obj, int x, int y)
      }
    /* only update during resize if triggered by resize */
    if (e_client_util_resizing_get(cw->ec) && (!cw->force_move)) return;
+   /* delay to move while surface waits paired commit serial*/
+   if (e_client_pending_geometry_has(cw->ec))
+     {
+        cw->ec->changes.pos = 1;
+        EC_CHANGED(cw->ec);
+        return;
+     }
+
    cw->ec->x = x, cw->ec->y = y;
    if (cw->ec->new_client)
      {
@@ -1436,6 +1444,12 @@ _e_comp_intercept_resize(void *data, Evas_Object *obj, int w, int h)
         /* netwm sync resizes queue themselves and then trigger later on */
         _e_comp_object_client_pending_resize_add(cw->ec, iw, ih, cw->ec->netwm.sync.serial);
      }
+   if (e_client_pending_geometry_has(cw->ec))
+     {
+        /* do nothing while waiting paired commit serial*/
+        return;
+     }
+
    cw->ec->w = w, cw->ec->h = h;
    if ((!cw->ec->shading) && (!cw->ec->shaded))
      {
index b479538872ca9df7a38e725c57839d68fbefea96..1e40f852eefa84240f9fb41d97eba5d6d3f0e721 100644 (file)
@@ -33,6 +33,7 @@ static void _e_comp_wl_subsurface_restack_bg_rectangle(E_Client *ec);
 static void _e_comp_wl_subsurface_check_below_bg_rectangle(E_Client *ec);
 static void _e_comp_wl_subsurface_show(E_Client *ec);
 static void _e_comp_wl_subsurface_hide(E_Client *ec);
+static void _e_comp_wl_move_resize_init(void);
 
 static E_Client * _e_comp_wl_client_usable_get(pid_t pid, E_Pixmap *ep);
 
@@ -2639,9 +2640,7 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
         if ((ec->comp_data->shell.surface) &&
             (ec->comp_data->shell.configure))
           {
-             ec->comp_data->shell.configure(ec->comp_data->shell.surface,
-                                            x, y,
-                                            ec->w, ec->h);
+             e_comp_wl_commit_sync_configure(ec);
           }
         else
           {
@@ -4847,6 +4846,7 @@ e_comp_wl_init(void)
    e_comp_wl_screenshooter_init();
    e_comp_wl_video_init();
    e_comp_wl_viewport_init();
+   _e_comp_wl_move_resize_init();
 
    /* add event handlers to catch E events */
    E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREEN_CHANGE,            _e_comp_wl_cb_randr_change,        NULL);
@@ -6250,3 +6250,216 @@ e_comp_wl_output_find(E_Client *ec)
 
    return NULL;
 }
+
+
+// --------------------------------------------------------
+// tizen_move_resize
+// --------------------------------------------------------
+EINTERN Eina_Bool
+e_comp_wl_commit_sync_client_geometry_add(E_Client *ec,
+                                          E_Client_Demand_Geometry mode,
+                                          uint32_t serial,
+                                          int32_t x,
+                                          int32_t y,
+                                          int32_t w,
+                                          int32_t h)
+{
+   E_Client_Pending_Geometry *geo;
+
+   if (!ec) goto err;
+   if (e_object_is_del(E_OBJECT(ec))) goto err;
+   if (ec->new_client || ec->fullscreen || ec->maximized) goto err;
+   if (mode == E_GEOMETRY_NONE) goto err;
+
+   geo = E_NEW(E_Client_Pending_Geometry, 1);
+   if (!geo) goto err;
+
+   geo->serial = serial;
+   geo->mode = mode;
+   if (mode & E_GEOMETRY_POS)
+     {
+        geo->x = x;
+        geo->y = y;
+     }
+   if (mode & E_GEOMETRY_SIZE)
+     {
+        geo->w = w;
+        geo->h = h;
+     }
+
+   ec->surface_sync.pending_geometry = eina_list_append(ec->surface_sync.pending_geometry, geo);
+   ec->surface_sync.wait_commit = EINA_TRUE;
+
+   return EINA_TRUE;
+
+err:
+   ELOGF("POSSIZE", "Could not add geometry(new:%d full:%d max:%d)", ec->pixmap, ec, ec->new_client, ec->fullscreen, ec->maximized);
+   return EINA_FALSE;
+}
+
+EINTERN Eina_Bool
+e_comp_wl_commit_sync_configure(E_Client *ec)
+{
+   Eina_List *l;
+   E_Client_Pending_Geometry *geo;
+   E_Client_Demand_Geometry change = 0;
+   int bw, bh;
+   struct
+     {
+        int x, y, w, h;
+     } config;
+
+   if (!ec || !ec->frame) goto ret;
+   if (e_object_is_del(E_OBJECT(ec))) goto ret;
+
+   bw = bh = 0;
+   config.x = ec->x; config.y = ec->y; config.w = ec->w; config.h = ec->h;
+   //if (!e_pixmap_size_get(ec->pixmap, &bw, &bh)) goto err;
+   e_pixmap_size_get(ec->pixmap, &bw, &bh);
+
+   if (eina_list_count(ec->surface_sync.pending_geometry))
+     {
+        EINA_LIST_FOREACH(ec->surface_sync.pending_geometry, l, geo)
+          {
+             if (geo->serial <= ec->surface_sync.serial)
+               {
+                  if (geo->mode & E_GEOMETRY_SIZE)
+                    {
+                       config.w = geo->w; config.h = geo->h;
+                    }
+                  if (geo->mode & E_GEOMETRY_POS)
+                    {
+                       config.x = geo->x; config.y = geo->y;
+                    }
+                  change |= geo->mode;
+                  ec->surface_sync.pending_geometry = eina_list_remove(ec->surface_sync.pending_geometry, geo);
+                  E_FREE(geo);
+               }
+          }
+
+        if (change & E_GEOMETRY_SIZE)
+          {
+             if ((config.w != ec->w) || (config.h != ec->h))
+               {
+                  ec->w = config.w;
+                  ec->h = config.h;
+                  ec->changes.size = EINA_TRUE;
+                  EC_CHANGED(ec);
+               }
+          }
+
+        if (change & E_GEOMETRY_POS)
+          {
+             ec->x = ec->client.x = ec->desk->geom.x + config.x;
+             ec->y = ec->client.y = ec->desk->geom.y + config.y;
+             ec->placed = 1;
+             ec->changes.pos = 1;
+             EC_CHANGED(ec);
+          }
+
+        if (change)
+          ELOGF("POSSIZE", "Configure pending geometry mode:%d(%d,%d - %dx%d)", ec->pixmap, ec, change, ec->x, ec->y, ec->w, ec->h);
+     }
+
+   // cw interceptor(move,resize) won't work if wait_commit is TRUE
+   ec->surface_sync.wait_commit = EINA_FALSE;
+
+   if ((ec->comp_data->shell.surface) &&
+       (ec->comp_data->shell.configure))
+     {
+        ec->comp_data->shell.configure(ec->comp_data->shell.surface,
+                                       ec->x, ec->y,
+                                       ec->w, ec->h);
+     }
+
+   // rollback wait_commit if there are pending requests remained
+   if (eina_list_count(ec->surface_sync.pending_geometry))
+     ec->surface_sync.wait_commit = EINA_TRUE;
+
+   return EINA_TRUE;
+
+err:
+   ELOGF("POSSIZE", "Could not configure geometry (%d,%d - %dx%d) bw:%d bh:%d", ec->pixmap, ec, ec->x, ec->y, ec->w, ec->h, bw, bh);
+
+ret:
+   return EINA_FALSE;
+}
+
+static void
+_tz_move_resize_iface_cb_destroy(struct wl_client *client EINA_UNUSED,
+                                 struct wl_resource *res_moveresize)
+{
+   wl_resource_destroy(res_moveresize);
+}
+
+static void
+_tz_move_resize_iface_cb_set_geometry(struct wl_client *client EINA_UNUSED,
+                                      struct wl_resource *res_moveresize,
+                                      struct wl_resource *surface,
+                                      uint32_t serial,
+                                      int32_t x,
+                                      int32_t y,
+                                      int32_t w,
+                                      int32_t h)
+{
+   /* to be implemented */
+   E_Client *ec;
+
+   ec = wl_resource_get_user_data(surface);
+   if (!ec) goto err;
+   if (!e_comp_wl_commit_sync_client_geometry_add(ec, E_GEOMETRY_POS | E_GEOMETRY_SIZE, serial, x, y, w, h)) goto err;
+   return;
+
+err:
+   ELOGF("POSSIZE", "Could not add set_geometry request(serial:%d, %d,%d - %dx%d)", ec->pixmap, ec, serial, x, y, w, h);
+}
+
+static const struct tizen_move_resize_interface _tz_move_resize_iface =
+{
+   _tz_move_resize_iface_cb_destroy,
+   _tz_move_resize_iface_cb_set_geometry,
+};
+
+static void
+_tz_moveresize_cb_bind(struct wl_client *client,
+                       void *data EINA_UNUSED,
+                       uint32_t ver,
+                       uint32_t id)
+{
+   struct wl_resource *res_moveresize;
+
+   res_moveresize = wl_resource_create(client,
+                                       &tizen_move_resize_interface,
+                                       ver,
+                                       id);
+   EINA_SAFETY_ON_NULL_GOTO(res_moveresize, err);
+
+
+   wl_resource_set_implementation(res_moveresize,
+                                  &_tz_move_resize_iface,
+                                  NULL,
+                                  NULL);
+   return;
+
+err:
+   ERR("Could not create tizen_move_resize_interface res: %m");
+   wl_client_post_no_memory(client);
+}
+
+static void
+_e_comp_wl_move_resize_init(void)
+{
+   if (!e_comp_wl) return;
+   if (!e_comp_wl->wl.disp) return;
+
+   if (!wl_global_create(e_comp_wl->wl.disp,
+                         &tizen_move_resize_interface,
+                         1,
+                         NULL,
+                         _tz_moveresize_cb_bind))
+     {
+        ERR("Could not create tizen_move_resize_interface to wayland globals: %m");
+     }
+
+   return;
+}
index 1ad68a7d5e54968e5a363e86922475766632285c..b4e6653bbb32e0fb033629c79b8c026e0a56e6a9 100644 (file)
@@ -574,5 +574,7 @@ E_API void e_comp_wl_subsurface_stack_update(E_Client *ec);
 
 E_API extern int E_EVENT_WAYLAND_GLOBAL_ADD;
 
+EINTERN Eina_Bool e_comp_wl_commit_sync_client_geometry_add(E_Client *ec, E_Client_Demand_Geometry mode, uint32_t serial, int32_t x, int32_t y, int32_t w, int32_t h);
+EINTERN Eina_Bool e_comp_wl_commit_sync_configure(E_Client *ec);
 # endif
 #endif
index 0d41b018303863060a4cbab07fc17ff0d15aa374..65f84acb127fc5ac563c9adb1d5808dcdc9cb950 100644 (file)
@@ -2182,6 +2182,8 @@ e_policy_allow_user_geometry_set(E_Client *ec, Eina_Bool set)
         ec->lock_client_size = EINA_TRUE;
         ec->placed = 0;
         ec->netwm.type = E_WINDOW_TYPE_NORMAL;
+
+        e_client_pending_geometry_flush(ec);
         EC_CHANGED(ec);
      }
 }
index 064889cace0580a561ca926bf40015926c522a63..a3b667cb3ed2842b85bf5d3a005650907bf4e3ab 100644 (file)
@@ -1231,10 +1231,20 @@ _tzpos_iface_cb_set(struct wl_client *client EINA_UNUSED, struct wl_resource *re
 
    if (!ec->lock_client_location)
      {
-        ec->x = ec->client.x = ec->desk->geom.x + x;
-        ec->y = ec->client.y = ec->desk->geom.y + y;
-        ec->placed = 1;
-        ec->changes.pos = 1;
+        if (e_client_pending_geometry_has(ec))
+          {
+             // if there is geometry pending list, add move job at the end of the list.
+             // so client to be applied new position at the same time with the pending requests
+             // pending geometries are flushed when 'wl surface commit' and matched serial are delivered.
+             e_comp_wl_commit_sync_client_geometry_add(ec, E_GEOMETRY_POS, ec->surface_sync.serial, x, y, 0, 0);
+          }
+        else
+          {
+             ec->x = ec->client.x = ec->desk->geom.x + x;
+             ec->y = ec->client.y = ec->desk->geom.y + y;
+             ec->placed = 1;
+             ec->changes.pos = 1;
+          }
         ec->changes.tz_position = 1;
         EC_CHANGED(ec);
      }
@@ -2770,6 +2780,8 @@ _tzpol_iface_cb_floating_mode_unset(struct wl_client *client EINA_UNUSED, struct
 
    ELOGF("TZPOL", "FLOATING Unset", ec->pixmap, ec);
 
+   e_client_pending_geometry_flush(ec);
+
    _e_policy_wl_floating_mode_apply(ec, EINA_FALSE);
 }