> Since awesome uses Cairo, I am interested in removing
> the window manager's requirement for Imlib2. I noticed that commit
> cee3e9b60da0eec5ab8d87463336e1472893ab73 seems to have done just
> that. However, these changes seem to have been removed from the current
> Git tree.
>
> What happened?
>
> Would anyone be interested in a patch that replaces the image class'
> use of Imlib2 with Cairo/gdk-pixbuf? I have a rough one working.
I have attached my patch. Not every feature of the image class is
implemented yet. Also, I need to add some error handling code. Finally,
menu icon images are clipped for some reason. I am submitting the patch
now so that I can determine if there is any interest in it.
Thanks.
--
Mike
:wq
diff -u --recursive awesome-3.4.6-vanilla/awesomeConfig.cmake
awesome-3.4.6/awesomeConfig.cmake
--- awesome-3.4.6-vanilla/awesomeConfig.cmake 2010-07-30 14:48:47.025993362
-0500
+++ awesome-3.4.6/awesomeConfig.cmake 2010-08-04 15:25:09.076556680 -0500
@@ -134,6 +134,8 @@
pkg_check_modules(AWESOME_REQUIRED REQUIRED
glib-2.0
cairo
+ gdk-2.0
+ gdk-pixbuf-2.0
x11
pango>=1.19.3
pangocairo>=1.19.3
@@ -151,7 +153,6 @@
cairo-xcb
libstartup-notification-1.0>=0.10
xproto>=7.0.15
- imlib2
libxdg-basedir>=1.0.0)
if(NOT AWESOME_REQUIRED_FOUND OR NOT AWESOME_COMMON_REQUIRED_FOUND)
diff -u --recursive awesome-3.4.6-vanilla/draw.c awesome-3.4.6/draw.c
--- awesome-3.4.6-vanilla/draw.c 2010-07-30 14:48:46.998988909 -0500
+++ awesome-3.4.6/draw.c 2010-08-04 15:06:07.506452324 -0500
@@ -496,26 +496,14 @@
* \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,
- double ratio, unsigned char *data)
+draw_image_from_surface(draw_context_t *ctx, int x, int y, int w, int h,
+ double ratio, cairo_surface_t *surface)
{
- cairo_t *cr;
- cairo_surface_t *source;
-
- source = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, w,
h,
-#if CAIRO_VERSION_MAJOR < 1 || (CAIRO_VERSION_MAJOR == 1 &&
CAIRO_VERSION_MINOR < 5) || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR ==
5 && CAIRO_VERSION_MICRO < 8)
- sizeof(unsigned char) * 4 *
w);
-#else
-
cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w));
-#endif
- cr = cairo_create(ctx->surface);
+ cairo_t *cr = cairo_create(ctx->surface);
+ cairo_set_source_surface(cr, surface, 0.0, 0.0);
cairo_scale(cr, ratio, ratio);
- cairo_set_source_surface(cr, source, x / ratio, y / ratio);
-
cairo_paint(cr);
-
cairo_destroy(cr);
- cairo_surface_destroy(source);
}
/** Draw an image to a draw context.
@@ -528,7 +516,13 @@
void
draw_image(draw_context_t *ctx, int x, int y, double ratio, image_t *image)
{
- draw_image_from_argb_data(ctx, x, y, image_getwidth(image),
image_getheight(image), ratio, image_getdata(image));
+ draw_image_from_surface(ctx,
+ x,
+ y,
+ image_getwidth(image),
+ image_getheight(image),
+ ratio,
+ image_getsurface(image));
}
/** Rotate a pixmap.
diff -u --recursive awesome-3.4.6-vanilla/image.c awesome-3.4.6/image.c
--- awesome-3.4.6-vanilla/image.c 2010-07-30 14:48:46.997988909 -0500
+++ awesome-3.4.6/image.c 2010-08-04 15:26:17.555556065 -0500
@@ -20,8 +20,7 @@
*/
#include <xcb/xcb_image.h>
-
-#include <Imlib2.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
#include "globalconf.h"
#include "config.h"
@@ -31,8 +30,9 @@
struct image
{
LUA_OBJECT_HEADER
- /** Imlib2 image */
- Imlib_Image image;
+ /** cairo image */
+ cairo_t *context;
+ cairo_surface_t *surface;
/** Image data */
uint8_t *data;
/** Flag telling if the image is up to date or needs computing before
@@ -46,52 +46,12 @@
luaA_image_gc(lua_State *L)
{
image_t *p = luaA_checkudata(L, 1, &image_class);
- imlib_context_set_image(p->image);
- imlib_free_image();
+ cairo_surface_destroy(p->surface);
+ cairo_destroy(p->context);
p_delete(&p->data);
return luaA_object_gc(L);
}
-static const char *
-image_imlib_load_strerror(Imlib_Load_Error e)
-{
- switch(e)
- {
- case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST:
- return "no such file or directory";
- case IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY:
- return "file is a directory";
- case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ:
- return "read permission denied";
- case IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT:
- return "no loader for file format";
- case IMLIB_LOAD_ERROR_PATH_TOO_LONG:
- return "path too long";
- case IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT:
- return "path component non existent";
- case IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY:
- return "path component not a directory";
- case IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE:
- return "path points outside address space";
- case IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS:
- return "too many symbolic links";
- case IMLIB_LOAD_ERROR_OUT_OF_MEMORY:
- return "out of memory";
- case IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS:
- return "out of file descriptors";
- case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE:
- return "write permission denied";
- case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE:
- return "out of disk space";
- case IMLIB_LOAD_ERROR_UNKNOWN:
- return "unknown error, that's really bad";
- case IMLIB_LOAD_ERROR_NONE:
- return "no error, oops";
- }
-
- return "unknown error";
-}
-
/** Get image width.
* \param image The image.
* \return The image width in pixel.
@@ -99,8 +59,7 @@
int
image_getwidth(image_t *image)
{
- imlib_context_set_image(image->image);
- return imlib_image_get_width();
+ return cairo_image_surface_get_width(image->surface);
}
/** Get image height.
@@ -110,64 +69,37 @@
int
image_getheight(image_t *image)
{
- imlib_context_set_image(image->image);
- return imlib_image_get_height();
+ return cairo_image_surface_get_height(image->surface);
}
-/** Get the ARGB32 data from an image.
+cairo_t *image_copy_cairo_surface_to_new_context(cairo_surface_t *source)
+{
+ cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ cairo_image_surface_get_width(source),
+ cairo_image_surface_get_height(source));
+ cairo_t *context = cairo_create(surface);
+ cairo_set_source_surface (context, source, 0.0, 0.0);
+ cairo_paint (context);
+ return context;
+}
+
+/** Get the Cairo surface from an image.
* \param image The image.
- * \return Data.
+ * \return Surface.
*/
-uint8_t *
-image_getdata(image_t *image)
+cairo_surface_t *
+image_getsurface(image_t *image)
{
- int size, i;
- uint32_t *data;
- double alpha;
- uint8_t *dataimg;
-#if AWESOME_IS_BIG_ENDIAN
- const int index_a = 0, index_r = 1, index_g = 2, index_b = 3;
-#else
- const int index_a = 3, index_r = 2, index_g = 1, index_b = 0;
-#endif
-
- if(image->isupdated)
- return image->data;
-
- imlib_context_set_image(image->image);
-
- data = imlib_image_get_data_for_reading_only();
-
- size = imlib_image_get_width() * imlib_image_get_height();
-
- p_realloc(&image->data, size * 4);
- dataimg = image->data;
-
- for(i = 0; i < size; i++, dataimg += 4)
- {
- dataimg[index_a] = (data[i] >> 24) & 0xff; /* A */
- /* cairo wants pre-multiplied alpha */
- alpha = dataimg[index_a] / 255.0;
- dataimg[index_r] = ((data[i] >> 16) & 0xff) * alpha; /* R */
- dataimg[index_g] = ((data[i] >> 8) & 0xff) * alpha; /* G */
- dataimg[index_b] = (data[i] & 0xff) * alpha; /* B */
- }
-
- image->isupdated = true;
-
- return image->data;
-
+ return image->surface;
}
static void
image_draw_to_1bit_ximage(image_t *image, xcb_image_t *img)
{
- imlib_context_set_image(image->image);
+ uint32_t *data = (uint32_t *) cairo_image_surface_get_data
(image->surface);
- uint32_t *data = imlib_image_get_data_for_reading_only();
-
- int width = imlib_image_get_width();
- int height = imlib_image_get_height();
+ int width = image_getwidth(image);
+ int height = image_getheight(image);
for(int y = 0; y < height; y++)
for(int x = 0; x < width; x++)
@@ -230,14 +162,20 @@
int
image_new_from_argb32(int width, int height, uint32_t *data)
{
- Imlib_Image imimage;
+ cairo_surface_t *surface;
- if((imimage = imlib_create_image_using_copied_data(width, height, data)))
+ if((surface = cairo_image_surface_create_for_data(data,
+ CAIRO_FORMAT_ARGB32,
+ width,
+ height,
+ width * 4)));
{
- imlib_context_set_image(imimage);
- imlib_image_set_has_alpha(true);
image_t *image = image_new(globalconf.L);
- image->image = imimage;
+ image->surface = surface;
+ if((image->context = cairo_create(image->surface)))
+ return 1;
+ else
+ cairo_surface_destroy(image->surface);
return 1;
}
@@ -252,18 +190,16 @@
static int
image_new_blank(int width, int height)
{
- Imlib_Image imimage;
+ cairo_surface_t *surface;
- if((imimage = imlib_create_image(width, height)))
+ if((surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width,
height)))
{
- imlib_context_set_image(imimage);
- imlib_image_set_has_alpha(true);
- /* After creation, an image has undefined content. Fix that up. */
- imlib_context_set_color(0, 0, 0, 0xff);
- imlib_image_fill_rectangle(0, 0, width, height);
image_t *image = image_new(globalconf.L);
- image->image = imimage;
- return 1;
+ image->surface = surface;
+ if((image->context = cairo_create(image->surface)))
+ return 1;
+ else
+ cairo_surface_destroy(image->surface);
}
return 0;
@@ -276,27 +212,31 @@
static int
image_new_from_file(const char *filename)
{
- Imlib_Image imimage;
- Imlib_Load_Error e = IMLIB_LOAD_ERROR_NONE;
+ GdkPixbuf *pixbuf;
+ cairo_status_t status;
+ GError *error = NULL;
+ cairo_surface_t *surface;
image_t *image;
if(!filename)
return 0;
- if(!(imimage = imlib_load_image_with_error_return(filename, &e)))
+ pixbuf = gdk_pixbuf_new_from_file(filename, &error);
+ if(error != NULL)
{
- warn("cannot load image %s: %s", filename,
image_imlib_load_strerror(e));
+ warn("cannot load image %s: %s", filename, error->message);
return 0;
}
- /* Make imlib check if the file changed on disk if it's later opened by the
- * same file name again before using its cache.
- */
- imlib_context_set_image(imimage);
- imlib_image_set_changes_on_disk();
-
image = image_new(globalconf.L);
- image->image = imimage;
+
+ image->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ gdk_pixbuf_get_width(pixbuf),
+ gdk_pixbuf_get_height(pixbuf));
+
+ image->context = cairo_create(image->surface);
+ gdk_cairo_set_source_pixbuf(image->context, pixbuf, 0, 0);
+ cairo_paint(image->context);
return 1;
}
@@ -335,9 +275,9 @@
unsigned int width = luaL_checknumber(L, 1);
unsigned int height = luaL_checknumber(L, 2);
- if (width == 0)
+ if(width == 0)
luaL_error(L, "image.argb32() called with zero width");
- if (height == 0)
+ if(height == 0)
luaL_error(L, "image.argb32() called with zero height");
if(lua_isnil(L, 3))
@@ -368,8 +308,7 @@
image_t *image = luaA_checkudata(L, 1, &image_class);
int orientation = luaL_checknumber(L, 2);
- imlib_context_set_image(image->image);
- imlib_image_orientate(orientation);
+ cairo_rotate(image->surface, orientation * 90);
image->isupdated = false;
@@ -388,12 +327,12 @@
luaA_image_rotate(lua_State *L)
{
image_t *image = luaA_checkudata(L, 1, &image_class), *new;
- double angle = luaL_checknumber(L, 2);
+ /* double angle = luaL_checknumber(L, 2); */
new = image_new(L);
- imlib_context_set_image(image->image);
- new->image = imlib_create_rotated_image(angle);
+ /* FIXME: */
+ warn("not implemented");
return 1;
}
@@ -416,11 +355,13 @@
int y = luaL_checkint(L, 3);
int w = luaL_checkint(L, 4);
int h = luaL_checkint(L, 5);
-
new = image_new(L);
- imlib_context_set_image(image->image);
- new->image = imlib_create_cropped_image(x, y, w, h);
+ new->context = image_copy_cairo_surface_to_new_context(image->surface);
+ new->surface = cairo_get_target(new->context);
+ cairo_rectangle(new->context, x, y, x + w, y + h);
+ cairo_clip (new->context);
+ cairo_paint(new->context);
return 1;
}
@@ -451,11 +392,12 @@
new = image_new(L);
- imlib_context_set_image(image->image);
- new->image = imlib_create_cropped_scaled_image(source_x,
- source_y,
- w, h,
- dest_w, dest_h);
+ new->context = image_copy_cairo_surface_to_new_context(image->surface);
+ new->surface = cairo_get_target(new->context);
+ cairo_rectangle(new->context, source_x, source_y, source_x + w, source_y +
h);
+ cairo_clip (new->context);
+ cairo_scale(new->context, ((float) w) / dest_w, ((float) h) / dest_h);
+ cairo_paint(new->context);
return 1;
}
@@ -480,14 +422,14 @@
const char *buf = luaL_checklstring(L, 4, &len);
cookie = color_init_unchecked(&color, buf, len);
- imlib_context_set_image(image->image);
color_init_reply(cookie);
- if((x > imlib_image_get_width()) || (y > imlib_image_get_height()))
+ if((x > image_getwidth(image)) || (y > image_getheight(image)))
return 0;
- imlib_context_set_color(color.red, color.green, color.blue, color.alpha);
- imlib_image_draw_pixel(x, y, 1);
+ /* FIXME: */
+ warn("not implemented");
+
image->isupdated = false;
return 0;
}
@@ -516,11 +458,11 @@
const char *buf = luaL_checklstring(L, 6, &len);
cookie = color_init_unchecked(&color, buf, len);
- imlib_context_set_image(image->image);
color_init_reply(cookie);
- imlib_context_set_color(color.red, color.green, color.blue, color.alpha);
- imlib_image_draw_line(x1, y1, x2, y2, 0);
+ cairo_set_line_width(image->context, 1.0);
+ cairo_move_to(image->context, x1, y1);
+ cairo_line_to(image->context, x2, y2);
image->isupdated = false;
return 0;
}
@@ -551,68 +493,15 @@
const char *buf = luaL_checklstring(L, 7, &len);
cookie = color_init_unchecked(&color, buf, len);
- imlib_context_set_image(image->image);
color_init_reply(cookie);
- imlib_context_set_color(color.red, color.green, color.blue, color.alpha);
- if(!fill)
- imlib_image_draw_rectangle(x, y, width, height);
- else
- imlib_image_fill_rectangle(x, y, width, height);
+ /* FIXME: */
+ warn("not implemented");
+
image->isupdated = false;
return 0;
}
-/** Convert a table to a color range and set it as current color range.
- * \param L The Lua VM state.
- * \param ud The index of the table.
- * \return A color range that you are responsible to free.
- */
-static Imlib_Color_Range
-luaA_table_to_color_range(lua_State *L, int ud)
-{
- Imlib_Color_Range range = imlib_create_color_range();
-
- imlib_context_set_color_range(range);
-
- for(size_t i = 1; i <= lua_objlen(L, ud); i++)
- {
- /* get t[i] */
- lua_pushnumber(L, i);
- lua_gettable(L, ud);
-
- size_t len;
- const char *colstr = lua_tolstring(L, -1, &len);
-
- if(colstr)
- {
- color_t color;
-
- color_init_cookie_t cookie = color_init_unchecked(&color, colstr,
len);
-
- /* get value with colstr as key in table */
- lua_pushvalue(L, -1);
- lua_gettable(L, ud);
-
- /* convert the distance, if any, to number, or set 1 */
- int distance = lua_tonumber(L, -1);
- /* remove distance */
- lua_pop(L, 1);
-
- color_init_reply(cookie);
-
- imlib_context_set_color(color.red, color.green, color.blue,
color.alpha);
-
- imlib_add_color_to_color_range(distance);
- }
-
- /* remove color string (value) */
- lua_pop(L, 1);
- }
-
- return range;
-}
-
/** Draw a rectangle in an image with gradient color.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
@@ -629,6 +518,9 @@
static int
luaA_image_draw_rectangle_gradient(lua_State *L)
{
+ /*
+ int h, w, stride;
+ guint32 *data;
image_t *image = luaA_checkudata(L, 1, &image_class);
int x = luaL_checkint(L, 2);
int y = luaL_checkint(L, 3);
@@ -636,16 +528,10 @@
int height = luaL_checkint(L, 5);
luaA_checktable(L, 6);
double angle = luaL_checknumber(L, 7);
+ */
- imlib_context_set_image(image->image);
-
- luaA_table_to_color_range(L, 6);
-
- imlib_image_fill_color_range_rectangle(x, y, width, height, angle);
-
- imlib_free_color_range();
-
- image->isupdated = false;
+ /* FIXME: */
+ warn("not implemented");
return 0;
}
@@ -676,14 +562,11 @@
const char *buf = luaL_checklstring(L, 7, &len);
cookie = color_init_unchecked(&color, buf, len);
- imlib_context_set_image(image->image);
color_init_reply(cookie);
- imlib_context_set_color(color.red, color.green, color.blue, color.alpha);
- if(!fill)
- imlib_image_draw_ellipse(x, y, ah, av);
- else
- imlib_image_fill_ellipse(x, y, ah, av);
+ /* FIXME: */
+ warn("not implemented");
+
image->isupdated = false;
return 0;
}
@@ -699,15 +582,29 @@
static int
luaA_image_save(lua_State *L)
{
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
image_t *image = luaA_checkudata(L, 1, &image_class);
const char *path = luaL_checkstring(L, 2);
- Imlib_Load_Error err;
+ cairo_format_t format = cairo_image_surface_get_format(image->surface);
+ pixbuf = gdk_pixbuf_new_from_data(
+
cairo_image_surface_get_data(image->surface),
+ GDK_COLORSPACE_RGB,
+ cairo_surface_get_content(image->surface)
+
&CAIRO_CONTENT_ALPHA,
+ /* NOTE: internal image class format is
ARGB32: */
+ 32,
+
cairo_image_surface_get_width(image->surface),
+
cairo_image_surface_get_height(image->surface),
+
cairo_image_surface_get_stride(image->surface),
+ NULL,
+ NULL);
+ gdk_pixbuf_save(pixbuf, path, strrchr(path, '.') + 1, &error, NULL);
- imlib_context_set_image(image->image);
- imlib_save_image_with_error_return(path, &err);
+ if(error != NULL)
+ warn("cannot save image %s: %s", path, error->message);
- if(err != IMLIB_LOAD_ERROR_NONE)
- warn("cannot save image %s: %s", path, image_imlib_load_strerror(err));
+ gdk_pixbuf_unref(pixbuf);
return 0;
}
@@ -748,17 +645,9 @@
int vxoff = luaL_optnumber(L, 11, 0);
int vyoff = luaL_optnumber(L, 12, image_getheight(image_source));
- imlib_context_set_image(image_target->image);
-
- imlib_blend_image_onto_image_skewed(image_source->image, 0,
- /* source rectangle */
- xsrc, ysrc, wsrc, hsrc,
- /* position of the source image in the
target image */
- xoff, yoff,
- /* axis offsets for the source image,
(w|0|0|h)
- * is the default */
- hxoff, hyoff, vxoff, vyoff);
-
+ /* FIXME: */
+ warn("not implemented");
+
image_target->isupdated = false;
return 0;
@@ -781,8 +670,7 @@
static int
luaA_image_get_alpha(lua_State *L, image_t *image)
{
- imlib_context_set_image(image->image);
- lua_pushboolean(L, imlib_image_has_alpha());
+ lua_pushboolean(L, TRUE);
return 1;
}
diff -u --recursive awesome-3.4.6-vanilla/image.h awesome-3.4.6/image.h
--- awesome-3.4.6-vanilla/image.h 2010-07-30 14:48:46.999988908 -0500
+++ awesome-3.4.6/image.h 2010-08-01 11:57:37.287456821 -0500
@@ -23,13 +23,14 @@
#define AWESOME_IMAGE_H
#include <xcb/xcb.h>
+#include <cairo/cairo.h>
#include "common/luaclass.h"
typedef struct image image_t;
void image_class_setup(lua_State *);
int image_new_from_argb32(int, int, uint32_t *);
-uint8_t * image_getdata(image_t *);
+cairo_surface_t * image_getsurface(image_t *);
int image_getwidth(image_t *);
int image_getheight(image_t *);