diff --git a/include/zdwm/bar.h b/include/zdwm/bar.h index f59013c..704f988 100644 --- a/include/zdwm/bar.h +++ b/include/zdwm/bar.h @@ -68,16 +68,10 @@ typedef struct zdwm_bar_item_type_t { void *state ); void (*destroy_state)(void *state); + zdwm_bar_item_t *instance; uint32_t update_interval_ms; } zdwm_bar_item_type_t; -typedef enum zdwm_bar_side_type_t { - ZDWM_BAR_SIDE_LEFT, - ZDWM_BAR_SIDE_RIGHT, - ZDWM_BAR_SIDE_CENTER_REST, /* 中央剩余部分,用于显示窗口列表 */ - ZDWM_BAR_SIDE_COUNT, -} zdwm_bar_side_type_t; - #if defined(__cplusplus) } #endif diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index 0ead1f7..4378caf 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -755,3 +755,5 @@ backend_bar_window_t backend_create_bar_window( return (backend_bar_window_t){.window_id = window_id, .cr = cr}; } + +void backend_flush(backend_t *backend) { xcb_flush(backend->conn); } diff --git a/src/bar/bar.c b/src/bar/bar.c index e4443b8..466fb02 100644 --- a/src/bar/bar.c +++ b/src/bar/bar.c @@ -1,29 +1,32 @@ #include "bar/bar.h" +#include #include #include #include #include #include +#include "bar/cell.h" #include "bar/text.h" #include "bar/types.h" #include "bar/workspaces.h" #include "base/array.h" +#include "base/macros.h" #include "base/memory.h" +#include "core/listeners.h" static zdwm_bar_item_t *bar_add_item( - bar_output_t *bar_output, - zdwm_bar_side_type_t side_type, + zdwm_output_id_t output_id, + bar_side_t *side, zdwm_bar_item_type_t item_type, void *config ) { - auto side = &bar_output->sides[side_type]; auto item = array_push(side->items, side->count, side->capacity); item->api = item_type; auto create_state = item_type.create_state; - if (create_state) item->state = create_state(bar_output->output_id, config); + if (create_state) item->state = create_state(output_id, config); return item; } @@ -46,10 +49,9 @@ static void bar_item_cleanup(zdwm_bar_item_t *item) { void bar_output_add_workspace( bar_output_t *bar_output, - zdwm_bar_config_t *config + zdwm_bar_config_t *config, + listeners_t *listeners ) { - auto side = ZDWM_BAR_SIDE_LEFT; - bar_workspace_config_t workspace_config = { .cell_padding = VALUE(config->tag_cell_padding_x, config->padding_x), .indicator_width = VALUE(config->tag_indicator_width, 4), @@ -60,18 +62,27 @@ void bar_output_add_workspace( .urgent_bg = config->tag_urgent_bg, .urgent_fg = config->tag_urgent_fg, }; - auto item = bar_add_item(bar_output, side, bar_workspace, &workspace_config); + auto item = bar_add_item( + bar_output->output_id, + &bar_output->left, + bar_workspace, + &workspace_config + ); item->cell_padding = workspace_config.cell_padding; item->indicator_width = workspace_config.indicator_width; + + bar_workspace_add_listeners(listeners, item->state); } -void bar_init(bar_t *bar) { +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); for (size_t i = 0; i < bar->count; ++i) { auto bar_output = &bar->bars[i]; - bar_output_add_workspace(bar_output, &bar->config); + + bar_output->height = bar->config.height; + bar_output_add_workspace(bar_output, &bar->config, listeners); } } @@ -88,25 +99,170 @@ void bar_cleanup(bar_t *bar) { for (size_t i = 0; i < bar->count; ++i) { auto bar_output = &bar->bars[i]; - for (size_t j = 0; j < ZDWM_BAR_SIDE_COUNT; ++j) { - auto side = &bar_output->sides[j]; - bar_side_cleanup(side); - } + bar_side_cleanup(&bar_output->left); + bar_side_cleanup(&bar_output->right); + bar_item_cleanup(&bar_output->center); + cairo_destroy(bar_output->cr); bar_output->cr = nullptr; } p_delete(&bar->bars); bar->count = 0; + + bar_cell_clean_color_cache(); } -static void bar_draw_item( - zdwm_bar_item_t *item, - text_context_t *context, +static inline void bar_item_update(zdwm_bar_item_t *item) { + auto update = item->api.update; + if (update) update(item, &bar_cell_api, item->state); +} + +static inline void bar_side_update(bar_side_t *side) { + for (size_t i = 0; i < side->count; ++i) { + bar_item_update(&side->items[i]); + } +} + +void bar_update(bar_t *bar) { + for (size_t i = 0; i < bar->count; ++i) { + auto bar_output = &bar->bars[i]; + bar_side_update(&bar_output->left); + bar_side_update(&bar_output->right); + bar_item_update(&bar_output->center); + } +} + +static void bar_output_layout(bar_output_t *bar_output, text_context_t *ctx) { + int32_t start = 0; + auto end = bar_output->width; + + auto left = &bar_output->left; + for (size_t i = 0; i < left->count; ++i) { + auto item = &left->items[i]; + + item->region.start = start; + for (size_t j = 0; j < item->count; ++j) { + auto cell = &item->cells[j]; + + int32_t width = 0; + text_context_get_text_size(ctx, cell->text, &width, nullptr); + + bar_x_region_t region = { + .start = start, + .end = start + width + item->cell_padding * 2, + }; + bar_cell_set_region(item, j, region); + + start = region.end; + } + item->region.end = start; + } + + auto right = &bar_output->right; + for (size_t i = right->count; i > 0; --i) { + auto item_index = i - 1; + auto item = &right->items[item_index]; + + item->region.end = end; + for (size_t j = item->count; j > 0; --j) { + auto cell_index = j - 1; + auto cell = &item->cells[cell_index]; + + int32_t width = 0; + text_context_get_text_size(ctx, cell->text, &width, nullptr); + + bar_x_region_t region = { + .start = end - width - item->cell_padding * 2, + .end = end, + }; + bar_cell_set_region(item, cell_index, region); + + end = region.start; + } + item->region.start = end; + } + + auto center = &bar_output->center; + if (center->count == 0) return; + center->region = (bar_x_region_t){.start = start, .end = end}; + + auto width = (end - start) / (int32_t)center->count; + for (size_t i = 0; i < center->count; ++i) { + bar_x_region_t region = { + .start = start, + .end = start + width + center->cell_padding * 2, + }; + bar_cell_set_region(center, i, region); + } +} + +static void bar_item_draw( cairo_t *cr, - int32_t width, + zdwm_bar_item_t *item, + text_context_t *ctx, int32_t height ) { - /* TODO: */ + for (size_t i = 0; i < item->count; ++i) { + auto cell = &item->cells[i]; + auto region = &cell->region; + + zdwm_rect_t cell_area = { + .x = region->start, + .y = 0, + .width = region->end - region->start, + .height = height, + }; + if (cell_area.width <= 0) { + cell->dirty = false; + continue; + } + + draw_background(cr, cell->bg, cell_area); + + if (cell->show_indicator) { + auto size = MIN(item->indicator_width, cell_area.width); + size = MIN(size, height); + + if (size > 0) { + zdwm_rect_t indicator_area = { + .x = region->start, + .y = 0, + .width = size, + .height = size, + }; + draw_background(cr, cell->fg, indicator_area); + } + } + + zdwm_rect_t text_area = { + .x = cell_area.x + item->cell_padding, + .y = 0, + .width = cell_area.width - item->cell_padding * 2, + .height = height, + }; + if (text_area.width > 0) { + draw_text(cr, ctx, cell->text, cell->fg, text_area); + } + + cell->dirty = false; + } + + item->dirty = false; +} + +static void bar_output_draw(bar_output_t *bar_output, text_context_t *ctx) { + auto cr = bar_output->cr; + + auto left = &bar_output->left; + for (size_t i = 0; i < left->count; ++i) { + bar_item_draw(cr, &left->items[i], ctx, bar_output->height); + } + auto right = &bar_output->right; + for (size_t i = 0; i < right->count; ++i) { + bar_item_draw(cr, &right->items[i], ctx, bar_output->height); + } + + bar_item_draw(cr, &bar_output->center, ctx, bar_output->height); } void bar_draw(bar_t *bar) { @@ -114,16 +270,7 @@ void bar_draw(bar_t *bar) { for (size_t i = 0; i < bar->count; ++i) { auto bar_output = &bar->bars[i]; - auto cr = bar_output->cr; - auto width = bar_output->width; - auto height = bar_output->height; - - for (size_t j = 0; j < ZDWM_BAR_SIDE_COUNT; ++j) { - auto side = &bar_output->sides[j]; - for (size_t k = 0; k < side->count; ++k) { - auto item = &side->items[k]; - bar_draw_item(item, ctx, cr, width, height); - } - } + bar_output_layout(bar_output, ctx); + bar_output_draw(bar_output, ctx); } } diff --git a/src/bar/bar.h b/src/bar/bar.h index 1936a9b..afd9bcd 100644 --- a/src/bar/bar.h +++ b/src/bar/bar.h @@ -9,6 +9,7 @@ #include "bar/text.h" #include "bar/types.h" #include "base/color.h" +#include "core/listeners.h" typedef struct bar_output_t { cairo_t *cr; @@ -16,7 +17,9 @@ typedef struct bar_output_t { zdwm_output_id_t output_id; int32_t width; int32_t height; - bar_side_t sides[ZDWM_BAR_SIDE_COUNT]; + bar_side_t left; + bar_side_t right; + zdwm_bar_item_t center; } bar_output_t; typedef struct bar_palette_t { @@ -34,6 +37,7 @@ typedef struct bar_t { text_context_t *ctx; } bar_t; -void bar_init(bar_t *bar); +void bar_init(bar_t *bar, listeners_t *listeners); void bar_cleanup(bar_t *bar); +void bar_update(bar_t *bar); void bar_draw(bar_t *bar); diff --git a/src/bar/cell.c b/src/bar/cell.c index a0a09b4..05aa1cc 100644 --- a/src/bar/cell.c +++ b/src/bar/cell.c @@ -53,18 +53,21 @@ void bar_cell_clean_color_cache(void) { cache.capacity = 0; } -size_t bar_cell_get_count(zdwm_bar_item_t *item) { return item->count; } +static size_t bar_cell_get_count(zdwm_bar_item_t *item) { return item->count; } -void bar_cell_set_count(zdwm_bar_item_t *item, size_t count) { +static void bar_cell_set_count(zdwm_bar_item_t *item, size_t count) { if (item->count == count) return; + for (size_t i = 0; i < item->count; ++i) p_delete(&item->cells[i].text); + item->count = count; p_realloc(&item->cells, count); p_clear(item->cells, count); item->dirty = true; } -void bar_cell_set_text(zdwm_bar_item_t *item, size_t index, const char *text) { +static void +bar_cell_set_text(zdwm_bar_item_t *item, size_t index, const char *text) { if (index >= item->count) return; auto cell = &item->cells[index]; @@ -78,7 +81,8 @@ void bar_cell_set_text(zdwm_bar_item_t *item, size_t index, const char *text) { item->dirty = true; } -void bar_cell_set_bg(zdwm_bar_item_t *item, size_t index, const char *color) { +static void +bar_cell_set_bg(zdwm_bar_item_t *item, size_t index, const char *color) { if (index >= item->count) return; auto cell = &item->cells[index]; @@ -91,7 +95,8 @@ void bar_cell_set_bg(zdwm_bar_item_t *item, size_t index, const char *color) { item->dirty = true; } -void bar_cell_set_fg(zdwm_bar_item_t *item, size_t index, const char *color) { +static void +bar_cell_set_fg(zdwm_bar_item_t *item, size_t index, const char *color) { if (index >= item->count) return; auto cell = &item->cells[index]; @@ -104,7 +109,8 @@ void bar_cell_set_fg(zdwm_bar_item_t *item, size_t index, const char *color) { item->dirty = true; } -void bar_cell_set_icon(zdwm_bar_item_t *item, size_t index, zdwm_icon_t icon) { +static void +bar_cell_set_icon(zdwm_bar_item_t *item, size_t index, zdwm_icon_t icon) { if (index >= item->count) return; auto cell = &item->cells[index]; @@ -131,7 +137,8 @@ void bar_cell_set_icon(zdwm_bar_item_t *item, size_t index, zdwm_icon_t icon) { item->dirty = true; } -void bar_cell_set_indicator(zdwm_bar_item_t *item, size_t index, bool show) { +static void +bar_cell_set_indicator(zdwm_bar_item_t *item, size_t index, bool show) { if (index >= item->count) return; auto cell = &item->cells[index]; @@ -142,3 +149,31 @@ void bar_cell_set_indicator(zdwm_bar_item_t *item, size_t index, bool show) { cell->dirty = true; item->dirty = true; } + +zdwm_bar_cell_api_t bar_cell_api = { + .get_cell_count = bar_cell_get_count, + .set_cell_count = bar_cell_set_count, + .cell_set_text = bar_cell_set_text, + .cell_set_bg = bar_cell_set_bg, + .cell_set_fg = bar_cell_set_fg, + .cell_set_icon = bar_cell_set_icon, + .cell_set_indicator = bar_cell_set_indicator, +}; + +void bar_cell_set_region( + zdwm_bar_item_t *item, + size_t index, + bar_x_region_t region +) { + if (index >= item->count) return; + + auto cell = &item->cells[index]; + auto r = &cell->region; + + if (r->start == region.start && r->end == region.end) return; + + *r = region; + + cell->dirty = true; + item->dirty = true; +} diff --git a/src/bar/cell.h b/src/bar/cell.h index d2e781c..814efa3 100644 --- a/src/bar/cell.h +++ b/src/bar/cell.h @@ -4,11 +4,15 @@ #include #include -size_t bar_cell_get_count(zdwm_bar_item_t *item); -void bar_cell_set_count(zdwm_bar_item_t *item, size_t count); +#include "bar/types.h" -void bar_cell_set_text(zdwm_bar_item_t *item, size_t index, const char *text); -void bar_cell_set_bg(zdwm_bar_item_t *item, size_t index, const char *color); -void bar_cell_set_fg(zdwm_bar_item_t *item, size_t index, const char *color); -void bar_cell_set_icon(zdwm_bar_item_t *item, size_t index, zdwm_icon_t icon); -void bar_cell_set_indicator(zdwm_bar_item_t *item, size_t index, bool show); +void bar_cell_reset_color_cache(void); +void bar_cell_clean_color_cache(void); + +void bar_cell_set_region( + zdwm_bar_item_t *item, + size_t index, + bar_x_region_t region +); + +extern zdwm_bar_cell_api_t bar_cell_api; diff --git a/src/bar/text.c b/src/bar/text.c index 14afe81..69c221c 100644 --- a/src/bar/text.c +++ b/src/bar/text.c @@ -98,7 +98,7 @@ void draw_text( cairo_t *cr, text_context_t *context, const char *text, - color_t *color, + const color_t *color, zdwm_rect_t area ) { assert(cr); @@ -127,7 +127,7 @@ void draw_text( pango_cairo_show_layout(cr, layout); } -void draw_background(cairo_t *cr, color_t *color, zdwm_rect_t area) { +void draw_background(cairo_t *cr, const color_t *color, zdwm_rect_t area) { cairo_move_to(cr, area.x, area.y); cairo_set_source_rgba( cr, diff --git a/src/bar/text.h b/src/bar/text.h index a55d672..1c44848 100644 --- a/src/bar/text.h +++ b/src/bar/text.h @@ -21,7 +21,7 @@ void draw_text( cairo_t *cr, text_context_t *context, const char *text, - color_t *color, + const color_t *color, zdwm_rect_t area ); -void draw_background(cairo_t *cr, color_t *color, zdwm_rect_t area); +void draw_background(cairo_t *cr, const color_t *color, zdwm_rect_t area); diff --git a/src/bar/types.h b/src/bar/types.h index 0ec5e41..92375ce 100644 --- a/src/bar/types.h +++ b/src/bar/types.h @@ -26,8 +26,8 @@ struct zdwm_bar_item_t { bar_cell_t *cells; size_t count; bar_x_region_t region; - uint32_t cell_padding; - uint32_t indicator_width; + int32_t cell_padding; + int32_t indicator_width; void *state; zdwm_bar_item_type_t api; @@ -35,7 +35,6 @@ struct zdwm_bar_item_t { }; typedef struct bar_side_t { - zdwm_bar_side_type_t type; zdwm_bar_item_t *items; size_t count; size_t capacity; diff --git a/src/bar/workspaces.c b/src/bar/workspaces.c index 2d559ff..8e1ccbe 100644 --- a/src/bar/workspaces.c +++ b/src/bar/workspaces.c @@ -85,9 +85,10 @@ bar_workspaces_create_state(zdwm_output_id_t output_id, void *config) { const bar_workspace_config_t *workspace_config = config; assert(workspace_config); - auto state = p_new(bar_workspace_state_t, 1); - state->output_id = output_id; - state->config = *workspace_config; + auto state = p_new(bar_workspace_state_t, 1); + state->output_id = output_id; + state->workspace_id = ZDWM_WORKSPACE_ID_INVALID; + state->config = *workspace_config; return state; } @@ -171,6 +172,11 @@ zdwm_bar_item_type_t bar_workspace = { .update_interval_ms = 0, }; +typedef struct bar_workspace_listener_user_data_t { + zdwm_bar_item_t *bar; + bar_workspace_state_t *state; +} bar_workspace_listener_user_data_t; + static void bar_workspace_list_filter( const zdwm_workspace_t *list, size_t count, diff --git a/src/config/defaults.c b/src/config/defaults.c index b89f5d1..08dd524 100644 --- a/src/config/defaults.c +++ b/src/config/defaults.c @@ -178,6 +178,15 @@ bool config_defaults_build( .dpi = 144, .bg = "#222222", + + .tag_cell_padding_x = 10, + .tag_indicator_width = 4, + .tag_bg = "#222222", + .tag_fg = "#bbbbbb", + .tag_active_bg = "#005577", + .tag_active_fg = "#eeeeee", + .tag_urgent_bg = "#222222", + .tag_urgent_fg = "#ff0000", }; api->set_bar_config(builder, bar_config); diff --git a/src/core/backend.h b/src/core/backend.h index 71e3c45..70f9b92 100644 --- a/src/core/backend.h +++ b/src/core/backend.h @@ -63,3 +63,4 @@ backend_bar_window_t backend_create_bar_window( rect_t geometry, uint32_t bg_pixel ); +void backend_flush(backend_t *backend); diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index efbee58..8bfce0d 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -77,6 +77,50 @@ static bool runtime_init_desc_valid(const runtime_init_desc_t *desc) { return true; } +static void runtime_init_bar(runtime_t *runtime) { + auto bar_height = runtime->bar.config.height; + if (bar_height <= 0) return; + + auto show_top = runtime->bar.config.show_top; + inset_t inset = { + .top = show_top ? bar_height : 0, + .bottom = show_top ? 0 : bar_height, + }; + + auto state = &runtime->state; + auto count = state_output_count(state); + + auto bar = &runtime->bar; + bar->bars = p_new(bar_output_t, count); + bar->count = count; + bar->visible = true; + + color_parse(bar->config.bg, &bar->palette.bg); + + auto backend = runtime->backend; + for (size_t i = 0; i < count; ++i) { + auto output = state_output_at(state, i); + state_output_inset_workarea(state, output->id, inset); + auto geometry = output->geometry; + rect_t bar_rect = { + .x = geometry.x, + .y = show_top ? 0 : geometry.y + geometry.height - bar_height, + .width = geometry.width, + .height = bar_height, + }; + auto color = bar->palette.bg.argb; + auto bar_window = backend_create_bar_window(backend, bar_rect, color); + auto bar_output = &bar->bars[i]; + bar_output->cr = bar_window.cr; + bar_output->window_id = bar_window.window_id; + bar_output->output_id = output->id; + bar_output->width = bar_rect.width; + bar_output->height = bar_rect.height; + } + + bar_init(&runtime->bar, &runtime->listeners); +} + static bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc) { if (!runtime || !runtime_init_desc_valid(desc)) return false; @@ -189,51 +233,7 @@ static void runtime_notify_initial_state(runtime_t *runtime) { listeners_notify_binding_mode(listeners, runtime->binding_table); } -static void runtime_init_bar(runtime_t *runtime) { - auto bar_height = runtime->bar.config.height; - if (bar_height <= 0) return; - - auto show_top = runtime->bar.config.show_top; - inset_t inset = { - .top = show_top ? bar_height : 0, - .bottom = show_top ? 0 : bar_height, - }; - - auto state = &runtime->state; - auto count = state_output_count(state); - - auto bar = &runtime->bar; - bar->bars = p_new(bar_output_t, count); - bar->count = count; - bar->visible = true; - - color_parse(bar->config.bg, &bar->palette.bg); - - auto backend = runtime->backend; - for (size_t i = 0; i < count; ++i) { - auto output = state_output_at(state, i); - state_output_inset_workarea(state, output->id, inset); - auto geometry = output->geometry; - rect_t bar_rect = { - .x = geometry.x, - .y = show_top ? 0 : geometry.y + geometry.height - bar_height, - .width = geometry.width, - .height = bar_height, - }; - auto color = bar->palette.bg.argb; - auto bar_window = backend_create_bar_window(backend, bar_rect, color); - auto bar_output = &bar->bars[i]; - bar_output->cr = bar_window.cr; - bar_output->window_id = bar_window.window_id; - bar_output->output_id = output->id; - bar_output->width = bar_rect.width; - bar_output->height = bar_rect.height; - } - - bar_init(&runtime->bar); -} - -static void runtime_setup(runtime_t *runtime) { +static void runtime_setup_bindings(runtime_t *runtime) { size_t bind_count = 0; auto bindings = binding_table_get_current_bindings(runtime->binding_table, &bind_count); @@ -257,9 +257,13 @@ static void runtime_setup(runtime_t *runtime) { backend_apply_effect(backend, plan->effects, plan->count); plan_reset(plan); - runtime_notify_initial_state(runtime); +} +static void runtime_setup(runtime_t *runtime) { + runtime_setup_bindings(runtime); runtime_init_bar(runtime); + + runtime_notify_initial_state(runtime); } static const layout_result_t *runtime_layout_calc(runtime_t *runtime) { @@ -448,6 +452,10 @@ 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);