I was trying to resolve this one, but there are problems. Have a look at this code snippet:
#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#include <xcb/shm.h>
#include <xcb/xcb_image.h>
#include <sys/shm.h> // shmget
#include <unistd.h> // usleep
#include <inttypes.h> // PRIu8
#include <wchar.h> // wmemset
int main(void) {
xcb_connection_t *c;
xcb_screen_t *s;
xcb_window_t w;
xcb_gcontext_t g;
xcb_generic_event_t *e;
uint32_t mask;
uint32_t values[2];
int done = 0;
xcb_rectangle_t r = { 20, 20, 160, 160 };
int ww= 600, wh = 400, wx = 800, wy = 500;
xcb_rectangle_t wr = { 0, 0, 800, 600 };
c = xcb_connect(NULL,NULL);
if (xcb_connection_has_error(c)) {
printf("Cannot open display\n");
exit(EXIT_FAILURE);
}
const xcb_setup_t* setup = xcb_get_setup(c);
s = xcb_setup_roots_iterator( setup ).data;
// create black graphics context
g = xcb_generate_id(c);
w = s->root;
mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
values[0] = s->white_pixel;
values[1] = 0;
xcb_create_gc(c, g, w, mask, values);
// create window
w = xcb_generate_id(c);
mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
values[0] = s->black_pixel;
values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS;
xcb_create_window(c, s->root_depth, w, s->root,
(s->width_in_pixels / 2) - (600 / 2),
(s->height_in_pixels / 2) - (400 / 2), 600, 400, 10,
XCB_WINDOW_CLASS_INPUT_OUTPUT, s->root_visual,
mask, values);
xcb_map_window(c, w);
// An attempt in mask preparation
xcb_pixmap_t cm1 = xcb_generate_id( c );
xcb_create_pixmap (c, 1, cm1, w, ww, wh); // depth = 1
// xcb_gcontext_t gm1 = xcb_generate_id(c); // <- 3
// mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
// values[0] = s->white_pixel;
// values[1] = s->black_pixel;
// xcb_create_gc(c, gm1, cm1, mask, values);
// The buffer where all the drawing shall be done
xcb_pixmap_t pix = xcb_generate_id( c );
xcb_create_pixmap (c, s->root_depth, pix, w, ww, wh);
xcb_gcontext_t fill = xcb_generate_id(c);
mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_CLIP_MASK;
values[0] = 0xdc143c;
values[1] = s->black_pixel;
values[2] = XCB_NONE; // <- 2
xcb_create_gc(c, fill, pix, mask, values);
// xcb_change_gc(c, fill, XCB_GC_CLIP_MASK, (uint32_t[]){ cm1 }); // <- 1
// xcb_clear_area(c, 1, cm1, 0, 0, ww, wh);
xcb_flush(c);
// event loop
int dx = 1, dy = 1;
xcb_get_geometry_cookie_t geom;
xcb_get_geometry_reply_t *geo;
int gg = 0;
geom = xcb_get_geometry(c, w);
geo = xcb_get_geometry_reply(c, geom, NULL);
ww = geo->width; wh = geo->height;
free(geo);
xcb_expose_event_t *ex_event;
while (!done) {
usleep(10000); // Around 100 FPS
if (r.x + r.width == ww)
dx = -1;
else if (r.x == 0)
dx = 1;
if (r.y + r.height == wh)
dy = -1;
else if (r.y == 0)
dy = 1;
r.x += dx;
r.y += dy;
// The above is just for moving the rectangle around
e = xcb_poll_for_event(c);
// Below: paint background, rectangle - and render it all
xcb_change_gc(c, fill, XCB_GC_FOREGROUND, (uint32_t[]){ 0x000000FF });
xcb_poly_fill_rectangle(c, pix, fill, 1, &wr);
xcb_change_gc(c, fill, XCB_GC_FOREGROUND, (uint32_t[]){ 0xdc143c });
xcb_poly_fill_rectangle(c, pix, fill, 1, &r);
xcb_copy_area(c, pix, w, g, 0, 0, 0, 0, ww, wh);
xcb_flush(c);
// printf("Flushed "); // <- 4
if (e) {
switch (e->response_type & ~0x80) {
case 0:
puts("Unfortunately, a request had no reply");
break;
case XCB_DESTROY_NOTIFY:
puts("Destruction!");
break;
case XCB_EXPOSE:
xcb_flush(c);
break;
case XCB_KEY_PRESS: // exit on key press
done = 1;
break;
case XCB_CLIENT_MESSAGE:
done = 1;
break;
default:
printf("Unrecognized event %"PRIu8"\n", e->response_type);
break;
}
}
free(e);
}
xcb_free_pixmap(c, cm1);
xcb_free_pixmap(c, pix);
xcb_disconnect(c);
exit(EXIT_SUCCESS);
}
Now if you run it „as is” you'll see the red rectangle moving around on a blue background (that's why I'm polling for events). Then I'd like to use just any mask simply to find out, how it is supposed to work. The scarce docs say that the mask can be attached to pixmap on creation time, or it can be done later using xcb_change_bc.
From what I see, either the docs are wrong, or I'm doing something wrong (or maybe there's a bug in XCB?) — because these methods aren't equivalent. You can test it by either removing the comment from the beginning of the line marked with „<- 1”, or by adding a parameter (instead of XCB_NONE) in the line marked with „<- 2”. In the latter case you'll notice plenty of „Unfortunately, a request had no reply” notices in your console, and the window becomes very unresponsive (cannot be closed with a keypress instantly, one has to wait quite a few seconds) — obviously something goes very wrong in that case.
By uncommenting the line marked with „<- 1” it looks somewhat better — there's no more that plenty of annoying messages — still there's also no more moving rectangle. Indeed in fact I didn't prepare proper black-and-white mask of depth 1 (just the uninitialized pixmap of that depth), still the created pixmap means allocating some memory area, where plenty of zero and non-zero values are present, so I could expect the moving picture like before, but looking like there was some raster imposed over it (some pixels visible, most of them not). Although indeed the image got spoiled in kind of that way, there are two unexpected effects in addition:
I can see (on my screen) a few green dots in addition — IMHO I shouldn't see there any other colour but blue and red.
There's no more movement of the rectangle! Somehow it got stuck now. Why? The loop doing recalculation and flushing seems to be still circling around, which can be verified by uncommenting the line marked with „<- 4”.
I was also trying to add the „context” to that mask and use it later also to paint it black and white (see the commented out block marked with „<- 3”), but somehow it didn't help neither. Unfortunately, there's no proper docs for XCB (since more than 20 years of its development), neither any decent tutorials (nor code snippets featuring that transparency thing, that one could google for).
Anyone could paste a „working example” that could be used to learn how in XCB actually we can take advantage out of transparency using masks — and how the masks are properly created and used? The suggestions I'm writing under, are vague.
Thanks in advance! :)