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
This commit is contained in:
Mike Blumenkrantz 2016-01-14 15:10:03 -05:00
parent 4d55682362
commit bdd175a47a
7 changed files with 197 additions and 123 deletions

View File

@ -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);

View File

@ -37,6 +37,7 @@ struct _E_Desk
Evas_Object *bg_object;
unsigned int animate_count;
Eina_Inlist *obstacles;
};
struct _E_Event_Desk_Show

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;
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;
x0 = 0;
yy0 = 0;
x1 = zone->w;
yy1 = zone->h;
shelves = e_shelf_list_all();
EINA_LIST_FREE(shelves, shelf)
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 (!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)
{
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)
{
/* 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);
}

View File

@ -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;