diff --git a/include/zdwm/config.h b/include/zdwm/config.h index 5620416..4456933 100644 --- a/include/zdwm/config.h +++ b/include/zdwm/config.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #if defined(__cplusplus) @@ -54,6 +55,19 @@ typedef struct zdwm_api_t { const zdwm_layout_id_t *layout_ids, size_t layout_count, zdwm_layout_id_t initial_layout_id); + + /** + * 用户调用这个函数添加窗口规则 + * @param builder 配置构建上下文 + * @param match 窗口匹配条件,不能为 nullptr + * @param action 匹配后执行的动作,不能为 nullptr + * @returns 添加成功返回 true ,不合法时返回 false + * @details 不合法的情况:match 所有字段全为 nullptr; + * 或 action 无任何动作;或 action 指定的 workspace 不存在 + */ + bool (*add_rule)(zdwm_config_builder_t *builder, + const zdwm_rule_match_t *match, + const zdwm_rule_action_t *action); } zdwm_api_t; /** diff --git a/include/zdwm/rules.h b/include/zdwm/rules.h new file mode 100644 index 0000000..3de08cd --- /dev/null +++ b/include/zdwm/rules.h @@ -0,0 +1,38 @@ +#ifndef ZDWM_RULES_H +#define ZDWM_RULES_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * @brief 窗口匹配条件 + * @details 仅匹配不为 nullptr 的字段,多个字段按且规则匹配 + */ +typedef struct zdwm_rule_match_t { + const char *app_id; + const char *role; + const char *class_name; + const char *instance_name; +} zdwm_rule_match_t; + +typedef struct zdwm_rule_action_t { + /** + * 目标 workspace id + * - 若规则不想指定 workspace ,则将其设为 ZDWM_WORKSPACE_ID_INVALID + */ + zdwm_workspace_id_t workspace; + + bool switch_to_workspace; /* 自动切换到目标 workspace(仅 true 时生效) */ + bool fullscreen; /* 强制全屏(仅 true 时生效) */ + bool maximize; /* 强制最大化(仅 true 时生效) */ + bool floating; /* 强制浮动(仅 true 时生效) */ +} zdwm_rule_action_t; + +#if defined(__cplusplus) +} +#endif + +#endif /* ZDWM_RULES_H */ diff --git a/src/config/runtime_config.c b/src/config/runtime_config.c index 772de6b..60199d5 100644 --- a/src/config/runtime_config.c +++ b/src/config/runtime_config.c @@ -1,6 +1,7 @@ #include "config/runtime_config.h" #include +#include #include #include "base/array.h" @@ -8,11 +9,14 @@ #include "config/defaults.h" #include "config/loader.h" #include "core/layout.h" +#include "core/rules.h" #include "core/runtime.h" +#include "core/types.h" #include "core/wm_desc.h" struct zdwm_config_builder_t { layout_registry_t layouts; + rules_t rules; workspace_desc_t *workspaces; size_t workspace_count; size_t workspace_capacity; @@ -89,6 +93,46 @@ static workspace_id_t runtime_config_define_workspace( return workspace_id; } +static bool rule_match_valid(const rule_match_t *match) { + if (!match) return false; + + return match->app_id || match->role || match->class_name || + match->instance_name; +} + +static bool rule_action_valid(const rule_action_t *action, + size_t workspace_count) { + if (!action) return false; + + bool flag_valid = action->switch_to_workspace || action->fullscreen || + action->maximize || action->floating; + + if (action->workspace == ZDWM_WORKSPACE_ID_INVALID) { + return flag_valid; + } else { + return action->workspace < workspace_count && flag_valid; + } +} + +static bool runtime_config_add_rule(zdwm_config_builder_t *builder, + const zdwm_rule_match_t *match, + const zdwm_rule_action_t *action) { + if (!builder) return false; + if (!rule_match_valid(match)) return false; + if (!rule_action_valid(action, builder->workspace_count)) return false; + + rules_t *rules = &builder->rules; + rule_item_t *rule = array_push(rules->items, rules->count, rules->capacity); + + rule->match.app_id = p_strdup_nullable(match->app_id); + rule->match.role = p_strdup_nullable(match->role); + rule->match.class_name = p_strdup_nullable(match->class_name); + rule->match.instance_name = p_strdup_nullable(match->instance_name); + rule->action = *action; + + return true; +} + static bool config_builder_finish(zdwm_config_builder_t *builder, runtime_init_desc_t *out) { if (!builder || !out) return false; @@ -96,6 +140,7 @@ static bool config_builder_finish(zdwm_config_builder_t *builder, if (!builder->layouts.slot_count || !builder->workspace_count) return false; if (!layout_registry_move(&builder->layouts, &out->layouts)) return false; + if (!rules_move(&builder->rules, &out->rules)) return false; out->workspaces = builder->workspaces; out->workspace_count = builder->workspace_count; builder->workspaces = nullptr; @@ -122,6 +167,7 @@ static bool runtime_config_build(zdwm_config_setup_fn *setup, }, .register_layout = runtime_config_register_layout, .define_workspace = runtime_config_define_workspace, + .add_rule = runtime_config_add_rule, }; bool ok = setup(&api, &builder, outputs, output_count) && config_builder_finish(&builder, out); diff --git a/src/core/rules.c b/src/core/rules.c new file mode 100644 index 0000000..7201584 --- /dev/null +++ b/src/core/rules.c @@ -0,0 +1,37 @@ +#include "core/rules.h" + +#include "base/memory.h" +#include "core/types.h" + +bool rules_move(rules_t *src, rules_t *dest) { + if (!dest || !src) return false; + + dest->items = src->items; + dest->count = src->count; + dest->capacity = src->capacity; + + src->items = nullptr; + src->count = 0; + src->capacity = 0; + + return true; +} + +void rules_cleanup(rules_t *rules) { + for (size_t i = 0; i < rules->count; ++i) { + rule_match_t *match = &rules->items[i].match; + rule_action_t *action = &rules->items[i].action; + + p_delete(&match->app_id); + p_delete(&match->role); + p_delete(&match->class_name); + p_delete(&match->instance_name); + + p_clear(action, 1); + action->workspace = ZDWM_WORKSPACE_ID_INVALID; + } + + p_delete(&rules->items); + rules->capacity = 0; + rules->count = 0; +} diff --git a/src/core/rules.h b/src/core/rules.h new file mode 100644 index 0000000..c2b6b46 --- /dev/null +++ b/src/core/rules.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "core/types.h" + +typedef struct rule_item_t { + rule_match_t match; + rule_action_t action; +} rule_item_t; + +typedef struct rules_t { + rule_item_t *items; + size_t count; + size_t capacity; +} rules_t; + +bool rules_move(rules_t *dest, rules_t *src); +void rules_cleanup(rules_t *rules); diff --git a/src/core/runtime.c b/src/core/runtime.c index 6c15e34..b4b0e9c 100644 --- a/src/core/runtime.c +++ b/src/core/runtime.c @@ -5,6 +5,8 @@ #include "base/memory.h" #include "core/backend.h" #include "core/event.h" +#include "core/layout.h" +#include "core/rules.h" #include "core/state.h" #include "core/wm_desc.h" @@ -42,11 +44,10 @@ bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc) { p_clear(runtime, 1); runtime->backend = desc->backend; - runtime->layouts = desc->layouts; + layout_registry_move(&desc->layouts, &runtime->layouts); + rules_move(&desc->rules, &runtime->rules); runtime->config_module_handle = desc->config_module_handle; - desc->backend = nullptr; - p_clear(&desc->layouts, 1); desc->config_module_handle = nullptr; state_init(&runtime->state, desc->outputs, desc->output_count, @@ -81,10 +82,8 @@ void runtime_init_desc_cleanup(runtime_init_desc_t *desc) { void runtime_shutdown(runtime_t *runtime) { runtime->running = false; - if (runtime->layouts.slots || runtime->layouts.slot_count || - runtime->layouts.slot_capacity) { - layout_registry_cleanup(&runtime->layouts); - } + layout_registry_cleanup(&runtime->layouts); + rules_cleanup(&runtime->rules); state_cleanup(&runtime->state); backend_destroy(runtime->backend); runtime->backend = nullptr; diff --git a/src/core/runtime.h b/src/core/runtime.h index 0ec78cb..bce3f0d 100644 --- a/src/core/runtime.h +++ b/src/core/runtime.h @@ -4,6 +4,7 @@ #include "core/backend.h" #include "core/layout.h" +#include "core/rules.h" #include "core/state.h" typedef struct runtime_init_desc_t { @@ -12,6 +13,7 @@ typedef struct runtime_init_desc_t { size_t output_count; layout_registry_t layouts; + rules_t rules; workspace_desc_t *workspaces; size_t workspace_count; void *config_module_handle; @@ -23,6 +25,7 @@ typedef struct runtime_t { state_t state; layout_registry_t layouts; + rules_t rules; backend_t *backend; void *config_module_handle; } runtime_t; diff --git a/src/core/types.h b/src/core/types.h index e6b3d9e..b360e65 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include /* clang-format off */ @@ -11,6 +12,9 @@ typedef uint32_t output_id_t; typedef zdwm_rect_t rect_t; typedef zdwm_output_info_t output_info_t; + +typedef zdwm_rule_match_t rule_match_t; +typedef zdwm_rule_action_t rule_action_t; /* clang-format on */ #define ZDWM_OUTPUT_ID_INVALID ((output_id_t)UINT32_MAX) diff --git a/tests/config/CMakeLists.txt b/tests/config/CMakeLists.txt index 07a1c09..86dd7dc 100644 --- a/tests/config/CMakeLists.txt +++ b/tests/config/CMakeLists.txt @@ -43,6 +43,7 @@ add_executable(${RUNTIME_CONFIG_TEST_APP_NAME} ${SOURCE_DIR}/config/runtime_config.c ${SOURCE_DIR}/core/layer.c ${SOURCE_DIR}/core/layout.c + ${SOURCE_DIR}/core/rules.c ${SOURCE_DIR}/core/runtime.c ${SOURCE_DIR}/core/state.c ) diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt index 98c5ecf..22f4a40 100644 --- a/tests/core/CMakeLists.txt +++ b/tests/core/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(${TEST_APP_NAME} ${SOURCE_DIR}/backend/x11/window.c ${SOURCE_DIR}/core/layer.c ${SOURCE_DIR}/core/layout.c + ${SOURCE_DIR}/core/rules.c ${SOURCE_DIR}/core/runtime.c ${SOURCE_DIR}/core/state.c )