discomfitor pushed a commit to branch master.

http://git.enlightenment.org/core/enlightenment.git/commit/?id=bdd175a47a5c5764ed96c56fc86d690570ba1ce4

commit bdd175a47a5c5764ed96c56fc86d690570ba1ce4
Author: Mike Blumenkrantz <zm...@osg.samsung.com>
Date:   Thu Jan 14 15:10:03 2016 -0500

    implement zone obstacles for calculating useful geometry
    
    these are generic objects which can be added to indicate that there
    is something blocking window placement at the edge of a screen/desk.
    this replaces the traditional method of watching shelves to calculate
    useful geometry with a managed object which will automatically trigger
    a recalc whenever it is updated, and it allows non-shelf objects to
    more easily register themselves as obstacles for window placement
---
 src/bin/e_desk.c             |   5 +
 src/bin/e_desk.h             |   1 +
 src/bin/e_int_shelf_config.c |   2 +-
 src/bin/e_shelf.c            |  57 +++++++---
 src/bin/e_shelf.h            |   2 +
 src/bin/e_zone.c             | 240 +++++++++++++++++++++++--------------------
 src/bin/e_zone.h             |  15 +++
 7 files changed, 198 insertions(+), 124 deletions(-)

diff --git a/src/bin/e_desk.c b/src/bin/e_desk.c
index 8fe0b82..01bfcd0 100644
--- a/src/bin/e_desk.c
+++ b/src/bin/e_desk.c
@@ -677,6 +677,11 @@ e_desks_count(void)
 static void
 _e_desk_free(E_Desk *desk)
 {
+   while (desk->obstacles)
+     {
+        E_Object *obs = (void*)EINA_INLIST_CONTAINER_GET(desk->obstacles, 
E_Zone_Obstacle);
+        e_object_del(obs);
+     }
    eina_stringshare_del(desk->name);
    desk->name = NULL;
    free(desk);
diff --git a/src/bin/e_desk.h b/src/bin/e_desk.h
index 4ccd6f6..389b1be 100644
--- a/src/bin/e_desk.h
+++ b/src/bin/e_desk.h
@@ -37,6 +37,7 @@ struct _E_Desk
    Evas_Object         *bg_object;
 
    unsigned int animate_count;
+   Eina_Inlist *obstacles;
 };
 
 struct _E_Event_Desk_Show
diff --git a/src/bin/e_int_shelf_config.c b/src/bin/e_int_shelf_config.c
index 1771369..d22b1a5 100644
--- a/src/bin/e_int_shelf_config.c
+++ b/src/bin/e_int_shelf_config.c
@@ -403,7 +403,7 @@ _basic_apply(E_Config_Dialog *cfd, E_Config_Dialog_Data 
*cfdata)
    else if ((!cfdata->escfg->autohide) && (cfdata->es->hidden))
      e_shelf_toggle(cfdata->es, 1);
 
-   e_zone_useful_geometry_dirty(cfdata->es->zone);
+   e_shelf_obstacles_update(cfdata->es);
    e_config_save_queue();
    cfdata->es->config_dialog = cfd;
    return 1;
diff --git a/src/bin/e_shelf.c b/src/bin/e_shelf.c
index b955b18..4957cd3 100644
--- a/src/bin/e_shelf.c
+++ b/src/bin/e_shelf.c
@@ -82,9 +82,7 @@ static const char *orient_names[] =
 E_API int E_EVENT_SHELF_RENAME = -1;
 E_API int E_EVENT_SHELF_ADD = -1;
 E_API int E_EVENT_SHELF_DEL = -1;
-static Ecore_Event_Handler *_e_shelf_gadcon_populate_handler = NULL;
-static Ecore_Event_Handler *_e_shelf_module_init_end_handler = NULL;
-static Ecore_Event_Handler *_e_shelf_zone_moveresize_handler = NULL;
+static Eina_List *handlers;
 
 static void
 _e_shelf_remaximize(E_Shelf *es)
@@ -104,6 +102,18 @@ _e_shelf_remaximize(E_Shelf *es)
      }
 }
 
+static Eina_Bool
+_e_shelf_desk_count_handler(void *d EINA_UNUSED, int t EINA_UNUSED, 
E_Event_Zone_Desk_Count_Set *ev)
+{
+   Eina_List *l;
+   E_Shelf *es;
+
+   EINA_LIST_FOREACH(shelves, l, es)
+     if (ev->zone == es->zone)
+       e_shelf_obstacles_update(es);
+   return ECORE_CALLBACK_RENEW;
+}
+
 /* externally accessible functions */
 EINTERN int
 e_shelf_init(void)
@@ -111,7 +121,8 @@ e_shelf_init(void)
    E_EVENT_SHELF_RENAME = ecore_event_type_new();
    E_EVENT_SHELF_ADD = ecore_event_type_new();
    E_EVENT_SHELF_DEL = ecore_event_type_new();
-   _e_shelf_gadcon_populate_handler = 
ecore_event_handler_add(E_EVENT_GADCON_POPULATE, 
_e_shelf_gadcon_populate_handler_cb, NULL);
+   E_LIST_HANDLER_APPEND(handlers, E_EVENT_GADCON_POPULATE, 
_e_shelf_gadcon_populate_handler_cb, NULL);
+   E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_DESK_COUNT_SET, 
_e_shelf_desk_count_handler, NULL);
    return 1;
 }
 
@@ -126,12 +137,7 @@ e_shelf_shutdown(void)
         es = eina_list_data_get(shelves);
         e_object_del(E_OBJECT(es));
      }
-   if (_e_shelf_gadcon_populate_handler)
-     _e_shelf_gadcon_populate_handler = 
ecore_event_handler_del(_e_shelf_gadcon_populate_handler);
-   if (_e_shelf_module_init_end_handler)
-     _e_shelf_module_init_end_handler = 
ecore_event_handler_del(_e_shelf_module_init_end_handler);
-   if (_e_shelf_zone_moveresize_handler)
-     _e_shelf_zone_moveresize_handler = 
ecore_event_handler_del(_e_shelf_zone_moveresize_handler);
+   E_FREE_LIST(handlers, ecore_event_handler_del);
 
    return 1;
 }
@@ -234,8 +240,6 @@ e_shelf_zone_new(E_Zone *zone, const char *name, const char 
*style, E_Layer laye
    es->h = 32;
    es->zone = zone;
    e_object_del_attach_func_set(E_OBJECT(es), _e_shelf_del_cb);
-   e_zone_useful_geometry_dirty(zone);
-
 
    es->ee = e_comp->ee;
    es->evas = e_comp->evas;
@@ -962,6 +966,31 @@ e_shelf_autohide_set(E_Shelf *es, int autohide_type)
  */
 }
 
+E_API void
+e_shelf_obstacles_update(E_Shelf *es)
+{
+   E_FREE_LIST(es->zone_obstacles, e_object_del);
+   if (es->cfg->overlap || es->cfg->autohide) return;
+   if (es->cfg->desk_show_mode)
+     {
+        Eina_List *l;
+        E_Config_Shelf_Desk *sd;
+
+        EINA_LIST_FOREACH(es->cfg->desk_list, l, sd)
+          {
+             E_Desk *desk;
+
+             desk = e_desk_at_xy_get(es->zone, sd->x, sd->y);
+             if (!desk) continue;
+             es->zone_obstacles = eina_list_append(es->zone_obstacles,
+               e_zone_obstacle_add(es->zone, desk, &(Eina_Rectangle){es->x, 
es->y, es->w, es->h}));
+          }
+     }
+   else
+     es->zone_obstacles = eina_list_append(es->zone_obstacles,
+       e_zone_obstacle_add(es->zone, NULL, &(Eina_Rectangle){es->x, es->y, 
es->w, es->h}));
+}
+
 E_API E_Shelf *
 e_shelf_config_new(E_Zone *zone, E_Config_Shelf *cf_es)
 {
@@ -992,6 +1021,7 @@ e_shelf_config_new(E_Zone *zone, E_Config_Shelf *cf_es)
      e_shelf_show(es);
 
    e_shelf_toggle(es, 0);
+   e_shelf_obstacles_update(es);
    return es;
 }
 
@@ -1108,9 +1138,8 @@ _e_shelf_free(E_Shelf *es)
    if (!es->dummy)
      _e_shelf_bindings_del(es);
 
-   if (!stopping)
-     e_zone_useful_geometry_dirty(es->zone);
    E_FREE_LIST(es->handlers, ecore_event_handler_del);
+   E_FREE_LIST(es->zone_obstacles, e_object_del);
 
    E_FREE_FUNC(es->autohide, ecore_event_handler_del);
    E_FREE_FUNC(es->hide_animator, ecore_animator_del);
diff --git a/src/bin/e_shelf.h b/src/bin/e_shelf.h
index e0ac359..9a7d9a8 100644
--- a/src/bin/e_shelf.h
+++ b/src/bin/e_shelf.h
@@ -40,6 +40,7 @@ struct _E_Shelf
    Ecore_Timer         *module_init_end_timer;
    Eina_List           *handlers;
    Ecore_Event_Handler *autohide;
+   Eina_List           *zone_obstacles;
    unsigned char        fit_along   : 1;
    unsigned char        fit_size    : 1;
    unsigned char        hidden      : 1;
@@ -94,5 +95,6 @@ E_API void             e_shelf_name_set(E_Shelf *es, const 
char *name);
 E_API void             e_shelf_rename_dialog(E_Shelf *es);
 E_API void             e_shelf_autohide_set(E_Shelf *es, int autohide_type);
 E_API Eina_Bool       e_shelf_desk_visible(const E_Shelf *es, const E_Desk 
*desk);
+E_API void e_shelf_obstacles_update(E_Shelf *es);
 #endif
 #endif
diff --git a/src/bin/e_zone.c b/src/bin/e_zone.c
index 4f19d63..baf5c92 100644
--- a/src/bin/e_zone.c
+++ b/src/bin/e_zone.c
@@ -18,6 +18,7 @@ static void        _e_zone_event_generic_free(void *data, 
void *ev);
 static void        _e_zone_object_del_attach(void *o);
 static E_Zone_Edge _e_zone_detect_edge(E_Zone *zone, Evas_Object *obj);
 static void        _e_zone_edge_move_resize(E_Zone *zone);
+static void _e_zone_obstacle_free(E_Zone_Obstacle *obs);
 
 E_API int E_EVENT_ZONE_DESK_COUNT_SET = 0;
 E_API int E_EVENT_POINTER_WARP = 0;
@@ -1220,98 +1221,49 @@ e_zone_fade_handle(E_Zone *zone, int out, double tim)
 static void
 _e_zone_useful_geometry_calc(const E_Zone *zone, int dx, int dy, int *x, int 
*y, int *w, int *h)
 {
-   const E_Shelf *shelf;
-   Eina_List *shelves;
-   int x0, x1, yy0, yy1;
-
-   x0 = 0;
-   yy0 = 0;
-   x1 = zone->w;
-   yy1 = zone->h;
-   shelves = e_shelf_list_all();
-   EINA_LIST_FREE(shelves, shelf)
+   E_Desk *desk;
+   E_Zone_Obstacle *obs;
+   Eina_Tiler *tiler;
+   int zx, zy, zw, zh;
+   Eina_Iterator *it;
+   Eina_Rectangle geom, *rect;
+   int size = 0;
+
+   zx = zone->x;
+   zy = zone->y;
+   zw = zone->w;
+   zh = zone->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_INLIST_FOREACH(zone->obstacles, obs)
      {
-        E_Config_Shelf_Desk *sd;
-        E_Gadcon_Orient orient;
-        Eina_List *ll;
-        int skip_shelf = 0;
-
-        if (shelf->zone != zone)
-          continue;
-
-        if (shelf->cfg)
-          {
-             if (shelf->cfg->overlap)
-               continue;
-
-             if (shelf->cfg->autohide)
-               continue;
-             orient = shelf->cfg->orient;
-
-             if (shelf->cfg->desk_show_mode)
-               {
-                  skip_shelf = 1;
-                  EINA_LIST_FOREACH(shelf->cfg->desk_list, ll, sd)
-                    {
-                       if (!sd) continue;
-                       if ((sd->x == dx) && (sd->y == dy))
-                         {
-                            skip_shelf = 0;
-                            break;
-                         }
-                    }
-                  if (skip_shelf)
-                    continue;
-               }
-          }
-        else
-          orient = shelf->gadcon->orient;
-
-        switch (orient)
+        if (!E_INTERSECTS(obs->x, obs->y, obs->w, obs->h, zx, zy, zw, zh)) 
continue;
+        eina_tiler_rect_del(tiler, &(Eina_Rectangle){obs->x - zx, obs->y - zy, 
obs->w, obs->h});
+     }
+   desk = e_desk_at_xy_get(zone, dx, dy);
+   if (desk)
+     {
+        EINA_INLIST_FOREACH(zone->obstacles, obs)
           {
-           /* these are non-edje orientations */
-           case E_GADCON_ORIENT_FLOAT:
-           case E_GADCON_ORIENT_HORIZ:
-           case E_GADCON_ORIENT_VERT:
-             break;
-
-           case E_GADCON_ORIENT_TOP:
-           case E_GADCON_ORIENT_CORNER_TL:
-           case E_GADCON_ORIENT_CORNER_TR:
-             if (yy0 < shelf->h)
-               yy0 = shelf->h;
-             break;
-
-           case E_GADCON_ORIENT_BOTTOM:
-           case E_GADCON_ORIENT_CORNER_BL:
-           case E_GADCON_ORIENT_CORNER_BR:
-             if (yy1 > zone->h - shelf->h)
-               yy1 = zone->h - shelf->h;
-             break;
-
-           case E_GADCON_ORIENT_LEFT:
-           case E_GADCON_ORIENT_CORNER_LT:
-           case E_GADCON_ORIENT_CORNER_LB:
-             if (x0 < shelf->w)
-               x0 = shelf->w;
-             break;
-
-           case E_GADCON_ORIENT_RIGHT:
-           case E_GADCON_ORIENT_CORNER_RT:
-           case E_GADCON_ORIENT_CORNER_RB:
-             if (x1 > zone->w - shelf->w)
-               x1 = zone->w - shelf->w;
-             break;
-
-           default:
-             break;
+             if (!E_INTERSECTS(obs->x, obs->y, obs->w, obs->h, zx, zy, zw, 
zh)) continue;
+             eina_tiler_rect_del(tiler, &(Eina_Rectangle){obs->x - zx, obs->y 
- zy, obs->w, 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 = zone->x + x0;
-   if (y) *y = zone->y + yy0;
-   if (w) *w = x1 - x0;
-   if (h) *h = yy1 - yy0;
+   if (x) *x = geom.x;
+   if (y) *y = geom.y;
+   if (w) *w = geom.w;
+   if (h) *h = geom.h;
 }
 
 /**
@@ -1324,39 +1276,20 @@ e_zone_useful_geometry_get(E_Zone *zone,
                            int *w,
                            int *h)
 {
-   E_Shelf *shelf;
    int zx, zy, zw, zh;
-   Eina_Bool calc = EINA_TRUE;
 
    E_OBJECT_CHECK(zone);
    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
 
-   if (!zone->useful_geometry.dirty)
-     {
-        Eina_List *l = e_shelf_list_all();
-        calc = EINA_FALSE;
-        EINA_LIST_FREE(l, shelf)
-          {
-             if (!shelf->cfg) continue;
-             if (shelf->cfg->desk_show_mode)
-               {
-                  _e_zone_useful_geometry_calc(zone, zone->desk_x_current, 
zone->desk_y_current, &zx, &zy, &zw, &zh);
-                  calc = EINA_TRUE;
-                  break;
-               }
-          }
-        eina_list_free(l);
-     }
-   else
-     _e_zone_useful_geometry_calc(zone, zone->desk_x_current, 
zone->desk_y_current, &zx, &zy, &zw, &zh);
-   zone->useful_geometry.dirty = 0;
-   if (calc)
+   if (zone->useful_geometry.dirty)
      {
+        _e_zone_useful_geometry_calc(zone, zone->desk_x_current, 
zone->desk_y_current, &zx, &zy, &zw, &zh);
         zone->useful_geometry.x = zx;
         zone->useful_geometry.y = zy;
         zone->useful_geometry.w = zw;
         zone->useful_geometry.h = zh;
      }
+   zone->useful_geometry.dirty = 0;
 
    if (x) *x = zone->useful_geometry.x;
    if (y) *y = zone->useful_geometry.y;
@@ -1400,6 +1333,68 @@ e_zone_useful_geometry_dirty(E_Zone *zone)
    zone->useful_geometry.h = -1;
 }
 
+E_API E_Zone_Obstacle *
+e_zone_obstacle_add(E_Zone *zone, E_Desk *desk, Eina_Rectangle *geom)
+{
+   E_Zone_Obstacle *obs;
+
+   E_OBJECT_CHECK_RETURN(zone, NULL);
+   E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, NULL);
+   if (desk)
+     {
+        E_OBJECT_CHECK_RETURN(desk, NULL);
+        E_OBJECT_TYPE_CHECK_RETURN(desk, E_DESK_TYPE, NULL);
+        if (desk->zone != zone)
+          {
+             ERR("zone != desk->zone");
+             return NULL;
+          }
+     }
+   obs = E_OBJECT_ALLOC(E_Zone_Obstacle, E_ZONE_OBSTACLE_TYPE, 
_e_zone_obstacle_free);
+   obs->x = geom->x, obs->y = geom->y;
+   obs->w = geom->w, obs->h = geom->h;
+   obs->owner = E_OBJECT(desk) ?: E_OBJECT(zone);
+   if (desk)
+     {
+        desk->obstacles = eina_inlist_append(desk->obstacles, 
EINA_INLIST_GET(obs));
+        if (desk->visible)
+          desk->zone->useful_geometry.dirty = 1;
+     }
+   else
+     {
+        zone->obstacles = eina_inlist_append(zone->obstacles, 
EINA_INLIST_GET(obs));
+        zone->useful_geometry.dirty = 1;
+     }
+   return obs;
+}
+
+E_API void
+e_zone_obstacle_modify(E_Zone_Obstacle *obs, Eina_Rectangle *geom)
+{
+   E_Zone *zone;
+   E_Desk *desk;
+
+   E_OBJECT_CHECK(obs);
+   E_OBJECT_TYPE_CHECK(obs, E_ZONE_OBSTACLE_TYPE);
+   EINA_SAFETY_ON_NULL_RETURN(geom);
+   if ((obs->x == geom->x) && (obs->y == geom->y) && (obs->w == geom->w) && 
(obs->h == geom->h))
+     return;
+   obs->x = geom->x, obs->y = geom->y;
+   obs->w = geom->w, obs->h = geom->h;
+
+   if (obs->owner->type == E_DESK_TYPE)
+     {
+        desk = (E_Desk*)obs->owner;
+        if (desk->visible)
+          desk->zone->useful_geometry.dirty = 1;
+     }
+   else
+     {
+        zone = (E_Zone*)obs->owner;
+        zone->useful_geometry.dirty = 1;
+     }
+}
+
 E_API void
 e_zone_stow(E_Zone *zone)
 {
@@ -1492,6 +1487,11 @@ _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)]));
      }
+   while (zone->obstacles)
+     {
+        E_Object *obs = (void*)EINA_INLIST_CONTAINER_GET(zone->obstacles, 
E_Zone_Obstacle);
+        e_object_del(obs);
+     }
    free(zone->desks);
    free(zone->randr2_id);
    free(zone);
@@ -1673,3 +1673,25 @@ _e_zone_edge_move_resize(E_Zone *zone)
    evas_object_geometry_set(zone->corner.bottom_left,
              zone->x + zone->w - cw - 2, zone->y + zone->h - 1, cw, 1);
 }
+
+static void
+_e_zone_obstacle_free(E_Zone_Obstacle *obs)
+{
+   E_Zone *zone;
+   E_Desk *desk;
+
+   if (obs->owner->type == E_DESK_TYPE)
+     {
+        desk = (E_Desk*)obs->owner;
+        desk->obstacles = eina_inlist_remove(desk->obstacles, 
EINA_INLIST_GET(obs));
+        if (desk->visible)
+          desk->zone->useful_geometry.dirty = 1;
+     }
+   else
+     {
+        zone = (E_Zone*)obs->owner;
+        zone->obstacles = eina_inlist_remove(zone->obstacles, 
EINA_INLIST_GET(obs));
+        zone->useful_geometry.dirty = 1;
+     }
+   free(obs);
+}
diff --git a/src/bin/e_zone.h b/src/bin/e_zone.h
index 2314fdb..bb7762e 100644
--- a/src/bin/e_zone.h
+++ b/src/bin/e_zone.h
@@ -25,11 +25,14 @@ typedef struct _E_Event_Zone_Edge           
E_Event_Zone_Edge;
 typedef struct _E_Event_Zone_Generic        E_Event_Zone_Stow;
 typedef struct _E_Event_Zone_Generic        E_Event_Zone_Unstow;
 
+typedef struct _E_Zone_Obstacle             E_Zone_Obstacle;
+
 #else
 #ifndef E_ZONE_H
 #define E_ZONE_H
 
 #define E_ZONE_TYPE (int)0xE0b0100d
+#define E_ZONE_OBSTACLE_TYPE (int)0xE0b0110d
 
 struct _E_Zone
 {
@@ -52,6 +55,7 @@ struct _E_Zone
    int          desk_x_current, desk_y_current;
    int          desk_x_prev, desk_y_prev;
    E_Desk     **desks;
+   Eina_Inlist *obstacles;
 
    Eina_List   *handlers;
 
@@ -119,6 +123,14 @@ struct _E_Event_Zone_Edge
    Eina_Bool  drag : 1;
 };
 
+struct _E_Zone_Obstacle
+{
+   E_Object     e_obj_inherit;
+   EINA_INLIST;
+   int x, y, w, h;
+   E_Object *owner;
+};
+
 EINTERN int    e_zone_init(void);
 EINTERN int    e_zone_shutdown(void);
 E_API E_Zone   *e_zone_new(int num, int id, int x, int y, int w, int h);
@@ -152,6 +164,9 @@ E_API void      e_zone_unstow(E_Zone *zone);
 
 E_API void      e_zone_fade_handle(E_Zone *zone, int out, double tim);
 
+E_API E_Zone_Obstacle *e_zone_obstacle_add(E_Zone *zone, E_Desk *desk, 
Eina_Rectangle *geom);
+E_API void e_zone_obstacle_modify(E_Zone_Obstacle *obs, Eina_Rectangle *geom);
+
 extern E_API int E_EVENT_ZONE_DESK_COUNT_SET;
 extern E_API int E_EVENT_ZONE_MOVE_RESIZE;
 extern E_API int E_EVENT_ZONE_ADD;

-- 


Reply via email to