From 46f03fd6a60fc49365741c6a65438262d32f559f Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sun, 22 Jun 2008 22:09:48 +0200 Subject: [PATCH] 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 --- common/draw.c | 89 ++++++++++++++++++++++++----------------------- common/draw.h | 15 ++++---- common/util.h | 2 ++ common/xscreen.c | 1 - layouts/tile.c | 2 +- mouse.c | 2 +- placement.c | 38 +++++++++++--------- screen.c | 2 +- widget.c | 2 +- widgets/taglist.c | 39 +++++++++++---------- 10 files changed, 100 insertions(+), 92 deletions(-) diff --git a/common/draw.c b/common/draw.c index c7ee6508..356369d2 100644 --- a/common/draw.c +++ b/common/draw.c @@ -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); } } } diff --git a/common/draw.h b/common/draw.h index 865ab7b9..cf1434cf 100644 --- a/common/draw.h +++ b/common/draw.h @@ -27,7 +27,7 @@ #include -#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 diff --git a/common/util.h b/common/util.h index 409216ca..80a79e16 100644 --- a/common/util.h +++ b/common/util.h @@ -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)) diff --git a/common/xscreen.c b/common/xscreen.c index 7fbaa334..de332204 100644 --- a/common/xscreen.c +++ b/common/xscreen.c @@ -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; } diff --git a/layouts/tile.c b/layouts/tile.c index c15771ad..16ac6ddf 100644 --- a/layouts/tile.c +++ b/layouts/tile.c @@ -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); diff --git a/mouse.c b/mouse.c index 0ca1fda6..0d992af2 100644 --- a/mouse.c +++ b/mouse.c @@ -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), "%dx%d+%d+%d", diff --git a/placement.c b/placement.c index 2800ba2e..397be5dd 100644 --- a/placement.c +++ b/placement.c @@ -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; } diff --git a/screen.c b/screen.c index 44b3fc4e..9ca45181 100644 --- a/screen.c +++ b/screen.c @@ -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); diff --git a/widget.c b/widget.c index e6d8b0f0..6a835724 100644 --- a/widget.c +++ b/widget.c @@ -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; diff --git a/widgets/taglist.c b/widgets/taglist.c index 680c6177..a7ea02f2 100644 --- a/widgets/taglist.c +++ b/widgets/taglist.c @@ -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