feat(runtime): 用基于 poll 的事件循环代替阻塞式事件等待

This commit is contained in:
2026-06-10 01:26:05 +08:00
parent 4e713682e4
commit dbbbbce379
6 changed files with 164 additions and 45 deletions

View File

@@ -194,6 +194,12 @@ void backend_destroy(backend_t *backend) {
free(backend);
}
int backend_get_fd(backend_t *backend) {
if (!backend || !backend->conn) return -1;
return xcb_get_file_descriptor(backend->conn);
}
static bool detect_monitor_by_randr(
const backend_t *backend,
output_info_t **outputs,

View File

@@ -446,13 +446,11 @@ static bool handle_client_message(
return false;
}
bool backend_next_event(backend_t *backend, event_t *event) {
if (!backend || !backend->conn || !event) return false;
for (;;) {
xcb_generic_event_t *raw_event = xcb_wait_for_event(backend->conn);
if (!raw_event) return false;
static bool handle_event(
backend_t *backend,
xcb_generic_event_t *raw_event,
event_t *event
) {
uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(raw_event);
bool handled = false;
@@ -484,5 +482,26 @@ bool backend_next_event(backend_t *backend, event_t *event) {
p_delete(&raw_event);
if (handled) return true;
event_reset(event);
return false;
}
bool backend_poll_event(backend_t *backend, event_t *event) {
if (!backend || !backend->conn || !event) return false;
auto raw_event = xcb_poll_for_event(backend->conn);
if (!raw_event) return false;
return handle_event(backend, raw_event, event);
}
bool backend_next_event(backend_t *backend, event_t *event) {
if (!backend || !backend->conn || !event) return false;
for (;;) {
xcb_generic_event_t *raw_event = xcb_wait_for_event(backend->conn);
if (!raw_event) return false;
if (handle_event(backend, raw_event, event)) return true;
}
}

View File

@@ -1,9 +1,13 @@
#include "bar/bar.h"
#include <assert.h>
#include <bits/time.h>
#include <bits/types/struct_itimerspec.h>
#include <cairo.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <zdwm/bar.h>
#include <zdwm/types.h>
@@ -84,6 +88,22 @@ void bar_init(bar_t *bar, listeners_t *listeners) {
bar_output->height = bar->config.height;
bar_output_add_workspace(bar_output, &bar->config, listeners);
}
bar->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
auto interval_ns = 1'000'000'000ULL / bar->config.fps;
struct itimerspec timer_spec = {
.it_interval =
{
.tv_sec = interval_ns / 1'000'000'000,
.tv_nsec = interval_ns % 1'000'000'000,
},
.it_value = {
.tv_sec = 0,
.tv_nsec = interval_ns % 1'000'000'000,
},
};
timerfd_settime(bar->timerfd, 0, &timer_spec, nullptr);
}
static void bar_side_cleanup(bar_side_t *side) {
@@ -94,6 +114,9 @@ static void bar_side_cleanup(bar_side_t *side) {
}
void bar_cleanup(bar_t *bar) {
close(bar->timerfd);
bar->timerfd = -1;
text_context_destory(bar->ctx);
bar->ctx = nullptr;
@@ -250,7 +273,35 @@ static void bar_item_draw(
item->dirty = false;
}
static bool bar_item_is_dirty(zdwm_bar_item_t *item) {
if (item->dirty) return true;
for (size_t i = 0; i < item->count; ++i) {
auto cell = &item->cells[i];
if (cell->dirty) return true;
}
return false;
}
static bool bar_side_is_dirty(bar_side_t *side) {
for (size_t j = 0; j < side->count; ++j) {
auto item = &side->items[j];
if (bar_item_is_dirty(item)) return true;
}
return false;
}
static inline bool bar_output_is_dirty(bar_output_t *bar_output) {
if (bar_side_is_dirty(&bar_output->left)) return true;
if (bar_side_is_dirty(&bar_output->right)) return true;
if (bar_item_is_dirty(&bar_output->center)) return true;
return false;
}
static void bar_output_draw(bar_output_t *bar_output, text_context_t *ctx) {
if (!bar_output_is_dirty(bar_output)) return;
auto cr = bar_output->cr;
auto left = &bar_output->left;

View File

@@ -31,6 +31,7 @@ typedef struct bar_t {
size_t count;
bool visible;
int timerfd;
zdwm_bar_config_t config;
bar_palette_t palette;

View File

@@ -20,6 +20,9 @@ void backend_destroy(backend_t *backend);
backend_detect_t *backend_detect(backend_t *backend);
void backend_detect_destroy(backend_detect_t *detect);
int backend_get_fd(backend_t *backend);
bool backend_poll_event(backend_t *backend, event_t *event);
/**
* @brief 阻塞等待 backend 产出下一个可交给 runtime 的归一化事件
* @details

View File

@@ -3,12 +3,15 @@
#include <dlfcn.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/poll.h>
#include <unistd.h>
#include <zdwm/layout.h>
#include "bar/bar.h"
#include "base/array.h"
#include "base/color.h"
#include "base/log.h"
#include "base/macros.h"
#include "base/memory.h"
#include "base/window_list.h"
#include "config/runtime_config.h"
@@ -428,19 +431,20 @@ static void runtime_scan(runtime_t *runtime) {
listeners_notify_initial_windows(&runtime->listeners, &runtime->state);
}
static void runtime_run_event_loop(runtime_t *runtime) {
runtime->running = true;
static void runtime_handle_event(runtime_t *runtime, short int revents) {
auto backend = runtime->backend;
auto command_buffer = &runtime->command_buffer;
auto plan = &runtime->plan;
auto ctx = policy_context_init(runtime);
backend_t *backend = runtime->backend;
command_buffer_t *command_buffer = &runtime->command_buffer;
plan_t *plan = &runtime->plan;
if (revents & POLLHUP) {
runtime->running = false;
}
policy_context_t ctx = policy_context_init(runtime);
if (!(revents & POLLIN)) return;
while (runtime->running) {
event_t event = {0};
if (!backend_next_event(backend, &event)) break;
while (backend_poll_event(backend, &event)) {
command_buffer_reset(command_buffer);
plan_reset(plan);
@@ -452,16 +456,51 @@ static void runtime_run_event_loop(runtime_t *runtime) {
if (plan->quit) {
runtime->running = false;
runtime->will_restart = plan->will_restart;
} else {
bar_update(&runtime->bar);
bar_draw(&runtime->bar);
backend_flush(backend);
}
event_cleanup(&event);
}
}
static inline void runtime_update_bar(runtime_t *runtime) {
auto bar = &runtime->bar;
bar_update(bar);
bar_draw(bar);
backend_flush(runtime->backend);
}
static void runtime_run_event_loop(runtime_t *runtime) {
runtime->running = true;
auto backend = runtime->backend;
auto backend_fd = backend_get_fd(backend);
if (backend_fd < 0) {
runtime->running = false;
return;
}
struct pollfd fds[] = {
[0] = {.fd = backend_fd, .events = POLLIN | POLLHUP},
[1] = {.fd = runtime->bar.timerfd, .events = POLLIN},
};
while (runtime->running) {
auto ready = poll(fds, countof(fds), -1);
if (ready < 0) continue;
runtime_handle_event(runtime, fds[0].revents);
if (fds[1].revents & POLLIN) {
uint64_t expirations = 0;
read(fds[1].fd, &expirations, sizeof(expirations));
if (expirations > 0) {
runtime_update_bar(runtime);
}
}
}
}
bool runtime_run(const char *config_so_path, const char *display_name) {
auto backend = backend_create(nullptr);
auto detect = backend_detect(backend);