Last active
September 6, 2024 16:13
-
-
Save vadz/2a5735efb0156c89e9ad43448f8ac2ce to your computer and use it in GitHub Desktop.
Simple shared library to debug XCB events received by the application
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
// Compile with | |
// | |
// $ cc -Wall -shared -fPIC -o libxcb_debug.so xcb_debug.c `pkg-config --cflags --libs xcb` | |
// | |
// Use with | |
// | |
// $ LD_PRELOAD=libxcb_debug.so any_program_using_xcb | |
#define _GNU_SOURCE | |
#include <dlfcn.h> | |
#include <errno.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <xcb/xcb.h> | |
__attribute__((constructor)) | |
void init(void) | |
{ | |
fprintf(stderr, "libxcb_debug.so loaded into %d\n", getpid()); | |
} | |
__attribute__((constructor)) | |
void fini(void) | |
{ | |
fprintf(stderr, "\nlibxcb_debug.so unloaded from %d\n", getpid()); | |
} | |
static const char *event_names[] = { | |
NULL, | |
NULL, | |
"KEY_PRESS", | |
"KEY_RELEASE", | |
"BUTTON_PRESS", | |
"BUTTON_RELEASE", | |
"MOTION_NOTIFY", | |
"ENTER_NOTIFY", | |
"LEAVE_NOTIFY", | |
"FOCUS_IN", | |
"FOCUS_OUT", | |
"KEYMAP_NOTIFY", | |
"EXPOSE", | |
"GRAPHICS_EXPOSURE", | |
"NO_EXPOSURE", | |
"VISIBILITY_NOTIFY", | |
"CREATE_NOTIFY", | |
"DESTROY_NOTIFY", | |
"UNMAP_NOTIFY", | |
"MAP_NOTIFY", | |
"MAP_REQUEST", | |
"REPARENT_NOTIFY", | |
"CONFIGURE_NOTIFY", | |
"CONFIGURE_REQUEST", | |
"GRAVITY_NOTIFY", | |
"RESIZE_REQUEST", | |
"CIRCULATE_NOTIFY", | |
"CIRCULATE_REQUEST", | |
"PROPERTY_NOTIFY", | |
"SELECTION_CLEAR", | |
"SELECTION_REQUEST", | |
"SELECTION_NOTIFY", | |
"COLORMAP_NOTIFY", | |
"CLIENT_MESSAGE", | |
"MAPPING_NOTIFY", | |
"GE_GENERIC", | |
}; | |
static xcb_generic_event_t *debug_event(void *ptr) | |
{ | |
xcb_generic_event_t *e = (xcb_generic_event_t *)ptr; | |
if (!e) | |
return NULL; | |
static int counter = 0; | |
char buf[32]; | |
static char last_buf[32]; | |
uint8_t response_type = e->response_type & ~0x80; | |
switch (response_type) { | |
case XCB_KEY_PRESS: | |
case XCB_KEY_RELEASE: { | |
xcb_key_press_event_t *ev = (xcb_key_press_event_t *)e; | |
snprintf(buf, sizeof(buf), "KEY_%s: %x", | |
response_type == XCB_KEY_PRESS ? "PRESS" : "RELEASE", | |
ev->detail | |
); | |
break; | |
} | |
case XCB_BUTTON_PRESS: | |
case XCB_BUTTON_RELEASE: { | |
xcb_button_press_event_t *ev = (xcb_button_press_event_t *)e; | |
snprintf(buf, sizeof(buf), "BUTTON_%s: %x", | |
response_type == XCB_BUTTON_PRESS ? "PRESS" : "RELEASE", | |
ev->detail | |
); | |
break; | |
} | |
default: { | |
const char *p = NULL; | |
if (response_type < sizeof(event_names) / sizeof(event_names[0])) | |
p = event_names[response_type]; | |
if (p) | |
strncpy(buf, p, sizeof(buf)); | |
else | |
snprintf(buf, sizeof(buf), "unknown (%u)", response_type); | |
break; | |
} | |
} | |
if (strcmp(buf, last_buf) != 0) { | |
fprintf(stderr, | |
"\n[%06u] %s%s", | |
counter, | |
buf, | |
e->response_type & 0x80 ? " (sent)" : "" | |
); | |
strncpy(last_buf, buf, sizeof(last_buf)); | |
} else { | |
fprintf(stderr, "."); | |
} | |
counter++; | |
return e; | |
} | |
xcb_generic_event_t *xcb_wait_for_event(xcb_connection_t *c) | |
{ | |
typedef xcb_generic_event_t *(*xcb_wait_for_event_t)(xcb_connection_t *); | |
static xcb_wait_for_event_t orig_xcb_wait_for_event = NULL; | |
if (!orig_xcb_wait_for_event) { | |
orig_xcb_wait_for_event = (xcb_wait_for_event_t)dlsym(RTLD_NEXT, "xcb_wait_for_event"); | |
if (!orig_xcb_wait_for_event) { | |
fprintf(stderr, "Failed to get xcb_wait_for_event(): %s\n", dlerror()); | |
exit(127); | |
} | |
} | |
return debug_event(orig_xcb_wait_for_event(c)); | |
} | |
xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c) | |
{ | |
typedef xcb_generic_event_t *(*xcb_poll_for_event_t)(xcb_connection_t *); | |
static xcb_poll_for_event_t orig_xcb_poll_for_event = NULL; | |
if (!orig_xcb_poll_for_event) { | |
orig_xcb_poll_for_event = (xcb_poll_for_event_t)dlsym(RTLD_NEXT, "xcb_poll_for_event"); | |
if (!orig_xcb_poll_for_event) { | |
fprintf(stderr, "Failed to get xcb_poll_for_event(): %s\n", dlerror()); | |
exit(127); | |
} | |
} | |
return debug_event(orig_xcb_poll_for_event(c)); | |
} | |
xcb_generic_event_t *xcb_poll_for_queued_event(xcb_connection_t *c) | |
{ | |
typedef xcb_generic_event_t *(*xcb_poll_for_queued_event_t)(xcb_connection_t *); | |
static xcb_poll_for_queued_event_t orig_xcb_poll_for_queued_event = NULL; | |
if (!orig_xcb_poll_for_queued_event) { | |
orig_xcb_poll_for_queued_event = (xcb_poll_for_queued_event_t)dlsym(RTLD_NEXT, "xcb_poll_for_queued_event"); | |
if (!orig_xcb_poll_for_queued_event) { | |
fprintf(stderr, "Failed to get xcb_poll_for_queued_event(): %s\n", dlerror()); | |
exit(127); | |
} | |
} | |
return debug_event(orig_xcb_poll_for_queued_event(c)); | |
} | |
void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e) | |
{ | |
typedef xcb_generic_event_t *(*xcb_wait_for_reply_t)(xcb_connection_t *, unsigned int, xcb_generic_error_t **); | |
static xcb_wait_for_reply_t orig_xcb_wait_for_reply = NULL; | |
if (!orig_xcb_wait_for_reply) { | |
orig_xcb_wait_for_reply = (xcb_wait_for_reply_t)dlsym(RTLD_NEXT, "xcb_wait_for_reply"); | |
if (!orig_xcb_wait_for_reply) { | |
fprintf(stderr, "Failed to get xcb_wait_for_reply(): %s\n", dlerror()); | |
exit(127); | |
} | |
} | |
return debug_event(orig_xcb_wait_for_reply(c, request, e)); | |
} | |
int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error) | |
{ | |
typedef int (*xcb_poll_for_reply_t)(xcb_connection_t *, unsigned int, void **, xcb_generic_error_t **); | |
static xcb_poll_for_reply_t orig_xcb_poll_for_reply = NULL; | |
if (!orig_xcb_poll_for_reply) { | |
orig_xcb_poll_for_reply = (xcb_poll_for_reply_t)dlsym(RTLD_NEXT, "xcb_poll_for_reply"); | |
if (!orig_xcb_poll_for_reply) { | |
fprintf(stderr, "Failed to get xcb_poll_for_reply(): %s\n", dlerror()); | |
exit(127); | |
} | |
} | |
int rc = orig_xcb_poll_for_reply(c, request, reply, error); | |
debug_event(*reply); | |
return rc; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment