diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bc50557..494d2cf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,6 @@ set(AWE_SRCS ${SOURCE_DIR}/swindow.c ${SOURCE_DIR}/common/buffer.c ${SOURCE_DIR}/common/atoms.c - ${SOURCE_DIR}/common/markup.c ${SOURCE_DIR}/common/socket.c ${SOURCE_DIR}/common/util.c ${SOURCE_DIR}/common/version.c diff --git a/README b/README index 80e0e519..176ca1b7 100644 --- a/README +++ b/README @@ -14,7 +14,6 @@ In order to build awesome itself, you need header files and libs of: - cairo built with xcb support - pango and pangocairo - libev - - glib - Imlib2 - dbus (optional, use -DWITH_DBUS=OFF with cmake to disable) - gperf diff --git a/awesomerc.5.txt b/awesomerc.5.txt index c4efa93c..8b8a83aa 100644 --- a/awesomerc.5.txt +++ b/awesomerc.5.txt @@ -37,22 +37,13 @@ alpha channel to `aa' and will blend the green with the color under it. TEXT FORMAT ----------- -You can use and mix Pango markup and awesome markup in text string. +You can use Pango markup in text string. This allows to format the text rendered in widgets. Pango markup documentation can be found in the Pango documentation at http://library.gnome.org/devel/pango/stable/PangoMarkupFormat.html. -List of *awesome* markup elements and their attributes: - -* bg - - image: path to a background image - - align: background image alignment - - resize: resize background image to text size - A Pango markup example: .... -An *awesome* markup example: . - SEE ALSO -------- awesome(1) awesome-client(1) diff --git a/awesomerc.lua.in b/awesomerc.lua.in index b3958e9b..4af90573 100644 --- a/awesomerc.lua.in +++ b/awesomerc.lua.in @@ -104,7 +104,7 @@ mymainmenu = awful.menu.new({ items = { { "awesome", myawesomemenu, beautiful.aw } }) -mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon, +mylauncher = awful.widget.launcher({ image = image(beautiful.awesome_icon), menu = mymainmenu }) -- Create a systray diff --git a/client.c b/client.c index 97624438..23e0a6c3 100644 --- a/client.c +++ b/client.c @@ -30,7 +30,6 @@ #include "systray.h" #include "property.h" #include "wibox.h" -#include "common/markup.h" #include "common/atoms.h" extern awesome_t globalconf; diff --git a/common/markup.c b/common/markup.c deleted file mode 100644 index 6de94d7f..00000000 --- a/common/markup.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * markup.c - markup functions - * - * Copyright © 2008 Julien Danjou - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include - -#include "common/markup.h" - -/** Callback to invoke when the opening tag of an element is seen. - * Here is just copies element elements we do not care about, and copies - * values we care. - * \param context the context of GMarkup - * \param element_name element name - * \param attribute_names array of attribute names - * \param attribute_values array of attribute values - * \param user_data pointer to user data, here a markup_parser_data_t pointer - * \param error a GError - */ -static void -markup_parse_start_element(GMarkupParseContext *context __attribute__ ((unused)), - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error __attribute__ ((unused))) -{ - markup_parser_data_t *p = (markup_parser_data_t *) user_data; - int i; - - for(i = 0; p->elements[i]; i++) - if(!a_strcmp(element_name, p->elements[i])) { - (*p->on_element)(p, element_name, attribute_names, - attribute_values); - return; - } - - if(a_strcmp(element_name, "markup")) - { - buffer_addf(&p->text, "<%s", element_name); - for(i = 0; attribute_names[i]; i++) - { - buffer_addf(&p->text, " %s=\"%s\"", attribute_names[i], - attribute_values[i]); - } - buffer_addc(&p->text, '>'); - } -} - -/** Callback to invoke when the closing tag of an element is seen. Note that - * this is also called for empty tags like \. - * Here is just copies element elements we do not care about. - * \param context the context of GMarkup - * \param element_name element name - * \param user_data pointer to user data, here a markup_parser_data_t pointer - * \param error a GError - */ -static void -markup_parse_end_element(GMarkupParseContext *context __attribute__ ((unused)), - const gchar *element_name, - gpointer user_data, - GError **error __attribute__ ((unused))) -{ - markup_parser_data_t *p = (markup_parser_data_t *) user_data; - int i; - - for(i = 0; p->elements[i]; i++) - if(!a_strcmp(element_name, p->elements[i])) - return; - - if(a_strcmp(element_name, "markup")) - buffer_addf(&p->text, "", element_name); -} - -/** Callback to invoke when some text is seen (text is always inside an - * element). Note that the text of an element may be spread over multiple calls - * of this function. If the G_MARKUP_TREAT_CDATA_AS_TEXT flag is set, this - * function is also called for the content of CDATA marked sections. - * Here it recopies blindly the text in the text attribute of user_data. - * \param context the context of GMarkup - * \param text the text - * \param text_len the text length - * \param user_data pointer to user data, here a markup_parser_data_t pointer - * \param error a GError - */ -static void -markup_parse_text(GMarkupParseContext *context __attribute__ ((unused)), - const gchar *text, - gsize text_len, - gpointer user_data, - GError **error __attribute__ ((unused))) -{ - markup_parser_data_t *p = (markup_parser_data_t *) user_data; - - if (text_len) { - buffer_grow(&p->text, text_len); - buffer_add_xmlescaped(&p->text, text); - } -} - -/** Create a markup_parser_data_t structure with elements list. - * \param a pointer to an allocated markup_parser_data_t which must be wiped - * with markup_parser_data_wipe() - */ -void markup_parser_data_init(markup_parser_data_t *p) -{ - buffer_init(&p->text); -} - -/** Wipe a markup_parser_data_t initialized with markup_parser_data_init. - * \param p markup_parser_data_t address - */ -void -markup_parser_data_wipe(markup_parser_data_t *p) -{ - buffer_wipe(&p->text); -} - -/** Parse markup defined in data on the string str. - * \param data A markup_parser_data_t allocated by markup_parser_data_new(). - * \param str A string to parse markup from. - * \param slen String length. - * \return True if success, false otherwise. - */ -bool -markup_parse(markup_parser_data_t *data, const char *str, ssize_t slen) -{ - static GMarkupParser const parser = - { - /* start_element */ - markup_parse_start_element, - /* end_element */ - markup_parse_end_element, - /* text */ - markup_parse_text, - /* passthrough */ - NULL, - /* error */ - NULL - }; - GMarkupParseContext *mkp_ctx; - GError *error = NULL; - - if(slen <= 0) - return false; - - mkp_ctx = g_markup_parse_context_new(&parser, 0, data, NULL); - - if(!g_markup_parse_context_parse(mkp_ctx, "", -1, &error) - || !g_markup_parse_context_parse(mkp_ctx, str, slen, &error) - || !g_markup_parse_context_parse(mkp_ctx, "", -1, &error) - || !g_markup_parse_context_end_parse(mkp_ctx, &error)) - { - warn("unable to parse text \"%s\": %s", str, error ? error->message : "unknown error"); - if(error) - g_error_free(error); - g_markup_parse_context_free(mkp_ctx); - return false; - } - - g_markup_parse_context_free(mkp_ctx); - - return true; -} - -// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/common/markup.h b/common/markup.h deleted file mode 100644 index e14d30c9..00000000 --- a/common/markup.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * markup.h - markup header - * - * Copyright © 2008 Julien Danjou - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#ifndef AWESOME_COMMON_MARKUP_H -#define AWESOME_COMMON_MARKUP_H - -#include "common/buffer.h" - -typedef struct markup_parser_data_t markup_parser_data_t; - -typedef void (markup_on_elem_f)(markup_parser_data_t *, const char *, - const char **, const char **); - -struct markup_parser_data_t -{ - buffer_t text; - const char * const *elements; - markup_on_elem_f *on_element; - void *priv; -}; - -void markup_parser_data_init(markup_parser_data_t *); -void markup_parser_data_wipe(markup_parser_data_t *); -bool markup_parse(markup_parser_data_t *data, const char *, ssize_t); - -#endif -// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/common/tokenize.gperf b/common/tokenize.gperf index 03e161ea..d168737e 100644 --- a/common/tokenize.gperf +++ b/common/tokenize.gperf @@ -1,8 +1,10 @@ -1 align bar_data_add bar_properties_set bg +bg_align +bg_image +bg_resize border_color border_padding border_width @@ -57,7 +59,6 @@ Mod5 mouse_enter mouse_leave name -on ontop opacity orientation @@ -84,7 +85,6 @@ ticks_gap titlebar top transient_for -true type urgent valign @@ -96,4 +96,3 @@ word word_char workarea wrap -yes diff --git a/common/util.h b/common/util.h index b0616909..483c0969 100644 --- a/common/util.h +++ b/common/util.h @@ -37,8 +37,6 @@ #include #endif -#include "tokenize.h" - typedef enum { East, @@ -313,29 +311,6 @@ a_strncat(char *dst, ssize_t n, const char *src, ssize_t l) return dlen + a_strncpy(dst + dlen, n - dlen, src, l); } -/** \brief convert a string to a boolean value. - * - * The a_strtobool() function converts a string \c s into a boolean. - * It recognizes the strings "true", "on", "yes" and "1". - * - * \param[in] s the string to convert - * \return true if the string is recognized as possibly true, false otherwise. - */ -static inline bool -a_strtobool(const char *s, ssize_t len) -{ - switch(a_tokenize(s, len)) - { - case A_TK_TRUE: - case A_TK_YES: - case A_TK_ON: - case A_TK_1: - return true; - default: - return false; - } -} - #define fatal(string, ...) _fatal(__LINE__, \ __FUNCTION__, \ string, ## __VA_ARGS__) diff --git a/common/xutil.c b/common/xutil.c index c46f73f0..4d947ebb 100644 --- a/common/xutil.c +++ b/common/xutil.c @@ -27,6 +27,7 @@ #include "common/xutil.h" #include "common/atoms.h" +#include "common/tokenize.h" /** Get the string value of an atom. * \param conn X connection. diff --git a/draw.c b/draw.c index 7e3aff4f..4790b113 100644 --- a/draw.c +++ b/draw.c @@ -32,7 +32,6 @@ #include "structs.h" #include "common/tokenize.h" -#include "common/markup.h" extern awesome_t globalconf; @@ -159,81 +158,28 @@ draw_font_delete(font_t **font) } } -static void -draw_markup_on_element(markup_parser_data_t *p, const char *elem, - const char **names, const char **values) +/** Initialize a draw_text_context_t with text data. + * \param data The draw text context to init. + * \param str The text string to render. + * \param slen The text string length. + * \return True if everything is ok, false otherwise. + */ +bool +draw_text_context_init(draw_text_context_t *data, const char *str, ssize_t slen) { - draw_parser_data_t *data = p->priv; - - /* hack: markup.c validates tags so we can avoid strcmps here */ - switch (*elem) { - case 'b': - if(elem[2] == '_') /* bg_margin */ - for(; *names; names++, values++) - switch(a_tokenize(*names, -1)) - { - case A_TK_LEFT: - data->bg_margin.left = atoi(*values); - break; - case A_TK_TOP: - data->bg_margin.top = atoi(*values); - default: - break; - } - else /* bg */ - for(; *names; names++, values++) - switch(a_tokenize(*names, -1)) - { - case A_TK_IMAGE: - if(data->bg_image) - image_delete(&data->bg_image); - data->bg_image = image_new_from_file(*values); - break; - case A_TK_ALIGN: - data->bg_align = draw_align_fromstr(*values, -1); - break; - case A_TK_RESIZE: - data->bg_resize = a_strtobool(*values, -1); - default: - break; - } - break; - } -} - -static bool -draw_text_markup_expand(draw_parser_data_t *data, - const char *str, ssize_t slen) -{ - static char const * const elements[] = { "bg", "bg_margin", NULL }; - markup_parser_data_t p = - { - .elements = elements, - .priv = data, - .on_element = &draw_markup_on_element, - }; GError *error = NULL; - bool ret = false; - markup_parser_data_init(&p); - - if(!markup_parse(&p, str, slen)) - goto bailout; - - if(!pango_parse_markup(p.text.s, p.text.len, 0, &data->attr_list, &data->text, NULL, &error)) + if(!pango_parse_markup(str, slen, 0, &data->attr_list, &data->text, NULL, &error)) { warn("cannot parse pango markup: %s", error ? error->message : "unknown error"); if(error) g_error_free(error); - goto bailout; + return false; } data->len = a_strlen(data->text); - ret = true; - bailout: - markup_parser_data_wipe(&p); - return ret; + return true; } /** Initialize a new draw context. @@ -273,57 +219,17 @@ draw_context_init(draw_context_t *d, int phys_screen, * \param align Text alignment. * \param margin Margin to respect when drawing text. * \param area Area to draw to. - * \param text Text to draw. - * \param len Text to draw length. - * \param data Optional parser data. + * \param data Draw text context data. * \param ext Text extents. */ void -draw_text(draw_context_t *ctx, font_t *font, PangoEllipsizeMode ellip, PangoWrapMode wrap, - alignment_t align, padding_t *margin, area_t area, const char *text, ssize_t len, - draw_parser_data_t *pdata, area_t *ext) +draw_text(draw_context_t *ctx, draw_text_context_t *data, font_t *font, + PangoEllipsizeMode ellip, PangoWrapMode wrap, + alignment_t align, padding_t *margin, area_t area, area_t *ext) { int x, y; - draw_parser_data_t parser_data; - if(!pdata) - { - draw_parser_data_init(&parser_data); - if(draw_text_markup_expand(&parser_data, text, len)) - { - text = parser_data.text; - len = parser_data.len; - } - pdata = &parser_data; - } - else - { - text = pdata->text; - len = pdata->len; - } - - if(pdata->bg_image) - { - x = area.x; - y = area.y; - switch(pdata->bg_align) - { - case AlignCenter: - x += (area.width - pdata->bg_image->width) / 2; - break; - case AlignRight: - x += area.width- pdata->bg_image->width; - break; - default: - break; - } - draw_image(ctx, - x + pdata->bg_margin.left, - y + pdata->bg_margin.top, - pdata->bg_resize ? area.height : 0, pdata->bg_image); - } - - pango_layout_set_text(ctx->layout, pdata->text, pdata->len); + pango_layout_set_text(ctx->layout, data->text, data->len); pango_layout_set_width(ctx->layout, pango_units_from_double(area.width - (margin->left @@ -332,7 +238,7 @@ draw_text(draw_context_t *ctx, font_t *font, PangoEllipsizeMode ellip, PangoWrap - (margin->top + margin->bottom)); pango_layout_set_ellipsize(ctx->layout, ellip); pango_layout_set_wrap(ctx->layout, wrap); - pango_layout_set_attributes(ctx->layout, pdata->attr_list); + pango_layout_set_attributes(ctx->layout, data->attr_list); pango_layout_set_font_description(ctx->layout, font->desc); x = area.x + margin->left; @@ -364,9 +270,6 @@ draw_text(draw_context_t *ctx, font_t *font, PangoEllipsizeMode ellip, PangoWrap ctx->fg.alpha / 65535.0); pango_cairo_update_layout(ctx->cr, ctx->layout); pango_cairo_show_layout(ctx->cr, ctx->layout); - - if (pdata == &parser_data) - draw_parser_data_wipe(&parser_data); } /** Setup color-source for cairo (gradient or mono). @@ -657,14 +560,13 @@ draw_graph_line(draw_context_t *ctx, area_t rect, int *to, int cur_index, * \param y Y coordinate. * \param w Width. * \param h Height. - * \param wanted_h Wanted height: if > 0, image will be resized. + * \param ratio The ratio to apply to the image. * \param data The image pixels array. */ static void draw_image_from_argb_data(draw_context_t *ctx, int x, int y, int w, int h, - int wanted_h, unsigned char *data) + double ratio, unsigned char *data) { - double ratio; cairo_t *cr; cairo_surface_t *source; @@ -675,14 +577,8 @@ draw_image_from_argb_data(draw_context_t *ctx, int x, int y, int w, int h, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w)); #endif cr = cairo_create(ctx->surface); - if(wanted_h > 0 && h > 0) - { - ratio = (double) wanted_h / (double) h; - cairo_scale(cr, ratio, ratio); - cairo_set_source_surface(cr, source, x / ratio, y / ratio); - } - else - cairo_set_source_surface(cr, source, x, y); + cairo_scale(cr, ratio, ratio); + cairo_set_source_surface(cr, source, x / ratio, y / ratio); cairo_paint(cr); @@ -694,13 +590,13 @@ draw_image_from_argb_data(draw_context_t *ctx, int x, int y, int w, int h, * \param ctx Draw context to draw to. * \param x X coordinate. * \param y Y coordinate. - * \param wanted_h Wanted height: if > 0, image will be resized. + * \param ratio The ratio to apply to the image. * \param image The image to draw. */ void -draw_image(draw_context_t *ctx, int x, int y, int wanted_h, image_t *image) +draw_image(draw_context_t *ctx, int x, int y, double ratio, image_t *image) { - draw_image_from_argb_data(ctx, x, y, image->width, image->height, wanted_h, image->data); + draw_image_from_argb_data(ctx, x, y, image->width, image->height, ratio, image->data); } /** Rotate a pixmap. @@ -743,14 +639,12 @@ draw_rotate(draw_context_t *ctx, } /** Return the width and height of a text in pixel. + * \param data The draw context text data. * \param font Font to use. - * \param text The text. - * \param len The text length. - * \param pdata The parser data to fill. * \return Text height and width. */ area_t -draw_text_extents(font_t *font, const char *text, ssize_t len, draw_parser_data_t *parser_data) +draw_text_extents(draw_text_context_t *data, font_t *font) { cairo_surface_t *surface; cairo_t *cr; @@ -759,10 +653,7 @@ draw_text_extents(font_t *font, const char *text, ssize_t len, draw_parser_data_ xcb_screen_t *s = xutil_screen_get(globalconf.connection, globalconf.default_screen); area_t geom = { 0, 0, 0, 0 }; - if(!len) - return geom; - - if(!draw_text_markup_expand(parser_data, text, len)) + if(data->len <= 0) return geom; surface = cairo_xcb_surface_create(globalconf.connection, @@ -773,8 +664,8 @@ draw_text_extents(font_t *font, const char *text, ssize_t len, draw_parser_data_ cr = cairo_create(surface); layout = pango_cairo_create_layout(cr); - pango_layout_set_text(layout, parser_data->text, parser_data->len); - pango_layout_set_attributes(layout, parser_data->attr_list); + pango_layout_set_text(layout, data->text, data->len); + pango_layout_set_attributes(layout, data->attr_list); pango_layout_set_font_description(layout, font->desc); pango_layout_get_pixel_extents(layout, NULL, &ext); g_object_unref(layout); diff --git a/draw.h b/draw.h index 89c3ce25..ee628f13 100644 --- a/draw.h +++ b/draw.h @@ -169,16 +169,10 @@ typedef struct PangoAttrList *attr_list; char *text; ssize_t len; - struct - { - int top, left; - } bg_margin; - image_t *bg_image; - alignment_t bg_align; - bool bg_resize; -} draw_parser_data_t; +} draw_text_context_t; -void draw_text(draw_context_t *, font_t *, PangoEllipsizeMode, PangoWrapMode, alignment_t, padding_t *, area_t, const char *, ssize_t len, draw_parser_data_t *, area_t *); +bool draw_text_context_init(draw_text_context_t *, const char *, ssize_t); +void draw_text(draw_context_t *, draw_text_context_t *, font_t *, PangoEllipsizeMode, PangoWrapMode, alignment_t, padding_t *, area_t, area_t *); void draw_rectangle(draw_context_t *, area_t, float, bool, const xcolor_t *); void draw_rectangle_gradient(draw_context_t *, area_t, float, bool, vector_t, const xcolor_t *, const xcolor_t *, const xcolor_t *); @@ -188,9 +182,9 @@ void draw_graph(draw_context_t *, area_t, int *, int *, int, position_t, vector_ const xcolor_t *, const xcolor_t *, const xcolor_t *); void draw_graph_line(draw_context_t *, area_t, int *, int, position_t, vector_t, const xcolor_t *, const xcolor_t *, const xcolor_t *); -void draw_image(draw_context_t *, int, int, int, image_t *); +void draw_image(draw_context_t *, int, int, double, image_t *); void draw_rotate(draw_context_t *, xcb_drawable_t, xcb_drawable_t, int, int, int, int, double, int, int); -area_t draw_text_extents(font_t *, const char *, ssize_t, draw_parser_data_t *); +area_t draw_text_extents(draw_text_context_t *, font_t *); alignment_t draw_align_fromstr(const char *, ssize_t); const char *draw_align_tostr(alignment_t); @@ -212,19 +206,13 @@ xcolor_init_request_t xcolor_init_unchecked(xcolor_t *, const char *, ssize_t); bool xcolor_init_reply(xcolor_init_request_t); static inline void -draw_parser_data_init(draw_parser_data_t *pdata) -{ - p_clear(pdata, 1); -} - -static inline void -draw_parser_data_wipe(draw_parser_data_t *pdata) +draw_text_context_wipe(draw_text_context_t *pdata) { if(pdata) { - pango_attr_list_unref(pdata->attr_list); + if(pdata->attr_list) + pango_attr_list_unref(pdata->attr_list); p_delete(&pdata->text); - image_unref(&pdata->bg_image); } } diff --git a/lib/awful/titlebar.lua.in b/lib/awful/titlebar.lua.in index 6d860188..bfacf4f4 100644 --- a/lib/awful/titlebar.lua.in +++ b/lib/awful/titlebar.lua.in @@ -6,6 +6,7 @@ -- Grab environment we need local math = math +local image = image local pairs = pairs local otable = otable local capi = @@ -72,13 +73,13 @@ function add(c, args) local closef if theme.titlebar_close_button_focus then closef = widget.button({ align = "right", - image = theme.titlebar_close_button_focus }) + image = image(theme.titlebar_close_button_focus) }) end local close if theme.titlebar_close_button_normal then close = widget.button({ align = "right", - image = theme.titlebar_close_button_normal }) + image = image(theme.titlebar_close_button_normal) }) end if close or closef then diff --git a/lib/awful/widget.lua.in b/lib/awful/widget.lua.in index 8d82e847..ecc666ee 100644 --- a/lib/awful/widget.lua.in +++ b/lib/awful/widget.lua.in @@ -15,6 +15,7 @@ local capi = client = client, button = button, widget = widget, + image = image, mouse = mouse } local util = require("awful.util") @@ -51,20 +52,24 @@ local function taglist_update (screen, w, label, buttons, data) end -- Update widgets text for k, tag in ipairs(tags) do - w[k].text, w[k].bg = label(tag) - if buttons then - if not data[tag] then - -- Replace press function by a new one calling with tags as - -- argument. - -- This is done here because order of tags can change - data[tag] = {} - for kb, b in ipairs(buttons) do - -- Copy object - data[tag][kb] = capi.button(b) - data[tag][kb].press = function () b.press(tag) end + local text, bg, bg_image, bg_resize = label(tag) + w[k].text = text + if text then + w[k].bg, w[k].bg_image, w[k].bg_resize = bg, bg_image, bg_resize + if buttons then + if not data[tag] then + -- Replace press function by a new one calling with tags as + -- argument. + -- This is done here because order of tags can change + data[tag] = {} + for kb, b in ipairs(buttons) do + -- Copy object + data[tag][kb] = capi.button(b) + data[tag][kb].press = function () b.press(tag) end + end end + w[k]:buttons(data[tag]) end - w[k]:buttons(data[tag]) end end end @@ -112,7 +117,8 @@ end -- squares_sel Optional: a user provided image for selected squares. -- squares_unsel Optional: a user provided image for unselected squares. -- squares_resize Optional: true or false to resize squares. --- @return A string to print and a background color. +-- @return A string to print, a background color, a background image and a +-- background resize value. function taglist.label.all(t, args) if not args then args = {} end local theme = beautiful.get() @@ -124,23 +130,26 @@ function taglist.label.all(t, args) local taglist_squares_unsel = args.squares_unsel or theme.taglist_squares_unsel local taglist_squares_resize = theme.taglist_squares_resize or args.squares_resize or "true" local font = args.font or theme.taglist_font or theme.font or "" - local text = "" - local background = "" + local text = " " local sel = capi.client.focus local bg_color = nil local fg_color = nil + local bg_image + local bg_resize = false if t.selected then bg_color = bg_focus fg_color = fg_focus end if sel and sel:tags()[t] then if taglist_squares_sel then - background = "resize=\"" .. taglist_squares_resize .. "\" image=\"" .. taglist_squares_sel .. "\"" + bg_image = capi.image(taglist_squares_sel) + bg_resize = taglist_squares_resize == "true" end else local cls = t:clients() if #cls > 0 and taglist_squares_unsel then - background = "resize=\"" .. taglist_squares_resize .. "\" image=\"" .. taglist_squares_unsel .. "\"" + bg_image = capi.image(taglist_squares_unsel) + bg_resize = taglist_squares_resize == "true" end for k, c in pairs(cls) do if c.urgent then @@ -151,12 +160,12 @@ function taglist.label.all(t, args) end end if fg_color then - text = text .. " "..util.escape(t.name).." " + text = text .. ""..util.escape(t.name).."" else - text = text .. " "..util.escape(t.name).." " + text = text .. util.escape(t.name) end - text = text .. "" - return text, bg_color + text = text .. " " + return text, bg_color, bg_image, bg_resize end --- Return labels for a taglist widget with all *non empty* tags from screen. @@ -168,7 +177,8 @@ end -- fg_focus The foreground color for selected tag. -- bg_urgent The background color for urgent tags. -- fg_urgent The foreground color for urgent tags. --- @return A string to print. +-- @return A string to print, a background color, a background image and a +-- background resize value. function taglist.label.noempty(t, args) if #t:clients() > 0 or t.selected then return taglist.label.all(t, args) @@ -195,6 +205,8 @@ local function tasklist_update(w, buttons, label, data) w[i] = capi.widget({ type = "imagebox", align = "flex" }) w[i + 1] = capi.widget({ type = "textbox", align = "flex" }) w[i + 1]:margin({ left = 2, right = 2 }) + w[i + 1].bg_resize = true + w[i + 1].bg_align = "right" end -- Remove widgets elseif len > #clients then @@ -220,7 +232,7 @@ local function tasklist_update(w, buttons, label, data) w[k]:buttons(data[c]) w[k + 1]:buttons(data[c]) end - w[k + 1].text, w[k + 1].bg = label(clients[(k + 1) / 2]) + w[k + 1].text, w[k + 1].bg, w[k + 1].bg_image= label(clients[(k + 1) / 2]) w[k].bg = w[k + 1].bg if w[k + 1].text then -- Set icon @@ -275,13 +287,13 @@ local function widget_tasklist_label_common(c, args) local fg_urgent = args.fg_urgent or theme.tasklist_fg_urgent or theme.fg_urgent local bg_urgent = args.bg_urgent or theme.tasklist_bg_urgent or theme.bg_urgent local floating_icon = args.floating_icon or theme.tasklist_floating_icon - local floating_icon_align = args.floating_icon_align or theme.tasklist_floating_icon_align or "right" local font = args.font or theme.tasklist_font or theme.font or "" local bg = nil local text = "" local name + local status_image if client.floating.get(c) and floating_icon then - text = text.."" + status_image = capi.image(floating_icon) end if c.minimized then name = util.escape(c.icon_name) or "" @@ -302,7 +314,7 @@ local function widget_tasklist_label_common(c, args) text = text .. name end text = text .. "" - return text, bg + return text, bg, status_image end --- Return labels for a tasklist widget with clients from all tags and screen. @@ -316,7 +328,7 @@ end -- fg_focus The foreground color for focused client. -- bg_urgent The background color for urgent clients. -- fg_urgent The foreground color for urgent clients. --- @return A string to print and a background color. +-- @return A string to print, a background color and a status image. function tasklist.label.allscreen(c, screen, args) return widget_tasklist_label_common(c, args) end @@ -332,7 +344,7 @@ end -- fg_focus The foreground color for focused client. -- bg_urgent The background color for urgent clients. -- fg_urgent The foreground color for urgent clients. --- @return A string to print and a background color. +-- @return A string to print, a background color and a status image. function tasklist.label.alltags(c, screen, args) -- Only print client on the same screen as this widget if c.screen ~= screen then return end @@ -350,7 +362,7 @@ end -- fg_focus The foreground color for focused client. -- bg_urgent The background color for urgent clients. -- fg_urgent The foreground color for urgent clients. --- @return A string to print and a background color. +-- @return A string to print, a background color and a status image. function tasklist.label.currenttags(c, screen, args) -- Only print client on the same screen as this widget if c.screen ~= screen then return end @@ -367,14 +379,14 @@ end -- @return A textbox widget configured as a button. function button(args) if not args or not args.image then return end - args.type = "textbox" + local img_release = args.image + local img_press = img_release:crop(-2, -2, img_release.width, img_release.height) + args.type = "imagebox" local w = capi.widget(args) - local img_release = "" - local img_press = "" - w.text = img_release - w:buttons({ capi.button({}, 1, function () w.text = img_press end, function () w.text = img_release end) }) - function w.mouse_leave(s) w.text = img_release end - function w.mouse_enter(s) if capi.mouse.coords().buttons[1] then w.text = img_press end end + w.image = img_release + w:buttons({ capi.button({}, 1, function () w.image = img_press end, function () w.image = img_release end) }) + function w.mouse_leave(s) w.image = img_release end + function w.mouse_enter(s) if capi.mouse.coords().buttons[1] then w.image = img_press end end return w end diff --git a/structs.h b/structs.h index f38ec60b..19138a80 100644 --- a/structs.h +++ b/structs.h @@ -32,6 +32,7 @@ #include "common/xutil.h" #include "common/xembed.h" #include "common/refcount.h" +#include "common/tokenize.h" /** Windows type */ typedef enum diff --git a/widgets/imagebox.c b/widgets/imagebox.c index e3dfecd3..a4eee33a 100644 --- a/widgets/imagebox.c +++ b/widgets/imagebox.c @@ -44,13 +44,15 @@ imagebox_geometry(widget_t *widget, int screen, int height, int width) { if(d->resize) { - geometry.width = ((double) height / (double) d->image->height) * d->image->width; - geometry.height = height; + double ratio = (double) height / d->image->height; + geometry.width = ratio * d->image->width; if(geometry.width > width) { geometry.width = 0; geometry.height = 0; } + else + geometry.height = height; } else if(d->image->width <= width) { @@ -91,6 +93,7 @@ imagebox_draw(widget_t *widget, draw_context_t *ctx, area_t geometry, draw_rectangle(ctx, geometry, 1.0, true, &d->bg); int y = geometry.y; + double ratio = d->resize ? (double) geometry.height / d->image->height : 1; switch(d->valign) { case AlignBottom: @@ -103,7 +106,7 @@ imagebox_draw(widget_t *widget, draw_context_t *ctx, area_t geometry, break; } - draw_image(ctx, geometry.x, y, d->resize ? ctx->height : 0, d->image); + draw_image(ctx, geometry.x, y, ratio, d->image); } } diff --git a/widgets/textbox.c b/widgets/textbox.c index dd3236cc..3d486300 100644 --- a/widgets/textbox.c +++ b/widgets/textbox.c @@ -27,18 +27,13 @@ extern awesome_t globalconf; /** The textbox private data structure */ typedef struct { - /** Textbox text */ - char *text; - /** Textbox text length */ - ssize_t len; + draw_text_context_t data; /** Textbox width */ int width; /** Extents */ area_t extents; PangoEllipsizeMode ellip; PangoWrapMode wrap; - /** Draw parser data */ - draw_parser_data_t pdata; /** Border */ struct { @@ -51,6 +46,12 @@ typedef struct padding_t margin; /** Background color */ xcolor_t bg; + /** Background image */ + image_t *bg_image; + /** Background resize to wibox height. */ + bool bg_resize; + /** Background alignment */ + alignment_t bg_align; } textbox_data_t; static area_t @@ -65,14 +66,13 @@ textbox_geometry(widget_t *widget, int screen, int height, int width) geometry.width = d->width; else if(widget->align == AlignFlex) geometry.width = width; - else + else if(d->bg_image) { - geometry.width = MIN(d->extents.width, width); - - if(d->pdata.bg_image) - geometry.width = MAX(geometry.width, - d->pdata.bg_resize ? ((double) d->pdata.bg_image->width / (double) d->pdata.bg_image->height) * geometry.height : d->pdata.bg_image->width); + double ratio = d->bg_resize ? (double) geometry.height / d->bg_image->height : 1; + geometry.width = MIN(width, MAX(d->extents.width, MAX(d->width, d->bg_image->width * ratio))); } + else + geometry.width = MIN(d->extents.width, width); return geometry; } @@ -95,8 +95,30 @@ textbox_draw(widget_t *widget, draw_context_t *ctx, area_t geometry, if(d->border.width > 0) draw_rectangle(ctx, geometry, d->border.width, false, &d->border.color); - draw_text(ctx, globalconf.font, d->ellip, d->wrap, d->align, &d->margin, - geometry, d->text, d->len, &d->pdata, &d->extents); + if(d->bg_image) + { + double ratio = d->bg_resize ? (double) geometry.height / d->bg_image->height : 1; + /* check there is enough space to draw the image */ + if(ratio * d->bg_image->width <= geometry.width) + { + int x = geometry.x; + int y = geometry.y; + switch(d->bg_align) + { + case AlignCenter: + x += (geometry.width - d->bg_image->width * ratio) / 2; + break; + case AlignRight: + x += geometry.width - d->bg_image->width * ratio; + break; + default: + break; + } + draw_image(ctx, x, y, ratio, d->bg_image); + } + } + + draw_text(ctx, &d->data, globalconf.font, d->ellip, d->wrap, d->align, &d->margin, geometry, &d->extents); } /** Delete a textbox widget. @@ -106,8 +128,7 @@ static void textbox_destructor(widget_t *w) { textbox_data_t *d = w->data; - draw_parser_data_wipe(&d->pdata); - p_delete(&d->text); + draw_text_context_wipe(&d->data); p_delete(&d); } @@ -140,6 +161,9 @@ luaA_textbox_margin(lua_State *L) * \lfield align Text alignment, left, center or right. * \lfield margin Method to pass text margin: a table with top, left, right and bottom keys. * \lfield bg Background color. + * \lfield bg_image Background image. + * \lfield bg_align Background image alignment. + * \lfield bg_resize Background resize. */ static int luaA_textbox_index(lua_State *L, awesome_token_t token) @@ -149,6 +173,17 @@ luaA_textbox_index(lua_State *L, awesome_token_t token) switch(token) { + case A_TK_BG_RESIZE: + lua_pushboolean(L, d->bg_resize); + return 1; + case A_TK_BG_ALIGN: + lua_pushstring(L, draw_align_tostr(d->bg_align)); + return 1; + case A_TK_BG_IMAGE: + if(d->bg_image) + return luaA_image_userdata_new(L, d->bg_image); + else + return 0; case A_TK_BG: return luaA_pushcolor(L, &d->bg); case A_TK_MARGIN: @@ -164,8 +199,12 @@ luaA_textbox_index(lua_State *L, awesome_token_t token) luaA_pushcolor(L, &d->border.color); return 1; case A_TK_TEXT: - lua_pushstring(L, d->text); - return 1; + if(d->data.len > 0) + { + lua_pushlstring(L, d->data.text, d->data.len); + return 1; + } + return 0; case A_TK_WIDTH: lua_pushnumber(L, d->width); return 1; @@ -214,9 +253,29 @@ luaA_textbox_newindex(lua_State *L, awesome_token_t token) widget_t **widget = luaA_checkudata(L, 1, "widget"); const char *buf = NULL; textbox_data_t *d = (*widget)->data; + image_t **image = NULL; switch(token) { + case A_TK_BG_ALIGN: + buf = luaL_checklstring(L, 3, &len); + d->bg_align = draw_align_fromstr(buf, len); + break; + case A_TK_BG_RESIZE: + d->bg_resize = luaA_checkboolean(L, 3); + break; + case A_TK_BG_IMAGE: + if(lua_isnil(L, 3) + || (image = luaA_checkudata(L, 3, "image"))) + { + /* unref image */ + image_unref(&d->bg_image); + if(image) + d->bg_image = image_ref(image); + else + d->bg_image = NULL; + } + break; case A_TK_BG: if(lua_isnil(L, 3)) p_clear(&d->bg, 1); @@ -239,21 +298,26 @@ luaA_textbox_newindex(lua_State *L, awesome_token_t token) || (buf = luaL_checklstring(L, 3, &len))) { /* delete */ - draw_parser_data_wipe(&d->pdata); - /* reinit since we are giving it as arg to draw_text unconditionally */ - draw_parser_data_init(&d->pdata); - p_delete(&d->text); + draw_text_context_wipe(&d->data); + p_clear(&d->data, 1); if(buf) { - a_iso2utf8(buf, len, &d->text, &d->len); - d->extents = draw_text_extents(globalconf.font, d->text, d->len, &d->pdata); + char *text; + ssize_t tlen; + /* if text has been converted to UTF-8 */ + if(draw_iso2utf8(buf, len, &text, &tlen)) + { + draw_text_context_init(&d->data, text, tlen); + p_delete(&text); + } + else + draw_text_context_init(&d->data, buf, len); + + d->extents = draw_text_extents(&d->data, globalconf.font); } else - { - d->len = 0; p_clear(&d->extents, 1); - } } break; case A_TK_WIDTH: