Gfx stack update
[nyanlinux.git] / files / x11cursorvis.c
blob704118972eb5bca423802c4de8da6f45774a2994
1 /*
2 * code protected with a GNU affero GPLv3 license
3 * copyright (C) 2020 Sylvain BERTRAND
4 */
5 /*
6 * usage:
7 * "x11cursorvis" alone will turn _ON_ the cursor visibility for the lifetime
8 * of the client
9 * "x11cursorvis WHATEVER" will turn _OFF_ x11 the cursor visibility for the
10 * lifetime of the client
12 * XXX: this code is there for cut and paste as the visibility will be reset
13 * once the client is gone
15 #include <stdbool.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
25 * ABBREVIATIONS:
26 * addr : ADDRess
27 * auth : AUTHentication
28 * err(s) : ERRor(S)
29 * evt(s) : EVenT(S)
30 * fd : File Descriptor
31 * fmt(s) : ForMaT(S)
32 * img(s) : IMaGe(S)
33 * max : MAXimum
34 * min : MINimum
35 * n : couNt
36 * nr(s) : NumbeR(S)
37 * of : OFfset
38 * recv : RECeiVe
39 * rep(s) : REPly(ieS)
40 * req(s) : REQuest(S)
41 * scr(s) : SCReen(S)
42 * seq : SEQuence
43 * str(s) : STRing(S)
44 * so : SOcket
45 * sz : SiZe (usually a count of bytes)
46 * w(s) : Word(S) (32 bits)
47 * win(s) : WINdow(S)
49 #define u8 uint8_t
50 #define u16 uint16_t
51 #define u32 uint32_t
52 #define loop for(;;)
53 #define FATAL(fmt, ...) ({fprintf(stderr, fmt, ##__VA_ARGS__); exit(EXIT_FAILURE);})
54 #define POUT(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__)
55 #define PERR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
56 static u8 *so_pathname = "/tmp/.X11-unix/X0";
57 static int so_fd;
58 #ifdef __GNUC__
59 #define PACKED __attribute__((packed))
60 #else
61 #error "missing C extension for packed structure declaration"
62 #endif
63 struct x11_setup {
64 u8 endian;
65 u8 unused0;
66 u16 major;
67 u16 minor;
68 u16 auth_name_sz;
69 u16 auth_data_sz;
70 u16 unused1;
71 } PACKED;
72 struct x11_setup_status_common {
73 u8 code;
74 u8 unused_or_reason_sz;
75 u16 major;
76 u16 minor;
77 u16 additional_data_ws_n;
78 } PACKED;
79 struct x11_query_extension_req {
80 u8 opcode;
81 u8 unused0;
82 u16 req_ws_n;
83 /*--------------------------------------------------------------------*/
84 u16 name_bytes_n;
85 u16 unused1;
86 u8 name[];
87 } PACKED;
88 struct x11_query_extension_rep {
89 u8 code;
90 u8 unused0;
91 u16 seq_nr;
92 u32 rep_ws_n;
93 /*--------------------------------------------------------------------*/
94 u8 present;
95 u8 opcode_major;
96 u8 first_evt;
97 u8 first_err;
98 u8 unused1[20];
99 } PACKED;
100 struct x11_xfixes_query_version_req {
101 u8 opcode_major;
102 u8 opcode_minor;
103 u16 req_ws_n;
104 /*--------------------------------------------------------------------*/
105 u32 version_major;
106 u32 version_minor;
107 } PACKED;
108 struct x11_xfixes_query_version_rep {
109 u8 code;
110 u8 unused0;
111 u16 seq_nr;
112 u32 rep_ws_n;
113 /*--------------------------------------------------------------------*/
114 u32 version_major;
115 u32 version_minor;
116 u32 unused1[4];
117 } PACKED;
118 struct x11_xfixes_hide_or_show_cursor_req {
119 u8 opcode_major;
120 u8 opcode_minor;
121 u16 req_ws_n;
122 /*--------------------------------------------------------------------*/
123 u32 win_id;
124 } PACKED;
125 /* handle short write */
126 static void x11_write(void *data, u16 sz)
128 u8 *p;
129 size_t sent_bytes_n;
131 if (sz == 0)
132 return;
133 sent_bytes_n = 0;
134 p = data;
135 loop {
136 ssize_t r;
138 errno = 0;
139 r = write(so_fd, p, (size_t)sz - sent_bytes_n);
140 if (r == -1)
141 FATAL("error while sending %u bytes to the x11 server:%s\n", (int)((size_t)sz - sent_bytes_n), strerror(errno));
143 sent_bytes_n += (size_t)r;
144 if (sent_bytes_n == (size_t)sz)
145 break;
146 p += r;
149 /* handle short read */
150 static u16 x11_read(void *buf, u16 max_sz)
152 u8 *p;
153 size_t recv_bytes_n;
155 if (max_sz == 0)
156 return 0;
157 p = buf;
158 recv_bytes_n = 0;
159 loop {
160 ssize_t r;
162 errno = 0;
163 r = read(so_fd, p, (size_t)max_sz - recv_bytes_n);
164 if (r == -1)
165 FATAL("error while receiving %u bytes from the x11 server:%s\n", (int)((size_t)max_sz - recv_bytes_n), strerror(errno));
166 if (r == 0) /* no more data: 0-sized datagram, connection properly closed, end of file... */
167 break;
168 recv_bytes_n += (size_t)r;
169 if (recv_bytes_n == (size_t)max_sz)
170 break;
171 p += r;
173 return (u16)recv_bytes_n;
175 int main(int argc, u8 **argv)
177 int ri;
178 u16 r16;
179 struct sockaddr_un addr;
180 struct x11_setup x11_setup;
181 struct x11_setup_status_common x11_status;
182 u8 *additional_data;
183 u16 vendor_str_bytes_n;
184 u8 *vendor_str_bytes_n_of;
185 u32 vendor_str_pad_bytes_n;
186 u8 *scrs_n_of;
187 u8 scrs_n;
188 u8 *formats_n_of;
189 u8 formats_n;
190 //struct format *f;
191 u8 *scrs_of;
192 u16 *scr0_width_of;
193 u16 *scr0_height_of;
194 u32 rootwin_id;
195 u16 req_ws_n;
196 struct x11_query_extension_req *qe_req;
197 u16 ext_name_pad_bytes_n;
198 struct x11_query_extension_rep qe_rep;
199 struct x11_xfixes_query_version_req xf_qv_req;
200 struct x11_xfixes_query_version_rep xf_qv_rep;
201 struct x11_xfixes_hide_or_show_cursor_req xf_hos_req;
202 bool show_cursor;
204 close(0);
205 additional_data = 0;
207 errno = 0;
208 /* xserver expects a SOCK_STREAM socket */
209 ri = socket(AF_UNIX, SOCK_STREAM, 0);
210 if (ri == -1)
211 FATAL("unable to create a socket:%s\n", strerror(errno));
212 so_fd = ri;
214 memset(&addr, 0, sizeof(addr));
215 addr.sun_family = AF_UNIX;
216 strncpy(addr.sun_path, so_pathname, sizeof(addr.sun_path));
217 ri = connect(so_fd, (struct sockaddr*)&addr, sizeof(addr));
218 if (ri == -1)
219 FATAL("unable to connect the socket %d to address '%s':%s\n", so_fd, so_pathname, strerror(errno));
220 POUT("connected to unix socket '%s'\n", so_pathname);
221 /*====================================================================*/
222 POUT("\nx11 setup -- START\n");
223 memset(&x11_setup, 0, sizeof(x11_setup));
224 x11_setup.endian = 'l'; /* l-ittle endian or 'B'-ig endian */
225 x11_setup.major = 11; /* wayland is x12 */
226 x11_write(&x11_setup, sizeof(x11_setup));
227 POUT("x11 connection setup sent\n");
228 POUT("receiving x11 setup status common data...\n");
229 r16 = x11_read(&x11_status, sizeof(x11_status));
230 if (r16 != sizeof(x11_status))
231 FATAL("unable to get x11 setup status common data\n");
232 if (x11_status.additional_data_ws_n != 0) {
233 additional_data = realloc(additional_data, x11_status.additional_data_ws_n * 4);
234 if (additional_data == 0)
235 FATAL("unable to allocate memory to x11 setup status additional data\n");
236 POUT("receiving x11 setup status additional data, %u bytes...\n", x11_status.additional_data_ws_n * 4);
237 r16 = x11_read(additional_data, x11_status.additional_data_ws_n * 4);
238 if (r16 != (x11_status.additional_data_ws_n * 4))
239 FATAL("incomplete x11 setup status additional data\n");
241 if (x11_status.code == 0) {
242 POUT("x11 setup: failure\n");
243 if (x11_status.additional_data_ws_n != 0)
244 /* don't expect any string to end with '\0' */
245 FATAL("reason:%.*s\n", (int)x11_status.unused_or_reason_sz, additional_data);
246 FATAL("no failure reason provided\n");
248 if (x11_status.code == 2)
249 FATAL("x11 setup: authentication is not supported\n");
250 if (x11_status.code != 1)
251 FATAL("x11 setup: unknown status code (0x%02x)\n", x11_status.code);
252 /* x11_status.code == 1 */
253 POUT("x11 setup success\n");
254 POUT("x11 setup -- END\n");
255 /*====================================================================*/
256 POUT("\nx11 setup additional data processing -- START\n");
257 #define VENDOR_STR_OF 32
258 #define FORMAT_BYTES_N 8
259 vendor_str_bytes_n_of = additional_data + 16; /* x11 specs */
260 vendor_str_bytes_n = *(u16*)vendor_str_bytes_n_of;
261 vendor_str_pad_bytes_n = vendor_str_bytes_n % 4 ?
262 4 - (vendor_str_bytes_n % 4) : 0;
263 POUT("vendor string size=%u bytes/%u padding bytes\n", vendor_str_bytes_n, vendor_str_pad_bytes_n);
264 /* don't expect any sting to end with '\0' */
265 POUT("vendor str is \"%.*s\"\n", vendor_str_bytes_n, additional_data + VENDOR_STR_OF);
266 /*--------------------------------------------------------------------*/
267 scrs_n_of = additional_data + 20;
268 scrs_n = *scrs_n_of;
269 POUT("count of screens is %u\n", scrs_n);
270 /*--------------------------------------------------------------------*/
271 formats_n_of = additional_data + 21;
272 formats_n = *formats_n_of;
273 POUT("count of formats is %u\n", formats_n);
274 /*--------------------------------------------------------------------*/
275 scrs_of = additional_data + VENDOR_STR_OF + vendor_str_bytes_n
276 + vendor_str_pad_bytes_n + FORMAT_BYTES_N * formats_n;
277 rootwin_id = *(u32*)scrs_of;
278 scr0_width_of = (u16*)(scrs_of + 20);
279 scr0_height_of = (u16*)(scrs_of + 22);
280 POUT("screen 0:root window id=0x%08x;width=%u pixels;height=%u pixels\n", rootwin_id, *scr0_width_of, *scr0_height_of);
281 #undef VENDOR_STR_OF
282 #undef FORMAT_BYTES_N
283 POUT("x11 setup additional data processing -- END\n");
284 /*====================================================================*/
285 POUT("\nQueryExtension request -- START\n");
286 #define STR_SZ(x) (sizeof(x)-1) /* terminate the terminating '\0' */
287 #define EXTENSION_NAME "XFIXES"
288 ext_name_pad_bytes_n = STR_SZ(EXTENSION_NAME) % 4 ? 4
289 - (STR_SZ(EXTENSION_NAME) % 4) : 0;
290 req_ws_n = 2 + (STR_SZ(EXTENSION_NAME) + ext_name_pad_bytes_n) / 4;
291 qe_req = calloc(1, req_ws_n * 4);
292 qe_req->opcode = 98;
293 qe_req->req_ws_n = req_ws_n;
294 qe_req->name_bytes_n = STR_SZ(EXTENSION_NAME);
295 strncpy(qe_req->name, EXTENSION_NAME, STR_SZ(EXTENSION_NAME));
296 x11_write(qe_req, req_ws_n * 4);
297 POUT("QueryExtension request sent\n");
298 #undef STR_SZ
299 #undef EXTENSION_NAME
300 POUT("QueryExtension request -- END\n");
301 /*====================================================================*/
302 POUT("\nQueryExtension reply -- START\n");
303 memset(&qe_rep, 0, sizeof(qe_rep));
304 r16 = x11_read(&qe_rep, sizeof(qe_rep));
305 if (r16 != sizeof(qe_rep))
306 FATAL("unable to get query extension reply\n");
307 POUT("\
308 QueryExtension reply:\n\
309 code = %u\n\
310 sequence number = %u\n\
311 reply 32bits words count = %u\n\
312 present = %s\n\
313 major opcode = %u\n\
314 first event = %u\n\
315 first err = %u\n\
316 ", 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);
317 POUT("QueryExtension reply -- END\n");
318 /*====================================================================*/
319 POUT("\nxfixes QueryVersion request -- START\n");
320 #define QUERY_VERSION_MINOR 0
321 #define REQ_WS_N 3
322 memset(&xf_qv_req, 0, sizeof(xf_qv_req));
323 xf_qv_req.opcode_major = qe_rep.opcode_major;
324 xf_qv_req.opcode_minor = QUERY_VERSION_MINOR;
325 xf_qv_req.req_ws_n = REQ_WS_N;
326 xf_qv_req.version_major = 4;
327 xf_qv_req.version_minor = 0;
328 x11_write(&xf_qv_req, REQ_WS_N * 4);
329 POUT("xfixes QueryVersion request sent\n");
330 #undef QUERY_VERSION_MINOR
331 #undef REQ_WS_N
332 POUT("xfixes QueryVersion request -- END\n");
333 /*====================================================================*/
334 POUT("\nxfixes QueryVersion reply -- START\n");
335 memset(&xf_qv_rep, 0, sizeof(xf_qv_rep));
336 r16 = x11_read(&xf_qv_rep, sizeof(xf_qv_rep));
337 if (r16 != sizeof(xf_qv_rep))
338 FATAL("unable to get xfixes query version reply\n");
339 POUT("\
340 xfixes QueryVersion reply:\n\
341 code = %u\n\
342 sequence number = %u\n\
343 reply 32bits words count = %u\n\
344 major version = %u\n\
345 minor version = %u\n\
346 ", 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);
347 POUT("xfixes QueryVersion reply -- END\n");
348 /*====================================================================*/
349 POUT("\nxfixes [Hide/Show]Cursor request -- START\n");
350 #define XFIXES_HIDE_CURSOR 29
351 #define XFIXES_SHOW_CURSOR 30
352 #define REQ_WS_N 2
353 memset(&xf_hos_req, 0, sizeof(xf_hos_req));
354 xf_hos_req.opcode_major = qe_rep.opcode_major;
355 if (argc > 1) {
356 show_cursor = false;
357 xf_hos_req.opcode_minor = XFIXES_HIDE_CURSOR;
358 } else {
359 show_cursor = true;
360 xf_hos_req.opcode_minor = XFIXES_SHOW_CURSOR;
362 xf_hos_req.req_ws_n = REQ_WS_N;
363 xf_hos_req.win_id = rootwin_id;
364 x11_write(&xf_hos_req, REQ_WS_N * 4);
365 POUT("xfixes %sCursor request sent on the root window (id = 0x%08x)\n", show_cursor ? "Show" : "Hide", rootwin_id);
366 #undef XFIXES_HIDE_CURSOR
367 #undef XFIXES_SHOW_CURSOR
368 #undef REQ_WS_N
369 POUT("xfixes [Hide/Show]Cursor request -- END\n");
370 /*====================================================================*/
371 POUT("done\n");
372 sleep(10);
373 exit(EXIT_SUCCESS);