core: 补全 state 容器初始化与实体访问接口
This commit is contained in:
@@ -57,7 +57,7 @@ wm_workspace_t *ws = &state->workspaces[workspace_id]; // O(1)
|
|||||||
wm_output_t *output = &state->outputs[output_id]; // O(1)
|
wm_output_t *output = &state->outputs[output_id]; // O(1)
|
||||||
|
|
||||||
// 动态实体:线性查找(简单且足够)
|
// 动态实体:线性查找(简单且足够)
|
||||||
wm_window_t *win = wm_state_find_window(state, window_id); // O(n)
|
const wm_window_t *win = wm_state_window_get(state, window_id); // O(n)
|
||||||
```
|
```
|
||||||
|
|
||||||
**设计优势**:
|
**设计优势**:
|
||||||
|
|||||||
@@ -53,27 +53,23 @@ void runtime_handle_metadata_event(wm_runtime_t *runtime, const wm_event_t *even
|
|||||||
const wm_window_metadata_changed_event_t *e = &event->as.window_metadata_changed;
|
const wm_window_metadata_changed_event_t *e = &event->as.window_metadata_changed;
|
||||||
|
|
||||||
// 1. 查找窗口
|
// 1. 查找窗口
|
||||||
wm_window_t *win = wm_state_find_window(&runtime->state, e->window_id);
|
const wm_window_t *win = wm_state_window_get(&runtime->state, e->window_id);
|
||||||
if (!win) {
|
if (!win) {
|
||||||
return; // 窗口已被销毁
|
return; // 窗口已被销毁
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 直接更新窗口元数据字段
|
// 2. 通过 state 接口更新窗口元数据字段
|
||||||
if (e->changed_fields & WM_WINDOW_META_CHANGED_TITLE) {
|
if (e->changed_fields & WM_WINDOW_META_CHANGED_TITLE) {
|
||||||
free(win->title);
|
wm_state_window_set_title(&runtime->state, e->window_id, e->title);
|
||||||
win->title = e->title ? strdup(e->title) : NULL;
|
|
||||||
}
|
}
|
||||||
if (e->changed_fields & WM_WINDOW_META_CHANGED_APP_ID) {
|
if (e->changed_fields & WM_WINDOW_META_CHANGED_APP_ID) {
|
||||||
free(win->app_id);
|
wm_state_window_set_app_id(&runtime->state, e->window_id, e->app_id);
|
||||||
win->app_id = e->app_id ? strdup(e->app_id) : NULL;
|
|
||||||
}
|
}
|
||||||
if (e->changed_fields & WM_WINDOW_META_CHANGED_CLASS) {
|
if (e->changed_fields & WM_WINDOW_META_CHANGED_CLASS) {
|
||||||
free(win->class_name);
|
wm_state_window_set_class(&runtime->state, e->window_id, e->class_name);
|
||||||
win->class_name = e->class_name ? strdup(e->class_name) : NULL;
|
|
||||||
}
|
}
|
||||||
if (e->changed_fields & WM_WINDOW_META_CHANGED_INSTANCE) {
|
if (e->changed_fields & WM_WINDOW_META_CHANGED_INSTANCE) {
|
||||||
free(win->instance_name);
|
wm_state_window_set_instance(&runtime->state, e->window_id, e->instance_name);
|
||||||
win->instance_name = e->instance_name ? strdup(e->instance_name) : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 标记 render 脏(状态栏需要更新)
|
// 3. 标记 render 脏(状态栏需要更新)
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ static bool apply_manage_window(wm_state_t *state,
|
|||||||
wm_window_id_t id = command->as.manage_window.window_id;
|
wm_window_id_t id = command->as.manage_window.window_id;
|
||||||
wm_workspace_id_t ws_id = command->as.manage_window.workspace_id;
|
wm_workspace_id_t ws_id = command->as.manage_window.workspace_id;
|
||||||
|
|
||||||
if (wm_state_find_window_const(state, id)) return false;
|
if (wm_state_window_get(state, id)) return false;
|
||||||
wm_workspace_t *ws = require_workspace(state, ws_id);
|
wm_workspace_t *ws = require_workspace(state, ws_id);
|
||||||
if (!ws) return false;
|
if (!ws) return false;
|
||||||
|
|
||||||
|
|||||||
539
src/core/state.c
Normal file
539
src/core/state.c
Normal file
@@ -0,0 +1,539 @@
|
|||||||
|
#include "core/state.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "core/types.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "wm_desc.h"
|
||||||
|
|
||||||
|
void wm_state_init(wm_state_t *state, const wm_output_info_t *outputs,
|
||||||
|
size_t output_count, const wm_workspace_desc_t *workspaces,
|
||||||
|
size_t workspace_count) {
|
||||||
|
p_clear(state, 1);
|
||||||
|
|
||||||
|
state->outputs = p_new(wm_output_t, output_count);
|
||||||
|
for (size_t i = 0; i < output_count; i++) {
|
||||||
|
const wm_output_info_t *output_info = &outputs[i];
|
||||||
|
wm_output_t *output = &state->outputs[i];
|
||||||
|
|
||||||
|
output->id = (wm_output_id_t)i;
|
||||||
|
output->current_workspace_id = WM_WORKSPACE_ID_INVALID;
|
||||||
|
output->name = p_strdup(output_info->name);
|
||||||
|
output->geometry = output_info->geometry;
|
||||||
|
output->workarea = output_info->geometry;
|
||||||
|
}
|
||||||
|
state->output_count = output_count;
|
||||||
|
|
||||||
|
state->workspaces = p_new(wm_workspace_t, workspace_count);
|
||||||
|
for (size_t i = 0; i < workspace_count; i++) {
|
||||||
|
const wm_workspace_desc_t *workspace_desc = &workspaces[i];
|
||||||
|
if (!wm_workspace_desc_valid(workspace_desc, output_count)) {
|
||||||
|
fatal("workspace desc at index %zu invalid", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_output_t *output = &state->outputs[workspace_desc->output_index];
|
||||||
|
wm_workspace_t *workspace = &state->workspaces[i];
|
||||||
|
workspace->id = (wm_workspace_id_t)i;
|
||||||
|
workspace->output_id = output->id;
|
||||||
|
workspace->focused_window_id = WM_WINDOW_ID_INVALID;
|
||||||
|
workspace->available_layouts =
|
||||||
|
p_copy(workspace_desc->layout_ids, workspace_desc->layout_count);
|
||||||
|
workspace->layout_id = workspace_desc->initial_layout_id;
|
||||||
|
workspace->layout_count = workspace_desc->layout_count;
|
||||||
|
workspace->name = p_strdup(workspace_desc->name);
|
||||||
|
|
||||||
|
if (output->current_workspace_id == WM_WORKSPACE_ID_INVALID) {
|
||||||
|
output->current_workspace_id = workspace->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state->workspace_count = workspace_count;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < state->output_count; i++) {
|
||||||
|
const wm_output_t *output = &state->outputs[i];
|
||||||
|
if (output->current_workspace_id == WM_WORKSPACE_ID_INVALID) {
|
||||||
|
fatal("output at index %zu has no workspace", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_cleanup(wm_state_t *state) {
|
||||||
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
|
wm_window_t *window = &state->windows[i];
|
||||||
|
p_delete(&window->title);
|
||||||
|
p_delete(&window->app_id);
|
||||||
|
p_delete(&window->class_name);
|
||||||
|
p_delete(&window->instance_name);
|
||||||
|
}
|
||||||
|
state->window_count = 0;
|
||||||
|
p_delete(&state->windows);
|
||||||
|
p_delete(&state->stack_order);
|
||||||
|
state->window_capacity = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < state->workspace_count; i++) {
|
||||||
|
wm_workspace_t *workspace = &state->workspaces[i];
|
||||||
|
p_delete(&workspace->name);
|
||||||
|
p_delete(&workspace->available_layouts);
|
||||||
|
workspace->layout_count = 0;
|
||||||
|
}
|
||||||
|
p_delete(&state->workspaces);
|
||||||
|
state->workspace_count = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < state->output_count; i++) {
|
||||||
|
wm_output_t *output = &state->outputs[i];
|
||||||
|
p_delete(&output->name);
|
||||||
|
}
|
||||||
|
p_delete(&state->outputs);
|
||||||
|
state->output_count = 0;
|
||||||
|
|
||||||
|
p_clear(state, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wm_workspace_t *wm_state_workspace_get(const wm_state_t *state,
|
||||||
|
wm_workspace_id_t id) {
|
||||||
|
if (id < state->workspace_count) return &state->workspaces[id];
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wm_workspace_t *wm_state_workspace_at(const wm_state_t *state,
|
||||||
|
size_t index) {
|
||||||
|
if (index < state->workspace_count) return &state->workspaces[index];
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wm_state_workspace_adjust_focused_window(
|
||||||
|
const wm_state_t *state, wm_workspace_id_t workspace_id) {
|
||||||
|
wm_workspace_t *workspace =
|
||||||
|
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
||||||
|
if (!workspace) return;
|
||||||
|
|
||||||
|
const wm_window_t *window =
|
||||||
|
wm_state_window_get(state, workspace->focused_window_id);
|
||||||
|
if (window && window->workspace_id == workspace_id) return;
|
||||||
|
|
||||||
|
for (size_t i = state->window_count; i > 0; i--) {
|
||||||
|
wm_window_id_t window_id = state->stack_order[i - 1];
|
||||||
|
const wm_window_t *window = wm_state_window_get(state, window_id);
|
||||||
|
if (window && window->workspace_id == workspace_id) {
|
||||||
|
workspace->focused_window_id = window_id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace->focused_window_id = WM_WINDOW_ID_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_state_workspace_cycle_layout(wm_state_t *state,
|
||||||
|
wm_workspace_id_t workspace_id) {
|
||||||
|
wm_workspace_t *workspace =
|
||||||
|
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
||||||
|
if (!workspace) return false;
|
||||||
|
|
||||||
|
size_t next_index = 0;
|
||||||
|
bool matched = false;
|
||||||
|
for (size_t i = 0; i < workspace->layout_count; i++) {
|
||||||
|
if (workspace->layout_id == workspace->available_layouts[i]) {
|
||||||
|
next_index = (i + 1) % workspace->layout_count;
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matched) return false;
|
||||||
|
|
||||||
|
auto next_layout_id = workspace->available_layouts[next_index];
|
||||||
|
workspace->layout_id = next_layout_id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_state_workspace_set_layout_by_index(wm_state_t *state,
|
||||||
|
wm_workspace_id_t workspace_id,
|
||||||
|
size_t index) {
|
||||||
|
wm_workspace_t *workspace =
|
||||||
|
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
||||||
|
if (!workspace) return false;
|
||||||
|
if (index >= workspace->layout_count) return false;
|
||||||
|
|
||||||
|
workspace->layout_id = workspace->available_layouts[index];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_state_workspace_set_layout_by_id(wm_state_t *state,
|
||||||
|
wm_workspace_id_t workspace_id,
|
||||||
|
wm_layout_id_t layout_id) {
|
||||||
|
wm_workspace_t *workspace =
|
||||||
|
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
||||||
|
if (!workspace) return false;
|
||||||
|
for (size_t i = 0; i < workspace->layout_count; i++) {
|
||||||
|
if (workspace->available_layouts[i] == layout_id) {
|
||||||
|
workspace->layout_id = layout_id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_workspace_set_focused_window(wm_state_t *state,
|
||||||
|
wm_workspace_id_t workspace_id,
|
||||||
|
wm_window_id_t window_id) {
|
||||||
|
wm_workspace_t *workspace =
|
||||||
|
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
||||||
|
if (!workspace) return;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
|
wm_window_t *window = &state->windows[i];
|
||||||
|
if (window->id == window_id && window->workspace_id == workspace_id) {
|
||||||
|
workspace->focused_window_id = window_id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_state_workspace_adjust_focused_window(state, workspace_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t wm_state_workspace_count(const wm_state_t *state) {
|
||||||
|
return state->workspace_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_state_workspace_valid(const wm_state_t *state, wm_workspace_id_t id) {
|
||||||
|
return id < state->workspace_count;
|
||||||
|
|
||||||
|
/* 线性扫描作为备用 */
|
||||||
|
#if 0
|
||||||
|
if (id >= state->workspace_count) return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < state->workspace_count; i++) {
|
||||||
|
if (state->workspaces[i].id == id) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const wm_output_t *wm_state_output_get(const wm_state_t *state,
|
||||||
|
wm_output_id_t id) {
|
||||||
|
if (id < state->output_count) return &state->outputs[id];
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wm_output_t *wm_state_output_at(const wm_state_t *state, size_t index) {
|
||||||
|
if (index < state->output_count) return &state->outputs[index];
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_output_set_workarea(wm_state_t *state, wm_output_id_t output_id,
|
||||||
|
wm_rect_t workarea) {
|
||||||
|
wm_output_t *output = (wm_output_t *)wm_state_output_get(state, output_id);
|
||||||
|
if (output) output->workarea = workarea;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_output_set_current_workspace(wm_state_t *state,
|
||||||
|
wm_output_id_t output_id,
|
||||||
|
wm_workspace_id_t workspace_id) {
|
||||||
|
wm_output_t *output = (wm_output_t *)wm_state_output_get(state, output_id);
|
||||||
|
if (!output) return;
|
||||||
|
const wm_workspace_t *workspace = wm_state_workspace_get(state, workspace_id);
|
||||||
|
if (!workspace || workspace->output_id != output_id) return;
|
||||||
|
|
||||||
|
output->current_workspace_id = workspace_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t wm_state_output_count(const wm_state_t *state) {
|
||||||
|
return state->output_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_state_output_valid(const wm_state_t *state, wm_output_id_t id) {
|
||||||
|
return id < state->output_count;
|
||||||
|
|
||||||
|
/* 线性扫描作为备用 */
|
||||||
|
#if 0
|
||||||
|
if (id >= state->output_count) return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < state->output_count; i++) {
|
||||||
|
if (state->outputs[i].id == id) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const wm_window_t *wm_state_window_add(wm_state_t *state,
|
||||||
|
const wm_window_info_t *info) {
|
||||||
|
wm_window_id_t id = info->id;
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, id);
|
||||||
|
if (!window) {
|
||||||
|
if (state->window_count == state->window_capacity) {
|
||||||
|
size_t capacity = next_capacity(state->window_capacity);
|
||||||
|
p_realloc(&state->windows, capacity);
|
||||||
|
p_realloc(&state->stack_order, capacity);
|
||||||
|
state->window_capacity = capacity;
|
||||||
|
}
|
||||||
|
window = &state->windows[state->window_count];
|
||||||
|
p_clear(window, 1);
|
||||||
|
window->id = id;
|
||||||
|
window->workspace_id = WM_WORKSPACE_ID_INVALID;
|
||||||
|
|
||||||
|
state->stack_order[state->window_count] = id;
|
||||||
|
state->window_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_state_window_set_geometry_mode(state, id, info->geometry_mode);
|
||||||
|
wm_state_window_set_urgent(state, id, info->urgent);
|
||||||
|
wm_state_window_set_fixed_size(state, id, info->fixed_size);
|
||||||
|
wm_state_window_set_frame_rect(state, id, info->frame_rect);
|
||||||
|
wm_state_window_set_title(state, id, info->title);
|
||||||
|
wm_state_window_set_app_id(state, id, info->app_id);
|
||||||
|
wm_state_window_set_class(state, id, info->class_name);
|
||||||
|
wm_state_window_set_instance(state, id, info->instance_name);
|
||||||
|
wm_state_window_set_skip_taskbar(state, id, info->skip_taskbar);
|
||||||
|
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wm_window_t *wm_state_window_get(const wm_state_t *state,
|
||||||
|
wm_window_id_t id) {
|
||||||
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
|
if (state->windows[i].id == id) return &state->windows[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wm_window_t *wm_state_window_at(const wm_state_t *state, size_t index) {
|
||||||
|
if (index < state->window_count) return &state->windows[index];
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_remove(wm_state_t *state, wm_window_id_t id) {
|
||||||
|
bool matched = false;
|
||||||
|
size_t index = 0;
|
||||||
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
|
if (state->windows[i].id == id) {
|
||||||
|
matched = true;
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!matched) return;
|
||||||
|
|
||||||
|
wm_window_t *window = &state->windows[index];
|
||||||
|
wm_workspace_id_t workspace_id = window->workspace_id;
|
||||||
|
p_delete(&window->title);
|
||||||
|
p_delete(&window->app_id);
|
||||||
|
p_delete(&window->class_name);
|
||||||
|
p_delete(&window->instance_name);
|
||||||
|
|
||||||
|
for (size_t i = index + 1; i < state->window_count; i++) {
|
||||||
|
state->windows[i - 1] = state->windows[i];
|
||||||
|
}
|
||||||
|
window = &state->windows[state->window_count - 1];
|
||||||
|
p_clear(window, 1);
|
||||||
|
window->id = WM_WINDOW_ID_INVALID;
|
||||||
|
window->workspace_id = WM_WORKSPACE_ID_INVALID;
|
||||||
|
|
||||||
|
matched = false;
|
||||||
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
|
if (state->stack_order[i] == id) {
|
||||||
|
matched = true;
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matched) {
|
||||||
|
for (size_t i = index + 1; i < state->window_count; i++) {
|
||||||
|
state->stack_order[i - 1] = state->stack_order[i];
|
||||||
|
}
|
||||||
|
state->stack_order[state->window_count - 1] = WM_WINDOW_ID_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->window_count--;
|
||||||
|
|
||||||
|
wm_workspace_t *workspace =
|
||||||
|
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
||||||
|
if (workspace && workspace->focused_window_id == id) {
|
||||||
|
wm_state_workspace_adjust_focused_window(state, workspace_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t wm_state_window_count(const wm_state_t *state) {
|
||||||
|
return state->window_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_set_workspace(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
wm_workspace_id_t workspace_id) {
|
||||||
|
const wm_workspace_t *workspace = wm_state_workspace_get(state, workspace_id);
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!workspace || !window || window->workspace_id == workspace_id) return;
|
||||||
|
|
||||||
|
workspace = wm_state_workspace_get(state, window->workspace_id);
|
||||||
|
window->workspace_id = workspace_id;
|
||||||
|
|
||||||
|
if (workspace && workspace->focused_window_id == window_id) {
|
||||||
|
wm_state_workspace_adjust_focused_window(state, workspace->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_state_workspace_adjust_focused_window(state, workspace_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_set_geometry_mode(
|
||||||
|
wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
wm_window_geometry_mode_t geometry_mode) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
window->geometry_mode = geometry_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_set_floating(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
bool floating) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
window->floating = floating;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_set_sticky(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
bool sticky) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
window->sticky = sticky;
|
||||||
|
if (window->sticky) wm_state_window_set_floating(state, window_id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_set_urgent(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
bool urgent) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
window->urgent = urgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_set_fixed_size(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
bool fixed_size) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
window->fixed_size = fixed_size;
|
||||||
|
if (fixed_size) wm_state_window_set_floating(state, window_id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_set_skip_taskbar(wm_state_t *state,
|
||||||
|
wm_window_id_t window_id,
|
||||||
|
bool skip_taskbar) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
window->skip_taskbar = skip_taskbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_set_float_rect(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
wm_rect_t float_rect) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
window->float_rect = float_rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_state_window_set_frame_rect(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
wm_rect_t frame_rect) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
window->frame_rect = frame_rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_state_window_set_title(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
const char *title) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return false;
|
||||||
|
|
||||||
|
p_delete(&window->title);
|
||||||
|
if (title) window->title = p_strdup(title);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_state_window_set_app_id(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
const char *app_id) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return false;
|
||||||
|
|
||||||
|
p_delete(&window->app_id);
|
||||||
|
if (app_id) window->app_id = p_strdup(app_id);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool wm_state_window_set_class(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
const char *class_name) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return false;
|
||||||
|
|
||||||
|
p_delete(&window->class_name);
|
||||||
|
if (class_name) window->class_name = p_strdup(class_name);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool wm_state_window_set_instance(wm_state_t *state, wm_window_id_t window_id,
|
||||||
|
const char *instance_name) {
|
||||||
|
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
||||||
|
if (!window) return false;
|
||||||
|
|
||||||
|
p_delete(&window->instance_name);
|
||||||
|
if (instance_name) window->instance_name = p_strdup(instance_name);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wm_window_id_t *wm_state_stack_order(const wm_state_t *state) {
|
||||||
|
return state->stack_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_window_id_t wm_state_stack_at(const wm_state_t *state, size_t index) {
|
||||||
|
if (index >= state->window_count) return WM_WINDOW_ID_INVALID;
|
||||||
|
return state->stack_order[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_state_stack_raise(wm_state_t *state, wm_window_id_t window_id) {
|
||||||
|
bool matched = false;
|
||||||
|
size_t index = 0;
|
||||||
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
|
if (state->stack_order[i] == window_id) {
|
||||||
|
matched = true;
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matched) return false;
|
||||||
|
|
||||||
|
for (size_t i = index + 1; i < state->window_count; i++) {
|
||||||
|
state->stack_order[i - 1] = state->stack_order[i];
|
||||||
|
}
|
||||||
|
state->stack_order[state->window_count - 1] = window_id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_state_stack_lower(wm_state_t *state, wm_window_id_t window_id) {
|
||||||
|
bool matched = false;
|
||||||
|
size_t index = 0;
|
||||||
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
|
if (state->stack_order[i] == window_id) {
|
||||||
|
matched = true;
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matched) return false;
|
||||||
|
|
||||||
|
for (size_t i = index; i > 0; i--) {
|
||||||
|
state->stack_order[i] = state->stack_order[i - 1];
|
||||||
|
}
|
||||||
|
state->stack_order[0] = window_id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -69,18 +69,25 @@ typedef struct wm_state_t {
|
|||||||
|
|
||||||
} wm_state_t;
|
} wm_state_t;
|
||||||
|
|
||||||
/* state 容器生命周期接口 */
|
|
||||||
void wm_state_init(wm_state_t *state, const wm_output_info_t *outputs,
|
|
||||||
size_t output_count);
|
|
||||||
void wm_state_cleanup(wm_state_t *state);
|
|
||||||
/*
|
/*
|
||||||
* 根据 workspace 描述表构建 state.workspaces[]。
|
* 调用约束:
|
||||||
|
* - state 必须是有效的非空指针
|
||||||
|
* - wm_state_init() / wm_state_cleanup() 必须成对调用
|
||||||
|
* - 同一个 state 生命周期内,wm_state_init() 不允许重复调用
|
||||||
|
* - 除 wm_state_init() 外,其余 state 相关接口都要求 state 已初始化
|
||||||
|
* - workspaces[i] 必须满足 wm_workspace_desc_valid(&workspaces[i], output_count)
|
||||||
|
* - 传入空指针、未初始化对象或违反前置条件属于调用方错误
|
||||||
*
|
*
|
||||||
|
* 初始化时根据描述表构建 outputs[] 与 workspaces[]。
|
||||||
* workspace_id 由 state 按描述表顺序分配并保持稳定,不从 desc 中读取。
|
* workspace_id 由 state 按描述表顺序分配并保持稳定,不从 desc 中读取。
|
||||||
|
* 每个 output 的 current_workspace_id 会自动设置为首个归属到该 output 的
|
||||||
|
* workspace;若某个 output 没有任何归属 workspace,wm_state_init() 会失败。
|
||||||
*/
|
*/
|
||||||
void wm_state_set_workspaces(wm_state_t *state,
|
void wm_state_init(wm_state_t *state, const wm_output_info_t *outputs,
|
||||||
|
size_t output_count,
|
||||||
const wm_workspace_desc_t *workspaces,
|
const wm_workspace_desc_t *workspaces,
|
||||||
size_t workspace_count);
|
size_t workspace_count);
|
||||||
|
void wm_state_cleanup(wm_state_t *state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* state 持有的 workspace 集合接口
|
* state 持有的 workspace 集合接口
|
||||||
@@ -186,7 +193,3 @@ const wm_window_id_t *wm_state_stack_order(const wm_state_t *state);
|
|||||||
wm_window_id_t wm_state_stack_at(const wm_state_t *state, size_t index);
|
wm_window_id_t wm_state_stack_at(const wm_state_t *state, size_t index);
|
||||||
bool wm_state_stack_raise(wm_state_t *state, wm_window_id_t window_id);
|
bool wm_state_stack_raise(wm_state_t *state, wm_window_id_t window_id);
|
||||||
bool wm_state_stack_lower(wm_state_t *state, wm_window_id_t window_id);
|
bool wm_state_stack_lower(wm_state_t *state, wm_window_id_t window_id);
|
||||||
|
|
||||||
/* 与 min_core_draft 中的查找命名保持一致 */
|
|
||||||
const wm_window_t *wm_state_find_window(const wm_state_t *state,
|
|
||||||
wm_window_id_t id);
|
|
||||||
|
|||||||
11
src/utils.h
11
src/utils.h
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
#define p_new(type, count) ((type *)xmalloc(sizeof(type) * (count)))
|
#define p_new(type, count) ((type *)xmalloc(sizeof(type) * (count)))
|
||||||
#define p_clear(p, count) ((void)memset((p), 0, sizeof(*(p)) * (count)))
|
#define p_clear(p, count) ((void)memset((p), 0, sizeof(*(p)) * (count)))
|
||||||
#define p_realloc(pp, count) xrealloc((void *)(pp), sizeof(**(pp)) * (count))
|
#define p_realloc(pp, count) xrealloc((void *)(pp), sizeof(**(pp)) * (count))
|
||||||
|
#define p_copy(src, count) xmemcopy((src), sizeof(*(src)) * (count))
|
||||||
|
|
||||||
#define p_delete(mem_p) \
|
#define p_delete(mem_p) \
|
||||||
do { \
|
do { \
|
||||||
@@ -46,6 +48,15 @@ static inline void *__attribute__((malloc)) xmalloc(ssize_t size) {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void *xmemcopy(const void *src, size_t n) {
|
||||||
|
if (!n) return nullptr;
|
||||||
|
|
||||||
|
void *mem = xmalloc(n);
|
||||||
|
void *ret = memcpy(mem, src, n);
|
||||||
|
if (ret != mem) abort();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void xrealloc(void **ptr, ssize_t newsize) {
|
static inline void xrealloc(void **ptr, ssize_t newsize) {
|
||||||
if (newsize <= 0)
|
if (newsize <= 0)
|
||||||
p_delete(ptr);
|
p_delete(ptr);
|
||||||
|
|||||||
@@ -30,9 +30,35 @@ typedef struct wm_window_info_t {
|
|||||||
} wm_window_info_t;
|
} wm_window_info_t;
|
||||||
|
|
||||||
typedef struct wm_workspace_desc_t {
|
typedef struct wm_workspace_desc_t {
|
||||||
wm_output_id_t output_id;
|
size_t output_index; /* 对应 wm_state_init() 中 outputs[] 的索引 */
|
||||||
const char *name;
|
const char *name;
|
||||||
const wm_layout_id_t *layout_ids;
|
const wm_layout_id_t *layout_ids;
|
||||||
size_t layout_count;
|
size_t layout_count;
|
||||||
wm_layout_id_t initial_layout_id;
|
wm_layout_id_t initial_layout_id;
|
||||||
} wm_workspace_desc_t;
|
} wm_workspace_desc_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* workspace 描述校验接口。
|
||||||
|
*
|
||||||
|
* 这组接口只校验描述表自身的一致性,不访问 state。
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
wm_workspace_desc_layouts_valid(const wm_workspace_desc_t *workspace) {
|
||||||
|
if (!workspace || !workspace->layout_count || !workspace->layout_ids) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < workspace->layout_count; i++) {
|
||||||
|
if (workspace->layout_ids[i] == workspace->initial_layout_id) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool wm_workspace_desc_valid(const wm_workspace_desc_t *workspace,
|
||||||
|
size_t output_count) {
|
||||||
|
if (!workspace || !workspace->name) return false;
|
||||||
|
if (workspace->output_index >= output_count) return false;
|
||||||
|
|
||||||
|
return wm_workspace_desc_layouts_valid(workspace);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user