diff --git a/src/core/layout.c b/src/core/layout.c new file mode 100644 index 0000000..de4ca4f --- /dev/null +++ b/src/core/layout.c @@ -0,0 +1,99 @@ +#include "core/layout.h" + +#include +#include +#include + +#include "utils.h" + +void wm_layout_result_init(wm_layout_result_t *result) { + result->item_count = 0; + result->item_capacity = INIT_CAPACITY; + result->items = p_new(wm_layout_item_t, result->item_capacity); +} + +void wm_layout_result_reset(wm_layout_result_t *result) { + result->item_count = 0; +} + +void wm_layout_result_shutdown(wm_layout_result_t *result) { + p_delete(&result->items); + result->item_count = 0; + result->item_capacity = 0; +} + +void wm_layout_result_push(wm_layout_result_t *result, wm_layout_item_t item) { + if (result->item_count == result->item_capacity) { + size_t new_capacity = next_capacity(result->item_capacity); + p_realloc(&result->items, new_capacity); + result->item_capacity = new_capacity; + } + + result->items[result->item_count++] = item; +} + +void wm_layout_registry_init(wm_layout_registry_t *registry) { + registry->slot_count = 0; + registry->slot_capacity = INIT_CAPACITY; + registry->slots = p_new(wm_layout_slot_t, registry->slot_capacity); +} + +void wm_layout_registry_shutdown(wm_layout_registry_t *registry) { + while (registry->slot_count > 0) { + wm_layout_slot_t *r = ®istry->slots[--registry->slot_count]; + p_delete(&r->name); + p_delete(&r->symbol); + p_delete(&r->description); + r->fn = nullptr; + r->id = WM_LAYOUT_ID_INVALID; + } + p_delete(®istry->slots); + registry->slot_count = 0; + registry->slot_capacity = 0; +} + +size_t wm_layout_registry_count(const wm_layout_registry_t *registry) { + return registry->slot_count; +} + +const wm_layout_slot_t *wm_layout_registry_at( + const wm_layout_registry_t *registry, size_t index) { + if (index >= registry->slot_count) return nullptr; + return ®istry->slots[index]; +} + +wm_layout_id_t wm_layout_register(wm_layout_registry_t *registry, + const char *name, const char *symbol, + const char *description, wm_layout_fn fn) { + if (!name || !symbol) return WM_LAYOUT_ID_INVALID; + + if (registry->slot_count == registry->slot_capacity) { + size_t new_capacity = next_capacity(registry->slot_capacity); + p_realloc(®istry->slots, new_capacity); + registry->slot_capacity = new_capacity; + } + wm_layout_id_t id = (wm_layout_id_t)registry->slot_count; + + wm_layout_slot_t *r = ®istry->slots[registry->slot_count]; + r->id = id; + r->name = p_strdup(name); + r->symbol = p_strdup(symbol); + r->description = description ? p_strdup(description) : nullptr; + r->fn = fn; + + registry->slot_count++; + return id; +} + +wm_layout_fn wm_layout_get(const wm_layout_registry_t *registry, + wm_layout_id_t id) { + const wm_layout_slot_t *layout_slot = wm_layout_slot_get(registry, id); + if (layout_slot) return layout_slot->fn; + return nullptr; +} + +const wm_layout_slot_t *wm_layout_slot_get(const wm_layout_registry_t *registry, + wm_layout_id_t id) { + if (id >= registry->slot_count) return nullptr; + return ®istry->slots[id]; +} diff --git a/src/core/layout.h b/src/core/layout.h index 85984db..9e304ae 100644 --- a/src/core/layout.h +++ b/src/core/layout.h @@ -4,17 +4,20 @@ #include "core/types.h" -typedef struct wm_layout_window_ref_t { - wm_window_id_t window_id; - wm_window_geometry_mode_t geometry_mode; -} wm_layout_window_ref_t; - typedef struct wm_layout_ctx_t { wm_output_id_t output_id; wm_workspace_id_t workspace_id; wm_window_id_t focused_window_id; wm_rect_t workarea; - const wm_layout_window_ref_t *windows; + /* + * 参与本次布局计算的窗口 ID 列表。 + * + * 调用方负责在进入 layout 前完成筛选;这里不包含 floating、sticky、 + * fullscreen、minimized 等不参与平铺计算的窗口。 + * + * 数组顺序具有语义,layout 应按该顺序解释窗口排列优先级。 + */ + const wm_window_id_t *window_ids; size_t window_count; } wm_layout_ctx_t; @@ -76,18 +79,48 @@ typedef struct wm_layout_registry_t { size_t slot_capacity; } wm_layout_registry_t; +/* + * 调用约束: + * - result 必须是有效的非空指针 + * - 除 init 之外,其余 result 相关接口都要求 result 已初始化 + * - 传入空指针或未初始化对象属于调用方错误 + */ void wm_layout_result_init(wm_layout_result_t *result); void wm_layout_result_reset(wm_layout_result_t *result); void wm_layout_result_shutdown(wm_layout_result_t *result); -bool wm_layout_result_push(wm_layout_result_t *result, wm_layout_item_t item); +void wm_layout_result_push(wm_layout_result_t *result, wm_layout_item_t item); +/* + * 调用约束: + * - registry 必须是有效的非空指针 + * - 除 init 之外,其余 registry 相关接口都要求 registry 已初始化 + * - 传入空指针或未初始化对象属于调用方错误 + */ void wm_layout_registry_init(wm_layout_registry_t *registry); void wm_layout_registry_shutdown(wm_layout_registry_t *registry); size_t wm_layout_registry_count(const wm_layout_registry_t *registry); const wm_layout_slot_t *wm_layout_registry_at( const wm_layout_registry_t *registry, size_t index); +/* + * 注册一个布局并返回其稳定 ID。 + * + * 前置条件: + * - registry 必须已初始化 + * + * 参数约束: + * - name 不可为空,用于稳定配置名、日志和调试展示 + * - symbol 不可为空,用于状态栏等紧凑展示 + * - description 可为空 + * - fn 可为空;fn == NULL 表示 floating 布局,不参与平铺计算 + * + * 返回值: + * - 成功时返回新注册布局的 ID + * - name 或 symbol 非法时返回 WM_LAYOUT_ID_INVALID + * + * 注册成功后,布局 ID 与其在 registry 中的槽位索引保持一致。 + */ wm_layout_id_t wm_layout_register(wm_layout_registry_t *registry, const char *name, const char *symbol, const char *description, wm_layout_fn fn); diff --git a/src/utils.h b/src/utils.h index 60ded39..69c3f54 100644 --- a/src/utils.h +++ b/src/utils.h @@ -28,6 +28,12 @@ #define unlikely(expr) expr #endif +static inline char *p_strdup(const char *text) { + char *r = strdup(text); + if (!r) abort(); + return r; +} + static inline void *__attribute__((malloc)) xmalloc(ssize_t size) { void *ptr; @@ -101,3 +107,9 @@ static inline void logger(const char *format, ...) { #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif + +static constexpr size_t INIT_CAPACITY = 4; +static inline size_t next_capacity(size_t capacity) { + if (capacity) return capacity * 2; + return INIT_CAPACITY; +}