diff --git a/src/bar/bar.c b/src/bar/bar.c index ad5ac0a..a29b460 100644 --- a/src/bar/bar.c +++ b/src/bar/bar.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -394,3 +395,49 @@ bool bar_draw(bar_t *bar) { return changed; } + +static inline bool +bar_item_click(zdwm_bar_item_t *item, int32_t x, zdwm_action_t *action) { + if (!(item->region.start <= x && item->region.end >= x)) return false; + + if (!item->api.on_click) return true; + + for (size_t i = 0; i < item->count; ++i) { + auto cell = &item->cells[i]; + if (cell->region.start <= x && cell->region.end >= x) { + *action = item->api.on_click(item, i, x, item->state); + return true; + } + } + + return true; +} + +static inline bool +bar_side_click(bar_side_t *side, int32_t x, zdwm_action_t *action) { + if (side->region.start > x || side->region.end < x) return false; + + for (size_t i = 0; i < side->count; ++i) { + if (bar_item_click(&side->items[i], x, action)) return true; + } + + return true; +} + +bool bar_click( + bar_t *bar, + zdwm_window_id_t window, + int32_t x, + zdwm_action_t *action +) { + for (size_t i = 0; i < bar->count; ++i) { + auto bar_output = &bar->bars[i]; + if (bar_output->window_id != window) continue; + + if (bar_side_click(&bar_output->left, x, action)) return true; + if (bar_item_click(&bar_output->center, x, action)) return true; + if (bar_side_click(&bar_output->right, x, action)) return true; + } + + return false; +} diff --git a/src/bar/bar.h b/src/bar/bar.h index 3c3e5fe..3e60e40 100644 --- a/src/bar/bar.h +++ b/src/bar/bar.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -42,3 +43,9 @@ void bar_init(bar_t *bar, listeners_t *listeners); void bar_cleanup(bar_t *bar); void bar_update(bar_t *bar); bool bar_draw(bar_t *bar); +bool bar_click( + bar_t *bar, + zdwm_window_id_t window, + int32_t x, + zdwm_action_t *action +); diff --git a/src/core/policy.c b/src/core/policy.c index c8be173..9a70843 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -371,7 +371,7 @@ static void toggle_bar_visibility( command_buffer_push(command_buffer, &set_bar_visibility_command); } -static void policy_resolve_action( +void policy_resolve_action( const policy_context_t *ctx, const zdwm_action_t *action, command_buffer_t *out diff --git a/src/core/policy.h b/src/core/policy.h index 636e045..4d5e381 100644 --- a/src/core/policy.h +++ b/src/core/policy.h @@ -33,6 +33,12 @@ typedef struct policy_context_t { const policy_bar_t bar; } policy_context_t; +void policy_resolve_action( + const policy_context_t *ctx, + const zdwm_action_t *action, + command_buffer_t *out +); + /** * @brief 事件路由:将运行时事件翻译为语义命令 * diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index c04b38b..181322d 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "bar/bar.h" @@ -456,10 +457,30 @@ static void runtime_scan(runtime_t *runtime) { listeners_notify_initial_windows(&runtime->listeners, &runtime->state); } +static bool runtime_handle_bar_click( + const policy_context_t *ctx, + const event_t *event, + bar_t *bar, + command_buffer_t *command_buffer +) { + if (event->type != ZDWM_EVENT_POINTER_BUTTON_PRESS) return false; + + auto data = &event->as.pointer_button_press; + + zdwm_action_t action = {.type = ZDWM_ACTION_NONE}; + if (bar_click(bar, data->window, data->local.x, &action)) { + policy_resolve_action(ctx, &action, command_buffer); + return true; + } + + return false; +} + 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 bar = &runtime->bar; auto ctx = policy_context_init(runtime); if (revents & POLLHUP) { @@ -473,7 +494,10 @@ static void runtime_handle_event(runtime_t *runtime, short int revents) { command_buffer_reset(command_buffer); plan_reset(plan); - policy_route_event(&ctx, &event, command_buffer); + if (!runtime_handle_bar_click(&ctx, &event, bar, command_buffer)) { + policy_route_event(&ctx, &event, command_buffer); + } + policy_apply_command(&ctx, command_buffer, plan); if (plan->need_relayout) runtime_arrange(runtime); if (plan->count) backend_apply_effect(backend, plan->effects, plan->count);