AtlatestRepositorysigil-wm
1
/* SPDX-License-Identifier: BSD-3-Clause2
* Real xdg-shell client for configuration, input and composed-pixel tests. */3
#define _POSIX_C_SOURCE 200809L4
#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"18
struct 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
};37
static void request_frame(struct client *c);38
static 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);45
}46
static const struct wl_callback_listener frame_listener={.done=frame};47
static 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);50
}51
static 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);70
}71
static 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);76
}77
static const struct xdg_surface_listener surface_listener={.configure=configure};78
static 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);87
}88
static void layer_closed(void *data, struct zwlr_layer_surface_v1 *surface) {89
(void)surface;90
((struct client *)data)->running = false;91
}92
static const struct zwlr_layer_surface_v1_listener layer_listener = {93
.configure = layer_configure, .closed = layer_closed,94
};95
static 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;100
}101
static void top_close(void *data,struct xdg_toplevel *top) { (void)top; ((struct client *)data)->running=false; }102
static void top_bounds(void *data,struct xdg_toplevel *top,int32_t width,int32_t height) {103
(void)data; (void)top; (void)width; (void)height;104
}105
static void top_capabilities(void *data,struct xdg_toplevel *top,struct wl_array *capabilities) {106
(void)data; (void)top; (void)capabilities;107
}108
static const struct xdg_toplevel_listener top_listener={.configure=top_configure,.close=top_close,109
.configure_bounds=top_bounds,.wm_capabilities=top_capabilities};110
static void ping(void *data,struct xdg_wm_base *shell,uint32_t serial) { (void)data; xdg_wm_base_pong(shell,serial); }111
static const struct xdg_wm_base_listener shell_listener={.ping=ping};112
static 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);114
}115
static 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);117
}118
static 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;120
}121
static 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);123
}124
static 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);126
}127
static void repeat(void *data,struct wl_keyboard *keyboard,int32_t rate,int32_t delay) {128
(void)data;(void)keyboard;(void)rate;(void)delay;129
}130
static const struct wl_keyboard_listener keyboard_listener={.keymap=keymap,.enter=key_enter,.leave=key_leave,.key=key,.modifiers=modifiers,.repeat_info=repeat};131
static 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);133
}134
static 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;136
}137
static 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);146
}147
static 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);149
}150
static 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);152
}153
static void pointer_frame(void *data,struct wl_pointer *p) {(void)data;(void)p;}154
static void pointer_source(void *data,struct wl_pointer *p,uint32_t source) {(void)data;(void)p;(void)source;}155
static void pointer_stop(void *data,struct wl_pointer *p,uint32_t time,uint32_t axis) {(void)data;(void)p;(void)time;(void)axis;}156
static void pointer_discrete(void *data,struct wl_pointer *p,uint32_t axis,int32_t discrete) {(void)data;(void)p;(void)axis;(void)discrete;}157
static 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};158
static 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
}166
}167
static void seat_name(void *data,struct wl_seat *seat,const char *name) {(void)data;(void)seat;(void)name;}168
static const struct wl_seat_listener seat_listener={.capabilities=capabilities,.name=seat_name};169
static 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;173
}174
static 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;177
}178
static const struct wl_output_listener output_listener={.geometry=output_geometry,.mode=output_mode};179
static 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
}199
}200
static void global_remove(void *data,struct wl_registry *registry,uint32_t name) {(void)data;(void)registry;(void)name;}201
static const struct wl_registry_listener registry_listener={.global=global,.global_remove=global_remove};202
int 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,®istry_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;235
}