From ea94f7f7e64fd2be233f5127e149ff622fbb668b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= Date: Mon, 30 Nov 2015 20:26:26 +0100 Subject: [PATCH] add an option to set the preferred client icon size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _NET_WM_ICON contains a list of icons and until now, the first one was picked without regard to it's size. This adds a global option to set the preferred icon size. When getting the client icon, the best size match is picked. The size can be set via awesome.set_preferred_icon_size() and the default is 0, which will pick the smallest non-zero size icon available. Signed-off-by: Lukáš Hrázký --- awesome.c | 3 +++ ewmh.c | 46 ++++++++++++++++++++++++++++++++-------------- ewmh.h | 2 +- globalconf.h | 2 ++ luaa.c | 16 ++++++++++++++++ property.c | 2 +- 6 files changed, 55 insertions(+), 16 deletions(-) diff --git a/awesome.c b/awesome.c index d643378e..aae5062d 100644 --- a/awesome.c +++ b/awesome.c @@ -543,6 +543,9 @@ main(int argc, char **argv) /* We have no clue where the input focus is right now */ globalconf.focus.need_update = true; + /* set the default preferred icon size */ + globalconf.preferred_icon_size = 0; + /* XLib sucks */ XkbIgnoreExtension(True); diff --git a/ewmh.c b/ewmh.c index 97a9a120..94142b8a 100755 --- a/ewmh.c +++ b/ewmh.c @@ -662,27 +662,45 @@ ewmh_window_icon_get_unchecked(xcb_window_t w) } static cairo_surface_t * -ewmh_window_icon_from_reply(xcb_get_property_reply_t *r) +ewmh_window_icon_from_reply(xcb_get_property_reply_t *r, uint32_t preferred_size) { - uint32_t *data; - uint64_t len; + uint32_t *data, *end, *found_data = 0; + uint32_t found_size = 0; if(!r || r->type != XCB_ATOM_CARDINAL || r->format != 32 || r->length < 2) return 0; data = (uint32_t *) xcb_get_property_value(r); - if (!data) - return 0; + if (!data) return 0; - /* Check that the property is as long as it should be, handling integer - * overflow. times always - * fits into an uint64_t and thus this multiplication cannot overflow. + end = data + r->length; + + /* Goes over the icon data and picks the icon that best matches the size preference. + * In case the size match is not exact, picks the closest bigger size if present, + * closest smaller size otherwise. */ - len = data[0] * (uint64_t) data[1]; - if (!data[0] || !data[1] || len > r->length - 2) - return 0; + while (data + 1 < end) { + /* check whether the data size specified by width and height fits into the array we got */ + uint64_t data_size = (uint64_t) data[0] * data[1]; + if (data_size > (uint64_t) (end - data - 2)) break; - return draw_surface_from_data(data[0], data[1], data + 2); + /* use the greater of the two dimensions to match against the preferred size */ + uint32_t size = MAX(data[0], data[1]); + /* pick the icon if it's a better match than the one we already have */ + if (data[0] && data[1] && ( + (found_size < preferred_size && size > found_size) || + (found_size > preferred_size && size >= preferred_size && size < found_size))) + { + found_data = data; + found_size = size; + } + + data += data_size + 2; + } + + if (!found_data) return 0; + + return draw_surface_from_data(found_data[0], found_data[1], found_data + 2); } /** Get NET_WM_ICON. @@ -690,10 +708,10 @@ ewmh_window_icon_from_reply(xcb_get_property_reply_t *r) * \return The number of elements on stack. */ cairo_surface_t * -ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie) +ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie, uint32_t preferred_size) { xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL); - cairo_surface_t *surface = ewmh_window_icon_from_reply(r); + cairo_surface_t *surface = ewmh_window_icon_from_reply(r, preferred_size); p_delete(&r); return surface; } diff --git a/ewmh.h b/ewmh.h index 42016215..6473687e 100644 --- a/ewmh.h +++ b/ewmh.h @@ -41,7 +41,7 @@ void ewmh_process_client_strut(client_t *); void ewmh_update_strut(xcb_window_t, strut_t *); void ewmh_update_window_type(xcb_window_t window, uint32_t type); xcb_get_property_cookie_t ewmh_window_icon_get_unchecked(xcb_window_t); -cairo_surface_t *ewmh_window_icon_get_reply(xcb_get_property_cookie_t); +cairo_surface_t *ewmh_window_icon_get_reply(xcb_get_property_cookie_t, uint32_t preferred_size); #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/globalconf.h b/globalconf.h index 344cfe5f..523474ce 100644 --- a/globalconf.h +++ b/globalconf.h @@ -167,6 +167,8 @@ typedef struct struct xkb_context *xkb_ctx; /* xkb state of dead keys on keyboard */ struct xkb_state *xkb_state; + /** The preferred size of client icons for this screen */ + uint32_t preferred_icon_size; } awesome_t; extern awesome_t globalconf; diff --git a/luaa.c b/luaa.c index a5a2cf5d..446cc7ea 100644 --- a/luaa.c +++ b/luaa.c @@ -162,6 +162,21 @@ luaA_load_image(lua_State *L) return 1; } +/** Set the preferred size for client icons. + * + * The closest equal or bigger size is picked if present, otherwise the closest + * smaller size is picked. The default is 0 pixels, ie. the smallest icon. + * + * @param size The size of the icons in pixels. + * @function set_preferred_icon_size + */ +static int +luaA_set_preferred_icon_size(lua_State *L) +{ + globalconf.preferred_icon_size = luaL_checknumber(L, 1); + return 0; +} + /** UTF-8 aware string length computing. * \param L The Lua VM state. * \return The number of elements pushed on stack. @@ -407,6 +422,7 @@ luaA_init(xdgHandle* xdg) { "emit_signal", luaA_awesome_emit_signal }, { "systray", luaA_systray }, { "load_image", luaA_load_image }, + { "set_preferred_icon_size", luaA_set_preferred_icon_size }, { "register_xproperty", luaA_register_xproperty }, { "set_xproperty", luaA_set_xproperty }, { "get_xproperty", luaA_get_xproperty }, diff --git a/property.c b/property.c index 542a9c2b..8069884c 100644 --- a/property.c +++ b/property.c @@ -273,7 +273,7 @@ property_get_net_wm_icon(client_t *c) void property_update_net_wm_icon(client_t *c, xcb_get_property_cookie_t cookie) { - cairo_surface_t *surface = ewmh_window_icon_get_reply(cookie); + cairo_surface_t *surface = ewmh_window_icon_get_reply(cookie, globalconf.preferred_icon_size); if(!surface) return;