vdi-cloud/terminal/native-cursor/capture-no-cursor.c

55 lines
2.0 KiB
C

/* Linux/glibc X11 capture adapter. Only preload into a leased Sunshine process.
* Sunshine resolves XFixesGetCursorImage with dlsym(), so a plain symbol
* interposer is insufficient. No system library or desktop theme is replaced.
* ABI matches XFixesCursorImage from the Xorg Xfixes.h public header.
*/
#define _GNU_SOURCE
#include <stddef.h>
extern void *dlvsym(void *, const char *, const char *);
extern char *getenv(const char *);
extern int strcmp(const char *, const char *);
extern void abort(void);
extern int open(const char *, int, ...);
extern long write(int, const void *, unsigned long);
extern int close(int);
typedef struct {
short x, y;
unsigned short width, height, xhot, yhot;
unsigned long serial;
unsigned long *pixels;
unsigned long atom;
const char *name;
} CursorImage;
typedef void *(*Lookup)(void *, const char *);
typedef CursorImage *(*GetImage)(void *);
static GetImage real_image;
static CursorImage *capture_image(void *display) {
GetImage fn = __atomic_load_n(&real_image, __ATOMIC_ACQUIRE);
if (!fn) abort();
CursorImage *image = fn(display);
if (image && image->pixels) {
unsigned long n = (unsigned long)image->width * image->height;
if (n > 1048576) abort();
for (unsigned long i = 0; i < n; ++i) image->pixels[i] = 0;
}
return image;
}
void *dlsym(void *handle, const char *name) {
Lookup lookup = (Lookup)dlvsym((void *)-1L, "dlsym", "GLIBC_2.2.5");
if (!lookup) abort();
void *result = lookup(handle, name);
if (result && getenv("VDI_CURSOR_LEASE") &&
strcmp(name, "XFixesGetCursorImage") == 0) {
__atomic_store_n(&real_image, (GetImage)result, __ATOMIC_RELEASE);
const char *receipt = getenv("VDI_CURSOR_RECEIPT");
if (receipt) {
int fd = open(receipt, 0101 | 01000 | 02000000, 0600);
if (fd >= 0) { write(fd, "xfixes-v1\n", 10); close(fd); }
}
return (void *)capture_image;
}
return result;
}