Oh my fucking god, fuck xcb and X
Some windows have WM_NAME of 0 bytes, so I have to ask for _NET_WM_NAME Atom, but some windows have it as XCB_ATOM_STRING and most of them have it as UTF8_STRING, so I'm just reading UTF-8 one. And ALSO coordinates from xcb_get_geometry are relative to the parent, so I have to translate them using xcb_translate_coordinates, which would be fine, except it completely kills my "queue a bunch of requests and read responses later" paradigm here. Hence, I'm doing it one. by. one. Fuck this shit.
This commit is contained in:
parent
a5cf7cabf3
commit
cfa2af3d91
|
@ -1,16 +1,20 @@
|
||||||
CFLAGS += -Wall -Wextra `exec pkg-config --cflags raylib xcb xcb-composite`
|
CFLAGS += -Wall -Wextra -Wpedantic -Werror `exec pkg-config --cflags raylib xcb xcb-composite`
|
||||||
LDFLAGS := -lm `pkg-config --libs raylib xcb xcb-composite`
|
LDFLAGS := -lm `pkg-config --libs raylib xcb xcb-composite`
|
||||||
|
|
||||||
OBJECTS = ./screenshot.o ./windowtree.o
|
OBJECTS = ./screenshot.o ./windowtree.o
|
||||||
|
|
||||||
scrall: main.c $(OBJECTS)
|
scrall: $(OBJECTS) main.c
|
||||||
$(CC) $(CFLAGS) main.c $(LDFLAGS) -o scrall $(OBJECTS)
|
$(CC) $(CFLAGS) main.c $(LDFLAGS) -o scrall $(OBJECTS)
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(CFLAGS) -c $^ -o $@
|
$(CC) $(CFLAGS) -c $^ -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) scrall
|
$(RM) scrall $(OBJECTS)
|
||||||
|
|
||||||
|
debug:
|
||||||
|
make CFLAGS+=-ggdb
|
||||||
|
gdb ./scrall
|
||||||
|
|
||||||
run: scrall
|
run: scrall
|
||||||
./scrall
|
./scrall
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// x-run: make run
|
// x-run: make run
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
#include "screenshot.h"
|
#include "screenshot.h"
|
||||||
|
@ -19,20 +20,30 @@ int main(int argc, char **argv) {
|
||||||
size_t n_windows;
|
size_t n_windows;
|
||||||
struct window_info *windows = get_windows_list(xcb, &n_windows);
|
struct window_info *windows = get_windows_list(xcb, &n_windows);
|
||||||
|
|
||||||
for (int i = 0; i < n_windows; i++) {
|
|
||||||
printf("0x%08x %02x %s\n", windows[i].wid, windows[i].win_gravity, windows[i].title);
|
|
||||||
}
|
|
||||||
|
|
||||||
xcb_disconnect(xcb);
|
xcb_disconnect(xcb);
|
||||||
|
|
||||||
return 0;
|
SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_RESIZABLE);
|
||||||
|
|
||||||
SetConfigFlags(FLAG_WINDOW_TRANSPARENT);
|
|
||||||
InitWindow(0, 0, "img/scrall");
|
InitWindow(0, 0, "img/scrall");
|
||||||
|
|
||||||
|
Font font = LoadFontEx("/usr/share/fonts/Unifont/Unifont.ttf", 16, 0, 1024);
|
||||||
|
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(BLANK);
|
ClearBackground(Fade(BLACK, 0.9));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n_windows; i++) {
|
||||||
|
DrawTextEx(font,
|
||||||
|
TextFormat("0x%08x %dx%d+%d+%d %s\n",
|
||||||
|
windows[i].wid,
|
||||||
|
windows[i].rect.width,
|
||||||
|
windows[i].rect.height,
|
||||||
|
windows[i].rect.x,
|
||||||
|
windows[i].rect.y,
|
||||||
|
windows[i].title),
|
||||||
|
(Vector2) { 8, 8 + 18 * i }, 16, 0, WHITE);
|
||||||
|
}
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnloadFont(font);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,51 +6,20 @@
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
|
|
||||||
struct _cookies_container {
|
|
||||||
xcb_get_property_cookie_t gp_cookie;
|
|
||||||
xcb_get_geometry_cookie_t gg_cookie;
|
|
||||||
xcb_get_window_attributes_cookie_t ga_cookie;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct window_info *get_windows_list(xcb_connection_t *conn, size_t *n_windows) {
|
struct window_info *get_windows_list(xcb_connection_t *conn, size_t *n_windows) {
|
||||||
xcb_generic_error_t *err;
|
xcb_generic_error_t *err;
|
||||||
|
|
||||||
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
|
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
|
||||||
|
|
||||||
#if 0
|
|
||||||
xcb_query_tree_reply_t *qt_reply;
|
|
||||||
xcb_query_tree_cookie_t qt_cookie = xcb_query_tree(conn, screen->root);
|
|
||||||
|
|
||||||
if (!(qt_reply = xcb_query_tree_reply(conn, qt_cookie, &err))) {
|
|
||||||
fprintf(stderr, "xcb: error: xcb_query_tree_reply: %d\n", err->error_code);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
xcb_window_t *children = xcb_query_tree_children(qt_reply);
|
|
||||||
|
|
||||||
*n_windows = xcb_query_tree_children_length(qt_reply);
|
|
||||||
struct window_info *windows = calloc(*n_windows, sizeof(struct window_info));
|
|
||||||
#else
|
|
||||||
xcb_intern_atom_cookie_t ia_cookie = xcb_intern_atom(conn, 1, 16, "_NET_CLIENT_LIST");
|
xcb_intern_atom_cookie_t ia_cookie = xcb_intern_atom(conn, 1, 16, "_NET_CLIENT_LIST");
|
||||||
xcb_intern_atom_reply_t *ia_reply = xcb_intern_atom_reply(conn, ia_cookie, &err);
|
xcb_intern_atom_reply_t *ia_reply = xcb_intern_atom_reply(conn, ia_cookie, &err);
|
||||||
|
|
||||||
enum xcb_atom_enum_t at_list = XCB_ATOM_WINDOW;
|
|
||||||
|
|
||||||
/*if (!ia_reply) {*/
|
|
||||||
/* printf("using _WIN_CLIENT_LIST\n");*/
|
|
||||||
/* ia_cookie = xcb_intern_atom(conn, 1, 16, "_WIN_CLIENT_LIST");*/
|
|
||||||
/* ia_reply = xcb_intern_atom_reply(conn, ia_cookie, &err);*/
|
|
||||||
/* at_list = XCB_ATOM_CARDINAL;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
if (!ia_reply) {
|
if (!ia_reply) {
|
||||||
fprintf(stderr, "xcb: error: xcb_intern_atom_reply: %d\n", err->error_code);
|
fprintf(stderr, "xcb: error: xcb_intern_atom_reply: %d\n", err->error_code);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_get_property_cookie_t gp_client_list_cookie = xcb_get_property(conn, 0, screen->root, ia_reply->atom, at_list, 0, 1024);
|
xcb_get_property_cookie_t gp_client_list_cookie = xcb_get_property(conn, 0, screen->root, ia_reply->atom, XCB_ATOM_WINDOW, 0, (uint32_t)~0UL);
|
||||||
free(ia_reply);
|
|
||||||
|
|
||||||
xcb_get_property_reply_t *gp_client_list_reply = xcb_get_property_reply(conn, gp_client_list_cookie, &err);
|
xcb_get_property_reply_t *gp_client_list_reply = xcb_get_property_reply(conn, gp_client_list_cookie, &err);
|
||||||
|
|
||||||
|
@ -59,35 +28,51 @@ struct window_info *get_windows_list(xcb_connection_t *conn, size_t *n_windows)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*n_windows = xcb_get_property_value_length(gp_client_list_reply);
|
*n_windows = xcb_get_property_value_length(gp_client_list_reply) / sizeof(xcb_window_t);
|
||||||
printf("length: %zu\n", *n_windows);
|
|
||||||
|
|
||||||
struct window_info *windows = calloc(*n_windows, sizeof(struct window_info));
|
struct window_info *windows = calloc(*n_windows, sizeof(struct window_info));
|
||||||
xcb_window_t *child = (xcb_window_t *)xcb_get_property_value(gp_client_list_reply);
|
xcb_window_t *child = xcb_get_property_value(gp_client_list_reply);
|
||||||
|
|
||||||
for (int i = 0; i < *n_windows; i++) {
|
for (size_t i = 0; i < *n_windows; i++) {
|
||||||
printf("WID 0x%08d\n", child[i]);
|
|
||||||
windows[i].wid = child[i];
|
windows[i].wid = child[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(ia_reply);
|
||||||
free(gp_client_list_reply);
|
free(gp_client_list_reply);
|
||||||
|
|
||||||
#endif
|
// Get atom: UTF8_STRING {{{
|
||||||
|
ia_cookie = xcb_intern_atom(conn, 1, 11, "UTF8_STRING");
|
||||||
|
ia_reply = xcb_intern_atom_reply(conn, ia_cookie, &err);
|
||||||
|
|
||||||
struct _cookies_container *cookies = calloc(*n_windows, sizeof(struct _cookies_container));
|
if (!ia_reply) {
|
||||||
// queueing requests
|
fprintf(stderr, "xcb: error: xcb_intern_atom(UTF8_STRING): %d\n", err->error_code);
|
||||||
for (int i = 0; i < *n_windows; i++) {
|
return NULL;
|
||||||
cookies[i].gp_cookie = xcb_get_property(conn, 0, windows[i].wid, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1023);
|
|
||||||
cookies[i].gg_cookie = xcb_get_geometry(conn, windows[i].wid);
|
|
||||||
cookies[i].ga_cookie = xcb_get_window_attributes(conn, windows[i].wid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reading results
|
xcb_atom_t atom_utf8_string = ia_reply->atom;
|
||||||
for (int i = 0; i < *n_windows; i++) {
|
free(ia_reply);
|
||||||
xcb_get_geometry_reply_t *gg_reply = xcb_get_geometry_reply(conn, cookies[i].gg_cookie, &err);
|
// }}}
|
||||||
|
|
||||||
|
// Get atom: _NET_WM_NAME {{{
|
||||||
|
ia_cookie = xcb_intern_atom(conn, 1, 12, "_NET_WM_NAME");
|
||||||
|
ia_reply = xcb_intern_atom_reply(conn, ia_cookie, &err);
|
||||||
|
|
||||||
|
if (!ia_reply) {
|
||||||
|
fprintf(stderr, "xcb: error: xcb_intern_atom(_NET_WM_NAME): %d\n", err->error_code);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_atom_t atom_net_wm_name = ia_reply->atom;
|
||||||
|
free(ia_reply);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < *n_windows; i++) {
|
||||||
|
// Getting geometry {{{
|
||||||
|
xcb_get_geometry_cookie_t gg_cookie = xcb_get_geometry(conn, windows[i].wid);
|
||||||
|
xcb_get_geometry_reply_t *gg_reply = xcb_get_geometry_reply(conn, gg_cookie, &err);
|
||||||
if (!gg_reply) {
|
if (!gg_reply) {
|
||||||
fprintf(stderr, "xcb: error: xcb_get_geometry: %d\n", err->error_code);
|
fprintf(stderr, "xcb: error: xcb_get_geometry: %d\n", err->error_code);
|
||||||
goto failure;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
windows[i].rect.x = gg_reply->x;
|
windows[i].rect.x = gg_reply->x;
|
||||||
|
@ -96,11 +81,28 @@ struct window_info *get_windows_list(xcb_connection_t *conn, size_t *n_windows)
|
||||||
windows[i].rect.height = gg_reply->height;
|
windows[i].rect.height = gg_reply->height;
|
||||||
|
|
||||||
free(gg_reply);
|
free(gg_reply);
|
||||||
|
// }}}
|
||||||
|
|
||||||
xcb_get_property_reply_t *gp_reply = xcb_get_property_reply(conn, cookies[i].gp_cookie, &err);
|
// Translating geometry {{{
|
||||||
|
xcb_translate_coordinates_cookie_t tc_cookie = xcb_translate_coordinates(conn, windows[i].wid, screen->root, windows[i].rect.x, windows[i].rect.y);
|
||||||
|
xcb_translate_coordinates_reply_t *tc_reply = xcb_translate_coordinates_reply(conn, tc_cookie, &err);
|
||||||
|
if (!tc_reply) {
|
||||||
|
fprintf(stderr, "xcb: error: xcb_translate_coordinates: %d\n", err->error_code);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
windows[i].rect.x = tc_reply->dst_x;
|
||||||
|
windows[i].rect.y = tc_reply->dst_y;
|
||||||
|
|
||||||
|
free(tc_reply);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// Getting name: {{{
|
||||||
|
xcb_get_property_cookie_t gp_cookie = xcb_get_property(conn, 0, windows[i].wid, atom_net_wm_name, atom_utf8_string, 0, 1024);
|
||||||
|
xcb_get_property_reply_t *gp_reply = xcb_get_property_reply(conn, gp_cookie, &err);
|
||||||
if (!gp_reply) {
|
if (!gp_reply) {
|
||||||
fprintf(stderr, "xcb: error: xcb_get_property: %d\n", err->error_code);
|
fprintf(stderr, "xcb: error: xcb_get_property: %d\n", err->error_code);
|
||||||
goto failure;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *gp_value = (char *)xcb_get_property_value(gp_reply);
|
char *gp_value = (char *)xcb_get_property_value(gp_reply);
|
||||||
|
@ -109,22 +111,9 @@ struct window_info *get_windows_list(xcb_connection_t *conn, size_t *n_windows)
|
||||||
strncpy(windows[i].title, gp_value, 1023);
|
strncpy(windows[i].title, gp_value, 1023);
|
||||||
|
|
||||||
free(gp_reply);
|
free(gp_reply);
|
||||||
|
// }}}
|
||||||
xcb_get_window_attributes_reply_t *ga_reply = xcb_get_window_attributes_reply(conn, cookies[i].ga_cookie, &err);
|
|
||||||
if (!gp_reply) {
|
|
||||||
fprintf(stderr, "xcb: error: xcb_get_window_attributes: %d\n", err->error_code);
|
|
||||||
goto failure;
|
|
||||||
}
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
windows[i].win_gravity = ga_reply->win_gravity;
|
|
||||||
|
|
||||||
free(ga_reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(cookies); // yay!
|
|
||||||
return windows; // ewww
|
return windows; // ewww
|
||||||
|
|
||||||
failure:
|
|
||||||
free(cookies);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ struct window_info {
|
||||||
xcb_window_t wid;
|
xcb_window_t wid;
|
||||||
xcb_rectangle_t rect;
|
xcb_rectangle_t rect;
|
||||||
char title[1024];
|
char title[1024];
|
||||||
uint8_t win_gravity;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct window_info *get_windows_list(xcb_connection_t *conn, size_t *n_windows);
|
struct window_info *get_windows_list(xcb_connection_t *conn, size_t *n_windows);
|
||||||
|
|
Loading…
Reference in New Issue