From 6bbcb1f56eb5234287f9e6e82a28f2d9970407ae Mon Sep 17 00:00:00 2001 From: Gregor Best Date: Tue, 10 Feb 2009 17:30:57 +0100 Subject: [PATCH] widgets: add bool widget_geometries(wibox_t *) Signed-off-by: Gregor Best Signed-off-by: Julien Danjou --- draw.c | 5 +- widget.c | 174 +++++++++++++++++++++++++----------------- widget.h | 3 +- widgets/graph.c | 10 +-- widgets/imagebox.c | 62 ++------------- widgets/progressbar.c | 28 +------ widgets/systray.c | 38 ++++----- widgets/textbox.c | 44 +++-------- 8 files changed, 145 insertions(+), 219 deletions(-) diff --git a/draw.c b/draw.c index e9486d4ba..6df4498ea 100644 --- a/draw.c +++ b/draw.c @@ -224,10 +224,7 @@ draw_text(draw_context_t *ctx, draw_text_context_t *data, pango_layout_set_font_description(ctx->layout, globalconf.font->desc); x = area.x + margin->left; - /* + 1 is added for rounding, so that in any case of doubt we rather draw - * the text 1px lower than too high which usually results in a better type - * face */ - y = area.y + (ctx->height - ext->height + 1) / 2 + margin->top; + y = area.y + margin->top; /* only honors alignment if enough space */ if(ext->width < area.width) diff --git a/widget.c b/widget.c index c2f64303b..fe95be92c 100644 --- a/widget.c +++ b/widget.c @@ -129,6 +129,93 @@ luaA_table2widgets(lua_State *L, widget_node_array_t *widgets) } } +/** Retrieve a list of widget geometries using a Lua layout function. + * a table which contains the geometries is then pushed onto the stack + * \param wibox The wibox. + * \return True is everything is ok, false otherwise. + * \todo What do we do if there's no layout defined? + */ +bool +widget_geometries(wibox_t *wibox) +{ + /* get the layout field of the widget table */ + if (wibox->widgets_table != LUA_REFNIL) + { + lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, wibox->widgets_table); + lua_getfield(globalconf.L, -1, "layout"); + } + else + lua_pushnil(globalconf.L); + + /* if the layout field is a function */ + if(lua_isfunction(globalconf.L, -1)) + { + /* Push 1st argument: wibox geometry */ + area_t geometry = wibox->sw.geometry; + geometry.x = 0; + geometry.y = 0; + /* we need to exchange the width and height of the wibox window if it + * it is rotated, so the layout function doesn't need to care about that + */ + if(wibox->sw.orientation != East) + { + int i = geometry.height; + geometry.height = geometry.width; + geometry.width = i; + } + geometry.height -= 2 * wibox->sw.border.width; + geometry.width -= 2 * wibox->sw.border.width; + luaA_pusharea(globalconf.L, geometry); + /* Re-push 2nd argument: widget table */ + lua_pushvalue(globalconf.L, -3); + /* Push 3rd argument: wibox screen */ + lua_pushnumber(globalconf.L, screen_array_indexof(&globalconf.screens, wibox->screen)); + /* Re-push the layout function */ + lua_pushvalue(globalconf.L, -4); + /* call the layout function with 3 arguments (wibox geometry, widget + * table, screen) and wait for one result */ + if(!luaA_dofunction(globalconf.L, 3, 1)) + return false; + + lua_insert(globalconf.L, -3); + lua_pop(globalconf.L, 2); + } + else + { + /* If no layout function has been specified, we just push a table with + * geometries onto the stack. These geometries are nothing fancy, they + * have x = y = 0 and their height and width set to the widgets demands + * or the wibox size, depending on which is less. + */ + + widget_node_array_t *widgets = &wibox->widgets; + widget_node_array_wipe(widgets); + widget_node_array_init(widgets); + + lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, wibox->widgets_table); + luaA_table2widgets(globalconf.L, widgets); + lua_pop(globalconf.L, 2); + + lua_newtable(globalconf.L); + for(int i = 0; i < widgets->len; i++) + { + lua_pushnumber(globalconf.L, i + 1); + widget_t *widget = widgets->tab[i].widget; + lua_pushnumber(globalconf.L, screen_array_indexof(&globalconf.screens, wibox->screen)); + area_t geometry = widget->extents(globalconf.L, widget); + lua_pop(globalconf.L, 1); + geometry.x = geometry.y = 0; + geometry.width = MIN(wibox->sw.geometry.width, geometry.width); + geometry.height = MIN(wibox->sw.geometry.height, geometry.height); + + luaA_pusharea(globalconf.L, geometry); + + lua_settable(globalconf.L, -3); + } + } + return true; +} + /** Render a list of widgets. * \param wibox The wibox. * \todo Remove GC. @@ -136,14 +223,17 @@ luaA_table2widgets(lua_State *L, widget_node_array_t *widgets) void widget_render(wibox_t *wibox) { + lua_State *L = globalconf.L; draw_context_t *ctx = &wibox->sw.ctx; - int left = 0, right = 0; area_t rectangle = { 0, 0, 0, 0 }; color_t col; rectangle.width = ctx->width; rectangle.height = ctx->height; + if (!widget_geometries(wibox)) + return; + if(ctx->bg.alpha != 0xffff) { int x = wibox->sw.geometry.x, y = wibox->sw.geometry.y; @@ -195,74 +285,23 @@ widget_render(wibox_t *wibox) widget_node_array_wipe(widgets); widget_node_array_init(widgets); - lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, wibox->widgets_table); - luaA_table2widgets(globalconf.L, widgets); + lua_rawgeti(L, LUA_REGISTRYINDEX, wibox->widgets_table); + luaA_table2widgets(L, widgets); - /* compute geometry */ - for(int i = 0; i < widgets->len; i++) - if(widgets->tab[i].widget->align == AlignLeft - && widgets->tab[i].widget->isvisible) - { - widgets->tab[i].geometry = widgets->tab[i].widget->geometry(widgets->tab[i].widget, - wibox->screen, ctx->height, - ctx->width - (left + right)); - widgets->tab[i].geometry.x = left; - left += widgets->tab[i].geometry.width; - } + /* get computed geometries */ + for(unsigned int i = 0; i < lua_objlen(L, -1); i++) + { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); - for(int i = widgets->len - 1; i >= 0; i--) - if(widgets->tab[i].widget->align == AlignRight && widgets->tab[i].widget->isvisible) - { - widgets->tab[i].geometry = widgets->tab[i].widget->geometry(widgets->tab[i].widget, - wibox->screen, ctx->height, - ctx->width - (left + right)); - right += widgets->tab[i].geometry.width; - widgets->tab[i].geometry.x = ctx->width - right; - } + widgets->tab[i].geometry.x = luaA_getopt_number(L, -1, "x", wibox->sw.geometry.x); + widgets->tab[i].geometry.y = luaA_getopt_number(L, -1, "y", wibox->sw.geometry.y); + widgets->tab[i].geometry.width = luaA_getopt_number(L, -1, "width", 1); + widgets->tab[i].geometry.height = luaA_getopt_number(L, -1, "height", 1); - /* save left value */ - int fake_left = left; - - /* compute width of flex or fixed aligned widgets */ - int flex = 0; - for(int i = 0; i < widgets->len; i++) - if(widgets->tab[i].widget->align & (AlignFlex | AlignFixed) - && widgets->tab[i].widget->isvisible) - { - if(widgets->tab[i].widget->align_supported & AlignFlex - && widgets->tab[i].widget->align == AlignFlex) - flex++; - else - fake_left += widgets->tab[i].widget->geometry(widgets->tab[i].widget, - wibox->screen, ctx->height, - ctx->width - (fake_left + right)).width; - } - - /* now compute everybody together! */ - int flex_rendered = 0; - for(int i = 0; i < widgets->len; i++) - if(widgets->tab[i].widget->align & (AlignFlex | AlignFixed) - && widgets->tab[i].widget->isvisible) - { - if(widgets->tab[i].widget->align_supported & AlignFlex - && widgets->tab[i].widget->align == AlignFlex) - { - int width = (ctx->width - (right + fake_left)) / flex; - /* give last pixels to last flex to be rendered */ - if(flex_rendered == flex - 1) - width += (ctx->width - (right + fake_left)) % flex; - widgets->tab[i].geometry = widgets->tab[i].widget->geometry(widgets->tab[i].widget, - wibox->screen, ctx->height, - width); - flex_rendered++; - } - else - widgets->tab[i].geometry = widgets->tab[i].widget->geometry(widgets->tab[i].widget, - wibox->screen, ctx->height, - ctx->width - (left + right)); - widgets->tab[i].geometry.x = left; - left += widgets->tab[i].geometry.width; - } + lua_pop(L, 1); + } + lua_pop(L, 1); /* draw background image, only if the background color is not opaque */ if(wibox->bg_image && ctx->bg.alpha != 0xffff) @@ -275,11 +314,8 @@ widget_render(wibox_t *wibox) /* draw everything! */ for(int i = 0; i < widgets->len; i++) if(widgets->tab[i].widget->isvisible) - { - widgets->tab[i].geometry.y = 0; widgets->tab[i].widget->draw(widgets->tab[i].widget, ctx, widgets->tab[i].geometry, wibox); - } switch(wibox->sw.orientation) { diff --git a/widget.h b/widget.h index 8855cc07c..3bf58c5bf 100644 --- a/widget.h +++ b/widget.h @@ -37,7 +37,7 @@ struct widget_t /** Widget destructor */ widget_destructor_t *destructor; /** Geometry function for drawing */ - area_t (*geometry)(widget_t *, screen_t *, int, int); + area_t (*geometry)(widget_t *, int); /** Extents function */ area_t (*extents)(lua_State *, widget_t *); /** Draw function */ @@ -72,6 +72,7 @@ struct widget_node_t widget_t *widget_getbycoords(orientation_t, widget_node_array_t *, int, int, int16_t *, int16_t *); void widget_render(wibox_t *); +bool widget_geometries(wibox_t *); void widget_invalidate_bywidget(widget_t *); void widget_invalidate_bytype(widget_constructor_t *); diff --git a/widgets/graph.c b/widgets/graph.c index 2ff30482f..878a1ac7c 100644 --- a/widgets/graph.c +++ b/widgets/graph.c @@ -148,13 +148,13 @@ graph_plot_get(graph_data_t *d, const char *title) } static area_t -graph_geometry(widget_t *widget, screen_t *screen, int height, int width) +graph_geometry(widget_t *widget, int screen) { area_t geometry; graph_data_t *d = widget->data; geometry.x = geometry.y = 0; - geometry.height = height; + geometry.height = d->width; geometry.width = d->width; return geometry; @@ -163,11 +163,7 @@ graph_geometry(widget_t *widget, screen_t *screen, int height, int width) static area_t graph_extents(lua_State *L, widget_t *widget) { - area_t geometry; - graph_data_t *d = widget->data; - geometry.width = geometry.height = d->width; - - return geometry; + return graph_geometry(widget, 0); } /** Draw a graph widget. diff --git a/widgets/imagebox.c b/widgets/imagebox.c index 195218dad..9895c5c5c 100644 --- a/widgets/imagebox.c +++ b/widgets/imagebox.c @@ -33,37 +33,15 @@ typedef struct } imagebox_data_t; static area_t -imagebox_geometry(widget_t *widget, screen_t *screen, int height, int width) +imagebox_geometry(widget_t *widget, int screen) { area_t geometry; imagebox_data_t *d = widget->data; if(d->image) { - int iwidth = image_getwidth(d->image); - int iheight = image_getheight(d->image); - if(d->resize) - { - double ratio = (double) height / iheight; - geometry.width = ratio * iwidth; - if(geometry.width > width) - { - geometry.width = 0; - geometry.height = 0; - } - else - geometry.height = height; - } - else if(iwidth <= width) - { - geometry.width = iwidth; - geometry.height = height; - } - else - { - geometry.width = 0; - geometry.height = 0; - } + geometry.width = image_getwidth(d->image); + geometry.height = image_getheight(d->image); } else { @@ -79,21 +57,7 @@ imagebox_geometry(widget_t *widget, screen_t *screen, int height, int width) static area_t imagebox_extents(lua_State *L, widget_t *widget) { - area_t geometry = { - .x = 0, - .y = 0, - .width = 0, - .height = 0 - }; - imagebox_data_t *d = widget->data; - - if(d->image) - { - geometry.width = image_getwidth(d->image); - geometry.height = image_getheight(d->image); - } - - return geometry; + return imagebox_geometry(widget, 0); } /** Draw an image. @@ -112,22 +76,8 @@ imagebox_draw(widget_t *widget, draw_context_t *ctx, area_t geometry, wibox_t *p if(d->bg.initialized) draw_rectangle(ctx, geometry, 1.0, true, &d->bg); - int y = geometry.y; - int iheight = image_getheight(d->image); - double ratio = d->resize ? (double) geometry.height / iheight : 1; - switch(d->valign) - { - case AlignBottom: - y += geometry.height - iheight; - break; - case AlignCenter: - y += (geometry.height - iheight) / 2; - break; - default: - break; - } - - draw_image(ctx, geometry.x, y, ratio, d->image); + double ratio = d->resize ? (double) geometry.height / image_getheight(d->image) : 1; + draw_image(ctx, geometry.x, geometry.y, ratio, d->image); } } diff --git a/widgets/progressbar.c b/widgets/progressbar.c index 8564dc293..afb48fa09 100644 --- a/widgets/progressbar.c +++ b/widgets/progressbar.c @@ -133,12 +133,11 @@ progressbar_bar_get(bar_array_t *bars, const char *title) } static area_t -progressbar_geometry(widget_t *widget, screen_t *screen, int height, int width) +progressbar_geometry(widget_t *widget, int screen) { area_t geometry; progressbar_data_t *d = widget->data; - geometry.height = height; if(d->vertical) { @@ -157,6 +156,7 @@ progressbar_geometry(widget_t *widget, screen_t *screen, int height, int width) } geometry.width = pb_width + 2 * (d->border_width + d->border_padding); } + geometry.height = geometry.width; geometry.x = geometry.y = 0; @@ -166,29 +166,7 @@ progressbar_geometry(widget_t *widget, screen_t *screen, int height, int width) static area_t progressbar_extents(lua_State *L, widget_t *widget) { - area_t geometry; - progressbar_data_t *d = widget->data; - - if (d->vertical) - { - int pb_width = (int) ((d->width - 2 * (d->border_width + d->border_padding) * d->bars.len - - d->gap * (d->bars.len - 1)) / d->bars.len); - geometry.width = d->bars.len * (pb_width + 2 * (d->border_width + d->border_padding) - + d->gap) - d->gap; - }else - { - int pb_width = d->width - 2 * (d->border_width + d->border_padding); - if(d->ticks_count && d->ticks_gap) - { - int unit = (pb_width + d->ticks_gap) / d->ticks_count; - pb_width = unit * d->ticks_count - d->ticks_gap; /* rounded to match ticks... */ - } - geometry.width = pb_width + 2 * (d->border_width + d->border_padding); - } - - geometry.height = geometry.width; - - return geometry; + return progressbar_geometry(widget, 0); } /** Draw a progressbar. diff --git a/widgets/systray.c b/widgets/systray.c index cb3b4a9ea..0504be857 100644 --- a/widgets/systray.c +++ b/widgets/systray.c @@ -25,6 +25,7 @@ #include "widget.h" #include "screen.h" #include "wibox.h" +#include "structs.h" #include "common/xembed.h" #include "common/atoms.h" @@ -32,36 +33,16 @@ #define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1 static area_t -systray_geometry(widget_t *widget, screen_t *screen, int height, int width) +systray_geometry(widget_t *widget, int screen) { area_t geometry; - int phys_screen = screen_virttophys(screen_array_indexof(&globalconf.screens, screen)), n = 0; - - geometry.height = height; - - for(int i = 0; i < globalconf.embedded.len; i++) - if(globalconf.embedded.tab[i].phys_screen == phys_screen) - n++; - - /** \todo use class hints */ - geometry.width = MIN(n * height, width); - - geometry.x = geometry.y = 0; - - return geometry; -} - -static area_t -systray_extents(lua_State *L, widget_t *widget) -{ - area_t geometry; - int screen = screen_virttophys(luaL_optnumber(L, -1, 1)), n = 0; + int phys_screen = screen_virttophys(screen), n = 0; geometry.height = 0; int width = 0; for(int i = 0; i < globalconf.embedded.len; i++) - if(globalconf.embedded.tab[i].phys_screen == screen) + if(globalconf.embedded.tab[i].phys_screen == phys_screen) { xcb_get_geometry_cookie_t geo = xcb_get_geometry(globalconf.connection, globalconf.embedded.tab[i].win); xcb_get_geometry_reply_t *g = xcb_get_geometry_reply(globalconf.connection, geo, NULL); @@ -73,11 +54,22 @@ systray_extents(lua_State *L, widget_t *widget) width = g->width; } + /** \todo use class hints */ geometry.width = width * n; + geometry.x = geometry.y = 0; + return geometry; } +static area_t +systray_extents(lua_State *L, widget_t *widget) +{ + int screen = screen_virttophys(luaL_optnumber(L, -1, 1)); + + return systray_geometry(widget, screen); +} + static void systray_draw(widget_t *widget, draw_context_t *ctx, area_t geometry, wibox_t *p) diff --git a/widgets/textbox.c b/widgets/textbox.c index 9fb5f4db1..6930ac666 100644 --- a/widgets/textbox.c +++ b/widgets/textbox.c @@ -20,6 +20,7 @@ */ #include "widget.h" +#include "wibox.h" #include "common/tokenize.h" /** The textbox private data structure */ @@ -53,38 +54,10 @@ typedef struct } textbox_data_t; static area_t -textbox_geometry(widget_t *widget, screen_t *screen, int height, int width) -{ - area_t geometry; - textbox_data_t *d = widget->data; - - geometry.height = height; - - if(d->width) - geometry.width = d->width; - else if(widget->align == AlignFlex) - geometry.width = width; - else if(d->bg_image) - { - int bgi_height = image_getheight(d->bg_image); - int bgi_width = image_getwidth(d->bg_image); - double ratio = d->bg_resize ? (double) geometry.height / bgi_height : 1; - geometry.width = MIN(width, MAX(d->extents.width + d->margin.left + d->margin.right, MAX(d->width, bgi_width * ratio))); - } - else - geometry.width = MIN(d->extents.width + d->margin.left + d->margin.right, width); - - geometry.x = geometry.y = 0; - - return geometry; -} - -static area_t -textbox_extents(lua_State *L, widget_t *widget) +textbox_geometry(widget_t *widget, int screen) { textbox_data_t *d = widget->data; area_t geometry = d->extents; - geometry.width += d->margin.left + d->margin.left; geometry.height += d->margin.bottom + d->margin.top; @@ -96,15 +69,17 @@ textbox_extents(lua_State *L, widget_t *widget) geometry.width = MAX(d->extents.width + d->margin.left + d->margin.right, MAX(d->width, bgi_width * ratio)); } - if (d->data.len == 0) - { - geometry.width = 0; - geometry.height = 0; - } + geometry.x = geometry.y = 0; return geometry; } +static area_t +textbox_extents(lua_State *L, widget_t *widget) +{ + return textbox_geometry(widget, 0); +} + /** Draw a textbox widget. * \param widget The widget. * \param ctx The draw context. @@ -152,6 +127,7 @@ textbox_draw(widget_t *widget, draw_context_t *ctx, area_t geometry, wibox_t *p) } } + geometry.y += (geometry.height - textbox_geometry(widget, ctx->phys_screen).height - p->sw.border.width + 1) / 2; draw_text(ctx, &d->data, d->ellip, d->wrap, d->align, &d->margin, geometry, &d->extents); }