From 78c33325d42e8856162235fc83b2304cde1edc72 Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Wed, 13 Aug 2025 03:23:00 +0300 Subject: [PATCH] Tssss... I am playing with libwayland-client --- .gitignore | 3 +- CMakeLists.txt | 3 + Makefile | 46 ++- src/l2/marie/graphics_geom.h | 8 + src/l2/tests/r1/r1.c | 550 +++++++++++++++++++++++++++++++++++ 5 files changed, 602 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 1fa5686..50f6faf 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ vgcore.* *.a8 *.xcf *_NORMAL.png -*_TEMPLATE.png \ No newline at end of file +*_TEMPLATE.png +/out \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 85d0bd0..8370195 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,9 @@ target_link_libraries(0_render_test -lvulkan -lX11 -lm) add_executable(0_render_test_tex_init_prep src/l2/tests/r0/r0_tex_init_prep.c) target_link_libraries(0_render_test_tex_init_prep -lm) +add_executable(1_render_test src/l2/tests/r1/r1.c gen/l_wl_protocols/xdg-shell-private.c) +target_link_libraries(1_render_test -lwayland-client -lrt -lm -lxkbcommon) + add_executable(0_play_test src/l3/tests/p0.c) target_link_libraries(0_play_test -lncurses) diff --git a/Makefile b/Makefile index 1728ba2..da36c86 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,44 @@ -HEADERS := $(shell find src -type f -name '*.h') +#HEADERS := $(shell find src -type f -name '*.h') -all: prototype1 +cflags := -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type --std=c99 -g -ggdb -O0 \ + -fno-trapping-math -D_POSIX_C_SOURCE=200112L -D_GNU_SOURCE +cc := 'gcc' -prototype1: src/l1/main.c $(HEADERS) - @gcc --std c99 -o $@ src/l1/main.c +wl_protocols := $(shell pkg-config --variable=pkgdatadir wayland-protocols) + +gen/l_wl_protocols/xdg-shell-client.h: $(wl_protocols)/stable/xdg-shell/xdg-shell.xml + mkdir -p gen/l_wl_protocols + wayland-scanner client-header $< $@ + +gen/l_wl_protocols/xdg-shell-private.c: $(wl_protocols)/stable/xdg-shell/xdg-shell.xml + mkdir -p gen/l_wl_protocols + wayland-scanner private-code $< $@ + +out/l1/t0: src/l1/tests/t0.c $(HEADERS) + mkdir -p out/l1 + $(cc) $(cflags) -o $@ $< + +out/l1/t1: src/l1/tests/t1.c $(HEADERS) + mkdir -p out/l1 + $(cc) $(cflags) -o $@ $< + +out/l2/codegen_l: src/l2/codegen.c $(HEADERS) + mkdir -p out/l2 + $(cc) $(cflags) -o $@ $< + +out/l2/r0: src/l2/tests/r0/r0.c $(HEADERS) + mkdir -p out/l2 + $(cc) $(cflags) -o $@ $< -lvulkan -lX11 -lm + +out/l2/r0: src/l2/tests/r0/r0_tex_init_prep.c $(HEADERS) + mkdir -p out/l2 + $(cc) $(cflags) -o $@ $< -lm + +out/l2/r1: src/l2/tests/r1/r1.c $(HEADERS) + mkdir -p out/l2 + $(cc) $(cflags) -o $@ $< gen/l_wl_protocols/xdg-shell-private.c -lwayland-client -lrt -lxkbcommon clean: - @rm -f prototype1 - -.PHONY: all clean + rm -rf gen out +.PHONY: clean diff --git a/src/l2/marie/graphics_geom.h b/src/l2/marie/graphics_geom.h index e6d5e09..06c7852 100644 --- a/src/l2/marie/graphics_geom.h +++ b/src/l2/marie/graphics_geom.h @@ -13,6 +13,14 @@ mat4 marie_translation_mat4(vec3 vec) { ); } +mat2 marie_2d_rot_mat2(float a) { + float cosa = cosf(a); + float sina = sinf(a); + return mat2_new( + cosa, -sina, + sina, cosa); +} + mat3 marie_3d_rot_mat3(vec3 r, float a) { float cosa = cosf(a); float sina = sinf(a); diff --git a/src/l2/tests/r1/r1.c b/src/l2/tests/r1/r1.c index e69de29..c5baf49 100644 --- a/src/l2/tests/r1/r1.c +++ b/src/l2/tests/r1/r1.c @@ -0,0 +1,550 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../../../../gen/l_wl_protocols/xdg-shell-client.h" +#include + +#include "../../../l1/core/util.h" +#include "../../marie/graphics_geom.h" +#include "../../marie/rasterization.h" + +// todo: remove +#include + +#define MAX_BUFFER_WIDTH 1000 +#define MAX_BUFFER_HEIGHT 800 +#define SWAPCHAIN_SLOTS 2 + +_Static_assert(INT32_MAX / MAX_BUFFER_WIDTH / MAX_BUFFER_HEIGHT / 4 / SWAPCHAIN_SLOTS > 1, "Swapchain is too big"); + +/* Shared memory support code */ +static void randname(char *buf) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) { + buf[i] = 'A'+(r&15)+(r&16)*2; + r >>= 5; + } +} + +static int create_shm_file(void){ + int retries = 100; + do { + char name[] = "/wl_shm-XXXXXX"; + randname(name + sizeof(name) - 7); + --retries; + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + return -1; +} + +static int allocate_shm_file(size_t size) { + int fd = create_shm_file(); + if (fd < 0) + return -1; + int ret; + do { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + close(fd); + return -1; + } + return fd; +} + +typedef struct { + int fd; + uint32_t* data; + struct wl_shm_pool* pool; + bool want_to_draw; + struct wl_buffer* used_buffers[SWAPCHAIN_SLOTS]; +} swapchain_t; + +typedef struct { + vec2 pos; + vec2 speed; +} durackaya_tochka; + +typedef struct { + /* Globals */ + struct wl_display *wl_display; + struct wl_registry *wl_registry; + struct wl_shm *wl_shm; + struct wl_compositor *wl_compositor; + struct xdg_wm_base *xdg_wm_base; + struct wl_seat *wl_seat; + /* Objects */ + swapchain_t swapchain; + struct wl_surface *wl_surface; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; + /* inputs */ + struct wl_pointer* pointer; + struct wl_keyboard* keyboard; + /* xkb */ + struct xkb_state* xkb_state; + struct xkb_context* xkb_context; + struct xkb_keymap* xkb_keymap; + /* app state */ + vec2 pointer_pos; + bool first_0x80_keys[0x80]; + durackaya_tochka v0; + durackaya_tochka v1; + durackaya_tochka v2; + uint32_t last_frame_time; + int32_t width; + int32_t height; + bool closed; +} my_state; + +typedef struct { + uint32_t* data; + int32_t width; + int32_t height; +} WhereToDrawTriangle; + +U32 color_vec4_to_color_u32(vec4 color) { + return (((U32)roundf(color.w * 255)) << 24) + (((U32)roundf(color.x * color.w * 255)) << 16) + + (((U32)roundf(color.y * color.w * 255)) << 8) + (((U32)roundf(color.z * color.w * 255)) << 0); +} + +void draw_frame_h_rasterizer_cb(void* ug, S32 x, S32 y, vec4 attr) { + WhereToDrawTriangle* g = ug; + if (0 <= x && x < g->width && 0 <= y && y < g->height) + g->data[y * g->width + x] = color_vec4_to_color_u32(attr); +} + +void draw_frame(my_state* state, uint32_t* data, int32_t width, int32_t height) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + data[y * width + x] = 0xFF00FFFF; + } + } + WhereToDrawTriangle aboba = {data, width, height}; + marie_rasterize_triangle_with_attr( + (MariePlaneVertAttr){.pos = state->v0.pos, .attr = {1, 0, 0, 1}}, + (MariePlaneVertAttr){.pos = state->v1.pos, .attr = {0, 1, 0, .5f}}, + (MariePlaneVertAttr){.pos = state->v2.pos, .attr = {0, 0, 1, .0f}}, + (FnMarieRasterizerCallback){.fn = draw_frame_h_rasterizer_cb, .guest = &aboba}); + vec2 points[3] = {state->v0.pos, state->v1.pos, state->v2.pos}; + for (int t = 0; t < 3; t++) { + int x = (int)roundf(points[t].x - .5f); + int y = (int)roundf(points[t].y - .5f); + for (int i = -5; i <= 5; i++) + for (int j = -5; j <= 5; j++) + if (0 <= x+i && x+i < width && 0 <= y+j && y+j < height) + data[(y+j) * width + x + i] = 0; + } +} + +void durackaya_tochka_update(durackaya_tochka* dot, float dur, float width, float height, bool turning_left, bool turning_right) { + vec2 *pos = &dot->pos; + vec2 *speed = &dot->speed; + float a = 0.9f * dur * ((turning_left ? -1.f : 0) + (turning_right ? 1.f : 0)); + *speed = mat2_mul_vec2(marie_2d_rot_mat2(a), *speed); + *pos = vec2_add_vec2(*pos, vec2_mul_scal(*speed, dur)); + if (pos->x < 0) { + speed->x = -speed->x; + pos->x = 0; + } + if (pos->y < 0) { + speed->y = -speed->y; + pos->y = 0; + } + if (pos->x > width) { + speed->x = -speed->x; + pos->x = width; + } + if (pos->y > height) { + speed->y = -speed->y; + pos->y = height; + } +} + +void update_state(my_state* state, uint32_t fl) { + const float width = (float)(state->width < MAX_BUFFER_WIDTH ? state->width : MAX_BUFFER_WIDTH); + const float height = (float)(state->height < MAX_BUFFER_HEIGHT ? state->height : MAX_BUFFER_HEIGHT); + float dur = (float)fl / 1000; + durackaya_tochka_update(&state->v0, dur, width, height, state->first_0x80_keys[XKB_KEY_u], state->first_0x80_keys[XKB_KEY_i]); + durackaya_tochka_update(&state->v1, dur, width, height, state->first_0x80_keys[XKB_KEY_j], state->first_0x80_keys[XKB_KEY_k]); + durackaya_tochka_update(&state->v2, dur, width, height, state->first_0x80_keys[XKB_KEY_m], state->first_0x80_keys[XKB_KEY_less]); +} + +static void main_h_wl_buffer_release(void *data, struct wl_buffer *buffer) { + my_state* state = data; + for (int ij = 0; ij < SWAPCHAIN_SLOTS; ij++) { + if (state->swapchain.used_buffers[ij] == buffer) { + // printf("Buffer %p was released and destroyed\n", buffer); + wl_buffer_destroy(buffer); + state->swapchain.used_buffers[ij] = NULL; + return; + } + } + abortf("HUH??!!!\n"); +} + +static const struct wl_buffer_listener main_h_wl_buffer_listener = { + .release = main_h_wl_buffer_release, +}; + +int swapchain_take_slot(my_state *state) { + for (int ij = 0; ij < SWAPCHAIN_SLOTS; ij++) { + if (!state->swapchain.used_buffers[ij]) { + const int32_t width = state->width < MAX_BUFFER_WIDTH ? state->width : MAX_BUFFER_WIDTH; + const int32_t height = state->height < MAX_BUFFER_HEIGHT ? state->height : MAX_BUFFER_HEIGHT; + struct wl_buffer* s = wl_shm_pool_create_buffer( + state->swapchain.pool, ij * 4 * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT, + width, height, 4 * width, WL_SHM_FORMAT_ARGB8888); + state->swapchain.used_buffers[ij] = s; + wl_buffer_add_listener(s, &main_h_wl_buffer_listener, state); + + return ij; + } + } + return -1; +} + +void try_drawing_frame(my_state *state){ + if (!state->swapchain.want_to_draw) + return; + int ij = swapchain_take_slot(state); + // printf("Got slot %d", ij); + if (ij < 0) + return; + assert(ij < SWAPCHAIN_SLOTS); + state->swapchain.want_to_draw = false; + const int32_t width = state->width < MAX_BUFFER_WIDTH ? state->width : MAX_BUFFER_WIDTH; + const int32_t height = state->height < MAX_BUFFER_HEIGHT ? state->height : MAX_BUFFER_HEIGHT; + + /* Draw checkerboxed background */ + uint32_t* data = state->swapchain.data + ij * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT; + draw_frame(state, data, width, height); + wl_surface_attach(state->wl_surface, state->swapchain.used_buffers[ij], 0, 0); + wl_surface_damage_buffer(state->wl_surface, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_commit(state->wl_surface); +} + +static void main_h_xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial){ + my_state *state = data; + printf("XDG surface configured!\n"); + xdg_surface_ack_configure(xdg_surface, serial); + // todo: synchronize with frame event + state->swapchain.want_to_draw = true; + try_drawing_frame(state); +} + +static void main_h_xdg_toplevel_configure( + void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states + ){ + my_state *state = data; + printf("XDG toplevel configured to (%d %d)\n", width, height); + if (width <= 0 || height < 0) + return; + state->width = width; + state->height = height; +} + +static void main_h_xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel){ + my_state *state = data; + state->closed = true; +} + +static const struct xdg_toplevel_listener main_h_xdg_toplevel_listener = { + .configure = main_h_xdg_toplevel_configure, + .close = main_h_xdg_toplevel_close, +}; + + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = main_h_xdg_surface_configure, +}; + +static void main_h_xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial){ + xdg_wm_base_pong(xdg_wm_base, serial); +} + +static const struct xdg_wm_base_listener main_h_xdg_wm_base_listener = { + .ping = main_h_xdg_wm_base_ping, +}; + + + +static void main_h_wl_keyboard_keymap( + void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size + ) { + my_state* state = data; + // todo: replace asserts with abortf + assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); + char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + assert(map_shm != MAP_FAILED); + + xkb_keymap_unref(state->xkb_keymap); + xkb_state_unref(state->xkb_state); + state->xkb_keymap = xkb_keymap_new_from_string( + state->xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(map_shm, size); + close(fd); + state->xkb_state = xkb_state_new(state->xkb_keymap); + printf("Keymap changed!\n"); + memset(&state->first_0x80_keys, 0, sizeof(state->first_0x80_keys)); +} + +static void main_h_wl_keyboard_enter( + void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys + ) { + my_state* state = data; + printf("keyboard enter; keys pressed are:\n"); + uint32_t *key; + wl_array_for_each(key, keys) { + char buf1[128]; + char buf2[128]; + uint32_t actual_key = *key + 8; + xkb_keysym_t sym = xkb_state_key_get_one_sym(state->xkb_state, actual_key); + // xkb_keysym_get_name(sym, buf1, sizeof(buf1)); + // xkb_state_key_get_utf8(state->xkb_state, actual_key, buf2, sizeof(buf2)); + // printf("sym: %-12s (%d), utf8: '%s'\n", buf1, sym, buf2); + if (sym < 0x80) + state->first_0x80_keys[sym] = true; + } +} + +static void main_h_wl_keyboard_leave( + void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface + ) { + my_state* state = data; + memset(&state->first_0x80_keys, 0, sizeof(state->first_0x80_keys)); +} + +static void main_h_wl_keyboard_key( + void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t key_action + ) { + my_state* state = data; + char buf1[128]; + char buf2[128]; + uint32_t actual_key = key + 8; + /* It actually could be nokey keysym. You never know without checking */ + xkb_keysym_t keysym = xkb_state_key_get_one_sym(state->xkb_state, actual_key); + xkb_keysym_get_name(keysym, buf1, sizeof(buf1)); + xkb_state_key_get_utf8(state->xkb_state, actual_key, buf2, sizeof(buf2)); + printf("Key %s (%d) %s, utf8: '%s'\n", + buf1, keysym, key_action == WL_KEYBOARD_KEY_STATE_PRESSED ? "pressed" : "released", buf2); + if (keysym < 0x80 && key_action == WL_KEYBOARD_KEY_STATE_RELEASED) { + state->first_0x80_keys[keysym] = false; + } else if (keysym < 0x80 && key_action == WL_KEYBOARD_KEY_STATE_PRESSED) { + state->first_0x80_keys[keysym] = true; + } +} + +static void main_h_wl_keyboard_modifiers( + void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group + ) { + my_state* state = data; + xkb_state_update_mask(state->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); +} + +static void main_h_wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay){ + printf("Repeat timings changed: rate = %d, delay = %d", rate, delay); +} + +static const struct wl_keyboard_listener main_h_wl_keyboard_listener = { + .keymap = main_h_wl_keyboard_keymap, + .enter = main_h_wl_keyboard_enter, + .leave = main_h_wl_keyboard_leave, + .key = main_h_wl_keyboard_key, + .modifiers = main_h_wl_keyboard_modifiers, + .repeat_info = main_h_wl_keyboard_repeat_info, +}; + + +static void main_h_wl_pointer_enter( + void *data, struct wl_pointer *wl_pointer, uint32_t serial, + struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y + ) { + my_state *state = data; + state->pointer_pos = (vec2){(float)surface_x / 256.f, (float)surface_y / 256.f}; +} + +static void main_h_wl_pointer_leave( + void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface + ) { + my_state *state = data; +} + +static void main_h_wl_pointer_motion( + void *data,struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y + ) { + my_state *state = data; + state->pointer_pos = (vec2){(float)surface_x / 256.f, (float)surface_y / 256.f}; +} + +static void main_h_wl_pointer_button( + void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t btn_action + ) { + my_state *state = data; + if (btn_action == WL_POINTER_BUTTON_STATE_PRESSED) { + printf("button = %u\n", button); + if (button == 0x110) { + state->v0.pos = state->pointer_pos; + } + } +} + +static void main_h_wl_pointer_axis( + void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value + ) { + my_state *state = data; +} + +static void main_h_wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { + my_state *state = data; +} + +const struct wl_pointer_listener main_h_wl_pointer_listener = { + .enter = main_h_wl_pointer_enter, + .leave = main_h_wl_pointer_leave, + .motion = main_h_wl_pointer_motion, + .button = main_h_wl_pointer_button, + .axis = main_h_wl_pointer_axis, + .frame = main_h_wl_pointer_frame +}; + +static void main_h_wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) { + my_state* state = data; + if (capabilities & WL_SEAT_CAPABILITY_POINTER) { + state->pointer = wl_seat_get_pointer(wl_seat); + assert(state->pointer); + wl_pointer_add_listener(state->pointer, &main_h_wl_pointer_listener, state); + } + if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + state->keyboard = wl_seat_get_keyboard(wl_seat); + assert(state->keyboard); + wl_keyboard_add_listener(state->keyboard, &main_h_wl_keyboard_listener, state); + } +} + +static void main_h_wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) { + printf("Our seat name: %s\n", name); +} + +static const struct wl_seat_listener main_h_wl_seat_listener = { + .capabilities = main_h_wl_seat_capabilities, + .name = main_h_wl_seat_name, +}; + +static void main_h_wl_registry_global( + void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version + ) { + my_state *state = data; + if (strcmp(interface, wl_shm_interface.name) == 0) { + state->wl_shm = wl_registry_bind(wl_registry, name, &wl_shm_interface, 1); + } else if (strcmp(interface, wl_compositor_interface.name) == 0) { + state->wl_compositor = wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + state->xdg_wm_base = wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(state->xdg_wm_base, &main_h_xdg_wm_base_listener, state); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + if (state->wl_seat) { + printf("We got second seat, but we only need one\n"); + return; + } + state->wl_seat = wl_registry_bind(wl_registry, name, &wl_seat_interface, 4); + wl_seat_add_listener(state->wl_seat, &main_h_wl_seat_listener, state); + } +} + +static void main_h_wl_registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name){ + // todo: delete seats +} + +static const struct wl_registry_listener main_h_wl_registry_listener = { + .global = main_h_wl_registry_global, + .global_remove = main_h_wl_registry_global_remove, +}; + +static const struct wl_callback_listener main_h_wl_surface_frame_listener; + +static void main_h_wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time){ + my_state *state = data; + wl_callback_destroy(cb); + cb = wl_surface_frame(state->wl_surface); + wl_callback_add_listener(cb, &main_h_wl_surface_frame_listener, state); + + if (state->last_frame_time != 0) { + update_state(state, time - state->last_frame_time); + } + + state->swapchain.want_to_draw = true; + try_drawing_frame(state); + + state->last_frame_time = time; +} + +static const struct wl_callback_listener main_h_wl_surface_frame_listener = { + .done = main_h_wl_surface_frame_done, +}; + + +int main(int argc, char *argv[]) { + my_state state = { .width = 800, .height = 480 }; + state.v0 = (durackaya_tochka){.pos = {10, 10}, .speed = {100, 100}}; + state.v1 = (durackaya_tochka){.pos = {100, 10}, .speed = {100, -50}}; + state.v2 = (durackaya_tochka){.pos = {5, 330}, .speed = {-20, 170}}; + state.wl_display = wl_display_connect(NULL); + state.wl_registry = wl_display_get_registry(state.wl_display); + wl_registry_add_listener(state.wl_registry, &main_h_wl_registry_listener, &state); + wl_display_roundtrip(state.wl_display); + assert(state.wl_shm); + assert(state.wl_compositor); + assert(state.xdg_wm_base); + { + size_t size = SWAPCHAIN_SLOTS * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT * 4; + assert(size < INT32_MAX); + state.swapchain.fd = allocate_shm_file(size); + if (state.swapchain.fd == -1) { + abortf("AAA"); + } + + state.swapchain.data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, state.swapchain.fd, 0); + if (state.swapchain.data == MAP_FAILED) { + close(state.swapchain.fd); + abortf("what the dog doing"); + } + + state.swapchain.pool = wl_shm_create_pool(state.wl_shm, state.swapchain.fd, size); + assert(state.swapchain.pool); + close(state.swapchain.fd); + } + state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + printf("I am gonna create surfaces\n"); + state.wl_surface = wl_compositor_create_surface(state.wl_compositor); + state.xdg_surface = xdg_wm_base_get_xdg_surface( + state.xdg_wm_base, state.wl_surface); + xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state); + state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface); + xdg_toplevel_add_listener(state.xdg_toplevel, &main_h_xdg_toplevel_listener, &state); + xdg_toplevel_set_title(state.xdg_toplevel, "r1"); + wl_surface_commit(state.wl_surface); + + struct wl_callback* cb = wl_surface_frame(state.wl_surface); + wl_callback_add_listener(cb, &main_h_wl_surface_frame_listener, &state); + + while (wl_display_dispatch(state.wl_display)) { + if (state.closed) + break; + } + // todo: clean up this mess + munmap(state.swapchain.data, SWAPCHAIN_SLOTS * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT * 2); + wl_display_disconnect(state.wl_display); + return 0; +}