core: 补全 state 容器初始化与实体访问接口
This commit is contained in:
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;
|
||||
|
||||
/* 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 中读取。
|
||||
* 每个 output 的 current_workspace_id 会自动设置为首个归属到该 output 的
|
||||
* workspace;若某个 output 没有任何归属 workspace,wm_state_init() 会失败。
|
||||
*/
|
||||
void wm_state_set_workspaces(wm_state_t *state,
|
||||
const wm_workspace_desc_t *workspaces,
|
||||
size_t workspace_count);
|
||||
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);
|
||||
void wm_state_cleanup(wm_state_t *state);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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);
|
||||
|
||||
/* 与 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
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -12,6 +13,7 @@
|
||||
#define p_new(type, count) ((type *)xmalloc(sizeof(type) * (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_copy(src, count) xmemcopy((src), sizeof(*(src)) * (count))
|
||||
|
||||
#define p_delete(mem_p) \
|
||||
do { \
|
||||
@@ -46,6 +48,15 @@ static inline void *__attribute__((malloc)) xmalloc(ssize_t size) {
|
||||
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) {
|
||||
if (newsize <= 0)
|
||||
p_delete(ptr);
|
||||
|
||||
@@ -30,9 +30,35 @@ typedef struct wm_window_info_t {
|
||||
} wm_window_info_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 wm_layout_id_t *layout_ids;
|
||||
size_t layout_count;
|
||||
wm_layout_id_t initial_layout_id;
|
||||
} 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