feat(runtime): 用基于 poll 的事件循环代替阻塞式事件等待
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -31,6 +31,7 @@ typedef struct bar_t {
|
||||
size_t count;
|
||||
|
||||
bool visible;
|
||||
int timerfd;
|
||||
|
||||
zdwm_bar_config_t config;
|
||||
bar_palette_t palette;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user