area_t: make it smaller, use arrays instead of lists.

Make area_t smaller so that it fits in an uint64_t using 4 {u,}int16_t's
for it. Note that xcb uses the very same structure, so we aren't loosing
any information while remaining very small.

This is better to use arrays in term of:
* memory access when iterating over area_t's;
* allocation because area_t's have no *next/*prev members anymore, which
  makes it a tiny structure (8 octets);
* allocation because we allocate area_t's by vector of'em rather than one
  by one.

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
This commit is contained in:
Julien Danjou 2008-06-22 22:09:48 +02:00
parent dc6373488f
commit 46f03fd6a6
10 changed files with 100 additions and 92 deletions

View File

@ -923,7 +923,7 @@ draw_image(draw_context_t *ctx, int x, int y, int wanted_h, draw_image_t *image)
area_t
draw_get_image_size(const char *filename)
{
area_t size = { -1, -1, -1, -1, NULL, NULL };
area_t size = { 0, 0, 0, 0 };
Imlib_Image image;
Imlib_Load_Error e = IMLIB_LOAD_ERROR_NONE;
@ -997,7 +997,7 @@ draw_text_extents(xcb_connection_t *conn, int phys_screen, font_t *font, const c
PangoLayout *layout;
PangoRectangle ext;
xcb_screen_t *s = xutil_screen_get(conn, phys_screen);
area_t geom = { 0, 0, 0, 0, NULL, NULL };
area_t geom = { 0, 0, 0, 0 };
ssize_t len;
draw_parser_data_t parser_data;
@ -1160,66 +1160,67 @@ xcolor_new(xcb_connection_t *conn, int phys_screen, const char *colstr, xcolor_t
/** Remove a area from a list of them,
* spliting the space between several area that can overlap
* \param head list head
* \param elem area to remove
* \param areas array of areas.
* \param elem area to remove
*/
void
area_list_remove(area_t **head, area_t *elem)
area_array_remove(area_array_t *areas, area_t elem)
{
area_t *r, inter, *extra, *rnext;
for(r = *head; r; r = rnext)
/* loop from the end because:
* (1) we remove elements ;
* (2) the one we add to the end are okay wrt the invariants
*/
for (int i = areas->len - 1; i >= 0; i--)
{
rnext = r->next;
if(area_intersect_area(*r, *elem))
if(area_intersect_area(areas->tab[i], elem))
{
/* remove it from the list */
area_list_detach(head, r);
area_t r = area_array_take(areas, i);
area_t inter = area_get_intersect_area(r, elem);
inter = area_get_intersect_area(*r, *elem);
if(AREA_LEFT(inter) > AREA_LEFT(*r))
if(AREA_LEFT(inter) > AREA_LEFT(r))
{
extra = p_new(area_t, 1);
extra->x = r->x;
extra->y = r->y;
extra->width = AREA_LEFT(inter) - r->x;
extra->height = r->height;
area_list_append(head, extra);
area_t extra = {
.x = r.x,
.y = r.y,
.width = AREA_LEFT(inter) - r.x,
.height = r.height,
};
area_array_append(areas, extra);
}
if(AREA_TOP(inter) > AREA_TOP(*r))
if(AREA_TOP(inter) > AREA_TOP(r))
{
extra = p_new(area_t, 1);
extra->x = r->x;
extra->y = r->y;
extra->width = r->width;
extra->height = AREA_TOP(inter) - r->y;
area_list_append(head, extra);
area_t extra = {
.x = r.x,
.y = r.y,
.width = r.width,
.height = AREA_TOP(inter) - r.y,
};
area_array_append(areas, extra);
}
if(AREA_RIGHT(inter) < AREA_RIGHT(*r))
if(AREA_RIGHT(inter) < AREA_RIGHT(r))
{
extra = p_new(area_t, 1);
extra->x = AREA_RIGHT(inter);
extra->y = r->y;
extra->width = AREA_RIGHT(*r) - AREA_RIGHT(inter);
extra->height = r->height;
area_list_append(head, extra);
area_t extra = {
.x = AREA_RIGHT(inter),
.y = r.y,
.width = AREA_RIGHT(r) - AREA_RIGHT(inter),
.height = r.height,
};
area_array_append(areas, extra);
}
if(AREA_BOTTOM(inter) < AREA_BOTTOM(*r))
if(AREA_BOTTOM(inter) < AREA_BOTTOM(r))
{
extra = p_new(area_t, 1);
extra->x = r->x;
extra->y = AREA_BOTTOM(inter);
extra->width = r->width;
extra->height = AREA_BOTTOM(*r) - AREA_BOTTOM(inter);
area_list_append(head, extra);
area_t extra = {
.x = r.x,
.y = AREA_BOTTOM(inter),
.width = r.width,
.height = AREA_BOTTOM(r) - AREA_BOTTOM(inter),
};
area_array_append(areas, extra);
}
/* delete the elem since we removed it from the list */
p_delete(&r);
}
}
}

View File

@ -27,7 +27,7 @@
#include <xcb/xcb.h>
#include "common/util.h"
#include "common/array.h"
#include "common/list.h"
typedef struct
@ -52,14 +52,13 @@ typedef struct area_t area_t;
struct area_t
{
/** Co-ords of upper left corner */
int x;
int y;
int width;
int height;
area_t *prev, *next;
int16_t x;
int16_t y;
uint16_t width;
uint16_t height;
};
DO_SLIST(area_t, area, p_delete)
DO_ARRAY(area_t, area, DO_NOTHING);
#define AREA_LEFT(a) ((a).x)
#define AREA_TOP(a) ((a).y)
@ -171,7 +170,7 @@ area_t draw_text_extents(xcb_connection_t *, int, font_t *, const char *);
alignment_t draw_align_get_from_str(const char *);
bool xcolor_new(xcb_connection_t *, int, const char *, xcolor_t *);
void area_list_remove(area_t **, area_t *);
void area_array_remove(area_array_t *, area_t);
#endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -58,6 +58,8 @@ typedef struct
/** \brief replace \c NULL strings with emtpy strings */
#define NONULL(x) (x ? x : "")
#define DO_NOTHING(...)
#undef MAX
#undef MIN
#define MAX(a,b) ((a) < (b) ? (b) : (a))

View File

@ -59,7 +59,6 @@ screen_xsitoarea(xcb_xinerama_screen_info_t si)
a.y = si.y_org;
a.width = si.width;
a.height = si.height;
a.next = a.prev = NULL;
return a;
}

View File

@ -38,7 +38,7 @@ _tile(int screen, const position_t position)
unsigned int mw = 0, mh = 0;
int n, i, masterwin = 0, otherwin = 0;
int real_ncol = 1, win_by_col = 1, current_col = 0;
area_t area, geometry = { 0, 0, 0, 0, NULL, NULL };
area_t area, geometry = { 0, 0, 0, 0 };
client_t *c;
tag_t **curtags = tags_get_current(screen);

View File

@ -243,7 +243,7 @@ mouse_infobox_draw(draw_context_t *ctx,
simple_window_t *sw,
area_t geometry, int border)
{
area_t draw_geometry = { 0, 0, ctx->width, ctx->height, NULL, NULL };
area_t draw_geometry = { 0, 0, ctx->width, ctx->height };
char size[64];
snprintf(size, sizeof(size), "<text align=\"center\"/>%dx%d+%d+%d",

View File

@ -68,20 +68,18 @@ area_t
placement_smart(client_t *c)
{
client_t *client;
area_t newgeometry = { 0, 0, 0, 0, NULL, NULL };
area_t *screen_geometry, *arealist = NULL, *r;
area_t newgeometry = { 0, 0, 0, 0 };
area_t screen_geometry;
area_array_t areas;
bool found = false;
layout_t *layout;
screen_geometry = p_new(area_t, 1);
*screen_geometry = screen_area_get(c->screen,
globalconf.screens[c->screen].statusbar,
&globalconf.screens[c->screen].padding);
screen_geometry = screen_area_get(c->screen,
globalconf.screens[c->screen].statusbar,
&globalconf.screens[c->screen].padding);
layout = layout_get_current(c->screen);
area_list_push(&arealist, screen_geometry);
area_array_append(&areas, screen_geometry);
for(client = globalconf.clients; client; client = client->next)
if((client->isfloating || layout == layout_floating)
@ -91,7 +89,7 @@ placement_smart(client_t *c)
newgeometry.width += 2 * client->border;
newgeometry.height += 2 * client->border;
newgeometry = titlebar_geometry_add(c->titlebar, c->border, newgeometry);
area_list_remove(&arealist, &newgeometry);
area_array_remove(&areas, newgeometry);
}
newgeometry.x = c->f_geometry.x;
@ -99,20 +97,29 @@ placement_smart(client_t *c)
newgeometry.width = 0;
newgeometry.height = 0;
for(r = arealist; r; r = r->next)
for(int i = 0; i < areas.len; i++)
{
area_t *r = &areas.tab[i];
if(r->width >= c->f_geometry.width && r->height >= c->f_geometry.height
&& r->width * r->height > newgeometry.width * newgeometry.height)
{
found = true;
newgeometry = *r;
}
}
/* we did not found a space with enough space for our size:
* just take the biggest available and go in */
if(!found)
for(r = arealist; r; r = r->next)
if(r->width * r->height > newgeometry.width * newgeometry.height)
newgeometry = *r;
{
for(int i = 0; i < areas.len; i++)
{
area_t *r = &areas.tab[i];
if(r->width * r->height > newgeometry.width * newgeometry.height)
newgeometry = *r;
}
}
/* restore height and width */
newgeometry.width = c->f_geometry.width;
@ -122,8 +129,7 @@ placement_smart(client_t *c)
newgeometry = placement_fix_offscreen(newgeometry, c->screen, c->border);
newgeometry = titlebar_geometry_remove(c->titlebar, c->border, newgeometry);
area_list_wipe(&arealist);
area_array_wipe(&areas);
return newgeometry;
}

View File

@ -82,7 +82,7 @@ screen_area_get(int screen, statusbar_t *statusbar, padding_t *padding)
area_t
display_area_get(int phys_screen, statusbar_t *statusbar, padding_t *padding)
{
area_t area = { 0, 0, 0, 0, NULL, NULL };
area_t area = { 0, 0, 0, 0 };
statusbar_t *sb;
xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);

View File

@ -143,7 +143,7 @@ widget_render(widget_node_t *wnode, draw_context_t *ctx, xcb_gcontext_t gc, xcb_
char *data;
xcb_get_property_reply_t *prop_r;
xcb_get_property_cookie_t prop_c;
area_t rectangle = { 0, 0, 0, 0, NULL, NULL };
area_t rectangle = { 0, 0, 0, 0 };
xcb_atom_t rootpix_atom;
xutil_intern_atom_request_t rootpix_atom_req;

View File

@ -33,14 +33,14 @@ typedef struct taglist_drawn_area_t taglist_drawn_area_t;
struct taglist_drawn_area_t
{
void *object;
area_t *area;
area_array_t areas;
taglist_drawn_area_t *next, *prev;
};
static void
taglist_drawn_area_delete(taglist_drawn_area_t **a)
{
area_list_wipe(&(*a)->area);
area_array_wipe(&(*a)->areas);
p_delete(a);
}
@ -138,7 +138,7 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w,
client_t *sel = globalconf.focus->client;
screen_t *vscreen = &globalconf.screens[screen];
int i = 0, prev_width = 0;
area_t *area, rectangle = { 0, 0, 0, 0, NULL, NULL };
area_t area, rectangle = { 0, 0, 0, 0 };
char **text = NULL;
taglist_drawn_area_t *tda;
@ -157,48 +157,47 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w,
taglist_drawn_area_list_push(&data->drawn_area, tda);
}
area_list_wipe(&tda->area);
tda->areas.len = 0;
/* First compute text and widget width */
for(tag = vscreen->tags; tag; tag = tag->next, i++)
{
p_realloc(&text, i + 1);
area = p_new(area_t, 1);
text[i] = taglist_text_get(tag, data);
text[i] = tag_markup_parse(tag, text[i], a_strlen(text[i]));
*area = draw_text_extents(ctx->connection, ctx->phys_screen,
area = draw_text_extents(ctx->connection, ctx->phys_screen,
globalconf.font, text[i]);
if (data->show_empty || tag->selected || tag_isoccupied(tag))
w->area.width += area->width;
w->area.width += area.width;
area_list_append(&tda->area, area);
area_array_append(&tda->areas, area);
}
/* Now that we have widget width we can compute widget x coordinate */
w->area.x = widget_calculate_offset(ctx->width, w->area.width,
offset, w->widget->align);
for(area = tda->area, tag = vscreen->tags, i = 0;
tag && area;
tag = tag->next, area = area->next, i++)
for(i = 0, tag = vscreen->tags; tag && i < tda->areas.len; i++, tag = tag->next)
{
area_t *r = &tda->areas.tab[i];
if (!data->show_empty && !tag->selected && !tag_isoccupied(tag))
{
p_delete(&text[i]);
continue;
}
area->x = w->area.x + prev_width;
prev_width += area->width;
draw_text(ctx, globalconf.font, *area, text[i]);
r->x = w->area.x + prev_width;
prev_width += r->width;
draw_text(ctx, globalconf.font, *r, text[i]);
p_delete(&text[i]);
if(tag_isoccupied(tag))
{
rectangle.width = rectangle.height = (globalconf.font->height + 2) / 3;
rectangle.x = area->x;
rectangle.y = area->y;
rectangle.x = r->x;
rectangle.y = r->y;
draw_rectangle(ctx, rectangle, 1.0,
sel && is_client_tagged(sel, tag), ctx->fg);
}
@ -228,16 +227,17 @@ taglist_button_press(widget_node_t *w,
button_t *b;
taglist_data_t *data = w->widget->data;
taglist_drawn_area_t *tda;
area_t *area;
tag_t *tag;
int i;
/* Find the good drawn area list */
for(tda = data->drawn_area; tda && tda->object != object; tda = tda->next);
area = tda->area;
for(b = w->widget->buttons; b; b = b->next)
if(ev->detail == b->button && CLEANMASK(ev->state) == b->mod && b->fct)
for(tag = vscreen->tags; tag && area; tag = tag->next, area = area->next)
for(i = 0, tag = vscreen->tags; tag && i < tda->areas.len; tag = tag->next, i++)
{
area_t *area = &tda->areas.tab[i];
if(ev->event_x >= AREA_LEFT(*area)
&& ev->event_x < AREA_RIGHT(*area)
&& (data->show_empty || tag->selected || tag_isoccupied(tag)) )
@ -247,6 +247,7 @@ taglist_button_press(widget_node_t *w,
luaA_dofunction(globalconf.L, b->fct, 2);
return;
}
}
}
static widget_tell_status_t