From dbbbbce379d6abeac91169fa094c1f028a201464 Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Wed, 10 Jun 2026 01:26:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(runtime):=20=E7=94=A8=E5=9F=BA=E4=BA=8E=20?= =?UTF-8?q?poll=20=E7=9A=84=E4=BA=8B=E4=BB=B6=E5=BE=AA=E7=8E=AF=E4=BB=A3?= =?UTF-8?q?=E6=9B=BF=E9=98=BB=E5=A1=9E=E5=BC=8F=E4=BA=8B=E4=BB=B6=E7=AD=89?= =?UTF-8?q?=E5=BE=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/x11/backend.c | 6 +++ src/backend/x11/event.c | 81 ++++++++++++++++++++++++--------------- src/bar/bar.c | 51 ++++++++++++++++++++++++ src/bar/bar.h | 1 + src/core/backend.h | 3 ++ src/runtime/runtime.c | 67 +++++++++++++++++++++++++------- 6 files changed, 164 insertions(+), 45 deletions(-) diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index 4378caf..20d8205 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -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, diff --git a/src/backend/x11/event.c b/src/backend/x11/event.c index ef45313..60aa757 100644 --- a/src/backend/x11/event.c +++ b/src/backend/x11/event.c @@ -446,6 +446,55 @@ static bool handle_client_message( 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; + + auto label = xcb_event_get_label(response_type); + printf("xcb event type: %s[%u]\n", label, response_type); + + switch (response_type) { +#define EVENT(type, handler) \ + case type: \ + event_reset(event); \ + handled = handler(backend, event, (void *)raw_event); \ + break + + EVENT(XCB_MAP_REQUEST, handle_map_request); + EVENT(XCB_UNMAP_NOTIFY, handle_unmap_notify); + EVENT(XCB_DESTROY_NOTIFY, handle_destroy_notify); + EVENT(XCB_CONFIGURE_REQUEST, handle_configure_request); + EVENT(XCB_KEY_PRESS, handle_key_press); + EVENT(XCB_ENTER_NOTIFY, handle_enter_notify); + EVENT(XCB_PROPERTY_NOTIFY, handle_property_notify); + EVENT(XCB_CLIENT_MESSAGE, handle_client_message); + +#undef EVENT + + default: + break; + } + + 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; @@ -453,36 +502,6 @@ bool backend_next_event(backend_t *backend, event_t *event) { xcb_generic_event_t *raw_event = xcb_wait_for_event(backend->conn); if (!raw_event) return false; - uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(raw_event); - bool handled = false; - - auto label = xcb_event_get_label(response_type); - printf("xcb event type: %s[%u]\n", label, response_type); - - switch (response_type) { -#define EVENT(type, handler) \ - case type: \ - event_reset(event); \ - handled = handler(backend, event, (void *)raw_event); \ - break - - EVENT(XCB_MAP_REQUEST, handle_map_request); - EVENT(XCB_UNMAP_NOTIFY, handle_unmap_notify); - EVENT(XCB_DESTROY_NOTIFY, handle_destroy_notify); - EVENT(XCB_CONFIGURE_REQUEST, handle_configure_request); - EVENT(XCB_KEY_PRESS, handle_key_press); - EVENT(XCB_ENTER_NOTIFY, handle_enter_notify); - EVENT(XCB_PROPERTY_NOTIFY, handle_property_notify); - EVENT(XCB_CLIENT_MESSAGE, handle_client_message); - -#undef EVENT - - default: - break; - } - - p_delete(&raw_event); - if (handled) return true; - event_reset(event); + if (handle_event(backend, raw_event, event)) return true; } } diff --git a/src/bar/bar.c b/src/bar/bar.c index 466fb02..5875249 100644 --- a/src/bar/bar.c +++ b/src/bar/bar.c @@ -1,9 +1,13 @@ #include "bar/bar.h" #include +#include +#include #include #include #include +#include +#include #include #include @@ -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; diff --git a/src/bar/bar.h b/src/bar/bar.h index afd9bcd..79da315 100644 --- a/src/bar/bar.h +++ b/src/bar/bar.h @@ -31,6 +31,7 @@ typedef struct bar_t { size_t count; bool visible; + int timerfd; zdwm_bar_config_t config; bar_palette_t palette; diff --git a/src/core/backend.h b/src/core/backend.h index 70f9b92..36d5238 100644 --- a/src/core/backend.h +++ b/src/core/backend.h @@ -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 diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 8bfce0d..9007084 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -3,12 +3,15 @@ #include #include #include +#include +#include #include #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); - - while (runtime->running) { - event_t event = {0}; - if (!backend_next_event(backend, &event)) break; + if (!(revents & POLLIN)) return; + event_t event = {0}; + 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);