отдельный поток для физики и изменение цвета

This commit is contained in:
2025-11-17 14:38:03 +03:00
parent de18bd8252
commit 8dd2aa19ad
5 changed files with 99 additions and 22 deletions

View File

@@ -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

View File

@@ -1,6 +1,7 @@
#ifndef WAYLAND_WINDOW_H
#define WAYLAND_WINDOW_H
#include <pthread.h>
#include <wayland-client.h>
#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-окна (одна поверхность) */

View File

@@ -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;
}

View File

@@ -5,6 +5,7 @@
#include <stdio.h>
#include <string.h>
#include <wayland-client.h>
#include <unistd.h>
#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;
}

View File

@@ -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,7 +245,13 @@ 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_title(win->xdg_toplevel, "Custom Title");
@@ -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);
}