core: 补全 layout 注册表与结果集接口

- 新增 src/core/layout.c,实现 layout result 和 registry 的基础操作
- 精简 wm_layout_ctx_t,改为按顺序传递参与布局的窗口 id 列表
- 为 layout API 补充中文前置条件说明
- 在 utils 中补充 p_strdup 和容量扩展辅助函数
This commit is contained in:
2026-03-13 01:49:09 +08:00
parent 57c6a831d4
commit 9954ae19d4
3 changed files with 151 additions and 7 deletions

99
src/core/layout.c Normal file
View File

@@ -0,0 +1,99 @@
#include "core/layout.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#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 = &registry->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(&registry->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 &registry->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(&registry->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 = &registry->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 &registry->slots[id];
}

View File

@@ -4,17 +4,20 @@
#include "core/types.h" #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 { typedef struct wm_layout_ctx_t {
wm_output_id_t output_id; wm_output_id_t output_id;
wm_workspace_id_t workspace_id; wm_workspace_id_t workspace_id;
wm_window_id_t focused_window_id; wm_window_id_t focused_window_id;
wm_rect_t workarea; 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; size_t window_count;
} wm_layout_ctx_t; } wm_layout_ctx_t;
@@ -76,18 +79,48 @@ typedef struct wm_layout_registry_t {
size_t slot_capacity; size_t slot_capacity;
} wm_layout_registry_t; } wm_layout_registry_t;
/*
* 调用约束:
* - result 必须是有效的非空指针
* - 除 init 之外,其余 result 相关接口都要求 result 已初始化
* - 传入空指针或未初始化对象属于调用方错误
*/
void wm_layout_result_init(wm_layout_result_t *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_reset(wm_layout_result_t *result);
void wm_layout_result_shutdown(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_init(wm_layout_registry_t *registry);
void wm_layout_registry_shutdown(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); size_t wm_layout_registry_count(const wm_layout_registry_t *registry);
const wm_layout_slot_t *wm_layout_registry_at( const wm_layout_slot_t *wm_layout_registry_at(
const wm_layout_registry_t *registry, size_t index); 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, wm_layout_id_t wm_layout_register(wm_layout_registry_t *registry,
const char *name, const char *symbol, const char *name, const char *symbol,
const char *description, wm_layout_fn fn); const char *description, wm_layout_fn fn);

View File

@@ -28,6 +28,12 @@
#define unlikely(expr) expr #define unlikely(expr) expr
#endif #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) { static inline void *__attribute__((malloc)) xmalloc(ssize_t size) {
void *ptr; void *ptr;
@@ -101,3 +107,9 @@ static inline void logger(const char *format, ...) {
#ifndef MAX #ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif #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;
}