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 area_t
draw_get_image_size(const char *filename) 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_Image image;
Imlib_Load_Error e = IMLIB_LOAD_ERROR_NONE; 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; PangoLayout *layout;
PangoRectangle ext; PangoRectangle ext;
xcb_screen_t *s = xutil_screen_get(conn, phys_screen); 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; ssize_t len;
draw_parser_data_t parser_data; 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, /** Remove a area from a list of them,
* spliting the space between several area that can overlap * spliting the space between several area that can overlap
* \param head list head * \param areas array of areas.
* \param elem area to remove * \param elem area to remove
*/ */
void 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; /* loop from the end because:
* (1) we remove elements ;
for(r = *head; r; r = rnext) * (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(areas->tab[i], elem))
if(area_intersect_area(*r, *elem))
{ {
/* remove it from the list */ /* 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); area_t extra = {
extra->x = r->x; .x = r.x,
extra->y = r->y; .y = r.y,
extra->width = AREA_LEFT(inter) - r->x; .width = AREA_LEFT(inter) - r.x,
extra->height = r->height; .height = r.height,
area_list_append(head, extra); };
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); area_t extra = {
extra->x = r->x; .x = r.x,
extra->y = r->y; .y = r.y,
extra->width = r->width; .width = r.width,
extra->height = AREA_TOP(inter) - r->y; .height = AREA_TOP(inter) - r.y,
area_list_append(head, extra); };
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); area_t extra = {
extra->x = AREA_RIGHT(inter); .x = AREA_RIGHT(inter),
extra->y = r->y; .y = r.y,
extra->width = AREA_RIGHT(*r) - AREA_RIGHT(inter); .width = AREA_RIGHT(r) - AREA_RIGHT(inter),
extra->height = r->height; .height = r.height,
area_list_append(head, extra); };
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); area_t extra = {
extra->x = r->x; .x = r.x,
extra->y = AREA_BOTTOM(inter); .y = AREA_BOTTOM(inter),
extra->width = r->width; .width = r.width,
extra->height = AREA_BOTTOM(*r) - AREA_BOTTOM(inter); .height = AREA_BOTTOM(r) - AREA_BOTTOM(inter),
area_list_append(head, extra); };
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 <xcb/xcb.h>
#include "common/util.h" #include "common/array.h"
#include "common/list.h" #include "common/list.h"
typedef struct typedef struct
@ -52,14 +52,13 @@ typedef struct area_t area_t;
struct area_t struct area_t
{ {
/** Co-ords of upper left corner */ /** Co-ords of upper left corner */
int x; int16_t x;
int y; int16_t y;
int width; uint16_t width;
int height; uint16_t height;
area_t *prev, *next;
}; };
DO_SLIST(area_t, area, p_delete) DO_ARRAY(area_t, area, DO_NOTHING);
#define AREA_LEFT(a) ((a).x) #define AREA_LEFT(a) ((a).x)
#define AREA_TOP(a) ((a).y) #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 *); alignment_t draw_align_get_from_str(const char *);
bool xcolor_new(xcb_connection_t *, int, const char *, xcolor_t *); 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 #endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // 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 */ /** \brief replace \c NULL strings with emtpy strings */
#define NONULL(x) (x ? x : "") #define NONULL(x) (x ? x : "")
#define DO_NOTHING(...)
#undef MAX #undef MAX
#undef MIN #undef MIN
#define MAX(a,b) ((a) < (b) ? (b) : (a)) #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.y = si.y_org;
a.width = si.width; a.width = si.width;
a.height = si.height; a.height = si.height;
a.next = a.prev = NULL;
return a; return a;
} }

View File

@ -38,7 +38,7 @@ _tile(int screen, const position_t position)
unsigned int mw = 0, mh = 0; unsigned int mw = 0, mh = 0;
int n, i, masterwin = 0, otherwin = 0; int n, i, masterwin = 0, otherwin = 0;
int real_ncol = 1, win_by_col = 1, current_col = 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; client_t *c;
tag_t **curtags = tags_get_current(screen); tag_t **curtags = tags_get_current(screen);

View File

@ -243,7 +243,7 @@ mouse_infobox_draw(draw_context_t *ctx,
simple_window_t *sw, simple_window_t *sw,
area_t geometry, int border) 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]; char size[64];
snprintf(size, sizeof(size), "<text align=\"center\"/>%dx%d+%d+%d", snprintf(size, sizeof(size), "<text align=\"center\"/>%dx%d+%d+%d",

View File

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

View File

@ -82,7 +82,7 @@ screen_area_get(int screen, statusbar_t *statusbar, padding_t *padding)
area_t area_t
display_area_get(int phys_screen, statusbar_t *statusbar, padding_t *padding) 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; statusbar_t *sb;
xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen); 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; char *data;
xcb_get_property_reply_t *prop_r; xcb_get_property_reply_t *prop_r;
xcb_get_property_cookie_t prop_c; 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; xcb_atom_t rootpix_atom;
xutil_intern_atom_request_t rootpix_atom_req; 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 struct taglist_drawn_area_t
{ {
void *object; void *object;
area_t *area; area_array_t areas;
taglist_drawn_area_t *next, *prev; taglist_drawn_area_t *next, *prev;
}; };
static void static void
taglist_drawn_area_delete(taglist_drawn_area_t **a) taglist_drawn_area_delete(taglist_drawn_area_t **a)
{ {
area_list_wipe(&(*a)->area); area_array_wipe(&(*a)->areas);
p_delete(a); 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; client_t *sel = globalconf.focus->client;
screen_t *vscreen = &globalconf.screens[screen]; screen_t *vscreen = &globalconf.screens[screen];
int i = 0, prev_width = 0; 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; char **text = NULL;
taglist_drawn_area_t *tda; 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); taglist_drawn_area_list_push(&data->drawn_area, tda);
} }
area_list_wipe(&tda->area); tda->areas.len = 0;
/* First compute text and widget width */ /* First compute text and widget width */
for(tag = vscreen->tags; tag; tag = tag->next, i++) for(tag = vscreen->tags; tag; tag = tag->next, i++)
{ {
p_realloc(&text, i + 1); p_realloc(&text, i + 1);
area = p_new(area_t, 1);
text[i] = taglist_text_get(tag, data); text[i] = taglist_text_get(tag, data);
text[i] = tag_markup_parse(tag, text[i], a_strlen(text[i])); 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]); globalconf.font, text[i]);
if (data->show_empty || tag->selected || tag_isoccupied(tag)) 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 */ /* Now that we have widget width we can compute widget x coordinate */
w->area.x = widget_calculate_offset(ctx->width, w->area.width, w->area.x = widget_calculate_offset(ctx->width, w->area.width,
offset, w->widget->align); offset, w->widget->align);
for(area = tda->area, tag = vscreen->tags, i = 0; for(i = 0, tag = vscreen->tags; tag && i < tda->areas.len; i++, tag = tag->next)
tag && area;
tag = tag->next, area = area->next, i++)
{ {
area_t *r = &tda->areas.tab[i];
if (!data->show_empty && !tag->selected && !tag_isoccupied(tag)) if (!data->show_empty && !tag->selected && !tag_isoccupied(tag))
{ {
p_delete(&text[i]); p_delete(&text[i]);
continue; continue;
} }
area->x = w->area.x + prev_width; r->x = w->area.x + prev_width;
prev_width += area->width; prev_width += r->width;
draw_text(ctx, globalconf.font, *area, text[i]); draw_text(ctx, globalconf.font, *r, text[i]);
p_delete(&text[i]); p_delete(&text[i]);
if(tag_isoccupied(tag)) if(tag_isoccupied(tag))
{ {
rectangle.width = rectangle.height = (globalconf.font->height + 2) / 3; rectangle.width = rectangle.height = (globalconf.font->height + 2) / 3;
rectangle.x = area->x; rectangle.x = r->x;
rectangle.y = area->y; rectangle.y = r->y;
draw_rectangle(ctx, rectangle, 1.0, draw_rectangle(ctx, rectangle, 1.0,
sel && is_client_tagged(sel, tag), ctx->fg); sel && is_client_tagged(sel, tag), ctx->fg);
} }
@ -228,16 +227,17 @@ taglist_button_press(widget_node_t *w,
button_t *b; button_t *b;
taglist_data_t *data = w->widget->data; taglist_data_t *data = w->widget->data;
taglist_drawn_area_t *tda; taglist_drawn_area_t *tda;
area_t *area;
tag_t *tag; tag_t *tag;
int i;
/* Find the good drawn area list */ /* Find the good drawn area list */
for(tda = data->drawn_area; tda && tda->object != object; tda = tda->next); for(tda = data->drawn_area; tda && tda->object != object; tda = tda->next);
area = tda->area;
for(b = w->widget->buttons; b; b = b->next) for(b = w->widget->buttons; b; b = b->next)
if(ev->detail == b->button && CLEANMASK(ev->state) == b->mod && b->fct) 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) if(ev->event_x >= AREA_LEFT(*area)
&& ev->event_x < AREA_RIGHT(*area) && ev->event_x < AREA_RIGHT(*area)
&& (data->show_empty || tag->selected || tag_isoccupied(tag)) ) && (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); luaA_dofunction(globalconf.L, b->fct, 2);
return; return;
} }
}
} }
static widget_tell_status_t static widget_tell_status_t