55 lines
2.0 KiB
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;
|
|
}
|