AtlatestRepositorysigil-wm

sigil-wm / tree / testpixel-client.c

1/* SPDX-License-Identifier: BSD-3-Clause
2 * Real xdg-shell client for configuration, input and composed-pixel tests. */
3#define _POSIX_C_SOURCE 200809L
4#include <errno.h>
5#include <fcntl.h>
6#include <poll.h>
7#include <stdbool.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/mman.h>
13#include <time.h>
14#include <unistd.h>
15#include <wayland-client.h>
16#include "xdg-shell-client-protocol.h"
17#include "wlr-layer-shell-unstable-v1-client-protocol.h"
18struct client {
19 struct wl_display *display;
20 struct wl_compositor *compositor;
21 struct wl_shm *shm;
22 struct wl_seat *seat;
23 struct wl_output *chosen_output;
24 unsigned output_count;
25 struct wl_keyboard *keyboard;
26 struct wl_pointer *pointer;
27 struct xdg_wm_base *shell;
28 struct zwlr_layer_shell_v1 *layers;
29 struct zwlr_layer_surface_v1 *layer;
30 struct wl_surface *surface;
31 struct xdg_surface *xdg;
32 struct xdg_toplevel *top;
33 int width,height;
34 uint32_t color;
35 bool running;
36};
37static void request_frame(struct client *c);
38static void frame(void *data,struct wl_callback *callback,uint32_t time) {
39 (void)time;
40 struct client *c=data;
41 wl_callback_destroy(callback);
42 request_frame(c);
43 wl_surface_damage_buffer(c->surface,0,0,INT32_MAX,INT32_MAX);
44 wl_surface_commit(c->surface);
46static const struct wl_callback_listener frame_listener={.done=frame};
47static void request_frame(struct client *c) {
48 struct wl_callback *callback=wl_surface_frame(c->surface);
49 wl_callback_add_listener(callback,&frame_listener,c);
51static void draw(struct client *c) {
52 char path[]="/tmp/sigil-wm-client-XXXXXX";
53 int fd=mkstemp(path);
54 unlink(path);
55 if(fd<0) exit(2);
56 size_t size=(size_t)c->width*c->height*4;
57 if(ftruncate(fd,size)) exit(2);
58 uint32_t *pixels=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
59 if(pixels==MAP_FAILED) exit(2);
60 for(size_t i=0;i<size/4;i++) pixels[i]=c->color;
61 struct wl_shm_pool *pool=wl_shm_create_pool(c->shm,fd,size);
62 struct wl_buffer *buffer=wl_shm_pool_create_buffer(pool,0,c->width,c->height,c->width*4,WL_SHM_FORMAT_XRGB8888);
63 wl_shm_pool_destroy(pool);
64 munmap(pixels,size); close(fd);
65 wl_surface_attach(c->surface,buffer,0,0);
66 wl_surface_damage_buffer(c->surface,0,0,INT32_MAX,INT32_MAX);
67 request_frame(c);
68 wl_surface_commit(c->surface);
69 wl_buffer_destroy(buffer);
71static void configure(void *data,struct xdg_surface *surface,uint32_t serial) {
72 struct client *c=data;
73 xdg_surface_ack_configure(surface,serial);
74 draw(c);
75 printf("CLIENT_CONFIGURE=%dx%d\n",c->width,c->height); fflush(stdout);
77static const struct xdg_surface_listener surface_listener={.configure=configure};
78static void layer_configure(void *data, struct zwlr_layer_surface_v1 *surface,
79 uint32_t serial, uint32_t width, uint32_t height) {
80 struct client *client = data;
81 client->width = width;
82 client->height = height;
83 zwlr_layer_surface_v1_ack_configure(surface, serial);
84 draw(client);
85 printf("LAYER_CONFIGURE=%ux%u\n", width, height);
86 fflush(stdout);
88static void layer_closed(void *data, struct zwlr_layer_surface_v1 *surface) {
89 (void)surface;
90 ((struct client *)data)->running = false;
92static const struct zwlr_layer_surface_v1_listener layer_listener = {
93 .configure = layer_configure, .closed = layer_closed,
94};
95static void top_configure(void *data,struct xdg_toplevel *top,int32_t width,int32_t height,struct wl_array *states) {
96 (void)top; (void)states;
97 struct client *c=data;
98 if(width>0 && width<=16384) c->width=width;
99 if(height>0 && height<=16384) c->height=height;
101static void top_close(void *data,struct xdg_toplevel *top) { (void)top; ((struct client *)data)->running=false; }
102static void top_bounds(void *data,struct xdg_toplevel *top,int32_t width,int32_t height) {
103 (void)data; (void)top; (void)width; (void)height;
105static void top_capabilities(void *data,struct xdg_toplevel *top,struct wl_array *capabilities) {
106 (void)data; (void)top; (void)capabilities;
108static const struct xdg_toplevel_listener top_listener={.configure=top_configure,.close=top_close,
109 .configure_bounds=top_bounds,.wm_capabilities=top_capabilities};
110static void ping(void *data,struct xdg_wm_base *shell,uint32_t serial) { (void)data; xdg_wm_base_pong(shell,serial); }
111static const struct xdg_wm_base_listener shell_listener={.ping=ping};
112static void keymap(void *data,struct wl_keyboard *keyboard,uint32_t format,int fd,uint32_t size) {
113 (void)data; (void)keyboard; (void)format; (void)size; close(fd);
115static void key_enter(void *data,struct wl_keyboard *keyboard,uint32_t serial,struct wl_surface *surface,struct wl_array *keys) {
116 (void)data;(void)keyboard;(void)serial;(void)surface;(void)keys; puts("CLIENT_KEYBOARD_ENTER"); fflush(stdout);
118static void key_leave(void *data,struct wl_keyboard *keyboard,uint32_t serial,struct wl_surface *surface) {
119 (void)data;(void)keyboard;(void)serial;(void)surface;
121static void key(void *data,struct wl_keyboard *keyboard,uint32_t serial,uint32_t time,uint32_t code,uint32_t state) {
122 (void)data;(void)keyboard;(void)serial;(void)time; printf("CLIENT_KEY=%u,%u\n",code,state); fflush(stdout);
124static void modifiers(void *data,struct wl_keyboard *keyboard,uint32_t serial,uint32_t dep,uint32_t lat,uint32_t lock,uint32_t group) {
125 (void)data;(void)keyboard;(void)serial; printf("CLIENT_MODIFIERS=%u,%u,%u,%u\n",dep,lat,lock,group); fflush(stdout);
127static void repeat(void *data,struct wl_keyboard *keyboard,int32_t rate,int32_t delay) {
128 (void)data;(void)keyboard;(void)rate;(void)delay;
130static const struct wl_keyboard_listener keyboard_listener={.keymap=keymap,.enter=key_enter,.leave=key_leave,.key=key,.modifiers=modifiers,.repeat_info=repeat};
131static void pointer_enter(void *data,struct wl_pointer *p,uint32_t serial,struct wl_surface *surface,wl_fixed_t x,wl_fixed_t y) {
132 (void)data;(void)p;(void)serial;(void)surface; printf("CLIENT_POINTER_ENTER=%d,%d\n",wl_fixed_to_int(x),wl_fixed_to_int(y)); fflush(stdout);
134static void pointer_leave(void *data,struct wl_pointer *p,uint32_t serial,struct wl_surface *surface) {
135 (void)data;(void)p;(void)serial;(void)surface;
137static void pointer_motion(void *data,struct wl_pointer *p,uint32_t time,wl_fixed_t x,wl_fixed_t y) {
138 if(getenv("SIGIL_WM_CLIENT_TIMESTAMPS")) {
139 struct timespec now;
140 clock_gettime(CLOCK_MONOTONIC,&now);
141 printf("CLIENT_POINTER_TIME=%lld %d %d protocol-ms=%u\n",
142 (long long)now.tv_sec*1000000000+now.tv_nsec,
143 wl_fixed_to_int(x),wl_fixed_to_int(y),time);
144 }
145 (void)data;(void)p;(void)time; printf("CLIENT_POINTER_MOTION=%d,%d\n",wl_fixed_to_int(x),wl_fixed_to_int(y)); fflush(stdout);
147static void pointer_button(void *data,struct wl_pointer *p,uint32_t serial,uint32_t time,uint32_t code,uint32_t state) {
148 (void)data;(void)p;(void)serial;(void)time; printf("CLIENT_BUTTON=%u,%u\n",code,state); fflush(stdout);
150static void pointer_axis(void *data,struct wl_pointer *p,uint32_t time,uint32_t axis,wl_fixed_t value) {
151 (void)data;(void)p;(void)time; printf("CLIENT_AXIS=%u,%d\n",axis,wl_fixed_to_int(value)); fflush(stdout);
153static void pointer_frame(void *data,struct wl_pointer *p) {(void)data;(void)p;}
154static void pointer_source(void *data,struct wl_pointer *p,uint32_t source) {(void)data;(void)p;(void)source;}
155static void pointer_stop(void *data,struct wl_pointer *p,uint32_t time,uint32_t axis) {(void)data;(void)p;(void)time;(void)axis;}
156static void pointer_discrete(void *data,struct wl_pointer *p,uint32_t axis,int32_t discrete) {(void)data;(void)p;(void)axis;(void)discrete;}
157static const struct wl_pointer_listener pointer_listener={.enter=pointer_enter,.leave=pointer_leave,.motion=pointer_motion,.button=pointer_button,.axis=pointer_axis,.frame=pointer_frame,.axis_source=pointer_source,.axis_stop=pointer_stop,.axis_discrete=pointer_discrete};
158static void capabilities(void *data,struct wl_seat *seat,uint32_t mask) {
159 struct client *c=data;
160 if((mask&WL_SEAT_CAPABILITY_KEYBOARD) && !c->keyboard) {
161 c->keyboard=wl_seat_get_keyboard(seat); wl_keyboard_add_listener(c->keyboard,&keyboard_listener,c);
162 }
163 if((mask&WL_SEAT_CAPABILITY_POINTER) && !c->pointer) {
164 c->pointer=wl_seat_get_pointer(seat); wl_pointer_add_listener(c->pointer,&pointer_listener,c);
165 }
167static void seat_name(void *data,struct wl_seat *seat,const char *name) {(void)data;(void)seat;(void)name;}
168static const struct wl_seat_listener seat_listener={.capabilities=capabilities,.name=seat_name};
169static void output_geometry(void *data,struct wl_output *output,int32_t x,int32_t y,
170 int32_t pw,int32_t ph,int32_t subpixel,const char *make,const char *model,int32_t transform) {
171 (void)data; (void)output; (void)x; (void)y; (void)pw; (void)ph;
172 (void)subpixel; (void)make; (void)model; (void)transform;
174static void output_mode(void *data,struct wl_output *output,uint32_t flags,
175 int32_t width,int32_t height,int32_t refresh) {
176 (void)data; (void)output; (void)flags; (void)width; (void)height; (void)refresh;
178static const struct wl_output_listener output_listener={.geometry=output_geometry,.mode=output_mode};
179static void global(void *data,struct wl_registry *registry,uint32_t name,const char *interface,uint32_t version) {
180 struct client *c=data;
181 if(!strcmp(interface,wl_compositor_interface.name)) c->compositor=wl_registry_bind(registry,name,&wl_compositor_interface,4);
182 else if(!strcmp(interface,wl_shm_interface.name)) c->shm=wl_registry_bind(registry,name,&wl_shm_interface,1);
183 else if(!strcmp(interface,xdg_wm_base_interface.name)) {
184 c->shell=wl_registry_bind(registry,name,&xdg_wm_base_interface,version<6 ? version : 6);
185 xdg_wm_base_add_listener(c->shell,&shell_listener,c);
186 } else if(!strcmp(interface,zwlr_layer_shell_v1_interface.name)) {
187 c->layers=wl_registry_bind(registry,name,&zwlr_layer_shell_v1_interface,version<4 ? version : 4);
188 } else if(!strcmp(interface,wl_output_interface.name)) {
189 c->output_count++;
190 const char *selected=getenv("SIGIL_WM_LAYER_OUTPUT");
191 if(selected && strtoul(selected,NULL,10)==c->output_count) {
192 c->chosen_output=wl_registry_bind(registry,name,&wl_output_interface,1);
193 wl_output_add_listener(c->chosen_output,&output_listener,c);
194 }
195 } else if(!strcmp(interface,wl_seat_interface.name)) {
196 c->seat=wl_registry_bind(registry,name,&wl_seat_interface,version<5 ? version : 5);
197 wl_seat_add_listener(c->seat,&seat_listener,c);
198 }
200static void global_remove(void *data,struct wl_registry *registry,uint32_t name) {(void)data;(void)registry;(void)name;}
201static const struct wl_registry_listener registry_listener={.global=global,.global_remove=global_remove};
202int main(int argc,char **argv) {
203 if(argc!=3 && argc!=4) { fprintf(stderr,"usage: pixel-client RGB TITLE [layer]\n"); return 2; }
204 struct client c={.width=320,.height=240,.color=0xff000000|(uint32_t)strtoul(argv[1],NULL,16),.running=true};
205 c.display=wl_display_connect(NULL);
206 if(!c.display) return 2;
207 struct wl_registry *registry=wl_display_get_registry(c.display);
208 wl_registry_add_listener(registry,&registry_listener,&c);
209 if(wl_display_roundtrip(c.display)<0 || !c.compositor || !c.shm || !c.shell) return 2;
210 c.surface=wl_compositor_create_surface(c.compositor);
211 if(argc==4) {
212 if(strcmp(argv[3], "layer") || !c.layers) return 2;
213 c.layer=zwlr_layer_shell_v1_get_layer_surface(c.layers,c.surface,c.chosen_output,
214 ZWLR_LAYER_SHELL_V1_LAYER_TOP,"sigil-wm-test");
215 zwlr_layer_surface_v1_add_listener(c.layer,&layer_listener,&c);
216 zwlr_layer_surface_v1_set_anchor(c.layer,ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
217 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
218 zwlr_layer_surface_v1_set_size(c.layer,0,32);
219 zwlr_layer_surface_v1_set_margin(c.layer,3,4,5,6);
220 zwlr_layer_surface_v1_set_exclusive_zone(c.layer,32);
221 zwlr_layer_surface_v1_set_keyboard_interactivity(c.layer,
222 ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE);
223 } else {
224 c.xdg=xdg_wm_base_get_xdg_surface(c.shell,c.surface);
225 xdg_surface_add_listener(c.xdg,&surface_listener,&c);
226 c.top=xdg_surface_get_toplevel(c.xdg);
227 xdg_toplevel_add_listener(c.top,&top_listener,&c);
228 xdg_toplevel_set_title(c.top,argv[2]);
229 xdg_toplevel_set_app_id(c.top,"sigil-wm-pixel-client");
230 }
231 wl_surface_commit(c.surface);
232 while(c.running && wl_display_dispatch(c.display)>=0) {}
233 wl_display_disconnect(c.display);
234 return 0;