Skip to content

Instantly share code, notes, and snippets.

@psychon
Created April 2, 2021 10:10
Show Gist options
  • Save psychon/05d666fb123a019a636430e36c938b69 to your computer and use it in GitHub Desktop.
Save psychon/05d666fb123a019a636430e36c938b69 to your computer and use it in GitHub Desktop.
#include <cairo.h>
#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
static cairo_region_t *unobscured_space(
xcb_connection_t *conn,
xcb_window_t window,
uint16_t width,
uint16_t height) {
int n_children;
xcb_window_t *children;
cairo_region_t *region = cairo_region_create_rectangle(
&(cairo_rectangle_int_t){
.x = 0,
.y = 0,
.width = width,
.height = height,
});
xcb_query_tree_reply_t *tree = xcb_query_tree_reply(
conn,
xcb_query_tree(conn, window),
NULL);
if (!tree) {
return region;
}
n_children = xcb_query_tree_children_length(tree);
children = xcb_query_tree_children(tree);
xcb_get_geometry_cookie_t geometries[n_children];
xcb_get_window_attributes_cookie_t attributes[n_children];
for (int i = 0; i < n_children; i++) {
geometries[i] = xcb_get_geometry(conn, children[i]);
attributes[i] = xcb_get_window_attributes(conn, children[i]);
}
for (int i = 0; i < n_children; i++) {
xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(conn, geometries[i], NULL);
xcb_get_window_attributes_reply_t *attr = xcb_get_window_attributes_reply(conn, attributes[i], NULL);
if (geom && attr && attr->map_state == XCB_MAP_STATE_VIEWABLE) {
cairo_region_subtract_rectangle(
region,
&(cairo_rectangle_int_t) {
.x = geom->x,
.y = geom->y,
.width = geom->width,
.height = geom->height,
});
}
free(geom);
free(attr);
}
free(tree);
return region;
}
static void flicker_window_at(xcb_connection_t *conn, xcb_screen_t *screen, int16_t x, int16_t y, xcb_window_t window, uint32_t pixel) {
xcb_create_window(conn, XCB_COPY_FROM_PARENT, window, screen->root, x, y, 10, 10,
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT,
XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT, (uint32_t[]) { pixel, 1 });
xcb_map_window(conn, window);
xcb_clear_area(conn, 0, window, 0, 0, 0, 0);
free(xcb_get_input_focus_reply(conn, xcb_get_input_focus(conn), NULL));
xcb_destroy_window(conn, window);
}
static void test_back_pixmap(xcb_connection_t *conn, xcb_screen_t *screen, int16_t x, int16_t y) {
xcb_window_t window = xcb_generate_id(conn);
xcb_get_image_reply_t *img1, *img2;
flicker_window_at(conn, screen, x, y, window, screen->black_pixel);
img1 = xcb_get_image_reply(conn,
xcb_get_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, screen->root, x, y, 1, 1, ~0),
NULL);
flicker_window_at(conn, screen, x, y, window, screen->white_pixel);
img2 = xcb_get_image_reply(conn,
xcb_get_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, screen->root, x, y, 1, 1, ~0),
NULL);
if (img1 && img2 && img1->length > 0 && img2->length > 0) {
uint8_t *data1 = xcb_get_image_data(img1);
uint8_t *data2 = xcb_get_image_data(img2);
printf("Pixel 1: %d; pixel 2: %d\n", *data1, *data2);
}
free(img1);
free(img2);
}
int main() {
xcb_connection_t *conn = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
cairo_region_t *region = unobscured_space(conn, screen->root, screen->width_in_pixels, screen->height_in_pixels);
int num_rectangles = cairo_region_num_rectangles(region);
cairo_rectangle_int_t rect;
printf("There are %d free/visible rectangles\n", num_rectangles);
for (int i = 0; i < num_rectangles; i++) {
cairo_region_get_rectangle(region, i, &rect);
printf("Rect %i: top left %dx%d size %dx%d\n", i, rect.x, rect.y, rect.width, rect.height);
test_back_pixmap(conn, screen, rect.x, rect.y);
}
cairo_region_destroy(region);
xcb_disconnect(conn);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment