Compare commits
5 Commits
8c145fb1b4
...
539563c53f
| Author | SHA1 | Date | |
|---|---|---|---|
|
539563c53f
|
|||
|
dbbbbce379
|
|||
|
4e713682e4
|
|||
|
4535e171a0
|
|||
|
fa2f058032
|
@@ -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
|
||||
|
||||
@@ -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,
|
||||
@@ -755,3 +761,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); }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
263
src/bar/bar.c
263
src/bar/bar.c
@@ -1,29 +1,36 @@
|
||||
#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>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -33,6 +40,11 @@ static void bar_item_cleanup(zdwm_bar_item_t *item) {
|
||||
if (destroy_state) destroy_state(item->state);
|
||||
item->state = nullptr;
|
||||
|
||||
for (size_t i = 0; i < item->count; ++i) {
|
||||
auto cell = &item->cells[i];
|
||||
p_delete(&cell->text);
|
||||
}
|
||||
|
||||
p_delete(&item->cells);
|
||||
p_clear(item, 1);
|
||||
}
|
||||
@@ -41,10 +53,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),
|
||||
@@ -55,19 +66,44 @@ 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);
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -78,30 +114,206 @@ 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;
|
||||
|
||||
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 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;
|
||||
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) {
|
||||
@@ -109,16 +321,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -28,12 +31,14 @@ typedef struct bar_t {
|
||||
size_t count;
|
||||
|
||||
bool visible;
|
||||
int timerfd;
|
||||
|
||||
zdwm_bar_config_t config;
|
||||
bar_palette_t palette;
|
||||
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);
|
||||
|
||||
@@ -53,30 +53,36 @@ 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];
|
||||
if (cell->text == text || strcmp(cell->text, text) == 0) return;
|
||||
if (cell->text && text && strcmp(cell->text, text) == 0) return;
|
||||
|
||||
cell->text = text;
|
||||
p_delete(&cell->text);
|
||||
|
||||
cell->text = p_strdup_nullable(text);
|
||||
|
||||
cell->dirty = true;
|
||||
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];
|
||||
@@ -89,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];
|
||||
@@ -102,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];
|
||||
@@ -129,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];
|
||||
@@ -140,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;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,15 @@
|
||||
#include <zdwm/bar.h>
|
||||
#include <zdwm/types.h>
|
||||
|
||||
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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -14,7 +14,7 @@ typedef struct bar_x_region_t {
|
||||
|
||||
typedef struct bar_cell_t {
|
||||
zdwm_icon_t icon;
|
||||
const char *text;
|
||||
char *text; /* 持有内存,避免野指针问题 */
|
||||
const color_t *fg;
|
||||
const color_t *bg;
|
||||
bar_x_region_t region;
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -63,3 +66,4 @@ backend_bar_window_t backend_create_bar_window(
|
||||
rect_t geometry,
|
||||
uint32_t bg_pixel
|
||||
);
|
||||
void backend_flush(backend_t *backend);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "core/command_buffer.h"
|
||||
#include "core/event.h"
|
||||
#include "core/layout.h"
|
||||
#include "core/listeners.h"
|
||||
#include "core/plan.h"
|
||||
#include "core/rules.h"
|
||||
#include "core/state.h"
|
||||
@@ -1306,11 +1307,25 @@ static void command_window_set_fullscreen(
|
||||
fullscreen_window(ctx, data->window, data->state, plan);
|
||||
}
|
||||
|
||||
static void
|
||||
switch_workspace(state_t *state, workspace_id_t workspace_id, plan_t *plan) {
|
||||
static inline void change_current_output(
|
||||
state_t *state,
|
||||
output_id_t output_id,
|
||||
const listeners_t *listeners
|
||||
) {
|
||||
if (!state_set_current_output(state, output_id)) return;
|
||||
listeners_notify_current_output(listeners, output_id);
|
||||
}
|
||||
|
||||
static void switch_workspace(
|
||||
const policy_context_t *ctx,
|
||||
workspace_id_t workspace_id,
|
||||
plan_t *plan
|
||||
) {
|
||||
auto state = ctx->state;
|
||||
auto workspace = state_workspace_get(state, workspace_id);
|
||||
if (!workspace) return;
|
||||
|
||||
auto listeners = ctx->listeners;
|
||||
auto output_id = workspace->output_id;
|
||||
workspace_id_t old_workspace = ZDWM_WORKSPACE_ID_INVALID;
|
||||
|
||||
@@ -1322,17 +1337,17 @@ switch_workspace(state_t *state, workspace_id_t workspace_id, plan_t *plan) {
|
||||
)) {
|
||||
plan->need_relayout = true;
|
||||
add_switch_workspace_effects(state, old_workspace, workspace_id, plan);
|
||||
listeners_notify_workspace_active(listeners, output_id, workspace_id);
|
||||
}
|
||||
|
||||
state_set_current_output(state, output_id);
|
||||
change_current_output(state, output_id, listeners);
|
||||
}
|
||||
|
||||
static void set_current_output(
|
||||
const policy_context_t *ctx,
|
||||
const set_current_output_command_t *command
|
||||
) {
|
||||
if (!state_set_current_output(ctx->state, command->output)) return;
|
||||
listeners_notify_current_output(ctx->listeners, command->output);
|
||||
change_current_output(ctx->state, command->output, ctx->listeners);
|
||||
}
|
||||
|
||||
static void set_layout(
|
||||
@@ -1461,7 +1476,7 @@ void policy_apply_command(
|
||||
command_window_set_fullscreen(ctx, &cmd->as.fullscreen, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_SWITCH_WORKSPACE:
|
||||
switch_workspace(state, cmd->as.switch_workspace.workspace, plan);
|
||||
switch_workspace(ctx, cmd->as.switch_workspace.workspace, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_SET_CURRENT_OUTPUT:
|
||||
set_current_output(ctx, &cmd->as.current_output);
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
#include "runtime/runtime.h"
|
||||
|
||||
#include <bits/types/sigset_t.h>
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/signalfd.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"
|
||||
@@ -29,6 +35,7 @@
|
||||
typedef struct runtime_t {
|
||||
bool running;
|
||||
bool will_restart;
|
||||
int signal_fd;
|
||||
|
||||
plan_t plan;
|
||||
command_buffer_t command_buffer;
|
||||
@@ -77,6 +84,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;
|
||||
|
||||
@@ -84,6 +135,7 @@ static bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc) {
|
||||
runtime->backend = desc->backend;
|
||||
layout_registry_move(&desc->layouts, &runtime->layouts);
|
||||
rules_move(&desc->rules, &runtime->rules);
|
||||
runtime->signal_fd = -1;
|
||||
runtime->border = desc->border;
|
||||
runtime->config_module_handle = desc->config_module_handle;
|
||||
runtime->binding_table = desc->binding_table;
|
||||
@@ -152,6 +204,9 @@ static void runtime_shutdown(runtime_t *runtime) {
|
||||
runtime->config_module_handle = nullptr;
|
||||
|
||||
bar_cleanup(&runtime->bar);
|
||||
|
||||
close(runtime->signal_fd);
|
||||
runtime->signal_fd = -1;
|
||||
}
|
||||
|
||||
static void runtime_notify_initial_state(runtime_t *runtime) {
|
||||
@@ -189,51 +244,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 +268,25 @@ static void runtime_setup(runtime_t *runtime) {
|
||||
|
||||
backend_apply_effect(backend, plan->effects, plan->count);
|
||||
plan_reset(plan);
|
||||
runtime_notify_initial_state(runtime);
|
||||
}
|
||||
|
||||
static inline void runtime_setup_signal(runtime_t *runtime) {
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGINT);
|
||||
sigaddset(&mask, SIGTERM);
|
||||
sigaddset(&mask, SIGQUIT);
|
||||
sigprocmask(SIG_BLOCK, &mask, nullptr);
|
||||
|
||||
runtime->signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
|
||||
}
|
||||
|
||||
static void runtime_setup(runtime_t *runtime) {
|
||||
runtime_setup_signal(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) {
|
||||
@@ -424,19 +451,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);
|
||||
|
||||
@@ -454,6 +482,52 @@ static void runtime_run_event_loop(runtime_t *runtime) {
|
||||
}
|
||||
}
|
||||
|
||||
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},
|
||||
[2] = {.fd = runtime->signal_fd, .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);
|
||||
}
|
||||
}
|
||||
|
||||
if (fds[2].revents & POLLIN) {
|
||||
struct signalfd_siginfo info = {0};
|
||||
read(fds[2].fd, &info, sizeof(info));
|
||||
runtime->running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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