draw: remove custom markup support

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2008-12-03 15:23:10 +01:00
parent a4d914f0e4
commit 26da80f90a
17 changed files with 192 additions and 496 deletions

View File

@ -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

1
README
View File

@ -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

View File

@ -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: <span weight="bold" foreground="#336699">...</span>.
An *awesome* markup example: <text align="right"/>.
SEE ALSO
--------
awesome(1) awesome-client(1)

View File

@ -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

View File

@ -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;

View File

@ -1,182 +0,0 @@
/*
* markup.c - markup functions
*
* Copyright © 2008 Julien Danjou <julien@danjou.info>
*
* 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 <glib.h>
#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 \<empty/\>.
* 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, "</%s>", 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, "<markup>", -1, &error)
|| !g_markup_parse_context_parse(mkp_ctx, str, slen, &error)
|| !g_markup_parse_context_parse(mkp_ctx, "</markup>", -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

View File

@ -1,45 +0,0 @@
/*
* markup.h - markup header
*
* Copyright © 2008 Julien Danjou <julien@danjou.info>
*
* 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

View File

@ -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

View File

@ -37,8 +37,6 @@
#include <alloca.h>
#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__)

View File

@ -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.

163
draw.c
View File

@ -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_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);

26
draw.h
View File

@ -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)
{
if(pdata->attr_list)
pango_attr_list_unref(pdata->attr_list);
p_delete(&pdata->text);
image_unref(&pdata->bg_image);
}
}

View File

@ -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

View File

@ -15,6 +15,7 @@ local capi =
client = client,
button = button,
widget = widget,
image = image,
mouse = mouse
}
local util = require("awful.util")
@ -51,7 +52,10 @@ 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)
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
@ -68,6 +72,7 @@ local function taglist_update (screen, w, label, buttons, data)
end
end
end
end
--- Create a new taglist widget.
-- @param screen The screen to draw tag list for.
@ -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()
@ -125,22 +131,25 @@ function taglist.label.all(t, args)
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 = "<span font_desc='"..font.."'> "
local background = ""
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 .. "<bg "..background.." /> <span color='"..util.color_strip_alpha(fg_color).."'>"..util.escape(t.name).."</span> "
text = text .. "<span color='"..util.color_strip_alpha(fg_color).."'>"..util.escape(t.name).."</span>"
else
text = text .. " <bg "..background.." />"..util.escape(t.name).." "
text = text .. util.escape(t.name)
end
text = text .. " </span>"
return text, bg_color
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 = "<span font_desc='"..font.."'>"
local name
local status_image
if client.floating.get(c) and floating_icon then
text = text.."<bg image=\"" .. floating_icon .. "\" align=\"" .. floating_icon_align .. "\"/>"
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 .. "</span>"
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 = "<bg image=\"" .. args.image .. "\" resize=\"true\"/>"
local img_press = "<bg_margin top=\"2\" left=\"2\"/><bg image=\"" .. args.image .. "\" resize=\"true\"/>"
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

View File

@ -32,6 +32,7 @@
#include "common/xutil.h"
#include "common/xembed.h"
#include "common/refcount.h"
#include "common/tokenize.h"
/** Windows type */
typedef enum

View File

@ -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);
}
}

View File

@ -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);
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
{
d->len = 0;
p_clear(&d->extents, 1);
draw_text_context_init(&d->data, buf, len);
d->extents = draw_text_extents(&d->data, globalconf.font);
}
else
p_clear(&d->extents, 1);
}
break;
case A_TK_WIDTH: