diff --git a/wayland/include/figure-animate.h b/wayland/include/figure-animate.h new file mode 100644 index 0000000..fc4d9e1 --- /dev/null +++ b/wayland/include/figure-animate.h @@ -0,0 +1,9 @@ +#ifndef FIGURE_ANIMATE_H +#define FIGURE_ANIMATE_H + +#include "window.h" + +/* Провести один шаг анимации на окне */ +void animation_step(struct window_draw_info* draw_info, float speed_multiplier); + +#endif diff --git a/wayland/include/window.h b/wayland/include/window.h index ed3dda6..ae655c9 100644 --- a/wayland/include/window.h +++ b/wayland/include/window.h @@ -1,6 +1,7 @@ #ifndef WAYLAND_WINDOW_H #define WAYLAND_WINDOW_H +#include #include #include "figure.h" @@ -8,8 +9,8 @@ struct window_draw_info { uint8_t *data; int32_t width; int32_t height; - uint8_t color; struct figure_info figure; + pthread_mutex_t figure_mutex; }; /* Данные одного Wayland-окна (одна поверхность) */ diff --git a/wayland/src/input-handle.c b/wayland/src/input-handle.c index 8305499..e9027a5 100644 --- a/wayland/src/input-handle.c +++ b/wayland/src/input-handle.c @@ -21,6 +21,15 @@ void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_st run_window(); break; + case '1': + window->draw_info.figure.type = FIGURE_CIRCLE; + break; + case '2': + window->draw_info.figure.type = FIGURE_TRIANGLE; + break; + case '3': + window->draw_info.figure.type = FIGURE_SQUARE; + break; default: break; } diff --git a/wayland/src/wayland-runtime.c b/wayland/src/wayland-runtime.c index 86a4984..8a8c716 100644 --- a/wayland/src/wayland-runtime.c +++ b/wayland/src/wayland-runtime.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "input.h" #include "registry.h" @@ -16,6 +17,7 @@ struct window_thread_slot { pthread_t thread; + pthread_t aux_thread; int active; struct wl_event_queue *queue; struct wayland_window window; @@ -38,6 +40,21 @@ static void signal_thread_exit(struct window_thread_slot *slot) pthread_mutex_unlock(&g_thread_lock); } +static void *window_aux_loop(void *arg) +{ + struct window_thread_slot *slot = arg; + struct window_draw_info *draw_info = &slot->window.draw_info; + while (!atomic_load(&g_shutdown) && !window_should_close(&slot->window)) + { + /* На время обновления позиции фигуры локаем мутекс */ + pthread_mutex_lock(&draw_info->figure_mutex); + usleep(10 * 1000); + pthread_mutex_unlock(&draw_info->figure_mutex); + usleep(100 * 1000); + } + return NULL; +} + static void *window_thread_main(void *arg) { struct window_thread_slot *slot = arg; @@ -50,7 +67,6 @@ static void *window_thread_main(void *arg) return NULL; } - if (window_init(g_display, slot->queue, &slot->window) < 0) { wl_event_queue_destroy(slot->queue); @@ -59,6 +75,12 @@ static void *window_thread_main(void *arg) return NULL; } + /* Запуск вспомогательного потока, который пока просто крутится с паузой 100 ms. + * Поток завершится, как только окно будет помечено как закрыто. */ + int aux_res = pthread_create(&slot->aux_thread, NULL, window_aux_loop, slot); + if (aux_res == 0) + pthread_detach(slot->aux_thread); + while (!atomic_load(&g_shutdown) && !window_should_close(&slot->window)) { int dispatch = wl_display_dispatch_queue(g_display, slot->queue); @@ -176,10 +198,10 @@ void destroy_wayland(void) atomic_store(&g_shutdown, 0); } -struct wayland_window* get_window_by_surface(struct wl_surface* surf) +struct wayland_window *get_window_by_surface(struct wl_surface *surf) { - for(int i = 0; i < MAX_WINDOW_THREADS; i++) - if(g_slots[i].window.wl_surface == surf) + for (int i = 0; i < MAX_WINDOW_THREADS; i++) + if (g_slots[i].window.wl_surface == surf) return &g_slots[i].window; return NULL; } diff --git a/wayland/src/window.c b/wayland/src/window.c index 7f5f274..e92f9fa 100644 --- a/wayland/src/window.c +++ b/wayland/src/window.c @@ -44,7 +44,7 @@ static void destroy_frame_callback(struct wayland_window *win) static void resize_canvas(struct wayland_window *win) { - struct window_draw_info* draw_info = &win->draw_info; + struct window_draw_info *draw_info = &win->draw_info; size_t stride = draw_info->width * 4; size_t size = stride * draw_info->height; int32_t fd = alloc_shm(size); @@ -76,7 +76,7 @@ static void resize_new(struct wayland_window *win, int32_t w, int32_t h) { if (!w || !h) return; - struct window_draw_info* draw_info = &win->draw_info; + struct window_draw_info *draw_info = &win->draw_info; if (draw_info->width != w || draw_info->height != h) { @@ -93,7 +93,7 @@ static void resize_new(struct wayland_window *win, int32_t w, int32_t h) static void draw(struct wayland_window *win) { - struct window_draw_info* draw_info = &win->draw_info; + struct window_draw_info *draw_info = &win->draw_info; size_t stride = draw_info->width * 4; size_t size = stride * draw_info->height; @@ -101,7 +101,35 @@ static void draw(struct wayland_window *win) if (!draw_info->data || !win->buffer) return; - memset(draw_info->data, draw_info->color++, size); + // Залочиться, чтобы операции обновления позиции фигуры происходили атомарно + pthread_mutex_lock(&draw_info->figure_mutex); + struct figure_info figure = draw_info->figure; + pthread_mutex_unlock(&draw_info->figure_mutex); + + uint32_t color; + switch (figure.type) + { + case FIGURE_CIRCLE: + color = 0xFFFFFFFF; + break; + case FIGURE_TRIANGLE: + color = 0xFFFF0000; + break; + case FIGURE_SQUARE: + color = 0xFF00FF00; + break; + + default: + break; + } + + uint8_t *bytes = (uint8_t *)draw_info->data; + for (int32_t y = 0; y < (int32_t)draw_info->height; ++y) + { + uint32_t *row = (uint32_t *)(bytes + y * stride); + for (int32_t x = 0; x < (int32_t)draw_info->width; ++x) + row[x] = color; + } wl_surface_attach(win->wl_surface, win->buffer, 0, 0); wl_surface_damage_buffer(win->wl_surface, 0, 0, draw_info->width, draw_info->height); @@ -134,12 +162,17 @@ static void xdg_toplevel_cls(void *data, struct xdg_toplevel *xdg_top) 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 struct wl_callback_listener callback_listener; @@ -162,19 +195,15 @@ static void frame_new(void *data, struct wl_callback *cb, uint32_t _) draw(win); } - static struct wl_callback_listener callback_listener = { - .done = frame_new -}; + .done = frame_new}; static struct xdg_surface_listener surface_listener = { - .configure = xdg_surface_conf -}; + .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 -}; + .wm_capabilities = xdg_toplevel_wm_caps}; int window_init(struct wl_display *display, struct wl_event_queue *queue, struct wayland_window *win) { @@ -202,12 +231,11 @@ int window_init(struct wl_display *display, struct wl_event_queue *queue, struct if (win->xdg_toplevel && queue) wl_proxy_set_queue((struct wl_proxy *)win->xdg_toplevel, queue); - xdg_toplevel_add_listener(win->xdg_toplevel, &top_listener, win); wl_surface_commit(win->wl_surface); - struct window_draw_info* draw_info = &win->draw_info; + struct window_draw_info *draw_info = &win->draw_info; /* Инициализация состояния */ win->id = id++; @@ -217,9 +245,15 @@ int window_init(struct wl_display *display, struct wl_event_queue *queue, struct win->buffer = NULL; win->frame_callback = NULL; win->need_close = 0; - draw_info->color = 0; + /* Мьютекс нужен для атомарного обращения к структуре фигуры */ + if (pthread_mutex_init(&win->draw_info.figure_mutex, NULL) != 0) + { + /* if mutex init failed — cleanup and return error */ + window_destroy(win); + return -1; + } - xdg_toplevel_set_app_id(win->xdg_toplevel, "my-wayland-window"); + xdg_toplevel_set_app_id(win->xdg_toplevel, "my-wayland-window"); xdg_toplevel_set_title(win->xdg_toplevel, "Custom Title"); return 0; @@ -243,4 +277,6 @@ void window_destroy(struct wayland_window *win) wl_surface_destroy(win->wl_surface); if (win->draw_info.data) munmap(win->draw_info.data, win->draw_info.width * win->draw_info.height * 4); + /* destroy mutex if initialized */ + pthread_mutex_destroy(&win->draw_info.figure_mutex); }