diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 8ad94e4..b111557 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -40,7 +40,7 @@ add_custom_command( add_custom_target(generate-xdg-shell DEPENDS xdg-shell-client-protocol.h xdg-shell-client-protocol.c) # Создаем исполняемый файл из ассемблерного, C и сгенерированного кода -add_executable(wayland asm.asm c.c xdg-shell-client-protocol.c) +add_executable(wayland asm.asm c.c input.c registry.c window.c xdg-shell-client-protocol.c) # Зависимость от генерации протокола add_dependencies(wayland generate-xdg-shell) diff --git a/wayland/c.c b/wayland/c.c index 03c284c..8423ecd 100644 --- a/wayland/c.c +++ b/wayland/c.c @@ -6,314 +6,28 @@ #include #include #include "xdg-shell-client-protocol.h" +#include "input.h" +#include "window.h" +#include "registry.h" -static struct wl_compositor *compositor; -static struct xdg_wm_base *xdg_wm_base; -static struct wl_seat *seat; -static struct wl_keyboard *keyboard; +// core is now split into modules: registry, input and window -/* xkbcommon helpers */ -static struct xkb_context *xkb_ctx = NULL; -static struct xkb_keymap *xkb_keymap = NULL; -static struct xkb_state *xkb_state = NULL; +// resize, draw and frame callbacks moved to `window.c` -// Всё ниже - для одного окна -static struct xdg_surface *xdg_surface; -static struct xdg_toplevel *xdg_toplevel; -static struct wl_surface *wl_surface; -static struct wl_buffer *buffer; -static struct wl_shm *shm; -static int16_t width = 200; -static int16_t height = 100; -static int8_t *data; -static int8_t need_close = 0; +/* Input, window and registry logic has been moved into separate modules. + * This file now wires them together and runs the main loop. */ -int32_t alloc_shm(size_t size) -{ - char name[32]; - sprintf(name, "/wayland-shm-%d", getpid()); +/* Window events moved to `window.c` */ - int32_t fd = shm_open(name, O_RDWR | O_CREAT, 0600); - if (fd == -1) - return fd; - shm_unlink(name); - ftruncate(fd, size); - return fd; -} +/* frame callback now in `window.c` */ -void resize_canvas() -{ - size_t stride = width * 4; - size_t size = stride * height; - int32_t fd = alloc_shm(size); - - data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); - buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - wl_shm_pool_destroy(pool); - close(fd); -} - -void resize_new(int16_t w, int16_t h) -{ - if (!w || !h) - return; - if (width != w || height != h) - { - if(data) - munmap(data, width*height*4); - width = w; - height = h; - resize_canvas(); - } -} - -/* ---------------- Keyboard handling ----------------- */ - -void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) -{ - printf("keyboard: keymap format=%u size=%u\n", format, size); - if (fd < 0) - return; - - /* Only support xkb v1 */ - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) - { - /* nothing we can do */ - close(fd); - return; - } - - /* Map keymap to memory */ - char *map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (map == MAP_FAILED) - { - perror("mmap"); - close(fd); - return; - } - - if (!xkb_ctx) - xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - /* Free previous keymap/state */ - if (xkb_state) - { - xkb_state_unref(xkb_state); - xkb_state = NULL; - } - if (xkb_keymap) - { - xkb_keymap_unref(xkb_keymap); - xkb_keymap = NULL; - } - - xkb_keymap = xkb_keymap_new_from_string(xkb_ctx, map, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - if (!xkb_keymap) - { - fprintf(stderr, "Unable to compile xkb keymap\n"); - munmap(map, size); - close(fd); - return; - } - - xkb_state = xkb_state_new(xkb_keymap); - - munmap(map, size); - close(fd); -} - -void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) -{ - printf("keyboard: enter serial=%u surface=%p\n", serial, surface); -} - -void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) -{ - printf("keyboard: leave serial=%u surface=%p\n", serial, surface); -} - -void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) -{ - const char *s = (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? "PRESSED" : "RELEASED"; - printf("keyboard: key serial=%u time=%u key=%u state=%s\n", serial, time, key, s); - - /* Convert keycode to keysym using xkb */ - if (xkb_state) - { - /* xkb uses keycodes offset by 8 */ - xkb_keycode_t kc = (xkb_keycode_t)key + 8; - xkb_keysym_t ks = xkb_state_key_get_one_sym(xkb_state, kc); - if (ks != XKB_KEY_NoSymbol) - { - char buf[64]; - int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf)); - if (n > 0) - printf("keyboard: symbol '%s' (keysym 0x%x)\n", buf, ks); - else - printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks); - } - } -} - -void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) -{ - printf("keyboard: modifiers serial=%u depressed=%u latched=%u locked=%u group=%u\n", serial, mods_depressed, mods_latched, mods_locked, group); - if (xkb_state) - { - /* newer libxkbcommon uses three layout args; use group for depressed */ - xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0); - } -} - -void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay) -{ - printf("keyboard: repeat rate=%d delay=%d\n", rate, delay); -} - -struct wl_keyboard_listener keyboard_listener = { - .keymap = keyboard_keymap, - .enter = keyboard_enter, - .leave = keyboard_leave, - .key = keyboard_key, - .modifiers = keyboard_modifiers, - .repeat_info = keyboard_repeat_info -}; - -void seat_capabilities(void *data, struct wl_seat *seat, uint32_t caps) -{ - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !keyboard) - { - keyboard = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(keyboard, &keyboard_listener, 0); - printf("Seat reports keyboard capability - keyboard bound\n"); - } - else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && keyboard) - { - wl_keyboard_destroy(keyboard); - keyboard = NULL; - if (xkb_state) - { - xkb_state_unref(xkb_state); - xkb_state = NULL; - } - if (xkb_keymap) - { - xkb_keymap_unref(xkb_keymap); - xkb_keymap = NULL; - } - } -} - -void seat_name(void *data, struct wl_seat *seat, const char *name) -{ - printf("Seat name: %s\n", name); -} - -struct wl_seat_listener seat_listener = { - .capabilities = seat_capabilities, - .name = seat_name -}; - -int8_t c; -void draw() -{ - size_t stride = width * 4; - size_t size = stride * height; - - memset(data, c++, size); - - wl_surface_attach(wl_surface, buffer, 0, 0); - wl_surface_damage_buffer(wl_surface, 0, 0, width, height); - wl_surface_commit(wl_surface); -} - -void xdg_surface_conf(void *data, struct xdg_surface *xdg_surface, uint32_t serial) -{ - xdg_surface_ack_configure(xdg_surface, serial); - if (!data) - resize_canvas(); - - draw(); -} - -void xdg_toplevel_conf(void *data, struct xdg_toplevel *xdg_top, int32_t w, int32_t h, struct wl_array *states) -{ - resize_new(w, h); -} - -void xdg_toplevel_cls(void *data, struct xdg_toplevel *xdg_top) -{ - need_close = 1; -} - -void xdg_toplevel_bounds(void *data, struct xdg_toplevel *xdg_top, int32_t w, int32_t h) -{ -} - -void xdg_toplevel_wm_caps(void *data, struct xdg_toplevel *xdg_top, struct wl_array *caps) -{ -} - -struct wl_callback_listener callback_listener; -void frame_new(void *date, struct wl_callback *cb, uint32_t _) -{ - wl_callback_destroy(cb); - cb = wl_surface_frame(wl_surface); - wl_callback_add_listener(cb, &callback_listener, 0); - draw(); -} - -void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial) -{ - xdg_wm_base_pong(wm_base, serial); -} - -struct xdg_wm_base_listener wm_base_listener; +/* ping/pong moved to `window.c` */ // Функция для прослушивания глобальных объектов -void registry_global(void *data, struct wl_registry *reg, uint32_t name, const char *intf, uint32_t version) -{ - printf("%u\t%s\tv:%u\n", name, intf, version); - if (!strcmp(intf, wl_compositor_interface.name)) - { - compositor = wl_registry_bind(reg, name, &wl_compositor_interface, version); - } - else if (!strcmp(intf, wl_shm_interface.name)) - { - shm = wl_registry_bind(reg, name, &wl_shm_interface, version); - } - else if (!strcmp(intf, xdg_wm_base_interface.name)) - { - xdg_wm_base = wl_registry_bind(reg, name, &xdg_wm_base_interface, version); - xdg_wm_base_add_listener(xdg_wm_base, &wm_base_listener, 0); - } - else if (!strcmp(intf, wl_seat_interface.name)) - { - seat = wl_registry_bind(reg, name, &wl_seat_interface, version); - wl_seat_add_listener(seat, &seat_listener, 0); - } -} +/* registry listener moved to `registry.c` */ -void registry_global_remove(void *data, struct wl_registry *reg, uint32_t name) {} +// No registry functions here; they are implemented in `registry.c`. -struct wl_callback_listener callback_listener = { - .done = frame_new}; - -struct xdg_wm_base_listener wm_base_listener = { - .ping = wm_base_ping}; - -struct xdg_toplevel_listener top_listener = { - .configure = xdg_toplevel_conf, - .close = xdg_toplevel_cls, - .configure_bounds = xdg_toplevel_bounds, - .wm_capabilities = xdg_toplevel_wm_caps}; - -struct xdg_surface_listener surface_listener = { - .configure = xdg_surface_conf}; - -struct wl_registry_listener registry_listener = { - .global = registry_global, - .global_remove = registry_global_remove}; +/* listeners implemented in modules */ int32_t run_wayland() { @@ -321,38 +35,22 @@ int32_t run_wayland() if (!display) return -1; struct wl_registry *registry = wl_display_get_registry(display); - wl_registry_add_listener(registry, ®istry_listener, 0); + registry_add_listener(registry); wl_display_roundtrip(display); - - wl_surface = wl_compositor_create_surface(compositor); - struct wl_callback *wl_callback = wl_surface_frame(wl_surface); - wl_callback_add_listener(wl_callback, &callback_listener, 0); - - xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, wl_surface); - xdg_surface_add_listener(xdg_surface, &surface_listener, 0); - xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); - xdg_toplevel_add_listener(xdg_toplevel, &top_listener, 0); - xdg_toplevel_set_title(xdg_toplevel, "Custom client"); - wl_surface_commit(wl_surface); + struct wayland_window win; + if (window_init(display, &win) < 0) + return -1; while (wl_display_dispatch(display)) { - if (need_close) + if (window_should_close(&win)) { printf("Window closing\n"); break; } } - - if (buffer) - wl_buffer_destroy(buffer); - xdg_toplevel_destroy(xdg_toplevel); - xdg_surface_destroy(xdg_surface); - wl_surface_destroy(wl_surface); - if (keyboard) - wl_keyboard_destroy(keyboard); - if (seat) - wl_seat_destroy(seat); + window_destroy(&win); + input_cleanup(); wl_display_disconnect(display); return 0; } \ No newline at end of file diff --git a/wayland/input.c b/wayland/input.c new file mode 100644 index 0000000..98290ee --- /dev/null +++ b/wayland/input.c @@ -0,0 +1,190 @@ +#include "input.h" +#include +#include +#include +#include +#include +#include + +static struct wl_seat *seat = NULL; +static struct wl_keyboard *keyboard = NULL; +static struct xkb_context *xkb_ctx = NULL; +static struct xkb_keymap *xkb_keymap = NULL; +static struct xkb_state *xkb_state = NULL; + +/* keyboard callbacks */ +static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) +{ + printf("keyboard: keymap format=%u size=%u\n", format, size); + if (fd < 0) + return; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) + { + close(fd); + return; + } + + char *map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + perror("mmap"); + close(fd); + return; + } + + if (!xkb_ctx) + xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + if (xkb_state) + { + xkb_state_unref(xkb_state); + xkb_state = NULL; + } + if (xkb_keymap) + { + xkb_keymap_unref(xkb_keymap); + xkb_keymap = NULL; + } + + xkb_keymap = xkb_keymap_new_from_string(xkb_ctx, map, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!xkb_keymap) + { + fprintf(stderr, "Unable to compile xkb keymap\n"); + munmap(map, size); + close(fd); + return; + } + + xkb_state = xkb_state_new(xkb_keymap); + + munmap(map, size); + close(fd); +} + +static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) +{ + printf("keyboard: enter serial=%u surface=%p\n", serial, surface); +} + +static void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) +{ + printf("keyboard: leave serial=%u surface=%p\n", serial, surface); +} + +static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + const char *s = (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? "PRESSED" : "RELEASED"; + printf("keyboard: key serial=%u time=%u key=%u state=%s\n", serial, time, key, s); + + if (xkb_state) + { + xkb_keycode_t kc = (xkb_keycode_t)key + 8; + xkb_keysym_t ks = xkb_state_key_get_one_sym(xkb_state, kc); + if (ks != XKB_KEY_NoSymbol) + { + char buf[64]; + int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf)); + if (n > 0) + printf("keyboard: symbol '%s' (keysym 0x%x)\n", buf, ks); + else + printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks); + } + } +} + +static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) +{ + printf("keyboard: modifiers serial=%u depressed=%u latched=%u locked=%u group=%u\n", serial, mods_depressed, mods_latched, mods_locked, group); + if (xkb_state) + { + xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0); + } +} + +static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay) +{ + printf("keyboard: repeat rate=%d delay=%d\n", rate, delay); +} + +static const struct wl_keyboard_listener keyboard_listener = { + .keymap = keyboard_keymap, + .enter = keyboard_enter, + .leave = keyboard_leave, + .key = keyboard_key, + .modifiers = keyboard_modifiers, + .repeat_info = keyboard_repeat_info +}; + +/* seat callbacks */ +static void seat_capabilities(void *data, struct wl_seat *seat_local, uint32_t caps) +{ + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !keyboard) + { + keyboard = wl_seat_get_keyboard(seat_local); + wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL); + printf("Seat reports keyboard capability - keyboard bound\n"); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && keyboard) + { + wl_keyboard_destroy(keyboard); + keyboard = NULL; + if (xkb_state) + { + xkb_state_unref(xkb_state); + xkb_state = NULL; + } + if (xkb_keymap) + { + xkb_keymap_unref(xkb_keymap); + xkb_keymap = NULL; + } + } +} + +static void seat_name(void *data, struct wl_seat *seat, const char *name) +{ + printf("Seat name: %s\n", name); +} + +static const struct wl_seat_listener seat_listener = { + .capabilities = seat_capabilities, + .name = seat_name +}; + +void input_register_seat(struct wl_seat *s) +{ + if (!s) + return; + seat = s; + wl_seat_add_listener(seat, &seat_listener, NULL); +} + +void input_cleanup(void) +{ + if (keyboard) + { + wl_keyboard_destroy(keyboard); + keyboard = NULL; + } + if (seat) + { + wl_seat_destroy(seat); + seat = NULL; + } + if (xkb_state) + { + xkb_state_unref(xkb_state); + xkb_state = NULL; + } + if (xkb_keymap) + { + xkb_keymap_unref(xkb_keymap); + xkb_keymap = NULL; + } + if (xkb_ctx) + { + xkb_context_unref(xkb_ctx); + xkb_ctx = NULL; + } +} diff --git a/wayland/input.h b/wayland/input.h new file mode 100644 index 0000000..5061b2e --- /dev/null +++ b/wayland/input.h @@ -0,0 +1,11 @@ +#ifndef WAYLAND_INPUT_H +#define WAYLAND_INPUT_H + +#include + +/* Called by registry when a wl_seat is bound */ +void input_register_seat(struct wl_seat *seat); +/* Perform any input-related cleanup (destroy keyboard, xkb state) */ +void input_cleanup(void); + +#endif diff --git a/wayland/registry.c b/wayland/registry.c new file mode 100644 index 0000000..89e50fb --- /dev/null +++ b/wayland/registry.c @@ -0,0 +1,63 @@ +#include "registry.h" +#include "input.h" +#include +#include +#include +#include "xdg-shell-client-protocol.h" + +static struct wl_compositor *compositor = NULL; +static struct xdg_wm_base *xdg_wm_base = NULL; +static struct wl_shm *shm = NULL; + +static void registry_global(void *data, struct wl_registry *reg, uint32_t name, const char *intf, uint32_t version) +{ + printf("%u\t%s\tv:%u\n", name, intf, version); + if (!strcmp(intf, wl_compositor_interface.name)) + { + compositor = wl_registry_bind(reg, name, &wl_compositor_interface, version); + } + else if (!strcmp(intf, wl_shm_interface.name)) + { + shm = wl_registry_bind(reg, name, &wl_shm_interface, version); + } + else if (!strcmp(intf, xdg_wm_base_interface.name)) + { + xdg_wm_base = wl_registry_bind(reg, name, &xdg_wm_base_interface, version); + xdg_wm_base_add_listener(xdg_wm_base, NULL, NULL); /* will be set by window module if needed */ + } + else if (!strcmp(intf, wl_seat_interface.name)) + { + struct wl_seat *seat = wl_registry_bind(reg, name, &wl_seat_interface, version); + /* Hook seat into input handler */ + input_register_seat(seat); + } +} + +static void registry_global_remove(void *data, struct wl_registry *reg, uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + .global = registry_global, + .global_remove = registry_global_remove +}; + +void registry_add_listener(struct wl_registry *registry) +{ + wl_registry_add_listener(registry, ®istry_listener, NULL); +} + +struct wl_compositor *registry_get_compositor(void) +{ + return compositor; +} + +struct wl_shm *registry_get_shm(void) +{ + return shm; +} + +struct xdg_wm_base *registry_get_xdg_wm_base(void) +{ + return xdg_wm_base; +} diff --git a/wayland/registry.h b/wayland/registry.h new file mode 100644 index 0000000..dfe4527 --- /dev/null +++ b/wayland/registry.h @@ -0,0 +1,14 @@ +#ifndef WAYLAND_REGISTRY_H +#define WAYLAND_REGISTRY_H + +#include + +/* Initialize registry listener on the given registry */ +void registry_add_listener(struct wl_registry *registry); + +/* Accessors for bound globals */ +struct wl_compositor *registry_get_compositor(void); +struct wl_shm *registry_get_shm(void); +struct xdg_wm_base *registry_get_xdg_wm_base(void); + +#endif diff --git a/wayland/window.c b/wayland/window.c new file mode 100644 index 0000000..5b0bca0 --- /dev/null +++ b/wayland/window.c @@ -0,0 +1,182 @@ +#include "window.h" +#include "registry.h" +#include "xdg-shell-client-protocol.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// Moving all window specific data into `struct wayland_window`. + +static struct wl_callback_listener callback_listener; +static struct xdg_surface_listener surface_listener; +static struct xdg_toplevel_listener top_listener; +static struct xdg_wm_base_listener wm_base_listener; + +static int32_t alloc_shm(size_t size) +{ + char name[32]; + sprintf(name, "/wayland-shm-%d", getpid()); + + int32_t fd = shm_open(name, O_RDWR | O_CREAT, 0600); + if (fd == -1) + return fd; + shm_unlink(name); + ftruncate(fd, size); + return fd; +} + +static void resize_canvas(struct wayland_window *win) +{ + size_t stride = win->width * 4; + size_t size = stride * win->height; + int32_t fd = alloc_shm(size); + + win->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + struct wl_shm *shm = registry_get_shm(); + struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); + win->buffer = wl_shm_pool_create_buffer(pool, 0, win->width, win->height, stride, WL_SHM_FORMAT_ARGB8888); + wl_shm_pool_destroy(pool); + close(fd); +} + +static void resize_new(struct wayland_window *win, int16_t w, int16_t h) +{ + if (!w || !h) + return; + if (win->width != w || win->height != h) + { + if(win->data) + munmap(win->data, win->width*win->height*4); + win->width = w; + win->height = h; + resize_canvas(win); + } +} + +static void draw(struct wayland_window *win) +{ + size_t stride = win->width * 4; + size_t size = stride * win->height; + + memset(win->data, win->color++, size); + + wl_surface_attach(win->wl_surface, win->buffer, 0, 0); + wl_surface_damage_buffer(win->wl_surface, 0, 0, win->width, win->height); + wl_surface_commit(win->wl_surface); +} + +static void xdg_surface_conf(void *data, struct xdg_surface *xdg_surface_local, uint32_t serial) +{ + xdg_surface_ack_configure(xdg_surface_local, serial); + struct wayland_window *win = data; + if (!win->data) + resize_canvas(win); + + draw(win); +} + +static void xdg_toplevel_conf(void *data, struct xdg_toplevel *xdg_top, int32_t w, int32_t h, struct wl_array *states) +{ + (void)states; + struct wayland_window *win = data; + resize_new(win, w, h); +} + +static void xdg_toplevel_cls(void *data, struct xdg_toplevel *xdg_top) +{ + struct wayland_window *win = data; + (void)xdg_top; + win->need_close = 1; +} + +static void xdg_toplevel_bounds(void *data, struct xdg_toplevel *xdg_top, int32_t w, int32_t h) +{ + (void)data; (void)xdg_top; (void)w; (void)h; +} + +static void xdg_toplevel_wm_caps(void *data, struct xdg_toplevel *xdg_top, struct wl_array *caps) +{ + (void)data; (void)xdg_top; (void)caps; +} + +static void frame_new(void *date, struct wl_callback *cb, uint32_t _) +{ + struct wayland_window *win = date; + wl_callback_destroy(cb); + cb = wl_surface_frame(win->wl_surface); + wl_callback_add_listener(cb, &callback_listener, win); + draw(win); +} + +static void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial) +{ + xdg_wm_base_pong(wm_base, serial); +} + +int window_init(struct wl_display *display, struct wayland_window *win) +{ + (void)display; + struct wl_compositor *compositor = registry_get_compositor(); + struct wl_shm *shm = registry_get_shm(); + struct xdg_wm_base *wm = registry_get_xdg_wm_base(); + if (!compositor || !shm || !wm) + return -1; + + win->wl_surface = wl_compositor_create_surface(compositor); + struct wl_callback *wl_callback = wl_surface_frame(win->wl_surface); + + callback_listener.done = frame_new; + wl_callback_add_listener(wl_callback, &callback_listener, win); + + win->xdg_surface = xdg_wm_base_get_xdg_surface(wm, win->wl_surface); + surface_listener.configure = xdg_surface_conf; + xdg_surface_add_listener(win->xdg_surface, &surface_listener, win); + + win->xdg_toplevel = xdg_surface_get_toplevel(win->xdg_surface); + + top_listener.configure = xdg_toplevel_conf; + top_listener.close = xdg_toplevel_cls; + top_listener.configure_bounds = xdg_toplevel_bounds; + top_listener.wm_capabilities = xdg_toplevel_wm_caps; + xdg_toplevel_add_listener(win->xdg_toplevel, &top_listener, win); + + xdg_toplevel_set_title(win->xdg_toplevel, "Custom client"); + wl_surface_commit(win->wl_surface); + + wm_base_listener.ping = wm_base_ping; + xdg_wm_base_add_listener(wm, &wm_base_listener, win); + + /* initialize state */ + win->width = 200; + win->height = 100; + win->data = NULL; + win->buffer = NULL; + win->need_close = 0; + win->color = 0; + + return 0; +} + +int window_should_close(struct wayland_window *win) +{ + return win->need_close; +} + +void window_destroy(struct wayland_window *win) +{ + if (win->buffer) + wl_buffer_destroy(win->buffer); + if (win->xdg_toplevel) + xdg_toplevel_destroy(win->xdg_toplevel); + if (win->xdg_surface) + xdg_surface_destroy(win->xdg_surface); + if (win->wl_surface) + wl_surface_destroy(win->wl_surface); + if (win->data) + munmap(win->data, win->width * win->height * 4); +} diff --git a/wayland/window.h b/wayland/window.h new file mode 100644 index 0000000..a87e947 --- /dev/null +++ b/wayland/window.h @@ -0,0 +1,28 @@ +#ifndef WAYLAND_WINDOW_H +#define WAYLAND_WINDOW_H + +#include + +/* Data for a single Wayland window (one surface) */ +struct wayland_window { + struct wl_surface *wl_surface; + struct wl_buffer *buffer; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; + uint8_t *data; + int16_t width; + int16_t height; + int need_close; + uint8_t color; +}; + +/* Initialize windowing for the given window structure. Caller provides the struct (on stack or heap) */ +int window_init(struct wl_display *display, struct wayland_window *win); + +/* Returns non-zero if the window requested to close */ +int window_should_close(struct wayland_window *win); + +/* Destroy window and related resources */ +void window_destroy(struct wayland_window *win); + +#endif