cx11cairoxlibpixmap

draw icon with transparency in xlib and cairo


Now that I've got the icons I want to draw them correctly. At the moment I'm using Cairo to draw these images on a window. I have a mask and the icon as pixmap.

cairo_surface_t *image;
cairo_surface_t *imask;
cairo_surface_t *surface;
cairo_t *csurface;

surface = cairo_xlib_surface_create(display, d, DefaultVisual(display, screen), 400, 400);
csurface = cairo_create(surface);

Pixmap icon;
Pixmap mask;

//XWM Stuff ...
if(icon != 0)
{
   get_pixmap_geometry(display, icon, &width, &height, &depth);
   image = cairo_xlib_surface_create(display, icon, DefaultVisual(display, screen), width, height);
   cairo_set_source_surface(csurface, image, 0, 0);
   //How do I apply the mask?
   //I tried cairo_set_operator(csurface, CAIRO_OPERATOR_SOURCE);
   cairo_paint(csurface);
}

But the icons do not have any transparencies. I've found no example to solve this with cairo on the internet. There is only a complicated way but it's so badly documented that it doesn't help me at all. Does someone have a link or an example for how to restore the original icon with its transparencies? Thank you in advance.


Solution

  • Here is an example from awesome where it "turns" the icon into a cairo surface: https://github.com/awesomeWM/awesome/blob/430f4fab15bb101b4af9fadbebb9a9bfa47ba9de/objects/client.c#L1501

    This uses xcb instead of Xlib, but you should manage to still understand this. The part that handles a mask begins in line 1538. Basically, a new cairo surface is created and a cairo context is set up for it. The source surface is the icon and the mask is applied via cairo_mask_surface ("use the alpha channel of some cairo surface as the mask of a drawing operation"). You can just copy this part to your code so that you don't have to draw the icons to a temporary surface.

    TL;DR: The answer to your //How do I apply the mask? is: Use cairo_mask_surface() instead of cairo_paint().