sylware / nyanlinux (public) (License: AFFERO GPLv3) (since 2019-09-09) (hash sha1)
scripts for a lean, from scratch, amd hardware, linux distro

/files/x11cursorvis.c (704118972eb5bca423802c4de8da6f45774a2994) (11928 bytes) (mode 100644) (type blob)

/*
 * code protected with a GNU affero GPLv3 license 
 * copyright (C) 2020 Sylvain BERTRAND
 */
/*
 * usage:
 * "x11cursorvis" alone will turn _ON_ the cursor visibility for the lifetime
 * of the client
 * "x11cursorvis WHATEVER" will turn _OFF_ x11 the cursor visibility for the
 * lifetime of the client
 * 
 * XXX: this code is there for cut and paste as the visibility will be reset
 * once the client is gone
 */
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
/*
 * ABBREVIATIONS:
 * addr : ADDRess
 * auth : AUTHentication
 * err(s) : ERRor(S)
 * evt(s) : EVenT(S)
 * fd : File Descriptor
 * fmt(s) : ForMaT(S)
 * img(s) : IMaGe(S)
 * max : MAXimum
 * min : MINimum
 * n : couNt
 * nr(s) : NumbeR(S)
 * of : OFfset
 * recv : RECeiVe
 * rep(s) : REPly(ieS)
 * req(s) : REQuest(S)
 * scr(s) : SCReen(S)
 * seq : SEQuence
 * str(s) : STRing(S)
 * so : SOcket
 * sz : SiZe (usually a count of bytes)
 * w(s) : Word(S) (32 bits)
 * win(s) : WINdow(S)
 */
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define loop for(;;)
#define FATAL(fmt, ...) ({fprintf(stderr, fmt, ##__VA_ARGS__); exit(EXIT_FAILURE);})
#define POUT(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__)
#define PERR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
static u8 *so_pathname = "/tmp/.X11-unix/X0";
static int so_fd;
#ifdef __GNUC__
#define PACKED __attribute__((packed))
#else
	#error "missing C extension for packed structure declaration"
#endif
struct x11_setup {
	u8 endian;
	u8 unused0;
	u16 major;
	u16 minor;
	u16 auth_name_sz;
	u16 auth_data_sz;
	u16 unused1;
} PACKED;
struct x11_setup_status_common {
	u8 code;
	u8 unused_or_reason_sz;
	u16 major;
	u16 minor;
	u16 additional_data_ws_n;
} PACKED;
struct x11_query_extension_req {
	u8 opcode;
	u8 unused0;
	u16 req_ws_n;
	/*--------------------------------------------------------------------*/
	u16 name_bytes_n;
	u16 unused1;
	u8 name[];
} PACKED;
struct x11_query_extension_rep {
	u8 code;
	u8 unused0;
	u16 seq_nr;
	u32 rep_ws_n;
	/*--------------------------------------------------------------------*/
	u8 present;
	u8 opcode_major;
	u8 first_evt;
	u8 first_err;
	u8 unused1[20];
} PACKED;
struct x11_xfixes_query_version_req {
	u8 opcode_major;
	u8 opcode_minor;
	u16 req_ws_n;
	/*--------------------------------------------------------------------*/
	u32 version_major;
	u32 version_minor;
} PACKED;
struct x11_xfixes_query_version_rep {
	u8 code;
	u8 unused0;
	u16 seq_nr;
	u32 rep_ws_n;
	/*--------------------------------------------------------------------*/
	u32 version_major;
	u32 version_minor;
	u32 unused1[4];
} PACKED;
struct x11_xfixes_hide_or_show_cursor_req {
	u8 opcode_major;
	u8 opcode_minor;
	u16 req_ws_n;
	/*--------------------------------------------------------------------*/
	u32 win_id;
} PACKED;
/* handle short write */
static void x11_write(void *data, u16 sz)
{
	u8 *p;
	size_t sent_bytes_n;

	if (sz == 0)
		return;
	sent_bytes_n = 0;
	p = data;
	loop {
		ssize_t r;

		errno = 0;
		r = write(so_fd, p, (size_t)sz - sent_bytes_n);
		if (r == -1)
			FATAL("error while sending %u bytes to the x11 server:%s\n", (int)((size_t)sz - sent_bytes_n), strerror(errno)); 

		sent_bytes_n += (size_t)r;
		if (sent_bytes_n == (size_t)sz)
			break;
		p += r;
	}
}
/* handle short read */
static u16 x11_read(void *buf, u16 max_sz)
{
	u8 *p;
	size_t recv_bytes_n;

	if (max_sz == 0)
		return 0;
	p = buf;
	recv_bytes_n = 0;
	loop {
		ssize_t r;

		errno = 0;
		r = read(so_fd, p, (size_t)max_sz - recv_bytes_n);
		if (r == -1)
			FATAL("error while receiving %u bytes from the x11 server:%s\n", (int)((size_t)max_sz - recv_bytes_n), strerror(errno));
		if (r == 0) /* no more data: 0-sized datagram, connection properly closed, end of file... */
			break;
		recv_bytes_n += (size_t)r;
		if (recv_bytes_n == (size_t)max_sz)
			break;
		p += r;
	}
	return (u16)recv_bytes_n;
}
int main(int argc, u8 **argv)
{
	int ri;
	u16 r16;
	struct sockaddr_un addr;
	struct x11_setup x11_setup;
	struct x11_setup_status_common x11_status;
	u8 *additional_data;
	u16 vendor_str_bytes_n;
	u8 *vendor_str_bytes_n_of;
	u32 vendor_str_pad_bytes_n;
	u8 *scrs_n_of;
	u8 scrs_n;
	u8 *formats_n_of;
	u8 formats_n;
	//struct format *f;
	u8 *scrs_of;
	u16 *scr0_width_of;
	u16 *scr0_height_of;
	u32 rootwin_id;
	u16 req_ws_n;
	struct x11_query_extension_req *qe_req;
	u16 ext_name_pad_bytes_n;
	struct x11_query_extension_rep qe_rep;
	struct x11_xfixes_query_version_req xf_qv_req;
	struct x11_xfixes_query_version_rep xf_qv_rep;
	struct x11_xfixes_hide_or_show_cursor_req xf_hos_req;
	bool show_cursor;

	close(0);
	additional_data = 0;

	errno = 0;
	/* xserver expects a SOCK_STREAM socket */
	ri = socket(AF_UNIX, SOCK_STREAM, 0);
	if (ri == -1)
		FATAL("unable to create a socket:%s\n", strerror(errno));
	so_fd = ri;
	
	memset(&addr, 0, sizeof(addr));
	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, so_pathname, sizeof(addr.sun_path));
	ri = connect(so_fd, (struct sockaddr*)&addr, sizeof(addr));
	if (ri == -1)
		FATAL("unable to connect the socket %d to address '%s':%s\n", so_fd, so_pathname, strerror(errno));
	POUT("connected to unix socket '%s'\n", so_pathname);
	/*====================================================================*/
	POUT("\nx11 setup -- START\n");
	memset(&x11_setup, 0, sizeof(x11_setup));
	x11_setup.endian = 'l'; /* l-ittle endian or 'B'-ig endian */
	x11_setup.major = 11; /* wayland is x12 */ 
	x11_write(&x11_setup, sizeof(x11_setup));
	POUT("x11 connection setup sent\n");
	POUT("receiving x11 setup status common data...\n");
	r16 = x11_read(&x11_status, sizeof(x11_status));
	if (r16 != sizeof(x11_status))
		FATAL("unable to get x11 setup status common data\n");
	if (x11_status.additional_data_ws_n != 0) {
		additional_data = realloc(additional_data, x11_status.additional_data_ws_n * 4);
		if (additional_data == 0)
			FATAL("unable to allocate memory to x11 setup status additional data\n");
		POUT("receiving x11 setup status additional data, %u bytes...\n", x11_status.additional_data_ws_n * 4);
		r16 = x11_read(additional_data, x11_status.additional_data_ws_n * 4);
		if (r16 != (x11_status.additional_data_ws_n * 4))
			FATAL("incomplete x11 setup status additional data\n");
	}
	if (x11_status.code == 0) {
		POUT("x11 setup: failure\n");
		if (x11_status.additional_data_ws_n != 0)
			/* don't expect any string to end with '\0' */
			FATAL("reason:%.*s\n", (int)x11_status.unused_or_reason_sz, additional_data);
		FATAL("no failure reason provided\n");
	}
	if (x11_status.code == 2)
		FATAL("x11 setup: authentication is not supported\n");
	if (x11_status.code != 1)
		FATAL("x11 setup: unknown status code (0x%02x)\n", x11_status.code);
	/* x11_status.code == 1 */
	POUT("x11 setup success\n");
	POUT("x11 setup -- END\n");
	/*====================================================================*/
	POUT("\nx11 setup additional data processing -- START\n");
	#define VENDOR_STR_OF	32
	#define FORMAT_BYTES_N	8
	vendor_str_bytes_n_of = additional_data + 16; /* x11 specs */
	vendor_str_bytes_n = *(u16*)vendor_str_bytes_n_of;
	vendor_str_pad_bytes_n = vendor_str_bytes_n % 4 ?
					4 - (vendor_str_bytes_n % 4) : 0;
	POUT("vendor string size=%u bytes/%u padding bytes\n", vendor_str_bytes_n, vendor_str_pad_bytes_n);
	/* don't expect any sting to end with '\0' */
	POUT("vendor str is \"%.*s\"\n", vendor_str_bytes_n, additional_data + VENDOR_STR_OF);
	/*--------------------------------------------------------------------*/
	scrs_n_of = additional_data + 20;
	scrs_n = *scrs_n_of;
	POUT("count of screens is %u\n", scrs_n);
	/*--------------------------------------------------------------------*/
	formats_n_of = additional_data + 21;
	formats_n = *formats_n_of;
	POUT("count of formats is %u\n", formats_n);
	/*--------------------------------------------------------------------*/
	scrs_of = additional_data + VENDOR_STR_OF + vendor_str_bytes_n
			+ vendor_str_pad_bytes_n + FORMAT_BYTES_N * formats_n;
	rootwin_id = *(u32*)scrs_of;
	scr0_width_of = (u16*)(scrs_of + 20);
	scr0_height_of = (u16*)(scrs_of + 22);
	POUT("screen 0:root window id=0x%08x;width=%u pixels;height=%u pixels\n", rootwin_id, *scr0_width_of, *scr0_height_of);
	#undef VENDOR_STR_OF
	#undef FORMAT_BYTES_N
	POUT("x11 setup additional data processing -- END\n");
	/*====================================================================*/
	POUT("\nQueryExtension request -- START\n");
	#define STR_SZ(x) (sizeof(x)-1) /* terminate the terminating '\0' */
	#define EXTENSION_NAME "XFIXES"
	ext_name_pad_bytes_n = STR_SZ(EXTENSION_NAME) % 4 ?  4
					- (STR_SZ(EXTENSION_NAME) % 4) : 0;
	req_ws_n = 2 + (STR_SZ(EXTENSION_NAME) + ext_name_pad_bytes_n) / 4;
	qe_req = calloc(1, req_ws_n * 4);
	qe_req->opcode = 98;
	qe_req->req_ws_n = req_ws_n;
	qe_req->name_bytes_n = STR_SZ(EXTENSION_NAME);
	strncpy(qe_req->name, EXTENSION_NAME, STR_SZ(EXTENSION_NAME));
	x11_write(qe_req, req_ws_n * 4);
	POUT("QueryExtension request sent\n");
	#undef STR_SZ
	#undef EXTENSION_NAME
	POUT("QueryExtension request -- END\n");
	/*====================================================================*/
	POUT("\nQueryExtension reply -- START\n");
	memset(&qe_rep, 0, sizeof(qe_rep));
	r16 = x11_read(&qe_rep, sizeof(qe_rep));
	if (r16 != sizeof(qe_rep))
		FATAL("unable to get query extension reply\n");
	POUT("\
QueryExtension reply:\n\
	code				= %u\n\
	sequence number			= %u\n\
	reply 32bits words count	= %u\n\
	present				= %s\n\
	major opcode			= %u\n\
	first event			= %u\n\
	first err			= %u\n\
", qe_rep.code, qe_rep.seq_nr, qe_rep.rep_ws_n, qe_rep.present ? "yes" : "no", qe_rep.opcode_major, qe_rep.first_evt, qe_rep.first_err);
	POUT("QueryExtension reply -- END\n");
	/*====================================================================*/
	POUT("\nxfixes QueryVersion request -- START\n");
	#define QUERY_VERSION_MINOR 0
	#define REQ_WS_N 3
	memset(&xf_qv_req, 0, sizeof(xf_qv_req));	
	xf_qv_req.opcode_major = qe_rep.opcode_major;
	xf_qv_req.opcode_minor = QUERY_VERSION_MINOR;
	xf_qv_req.req_ws_n = REQ_WS_N;
	xf_qv_req.version_major = 4;
	xf_qv_req.version_minor = 0;
	x11_write(&xf_qv_req, REQ_WS_N * 4);
	POUT("xfixes QueryVersion request sent\n");
	#undef QUERY_VERSION_MINOR
	#undef REQ_WS_N
	POUT("xfixes QueryVersion request -- END\n");
	/*====================================================================*/
	POUT("\nxfixes QueryVersion reply -- START\n");
	memset(&xf_qv_rep, 0, sizeof(xf_qv_rep));
	r16 = x11_read(&xf_qv_rep, sizeof(xf_qv_rep));
	if (r16 != sizeof(xf_qv_rep))
		FATAL("unable to get xfixes query version reply\n");
	POUT("\
xfixes QueryVersion reply:\n\
	code				= %u\n\
	sequence number			= %u\n\
	reply 32bits words count	= %u\n\
	major version			= %u\n\
	minor version			= %u\n\
", xf_qv_rep.code, xf_qv_rep.seq_nr, xf_qv_rep.rep_ws_n, xf_qv_rep.version_major, xf_qv_rep.version_minor);
	POUT("xfixes QueryVersion reply -- END\n");
	/*====================================================================*/
	POUT("\nxfixes [Hide/Show]Cursor request -- START\n");
	#define XFIXES_HIDE_CURSOR 29
	#define XFIXES_SHOW_CURSOR 30
	#define REQ_WS_N 2
	memset(&xf_hos_req, 0, sizeof(xf_hos_req));	
	xf_hos_req.opcode_major = qe_rep.opcode_major;
	if (argc > 1) {
		show_cursor = false;
		xf_hos_req.opcode_minor = XFIXES_HIDE_CURSOR;
	} else {
		show_cursor = true;
		xf_hos_req.opcode_minor = XFIXES_SHOW_CURSOR;
	}
	xf_hos_req.req_ws_n = REQ_WS_N;
	xf_hos_req.win_id = rootwin_id;
	x11_write(&xf_hos_req, REQ_WS_N * 4);
	POUT("xfixes %sCursor request sent on the root window (id = 0x%08x)\n", show_cursor ? "Show" : "Hide", rootwin_id);
	#undef XFIXES_HIDE_CURSOR
	#undef XFIXES_SHOW_CURSOR
	#undef REQ_WS_N
	POUT("xfixes [Hide/Show]Cursor request -- END\n");
	/*====================================================================*/
	POUT("done\n");
	sleep(10);
	exit(EXIT_SUCCESS);
}


Mode Type Size Ref File
100644 blob 5 8eba6c8dd4dcaf6166bd22285ed34625f38a84ff .gitignore
100755 blob 1587 57fa4264b9ee0ae0a6f678f2527a05d3b22dda78 00-bootstrap-build.sh
100755 blob 848 a30f443bf405d56682efe3b4c5d3a19d5f7eb45d 01-re-bootstrap-build.sh
100644 blob 2142 f19c2d6b293244bb11a3f74ee77c10675cadc7d6 INSTALL
100644 blob 30 c9b735fa1332286f4b3f5f81fa10527fd7506b6e LICENSE
040000 tree - 169c9f0dee844f98b3123398bc664738b05292a1 builders
100644 blob 1773 ef1551089a803bde37e36edc8d61bb819d06f793 conf.bootstrap.sh
100644 blob 479 8cc15efe46965ac7750fe304460f5a2b0aa4201c conf.sh
040000 tree - 120fb2d034cb100ec077f85a9160bb38c059b440 files
100755 blob 356 8fb8be28ac72f7214b59934b9f74a682665f2d32 pkg-build
100644 blob 22800641 e9e6291054c857401f6835c728f31541dae4311e steam.tar.bz2
100644 blob 173 2047af328b22f9d146585cd9e759edbc18122250 utils.sh
040000 tree - 8e23f551092a35f82b37129dd08c35c4d313c17b x64
040000 tree - b7a22de7f5cbd97650dd45412ef7d4246e395eb8 x86
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/sylware/nyanlinux

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/sylware/nyanlinux

Clone this repository using git:
git clone git://git.rocketgit.com/user/sylware/nyanlinux

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main