Файл для обработки ввода
This commit is contained in:
187
wayland/src/wayland-runtime.c
Normal file
187
wayland/src/wayland-runtime.c
Normal file
@@ -0,0 +1,187 @@
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "registry.h"
|
||||
#include "wayland-runtime.h"
|
||||
#include "window.h"
|
||||
|
||||
#define MAX_WINDOW_THREADS 128
|
||||
|
||||
struct window_thread_slot
|
||||
{
|
||||
pthread_t thread;
|
||||
int active;
|
||||
struct wl_event_queue *queue;
|
||||
struct wayland_window window;
|
||||
};
|
||||
|
||||
static struct wl_display *g_display = NULL;
|
||||
static struct window_thread_slot g_slots[MAX_WINDOW_THREADS];
|
||||
static pthread_mutex_t g_thread_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t g_thread_cond = PTHREAD_COND_INITIALIZER;
|
||||
static atomic_int g_active_threads = 0;
|
||||
static atomic_bool g_shutdown = 0;
|
||||
static int g_initialized = 0;
|
||||
|
||||
static void signal_thread_exit(struct window_thread_slot *slot)
|
||||
{
|
||||
pthread_mutex_lock(&g_thread_lock);
|
||||
slot->active = 0;
|
||||
atomic_fetch_sub(&g_active_threads, 1);
|
||||
pthread_cond_broadcast(&g_thread_cond);
|
||||
pthread_mutex_unlock(&g_thread_lock);
|
||||
}
|
||||
|
||||
static void *window_thread_main(void *arg)
|
||||
{
|
||||
struct window_thread_slot *slot = arg;
|
||||
memset(&slot->window, 0, sizeof(slot->window));
|
||||
|
||||
slot->queue = wl_display_create_queue(g_display);
|
||||
if (!slot->queue)
|
||||
{
|
||||
signal_thread_exit(slot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (window_init(g_display, slot->queue, &slot->window) < 0)
|
||||
{
|
||||
input_cleanup();
|
||||
wl_event_queue_destroy(slot->queue);
|
||||
slot->queue = NULL;
|
||||
signal_thread_exit(slot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (!atomic_load(&g_shutdown) && !window_should_close(&slot->window))
|
||||
{
|
||||
int dispatch = wl_display_dispatch_queue(g_display, slot->queue);
|
||||
if (dispatch < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
atomic_store(&g_shutdown, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("Window #%d closed\n", slot->window.id);
|
||||
|
||||
input_cleanup();
|
||||
window_destroy(&slot->window);
|
||||
|
||||
if (slot->queue)
|
||||
{
|
||||
wl_event_queue_destroy(slot->queue);
|
||||
slot->queue = NULL;
|
||||
}
|
||||
|
||||
signal_thread_exit(slot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t init_wayland(void)
|
||||
{
|
||||
if (g_initialized)
|
||||
return 0;
|
||||
|
||||
g_display = wl_display_connect(NULL);
|
||||
if (!g_display)
|
||||
return -1;
|
||||
|
||||
/* Привязать глобальные объекты и запустить поток обработки (дефолтная очередь).
|
||||
* `registry_global_bind` добавляет listener и делает roundtrip. */
|
||||
if (registry_global_bind(g_display) < 0)
|
||||
{
|
||||
wl_display_disconnect(g_display);
|
||||
g_display = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
atomic_store(&g_shutdown, 0);
|
||||
atomic_store(&g_active_threads, 0);
|
||||
g_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t run_window(void)
|
||||
{
|
||||
if (!g_initialized || !g_display)
|
||||
return -1;
|
||||
|
||||
int slot_index = -1;
|
||||
|
||||
pthread_mutex_lock(&g_thread_lock);
|
||||
for (int i = 0; i < MAX_WINDOW_THREADS; ++i)
|
||||
{
|
||||
if (!g_slots[i].active)
|
||||
{
|
||||
slot_index = i;
|
||||
g_slots[i].active = 1;
|
||||
atomic_fetch_add(&g_active_threads, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_thread_lock);
|
||||
|
||||
if (slot_index < 0)
|
||||
return -1;
|
||||
|
||||
int create_res = pthread_create(&g_slots[slot_index].thread, NULL, window_thread_main, &g_slots[slot_index]);
|
||||
if (create_res != 0)
|
||||
{
|
||||
pthread_mutex_lock(&g_thread_lock);
|
||||
g_slots[slot_index].active = 0;
|
||||
atomic_fetch_sub(&g_active_threads, 1);
|
||||
pthread_mutex_unlock(&g_thread_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_detach(g_slots[slot_index].thread);
|
||||
return slot_index;
|
||||
}
|
||||
|
||||
void wait_for_windows(void)
|
||||
{
|
||||
pthread_mutex_lock(&g_thread_lock);
|
||||
while (atomic_load(&g_active_threads) > 0)
|
||||
pthread_cond_wait(&g_thread_cond, &g_thread_lock);
|
||||
pthread_mutex_unlock(&g_thread_lock);
|
||||
}
|
||||
|
||||
void destroy_wayland(void)
|
||||
{
|
||||
if (!g_initialized)
|
||||
return;
|
||||
|
||||
wait_for_windows();
|
||||
|
||||
input_cleanup();
|
||||
/* Остановить поток глобального реестра и сбросить глобальные данные */
|
||||
registry_global_unbind();
|
||||
|
||||
if (g_display)
|
||||
{
|
||||
wl_display_disconnect(g_display);
|
||||
g_display = NULL;
|
||||
}
|
||||
|
||||
memset(g_slots, 0, sizeof(g_slots));
|
||||
|
||||
g_initialized = 0;
|
||||
atomic_store(&g_shutdown, 0);
|
||||
}
|
||||
|
||||
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)
|
||||
return &g_slots[i].window;
|
||||
return NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user