e_zone: add E_Zone_Obstacle feature 10/292210/1
authorDoyoun Kang <doyoun.kang@samsung.com>
Fri, 28 Apr 2023 10:30:05 +0000 (19:30 +0900)
committerDoyoun Kang <doyoun.kang@samsung.com>
Tue, 2 May 2023 02:54:30 +0000 (11:54 +0900)
Change-Id: I8366c9bff5d9dc3b83b52e8831aa235a485a0858

src/bin/e_zone.c
src/bin/e_zone.h

index 4ca4828b94970884bb5efda84b51e80e979d8e3d..139e55a2d960420f012d13a6aceaf6071d761c0a 100644 (file)
@@ -1129,6 +1129,172 @@ e_zone_fade_handle(E_Zone *zone, int out, double tim)
    EINA_SAFETY_ON_NULL_RETURN(zone);
 }
 
+EINTERN Eina_Bool
+e_zone_obstacle_add(E_Zone *zone, E_Client *ec, Eina_Rectangle *geom, Eina_Bool vertical)
+{
+   E_Zone_Obstacle *obs;
+   Eina_List *l;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(geom, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(zone == ec->zone, EINA_FALSE);
+
+   // check in the list...
+   EINA_LIST_FOREACH(zone->obstacles, l, obs)
+     {
+        if (obs->ec == ec)
+          {
+             ELOGF("E_ZONE", "Already ADDED in the obstacle list", ec);
+             return EINA_TRUE;
+          }
+     }
+
+   obs = E_NEW(E_Zone_Obstacle, 1);
+   if (!obs) return EINA_FALSE;
+   obs->ec = ec;
+   obs->x = geom->x;
+   obs->y = geom->y;
+   obs->w = geom->w;
+   obs->h = geom->h;
+   obs->vertical = !!vertical;
+
+   ELOGF("E_ZONE", "ADD obstacle... geo(%d,%d,%dx%d), vertical:%d", ec, obs->x, obs->y, obs->w, obs->h, obs->vertical);
+
+   zone->obstacles = eina_list_append(zone->obstacles, obs);
+   return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_zone_obstacle_update(E_Zone *zone, E_Client *ec, Eina_Rectangle *geom, Eina_Bool vertical)
+{
+   E_Zone_Obstacle *obs;
+   Eina_List *l;
+   Eina_Bool changed = EINA_FALSE;
+
+   if (!zone) return EINA_FALSE;
+   if (!ec) return EINA_FALSE;
+   if (zone != ec->zone) return EINA_FALSE;
+
+   EINA_LIST_FOREACH(zone->obstacles, l, obs)
+     {
+        if (obs->ec == ec)
+          break;
+     }
+
+   if (!obs)
+     {
+        ELOGF("E_ZONE", "Not found in the obstacle list", ec);
+        return EINA_FALSE;
+     }
+
+   if (geom)
+     {
+        if ((obs->x != geom->x) ||
+            (obs->y != geom->y) ||
+            (obs->w != geom->w) ||
+            (obs->h != geom->h))
+          {
+             obs->x = geom->x;
+             obs->y = geom->y;
+             obs->w = geom->w;
+             obs->h = geom->h;
+             changed = EINA_TRUE;
+          }
+     }
+
+   if (obs->vertical != vertical)
+     {
+        obs->vertical = !!vertical;
+        changed = EINA_TRUE;
+     }
+
+   ELOGF("E_ZONE", "UPDATE obstacle... geo(%d,%d,%dx%d), vertical:%d", ec, obs->x, obs->y, obs->w, obs->h, obs->vertical);
+
+   if (changed)
+     {
+        // TODO: Generate event
+     }
+
+   return EINA_TRUE;
+}
+
+EINTERN void
+e_zone_obstacle_remove(E_Zone *zone, E_Client *ec)
+{
+   E_Zone_Obstacle *obs;
+   Eina_List *l, *ll;
+
+   if (!zone) return;
+   if (!ec) return;
+   if (zone != ec->zone) return;
+
+   EINA_LIST_FOREACH_SAFE(zone->obstacles, l, ll, obs)
+     {
+        if (obs->ec == ec)
+          {
+             ELOGF("E_ZONE", "REMOVE obstacle...", ec);
+             zone->obstacles = eina_list_remove_list(zone->obstacles, l);
+             E_FREE(obs);
+             break;
+          }
+     }
+}
+
+static void
+_e_zone_useful_geometry_calc(const E_Zone *zone, E_Desk *desk, int *x, int *y, int *w, int *h)
+{
+   Eina_Tiler *tiler;
+   E_Zone_Obstacle *obs;
+   Eina_List *l;
+   int zx, zy, zw, zh;
+   Eina_Iterator *it;
+   Eina_Rectangle geom = { 0 } , *rect;
+   int size = 0;
+
+   zx = zone->x;
+   zy = zone->y;
+   zw = zone->w;
+   zh = zone->h;
+
+   if (desk)
+     {
+        zx = desk->geom.x;
+        zy = desk->geom.y;
+        zw = desk->geom.w;
+        zh = desk->geom.h;
+     }
+
+   tiler = eina_tiler_new(zw, zh);
+   eina_tiler_tile_size_set(tiler, 1, 1);
+   eina_tiler_rect_add(tiler, &(Eina_Rectangle){0, 0, zw, zh});
+
+   EINA_LIST_FOREACH(zone->obstacles, l, obs)
+     {
+        if (!E_INTERSECTS(obs->x, obs->y, obs->w, obs->h, zx, zy, zw, zh)) continue;
+
+        if (obs->vertical)
+          eina_tiler_rect_del(tiler, &(Eina_Rectangle){obs->x - zx, 0, obs->w, zh});
+        else
+          eina_tiler_rect_del(tiler, &(Eina_Rectangle){0, obs->y - zy, zw, obs->h});
+     }
+
+   it = eina_tiler_iterator_new(tiler);
+   EINA_ITERATOR_FOREACH(it, rect)
+     {
+        if (rect->w * rect->h < size) continue;
+        size = rect->w * rect->h;
+        geom = *rect;
+     }
+   eina_iterator_free(it);
+   eina_tiler_free(tiler);
+
+   if (x) *x = geom.x + zx;
+   if (y) *y = geom.y + zy;
+   if (w) *w = geom.w;
+   if (h) *h = geom.h;
+}
+
 /**
  * Get (or calculate) the useful (or free, without any shelves) area.
  */
@@ -1148,6 +1314,24 @@ e_zone_useful_geometry_get(E_Zone *zone,
    if (h) *h = zone->h;
 }
 
+EINTERN void
+e_zone_desk_useful_geometry_get(E_Zone *zone, E_Desk *desk, int *x, int *y, int *w, int *h)
+{
+   E_OBJECT_CHECK(zone);
+   E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
+   E_OBJECT_CHECK(desk);
+   E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE);
+   E_OBJECT_CHECK(desk->zone);
+
+   if (desk->zone != zone)
+     {
+        ELOGF("E_ZONE", "CRI... Zone(%d) and Desk's zone(%d) mismatch!", NULL, zone->id, desk->zone->id);
+        return;
+     }
+
+   _e_zone_useful_geometry_calc(zone, desk, x, y, w, h);
+}
+
 /**
  * Mark as dirty so e_zone_useful_geometry_get() will need to recalculate.
  *
@@ -1281,6 +1465,8 @@ static void
 _e_zone_free(E_Zone *zone)
 {
    int x, y;
+   E_Zone_Obstacle *obs;
+
    //printf("@@@@@@@@@@ e_zone_free: %i %i | %i %i %ix%i = %p\n", zone->num, zone->id, zone->x, zone->y, zone->w, zone->h, zone);
    /* Delete the edge windows if they exist */
    E_FREE_FUNC(zone->edge.top, evas_object_del);
@@ -1326,6 +1512,10 @@ _e_zone_free(E_Zone *zone)
         for (y = 0; y < zone->desk_y_count; y++)
           e_object_del(E_OBJECT(zone->desks[x + (y * zone->desk_x_count)]));
      }
+   EINA_LIST_FREE(zone->obstacles, obs)
+     {
+        E_FREE(obs);
+     }
    free(zone->desks);
    free(zone->output_id);
    free(zone);
index d6d73433d65776df178ec6d0dc88fc1bcbadca28..8472ec5862ea7f71b4ca78f6c4cbc5eb4eed786e 100644 (file)
@@ -20,6 +20,7 @@ typedef enum _E_Zone_Display_State
 } E_Zone_Display_State;
 
 typedef struct _E_Zone                      E_Zone;
+typedef struct _E_Zone_Obstacle             E_Zone_Obstacle;
 
 typedef struct _E_Event_Zone_Generic        E_Event_Zone_Desk_Count_Set;
 typedef struct _E_Event_Zone_Generic        E_Event_Zone_Move_Resize;
@@ -151,6 +152,15 @@ struct _E_Zone
 
    E_Zone_Display_State display_state;
    char                 *output_id; // same id we get from e_comp_screen so look it up there
+
+   Eina_List *obstacles;
+};
+
+struct _E_Zone_Obstacle
+{
+   E_Client *ec;
+   int x, y, w, h; // obstacle area, this can not be same to ec's geometry
+   Eina_Bool vertical;
 };
 
 struct _E_Event_Zone_Generic
@@ -229,8 +239,14 @@ E_API void      e_zone_edges_desk_flip_capable(E_Zone *zone, Eina_Bool l, Eina_B
 E_API Eina_Bool e_zone_exists_direction(E_Zone *zone, E_Zone_Edge edge);
 E_API void      e_zone_edge_win_layer_set(E_Zone *zone, E_Layer layer);
 
+EINTERN Eina_Bool e_zone_obstacle_add(E_Zone *zone, E_Client *ec, Eina_Rectangle *geom, Eina_Bool vertical);
+EINTERN Eina_Bool e_zone_obstacle_update(E_Zone *zone, E_Client *ec, Eina_Rectangle *geom, Eina_Bool vertical);
+EINTERN void      e_zone_obstacle_remove(E_Zone *zone, E_Client *ec);
+
 E_API void      e_zone_useful_geometry_dirty(E_Zone *zone);
 E_API void      e_zone_useful_geometry_get(E_Zone *zone, int *x, int *y, int *w, int *h);
+EINTERN void    e_zone_desk_useful_geometry_get(E_Zone *zone, E_Desk *desk, int *x, int *y, int *w, int *h);
+
 E_API void      e_zone_stow(E_Zone *zone);
 E_API void      e_zone_unstow(E_Zone *zone);