Don't pass cairo surfaces around on the lua stack

Now that the C code uses lightuserdata for passing around cairo surfaces, they
are no longer automatically garbage collected. To avoid memleaks, this commit
compares the C code to use cairo_surface_t pointers instead of the lua stack.

This also fixes a memleak were a client's icon was leaked.

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2012-05-28 09:29:47 +02:00
parent 68d630c32a
commit e57af377bb
8 changed files with 49 additions and 43 deletions

17
draw.c
View File

@ -105,8 +105,8 @@ free_data(void *data)
* \param data The image's data in ARGB format, will be copied by this function. * \param data The image's data in ARGB format, will be copied by this function.
* \return Number of items pushed on the lua stack. * \return Number of items pushed on the lua stack.
*/ */
int cairo_surface_t *
luaA_surface_from_data(lua_State *L, int width, int height, uint32_t *data) draw_surface_from_data(int width, int height, uint32_t *data)
{ {
unsigned long int len = width * height; unsigned long int len = width * height;
unsigned long int i; unsigned long int i;
@ -133,10 +133,7 @@ luaA_surface_from_data(lua_State *L, int width, int height, uint32_t *data)
/* This makes sure that buffer will be freed */ /* This makes sure that buffer will be freed */
cairo_surface_set_user_data(surface, &data_key, buffer, &free_data); cairo_surface_set_user_data(surface, &data_key, buffer, &free_data);
/* lua has to make sure to free the ref or we have a leak */ return surface;
lua_pushlightuserdata(L, surface);
return 1;
} }
/** Duplicate the specified image surface. /** Duplicate the specified image surface.
@ -205,21 +202,21 @@ image_imlib_load_strerror(Imlib_Load_Error e)
* \param path file to load * \param path file to load
* \return A cairo image surface or NULL on error. * \return A cairo image surface or NULL on error.
*/ */
int cairo_surface_t *
draw_load_image(lua_State *L, const char *path) draw_load_image(lua_State *L, const char *path)
{ {
Imlib_Image imimage; Imlib_Image imimage;
Imlib_Load_Error e = IMLIB_LOAD_ERROR_NONE; Imlib_Load_Error e = IMLIB_LOAD_ERROR_NONE;
int ret; cairo_surface_t *ret;
imimage = imlib_load_image_with_error_return(path, &e); imimage = imlib_load_image_with_error_return(path, &e);
if (!imimage) { if (!imimage) {
luaL_error(L, "Cannot load image '%s': %s", path, image_imlib_load_strerror(e)); luaL_error(L, "Cannot load image '%s': %s", path, image_imlib_load_strerror(e));
return 0; return NULL;
} }
imlib_context_set_image(imimage); imlib_context_set_image(imimage);
ret = luaA_surface_from_data(L, imlib_image_get_width(), ret = draw_surface_from_data(imlib_image_get_width(),
imlib_image_get_height(), imlib_image_get_data_for_reading_only()); imlib_image_get_height(), imlib_image_get_data_for_reading_only());
imlib_free_image_and_decache(); imlib_free_image_and_decache();
return ret; return ret;

4
draw.h
View File

@ -65,9 +65,9 @@ a_iso2utf8(const char *str, ssize_t len, char **dest, ssize_t *dlen)
return false; return false;
} }
int luaA_surface_from_data(lua_State *L, int width, int height, uint32_t *data); cairo_surface_t *draw_surface_from_data(int width, int height, uint32_t *data);
cairo_surface_t *draw_dup_image_surface(cairo_surface_t *surface); cairo_surface_t *draw_dup_image_surface(cairo_surface_t *surface);
int draw_load_image(lua_State *L, const char *path); cairo_surface_t *draw_load_image(lua_State *L, const char *path);
#endif #endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

10
ewmh.c
View File

@ -634,7 +634,7 @@ ewmh_window_icon_get_unchecked(xcb_window_t w)
_NET_WM_ICON, XCB_ATOM_CARDINAL, 0, UINT32_MAX); _NET_WM_ICON, XCB_ATOM_CARDINAL, 0, UINT32_MAX);
} }
static int 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 *data; uint32_t *data;
@ -655,20 +655,20 @@ ewmh_window_icon_from_reply(xcb_get_property_reply_t *r)
if (!data[0] || !data[1] || len > r->length - 2) if (!data[0] || !data[1] || len > r->length - 2)
return 0; return 0;
return luaA_surface_from_data(globalconf.L, data[0], data[1], data + 2); return draw_surface_from_data(data[0], data[1], data + 2);
} }
/** Get NET_WM_ICON. /** Get NET_WM_ICON.
* \param cookie The cookie. * \param cookie The cookie.
* \return The number of elements on stack. * \return The number of elements on stack.
*/ */
int 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)
{ {
xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL); xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL);
int ret = ewmh_window_icon_from_reply(r); cairo_surface_t *surface = ewmh_window_icon_from_reply(r);
p_delete(&r); p_delete(&r);
return ret; return surface;
} }
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

4
ewmh.h
View File

@ -22,6 +22,8 @@
#ifndef AWESOME_EWMH_H #ifndef AWESOME_EWMH_H
#define AWESOME_EWMH_H #define AWESOME_EWMH_H
#include <cairo.h>
#include "globalconf.h" #include "globalconf.h"
#include "strut.h" #include "strut.h"
@ -37,7 +39,7 @@ void ewmh_process_client_strut(client_t *);
void ewmh_update_strut(xcb_window_t, strut_t *); void ewmh_update_strut(xcb_window_t, strut_t *);
void ewmh_update_window_type(xcb_window_t window, uint32_t type); 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); xcb_get_property_cookie_t ewmh_window_icon_get_unchecked(xcb_window_t);
int ewmh_window_icon_get_reply(xcb_get_property_cookie_t); cairo_surface_t *ewmh_window_icon_get_reply(xcb_get_property_cookie_t);
#endif #endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

7
luaa.c
View File

@ -109,7 +109,12 @@ static int
luaA_load_image(lua_State *L) luaA_load_image(lua_State *L)
{ {
const char *filename = luaL_checkstring(L, 1); const char *filename = luaL_checkstring(L, 1);
return draw_load_image(L, filename); cairo_surface_t *surface = draw_load_image(L, filename);
if (!surface)
return 0;
/* lua has to make sure to free the ref or we have a leak */
lua_pushlightuserdata(L, surface);
return 1;
} }
/** UTF-8 aware string length computing. /** UTF-8 aware string length computing.

View File

@ -1040,19 +1040,17 @@ luaA_client_isvisible(lua_State *L)
* \param iidx The image index on the stack. * \param iidx The image index on the stack.
*/ */
void void
client_set_icon(lua_State *L, int cidx, int iidx) client_set_icon(client_t *c, cairo_surface_t *s)
{ {
client_t *c = luaA_checkudata(L, cidx, &client_class); if (s)
cairo_surface_t *surf = NULL; s = draw_dup_image_surface(s);
if(!lua_isnil(L, iidx))
{
cairo_surface_t **cairo_surface = (cairo_surface_t **)lua_touserdata(L, iidx);
surf = draw_dup_image_surface(*cairo_surface);
}
if(c->icon) if(c->icon)
cairo_surface_destroy(c->icon); cairo_surface_destroy(c->icon);
c->icon = surf; c->icon = s;
luaA_object_emit_signal(L, cidx < iidx ? cidx : cidx - 1, "property::icon", 0);
luaA_object_push(globalconf.L, c);
luaA_object_emit_signal(globalconf.L, -1, "property::icon", 0);
lua_pop(globalconf.L, 1);
} }
/** Kill a client. /** Kill a client.
@ -1294,7 +1292,10 @@ luaA_client_set_maximized_vertical(lua_State *L, client_t *c)
static int static int
luaA_client_set_icon(lua_State *L, client_t *c) luaA_client_set_icon(lua_State *L, client_t *c)
{ {
client_set_icon(L, -3, -1); cairo_surface_t *surf = NULL;
if(!lua_isnil(L, -1))
surf = (cairo_surface_t *)lua_touserdata(L, -1);
client_set_icon(c, surf);
return 0; return 0;
} }
@ -1393,7 +1394,7 @@ luaA_client_get_content(lua_State *L, client_t *c)
c->geometry.width, c->geometry.width,
c->geometry.height, c->geometry.height,
~0, XCB_IMAGE_FORMAT_Z_PIXMAP); ~0, XCB_IMAGE_FORMAT_Z_PIXMAP);
int retval = 0; cairo_surface_t *surface = NULL;
if(ximage) if(ximage)
{ {
@ -1408,13 +1409,18 @@ luaA_client_get_content(lua_State *L, client_t *c)
data[y * ximage->width + x] |= 0xff000000; /* set alpha to 0xff */ data[y * ximage->width + x] |= 0xff000000; /* set alpha to 0xff */
} }
retval = luaA_surface_from_data(L, ximage->width, ximage->height, data); surface = draw_surface_from_data(ximage->width, ximage->height, data);
p_delete(&data); p_delete(&data);
} }
xcb_image_destroy(ximage); xcb_image_destroy(ximage);
} }
return retval; if (!surface)
return 0;
/* lua has to make sure to free the ref or we have a leak */
lua_pushlightuserdata(L, surface);
return 1;
} }
static int static int

View File

@ -142,7 +142,7 @@ void client_set_transient_for(lua_State *L, int, client_t *);
void client_set_name(lua_State *L, int, char *); void client_set_name(lua_State *L, int, char *);
void client_set_alt_name(lua_State *L, int, char *); void client_set_alt_name(lua_State *L, int, char *);
void client_set_group_window(lua_State *, int, xcb_window_t); void client_set_group_window(lua_State *, int, xcb_window_t);
void client_set_icon(lua_State *, int, int); void client_set_icon(client_t *c, cairo_surface_t *s);
void client_set_skip_taskbar(lua_State *, int, bool); void client_set_skip_taskbar(lua_State *, int, bool);
void client_focus(client_t *); void client_focus(client_t *);
void client_focus_update(client_t *); void client_focus_update(client_t *);

View File

@ -241,17 +241,13 @@ property_get_net_wm_icon(client_t *c)
void void
property_update_net_wm_icon(client_t *c, xcb_get_property_cookie_t cookie) property_update_net_wm_icon(client_t *c, xcb_get_property_cookie_t cookie)
{ {
luaA_object_push(globalconf.L, c); cairo_surface_t *surface = ewmh_window_icon_get_reply(cookie);
if(ewmh_window_icon_get_reply(cookie)) if(!surface)
{ return;
client_set_icon(globalconf.L, -2, -1);
/* remove icon */
lua_pop(globalconf.L, 1);
}
/* remove client */ client_set_icon(c, surface);
lua_pop(globalconf.L, 1); cairo_surface_destroy(surface);
} }
xcb_get_property_cookie_t xcb_get_property_cookie_t