diff --git a/wayland/include/input.h b/wayland/include/input.h index 5061b2e..6a56bff 100644 --- a/wayland/include/input.h +++ b/wayland/include/input.h @@ -3,9 +3,12 @@ #include -/* Called by registry when a wl_seat is bound */ +/* Вызывается при привязке wl_seat регистром */ void input_register_seat(struct wl_seat *seat); -/* Perform any input-related cleanup (destroy keyboard, xkb state) */ +/* Очистка input (разрушить keyboard и xkb state) */ void input_cleanup(void); +/* Возвращает wl_surface, имеющую фокус клавиатуры или NULL */ +struct wl_surface *input_get_keyboard_focus(void); + #endif diff --git a/wayland/include/registry.h b/wayland/include/registry.h index 2371397..cb36fd9 100644 --- a/wayland/include/registry.h +++ b/wayland/include/registry.h @@ -3,19 +3,10 @@ #include -/* Initialize registry listener on the given registry */ -void registry_add_listener(struct wl_registry *registry); +int registry_global_bind(struct wl_display *display); +void registry_global_unbind(void); -/* Prepare per-thread bindings for compositor/shm/xdg_wm_base */ -int registry_thread_bind(struct wl_display *display, struct wl_event_queue *queue); - -/* Release per-thread resources allocated by registry_thread_bind */ -void registry_thread_unbind(void); - -/* Reset global registry bookkeeping (used during teardown) */ -void registry_reset_globals(void); - -/* Accessors for bound globals (per-thread via registry_thread_bind) */ +/* Доступ к привязанным глобальным объектам */ struct wl_compositor *registry_get_compositor(void); struct wl_shm *registry_get_shm(void); struct xdg_wm_base *registry_get_xdg_wm_base(void); diff --git a/wayland/include/wayland_runtime.h b/wayland/include/wayland_runtime.h index db02b4a..51f1b6f 100644 --- a/wayland/include/wayland_runtime.h +++ b/wayland/include/wayland_runtime.h @@ -3,16 +3,16 @@ #include -/* Initialize shared Wayland connection and prepare global data */ +/* Инициализация общего соединения Wayland и подготовка глобальных данных */ int32_t init_wayland(void); -/* Spawn a new window thread; returns slot index or negative on failure */ +/* Создать поток для окна; вернуть индекс слота или отрицательное при ошибке */ int32_t run_window(void); -/* Block until all window threads have exited */ +/* Блокировать до завершения всех оконных потоков */ void wait_for_windows(void); -/* Tear down window threads, input, and the shared Wayland connection */ +/* Остановить оконные потоки, очистить input и закрыть соединение Wayland */ void destroy_wayland(void); #endif diff --git a/wayland/include/window.h b/wayland/include/window.h index c22bc5e..4accfa4 100644 --- a/wayland/include/window.h +++ b/wayland/include/window.h @@ -3,7 +3,7 @@ #include -/* Data for a single Wayland window (one surface) */ +/* Данные одного Wayland-окна (одна поверхность) */ struct wayland_window { int id; struct wl_surface *wl_surface; @@ -11,6 +11,7 @@ struct wayland_window { struct wl_callback *frame_callback; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; + struct wl_event_queue *queue; /* очередь событий для окна */ uint8_t *data; int32_t width; int32_t height; @@ -18,13 +19,13 @@ struct wayland_window { 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); +/* Инициализация окна; структура предоставляется вызывающим */ +int window_init(struct wl_display *display, struct wl_event_queue *queue, 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 diff --git a/wayland/src/c.c b/wayland/src/c.c index 9fd076f..fee66e2 100644 --- a/wayland/src/c.c +++ b/wayland/src/c.c @@ -50,19 +50,10 @@ static void *window_thread_main(void *arg) return NULL; } - if (registry_thread_bind(g_display, slot->queue) < 0) - { - input_cleanup(); - wl_event_queue_destroy(slot->queue); - slot->queue = NULL; - signal_thread_exit(slot); - return NULL; - } - if (window_init(g_display, &slot->window) < 0) + if (window_init(g_display, slot->queue, &slot->window) < 0) { input_cleanup(); - registry_thread_unbind(); wl_event_queue_destroy(slot->queue); slot->queue = NULL; signal_thread_exit(slot); @@ -84,7 +75,6 @@ static void *window_thread_main(void *arg) input_cleanup(); window_destroy(&slot->window); - registry_thread_unbind(); if (slot->queue) { @@ -105,24 +95,15 @@ int32_t init_wayland(void) if (!g_display) return -1; - struct wl_registry *registry = wl_display_get_registry(g_display); - if (!registry) + /* Привязать глобальные объекты и запустить поток обработки (дефолтная очередь). + * `registry_global_bind` добавляет listener и делает roundtrip. */ + if (registry_global_bind(g_display) < 0) { wl_display_disconnect(g_display); g_display = NULL; return -1; } - registry_add_listener(registry); - if (wl_display_roundtrip(g_display) < 0) - { - wl_registry_destroy(registry); - wl_display_disconnect(g_display); - g_display = NULL; - return -1; - } - wl_registry_destroy(registry); - atomic_store(&g_shutdown, 0); atomic_store(&g_active_threads, 0); g_initialized = 1; @@ -182,7 +163,8 @@ void destroy_wayland(void) wait_for_windows(); input_cleanup(); - registry_reset_globals(); + /* Остановить поток глобального реестра и сбросить глобальные данные */ + registry_global_unbind(); if (g_display) { diff --git a/wayland/src/input.c b/wayland/src/input.c index 68ded98..d70f74c 100644 --- a/wayland/src/input.c +++ b/wayland/src/input.c @@ -5,14 +5,17 @@ #include #include #include +#include + static __thread struct wl_seat *seat = NULL; static __thread struct wl_keyboard *keyboard = NULL; static __thread struct xkb_context *xkb_ctx = NULL; static __thread struct xkb_keymap *xkb_keymap = NULL; static __thread struct xkb_state *xkb_state = NULL; +static struct wl_surface *keyboard_focus = 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); @@ -65,19 +68,27 @@ static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t f 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); + /* Сохраняем поверхность, которая получила фокус клавиатуры */ + keyboard_focus = 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); + /* Если уходим с фокусной поверхности — сбросить фокус */ + if (keyboard_focus == surface) + keyboard_focus = NULL; } 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); + const char *s = (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? "PRESSED" + : (state == WL_KEYBOARD_KEY_STATE_RELEASED) ? "RELEASED" + : (state == WL_KEYBOARD_KEY_STATE_REPEATED) ? "REPEATED" + : "Unknown"; + /* Отладочный вывод удалён */ - if (xkb_state) + if (xkb_state && keyboard_focus) { xkb_keycode_t kc = (xkb_keycode_t)key + 8; xkb_keysym_t ks = xkb_state_key_get_one_sym(xkb_state, kc); @@ -85,8 +96,10 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t seri { char buf[64]; int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf)); + if (ks == XKB_KEY_Return) + sprintf(buf, "Return"); if (n > 0) - printf("keyboard: symbol '%s' (keysym 0x%x)\n", buf, ks); + printf("keyboard: symbol '%s' (keysym 0x%x) on surface:%p\n", buf, ks, keyboard_focus); else printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks); } @@ -113,10 +126,9 @@ static const struct wl_keyboard_listener keyboard_listener = { .leave = keyboard_leave, .key = keyboard_key, .modifiers = keyboard_modifiers, - .repeat_info = keyboard_repeat_info -}; + .repeat_info = keyboard_repeat_info}; -/* seat callbacks */ +/* Обработчики wl_seat */ static void seat_capabilities(void *data, struct wl_seat *seat_local, uint32_t caps) { if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !keyboard) @@ -149,8 +161,7 @@ static void seat_name(void *data, struct wl_seat *seat, const char *name) static const struct wl_seat_listener seat_listener = { .capabilities = seat_capabilities, - .name = seat_name -}; + .name = seat_name}; void input_register_seat(struct wl_seat *s) { @@ -197,4 +208,10 @@ void input_cleanup(void) xkb_context_unref(xkb_ctx); xkb_ctx = NULL; } + keyboard_focus = NULL; +} + +struct wl_surface *input_get_keyboard_focus(void) +{ + return keyboard_focus; } diff --git a/wayland/src/registry.c b/wayland/src/registry.c index 0a4d028..16a2e72 100644 --- a/wayland/src/registry.c +++ b/wayland/src/registry.c @@ -1,27 +1,39 @@ -/* Copyright (c) 202325? retaining? existing license? not specified */ +/* Copyright (c) 2025 */ #include "registry.h" #include "input.h" #include #include #include +#include +#include +#include +#include #include #include "xdg-shell-client-protocol.h" -struct registry_binding +static void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial) { - uint32_t name; - uint32_t version; + (void)data; + xdg_wm_base_pong(wm_base, serial); +} + +static struct xdg_wm_base_listener wm_base_listener = { + .ping = wm_base_ping }; -static struct registry_binding compositor_binding = {0}; -static struct registry_binding shm_binding = {0}; -static struct registry_binding wm_base_binding = {0}; -static struct registry_binding seat_binding = {0}; -static __thread struct wl_compositor *tls_compositor; -static __thread struct wl_shm *tls_shm; -static __thread struct xdg_wm_base *tls_wm_base; +/* Глобальные объекты, привязанные к единому registry-потоку (общие для процесса) */ +static struct wl_compositor *global_compositor; +static struct wl_shm *global_shm; +static struct xdg_wm_base *global_wm_base; +/* Глобальный реестр живёт на весь срок программы (удаляется при сбросе) */ +static struct wl_registry *global_registry = NULL; + +/* Поток обработки глобальных событий: использует дефолтную очередь */ +static pthread_t global_thread; +static _Atomic int global_thread_running = 0; +static struct wl_display *global_display = NULL; static uint32_t clamp_version(uint32_t announced, uint32_t supported) { @@ -33,23 +45,32 @@ static void registry_global(void *data, struct wl_registry *reg, uint32_t name, printf("%u\t%s\tv:%u\n", name, intf, version); if (!strcmp(intf, wl_compositor_interface.name)) { - compositor_binding.name = name; - compositor_binding.version = clamp_version(version, wl_compositor_interface.version); + uint32_t ver = clamp_version(version, wl_compositor_interface.version); + /* Привязать compositor на дефолтной очереди сразу */ + if (!global_compositor) + global_compositor = wl_registry_bind(reg, name, &wl_compositor_interface, ver); } else if (!strcmp(intf, wl_shm_interface.name)) { - shm_binding.name = name; - shm_binding.version = clamp_version(version, wl_shm_interface.version); + uint32_t ver = clamp_version(version, wl_shm_interface.version); + if (!global_shm) + global_shm = wl_registry_bind(reg, name, &wl_shm_interface, ver); } else if (!strcmp(intf, xdg_wm_base_interface.name)) { - wm_base_binding.name = name; - wm_base_binding.version = clamp_version(version, xdg_wm_base_interface.version); + uint32_t ver = clamp_version(version, xdg_wm_base_interface.version); + if (!global_wm_base) + global_wm_base = wl_registry_bind(reg, name, &xdg_wm_base_interface, ver); + if (global_wm_base) + xdg_wm_base_add_listener(global_wm_base, &wm_base_listener, NULL); } else if (!strcmp(intf, wl_seat_interface.name)) { - seat_binding.name = name; - seat_binding.version = clamp_version(version, wl_seat_interface.version); + uint32_t ver = clamp_version(version, wl_seat_interface.version); + /* Привязать seat на дефолтной очереди */ + struct wl_seat *seat = wl_registry_bind(reg, name, &wl_seat_interface, ver); + if (seat) + input_register_seat(seat); } } @@ -65,99 +86,137 @@ static const struct wl_registry_listener registry_listener = { .global_remove = registry_global_remove }; -void registry_add_listener(struct wl_registry *registry) -{ - wl_registry_add_listener(registry, ®istry_listener, NULL); -} -static void destroy_tls_objects(void) +static void destroy_global_objects(void) { - if (tls_compositor) + if (global_compositor) { - wl_compositor_destroy(tls_compositor); - tls_compositor = NULL; + wl_compositor_destroy(global_compositor); + global_compositor = NULL; } - if (tls_shm) + if (global_shm) { - wl_shm_destroy(tls_shm); - tls_shm = NULL; + wl_shm_destroy(global_shm); + global_shm = NULL; } - if (tls_wm_base) + if (global_wm_base) { - xdg_wm_base_destroy(tls_wm_base); - tls_wm_base = NULL; + xdg_wm_base_destroy(global_wm_base); + global_wm_base = NULL; + } + if (global_registry) + { + wl_registry_destroy(global_registry); + global_registry = NULL; } } -int registry_thread_bind(struct wl_display *display, struct wl_event_queue *queue) -{ - if (!display || !queue) - return -1; - if (!compositor_binding.name || !shm_binding.name || !wm_base_binding.name) - return -1; - destroy_tls_objects(); +/* Привязка глобального реестра — привязать compositor/shm/xdg_wm_base и + * запустить поток обработки глобальной очереди. Возвращает 0 при успехе, + * -1 при ошибке. + */ +static void *registry_global_thread(void *arg) +{ + struct wl_display *display = arg; + int fd = wl_display_get_fd(display); + while (global_thread_running) + { + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + int ret = poll(&pfd, 1, 100); /* таймаут 100 ms для проверки флага запуска */ + if (ret == -1) + { + if (errno == EINTR) + continue; + break; + } + if (ret == 0) + continue; + if (pfd.revents & POLLIN) + { + int r = wl_display_dispatch(display); + if (r < 0) + break; + } + } + return NULL; +} + +int registry_global_bind(struct wl_display *display) +{ + if (!display) + return -1; + if (global_thread_running) + return 0; /* уже привязан */ + /* Используем дефолтную очередь для глобальных объектов. + * Добавим listener и сделаем roundtrip, чтобы вызывающий код + * мог не делать этого заранее. Реестр привяжет глобалы сразу + * при получении событий. */ struct wl_registry *registry = wl_display_get_registry(display); if (!registry) - return -1; - - wl_proxy_set_queue((struct wl_proxy *)registry, queue); - - tls_compositor = wl_registry_bind(registry, compositor_binding.name, &wl_compositor_interface, compositor_binding.version); - tls_shm = wl_registry_bind(registry, shm_binding.name, &wl_shm_interface, shm_binding.version); - tls_wm_base = wl_registry_bind(registry, wm_base_binding.name, &xdg_wm_base_interface, wm_base_binding.version); - - if (!tls_compositor || !tls_shm || !tls_wm_base) { + return -1; + } + + wl_registry_add_listener(registry, ®istry_listener, NULL); + if (wl_display_roundtrip(display) < 0) + { + /* произошла ошибка — уничтожить registry и вернуть ошибку */ wl_registry_destroy(registry); - destroy_tls_objects(); + return -1; + } + global_registry = registry; + + if (!global_compositor || !global_shm || !global_wm_base) + { + destroy_global_objects(); return -1; } - wl_proxy_set_queue((struct wl_proxy *)tls_compositor, queue); - wl_proxy_set_queue((struct wl_proxy *)tls_shm, queue); - wl_proxy_set_queue((struct wl_proxy *)tls_wm_base, queue); - - if (seat_binding.name) + /* Запустить поток обработки событий дефолтной очереди */ + global_thread_running = 1; + global_display = display; + int thr_res = pthread_create(&global_thread, NULL, registry_global_thread, display); + if (thr_res != 0) { - struct wl_seat *seat = wl_registry_bind(registry, seat_binding.name, &wl_seat_interface, seat_binding.version); - if (seat) - { - wl_proxy_set_queue((struct wl_proxy *)seat, queue); - input_register_seat(seat); - } + global_thread_running = 0; + destroy_global_objects(); + return -1; } - wl_registry_destroy(registry); return 0; } -void registry_thread_unbind(void) +void registry_global_unbind(void) { - destroy_tls_objects(); -} + if (!global_thread_running) + return; -void registry_reset_globals(void) -{ - destroy_tls_objects(); - compositor_binding.name = 0; - shm_binding.name = 0; - wm_base_binding.name = 0; - seat_binding.name = 0; + /* Корректно остановить поток */ + global_thread_running = 0; + pthread_join(global_thread, NULL); + global_display = NULL; + + destroy_global_objects(); + + return; } struct wl_compositor *registry_get_compositor(void) { - return tls_compositor; + return global_compositor; } struct wl_shm *registry_get_shm(void) { - return tls_shm; + return global_shm; } struct xdg_wm_base *registry_get_xdg_wm_base(void) { - return tls_wm_base; + return global_wm_base; } diff --git a/wayland/src/window.c b/wayland/src/window.c index 0514967..9daa84c 100644 --- a/wayland/src/window.c +++ b/wayland/src/window.c @@ -12,220 +12,232 @@ #include -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 atomic_uint_fast64_t shm_counter = 0; static int32_t alloc_shm(size_t size) { - char name[64]; - uint64_t id = atomic_fetch_add(&shm_counter, 1); - snprintf(name, sizeof(name), "/wayland-shm-%d-%llu", getpid(), (unsigned long long)id); + char name[64]; + uint64_t id = atomic_fetch_add(&shm_counter, 1); + snprintf(name, sizeof(name), "/wayland-shm-%d-%llu", getpid(), (unsigned long long)id); - int32_t fd = shm_open(name, O_RDWR | O_CREAT, 0600); - if (fd == -1) - return fd; - shm_unlink(name); - if (ftruncate(fd, size) == -1) - { - close(fd); - return -1; - } - return fd; + int32_t fd = shm_open(name, O_RDWR | O_CREAT, 0600); + if (fd == -1) + return fd; + shm_unlink(name); + if (ftruncate(fd, size) == -1) + { + close(fd); + return -1; + } + return fd; } static void destroy_frame_callback(struct wayland_window *win) { - if (win->frame_callback) - { - wl_callback_destroy(win->frame_callback); - win->frame_callback = NULL; - } + if (win->frame_callback) + { + wl_callback_destroy(win->frame_callback); + win->frame_callback = NULL; + } } 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); - if (fd == -1) - return; + size_t stride = win->width * 4; + size_t size = stride * win->height; + int32_t fd = alloc_shm(size); + if (fd == -1) + return; - if (win->buffer) - { - wl_buffer_destroy(win->buffer); - win->buffer = NULL; - } + if (win->buffer) + { + wl_buffer_destroy(win->buffer); + win->buffer = NULL; + } - void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (map == MAP_FAILED) - { - close(fd); - return; - } - 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); + void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + close(fd); + return; + } + 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); - win->data = map; + win->data = map; } static void resize_new(struct wayland_window *win, int32_t w, int32_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->data = NULL; - } - win->width = w; - win->height = h; - resize_canvas(win); - } + if (!w || !h) + return; + if (win->width != w || win->height != h) + { + if (win->data) + { + munmap(win->data, win->width * win->height * 4); + win->data = NULL; + } + 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; + size_t stride = win->width * 4; + size_t size = stride * win->height; - if (!win->data || !win->buffer) - return; + if (!win->data || !win->buffer) + return; - memset(win->data, win->color++, size); + 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); + 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); + xdg_surface_ack_configure(xdg_surface_local, serial); + struct wayland_window *win = data; + if (!win->data) + resize_canvas(win); - draw(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); + (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; + 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; + (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; + (void)data; (void)xdg_top; (void)caps; } -static void setup_frame_callback(struct wayland_window *win) +static struct wl_callback_listener callback_listener; +static void setup_frame_callback(struct wayland_window *win, struct wl_event_queue *queue) { - struct wl_callback *cb = wl_surface_frame(win->wl_surface); - win->frame_callback = cb; - wl_callback_add_listener(cb, &callback_listener, win); + struct wl_callback *cb = wl_surface_frame(win->wl_surface); + win->frame_callback = cb; + if (cb && queue) + wl_proxy_set_queue((struct wl_proxy *)cb, queue); + wl_callback_add_listener(cb, &callback_listener, win); } static void frame_new(void *data, struct wl_callback *cb, uint32_t _) { - struct wayland_window *win = data; - if (win->frame_callback == cb) - win->frame_callback = NULL; - wl_callback_destroy(cb); - setup_frame_callback(win); - draw(win); + struct wayland_window *win = data; + if (win->frame_callback == cb) + win->frame_callback = NULL; + wl_callback_destroy(cb); + setup_frame_callback(win, win->queue); + draw(win); } -static void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial) + +static struct wl_callback_listener callback_listener = { + .done = frame_new +}; +static struct xdg_surface_listener surface_listener = { + .configure = xdg_surface_conf +}; +static 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 +}; + +int window_init(struct wl_display *display, struct wl_event_queue *queue, struct wayland_window *win) { - xdg_wm_base_pong(wm_base, serial); -} + static int id = 0; + (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; -int window_init(struct wl_display *display, struct wayland_window *win) -{ - static int id = 0; - (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); + win->queue = queue; + if (win->wl_surface && queue) + wl_proxy_set_queue((struct wl_proxy *)win->wl_surface, queue); - win->wl_surface = wl_compositor_create_surface(compositor); + setup_frame_callback(win, queue); - callback_listener.done = frame_new; - win->frame_callback = NULL; - setup_frame_callback(win); + win->xdg_surface = xdg_wm_base_get_xdg_surface(wm, win->wl_surface); + if (win->xdg_surface && queue) + wl_proxy_set_queue((struct wl_proxy *)win->xdg_surface, queue); + xdg_surface_add_listener(win->xdg_surface, &surface_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); + if (win->xdg_toplevel && queue) + wl_proxy_set_queue((struct wl_proxy *)win->xdg_toplevel, queue); - win->xdg_toplevel = xdg_surface_get_toplevel(win->xdg_surface); + + xdg_toplevel_add_listener(win->xdg_toplevel, &top_listener, win); - 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); + wl_surface_commit(win->wl_surface); - xdg_toplevel_set_title(win->xdg_toplevel, "Custom client"); - wl_surface_commit(win->wl_surface); + /* wm_base — глобальный объект, listener в registry */ - wm_base_listener.ping = wm_base_ping; - xdg_wm_base_add_listener(wm, &wm_base_listener, win); + /* Инициализация состояния */ + win->id = id++; + win->width = 400; + win->height = 250; + win->data = NULL; + win->buffer = NULL; + win->frame_callback = NULL; + win->need_close = 0; + win->color = 0; - /* initialize state */ - win->id = id++; - win->width = 200; - win->height = 100; - win->data = NULL; - win->buffer = NULL; - win->frame_callback = NULL; - win->need_close = 0; - win->color = 0; + xdg_toplevel_set_app_id(win->xdg_toplevel, "my-wayland-window"); + xdg_toplevel_set_title(win->xdg_toplevel, "Custom Title"); - return 0; + return 0; } int window_should_close(struct wayland_window *win) { - return win->need_close; + return win->need_close; } void window_destroy(struct wayland_window *win) { - destroy_frame_callback(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); + destroy_frame_callback(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); } +/* конец файла */ +#include "registry.h"