From a4bd0b53de6cda1d73f8d2c20e29a931f1415a3a Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Tue, 16 Jun 2026 17:14:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(bar):=20=E6=B7=BB=E5=8A=A0=E7=AA=97?= =?UTF-8?q?=E5=8F=A3=E5=88=97=E8=A1=A8=E6=98=BE=E7=A4=BA=E5=BD=93=E5=89=8D?= =?UTF-8?q?=20workspace=20=E7=9A=84=E7=AA=97=E5=8F=A3=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + include/zdwm/bar.h | 1 + src/bar/bar.c | 27 +++++++ src/bar/windows.c | 175 ++++++++++++++++++++++++++++++++++++++++++ src/bar/windows.h | 18 +++++ src/config/defaults.c | 3 + 6 files changed, 225 insertions(+) create mode 100644 src/bar/windows.c create mode 100644 src/bar/windows.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f4163d5..8eddaac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ add_executable(${APP_NAME} ${SOURCE_DIR}/bar/binding.c ${SOURCE_DIR}/bar/cell.c ${SOURCE_DIR}/bar/text.c + ${SOURCE_DIR}/bar/windows.c ${SOURCE_DIR}/bar/workspaces.c ${SOURCE_DIR}/base/color.c diff --git a/include/zdwm/bar.h b/include/zdwm/bar.h index 051985b..44a2432 100644 --- a/include/zdwm/bar.h +++ b/include/zdwm/bar.h @@ -39,6 +39,7 @@ typedef struct zdwm_bar_config_t { const char *binding_mode_bg; const char *binding_mode_fg; + uint32_t window_padding_x; const char *window_bg; const char *window_fg; const char *window_focused_bg; diff --git a/src/bar/bar.c b/src/bar/bar.c index dd5768d..983c611 100644 --- a/src/bar/bar.c +++ b/src/bar/bar.c @@ -12,6 +12,7 @@ #include "bar/cell.h" #include "bar/text.h" #include "bar/types.h" +#include "bar/windows.h" #include "bar/workspaces.h" #include "base/array.h" #include "base/macros.h" @@ -103,6 +104,31 @@ static void bar_output_add_binding( bar_binding_add_listeners(listeners, item->state); } +static void bar_output_add_windows( + bar_output_t *bar_output, + zdwm_bar_config_t *config, + listeners_t *listeners +) { + auto item = &bar_output->center; + + bar_windows_config_t window_config = { + .cell_padding = VALUE(config->window_padding_x, config->padding_x), + .bg = VALUE(config->window_bg, config->bg), + .fg = VALUE(config->window_fg, config->fg), + .focused_bg = VALUE(config->window_focused_bg, config->bg), + .focused_fg = VALUE(config->window_focused_fg, config->fg), + }; + item->cell_padding = window_config.cell_padding; + + item->api = bar_windows; + + auto create_state = item->api.create_state; + auto output_id = bar_output->output_id; + if (create_state) item->state = create_state(output_id, &window_config); + + bar_windows_add_listeners(listeners, item->state); +} + void bar_init(bar_t *bar, listeners_t *listeners) { auto c = &bar->config; bar->ctx = text_context_create(c->font_family, c->font_size, c->dpi); @@ -113,6 +139,7 @@ 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_output_add_binding(bar_output, &bar->config, listeners); + bar_output_add_windows(bar_output, &bar->config, listeners); } bar->timerfd = time_create_monotonic_timerfd_by_fps(bar->config.fps); diff --git a/src/bar/windows.c b/src/bar/windows.c new file mode 100644 index 0000000..1da56d3 --- /dev/null +++ b/src/bar/windows.c @@ -0,0 +1,175 @@ +#include "bar/windows.h" + +#include +#include +#include +#include +#include + +#include "base/array.h" +#include "base/memory.h" +#include "core/listeners.h" + +typedef struct bar_windows_state_t { + zdwm_output_id_t output_id; + zdwm_workspace_id_t workspace_id; + + zdwm_window_t *windows; + size_t count; + size_t capacity; + + bar_windows_config_t config; + + bool workspace_inited; + bool dirty; +} bar_windows_state_t; + +static zdwm_window_t * +state_get_window(bar_windows_state_t *state, zdwm_window_id_t window_id) { + for (size_t i = 0; i < state->count; ++i) { + auto window = &state->windows[i]; + if (window->id == window_id) return window; + } + + return nullptr; +} + +static void * +bar_windows_create_state(zdwm_output_id_t output_id, void *config) { + const bar_windows_config_t *windows_config = config; + assert(windows_config); + + auto state = p_new(bar_windows_state_t, 1); + state->output_id = output_id; + state->workspace_id = ZDWM_WORKSPACE_ID_INVALID; + state->config = *windows_config; + + return state; +} + +static void bar_windows_update( + zdwm_bar_item_t *item, + const zdwm_bar_cell_api_t *cells, + void *state +) { + bar_windows_state_t *data = state; + if (!data->workspace_inited || !data->dirty) return; + + zdwm_window_t *windows = nullptr; + size_t count = 0, capacity = 0; + for (size_t i = 0; i < data->count; ++i) { + auto win = &data->windows[i]; + if (win->workspace != data->workspace_id || win->skip_taskbar) continue; + + auto window = array_push(windows, count, capacity); + *window = *win; + } + + cells->set_cell_count(item, count); + for (size_t i = 0; i < count; ++i) { + auto window = &windows[i]; + auto bg = window->focused ? data->config.focused_bg : data->config.bg; + auto fg = window->focused ? data->config.focused_fg : data->config.fg; + cells->cell_set_text(item, i, window->title); + cells->cell_set_bg(item, i, bg); + cells->cell_set_fg(item, i, fg); + } + p_delete(&windows); + + data->dirty = false; +} + +static void bar_windows_destroy_state(void *state) { + bar_windows_state_t *data = state; + + p_delete(&data->windows); + p_delete(&data); +} + +zdwm_bar_item_type_t bar_windows = { + .create_state = bar_windows_create_state, + .update = bar_windows_update, + .destroy_state = bar_windows_destroy_state, + .update_interval_ms = 0, +}; + +static void bar_windows_workspace_active( + zdwm_output_id_t output_id, + zdwm_workspace_id_t workspace_id, + void *user_data +) { + bar_windows_state_t *state = user_data; + if (state->output_id != output_id) return; + if (state->workspace_id == workspace_id) return; + + state->workspace_id = workspace_id; + + state->workspace_inited = true; + state->dirty = true; +} + +static void +bar_windows_add_window(const zdwm_window_t *window, void *user_data) { + bar_windows_state_t *state = user_data; + auto win = array_push(state->windows, state->count, state->capacity); + *win = *window; + + state->dirty = true; +} + +static void +bar_windows_initial(const zdwm_window_t *list, size_t count, void *user_data) { + bar_windows_state_t *state = user_data; + + for (size_t i = 0; i < count; ++i) { + auto window = &list[i]; + bar_windows_add_window(window, state); + } + + state->dirty = true; +} + +static void +bar_windows_update_window(const zdwm_window_t *window, void *user_data) { + bar_windows_state_t *state = user_data; + + auto old_window = state_get_window(state, window->id); + *old_window = *window; + + state->dirty = true; +} + +static void +bar_windows_remove_window(zdwm_window_id_t window_id, void *user_data) { + bar_windows_state_t *state = user_data; + + bool found = false; + size_t index = 0; + + for (size_t i = 0; i < state->count; ++i) { + auto window = &state->windows[i]; + if (window->id == window_id) { + found = true; + index = i; + break; + } + } + + if (!found) return; + + if (array_erase(state->windows, state->count, index)) { + state->dirty = true; + } +} + +void bar_windows_add_listeners(listeners_t *listeners, void *state) { +#define ADD(ADD_FN, LISTENER) ADD_FN(listeners, LISTENER, state) + + ADD(listeners_add_active_workspace_listener, bar_windows_workspace_active); + ADD(listeners_add_initial_window_listener, bar_windows_initial); + ADD(listeners_add_window_added_listener, bar_windows_add_window); + ADD(listeners_add_window_updated_listener, bar_windows_update_window); + ADD(listeners_add_window_removed_listener, bar_windows_remove_window); + +#undef ADD +} diff --git a/src/bar/windows.h b/src/bar/windows.h new file mode 100644 index 0000000..58593d5 --- /dev/null +++ b/src/bar/windows.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +#include "core/listeners.h" + +typedef struct bar_windows_config_t { + uint32_t cell_padding; + const char *bg; + const char *fg; + const char *focused_bg; + const char *focused_fg; +} bar_windows_config_t; + +extern zdwm_bar_item_type_t bar_windows; + +void bar_windows_add_listeners(listeners_t *listeners, void *state); diff --git a/src/config/defaults.c b/src/config/defaults.c index 9cb435a..135296e 100644 --- a/src/config/defaults.c +++ b/src/config/defaults.c @@ -194,6 +194,9 @@ bool config_defaults_build( .binding_padding_x = 2, .binding_mode_bg = "#900000", .binding_mode_fg = "#ffffff", + + .window_focused_bg = "#005577", + .window_focused_fg = "#eeeeee", }; api->set_bar_config(builder, bar_config);