Created
April 2, 2021 10:10
-
-
Save psychon/05d666fb123a019a636430e36c938b69 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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