> 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 *);
 

Reply via email to