Compare commits

...

2 Commits

Author SHA1 Message Date
2fc4b33359 style: 更新 .clang-format 规则并重新格式化所有源文件
- 重构模块使用新的代码风格
- 老代码 (src 目录下的代码) 继续使用之前的代码风格

通过在需要不同代码风格的目录下放对应 .clang-format 配置文件实现
2026-04-14 01:52:53 +08:00
7b5404e8e0 refactor(backend/x11): 用 X-macro 统一 atom 列表的声明和初始化 2026-04-14 01:35:25 +08:00
63 changed files with 1287 additions and 817 deletions

View File

@@ -5,12 +5,34 @@ BasedOnStyle: Google
IndentWidth: 2 IndentWidth: 2
ConstructorInitializerIndentWidth: 2 ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2 ContinuationIndentWidth: 2
---
Language: C AlignConsecutiveAssignments:
DerivePointerAlignment: false Enabled: true
PointerAlignment: Right AcrossEmptyLines: false
--- AcrossComments: false
Language: Cpp AlignCompound: true
PadOperators: true
AlignConsecutiveBitFields:
Enabled: true
AlignConsecutiveMacros:
Enabled: true
AlignConsecutiveShortCaseStatements:
Enabled: true
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
IndentCaseLabels: false
# 多行函数每个参数单独一行
AlignAfterOpenBracket: BlockIndent
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
BinPackArguments: false
BinPackParameters: false
# 指针样式(右对齐)
DerivePointerAlignment: false DerivePointerAlignment: false
PointerAlignment: Right PointerAlignment: Right
--- ---

View File

@@ -24,8 +24,10 @@ typedef struct wm_backend_api_t {
* X11 这类需要被动抓键的平台可以在这里建立平台侧 grab * X11 这类需要被动抓键的平台可以在这里建立平台侧 grab
* 总能收到所有键盘事件的 backend 可以把它留空。 * 总能收到所有键盘事件的 backend 可以把它留空。
*/ */
bool (*set_keybindings)(wm_backend_t *backend, bool (*set_keybindings)(
const wm_key_binding_table_t *keybindings); wm_backend_t *backend,
const wm_key_binding_table_t *keybindings
);
/* /*
* 安装 bootstrap 固定下来的鼠标按键绑定表。 * 安装 bootstrap 固定下来的鼠标按键绑定表。
* X11 这类需要被动抓按钮的平台可以把它缓存下来,并在 root 或新受管窗口 * X11 这类需要被动抓按钮的平台可以把它缓存下来,并在 root 或新受管窗口
@@ -33,13 +35,17 @@ typedef struct wm_backend_api_t {
* 可以把它留空。 * 可以把它留空。
*/ */
bool (*set_pointer_bindings)( bool (*set_pointer_bindings)(
wm_backend_t *backend, wm_backend_t *backend,
const wm_pointer_binding_table_t *pointer_bindings); const wm_pointer_binding_table_t *pointer_bindings
);
/* /*
* 返回一个 backend 轮询结果。 * 返回一个 backend 轮询结果。
* 只有返回 WM_BACKEND_NEXT_EVENT 时out 才包含一个完整的 runtime 输入事件。 * 只有返回 WM_BACKEND_NEXT_EVENT 时out 才包含一个完整的 runtime 输入事件。
*/ */
wm_backend_next_result_t (*next_event)(wm_backend_t *backend, wm_event_t *out); wm_backend_next_result_t (*next_event)(
wm_backend_t *backend,
wm_event_t *out
);
/* /*
* Runtime filters out service-side effects such as WM_EFFECT_RENDER_OUTPUT. * Runtime filters out service-side effects such as WM_EFFECT_RENDER_OUTPUT.
* Backends only receive platform effects here. * Backends only receive platform effects here.

View File

@@ -1,9 +1,10 @@
#pragma once #pragma once
#include <stdbool.h>
#include <stddef.h>
#include "wm_command.h" #include "wm_command.h"
#include "wm_types.h" #include "wm_types.h"
#include <stdbool.h>
#include <stddef.h>
/* /*
* 输入绑定只匹配 backend 已归一化后的输入事件。 * 输入绑定只匹配 backend 已归一化后的输入事件。
@@ -71,8 +72,10 @@ typedef struct wm_pointer_binding_table_t {
* 出现在 key binding table 里。 * 出现在 key binding table 里。
*/ */
const wm_key_binding_t *wm_key_binding_find( const wm_key_binding_t *wm_key_binding_find(
const wm_key_binding_table_t *table, wm_keysym_t keysym, const wm_key_binding_table_t *table,
wm_modifier_mask_t modifiers); wm_keysym_t keysym,
wm_modifier_mask_t modifiers
);
/* /*
* 查找与当前按钮按下事件匹配的鼠标绑定。 * 查找与当前按钮按下事件匹配的鼠标绑定。
@@ -82,5 +85,8 @@ const wm_key_binding_t *wm_key_binding_find(
* 匹配顺序与键盘绑定一致:先 exact再 allow-extra-modifiers。 * 匹配顺序与键盘绑定一致:先 exact再 allow-extra-modifiers。
*/ */
const wm_pointer_binding_t *wm_pointer_binding_find( const wm_pointer_binding_t *wm_pointer_binding_find(
const wm_pointer_binding_table_t *table, wm_button_t button, const wm_pointer_binding_table_t *table,
wm_modifier_mask_t modifiers, bool hits_window); wm_button_t button,
wm_modifier_mask_t modifiers,
bool hits_window
);

View File

@@ -71,7 +71,8 @@ typedef struct wm_pointer_enter_event_t {
wm_point_t root; wm_point_t root;
// 相对 window 的坐标;若 window == WM_WINDOW_ID_INVALID则该值未定义 // 相对 window 的坐标;若 window == WM_WINDOW_ID_INVALID则该值未定义
wm_point_t local; wm_point_t local;
// 当前进入并获得 pointer focus 的窗口;若未命中窗口,则为 WM_WINDOW_ID_INVALID // 当前进入并获得 pointer focus 的窗口;若未命中窗口,则为
// WM_WINDOW_ID_INVALID
wm_window_id_t window; wm_window_id_t window;
} wm_pointer_enter_event_t; } wm_pointer_enter_event_t;
@@ -99,10 +100,10 @@ typedef struct wm_window_remove_event_t {
} wm_window_remove_event_t; } wm_window_remove_event_t;
typedef enum wm_window_meta_changed_flags_t { typedef enum wm_window_meta_changed_flags_t {
WM_WINDOW_META_CHANGED_NONE = 0, WM_WINDOW_META_CHANGED_NONE = 0,
WM_WINDOW_META_CHANGED_TITLE = 1u << 0, WM_WINDOW_META_CHANGED_TITLE = 1u << 0,
WM_WINDOW_META_CHANGED_APP_ID = 1u << 1, WM_WINDOW_META_CHANGED_APP_ID = 1u << 1,
WM_WINDOW_META_CHANGED_CLASS = 1u << 2, WM_WINDOW_META_CHANGED_CLASS = 1u << 2,
WM_WINDOW_META_CHANGED_INSTANCE = 1u << 3, WM_WINDOW_META_CHANGED_INSTANCE = 1u << 3,
} wm_window_meta_changed_flags_t; } wm_window_meta_changed_flags_t;
@@ -122,9 +123,9 @@ typedef struct wm_window_metadata_changed_event_t {
} wm_window_metadata_changed_event_t; } wm_window_metadata_changed_event_t;
typedef enum wm_window_hint_changed_flags_t { typedef enum wm_window_hint_changed_flags_t {
WM_WINDOW_HINT_CHANGED_NONE = 0, WM_WINDOW_HINT_CHANGED_NONE = 0,
WM_WINDOW_HINT_CHANGED_URGENT = 1u << 0, WM_WINDOW_HINT_CHANGED_URGENT = 1u << 0,
WM_WINDOW_HINT_CHANGED_FIXED_SIZE = 1u << 1, WM_WINDOW_HINT_CHANGED_FIXED_SIZE = 1u << 1,
WM_WINDOW_HINT_CHANGED_SKIP_TASKBAR = 1u << 2, WM_WINDOW_HINT_CHANGED_SKIP_TASKBAR = 1u << 2,
} wm_window_hint_changed_flags_t; } wm_window_hint_changed_flags_t;
@@ -149,9 +150,9 @@ typedef struct wm_window_hints_changed_event_t {
* - 2: pager / taskbar / window switcher 发起 * - 2: pager / taskbar / window switcher 发起
*/ */
typedef enum wm_window_activation_source_t { typedef enum wm_window_activation_source_t {
WM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0, WM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0,
WM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1, WM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1,
WM_WINDOW_ACTIVATION_SOURCE_PAGER = 2, WM_WINDOW_ACTIVATION_SOURCE_PAGER = 2,
} wm_window_activation_source_t; } wm_window_activation_source_t;
typedef struct wm_window_activate_request_event_t { typedef struct wm_window_activate_request_event_t {
@@ -183,10 +184,10 @@ typedef struct wm_window_state_request_event_t {
} wm_window_state_request_event_t; } wm_window_state_request_event_t;
typedef enum wm_configure_request_field_t { typedef enum wm_configure_request_field_t {
WM_CONFIGURE_REQUEST_FIELD_NONE = 0, WM_CONFIGURE_REQUEST_FIELD_NONE = 0,
WM_CONFIGURE_REQUEST_FIELD_X = 1u << 0, WM_CONFIGURE_REQUEST_FIELD_X = 1u << 0,
WM_CONFIGURE_REQUEST_FIELD_Y = 1u << 1, WM_CONFIGURE_REQUEST_FIELD_Y = 1u << 1,
WM_CONFIGURE_REQUEST_FIELD_WIDTH = 1u << 2, WM_CONFIGURE_REQUEST_FIELD_WIDTH = 1u << 2,
WM_CONFIGURE_REQUEST_FIELD_HEIGHT = 1u << 3, WM_CONFIGURE_REQUEST_FIELD_HEIGHT = 1u << 3,
} wm_configure_request_field_t; } wm_configure_request_field_t;

View File

@@ -27,8 +27,10 @@ typedef struct wm_layout_result_t {
size_t item_capacity; size_t item_capacity;
} wm_layout_result_t; } wm_layout_result_t;
typedef bool (*wm_layout_fn)(const wm_layout_ctx_t *ctx, typedef bool (*wm_layout_fn)(
wm_layout_result_t *out); const wm_layout_ctx_t *ctx,
wm_layout_result_t *out
);
typedef struct wm_layout_slot_t { typedef struct wm_layout_slot_t {
wm_layout_id_t id; wm_layout_id_t id;
@@ -67,17 +69,20 @@ bool wm_layout_result_push(wm_layout_result_t *result, wm_layout_item_t item);
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 *
const wm_layout_registry_t *registry, size_t index); wm_layout_registry_at(const wm_layout_registry_t *registry, size_t index);
wm_layout_id_t wm_layout_register(wm_layout_registry_t *registry, wm_layout_id_t wm_layout_register(
const char *name, const char *symbol, wm_layout_registry_t *registry,
wm_layout_fn fn); const char *name,
const char *symbol,
wm_layout_fn fn
);
/* /*
* layout registry 只允许在 bootstrap / 初始化阶段注册。 * layout registry 只允许在 bootstrap / 初始化阶段注册。
* 运行时布局集合保持固定,只允许切换 workspace 当前选中的 layout_id。 * 运行时布局集合保持固定,只允许切换 workspace 当前选中的 layout_id。
*/ */
wm_layout_fn wm_layout_lookup(const wm_layout_registry_t *registry, wm_layout_fn
wm_layout_id_t id); wm_layout_lookup(const wm_layout_registry_t *registry, wm_layout_id_t id);
const wm_layout_slot_t *wm_layout_slot_get(const wm_layout_registry_t *registry, const wm_layout_slot_t *
wm_layout_id_t id); wm_layout_slot_get(const wm_layout_registry_t *registry, wm_layout_id_t id);

View File

@@ -3,14 +3,14 @@
#include "wm_types.h" #include "wm_types.h"
typedef enum wm_dirty_flags_t { typedef enum wm_dirty_flags_t {
WM_DIRTY_NONE = 0, WM_DIRTY_NONE = 0,
WM_DIRTY_STATE = 1u << 0, WM_DIRTY_STATE = 1u << 0,
WM_DIRTY_LAYOUT = 1u << 1, WM_DIRTY_LAYOUT = 1u << 1,
WM_DIRTY_STACK = 1u << 2, WM_DIRTY_STACK = 1u << 2,
WM_DIRTY_OUTPUT = 1u << 3, WM_DIRTY_OUTPUT = 1u << 3,
// 只影响窗口装饰,不改变 layout 结果;例如焦点切换导致边框颜色变化 // 只影响窗口装饰,不改变 layout 结果;例如焦点切换导致边框颜色变化
WM_DIRTY_DECORATION = 1u << 4, WM_DIRTY_DECORATION = 1u << 4,
WM_DIRTY_RENDER = 1u << 5, WM_DIRTY_RENDER = 1u << 5,
} wm_dirty_flags_t; } wm_dirty_flags_t;
typedef enum wm_effect_type_t { typedef enum wm_effect_type_t {
@@ -36,8 +36,8 @@ typedef struct wm_effect_t {
struct { struct {
wm_window_id_t window_id; wm_window_id_t window_id;
wm_rect_t rect; // 最终外框矩形(包含边框) wm_rect_t rect; // 最终外框矩形(包含边框)
uint16_t border_width; // runtime 解析出的有效边框宽度 uint16_t border_width; // runtime 解析出的有效边框宽度
wm_rgba32_t border_rgba; // runtime 解析出的有效边框颜色 wm_rgba32_t border_rgba; // runtime 解析出的有效边框颜色
} configure_window; } configure_window;

View File

@@ -20,14 +20,19 @@ void wm_command_buffer_shutdown(wm_command_buffer_t *buffer);
bool wm_command_buffer_push(wm_command_buffer_t *buffer, wm_command_t command); bool wm_command_buffer_push(wm_command_buffer_t *buffer, wm_command_t command);
bool wm_policy_route_event(const wm_state_t *state, bool wm_policy_route_event(
const wm_policy_config_t *policy, const wm_state_t *state,
const wm_key_binding_table_t *keybindings, const wm_policy_config_t *policy,
const wm_pointer_binding_table_t *pointer_bindings, const wm_key_binding_table_t *keybindings,
const wm_event_t *event, const wm_pointer_binding_table_t *pointer_bindings,
wm_command_buffer_t *out); const wm_event_t *event,
wm_command_buffer_t *out
);
bool wm_policy_apply_command(wm_state_t *state, bool wm_policy_apply_command(
const wm_policy_config_t *policy, wm_state_t *state,
const wm_layout_registry_t *layouts, const wm_policy_config_t *policy,
const wm_command_t *command, wm_plan_t *plan); const wm_layout_registry_t *layouts,
const wm_command_t *command,
wm_plan_t *plan
);

View File

@@ -1,14 +1,15 @@
#pragma once #pragma once
#include "wm_binding.h" #include <stdint.h>
#include "wm_backend.h" #include "wm_backend.h"
#include "wm_binding.h"
#include "wm_layout.h" #include "wm_layout.h"
#include "wm_plan.h" #include "wm_plan.h"
#include "wm_policy_config.h"
#include "wm_policy.h" #include "wm_policy.h"
#include "wm_policy_config.h"
#include "wm_service.h" #include "wm_service.h"
#include "wm_state.h" #include "wm_state.h"
#include <stdint.h>
typedef enum wm_interaction_mode_t { typedef enum wm_interaction_mode_t {
WM_INTERACTION_NONE, WM_INTERACTION_NONE,
@@ -63,7 +64,8 @@ typedef struct wm_runtime_bootstrap_t {
/* /*
* 不可变键盘绑定表。 * 不可变键盘绑定表。
* 当前草案把它视为 bootstrap 提供的只读视图items 的生命周期必须覆盖 runtime。 * 当前草案把它视为 bootstrap 提供的只读视图items 的生命周期必须覆盖
* runtime。
*/ */
wm_key_binding_table_t keybindings; wm_key_binding_table_t keybindings;
@@ -115,8 +117,11 @@ typedef struct wm_runtime_t {
wm_service_registry_t services; wm_service_registry_t services;
} wm_runtime_t; } wm_runtime_t;
bool wm_runtime_init(wm_runtime_t *runtime, wm_backend_t backend, bool wm_runtime_init(
const wm_runtime_bootstrap_t *bootstrap); wm_runtime_t *runtime,
wm_backend_t backend,
const wm_runtime_bootstrap_t *bootstrap
);
bool wm_runtime_register_service(wm_runtime_t *runtime, wm_service_t service); bool wm_runtime_register_service(wm_runtime_t *runtime, wm_service_t service);
/* /*

View File

@@ -30,8 +30,11 @@ typedef struct wm_service_t wm_service_t;
typedef struct wm_service_api_t { typedef struct wm_service_api_t {
bool (*init)(wm_service_t *service); bool (*init)(wm_service_t *service);
void (*handle_event)(wm_service_t *service, const wm_service_event_t *event, void (*handle_event)(
const wm_state_t *state); wm_service_t *service,
const wm_service_event_t *event,
const wm_state_t *state
);
void (*shutdown)(wm_service_t *service); void (*shutdown)(wm_service_t *service);
} wm_service_api_t; } wm_service_api_t;
@@ -49,8 +52,12 @@ typedef struct wm_service_registry_t {
void wm_service_registry_init(wm_service_registry_t *registry); void wm_service_registry_init(wm_service_registry_t *registry);
void wm_service_registry_shutdown(wm_service_registry_t *registry); void wm_service_registry_shutdown(wm_service_registry_t *registry);
bool wm_service_registry_register(wm_service_registry_t *registry, bool wm_service_registry_register(
wm_service_t service); wm_service_registry_t *registry,
void wm_service_registry_emit(wm_service_registry_t *registry, wm_service_t service
const wm_service_event_t *event, );
const wm_state_t *state); void wm_service_registry_emit(
wm_service_registry_t *registry,
const wm_service_event_t *event,
const wm_state_t *state
);

View File

@@ -1,10 +1,11 @@
#pragma once #pragma once
#include "wm_types.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "wm_types.h"
// ========== 核心实体定义 ========== // ========== 核心实体定义 ==========
typedef struct wm_window_t { typedef struct wm_window_t {
@@ -19,8 +20,8 @@ typedef struct wm_window_t {
bool fixed_size; bool fixed_size;
// 几何信息(均为包含边框后的外框矩形) // 几何信息(均为包含边框后的外框矩形)
wm_rect_t float_rect; // floating 模式下记忆的外框矩形 wm_rect_t float_rect; // floating 模式下记忆的外框矩形
wm_rect_t frame_rect; // 当前最终外框矩形(由 layout 或 float_rect 解析) wm_rect_t frame_rect; // 当前最终外框矩形(由 layout 或 float_rect 解析)
// 元数据(核心算法不依赖,仅用于规则匹配和服务层展示) // 元数据(核心算法不依赖,仅用于规则匹配和服务层展示)
char *title; char *title;
@@ -34,8 +35,8 @@ typedef struct wm_window_t {
typedef struct wm_workspace_t { typedef struct wm_workspace_t {
wm_workspace_id_t id; wm_workspace_id_t id;
wm_output_id_t output_id; // 固定归属某个输出 wm_output_id_t output_id; // 固定归属某个输出
wm_layout_id_t layout_id; // 当前活动布局(可用布局列表中的一个) wm_layout_id_t layout_id; // 当前活动布局(可用布局列表中的一个)
wm_window_id_t focused_window_id; wm_window_id_t focused_window_id;
// 可用布局列表(启动时根据配置分配,之后固定不变) // 可用布局列表(启动时根据配置分配,之后固定不变)
@@ -48,8 +49,8 @@ typedef struct wm_workspace_t {
typedef struct wm_output_t { typedef struct wm_output_t {
wm_output_id_t id; wm_output_id_t id;
wm_rect_t geometry; // 输出完整几何bootstrap 后固定) wm_rect_t geometry; // 输出完整几何bootstrap 后固定)
wm_rect_t workarea; // 可用区域排除面板等bootstrap 后固定) wm_rect_t workarea; // 可用区域排除面板等bootstrap 后固定)
wm_workspace_id_t current_workspace_id; wm_workspace_id_t current_workspace_id;
} wm_output_t; } wm_output_t;
@@ -80,9 +81,11 @@ typedef struct wm_state_t {
// 初始化/清理 // 初始化/清理
// workspace/output 集合大小在 init 时一次性确定,之后不再变化。 // workspace/output 集合大小在 init 时一次性确定,之后不再变化。
void wm_state_init(wm_state_t *state, void wm_state_init(
size_t workspace_count, wm_state_t *state,
size_t output_count); size_t workspace_count,
size_t output_count
);
void wm_state_shutdown(wm_state_t *state); void wm_state_shutdown(wm_state_t *state);
// ========== Workspace 访问 ========== // ========== Workspace 访问 ==========
@@ -91,14 +94,18 @@ wm_workspace_t *wm_state_workspace(wm_state_t *state, wm_workspace_id_t id);
wm_workspace_t *wm_state_workspace_at(wm_state_t *state, size_t index); wm_workspace_t *wm_state_workspace_at(wm_state_t *state, size_t index);
size_t wm_state_workspace_count(const wm_state_t *state); size_t wm_state_workspace_count(const wm_state_t *state);
bool wm_state_workspace_valid(wm_state_t *state, wm_workspace_id_t id); bool wm_state_workspace_valid(wm_state_t *state, wm_workspace_id_t id);
void wm_state_workspace_set_focused_window(wm_state_t *state, void wm_state_workspace_set_focused_window(
wm_workspace_id_t workspace_id, wm_state_t *state,
wm_window_id_t window_id); wm_workspace_id_t workspace_id,
wm_window_id_t window_id
);
// 查询某个 output 的所有 workspace只读视图 // 查询某个 output 的所有 workspace只读视图
size_t wm_state_workspace_get_by_output(const wm_state_t *state, size_t wm_state_workspace_get_by_output(
wm_output_id_t output_id, const wm_state_t *state,
wm_workspace_t **out_workspaces); wm_output_id_t output_id,
wm_workspace_t **out_workspaces
);
// ========== Workspace 布局操作 ========== // ========== Workspace 布局操作 ==========
@@ -106,16 +113,18 @@ size_t wm_state_workspace_get_by_output(const wm_state_t *state,
* 设置 workspace 的可用布局列表。 * 设置 workspace 的可用布局列表。
* 仅允许在 bootstrap / 初始化阶段调用;运行时不应修改。 * 仅允许在 bootstrap / 初始化阶段调用;运行时不应修改。
*/ */
void wm_workspace_set_layouts(wm_workspace_t *workspace, void wm_workspace_set_layouts(
const wm_layout_id_t *layouts, wm_workspace_t *workspace,
size_t count); const wm_layout_id_t *layouts,
size_t count
);
/* /*
* 获取 workspace 的可用布局列表。 * 获取 workspace 的可用布局列表。
* 该列表在 bootstrap 完成后保持不变。 * 该列表在 bootstrap 完成后保持不变。
*/ */
const wm_layout_id_t *wm_workspace_get_layouts(const wm_workspace_t *workspace, const wm_layout_id_t *
size_t *out_count); wm_workspace_get_layouts(const wm_workspace_t *workspace, size_t *out_count);
/* /*
* 切换到下一个布局(循环) * 切换到下一个布局(循环)
@@ -130,7 +139,10 @@ bool wm_workspace_set_layout_by_index(wm_workspace_t *workspace, size_t index);
/* /*
* 切换到指定 ID 的布局(如果该布局在可用列表中) * 切换到指定 ID 的布局(如果该布局在可用列表中)
*/ */
bool wm_workspace_set_layout_by_id(wm_workspace_t *workspace, wm_layout_id_t id); bool wm_workspace_set_layout_by_id(
wm_workspace_t *workspace,
wm_layout_id_t id
);
// ========== Output 访问 ========== // ========== Output 访问 ==========
@@ -143,9 +155,11 @@ bool wm_state_output_valid(wm_state_t *state, wm_output_id_t id);
* 这不会修改 output 集合本身,也不会改变 workspace->output_id 绑定。 * 这不会修改 output 集合本身,也不会改变 workspace->output_id 绑定。
* 调用方必须保证目标 workspace 固定归属于该 output。 * 调用方必须保证目标 workspace 固定归属于该 output。
*/ */
void wm_state_output_set_current_workspace(wm_state_t *state, void wm_state_output_set_current_workspace(
wm_output_id_t output_id, wm_state_t *state,
wm_workspace_id_t workspace_id); wm_output_id_t output_id,
wm_workspace_id_t workspace_id
);
// ========== Window 操作 ========== // ========== Window 操作 ==========
@@ -154,43 +168,81 @@ wm_window_t *wm_state_window_get(wm_state_t *state, wm_window_id_t id);
wm_window_t *wm_state_window_at(wm_state_t *state, size_t index); wm_window_t *wm_state_window_at(wm_state_t *state, size_t index);
void wm_state_window_remove(wm_state_t *state, wm_window_id_t id); void wm_state_window_remove(wm_state_t *state, wm_window_id_t id);
size_t wm_state_window_count(const wm_state_t *state); size_t wm_state_window_count(const wm_state_t *state);
void wm_state_window_set_workspace(wm_state_t *state, wm_window_id_t window_id, void wm_state_window_set_workspace(
wm_workspace_id_t workspace_id); wm_state_t *state,
void wm_state_window_set_geometry_mode(wm_state_t *state, wm_window_id_t window_id,
wm_window_id_t window_id, wm_workspace_id_t workspace_id
wm_window_geometry_mode_t geometry_mode); );
void wm_state_window_set_floating(wm_state_t *state, wm_window_id_t window_id, void wm_state_window_set_geometry_mode(
bool floating); wm_state_t *state,
void wm_state_window_set_sticky(wm_state_t *state, wm_window_id_t window_id, wm_window_id_t window_id,
bool sticky); wm_window_geometry_mode_t geometry_mode
void wm_state_window_set_urgent(wm_state_t *state, wm_window_id_t window_id, );
bool urgent); void wm_state_window_set_floating(
void wm_state_window_set_fixed_size(wm_state_t *state, wm_state_t *state,
wm_window_id_t window_id, wm_window_id_t window_id,
bool fixed_size); bool floating
void wm_state_window_set_skip_taskbar(wm_state_t *state, );
wm_window_id_t window_id, void wm_state_window_set_sticky(
bool skip_taskbar); wm_state_t *state,
void wm_state_window_set_float_rect(wm_state_t *state, wm_window_id_t window_id, wm_window_id_t window_id,
wm_rect_t float_rect); bool sticky
void wm_state_window_set_frame_rect(wm_state_t *state, wm_window_id_t window_id, );
wm_rect_t frame_rect); void wm_state_window_set_urgent(
bool wm_state_window_set_title(wm_state_t *state, wm_window_id_t window_id, wm_state_t *state,
const char *title); wm_window_id_t window_id,
bool wm_state_window_set_app_id(wm_state_t *state, wm_window_id_t window_id, bool urgent
const char *app_id); );
bool wm_state_window_set_class(wm_state_t *state, wm_window_id_t window_id, void wm_state_window_set_fixed_size(
const char *class_name); wm_state_t *state,
bool wm_state_window_set_instance(wm_state_t *state, wm_window_id_t window_id, wm_window_id_t window_id,
const char *instance_name); bool fixed_size
);
void wm_state_window_set_skip_taskbar(
wm_state_t *state,
wm_window_id_t window_id,
bool skip_taskbar
);
void wm_state_window_set_float_rect(
wm_state_t *state,
wm_window_id_t window_id,
wm_rect_t float_rect
);
void wm_state_window_set_frame_rect(
wm_state_t *state,
wm_window_id_t window_id,
wm_rect_t frame_rect
);
bool wm_state_window_set_title(
wm_state_t *state,
wm_window_id_t window_id,
const char *title
);
bool wm_state_window_set_app_id(
wm_state_t *state,
wm_window_id_t window_id,
const char *app_id
);
bool wm_state_window_set_class(
wm_state_t *state,
wm_window_id_t window_id,
const char *class_name
);
bool wm_state_window_set_instance(
wm_state_t *state,
wm_window_id_t window_id,
const char *instance_name
);
// ========== 查询辅助函数 ========== // ========== 查询辅助函数 ==========
/* /*
* 判断工作区是否可见(某个 output 正在显示它) * 判断工作区是否可见(某个 output 正在显示它)
*/ */
bool wm_state_workspace_is_visible(const wm_state_t *state, bool wm_state_workspace_is_visible(
wm_workspace_id_t workspace_id); const wm_state_t *state,
wm_workspace_id_t workspace_id
);
/* /*
* 判断窗口是否可见 * 判断窗口是否可见
@@ -199,12 +251,16 @@ bool wm_state_workspace_is_visible(const wm_state_t *state,
* 2. 否则,窗口的 workspace 固定归属某个 output * 2. 否则,窗口的 workspace 固定归属某个 output
* 3. 且该 output 当前正显示这个 workspace * 3. 且该 output 当前正显示这个 workspace
*/ */
bool wm_state_window_should_be_visible(const wm_state_t *state, bool wm_state_window_should_be_visible(
const wm_window_t *window); const wm_state_t *state,
const wm_window_t *window
);
/* /*
* 判断窗口是否在特定 output 上可见 * 判断窗口是否在特定 output 上可见
*/ */
bool wm_state_window_should_be_visible_on_output(const wm_state_t *state, bool wm_state_window_should_be_visible_on_output(
const wm_window_t *window, const wm_state_t *state,
const wm_output_t *output); const wm_window_t *window,
const wm_output_t *output
);

View File

@@ -30,11 +30,11 @@ typedef uint32_t wm_modifier_mask_t;
typedef uint32_t wm_rgba32_t; typedef uint32_t wm_rgba32_t;
// 无效 ID 标记 // 无效 ID 标记
#define WM_WINDOW_ID_INVALID ((wm_window_id_t)0) #define WM_WINDOW_ID_INVALID ((wm_window_id_t)0)
#define WM_WORKSPACE_ID_INVALID ((wm_workspace_id_t)-1) #define WM_WORKSPACE_ID_INVALID ((wm_workspace_id_t) - 1)
#define WM_OUTPUT_ID_INVALID ((wm_output_id_t)-1) #define WM_OUTPUT_ID_INVALID ((wm_output_id_t) - 1)
#define WM_LAYOUT_ID_INVALID ((wm_layout_id_t)-1) #define WM_LAYOUT_ID_INVALID ((wm_layout_id_t) - 1)
#define WM_KEYSYM_INVALID ((wm_keysym_t)0) #define WM_KEYSYM_INVALID ((wm_keysym_t)0)
/* /*
* 归一化后的修饰键掩码: * 归一化后的修饰键掩码:
@@ -42,10 +42,10 @@ typedef uint32_t wm_rgba32_t;
* - CapsLock / NumLock 这类锁定位不应进入该掩码 * - CapsLock / NumLock 这类锁定位不应进入该掩码
*/ */
typedef enum wm_modifier_bit_t { typedef enum wm_modifier_bit_t {
WM_MOD_NONE = 0, WM_MOD_NONE = 0,
WM_MOD_SHIFT = 1u << 0, WM_MOD_SHIFT = 1u << 0,
WM_MOD_CTRL = 1u << 1, WM_MOD_CTRL = 1u << 1,
WM_MOD_ALT = 1u << 2, WM_MOD_ALT = 1u << 2,
WM_MOD_SUPER = 1u << 3, WM_MOD_SUPER = 1u << 3,
} wm_modifier_bit_t; } wm_modifier_bit_t;

View File

@@ -35,10 +35,13 @@ typedef struct zdwm_api_t {
* @returns 返回布局算法对应的布局 id ,如果注册失败,返回 * @returns 返回布局算法对应的布局 id ,如果注册失败,返回
* ZDWM_LAYOUT_ID_INVALID * ZDWM_LAYOUT_ID_INVALID
*/ */
zdwm_layout_id_t (*register_layout)(zdwm_config_builder_t *builder, zdwm_layout_id_t (*register_layout)(
const char *name, const char *symbol, zdwm_config_builder_t *builder,
const char *description, const char *name,
zdwm_layout_fn fn); const char *symbol,
const char *description,
zdwm_layout_fn fn
);
/** /**
* 用户调用这个函数添加 output 中的工作空间 * 用户调用这个函数添加 output 中的工作空间
@@ -50,11 +53,14 @@ typedef struct zdwm_api_t {
* @param initial_layout_id 初始布局算法 id * @param initial_layout_id 初始布局算法 id
* @returns 返回工作空间 id 。如果注册失败,返回 ZDWM_WORKSPACE_ID_INVALID * @returns 返回工作空间 id 。如果注册失败,返回 ZDWM_WORKSPACE_ID_INVALID
*/ */
zdwm_workspace_id_t (*define_workspace)(zdwm_config_builder_t *builder, zdwm_workspace_id_t (*define_workspace)(
size_t output_index, const char *name, zdwm_config_builder_t *builder,
const zdwm_layout_id_t *layout_ids, size_t output_index,
size_t layout_count, const char *name,
zdwm_layout_id_t initial_layout_id); const zdwm_layout_id_t *layout_ids,
size_t layout_count,
zdwm_layout_id_t initial_layout_id
);
/** /**
* 用户调用这个函数添加窗口规则 * 用户调用这个函数添加窗口规则
@@ -65,9 +71,11 @@ typedef struct zdwm_api_t {
* @details 不合法的情况match 所有字段全为 nullptr * @details 不合法的情况match 所有字段全为 nullptr
* 或 action 无任何动作;或 action 指定的 workspace 不存在 * 或 action 无任何动作;或 action 指定的 workspace 不存在
*/ */
bool (*add_rule)(zdwm_config_builder_t *builder, bool (*add_rule)(
const zdwm_rule_match_t *match, zdwm_config_builder_t *builder,
const zdwm_rule_action_t *action); const zdwm_rule_match_t *match,
const zdwm_rule_action_t *action
);
} zdwm_api_t; } zdwm_api_t;
/** /**
@@ -79,10 +87,12 @@ typedef struct zdwm_api_t {
* @param output_count 屏幕个数 * @param output_count 屏幕个数
* @returns 用户配置成功返回 true ,配置失败返回 false * @returns 用户配置成功返回 true ,配置失败返回 false
*/ */
typedef bool zdwm_config_setup_fn(const zdwm_api_t *api, typedef bool zdwm_config_setup_fn(
zdwm_config_builder_t *builder, const zdwm_api_t *api,
const zdwm_output_info_t *outputs, zdwm_config_builder_t *builder,
size_t output_count); const zdwm_output_info_t *outputs,
size_t output_count
);
/* 用户在自己的动态链接库配置中必须实现该函数 */ /* 用户在自己的动态链接库配置中必须实现该函数 */
extern zdwm_config_setup_fn setup; extern zdwm_config_setup_fn setup;

View File

@@ -30,16 +30,18 @@ typedef struct zdwm_layout_result_t {
size_t item_capacity; size_t item_capacity;
} zdwm_layout_result_t; } zdwm_layout_result_t;
typedef bool (*zdwm_layout_fn)(const zdwm_layout_ctx_t *ctx, typedef bool (*zdwm_layout_fn)(
zdwm_layout_result_t *out); const zdwm_layout_ctx_t *ctx,
zdwm_layout_result_t *out
);
static inline void zdwm_layout_result_reset(zdwm_layout_result_t *result) { static inline void zdwm_layout_result_reset(zdwm_layout_result_t *result) {
if (!result) abort(); if (!result) abort();
result->item_count = 0; result->item_count = 0;
} }
static inline void zdwm_layout_result_push(zdwm_layout_result_t *result, static inline void
zdwm_layout_item_t item) { zdwm_layout_result_push(zdwm_layout_result_t *result, zdwm_layout_item_t item) {
if (!result) abort(); if (!result) abort();
if (result->item_count == result->item_capacity) { if (result->item_count == result->item_capacity) {
@@ -47,7 +49,8 @@ static inline void zdwm_layout_result_push(zdwm_layout_result_t *result,
zdwm_layout_item_t *items = zdwm_layout_item_t *items =
realloc(result->items, capacity * sizeof(*result->items)); realloc(result->items, capacity * sizeof(*result->items));
if (!items) abort(); if (!items) abort();
result->items = items;
result->items = items;
result->item_capacity = capacity; result->item_capacity = capacity;
} }

View File

@@ -11,11 +11,9 @@ typedef uint32_t zdwm_layout_id_t;
typedef uint32_t zdwm_window_id_t; typedef uint32_t zdwm_window_id_t;
typedef uint32_t zdwm_workspace_id_t; typedef uint32_t zdwm_workspace_id_t;
/* clang-format off */ #define ZDWM_LAYOUT_ID_INVALID ((zdwm_layout_id_t)UINT32_MAX)
#define ZDWM_LAYOUT_ID_INVALID ((zdwm_layout_id_t)UINT32_MAX) #define ZDWM_WINDOW_ID_INVALID ((zdwm_window_id_t)0)
#define ZDWM_WINDOW_ID_INVALID ((zdwm_window_id_t)0) #define ZDWM_WORKSPACE_ID_INVALID ((zdwm_workspace_id_t)UINT32_MAX)
#define ZDWM_WORKSPACE_ID_INVALID ((zdwm_workspace_id_t)UINT32_MAX)
/* clang-format on */
typedef struct zdwm_rect_t { typedef struct zdwm_rect_t {
int32_t x; int32_t x;

16
src/.clang-format Normal file
View File

@@ -0,0 +1,16 @@
# -*- mode: yaml; -*-
---
BasedOnStyle: Google
IndentWidth: 2
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
---
Language: C
DerivePointerAlignment: false
PointerAlignment: Right
---
Language: Cpp
DerivePointerAlignment: false
PointerAlignment: Right
---

View File

@@ -78,9 +78,9 @@ void raise_or_run(const user_action_arg_t *arg) {
bool monitor_changed = client->monitor != wm.current_monitor; bool monitor_changed = client->monitor != wm.current_monitor;
bool tag_changed = client->tags != client->monitor->selected_tag->mask; bool tag_changed = client->tags != client->monitor->selected_tag->mask;
if (monitor_changed || tag_changed) { if (monitor_changed || tag_changed) {
point_t point = monitor_changed ? monitor_get_restore_cursor_point( point_t point = monitor_changed
client->monitor) ? monitor_get_restore_cursor_point(client->monitor)
: xcursor_query_pointer_position(); : xcursor_query_pointer_position();
wm_ignore_enter_notify_at_point(point); wm_ignore_enter_notify_at_point(point);
} }
wm_set_current_monitor(client->monitor, true); wm_set_current_monitor(client->monitor, true);

1
src/backend/.clang-format Symbolic link
View File

@@ -0,0 +1 @@
../../.clang-format

View File

@@ -14,8 +14,8 @@ static inline bool fully_contains(rect_t outer, rect_t inner) {
right(inner) <= right(outer) && bottom(inner) <= bottom(outer); right(inner) <= right(outer) && bottom(inner) <= bottom(outer);
} }
backend_detect_t *output_remove_duplication(const output_info_t *output, backend_detect_t *
const size_t count) { output_remove_duplication(const output_info_t *output, const size_t count) {
if (!output || count < 1) return nullptr; if (!output || count < 1) return nullptr;
bool *remove = p_new(bool, count); bool *remove = p_new(bool, count);
@@ -42,14 +42,14 @@ backend_detect_t *output_remove_duplication(const output_info_t *output,
} }
output_info_t *list = p_new(output_info_t, amount); output_info_t *list = p_new(output_info_t, amount);
amount = 0; amount = 0;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
if (remove[i]) continue; if (remove[i]) continue;
list[amount++] = output[i]; list[amount++] = output[i];
} }
p_delete(&remove); p_delete(&remove);
backend_detect_t *detect = p_new(backend_detect_t, 1); backend_detect_t *detect = p_new(backend_detect_t, 1);
detect->outputs = list; detect->outputs = list;
detect->output_count = amount; detect->output_count = amount;
return detect; return detect;
} }

View File

@@ -5,5 +5,5 @@
#include "core/backend.h" #include "core/backend.h"
#include "core/types.h" #include "core/types.h"
backend_detect_t *output_remove_duplication(const output_info_t *output, backend_detect_t *
const size_t count); output_remove_duplication(const output_info_t *output, const size_t count);

View File

@@ -16,7 +16,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/types.h" #include "core/types.h"
#include "internal.h" /* IWYU pragma: keep */ #include "internal.h"
typedef struct atom_item_t { typedef struct atom_item_t {
const char *name; const char *name;
@@ -26,66 +26,11 @@ typedef struct atom_item_t {
static void atoms_init(backend_t *backend) { static void atoms_init(backend_t *backend) {
xcb_connection_t *conn = backend->conn; xcb_connection_t *conn = backend->conn;
atoms_t *atoms = &backend->atoms; atoms_t *atoms = &backend->atoms;
atom_item_t atom_list[] = { #define ATOM_ITEM(name) {#name, sizeof(#name) - 1, &atoms->name},
{"COMPOUND_TEXT", sizeof("COMPOUND_TEXT") - 1, &atoms->COMPOUND_TEXT}, atom_item_t atom_list[] = {ATOM_LIST(ATOM_ITEM)};
{"UTF8_STRING", sizeof("UTF8_STRING") - 1, &atoms->UTF8_STRING}, #undef ATOM_ITEM
{"WM_WINDOW_ROLE", sizeof("WM_WINDOW_ROLE") - 1, &atoms->WM_WINDOW_ROLE},
{"WM_NAME", sizeof("WM_NAME") - 1, &atoms->WM_NAME},
{"_NET_WM_NAME", sizeof("_NET_WM_NAME") - 1, &atoms->_NET_WM_NAME},
{"_NET_WM_STATE", sizeof("_NET_WM_STATE") - 1, &atoms->_NET_WM_STATE},
{"_NET_WM_STATE_FULLSCREEN", sizeof("_NET_WM_STATE_FULLSCREEN") - 1,
&atoms->_NET_WM_STATE_FULLSCREEN},
{"_NET_WM_STATE_ABOVE", sizeof("_NET_WM_STATE_ABOVE") - 1,
&atoms->_NET_WM_STATE_ABOVE},
{"_NET_WM_STATE_STICKY", sizeof("_NET_WM_STATE_STICKY") - 1,
&atoms->_NET_WM_STATE_STICKY},
{"_NET_WM_STATE_MODAL", sizeof("_NET_WM_STATE_MODAL") - 1,
&atoms->_NET_WM_STATE_MODAL},
{"_NET_WM_STATE_SKIP_TASKBAR", sizeof("_NET_WM_STATE_SKIP_TASKBAR") - 1,
&atoms->_NET_WM_STATE_SKIP_TASKBAR},
{"_NET_WM_STATE_MAXIMIZED_VERT", sizeof("_NET_WM_STATE_MAXIMIZED_VERT") - 1,
&atoms->_NET_WM_STATE_MAXIMIZED_VERT},
{"_NET_WM_STATE_MAXIMIZED_HORZ", sizeof("_NET_WM_STATE_MAXIMIZED_HORZ") - 1,
&atoms->_NET_WM_STATE_MAXIMIZED_HORZ},
{"_NET_WM_WINDOW_TYPE", sizeof("_NET_WM_WINDOW_TYPE") - 1,
&atoms->_NET_WM_WINDOW_TYPE},
{"_NET_WM_WINDOW_TYPE_NORMAL", sizeof("_NET_WM_WINDOW_TYPE_NORMAL") - 1,
&atoms->_NET_WM_WINDOW_TYPE_NORMAL},
{"_NET_WM_WINDOW_TYPE_DESKTOP", sizeof("_NET_WM_WINDOW_TYPE_DESKTOP") - 1,
&atoms->_NET_WM_WINDOW_TYPE_DESKTOP},
{"_NET_WM_WINDOW_TYPE_DOCK", sizeof("_NET_WM_WINDOW_TYPE_DOCK") - 1,
&atoms->_NET_WM_WINDOW_TYPE_DOCK},
{"_NET_WM_WINDOW_TYPE_TOOLBAR", sizeof("_NET_WM_WINDOW_TYPE_TOOLBAR") - 1,
&atoms->_NET_WM_WINDOW_TYPE_TOOLBAR},
{"_NET_WM_WINDOW_TYPE_DIALOG", sizeof("_NET_WM_WINDOW_TYPE_DIALOG") - 1,
&atoms->_NET_WM_WINDOW_TYPE_DIALOG},
{"_NET_WM_WINDOW_TYPE_UTILITY", sizeof("_NET_WM_WINDOW_TYPE_UTILITY") - 1,
&atoms->_NET_WM_WINDOW_TYPE_UTILITY},
{"_NET_WM_WINDOW_TYPE_SPLASH", sizeof("_NET_WM_WINDOW_TYPE_SPLASH") - 1,
&atoms->_NET_WM_WINDOW_TYPE_SPLASH},
{"_NET_WM_WINDOW_TYPE_MENU", sizeof("_NET_WM_WINDOW_TYPE_MENU") - 1,
&atoms->_NET_WM_WINDOW_TYPE_MENU},
{"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
sizeof("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU") - 1,
&atoms->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU},
{"_NET_WM_WINDOW_TYPE_POPUP_MENU",
sizeof("_NET_WM_WINDOW_TYPE_POPUP_MENU") - 1,
&atoms->_NET_WM_WINDOW_TYPE_POPUP_MENU},
{"_NET_WM_WINDOW_TYPE_TOOLTIP", sizeof("_NET_WM_WINDOW_TYPE_TOOLTIP") - 1,
&atoms->_NET_WM_WINDOW_TYPE_TOOLTIP},
{"_NET_WM_WINDOW_TYPE_COMBO", sizeof("_NET_WM_WINDOW_TYPE_COMBO") - 1,
&atoms->_NET_WM_WINDOW_TYPE_COMBO},
{"_NET_WM_WINDOW_TYPE_DND", sizeof("_NET_WM_WINDOW_TYPE_DND") - 1,
&atoms->_NET_WM_WINDOW_TYPE_DND},
{"_NET_WM_WINDOW_TYPE_NOTIFICATION",
sizeof("_NET_WM_WINDOW_TYPE_NOTIFICATION") - 1,
&atoms->_NET_WM_WINDOW_TYPE_NOTIFICATION},
};
xcb_intern_atom_cookie_t cookies[countof(atom_list)]; xcb_intern_atom_cookie_t cookies[countof(atom_list)];
for (size_t i = 0; i < countof(atom_list); ++i) { for (size_t i = 0; i < countof(atom_list); ++i) {
@@ -99,15 +44,15 @@ static void atoms_init(backend_t *backend) {
if (!reply) continue; if (!reply) continue;
atom_item_t *atom = &atom_list[i]; atom_item_t *atom = &atom_list[i];
*atom->atom = reply->atom; *atom->atom = reply->atom;
p_delete(&reply); p_delete(&reply);
} }
} }
backend_t *backend_create(const char *display_name) { backend_t *backend_create(const char *display_name) {
int screen_num = 0; int screen_num = 0;
xcb_connection_t *conn = xcb_connect(display_name, &screen_num); xcb_connection_t *conn = xcb_connect(display_name, &screen_num);
int xcb_conn_error = xcb_connection_has_error(conn); int xcb_conn_error = xcb_connection_has_error(conn);
if (xcb_conn_error) { if (xcb_conn_error) {
fatal("cannot open display %s, error %d", display_name, xcb_conn_error); fatal("cannot open display %s, error %d", display_name, xcb_conn_error);
} }
@@ -116,7 +61,7 @@ backend_t *backend_create(const char *display_name) {
if (!screen) fatal("cannot get screen info"); if (!screen) fatal("cannot get screen info");
xcb_window_t root = screen->root; xcb_window_t root = screen->root;
uint32_t mask = XCB_CW_EVENT_MASK; uint32_t mask = XCB_CW_EVENT_MASK;
const xcb_params_cw_t params = { const xcb_params_cw_t params = {
.event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, .event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
}; };
@@ -125,20 +70,24 @@ backend_t *backend_create(const char *display_name) {
if (xcb_request_check(conn, cookie)) { if (xcb_request_check(conn, cookie)) {
fatal( fatal(
"another window manager is already running (cannot select " "another window manager is already running (cannot select "
"SubstructureRedirect)"); "SubstructureRedirect)"
);
} }
backend_t *backend = p_new(backend_t, 1); backend_t *backend = p_new(backend_t, 1);
backend->conn = conn; backend->conn = conn;
backend->screen = screen; backend->screen = screen;
backend->screenp = screen_num; backend->screenp = screen_num;
xcb_prefetch_extension_data(conn, &xcb_xfixes_id); xcb_prefetch_extension_data(conn, &xcb_xfixes_id);
const xcb_query_extension_reply_t *query = const xcb_query_extension_reply_t *query =
xcb_get_extension_data(conn, &xcb_xfixes_id); xcb_get_extension_data(conn, &xcb_xfixes_id);
if (query && query->present) { if (query && query->present) {
xcb_xfixes_query_version_cookie_t cookie = xcb_xfixes_query_version( xcb_xfixes_query_version_cookie_t cookie = xcb_xfixes_query_version(
conn, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); conn,
XCB_XFIXES_MAJOR_VERSION,
XCB_XFIXES_MINOR_VERSION
);
xcb_xfixes_query_version_reply_t *reply = xcb_xfixes_query_version_reply_t *reply =
xcb_xfixes_query_version_reply(conn, cookie, nullptr); xcb_xfixes_query_version_reply(conn, cookie, nullptr);
@@ -163,15 +112,21 @@ void backend_destroy(backend_t *backend) {
free(backend); free(backend);
} }
static bool detect_monitor_by_randr(const backend_t *backend, static bool detect_monitor_by_randr(
output_info_t **outputs, size_t *count) { const backend_t *backend,
output_info_t **outputs,
size_t *count
) {
xcb_prefetch_extension_data(backend->conn, &xcb_randr_id); xcb_prefetch_extension_data(backend->conn, &xcb_randr_id);
const xcb_query_extension_reply_t *query = const xcb_query_extension_reply_t *query =
xcb_get_extension_data(backend->conn, &xcb_randr_id); xcb_get_extension_data(backend->conn, &xcb_randr_id);
if (!query || !query->present) return false; if (!query || !query->present) return false;
xcb_randr_query_version_cookie_t cookie = xcb_randr_query_version( xcb_randr_query_version_cookie_t cookie = xcb_randr_query_version(
backend->conn, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION); backend->conn,
XCB_RANDR_MAJOR_VERSION,
XCB_RANDR_MINOR_VERSION
);
xcb_randr_query_version_reply_t *reply = xcb_randr_query_version_reply_t *reply =
xcb_randr_query_version_reply(backend->conn, cookie, nullptr); xcb_randr_query_version_reply(backend->conn, cookie, nullptr);
if (!reply) return false; if (!reply) return false;
@@ -204,10 +159,10 @@ static bool detect_monitor_by_randr(const backend_t *backend,
xcb_randr_monitor_info_iterator_t iter = xcb_randr_monitor_info_iterator_t iter =
xcb_randr_get_monitors_monitors_iterator(monitors_reply); xcb_randr_get_monitors_monitors_iterator(monitors_reply);
for (int i = 0; iter.rem; xcb_randr_monitor_info_next(&iter), i++) { for (int i = 0; iter.rem; xcb_randr_monitor_info_next(&iter), i++) {
output_info_t *output = &output_list[i]; output_info_t *output = &output_list[i];
output->geometry.x = iter.data->x; output->geometry.x = iter.data->x;
output->geometry.y = iter.data->y; output->geometry.y = iter.data->y;
output->geometry.width = iter.data->width; output->geometry.width = iter.data->width;
output->geometry.height = iter.data->height; output->geometry.height = iter.data->height;
xcb_get_atom_name_cookie_t name_cookie = xcb_get_atom_name_cookie_t name_cookie =
@@ -216,8 +171,8 @@ static bool detect_monitor_by_randr(const backend_t *backend,
xcb_get_atom_name_reply(backend->conn, name_cookie, nullptr); xcb_get_atom_name_reply(backend->conn, name_cookie, nullptr);
if (name_reply) { if (name_reply) {
char *name = xcb_get_atom_name_name(name_reply); char *name = xcb_get_atom_name_name(name_reply);
int length = xcb_get_atom_name_name_length(name_reply); int length = xcb_get_atom_name_name_length(name_reply);
output->name = p_strndup(name, length); output->name = p_strndup(name, length);
p_delete(&name_reply); p_delete(&name_reply);
} }
@@ -236,15 +191,21 @@ static bool detect_monitor_by_randr(const backend_t *backend,
return true; return true;
} }
static bool detect_monitor_by_xinerama(const backend_t *backend, static bool detect_monitor_by_xinerama(
output_info_t **outputs, size_t *count) { const backend_t *backend,
output_info_t **outputs,
size_t *count
) {
xcb_prefetch_extension_data(backend->conn, &xcb_xinerama_id); xcb_prefetch_extension_data(backend->conn, &xcb_xinerama_id);
const xcb_query_extension_reply_t *query = const xcb_query_extension_reply_t *query =
xcb_get_extension_data(backend->conn, &xcb_xinerama_id); xcb_get_extension_data(backend->conn, &xcb_xinerama_id);
if (!query || !query->present) return false; if (!query || !query->present) return false;
xcb_xinerama_query_version_cookie_t cookie = xcb_xinerama_query_version( xcb_xinerama_query_version_cookie_t cookie = xcb_xinerama_query_version(
backend->conn, XCB_XINERAMA_MAJOR_VERSION, XCB_XINERAMA_MINOR_VERSION); backend->conn,
XCB_XINERAMA_MAJOR_VERSION,
XCB_XINERAMA_MINOR_VERSION
);
xcb_xinerama_query_version_reply_t *version_reply = xcb_xinerama_query_version_reply_t *version_reply =
xcb_xinerama_query_version_reply(backend->conn, cookie, nullptr); xcb_xinerama_query_version_reply(backend->conn, cookie, nullptr);
if (!version_reply) return false; if (!version_reply) return false;
@@ -280,10 +241,10 @@ static bool detect_monitor_by_xinerama(const backend_t *backend,
output_info_t *output_list = p_new(output_info_t, len); output_info_t *output_list = p_new(output_info_t, len);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
output_info_t *output = &output_list[i]; output_info_t *output = &output_list[i];
output->geometry.x = screen_info[i].x_org; output->geometry.x = screen_info[i].x_org;
output->geometry.y = screen_info[i].y_org; output->geometry.y = screen_info[i].y_org;
output->geometry.width = screen_info[i].width; output->geometry.width = screen_info[i].width;
output->geometry.height = screen_info[i].height; output->geometry.height = screen_info[i].height;
} }
p_delete(&screens_reply); p_delete(&screens_reply);
@@ -301,7 +262,7 @@ static bool detect_monitor_by_xinerama(const backend_t *backend,
backend_detect_t *backend_detect(backend_t *backend) { backend_detect_t *backend_detect(backend_t *backend) {
output_info_t *outputs = nullptr; output_info_t *outputs = nullptr;
size_t count = 0; size_t count = 0;
if (detect_monitor_by_randr(backend, &outputs, &count)) { if (detect_monitor_by_randr(backend, &outputs, &count)) {
backend_detect_t *detect = output_remove_duplication(outputs, count); backend_detect_t *detect = output_remove_duplication(outputs, count);
@@ -315,15 +276,15 @@ backend_detect_t *backend_detect(backend_t *backend) {
return detect; return detect;
} }
output_info_t *output = p_new(output_info_t, 1); output_info_t *output = p_new(output_info_t, 1);
output->geometry.x = 0; output->geometry.x = 0;
output->geometry.y = 0; output->geometry.y = 0;
output->geometry.width = backend->screen->width_in_pixels; output->geometry.width = backend->screen->width_in_pixels;
output->geometry.height = backend->screen->height_in_pixels; output->geometry.height = backend->screen->height_in_pixels;
backend_detect_t *detect = p_new(backend_detect_t, 1); backend_detect_t *detect = p_new(backend_detect_t, 1);
detect->outputs = output; detect->outputs = output;
detect->output_count = 1; detect->output_count = 1;
return detect; return detect;
} }
@@ -338,8 +299,11 @@ void backend_detect_destroy(backend_detect_t *detect) {
free(detect); free(detect);
} }
bool backend_apply_effect(backend_t *backend, const effect_t *effects, bool backend_apply_effect(
size_t effect_count) { backend_t *backend,
const effect_t *effects,
size_t effect_count
) {
/* TODO: */ /* TODO: */
return true; return true;
} }

View File

@@ -11,17 +11,20 @@
#include "core/backend.h" #include "core/backend.h"
#include "core/types.h" #include "core/types.h"
#include "core/window.h" #include "core/window.h"
#include "internal.h" /* IWYU pragma: keep */ #include "internal.h"
static window_state_t *derive_window_states(const atoms_t *atoms, static window_state_t *derive_window_states(
const xcb_atom_t *raw, const atoms_t *atoms,
uint32_t count, size_t *out_count) { const xcb_atom_t *raw,
uint32_t count,
size_t *out_count
) {
if (!raw || count == 0) { if (!raw || count == 0) {
*out_count = 0; *out_count = 0;
return nullptr; return nullptr;
} }
window_state_t *buf = p_new(window_state_t, count); window_state_t *buf = p_new(window_state_t, count);
size_t valid = 0; size_t valid = 0;
for (uint32_t i = 0; i < count; i++) { for (uint32_t i = 0; i < count; i++) {
window_state_t s = atom_to_window_state(atoms, raw[i]); window_state_t s = atom_to_window_state(atoms, raw[i]);
if (s != (window_state_t)-1) buf[valid++] = s; if (s != (window_state_t)-1) buf[valid++] = s;
@@ -35,22 +38,29 @@ static window_state_t *derive_window_states(const atoms_t *atoms,
return buf; return buf;
} }
static bool derive_skip_taskbar(const atoms_t *atoms, const xcb_atom_t *raw, static bool derive_skip_taskbar(
uint32_t count) { const atoms_t *atoms,
const xcb_atom_t *raw,
uint32_t count
) {
for (uint32_t i = 0; i < count; i++) for (uint32_t i = 0; i < count; i++)
if (raw[i] == atoms->_NET_WM_STATE_SKIP_TASKBAR) return true; if (raw[i] == atoms->_NET_WM_STATE_SKIP_TASKBAR) return true;
return false; return false;
} }
static window_geometry_mode_t geometry_mode_from_hints( static window_geometry_mode_t geometry_mode_from_hints(
const xcb_icccm_wm_hints_t *hints) { const xcb_icccm_wm_hints_t *hints
) {
if (hints->initial_state == XCB_ICCCM_WM_STATE_ICONIC) if (hints->initial_state == XCB_ICCCM_WM_STATE_ICONIC)
return ZDWM_GEOMETRY_MINIMIZED; return ZDWM_GEOMETRY_MINIMIZED;
return ZDWM_GEOMETRY_NORMAL; return ZDWM_GEOMETRY_NORMAL;
} }
static window_geometry_mode_t geometry_mode_from_states( static window_geometry_mode_t geometry_mode_from_states(
const atoms_t *atoms, const xcb_atom_t *state_atoms, uint32_t state_count) { const atoms_t *atoms,
const xcb_atom_t *state_atoms,
uint32_t state_count
) {
for (uint32_t i = 0; i < state_count; i++) { for (uint32_t i = 0; i < state_count; i++) {
if (state_atoms[i] == atoms->_NET_WM_STATE_FULLSCREEN) if (state_atoms[i] == atoms->_NET_WM_STATE_FULLSCREEN)
return ZDWM_GEOMETRY_FULLSCREEN; return ZDWM_GEOMETRY_FULLSCREEN;
@@ -61,17 +71,20 @@ static window_geometry_mode_t geometry_mode_from_states(
return ZDWM_GEOMETRY_NORMAL; return ZDWM_GEOMETRY_NORMAL;
} }
static bool handle_map_request(backend_t *backend, event_t *event, static bool handle_map_request(
const xcb_map_request_event_t *xcb_event) { backend_t *backend,
event_t *event,
const xcb_map_request_event_t *xcb_event
) {
xcb_window_t window = xcb_event->window; xcb_window_t window = xcb_event->window;
event_reset(event); event_reset(event);
event->type = ZDWM_EVENT_WINDOW_MAP_REQUEST; event->type = ZDWM_EVENT_WINDOW_MAP_REQUEST;
window_map_request_event_t *ev = &event->as.window_map_request; window_map_request_event_t *ev = &event->as.window_map_request;
ev->window = (window_id_t)window; ev->window = (window_id_t)window;
ev->transient_for = window_get_transient_for(backend, window); ev->transient_for = window_get_transient_for(backend, window);
ev->geometry_mode = ZDWM_GEOMETRY_NORMAL; ev->geometry_mode = ZDWM_GEOMETRY_NORMAL;
xcb_get_window_attributes_reply_t *wa = xcb_get_window_attributes_reply_t *wa =
window_get_attributes(backend, window); window_get_attributes(backend, window);
@@ -81,18 +94,23 @@ static bool handle_map_request(backend_t *backend, event_t *event,
xcb_icccm_wm_hints_t wm_hints = {0}; xcb_icccm_wm_hints_t wm_hints = {0};
if (window_get_wm_hints(backend, window, &wm_hints)) { if (window_get_wm_hints(backend, window, &wm_hints)) {
ev->urgent = (bool)xcb_icccm_wm_hints_get_urgency(&wm_hints); ev->urgent = (bool)xcb_icccm_wm_hints_get_urgency(&wm_hints);
ev->geometry_mode = geometry_mode_from_hints(&wm_hints); ev->geometry_mode = geometry_mode_from_hints(&wm_hints);
} }
if (!window_get_fixed_size(backend, window, &ev->fixed_size)) return false; if (!window_get_fixed_size(backend, window, &ev->fixed_size)) return false;
if (!window_get_geometry(backend, window, &ev->rect)) return false; if (!window_get_geometry(backend, window, &ev->rect)) return false;
const atoms_t *atoms = &backend->atoms; const atoms_t *atoms = &backend->atoms;
xcb_atom_t *state_atoms = nullptr; xcb_atom_t *state_atoms = nullptr;
uint32_t state_count = 0; uint32_t state_count = 0;
if (!window_get_atom_array(backend, window, atoms->_NET_WM_STATE, if (!window_get_atom_array(
&state_atoms, &state_count)) { backend,
window,
atoms->_NET_WM_STATE,
&state_atoms,
&state_count
)) {
return false; return false;
} }
@@ -103,8 +121,12 @@ static bool handle_map_request(backend_t *backend, event_t *event,
if (state_atoms) { if (state_atoms) {
ev->skip_taskbar = derive_skip_taskbar(atoms, state_atoms, state_count); ev->skip_taskbar = derive_skip_taskbar(atoms, state_atoms, state_count);
ev->props.states = derive_window_states(atoms, state_atoms, state_count, ev->props.states = derive_window_states(
&ev->props.state_count); atoms,
state_atoms,
state_count,
&ev->props.state_count
);
} }
p_delete(&state_atoms); p_delete(&state_atoms);
@@ -115,24 +137,34 @@ static bool handle_map_request(backend_t *backend, event_t *event,
return false; return false;
} }
ev->metadata.role = window_get_role(backend, window); ev->metadata.role = window_get_role(backend, window);
ev->metadata.title = window_get_title(backend, window); ev->metadata.title = window_get_title(backend, window);
window_get_class(backend, window, &ev->metadata.class_name, window_get_class(
&ev->metadata.instance_name); backend,
window,
&ev->metadata.class_name,
&ev->metadata.instance_name
);
return true; return true;
} }
static bool handle_unmap_notify(backend_t *backend, event_t *event, static bool handle_unmap_notify(
const xcb_unmap_notify_event_t *xcb_event) { backend_t *backend,
event_t *event,
const xcb_unmap_notify_event_t *xcb_event
) {
event_reset(event); event_reset(event);
event->type = ZDWM_EVENT_WINDOW_REMOVE; event->type = ZDWM_EVENT_WINDOW_REMOVE;
/* TODO: */ /* TODO: */
return true; return true;
} }
static bool handle_destroy_notify(backend_t *backend, event_t *event, static bool handle_destroy_notify(
const xcb_destroy_notify_event_t *xcb_event) { backend_t *backend,
event_t *event,
const xcb_destroy_notify_event_t *xcb_event
) {
event_reset(event); event_reset(event);
event->type = ZDWM_EVENT_WINDOW_REMOVE; event->type = ZDWM_EVENT_WINDOW_REMOVE;
/* TODO: */ /* TODO: */
@@ -140,8 +172,10 @@ static bool handle_destroy_notify(backend_t *backend, event_t *event,
} }
static bool handle_configure_request( static bool handle_configure_request(
backend_t *backend, event_t *event, backend_t *backend,
const xcb_configure_request_event_t *xcb_event) { event_t *event,
const xcb_configure_request_event_t *xcb_event
) {
event_reset(event); event_reset(event);
event->type = ZDWM_EVENT_CONFIGURE_REQUEST; event->type = ZDWM_EVENT_CONFIGURE_REQUEST;
/* TODO: */ /* TODO: */
@@ -156,7 +190,7 @@ bool backend_next_event(backend_t *backend, event_t *event) {
if (!raw_event) return false; if (!raw_event) return false;
uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(raw_event); uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(raw_event);
bool handled = false; bool handled = false;
printf("xcb event type: %u\n", response_type); printf("xcb event type: %u\n", response_type);
@@ -173,8 +207,8 @@ bool backend_next_event(backend_t *backend, event_t *event) {
#undef EVENT #undef EVENT
default: default:
break; break;
} }
p_delete(&raw_event); p_delete(&raw_event);

View File

@@ -3,38 +3,43 @@
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include "core/backend.h" /* IWYU pragma: keep */ #define ATOM_LIST(X) \
X(COMPOUND_TEXT) \
X(UTF8_STRING) \
\
X(WM_WINDOW_ROLE) \
X(WM_NAME) \
X(_NET_WM_NAME) \
\
X(_NET_WM_STATE) \
X(_NET_WM_STATE_FULLSCREEN) \
X(_NET_WM_STATE_ABOVE) \
X(_NET_WM_STATE_STICKY) \
X(_NET_WM_STATE_MODAL) \
X(_NET_WM_STATE_SKIP_TASKBAR) \
X(_NET_WM_STATE_MAXIMIZED_VERT) \
X(_NET_WM_STATE_MAXIMIZED_HORZ) \
\
X(_NET_WM_WINDOW_TYPE) \
X(_NET_WM_WINDOW_TYPE_NORMAL) \
X(_NET_WM_WINDOW_TYPE_DESKTOP) \
X(_NET_WM_WINDOW_TYPE_DOCK) \
X(_NET_WM_WINDOW_TYPE_TOOLBAR) \
X(_NET_WM_WINDOW_TYPE_DIALOG) \
X(_NET_WM_WINDOW_TYPE_UTILITY) \
X(_NET_WM_WINDOW_TYPE_SPLASH) \
X(_NET_WM_WINDOW_TYPE_MENU) \
X(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU) \
X(_NET_WM_WINDOW_TYPE_POPUP_MENU) \
X(_NET_WM_WINDOW_TYPE_TOOLTIP) \
X(_NET_WM_WINDOW_TYPE_COMBO) \
X(_NET_WM_WINDOW_TYPE_DND) \
X(_NET_WM_WINDOW_TYPE_NOTIFICATION)
typedef struct atoms_t { typedef struct atoms_t {
xcb_atom_t COMPOUND_TEXT; #define DECLARATION_ATOM(name) xcb_atom_t name;
xcb_atom_t UTF8_STRING; ATOM_LIST(DECLARATION_ATOM);
xcb_atom_t WM_WINDOW_ROLE; #undef DECLARATION_ATOM
xcb_atom_t WM_NAME;
xcb_atom_t _NET_WM_NAME;
xcb_atom_t _NET_WM_STATE;
xcb_atom_t _NET_WM_STATE_FULLSCREEN;
xcb_atom_t _NET_WM_STATE_ABOVE;
xcb_atom_t _NET_WM_STATE_STICKY;
xcb_atom_t _NET_WM_STATE_MODAL;
xcb_atom_t _NET_WM_STATE_SKIP_TASKBAR;
xcb_atom_t _NET_WM_STATE_MAXIMIZED_VERT;
xcb_atom_t _NET_WM_STATE_MAXIMIZED_HORZ;
xcb_atom_t _NET_WM_WINDOW_TYPE;
xcb_atom_t _NET_WM_WINDOW_TYPE_NORMAL;
xcb_atom_t _NET_WM_WINDOW_TYPE_DESKTOP;
xcb_atom_t _NET_WM_WINDOW_TYPE_DOCK;
xcb_atom_t _NET_WM_WINDOW_TYPE_TOOLBAR;
xcb_atom_t _NET_WM_WINDOW_TYPE_DIALOG;
xcb_atom_t _NET_WM_WINDOW_TYPE_UTILITY;
xcb_atom_t _NET_WM_WINDOW_TYPE_SPLASH;
xcb_atom_t _NET_WM_WINDOW_TYPE_MENU;
xcb_atom_t _NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
xcb_atom_t _NET_WM_WINDOW_TYPE_POPUP_MENU;
xcb_atom_t _NET_WM_WINDOW_TYPE_TOOLTIP;
xcb_atom_t _NET_WM_WINDOW_TYPE_COMBO;
xcb_atom_t _NET_WM_WINDOW_TYPE_DND;
xcb_atom_t _NET_WM_WINDOW_TYPE_NOTIFICATION;
} atoms_t; } atoms_t;
struct backend_t { struct backend_t {

View File

@@ -7,17 +7,28 @@
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include "base/memory.h" #include "base/memory.h"
#include "core/backend.h"
#include "internal.h" #include "internal.h"
static char *window_get_text_property(backend_t *backend, xcb_window_t window, static char *window_get_text_property(
xcb_atom_t property) { backend_t *backend,
xcb_window_t window,
xcb_atom_t property
) {
xcb_get_property_cookie_t cookie = xcb_get_property_unchecked( xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(
backend->conn, false, window, property, XCB_ATOM_ANY, 0, UINT32_MAX); backend->conn,
false,
window,
property,
XCB_ATOM_ANY,
0,
UINT32_MAX
);
xcb_get_property_reply_t *reply = xcb_get_property_reply_t *reply =
xcb_get_property_reply(backend->conn, cookie, nullptr); xcb_get_property_reply(backend->conn, cookie, nullptr);
if (!reply) return nullptr; if (!reply) return nullptr;
int length = xcb_get_property_value_length(reply); int length = xcb_get_property_value_length(reply);
char *value = (char *)xcb_get_property_value(reply); char *value = (char *)xcb_get_property_value(reply);
char *text = nullptr; char *text = nullptr;
@@ -39,16 +50,20 @@ char *window_get_role(backend_t *backend, xcb_window_t window) {
char *window_get_title(backend_t *backend, xcb_window_t window) { char *window_get_title(backend_t *backend, xcb_window_t window) {
xcb_atom_t property = backend->atoms._NET_WM_NAME; xcb_atom_t property = backend->atoms._NET_WM_NAME;
char *name = window_get_text_property(backend, window, property); char *name = window_get_text_property(backend, window, property);
if (!name) { if (!name) {
property = backend->atoms.WM_NAME; property = backend->atoms.WM_NAME;
name = window_get_text_property(backend, window, property); name = window_get_text_property(backend, window, property);
} }
return name; return name;
} }
void window_get_class(backend_t *backend, xcb_window_t window, char **class_out, void window_get_class(
char **instance_out) { backend_t *backend,
xcb_window_t window,
char **class_out,
char **instance_out
) {
xcb_icccm_get_wm_class_reply_t prop; xcb_icccm_get_wm_class_reply_t prop;
xcb_get_property_cookie_t cookie = xcb_get_property_cookie_t cookie =
xcb_icccm_get_wm_class_unchecked(backend->conn, window); xcb_icccm_get_wm_class_unchecked(backend->conn, window);
@@ -74,15 +89,15 @@ xcb_window_t window_get_transient_for(backend_t *backend, xcb_window_t window) {
return XCB_WINDOW_NONE; return XCB_WINDOW_NONE;
} }
xcb_get_window_attributes_reply_t *window_get_attributes(backend_t *backend, xcb_get_window_attributes_reply_t *
xcb_window_t window) { window_get_attributes(backend_t *backend, xcb_window_t window) {
xcb_get_window_attributes_cookie_t cookie = xcb_get_window_attributes_cookie_t cookie =
xcb_get_window_attributes(backend->conn, window); xcb_get_window_attributes(backend->conn, window);
return xcb_get_window_attributes_reply(backend->conn, cookie, nullptr); return xcb_get_window_attributes_reply(backend->conn, cookie, nullptr);
} }
static window_type_t atom_to_window_type(const atoms_t *atoms, static window_type_t
xcb_atom_t atom) { atom_to_window_type(const atoms_t *atoms, xcb_atom_t atom) {
if (atom == atoms->_NET_WM_WINDOW_TYPE_DESKTOP) if (atom == atoms->_NET_WM_WINDOW_TYPE_DESKTOP)
return ZDWM_WINDOW_TYPE_DESKTOP; return ZDWM_WINDOW_TYPE_DESKTOP;
if (atom == atoms->_NET_WM_WINDOW_TYPE_DOCK) return ZDWM_WINDOW_TYPE_DOCK; if (atom == atoms->_NET_WM_WINDOW_TYPE_DOCK) return ZDWM_WINDOW_TYPE_DOCK;
@@ -106,13 +121,21 @@ static window_type_t atom_to_window_type(const atoms_t *atoms,
return ZDWM_WINDOW_TYPE_NORMAL; return ZDWM_WINDOW_TYPE_NORMAL;
} }
bool window_get_types(backend_t *backend, xcb_window_t window, bool window_get_types(
window_type_t **types, size_t *count) { backend_t *backend,
xcb_window_t window,
window_type_t **types,
size_t *count
) {
uint32_t atom_count = 0; uint32_t atom_count = 0;
xcb_atom_t *atoms = nullptr; xcb_atom_t *atoms = nullptr;
if (!window_get_atom_array(backend, window, if (!window_get_atom_array(
backend->atoms._NET_WM_WINDOW_TYPE, &atoms, backend,
&atom_count)) { window,
backend->atoms._NET_WM_WINDOW_TYPE,
&atoms,
&atom_count
)) {
return false; return false;
} }
if (!atoms) { if (!atoms) {
@@ -156,20 +179,31 @@ bool window_get_geometry(backend_t *backend, xcb_window_t window, rect_t *out) {
xcb_get_geometry_reply(backend->conn, cookie, nullptr); xcb_get_geometry_reply(backend->conn, cookie, nullptr);
if (!reply) return false; if (!reply) return false;
out->x = reply->x; out->x = reply->x;
out->y = reply->y; out->y = reply->y;
out->width = reply->width; out->width = reply->width;
out->height = reply->height; out->height = reply->height;
p_delete(&reply); p_delete(&reply);
return true; return true;
} }
bool window_get_atom_array(backend_t *backend, xcb_window_t window, bool window_get_atom_array(
xcb_atom_t property, xcb_atom_t **out_atoms, backend_t *backend,
uint32_t *out_len) { xcb_window_t window,
xcb_atom_t property,
xcb_atom_t **out_atoms,
uint32_t *out_len
) {
xcb_get_property_cookie_t cookie = xcb_get_property_unchecked( xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(
backend->conn, false, window, property, XCB_ATOM_ATOM, 0, UINT32_MAX); backend->conn,
false,
window,
property,
XCB_ATOM_ATOM,
0,
UINT32_MAX
);
xcb_get_property_reply_t *reply = xcb_get_property_reply_t *reply =
xcb_get_property_reply(backend->conn, cookie, nullptr); xcb_get_property_reply(backend->conn, cookie, nullptr);
if (!reply) return false; if (!reply) return false;
@@ -179,7 +213,7 @@ bool window_get_atom_array(backend_t *backend, xcb_window_t window,
*out_atoms = *out_atoms =
p_copy((xcb_atom_t *)xcb_get_property_value(reply), reply->value_len); p_copy((xcb_atom_t *)xcb_get_property_value(reply), reply->value_len);
} else { } else {
*out_len = 0; *out_len = 0;
*out_atoms = nullptr; *out_atoms = nullptr;
} }
@@ -187,8 +221,11 @@ bool window_get_atom_array(backend_t *backend, xcb_window_t window,
return true; return true;
} }
bool window_get_wm_hints(backend_t *backend, xcb_window_t window, bool window_get_wm_hints(
xcb_icccm_wm_hints_t *out) { backend_t *backend,
xcb_window_t window,
xcb_icccm_wm_hints_t *out
) {
xcb_get_property_cookie_t cookie = xcb_get_property_cookie_t cookie =
xcb_icccm_get_wm_hints_unchecked(backend->conn, window); xcb_icccm_get_wm_hints_unchecked(backend->conn, window);
if (!xcb_icccm_get_wm_hints_reply(backend->conn, cookie, out, nullptr)) { if (!xcb_icccm_get_wm_hints_reply(backend->conn, cookie, out, nullptr)) {

View File

@@ -35,18 +35,33 @@ char *window_get_title(backend_t *backend, xcb_window_t window);
* @param instance_out instance 信息返回指针,调用者持有其内存并负责调用 free * @param instance_out instance 信息返回指针,调用者持有其内存并负责调用 free
* 释放 * 释放
*/ */
void window_get_class(backend_t *backend, xcb_window_t window, char **class_out, void window_get_class(
char **instance_out); backend_t *backend,
xcb_window_t window,
char **class_out,
char **instance_out
);
xcb_window_t window_get_transient_for(backend_t *backend, xcb_window_t window); xcb_window_t window_get_transient_for(backend_t *backend, xcb_window_t window);
xcb_get_window_attributes_reply_t *window_get_attributes(backend_t *backend, xcb_get_window_attributes_reply_t *
xcb_window_t window); window_get_attributes(backend_t *backend, xcb_window_t window);
bool window_get_types(backend_t *backend, xcb_window_t window, bool window_get_types(
window_type_t **types, size_t *count); backend_t *backend,
xcb_window_t window,
window_type_t **types,
size_t *count
);
bool window_get_fixed_size(backend_t *backend, xcb_window_t window, bool *out); bool window_get_fixed_size(backend_t *backend, xcb_window_t window, bool *out);
bool window_get_geometry(backend_t *backend, xcb_window_t window, rect_t *out); bool window_get_geometry(backend_t *backend, xcb_window_t window, rect_t *out);
bool window_get_atom_array(backend_t *backend, xcb_window_t window, bool window_get_atom_array(
xcb_atom_t property, xcb_atom_t **out_atoms, backend_t *backend,
uint32_t *out_len); xcb_window_t window,
bool window_get_wm_hints(backend_t *backend, xcb_window_t window, xcb_atom_t property,
xcb_icccm_wm_hints_t *out); xcb_atom_t **out_atoms,
uint32_t *out_len
);
bool window_get_wm_hints(
backend_t *backend,
xcb_window_t window,
xcb_icccm_wm_hints_t *out
);
window_state_t atom_to_window_state(const atoms_t *atoms, xcb_atom_t atom); window_state_t atom_to_window_state(const atoms_t *atoms, xcb_atom_t atom);

View File

@@ -1,2 +0,0 @@
#pragma once

1
src/base/.clang-format Symbolic link
View File

@@ -0,0 +1 @@
../../.clang-format

View File

@@ -24,8 +24,12 @@ static inline size_t next_capacity(size_t capacity) {
* @param capacity 当前容量地址 * @param capacity 当前容量地址
* @param need 目标容量 * @param need 目标容量
*/ */
static inline void array_reserve_impl(void **items, size_t item_size, static inline void array_reserve_impl(
size_t *capacity, size_t need) { void **items,
size_t item_size,
size_t *capacity,
size_t need
) {
if (*capacity >= need) return; if (*capacity >= need) return;
size_t new_capacity = next_capacity(*capacity); size_t new_capacity = next_capacity(*capacity);
@@ -51,8 +55,12 @@ static inline void array_reserve_impl(void **items, size_t item_size,
* *
* @return void* 新槽位地址 * @return void* 新槽位地址
*/ */
static inline void *array_push_impl(void **items, size_t item_size, static inline void *array_push_impl(
size_t *count, size_t *capacity) { void **items,
size_t item_size,
size_t *count,
size_t *capacity
) {
array_reserve_impl(items, item_size, capacity, *count + 1); array_reserve_impl(items, item_size, capacity, *count + 1);
void *slot = (char *)*items + *count * item_size; void *slot = (char *)*items + *count * item_size;
@@ -71,14 +79,14 @@ static inline void *array_push_impl(void **items, size_t item_size,
* @return true 删除成功 * @return true 删除成功
* @return false 下标越界 * @return false 下标越界
*/ */
static inline bool array_erase_impl(void *items, size_t item_size, static inline bool
size_t *count, size_t index) { array_erase_impl(void *items, size_t item_size, size_t *count, size_t index) {
if (index >= *count) return false; if (index >= *count) return false;
size_t tail_count = *count - index - 1; size_t tail_count = *count - index - 1;
if (tail_count > 0) { if (tail_count > 0) {
char *dest = (char *)items + index * item_size; char *dest = (char *)items + index * item_size;
char *src = dest + item_size; char *src = dest + item_size;
memmove(dest, src, tail_count * item_size); memmove(dest, src, tail_count * item_size);
} }

View File

@@ -5,14 +5,23 @@
#define fatal(format, ...) \ #define fatal(format, ...) \
_fatal(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__) _fatal(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__)
void _fatal(int line, const char *function, const char *file, void _fatal(
const char *format, ...) __attribute__((noreturn)) int line,
__attribute__((format(printf, 4, 5))); const char *function,
const char *file,
const char *format,
...
) __attribute__((noreturn)) __attribute__((format(printf, 4, 5)));
#define warn(format, ...) \ #define warn(format, ...) \
_warn(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__) _warn(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__)
void _warn(int line, const char *function, const char *file, const char *format, void _warn(
...) __attribute__((format(printf, 4, 5))); int line,
const char *function,
const char *file,
const char *format,
...
) __attribute__((format(printf, 4, 5)));
const char *current_time_str(void); const char *current_time_str(void);

View File

@@ -7,10 +7,10 @@
#define countof(foo) (ssizeof(foo) / ssizeof(foo[0])) #define countof(foo) (ssizeof(foo) / ssizeof(foo[0]))
#ifdef __GNUC__ #ifdef __GNUC__
#define likely(expr) __builtin_expect(!!(expr), 1) #define likely(expr) __builtin_expect(!!(expr), 1)
#define unlikely(expr) __builtin_expect((expr), 0) #define unlikely(expr) __builtin_expect((expr), 0)
#else #else
#define likely(expr) expr #define likely(expr) expr
#define unlikely(expr) expr #define unlikely(expr) expr
#endif #endif

View File

@@ -5,11 +5,11 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#define p_alloc_nr(x) (((x) + 16) * 3 / 2) #define p_alloc_nr(x) (((x) + 16) * 3 / 2)
#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_copy(src, count) xmemcopy((src), sizeof(*(src)) * (count))
#define p_delete(mem_p) \ #define p_delete(mem_p) \
do { \ do { \
@@ -64,8 +64,7 @@ static inline void *xmemcopy(const void *src, size_t n) {
} }
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);
else { else {
*ptr = realloc(*ptr, newsize); *ptr = realloc(*ptr, newsize);
if (!*ptr) abort(); if (!*ptr) abort();

1
src/config/.clang-format Symbolic link
View File

@@ -0,0 +1 @@
../../.clang-format

View File

@@ -2,16 +2,28 @@
#include "base/macros.h" #include "base/macros.h"
bool config_defaults_build(const zdwm_api_t *api, bool config_defaults_build(
zdwm_config_builder_t *builder, const zdwm_api_t *api,
const zdwm_output_info_t *outputs, zdwm_config_builder_t *builder,
size_t output_count) { const zdwm_output_info_t *outputs,
size_t output_count
) {
if (!api || !builder || !outputs || output_count == 0) return false; if (!api || !builder || !outputs || output_count == 0) return false;
zdwm_layout_id_t tile_id = api->register_layout( zdwm_layout_id_t tile_id = api->register_layout(
builder, "tile", "[]=", "builtin tile", api->builtin_layouts.tile); builder,
"tile",
"[]=",
"builtin tile",
api->builtin_layouts.tile
);
zdwm_layout_id_t monocle_id = api->register_layout( zdwm_layout_id_t monocle_id = api->register_layout(
builder, "monocle", "[M]", "builtin monocle", api->builtin_layouts.monocle); builder,
"monocle",
"[M]",
"builtin monocle",
api->builtin_layouts.monocle
);
zdwm_layout_id_t floating_id = zdwm_layout_id_t floating_id =
api->register_layout(builder, "floating", "><>", "floating", nullptr); api->register_layout(builder, "floating", "><>", "floating", nullptr);
if (tile_id == ZDWM_LAYOUT_ID_INVALID || if (tile_id == ZDWM_LAYOUT_ID_INVALID ||
@@ -22,9 +34,14 @@ bool config_defaults_build(const zdwm_api_t *api,
zdwm_layout_id_t layout_ids[] = {tile_id, monocle_id, floating_id}; zdwm_layout_id_t layout_ids[] = {tile_id, monocle_id, floating_id};
for (size_t i = 0; i < output_count; i++) { for (size_t i = 0; i < output_count; i++) {
if (api->define_workspace(builder, i, "main", layout_ids, if (api->define_workspace(
countof(layout_ids), builder,
tile_id) == ZDWM_WORKSPACE_ID_INVALID) { i,
"main",
layout_ids,
countof(layout_ids),
tile_id
) == ZDWM_WORKSPACE_ID_INVALID) {
return false; return false;
} }
} }

View File

@@ -10,40 +10,43 @@
static char *config_loader_join_path(const char *base, const char *suffix) { static char *config_loader_join_path(const char *base, const char *suffix) {
if (!base || !suffix) return nullptr; if (!base || !suffix) return nullptr;
size_t base_len = strlen(base); size_t base_len = strlen(base);
size_t suffix_len = strlen(suffix); size_t suffix_len = strlen(suffix);
char *path = p_new(char, base_len + suffix_len + 1); char *path = p_new(char, base_len + suffix_len + 1);
memcpy(path, base, base_len); memcpy(path, base, base_len);
memcpy(path + base_len, suffix, suffix_len + 1); memcpy(path + base_len, suffix, suffix_len + 1);
return path; return path;
} }
static bool config_loader_resolve_path(char **out_path, bool *out_is_explicit, static bool config_loader_resolve_path(
const char *override_path) { char **out_path,
bool *out_is_explicit,
const char *override_path
) {
const char *path = override_path; const char *path = override_path;
if (path && *path) { if (path && *path) {
*out_path = p_strdup(path); *out_path = p_strdup(path);
*out_is_explicit = true; *out_is_explicit = true;
return true; return true;
} }
path = getenv("ZDWM_CONFIG_LIB"); path = getenv("ZDWM_CONFIG_LIB");
if (path && *path) { if (path && *path) {
*out_path = p_strdup(path); *out_path = p_strdup(path);
*out_is_explicit = true; *out_is_explicit = true;
return true; return true;
} }
path = getenv("XDG_CONFIG_HOME"); path = getenv("XDG_CONFIG_HOME");
if (path && *path) { if (path && *path) {
*out_path = config_loader_join_path(path, "/zdwm/config.so"); *out_path = config_loader_join_path(path, "/zdwm/config.so");
*out_is_explicit = false; *out_is_explicit = false;
return *out_path != nullptr; return *out_path != nullptr;
} }
path = getenv("HOME"); path = getenv("HOME");
if (path && *path) { if (path && *path) {
*out_path = config_loader_join_path(path, "/.config/zdwm/config.so"); *out_path = config_loader_join_path(path, "/.config/zdwm/config.so");
*out_is_explicit = false; *out_is_explicit = false;
return *out_path != nullptr; return *out_path != nullptr;
} }
@@ -76,7 +79,7 @@ bool config_loader_load(config_loader_t *loader, const char *override_path) {
} }
dlerror(); dlerror();
loader->setup = (zdwm_config_setup_fn *)dlsym(loader->handle, "setup"); loader->setup = (zdwm_config_setup_fn *)dlsym(loader->handle, "setup");
const char *error = dlerror(); const char *error = dlerror();
if (!error) return true; if (!error) return true;

View File

@@ -44,21 +44,29 @@ static void config_builder_cleanup(zdwm_config_builder_t *builder) {
} }
workspace_desc_list_cleanup(&builder->workspaces, &builder->workspace_count); workspace_desc_list_cleanup(&builder->workspaces, &builder->workspace_count);
builder->workspace_capacity = 0; builder->workspace_capacity = 0;
builder->output_count = 0; builder->output_count = 0;
} }
static layout_id_t runtime_config_register_layout( static layout_id_t runtime_config_register_layout(
zdwm_config_builder_t *builder, const char *name, const char *symbol, zdwm_config_builder_t *builder,
const char *description, layout_fn fn) { const char *name,
const char *symbol,
const char *description,
layout_fn fn
) {
if (!builder || !name || !symbol) return ZDWM_LAYOUT_ID_INVALID; if (!builder || !name || !symbol) return ZDWM_LAYOUT_ID_INVALID;
return layout_register(&builder->layouts, name, symbol, description, fn); return layout_register(&builder->layouts, name, symbol, description, fn);
} }
static workspace_id_t runtime_config_define_workspace( static workspace_id_t runtime_config_define_workspace(
zdwm_config_builder_t *builder, size_t output_index, const char *name, zdwm_config_builder_t *builder,
const layout_id_t *layout_ids, size_t layout_count, size_t output_index,
layout_id_t initial_layout_id) { const char *name,
const layout_id_t *layout_ids,
size_t layout_count,
layout_id_t initial_layout_id
) {
if (!builder) return ZDWM_WORKSPACE_ID_INVALID; if (!builder) return ZDWM_WORKSPACE_ID_INVALID;
if (output_index >= builder->output_count) return ZDWM_WORKSPACE_ID_INVALID; if (output_index >= builder->output_count) return ZDWM_WORKSPACE_ID_INVALID;
if (builder->workspace_count >= (size_t)ZDWM_WORKSPACE_ID_INVALID) { if (builder->workspace_count >= (size_t)ZDWM_WORKSPACE_ID_INVALID) {
@@ -66,10 +74,10 @@ static workspace_id_t runtime_config_define_workspace(
} }
workspace_desc_t desc = { workspace_desc_t desc = {
.output_index = output_index, .output_index = output_index,
.name = name, .name = name,
.layout_ids = layout_ids, .layout_ids = layout_ids,
.layout_count = layout_count, .layout_count = layout_count,
.initial_layout_id = initial_layout_id, .initial_layout_id = initial_layout_id,
}; };
if (!workspace_desc_valid(&desc, builder->output_count)) { if (!workspace_desc_valid(&desc, builder->output_count)) {
@@ -83,12 +91,15 @@ static workspace_id_t runtime_config_define_workspace(
} }
workspace_id_t workspace_id = (workspace_id_t)builder->workspace_count; workspace_id_t workspace_id = (workspace_id_t)builder->workspace_count;
workspace_desc_t *slot = array_push( workspace_desc_t *slot = array_push(
builder->workspaces, builder->workspace_count, builder->workspace_capacity); builder->workspaces,
slot->output_index = output_index; builder->workspace_count,
slot->name = p_strdup(name); builder->workspace_capacity
slot->layout_ids = p_copy(layout_ids, layout_count); );
slot->layout_count = layout_count; slot->output_index = output_index;
slot->name = p_strdup(name);
slot->layout_ids = p_copy(layout_ids, layout_count);
slot->layout_count = layout_count;
slot->initial_layout_id = initial_layout_id; slot->initial_layout_id = initial_layout_id;
return workspace_id; return workspace_id;
} }
@@ -100,8 +111,8 @@ static bool rule_match_valid(const rule_match_t *match) {
match->instance_name; match->instance_name;
} }
static bool rule_action_valid(const rule_action_t *action, static bool
size_t workspace_count) { rule_action_valid(const rule_action_t *action, size_t workspace_count) {
if (!action) return false; if (!action) return false;
if (action->workspace == ZDWM_WORKSPACE_ID_INVALID) { if (action->workspace == ZDWM_WORKSPACE_ID_INVALID) {
@@ -112,60 +123,66 @@ static bool rule_action_valid(const rule_action_t *action,
return action->workspace < workspace_count; return action->workspace < workspace_count;
} }
static bool runtime_config_add_rule(zdwm_config_builder_t *builder, static bool runtime_config_add_rule(
const zdwm_rule_match_t *match, zdwm_config_builder_t *builder,
const zdwm_rule_action_t *action) { const zdwm_rule_match_t *match,
const zdwm_rule_action_t *action
) {
if (!builder) return false; if (!builder) return false;
if (!rule_match_valid(match)) return false; if (!rule_match_valid(match)) return false;
if (!rule_action_valid(action, builder->workspace_count)) return false; if (!rule_action_valid(action, builder->workspace_count)) return false;
rules_t *rules = &builder->rules; rules_t *rules = &builder->rules;
rule_item_t *rule = array_push(rules->items, rules->count, rules->capacity); rule_item_t *rule = array_push(rules->items, rules->count, rules->capacity);
rule->match.app_id = p_strdup_nullable(match->app_id); rule->match.app_id = p_strdup_nullable(match->app_id);
rule->match.role = p_strdup_nullable(match->role); rule->match.role = p_strdup_nullable(match->role);
rule->match.class_name = p_strdup_nullable(match->class_name); rule->match.class_name = p_strdup_nullable(match->class_name);
rule->match.instance_name = p_strdup_nullable(match->instance_name); rule->match.instance_name = p_strdup_nullable(match->instance_name);
rule->action = *action; rule->action = *action;
return true; return true;
} }
static bool config_builder_finish(zdwm_config_builder_t *builder, static bool config_builder_finish(
runtime_init_desc_t *out) { zdwm_config_builder_t *builder,
runtime_init_desc_t *out
) {
if (!builder || !out) return false; if (!builder || !out) return false;
if (!builder->layouts.slot_count || !builder->workspace_count) return false; if (!builder->layouts.slot_count || !builder->workspace_count) return false;
if (!layout_registry_move(&builder->layouts, &out->layouts)) return false; if (!layout_registry_move(&builder->layouts, &out->layouts)) return false;
if (!rules_move(&builder->rules, &out->rules)) return false; if (!rules_move(&builder->rules, &out->rules)) return false;
out->workspaces = builder->workspaces; out->workspaces = builder->workspaces;
out->workspace_count = builder->workspace_count; out->workspace_count = builder->workspace_count;
builder->workspaces = nullptr; builder->workspaces = nullptr;
builder->workspace_count = 0; builder->workspace_count = 0;
builder->workspace_capacity = 0; builder->workspace_capacity = 0;
builder->output_count = 0; builder->output_count = 0;
return true; return true;
} }
static bool runtime_config_build(zdwm_config_setup_fn *setup, static bool runtime_config_build(
const output_info_t *outputs, zdwm_config_setup_fn *setup,
size_t output_count, const output_info_t *outputs,
runtime_init_desc_t *out) { size_t output_count,
runtime_init_desc_t *out
) {
if (!setup || !out) return false; if (!setup || !out) return false;
zdwm_config_builder_t builder = {0}; zdwm_config_builder_t builder = {0};
builder.output_count = output_count; builder.output_count = output_count;
zdwm_api_t api = { zdwm_api_t api = {
.abi_version = ZDWM_CONFIG_ABI_VERSION, .abi_version = ZDWM_CONFIG_ABI_VERSION,
.builtin_layouts = .builtin_layouts =
{ {
.tile = nullptr, .tile = nullptr,
.monocle = nullptr, .monocle = nullptr,
}, },
.register_layout = runtime_config_register_layout, .register_layout = runtime_config_register_layout,
.define_workspace = runtime_config_define_workspace, .define_workspace = runtime_config_define_workspace,
.add_rule = runtime_config_add_rule, .add_rule = runtime_config_add_rule,
}; };
bool ok = setup(&api, &builder, outputs, output_count) && bool ok = setup(&api, &builder, outputs, output_count) &&
config_builder_finish(&builder, out); config_builder_finish(&builder, out);
@@ -178,7 +195,7 @@ bool runtime_config_load(const char *override_path, runtime_init_desc_t *out) {
runtime_config_cleanup(out); runtime_config_cleanup(out);
config_loader_t loader = {0}; config_loader_t loader = {0};
bool ok = false; bool ok = false;
if (!config_loader_load(&loader, override_path)) goto cleanup; if (!config_loader_load(&loader, override_path)) goto cleanup;
zdwm_config_setup_fn *setup = zdwm_config_setup_fn *setup =
@@ -186,7 +203,7 @@ bool runtime_config_load(const char *override_path, runtime_init_desc_t *out) {
ok = runtime_config_build(setup, out->outputs, out->output_count, out); ok = runtime_config_build(setup, out->outputs, out->output_count, out);
if (ok) { if (ok) {
out->config_module_handle = loader.handle; out->config_module_handle = loader.handle;
loader.handle = nullptr; loader.handle = nullptr;
} }
cleanup: cleanup:

1
src/core/.clang-format Symbolic link
View File

@@ -0,0 +1 @@
../../.clang-format

View File

@@ -32,5 +32,8 @@ void backend_detect_destroy(backend_detect_t *detect);
* 无需 cleanup 的状态,调用方可以直接退出循环。 * 无需 cleanup 的状态,调用方可以直接退出循环。
*/ */
bool backend_next_event(backend_t *backend, event_t *event); bool backend_next_event(backend_t *backend, event_t *event);
bool backend_apply_effect(backend_t *backend, const effect_t *effects, bool backend_apply_effect(
size_t effect_count); backend_t *backend,
const effect_t *effects,
size_t effect_count
);

View File

@@ -13,11 +13,11 @@ void command_buffer_reset(command_buffer_t *buffer) {
void command_buffer_cleanup(command_buffer_t *buffer) { void command_buffer_cleanup(command_buffer_t *buffer) {
p_delete(&buffer->items); p_delete(&buffer->items);
buffer->count = 0; buffer->count = 0;
buffer->capacity = 0; buffer->capacity = 0;
} }
void command_buffer_push(command_buffer_t *buffer, const command_t *command) { void command_buffer_push(command_buffer_t *buffer, const command_t *command) {
command_t *cmd = array_push(buffer->items, buffer->count, buffer->capacity); command_t *cmd = array_push(buffer->items, buffer->count, buffer->capacity);
*cmd = *command; *cmd = *command;
} }

View File

@@ -25,15 +25,15 @@ void event_cleanup(event_t *event) {
if (!event) return; if (!event) return;
switch (event->type) { switch (event->type) {
case ZDWM_EVENT_WINDOW_MAP_REQUEST: case ZDWM_EVENT_WINDOW_MAP_REQUEST:
window_layer_props_cleanup(&event->as.window_map_request.props); window_layer_props_cleanup(&event->as.window_map_request.props);
window_metadata_cleanup(&event->as.window_map_request.metadata); window_metadata_cleanup(&event->as.window_map_request.metadata);
break; break;
case ZDWM_EVENT_WINDOW_METADATA_CHANGED: case ZDWM_EVENT_WINDOW_METADATA_CHANGED:
window_metadata_cleanup(&event->as.window_metadata_change.metadata); window_metadata_cleanup(&event->as.window_metadata_change.metadata);
break; break;
default: default:
break; break;
} }
} }

View File

@@ -22,8 +22,8 @@ typedef enum event_type_t {
typedef enum modifier_bit_t { typedef enum modifier_bit_t {
ZDWM_MOD_SHIFT = 1u << 0, ZDWM_MOD_SHIFT = 1u << 0,
ZDWM_MOD_CTRL = 1u << 1, ZDWM_MOD_CTRL = 1u << 1,
ZDWM_MOD_ALT = 1u << 2, ZDWM_MOD_ALT = 1u << 2,
ZDWM_MOD_SUPER = 1u << 3, ZDWM_MOD_SUPER = 1u << 3,
} modifier_bit_t; } modifier_bit_t;
@@ -87,10 +87,10 @@ typedef struct window_remove_event_t {
} window_remove_event_t; } window_remove_event_t;
typedef enum window_metadata_change_flags_t { typedef enum window_metadata_change_flags_t {
ZDWM_WINDOW_METADATA_CHANGE_TITLE = 1u << 0, ZDWM_WINDOW_METADATA_CHANGE_TITLE = 1u << 0,
ZDWM_WINDOW_METADATA_CHANGE_APP_ID = 1u << 1, ZDWM_WINDOW_METADATA_CHANGE_APP_ID = 1u << 1,
ZDWM_WINDOW_METADATA_CHANGE_ROLE = 1u << 2, ZDWM_WINDOW_METADATA_CHANGE_ROLE = 1u << 2,
ZDWM_WINDOW_METADATA_CHANGE_CLASS = 1u << 3, ZDWM_WINDOW_METADATA_CHANGE_CLASS = 1u << 3,
ZDWM_WINDOW_METADATA_CHANGE_INSTANCE = 1u << 4, ZDWM_WINDOW_METADATA_CHANGE_INSTANCE = 1u << 4,
} window_metadata_change_flags_t; } window_metadata_change_flags_t;
@@ -101,9 +101,9 @@ typedef struct window_metadata_change_event_t {
} window_metadata_change_event_t; } window_metadata_change_event_t;
typedef enum window_hint_changed_flags_t { typedef enum window_hint_changed_flags_t {
ZDWM_WINDOW_HINT_CHANGED_NONE = 0, ZDWM_WINDOW_HINT_CHANGED_NONE = 0,
ZDWM_WINDOW_HINT_CHANGED_URGENT = 1u << 0, ZDWM_WINDOW_HINT_CHANGED_URGENT = 1u << 0,
ZDWM_WINDOW_HINT_CHANGED_FIXED_SIZE = 1u << 1, ZDWM_WINDOW_HINT_CHANGED_FIXED_SIZE = 1u << 1,
ZDWM_WINDOW_HINT_CHANGED_SKIP_TASKBAR = 1u << 2, ZDWM_WINDOW_HINT_CHANGED_SKIP_TASKBAR = 1u << 2,
} window_hint_changed_flags_t; } window_hint_changed_flags_t;
@@ -116,9 +116,9 @@ typedef struct window_hints_changed_event_t {
} window_hints_changed_event_t; } window_hints_changed_event_t;
typedef enum window_activation_source_t { typedef enum window_activation_source_t {
ZDWM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0, ZDWM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0,
ZDWM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1, ZDWM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1,
ZDWM_WINDOW_ACTIVATION_SOURCE_PAGER = 2, ZDWM_WINDOW_ACTIVATION_SOURCE_PAGER = 2,
} window_activation_source_t; } window_activation_source_t;
typedef struct window_activate_request_event_t { typedef struct window_activate_request_event_t {
@@ -145,10 +145,10 @@ typedef struct window_state_request_event_t {
} window_state_request_event_t; } window_state_request_event_t;
typedef enum configure_request_field_t { typedef enum configure_request_field_t {
ZDWM_CONFIGURE_REQUEST_FIELD_NONE = 0, ZDWM_CONFIGURE_REQUEST_FIELD_NONE = 0,
ZDWM_CONFIGURE_REQUEST_FIELD_X = 1u << 0, ZDWM_CONFIGURE_REQUEST_FIELD_X = 1u << 0,
ZDWM_CONFIGURE_REQUEST_FIELD_Y = 1u << 1, ZDWM_CONFIGURE_REQUEST_FIELD_Y = 1u << 1,
ZDWM_CONFIGURE_REQUEST_FIELD_WIDTH = 1u << 2, ZDWM_CONFIGURE_REQUEST_FIELD_WIDTH = 1u << 2,
ZDWM_CONFIGURE_REQUEST_FIELD_HEIGHT = 1u << 3, ZDWM_CONFIGURE_REQUEST_FIELD_HEIGHT = 1u << 3,
} configure_request_field_t; } configure_request_field_t;

View File

@@ -9,7 +9,7 @@
void layer_stack_cleanup(layer_stack_t *layer) { void layer_stack_cleanup(layer_stack_t *layer) {
p_delete(&layer->order); p_delete(&layer->order);
layer->count = 0; layer->count = 0;
layer->capacity = 0; layer->capacity = 0;
} }
@@ -20,7 +20,7 @@ void layer_stack_append(layer_stack_t *layer, window_id_t window) {
} }
bool layer_stack_remove(layer_stack_t *layer, window_id_t window) { bool layer_stack_remove(layer_stack_t *layer, window_id_t window) {
bool found = false; bool found = false;
size_t index = 0; size_t index = 0;
for (size_t i = 0; i < layer->count; ++i) { for (size_t i = 0; i < layer->count; ++i) {
if (layer->order[i] != window) continue; if (layer->order[i] != window) continue;
@@ -41,7 +41,7 @@ bool layer_stack_remove(layer_stack_t *layer, window_id_t window) {
} }
bool layer_stack_raise(layer_stack_t *layer, window_id_t window) { bool layer_stack_raise(layer_stack_t *layer, window_id_t window) {
bool found = false; bool found = false;
size_t index = 0; size_t index = 0;
for (size_t i = 0; i < layer->count; ++i) { for (size_t i = 0; i < layer->count; ++i) {
if (layer->order[i] != window) continue; if (layer->order[i] != window) continue;
@@ -65,7 +65,7 @@ bool layer_stack_raise(layer_stack_t *layer, window_id_t window) {
} }
bool layer_stack_lower(layer_stack_t *layer, window_id_t window) { bool layer_stack_lower(layer_stack_t *layer, window_id_t window) {
bool found = false; bool found = false;
size_t index = 0; size_t index = 0;
for (size_t i = 0; i < layer->count; ++i) { for (size_t i = 0; i < layer->count; ++i) {
if (layer->order[i] != window) continue; if (layer->order[i] != window) continue;

View File

@@ -10,7 +10,7 @@
void layout_result_cleanup(layout_result_t *result) { void layout_result_cleanup(layout_result_t *result) {
p_delete(&result->items); p_delete(&result->items);
result->item_count = 0; result->item_count = 0;
result->item_capacity = 0; result->item_capacity = 0;
} }
@@ -31,19 +31,19 @@ void layout_registry_cleanup(layout_registry_t *registry) {
} }
p_delete(&registry->slots); p_delete(&registry->slots);
registry->slot_count = 0; registry->slot_count = 0;
registry->slot_capacity = 0; registry->slot_capacity = 0;
} }
bool layout_registry_move(layout_registry_t *src, layout_registry_t *dest) { bool layout_registry_move(layout_registry_t *src, layout_registry_t *dest) {
if (!src || !dest) return false; if (!src || !dest) return false;
dest->slots = src->slots; dest->slots = src->slots;
dest->slot_count = src->slot_count; dest->slot_count = src->slot_count;
dest->slot_capacity = src->slot_capacity; dest->slot_capacity = src->slot_capacity;
src->slots = nullptr; src->slots = nullptr;
src->slot_count = 0; src->slot_count = 0;
src->slot_capacity = 0; src->slot_capacity = 0;
return true; return true;
@@ -53,25 +53,29 @@ size_t layout_registry_count(const layout_registry_t *registry) {
return registry->slot_count; return registry->slot_count;
} }
const layout_slot_t *layout_registry_at(const layout_registry_t *registry, const layout_slot_t *
size_t index) { layout_registry_at(const layout_registry_t *registry, size_t index) {
if (index >= registry->slot_count) return nullptr; if (index >= registry->slot_count) return nullptr;
return &registry->slots[index]; return &registry->slots[index];
} }
layout_id_t layout_register(layout_registry_t *registry, const char *name, layout_id_t layout_register(
const char *symbol, const char *description, layout_registry_t *registry,
layout_fn fn) { const char *name,
const char *symbol,
const char *description,
layout_fn fn
) {
if (!name || !symbol) return ZDWM_LAYOUT_ID_INVALID; if (!name || !symbol) return ZDWM_LAYOUT_ID_INVALID;
layout_id_t id = (layout_id_t)registry->slot_count; layout_id_t id = (layout_id_t)registry->slot_count;
layout_slot_t *r = layout_slot_t *r =
array_push(registry->slots, registry->slot_count, registry->slot_capacity); array_push(registry->slots, registry->slot_count, registry->slot_capacity);
r->id = id; r->id = id;
r->name = p_strdup(name); r->name = p_strdup(name);
r->symbol = p_strdup(symbol); r->symbol = p_strdup(symbol);
r->description = p_strdup_nullable(description); r->description = p_strdup_nullable(description);
r->fn = fn; r->fn = fn;
return r->id; return r->id;
} }
@@ -82,8 +86,8 @@ layout_fn layout_get(const layout_registry_t *registry, layout_id_t id) {
return nullptr; return nullptr;
} }
const layout_slot_t *layout_slot_get(const layout_registry_t *registry, const layout_slot_t *
layout_id_t id) { layout_slot_get(const layout_registry_t *registry, layout_id_t id) {
if (id >= registry->slot_count) return nullptr; if (id >= registry->slot_count) return nullptr;
return &registry->slots[id]; return &registry->slots[id];
} }

View File

@@ -54,8 +54,8 @@ void layout_result_push(layout_result_t *result, layout_item_t item);
void layout_registry_cleanup(layout_registry_t *registry); void layout_registry_cleanup(layout_registry_t *registry);
bool layout_registry_move(layout_registry_t *src, layout_registry_t *dest); bool layout_registry_move(layout_registry_t *src, layout_registry_t *dest);
size_t layout_registry_count(const layout_registry_t *registry); size_t layout_registry_count(const layout_registry_t *registry);
const layout_slot_t *layout_registry_at(const layout_registry_t *registry, const layout_slot_t *
size_t index); layout_registry_at(const layout_registry_t *registry, size_t index);
/* /*
* 注册一个布局并返回其稳定 ID。 * 注册一个布局并返回其稳定 ID。
@@ -75,9 +75,13 @@ const layout_slot_t *layout_registry_at(const layout_registry_t *registry,
* *
* 注册成功后,布局 ID 与其在 registry 中的槽位索引保持一致。 * 注册成功后,布局 ID 与其在 registry 中的槽位索引保持一致。
*/ */
layout_id_t layout_register(layout_registry_t *registry, const char *name, layout_id_t layout_register(
const char *symbol, const char *description, layout_registry_t *registry,
layout_fn fn); const char *name,
const char *symbol,
const char *description,
layout_fn fn
);
/* /*
* 获取可执行的布局函数。 * 获取可执行的布局函数。
* *
@@ -87,5 +91,5 @@ layout_id_t layout_register(layout_registry_t *registry, const char *name,
* - slot 存在,但 fn == NULL表示 floating 布局) * - slot 存在,但 fn == NULL表示 floating 布局)
*/ */
layout_fn layout_get(const layout_registry_t *registry, layout_id_t id); layout_fn layout_get(const layout_registry_t *registry, layout_id_t id);
const layout_slot_t *layout_slot_get(const layout_registry_t *registry, const layout_slot_t *
layout_id_t id); layout_slot_get(const layout_registry_t *registry, layout_id_t id);

View File

@@ -12,11 +12,11 @@ void plan_reset(plan_t *plan) {
void plan_cleanup(plan_t *plan) { void plan_cleanup(plan_t *plan) {
p_delete(&plan->effects); p_delete(&plan->effects);
plan->count = 0; plan->count = 0;
plan->capacity = 0; plan->capacity = 0;
} }
void plan_push_effect(plan_t *plan, const effect_t *effect) { void plan_push_effect(plan_t *plan, const effect_t *effect) {
effect_t *eft = array_push(plan->effects, plan->count, plan->capacity); effect_t *eft = array_push(plan->effects, plan->count, plan->capacity);
*eft = *effect; *eft = *effect;
} }

View File

@@ -8,7 +8,7 @@
typedef uint32_t dirty_mask_t; typedef uint32_t dirty_mask_t;
typedef enum dirty_flags_t : dirty_mask_t { typedef enum dirty_flags_t : dirty_mask_t {
ZDWM_DIRTY_NONE = 0, ZDWM_DIRTY_NONE = 0,
ZDWM_DIRTY_LAYOUT = 1u << 0, ZDWM_DIRTY_LAYOUT = 1u << 0,
} dirty_flags_t; } dirty_flags_t;

View File

@@ -16,9 +16,12 @@ static workspace_id_t derive_window_workspace(const state_t *state) {
return state->outputs[state->current_output_index].current_workspace_id; return state->outputs[state->current_output_index].current_workspace_id;
} }
static bool route_map_request(const state_t *state, const rules_t *rules, static bool route_map_request(
const window_map_request_event_t *e, const state_t *state,
command_buffer_t *out) { const rules_t *rules,
const window_map_request_event_t *e,
command_buffer_t *out
) {
if (state_window_get(state, e->window)) return false; if (state_window_get(state, e->window)) return false;
layer_type_t layer_type = layer_classify(&e->props); layer_type_t layer_type = layer_classify(&e->props);
@@ -28,29 +31,27 @@ static bool route_map_request(const state_t *state, const rules_t *rules,
} }
command_t cmd = { command_t cmd = {
.type = ZDWM_COMMAND_MANAGE_WINDOW, .type = ZDWM_COMMAND_MANAGE_WINDOW,
.as.manage_window = .as.manage_window = {
{ .workspace = derive_window_workspace(state),
.workspace = derive_window_workspace(state), .info = {
.info = .id = e->window,
{ .transient_for = e->transient_for,
.id = e->window, .frame_rect = e->rect,
.transient_for = e->transient_for,
.frame_rect = e->rect,
.title = e->metadata.title, .title = e->metadata.title,
.app_id = e->metadata.app_id, .app_id = e->metadata.app_id,
.role = e->metadata.role, .role = e->metadata.role,
.class_name = e->metadata.class_name, .class_name = e->metadata.class_name,
.instance_name = e->metadata.instance_name, .instance_name = e->metadata.instance_name,
.geometry_mode = e->geometry_mode, .geometry_mode = e->geometry_mode,
.layer_type = layer_type, .layer_type = layer_type,
.urgent = e->urgent, .urgent = e->urgent,
.fixed_size = e->fixed_size, .fixed_size = e->fixed_size,
.skip_taskbar = e->skip_taskbar, .skip_taskbar = e->skip_taskbar,
},
}, },
},
}; };
rule_action_t action = {.workspace = ZDWM_WORKSPACE_ID_INVALID}; rule_action_t action = {.workspace = ZDWM_WORKSPACE_ID_INVALID};
@@ -73,17 +74,16 @@ static bool route_map_request(const state_t *state, const rules_t *rules,
command_buffer_push(out, &cmd); command_buffer_push(out, &cmd);
if (have_rule_match && action.switch_to_workspace) { if (have_rule_match && action.switch_to_workspace) {
workspace_id_t workspace_id = cmd.as.manage_window.workspace; workspace_id_t workspace_id = cmd.as.manage_window.workspace;
const workspace_t *workspace = state_workspace_get(state, workspace_id); const workspace_t *workspace = state_workspace_get(state, workspace_id);
if (workspace) { if (workspace) {
command_t switch_workspace_cmd = { command_t switch_workspace_cmd = {
.type = ZDWM_COMMAND_SWITCH_WORKSPACE, .type = ZDWM_COMMAND_SWITCH_WORKSPACE,
.as.switch_workspace = .as.switch_workspace = {
{ .output = workspace->output_id,
.output = workspace->output_id, .workspace = workspace_id,
.workspace = workspace_id, },
},
}; };
command_buffer_push(out, &switch_workspace_cmd); command_buffer_push(out, &switch_workspace_cmd);
@@ -95,17 +95,23 @@ static bool route_map_request(const state_t *state, const rules_t *rules,
bool policy_route_event(const policy_context_t *ctx, command_buffer_t *out) { bool policy_route_event(const policy_context_t *ctx, command_buffer_t *out) {
switch (ctx->event->type) { switch (ctx->event->type) {
case ZDWM_EVENT_WINDOW_MAP_REQUEST: case ZDWM_EVENT_WINDOW_MAP_REQUEST:
return route_map_request(ctx->state, ctx->rules, return route_map_request(
&ctx->event->as.window_map_request, out); ctx->state,
default: ctx->rules,
return false; &ctx->event->as.window_map_request,
out
);
default:
return false;
} }
} }
bool policy_apply_command(const policy_context_t *ctx, bool policy_apply_command(
const command_buffer_t *command_buffer, const policy_context_t *ctx,
plan_t *plan) { const command_buffer_t *command_buffer,
plan_t *plan
) {
/* TODO: */ /* TODO: */
return true; return true;
} }

View File

@@ -13,5 +13,8 @@ typedef struct policy_context_t {
} policy_context_t; } policy_context_t;
bool policy_route_event(const policy_context_t *ctx, command_buffer_t *out); bool policy_route_event(const policy_context_t *ctx, command_buffer_t *out);
bool policy_apply_command(const policy_context_t *ctx, bool policy_apply_command(
const command_buffer_t *command_buffer, plan_t *plan); const policy_context_t *ctx,
const command_buffer_t *command_buffer,
plan_t *plan
);

View File

@@ -10,12 +10,12 @@
bool rules_move(rules_t *src, rules_t *dest) { bool rules_move(rules_t *src, rules_t *dest) {
if (!dest || !src) return false; if (!dest || !src) return false;
dest->items = src->items; dest->items = src->items;
dest->count = src->count; dest->count = src->count;
dest->capacity = src->capacity; dest->capacity = src->capacity;
src->items = nullptr; src->items = nullptr;
src->count = 0; src->count = 0;
src->capacity = 0; src->capacity = 0;
return true; return true;
@@ -23,7 +23,7 @@ bool rules_move(rules_t *src, rules_t *dest) {
void rules_cleanup(rules_t *rules) { void rules_cleanup(rules_t *rules) {
for (size_t i = 0; i < rules->count; ++i) { for (size_t i = 0; i < rules->count; ++i) {
rule_match_t *match = &rules->items[i].match; rule_match_t *match = &rules->items[i].match;
rule_action_t *action = &rules->items[i].action; rule_action_t *action = &rules->items[i].action;
p_delete(&match->app_id); p_delete(&match->app_id);
@@ -37,15 +37,15 @@ void rules_cleanup(rules_t *rules) {
p_delete(&rules->items); p_delete(&rules->items);
rules->capacity = 0; rules->capacity = 0;
rules->count = 0; rules->count = 0;
} }
static inline bool str_match(const char *pattern, const char *value) { static inline bool str_match(const char *pattern, const char *value) {
return !pattern || (value && strcmp(pattern, value) == 0); return !pattern || (value && strcmp(pattern, value) == 0);
} }
static bool rule_match_window(const rule_match_t *match, static bool
const window_metadata_t *meta) { rule_match_window(const rule_match_t *match, const window_metadata_t *meta) {
return str_match(match->app_id, meta->app_id) && return str_match(match->app_id, meta->app_id) &&
str_match(match->role, meta->role) && str_match(match->role, meta->role) &&
str_match(match->class_name, meta->class_name) && str_match(match->class_name, meta->class_name) &&
@@ -59,13 +59,16 @@ static void rule_action_merge(const rule_action_t *src, rule_action_t *dest) {
dest->workspace = src->workspace; dest->workspace = src->workspace;
} }
dest->switch_to_workspace |= src->switch_to_workspace; dest->switch_to_workspace |= src->switch_to_workspace;
dest->fullscreen |= src->fullscreen; dest->fullscreen |= src->fullscreen;
dest->maximize |= src->maximize; dest->maximize |= src->maximize;
dest->floating |= src->floating; dest->floating |= src->floating;
} }
bool rules_resolve(const rules_t *rules, const window_metadata_t *metadata, bool rules_resolve(
rule_action_t *action_out) { const rules_t *rules,
const window_metadata_t *metadata,
rule_action_t *action_out
) {
if (!action_out) return false; if (!action_out) return false;
bool matched = false; bool matched = false;

View File

@@ -19,5 +19,8 @@ typedef struct rules_t {
bool rules_move(rules_t *src, rules_t *dest); bool rules_move(rules_t *src, rules_t *dest);
void rules_cleanup(rules_t *rules); void rules_cleanup(rules_t *rules);
bool rules_resolve(const rules_t *rules, const window_metadata_t *metadata, bool rules_resolve(
rule_action_t *action_out); const rules_t *rules,
const window_metadata_t *metadata,
rule_action_t *action_out
);

View File

@@ -14,7 +14,9 @@
#include "core/wm_desc.h" #include "core/wm_desc.h"
static bool runtime_workspace_desc_has_valid_layouts( static bool runtime_workspace_desc_has_valid_layouts(
const layout_registry_t *layouts, const workspace_desc_t *workspace) { const layout_registry_t *layouts,
const workspace_desc_t *workspace
) {
if (!layouts || !workspace) return false; if (!layouts || !workspace) return false;
for (size_t i = 0; i < workspace->layout_count; i++) { for (size_t i = 0; i < workspace->layout_count; i++) {
@@ -50,14 +52,19 @@ bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc) {
layout_registry_move(&desc->layouts, &runtime->layouts); layout_registry_move(&desc->layouts, &runtime->layouts);
rules_move(&desc->rules, &runtime->rules); rules_move(&desc->rules, &runtime->rules);
runtime->config_module_handle = desc->config_module_handle; runtime->config_module_handle = desc->config_module_handle;
desc->backend = nullptr; desc->backend = nullptr;
desc->config_module_handle = nullptr; desc->config_module_handle = nullptr;
state_init(&runtime->state, desc->outputs, desc->output_count, state_init(
desc->workspaces, desc->workspace_count); &runtime->state,
desc->outputs,
desc->output_count,
desc->workspaces,
desc->workspace_count
);
workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count); workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count);
desc->outputs = nullptr; desc->outputs = nullptr;
desc->output_count = 0; desc->output_count = 0;
return true; return true;
@@ -77,7 +84,7 @@ void runtime_init_desc_cleanup(runtime_init_desc_t *desc) {
} }
workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count); workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count);
desc->outputs = nullptr; desc->outputs = nullptr;
desc->output_count = 0; desc->output_count = 0;
if (desc->config_module_handle) dlclose(desc->config_module_handle); if (desc->config_module_handle) dlclose(desc->config_module_handle);
desc->config_module_handle = nullptr; desc->config_module_handle = nullptr;
@@ -99,9 +106,9 @@ void runtime_shutdown(runtime_t *runtime) {
void runtime_run(runtime_t *runtime) { void runtime_run(runtime_t *runtime) {
runtime->running = true; runtime->running = true;
backend_t *backend = runtime->backend; backend_t *backend = runtime->backend;
command_buffer_t *command_buffer = &runtime->command_buffer; command_buffer_t *command_buffer = &runtime->command_buffer;
plan_t *plan = &runtime->plan; plan_t *plan = &runtime->plan;
while (runtime->running) { while (runtime->running) {
event_t event = {0}; event_t event = {0};

View File

@@ -13,21 +13,25 @@
#include "core/types.h" #include "core/types.h"
#include "core/wm_desc.h" #include "core/wm_desc.h"
void state_init(state_t *state, const output_info_t *outputs, void state_init(
size_t output_count, const workspace_desc_t *workspaces, state_t *state,
size_t workspace_count) { const output_info_t *outputs,
size_t output_count,
const workspace_desc_t *workspaces,
size_t workspace_count
) {
p_clear(state, 1); p_clear(state, 1);
state->outputs = p_new(output_t, output_count); state->outputs = p_new(output_t, output_count);
for (size_t i = 0; i < output_count; i++) { for (size_t i = 0; i < output_count; i++) {
const output_info_t *output_info = &outputs[i]; const output_info_t *output_info = &outputs[i];
output_t *output = &state->outputs[i]; output_t *output = &state->outputs[i];
output->id = (output_id_t)i; output->id = (output_id_t)i;
output->current_workspace_id = ZDWM_WORKSPACE_ID_INVALID; output->current_workspace_id = ZDWM_WORKSPACE_ID_INVALID;
output->name = p_strdup_nullable(output_info->name); output->name = p_strdup_nullable(output_info->name);
output->geometry = output_info->geometry; output->geometry = output_info->geometry;
output->workarea = output_info->geometry; output->workarea = output_info->geometry;
} }
state->output_count = output_count; state->output_count = output_count;
@@ -38,16 +42,16 @@ void state_init(state_t *state, const output_info_t *outputs,
fatal("workspace desc at index %zu invalid", i); fatal("workspace desc at index %zu invalid", i);
} }
output_t *output = &state->outputs[workspace_desc->output_index]; output_t *output = &state->outputs[workspace_desc->output_index];
workspace_t *workspace = &state->workspaces[i]; workspace_t *workspace = &state->workspaces[i];
workspace->id = (workspace_id_t)i; workspace->id = (workspace_id_t)i;
workspace->output_id = output->id; workspace->output_id = output->id;
workspace->focused_window_id = ZDWM_WINDOW_ID_INVALID; workspace->focused_window_id = ZDWM_WINDOW_ID_INVALID;
workspace->available_layouts = workspace->available_layouts =
p_copy(workspace_desc->layout_ids, workspace_desc->layout_count); p_copy(workspace_desc->layout_ids, workspace_desc->layout_count);
workspace->layout_id = workspace_desc->initial_layout_id; workspace->layout_id = workspace_desc->initial_layout_id;
workspace->layout_count = workspace_desc->layout_count; workspace->layout_count = workspace_desc->layout_count;
workspace->name = p_strdup(workspace_desc->name); workspace->name = p_strdup(workspace_desc->name);
if (output->current_workspace_id == ZDWM_WORKSPACE_ID_INVALID) { if (output->current_workspace_id == ZDWM_WORKSPACE_ID_INVALID) {
output->current_workspace_id = workspace->id; output->current_workspace_id = workspace->id;
@@ -79,7 +83,7 @@ void state_cleanup(state_t *state) {
for (size_t i = 0; i < ZDWM_WINDOW_LAYER_COUNT; ++i) { for (size_t i = 0; i < ZDWM_WINDOW_LAYER_COUNT; ++i) {
layer_stack_t *layer = &state->stacks[i]; layer_stack_t *layer = &state->stacks[i];
p_delete(&layer->order); p_delete(&layer->order);
layer->order = 0; layer->order = 0;
layer->capacity = 0; layer->capacity = 0;
} }
@@ -102,8 +106,8 @@ void state_cleanup(state_t *state) {
p_clear(state, 1); p_clear(state, 1);
} }
const workspace_t *state_workspace_get(const state_t *state, const workspace_t *
workspace_id_t id) { state_workspace_get(const state_t *state, workspace_id_t id) {
if (id < state->workspace_count) return &state->workspaces[id]; if (id < state->workspace_count) return &state->workspaces[id];
return nullptr; return nullptr;
} }
@@ -113,8 +117,10 @@ const workspace_t *state_workspace_at(const state_t *state, size_t index) {
return nullptr; return nullptr;
} }
static void state_workspace_adjust_focused_window(const state_t *state, static void state_workspace_adjust_focused_window(
workspace_id_t workspace_id) { const state_t *state,
workspace_id_t workspace_id
) {
workspace_t *workspace = workspace_t *workspace =
(workspace_t *)state_workspace_get(state, workspace_id); (workspace_t *)state_workspace_get(state, workspace_id);
if (!workspace) return; if (!workspace) return;
@@ -127,7 +133,7 @@ static void state_workspace_adjust_focused_window(const state_t *state,
const layer_stack_t *layer = &state->stacks[i]; const layer_stack_t *layer = &state->stacks[i];
for (size_t i = layer->count; i > 0; --i) { for (size_t i = layer->count; i > 0; --i) {
window_id_t window_id = layer->order[i - 1]; window_id_t window_id = layer->order[i - 1];
window = state_window_get(state, window_id); window = state_window_get(state, window_id);
if (window && window->workspace_id == workspace_id) { if (window && window->workspace_id == workspace_id) {
workspace->focused_window_id = window_id; workspace->focused_window_id = window_id;
return; return;
@@ -144,25 +150,27 @@ bool state_workspace_cycle_layout(state_t *state, workspace_id_t workspace_id) {
if (!workspace) return false; if (!workspace) return false;
size_t next_index = 0; size_t next_index = 0;
bool matched = false; bool matched = false;
for (size_t i = 0; i < workspace->layout_count; i++) { for (size_t i = 0; i < workspace->layout_count; i++) {
if (workspace->layout_id == workspace->available_layouts[i]) { if (workspace->layout_id == workspace->available_layouts[i]) {
next_index = (i + 1) % workspace->layout_count; next_index = (i + 1) % workspace->layout_count;
matched = true; matched = true;
break; break;
} }
} }
if (!matched) return false; if (!matched) return false;
auto next_layout_id = workspace->available_layouts[next_index]; auto next_layout_id = workspace->available_layouts[next_index];
workspace->layout_id = next_layout_id; workspace->layout_id = next_layout_id;
return true; return true;
} }
bool state_workspace_set_layout_by_index(state_t *state, bool state_workspace_set_layout_by_index(
workspace_id_t workspace_id, state_t *state,
size_t index) { workspace_id_t workspace_id,
size_t index
) {
workspace_t *workspace = workspace_t *workspace =
(workspace_t *)state_workspace_get(state, workspace_id); (workspace_t *)state_workspace_get(state, workspace_id);
if (!workspace) return false; if (!workspace) return false;
@@ -172,9 +180,11 @@ bool state_workspace_set_layout_by_index(state_t *state,
return true; return true;
} }
bool state_workspace_set_layout_by_id(state_t *state, bool state_workspace_set_layout_by_id(
workspace_id_t workspace_id, state_t *state,
layout_id_t layout_id) { workspace_id_t workspace_id,
layout_id_t layout_id
) {
workspace_t *workspace = workspace_t *workspace =
(workspace_t *)state_workspace_get(state, workspace_id); (workspace_t *)state_workspace_get(state, workspace_id);
if (!workspace) return false; if (!workspace) return false;
@@ -188,9 +198,11 @@ bool state_workspace_set_layout_by_id(state_t *state,
return false; return false;
} }
void state_workspace_set_focused_window(state_t *state, void state_workspace_set_focused_window(
workspace_id_t workspace_id, state_t *state,
window_id_t window_id) { workspace_id_t workspace_id,
window_id_t window_id
) {
workspace_t *workspace = workspace_t *workspace =
(workspace_t *)state_workspace_get(state, workspace_id); (workspace_t *)state_workspace_get(state, workspace_id);
if (!workspace) return; if (!workspace) return;
@@ -235,14 +247,20 @@ const output_t *state_output_at(const state_t *state, size_t index) {
return nullptr; return nullptr;
} }
void state_output_set_workarea(state_t *state, output_id_t output_id, void state_output_set_workarea(
rect_t workarea) { state_t *state,
output_id_t output_id,
rect_t workarea
) {
output_t *output = (output_t *)state_output_get(state, output_id); output_t *output = (output_t *)state_output_get(state, output_id);
if (output) output->workarea = workarea; if (output) output->workarea = workarea;
} }
void state_output_set_current_workspace(state_t *state, output_id_t output_id, void state_output_set_current_workspace(
workspace_id_t workspace_id) { state_t *state,
output_id_t output_id,
workspace_id_t workspace_id
) {
output_t *output = (output_t *)state_output_get(state, output_id); output_t *output = (output_t *)state_output_get(state, output_id);
if (!output) return; if (!output) return;
const workspace_t *workspace = state_workspace_get(state, workspace_id); const workspace_t *workspace = state_workspace_get(state, workspace_id);
@@ -269,15 +287,17 @@ bool state_output_valid(const state_t *state, output_id_t id) {
} }
void state_cycle_current_output(state_t *state, int delta) { void state_cycle_current_output(state_t *state, int delta) {
int64_t count = (int64_t)state->output_count; int64_t count = (int64_t)state->output_count;
int64_t current = (int64_t)state->current_output_index; int64_t current = (int64_t)state->current_output_index;
int64_t next = (current + (int64_t)delta) % count; int64_t next = (current + (int64_t)delta) % count;
if (next < 0) next += count; if (next < 0) next += count;
state->current_output_index = (size_t)next; state->current_output_index = (size_t)next;
} }
static inline void window_set_geometry_mode( static inline void window_set_geometry_mode(
window_t *window, window_geometry_mode_t geometry_mode) { window_t *window,
window_geometry_mode_t geometry_mode
) {
window->geometry_mode = geometry_mode; window->geometry_mode = geometry_mode;
} }
static inline void window_set_floating(window_t *window, bool floating) { static inline void window_set_floating(window_t *window, bool floating) {
@@ -317,18 +337,18 @@ static inline void window_set_class(window_t *window, const char *class_name) {
p_delete(&window->class_name); p_delete(&window->class_name);
window->class_name = p_strdup_nullable(class_name); window->class_name = p_strdup_nullable(class_name);
} }
static inline void window_set_instance(window_t *window, static inline void
const char *instance_name) { window_set_instance(window_t *window, const char *instance_name) {
p_delete(&window->instance_name); p_delete(&window->instance_name);
window->instance_name = p_strdup_nullable(instance_name); window->instance_name = p_strdup_nullable(instance_name);
} }
static inline void window_set_skip_taskbar(window_t *window, static inline void
bool skip_taskbar) { window_set_skip_taskbar(window_t *window, bool skip_taskbar) {
window->skip_taskbar = skip_taskbar; window->skip_taskbar = skip_taskbar;
} }
const window_t *state_window_add(state_t *state, const window_info_t *info) { const window_t *state_window_add(state_t *state, const window_info_t *info) {
window_id_t id = info->id; window_id_t id = info->id;
window_t *window = (window_t *)state_window_get(state, id); window_t *window = (window_t *)state_window_get(state, id);
if (!window) { if (!window) {
window = window =
@@ -338,10 +358,10 @@ const window_t *state_window_add(state_t *state, const window_info_t *info) {
layer_stack_append(layer, id); layer_stack_append(layer, id);
p_clear(window, 1); p_clear(window, 1);
window->id = id; window->id = id;
window->transient_for = info->transient_for; window->transient_for = info->transient_for;
window->workspace_id = ZDWM_WORKSPACE_ID_INVALID; window->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
window->layer = info->layer_type; window->layer = info->layer_type;
} }
window_set_geometry_mode(window, info->geometry_mode); window_set_geometry_mode(window, info->geometry_mode);
@@ -378,14 +398,14 @@ void state_window_remove(state_t *state, window_id_t id) {
for (size_t i = 0; i < state->window_count; i++) { for (size_t i = 0; i < state->window_count; i++) {
if (state->windows[i].id == id) { if (state->windows[i].id == id) {
matched = true; matched = true;
index = i; index = i;
break; break;
} }
} }
if (!matched) return; if (!matched) return;
window_t *window = &state->windows[index]; window_t *window = &state->windows[index];
layer_type_t layer_type = window->layer; layer_type_t layer_type = window->layer;
workspace_id_t workspace_id = window->workspace_id; workspace_id_t workspace_id = window->workspace_id;
p_delete(&window->title); p_delete(&window->title);
p_delete(&window->app_id); p_delete(&window->app_id);
@@ -398,7 +418,7 @@ void state_window_remove(state_t *state, window_id_t id) {
} }
window = &state->windows[state->window_count - 1]; window = &state->windows[state->window_count - 1];
p_clear(window, 1); p_clear(window, 1);
window->id = ZDWM_WINDOW_ID_INVALID; window->id = ZDWM_WINDOW_ID_INVALID;
window->workspace_id = ZDWM_WORKSPACE_ID_INVALID; window->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
state->window_count--; state->window_count--;
@@ -416,13 +436,16 @@ void state_window_remove(state_t *state, window_id_t id) {
size_t state_window_count(const state_t *state) { return state->window_count; } size_t state_window_count(const state_t *state) { return state->window_count; }
void state_window_set_workspace(state_t *state, window_id_t window_id, void state_window_set_workspace(
workspace_id_t workspace_id) { state_t *state,
window_id_t window_id,
workspace_id_t workspace_id
) {
const workspace_t *workspace = state_workspace_get(state, workspace_id); const workspace_t *workspace = state_workspace_get(state, workspace_id);
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (!workspace || !window || window->workspace_id == workspace_id) return; if (!workspace || !window || window->workspace_id == workspace_id) return;
workspace = state_workspace_get(state, window->workspace_id); workspace = state_workspace_get(state, window->workspace_id);
window->workspace_id = workspace_id; window->workspace_id = workspace_id;
if (workspace && workspace->focused_window_id == window_id) { if (workspace && workspace->focused_window_id == window_id) {
@@ -432,57 +455,84 @@ void state_window_set_workspace(state_t *state, window_id_t window_id,
state_workspace_adjust_focused_window(state, workspace_id); state_workspace_adjust_focused_window(state, workspace_id);
} }
void state_window_set_geometry_mode(state_t *state, window_id_t window_id, void state_window_set_geometry_mode(
window_geometry_mode_t geometry_mode) { state_t *state,
window_id_t window_id,
window_geometry_mode_t geometry_mode
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (window) window_set_geometry_mode(window, geometry_mode); if (window) window_set_geometry_mode(window, geometry_mode);
} }
void state_window_set_floating(state_t *state, window_id_t window_id, void state_window_set_floating(
bool floating) { state_t *state,
window_id_t window_id,
bool floating
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (window) window_set_floating(window, floating); if (window) window_set_floating(window, floating);
} }
void state_window_set_sticky(state_t *state, window_id_t window_id, void state_window_set_sticky(
bool sticky) { state_t *state,
window_id_t window_id,
bool sticky
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (window) window_set_sticky(window, sticky); if (window) window_set_sticky(window, sticky);
} }
void state_window_set_urgent(state_t *state, window_id_t window_id, void state_window_set_urgent(
bool urgent) { state_t *state,
window_id_t window_id,
bool urgent
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (window) window_set_urgent(window, urgent); if (window) window_set_urgent(window, urgent);
} }
void state_window_set_fixed_size(state_t *state, window_id_t window_id, void state_window_set_fixed_size(
bool fixed_size) { state_t *state,
window_id_t window_id,
bool fixed_size
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (window) window_set_fixed_size(window, fixed_size); if (window) window_set_fixed_size(window, fixed_size);
} }
void state_window_set_skip_taskbar(state_t *state, window_id_t window_id, void state_window_set_skip_taskbar(
bool skip_taskbar) { state_t *state,
window_id_t window_id,
bool skip_taskbar
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (window) window_set_skip_taskbar(window, skip_taskbar); if (window) window_set_skip_taskbar(window, skip_taskbar);
} }
void state_window_set_float_rect(state_t *state, window_id_t window_id, void state_window_set_float_rect(
rect_t float_rect) { state_t *state,
window_id_t window_id,
rect_t float_rect
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (window) window_set_float_rect(window, float_rect); if (window) window_set_float_rect(window, float_rect);
} }
void state_window_set_frame_rect(state_t *state, window_id_t window_id, void state_window_set_frame_rect(
rect_t frame_rect) { state_t *state,
window_id_t window_id,
rect_t frame_rect
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (window) window_set_frame_rect(window, frame_rect); if (window) window_set_frame_rect(window, frame_rect);
} }
bool state_window_take_metadata(state_t *state, window_id_t window_id, bool state_window_take_metadata(
window_metadata_t *metadata, state_t *state,
uint32_t changed_fields) { window_id_t window_id,
window_metadata_t *metadata,
uint32_t changed_fields
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (!window) return false; if (!window) return false;
@@ -505,8 +555,11 @@ bool state_window_take_metadata(state_t *state, window_id_t window_id,
return true; return true;
} }
bool state_window_set_title(state_t *state, window_id_t window_id, bool state_window_set_title(
const char *title) { state_t *state,
window_id_t window_id,
const char *title
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (!window) return false; if (!window) return false;
@@ -514,8 +567,11 @@ bool state_window_set_title(state_t *state, window_id_t window_id,
return true; return true;
} }
bool state_window_set_app_id(state_t *state, window_id_t window_id, bool state_window_set_app_id(
const char *app_id) { state_t *state,
window_id_t window_id,
const char *app_id
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (!window) return false; if (!window) return false;
@@ -523,8 +579,11 @@ bool state_window_set_app_id(state_t *state, window_id_t window_id,
return true; return true;
} }
bool state_window_set_role(state_t *state, window_id_t window_id, bool state_window_set_role(
const char *role) { state_t *state,
window_id_t window_id,
const char *role
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (!window) return false; if (!window) return false;
@@ -532,8 +591,11 @@ bool state_window_set_role(state_t *state, window_id_t window_id,
return true; return true;
} }
bool state_window_set_class(state_t *state, window_id_t window_id, bool state_window_set_class(
const char *class_name) { state_t *state,
window_id_t window_id,
const char *class_name
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (!window) return false; if (!window) return false;
@@ -541,8 +603,11 @@ bool state_window_set_class(state_t *state, window_id_t window_id,
return true; return true;
} }
bool state_window_set_instance(state_t *state, window_id_t window_id, bool state_window_set_instance(
const char *instance_name) { state_t *state,
window_id_t window_id,
const char *instance_name
) {
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (!window) return false; if (!window) return false;

View File

@@ -90,9 +90,13 @@ typedef struct state_t {
* 每个 output 的 current_workspace_id 会自动设置为首个归属到该 output 的 * 每个 output 的 current_workspace_id 会自动设置为首个归属到该 output 的
* workspace若某个 output 没有任何归属 workspacestate_init() 会失败。 * workspace若某个 output 没有任何归属 workspacestate_init() 会失败。
*/ */
void state_init(state_t *state, const output_info_t *outputs, void state_init(
size_t output_count, const workspace_desc_t *workspaces, state_t *state,
size_t workspace_count); const output_info_t *outputs,
size_t output_count,
const workspace_desc_t *workspaces,
size_t workspace_count
);
void state_cleanup(state_t *state); void state_cleanup(state_t *state);
/* /*
@@ -104,15 +108,21 @@ void state_cleanup(state_t *state);
const workspace_t *state_workspace_get(const state_t *state, workspace_id_t id); const workspace_t *state_workspace_get(const state_t *state, workspace_id_t id);
const workspace_t *state_workspace_at(const state_t *state, size_t index); const workspace_t *state_workspace_at(const state_t *state, size_t index);
bool state_workspace_cycle_layout(state_t *state, workspace_id_t workspace_id); bool state_workspace_cycle_layout(state_t *state, workspace_id_t workspace_id);
bool state_workspace_set_layout_by_index(state_t *state, bool state_workspace_set_layout_by_index(
workspace_id_t workspace_id, state_t *state,
size_t index); workspace_id_t workspace_id,
bool state_workspace_set_layout_by_id(state_t *state, size_t index
workspace_id_t workspace_id, );
layout_id_t layout_id); bool state_workspace_set_layout_by_id(
void state_workspace_set_focused_window(state_t *state, state_t *state,
workspace_id_t workspace_id, workspace_id_t workspace_id,
window_id_t window_id); layout_id_t layout_id
);
void state_workspace_set_focused_window(
state_t *state,
workspace_id_t workspace_id,
window_id_t window_id
);
size_t state_workspace_count(const state_t *state); size_t state_workspace_count(const state_t *state);
bool state_workspace_valid(const state_t *state, workspace_id_t id); bool state_workspace_valid(const state_t *state, workspace_id_t id);
@@ -124,10 +134,16 @@ bool state_workspace_valid(const state_t *state, workspace_id_t id);
*/ */
const output_t *state_output_get(const state_t *state, output_id_t id); const output_t *state_output_get(const state_t *state, output_id_t id);
const output_t *state_output_at(const state_t *state, size_t index); const output_t *state_output_at(const state_t *state, size_t index);
void state_output_set_workarea(state_t *state, output_id_t output_id, void state_output_set_workarea(
rect_t workarea); state_t *state,
void state_output_set_current_workspace(state_t *state, output_id_t output_id, output_id_t output_id,
workspace_id_t workspace_id); rect_t workarea
);
void state_output_set_current_workspace(
state_t *state,
output_id_t output_id,
workspace_id_t workspace_id
);
size_t state_output_count(const state_t *state); size_t state_output_count(const state_t *state);
bool state_output_valid(const state_t *state, output_id_t id); bool state_output_valid(const state_t *state, output_id_t id);
void state_cycle_current_output(state_t *state, int delta); void state_cycle_current_output(state_t *state, int delta);
@@ -153,24 +169,51 @@ void state_window_remove(state_t *state, window_id_t id);
size_t state_window_count(const state_t *state); size_t state_window_count(const state_t *state);
/* state 持有的单个 window 状态更新接口 */ /* state 持有的单个 window 状态更新接口 */
void state_window_set_workspace(state_t *state, window_id_t window_id, void state_window_set_workspace(
workspace_id_t workspace_id); state_t *state,
void state_window_set_geometry_mode(state_t *state, window_id_t window_id, window_id_t window_id,
window_geometry_mode_t geometry_mode); workspace_id_t workspace_id
void state_window_set_floating(state_t *state, window_id_t window_id, );
bool floating); void state_window_set_geometry_mode(
void state_window_set_sticky(state_t *state, window_id_t window_id, state_t *state,
bool sticky); window_id_t window_id,
void state_window_set_urgent(state_t *state, window_id_t window_id, window_geometry_mode_t geometry_mode
bool urgent); );
void state_window_set_fixed_size(state_t *state, window_id_t window_id, void state_window_set_floating(
bool fixed_size); state_t *state,
void state_window_set_skip_taskbar(state_t *state, window_id_t window_id, window_id_t window_id,
bool skip_taskbar); bool floating
void state_window_set_float_rect(state_t *state, window_id_t window_id, );
rect_t float_rect); void state_window_set_sticky(
void state_window_set_frame_rect(state_t *state, window_id_t window_id, state_t *state,
rect_t frame_rect); window_id_t window_id,
bool sticky
);
void state_window_set_urgent(
state_t *state,
window_id_t window_id,
bool urgent
);
void state_window_set_fixed_size(
state_t *state,
window_id_t window_id,
bool fixed_size
);
void state_window_set_skip_taskbar(
state_t *state,
window_id_t window_id,
bool skip_taskbar
);
void state_window_set_float_rect(
state_t *state,
window_id_t window_id,
rect_t float_rect
);
void state_window_set_frame_rect(
state_t *state,
window_id_t window_id,
rect_t frame_rect
);
/** /**
* @brief 按字段掩码转移窗口元数据的所有权 * @brief 按字段掩码转移窗口元数据的所有权
* @param state 状态实例指针 * @param state 状态实例指针
@@ -185,19 +228,37 @@ void state_window_set_frame_rect(state_t *state, window_id_t window_id,
* 失败时,不接管 metadata 中任何字段的所有权metadata 保持不变,仍由调用方负 * 失败时,不接管 metadata 中任何字段的所有权metadata 保持不变,仍由调用方负
* 责后续访问与释放。 * 责后续访问与释放。
*/ */
bool state_window_take_metadata(state_t *state, window_id_t window_id, bool state_window_take_metadata(
window_metadata_t *metadata, state_t *state,
uint32_t changed_fields); window_id_t window_id,
bool state_window_set_title(state_t *state, window_id_t window_id, window_metadata_t *metadata,
const char *title); uint32_t changed_fields
bool state_window_set_app_id(state_t *state, window_id_t window_id, );
const char *app_id); bool state_window_set_title(
bool state_window_set_role(state_t *state, window_id_t window_id, state_t *state,
const char *role); window_id_t window_id,
bool state_window_set_class(state_t *state, window_id_t window_id, const char *title
const char *class_name); );
bool state_window_set_instance(state_t *state, window_id_t window_id, bool state_window_set_app_id(
const char *instance_name); state_t *state,
window_id_t window_id,
const char *app_id
);
bool state_window_set_role(
state_t *state,
window_id_t window_id,
const char *role
);
bool state_window_set_class(
state_t *state,
window_id_t window_id,
const char *class_name
);
bool state_window_set_instance(
state_t *state,
window_id_t window_id,
const char *instance_name
);
bool state_stack_raise(state_t *state, window_id_t window_id); bool state_stack_raise(state_t *state, window_id_t window_id);
bool state_stack_lower(state_t *state, window_id_t window_id); bool state_stack_lower(state_t *state, window_id_t window_id);

View File

@@ -42,13 +42,13 @@ static inline void workspace_desc_cleanup(workspace_desc_t *workspace) {
p_delete(&workspace->name); p_delete(&workspace->name);
p_delete(&workspace->layout_ids); p_delete(&workspace->layout_ids);
workspace->output_index = 0; workspace->output_index = 0;
workspace->layout_count = 0; workspace->layout_count = 0;
workspace->initial_layout_id = ZDWM_LAYOUT_ID_INVALID; workspace->initial_layout_id = ZDWM_LAYOUT_ID_INVALID;
} }
static inline void workspace_desc_list_cleanup(workspace_desc_t **list, static inline void
size_t *count) { workspace_desc_list_cleanup(workspace_desc_t **list, size_t *count) {
if (!list || !count) return; if (!list || !count) return;
for (size_t i = 0; i < *count; i++) { for (size_t i = 0; i < *count; i++) {
@@ -65,7 +65,8 @@ static inline void workspace_desc_list_cleanup(workspace_desc_t **list,
* 这组接口只校验描述表自身的一致性,不访问 state。 * 这组接口只校验描述表自身的一致性,不访问 state。
*/ */
static inline bool workspace_desc_layouts_valid( static inline bool workspace_desc_layouts_valid(
const workspace_desc_t *workspace) { const workspace_desc_t *workspace
) {
if (!workspace || !workspace->layout_count || !workspace->layout_ids) { if (!workspace || !workspace->layout_count || !workspace->layout_ids) {
return false; return false;
} }
@@ -77,8 +78,8 @@ static inline bool workspace_desc_layouts_valid(
return false; return false;
} }
static inline bool workspace_desc_valid(const workspace_desc_t *workspace, static inline bool
size_t output_count) { workspace_desc_valid(const workspace_desc_t *workspace, size_t output_count) {
if (!workspace || !workspace->name) return false; if (!workspace || !workspace->name) return false;
if (workspace->output_index >= output_count) return false; if (workspace->output_index >= output_count) return false;

View File

@@ -35,7 +35,7 @@ static const config_status_item_t status_list[] = {
.type = status_net_down, .type = status_net_down,
.icon_type = icon_type_image, .icon_type = icon_type_image,
.icon = "/home/zedhugh/develop/zswm/src/resources/icons/" .icon = "/home/zedhugh/develop/zswm/src/resources/icons/"
"corner-left-down-line.png", "corner-left-down-line.png",
.color = "#87af5f", .color = "#87af5f",
}, },
{ {
@@ -91,9 +91,9 @@ static const button_t button_list[] = {
}; };
#define TAGKEYS(KEY, TAG) \ #define TAGKEYS(KEY, TAG) \
{modifier_super, KEY, select_tag_of_current_monitor, {.ui = TAG}}, { \ {modifier_super, KEY, select_tag_of_current_monitor, {.ui = TAG}}, { \
modifier_super | modifier_shift, KEY, send_client_to_tag, {.ui = TAG}, \ modifier_super | modifier_shift, KEY, send_client_to_tag, {.ui = TAG}, \
} }
static const char launcher[] = static const char launcher[] =
"rofi -show combi -modes combi -combi-modes window,drun,run,ssh,windowcd"; "rofi -show combi -modes combi -combi-modes window,drun,run,ssh,windowcd";

View File

@@ -113,7 +113,8 @@ static image_cache_entry_t *image_cache_get(const char *path) {
entry->surface = nullptr; entry->surface = nullptr;
} }
if (!image_load_surface(path, &entry->surface, &entry->width, &entry->height)) { if (!image_load_surface(path, &entry->surface, &entry->width,
&entry->height)) {
return nullptr; return nullptr;
} }
return entry; return entry;

View File

@@ -17,7 +17,8 @@ size_t rect_subtract(rect_t source, rect_t clip, rect_t remaining[4]);
* @param source 源矩形 * @param source 源矩形
* @param clips 要减去的矩形数组,可为 nullptr * @param clips 要减去的矩形数组,可为 nullptr
* @param clip_count clips 的长度 * @param clip_count clips 的长度
* @param remaining 输出剩余矩形数组;若不为 nullptr则由函数分配内存并由调用方释放 * @param remaining 输出剩余矩形数组;若不为
* nullptr则由函数分配内存并由调用方释放
* @return 剩余矩形数量 * @return 剩余矩形数量
* *
* @code{.c} * @code{.c}

View File

@@ -123,7 +123,8 @@ static void tray_get_icon_layout(const tray_icon_t *icon, uint16_t *width,
} }
static uint16_t tray_compute_width(void) { static uint16_t tray_compute_width(void) {
if (!tray.initialized || tray.host_monitor == nullptr || tray.icon_count == 0) { if (!tray.initialized || tray.host_monitor == nullptr ||
tray.icon_count == 0) {
return 0; return 0;
} }
@@ -163,11 +164,10 @@ static void tray_select_icon_events(xcb_window_t window) {
xcb_params_cw_t params = { xcb_params_cw_t params = {
.back_pixel = wm.color_set.bar_bg.argb, .back_pixel = wm.color_set.bar_bg.argb,
.border_pixel = 0, .border_pixel = 0,
.event_mask = XCB_EVENT_MASK_PROPERTY_CHANGE | .event_mask =
XCB_EVENT_MASK_STRUCTURE_NOTIFY, XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY,
}; };
uint32_t mask = uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK;
XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK;
xcb_aux_change_window_attributes(wm.xcb_conn, window, mask, &params); xcb_aux_change_window_attributes(wm.xcb_conn, window, mask, &params);
xcb_clear_area(wm.xcb_conn, false, window, 0, 0, 0, 0); xcb_clear_area(wm.xcb_conn, false, window, 0, 0, 0, 0);
} }
@@ -180,9 +180,9 @@ static void tray_release_icon_window(tray_icon_t *icon) {
.event_mask = XCB_EVENT_MASK_NO_EVENT, .event_mask = XCB_EVENT_MASK_NO_EVENT,
.border_pixel = 0, .border_pixel = 0,
}; };
xcb_aux_change_window_attributes( xcb_aux_change_window_attributes(wm.xcb_conn, icon->window,
wm.xcb_conn, icon->window, XCB_CW_EVENT_MASK | XCB_CW_BORDER_PIXEL, XCB_CW_EVENT_MASK | XCB_CW_BORDER_PIXEL,
&params); &params);
xcb_reparent_window(wm.xcb_conn, icon->window, wm.screen->root, 0, 0); xcb_reparent_window(wm.xcb_conn, icon->window, wm.screen->root, 0, 0);
} }
@@ -299,7 +299,8 @@ static void tray_add_icon(xcb_window_t window) {
static bool tray_create_window(void) { static bool tray_create_window(void) {
static xcb_colormap_t colormap = XCB_NONE; static xcb_colormap_t colormap = XCB_NONE;
if (tray.host_monitor == nullptr || tray.host_monitor->bar_window == XCB_NONE) { if (tray.host_monitor == nullptr ||
tray.host_monitor->bar_window == XCB_NONE) {
return false; return false;
} }
@@ -319,8 +320,8 @@ static bool tray_create_window(void) {
const xcb_create_window_value_list_t value_list = { const xcb_create_window_value_list_t value_list = {
.background_pixel = wm.color_set.bar_bg.argb, .background_pixel = wm.color_set.bar_bg.argb,
.border_pixel = 0, .border_pixel = 0,
.event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | .event_mask =
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
.colormap = colormap, .colormap = colormap,
}; };
@@ -362,7 +363,8 @@ static bool tray_take_selection_owner(void) {
XCB_CURRENT_TIME); XCB_CURRENT_TIME);
owner_cookie = xcb_get_selection_owner(wm.xcb_conn, tray.selection_atom); owner_cookie = xcb_get_selection_owner(wm.xcb_conn, tray.selection_atom);
owner_reply = xcb_get_selection_owner_reply(wm.xcb_conn, owner_cookie, nullptr); owner_reply =
xcb_get_selection_owner_reply(wm.xcb_conn, owner_cookie, nullptr);
bool success = owner_reply && owner_reply->owner == tray.window; bool success = owner_reply && owner_reply->owner == tray.window;
p_delete(&owner_reply); p_delete(&owner_reply);
@@ -378,18 +380,12 @@ static void tray_set_properties(void) {
const color_t *fg = &wm.color_set.tag_color; const color_t *fg = &wm.color_set.tag_color;
uint32_t colors[12] = { uint32_t colors[12] = {
tray_color_component_u16(fg->red), tray_color_component_u16(fg->red), tray_color_component_u16(fg->green),
tray_color_component_u16(fg->green), tray_color_component_u16(fg->blue), tray_color_component_u16(fg->red),
tray_color_component_u16(fg->blue), tray_color_component_u16(fg->green), tray_color_component_u16(fg->blue),
tray_color_component_u16(fg->red), tray_color_component_u16(fg->red), tray_color_component_u16(fg->green),
tray_color_component_u16(fg->green), tray_color_component_u16(fg->blue), tray_color_component_u16(fg->red),
tray_color_component_u16(fg->blue), tray_color_component_u16(fg->green), tray_color_component_u16(fg->blue),
tray_color_component_u16(fg->red),
tray_color_component_u16(fg->green),
tray_color_component_u16(fg->blue),
tray_color_component_u16(fg->red),
tray_color_component_u16(fg->green),
tray_color_component_u16(fg->blue),
}; };
xcb_change_property(wm.xcb_conn, XCB_PROP_MODE_REPLACE, tray.window, xcb_change_property(wm.xcb_conn, XCB_PROP_MODE_REPLACE, tray.window,
_NET_SYSTEM_TRAY_COLORS, XCB_ATOM_CARDINAL, 32, _NET_SYSTEM_TRAY_COLORS, XCB_ATOM_CARDINAL, 32,

View File

@@ -2,6 +2,7 @@
#include <stdint.h> #include <stdint.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include "types.h" #include "types.h"
typedef struct wallpaper_context_t wallpaper_context_t; typedef struct wallpaper_context_t wallpaper_context_t;

View File

@@ -6,8 +6,13 @@
#include "core/types.h" #include "core/types.h"
#include "utils.h" #include "utils.h"
static void assert_output_geometry(const output_info_t *output, int32_t x, static void assert_output_geometry(
int32_t y, int32_t width, int32_t height) { const output_info_t *output,
int32_t x,
int32_t y,
int32_t width,
int32_t height
) {
assert(output); assert(output);
assert(output->geometry.x == x); assert(output->geometry.x == x);
assert(output->geometry.y == y); assert(output->geometry.y == y);

View File

@@ -1,14 +1,15 @@
#include "config/loader.h"
#include <assert.h> #include <assert.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "config/loader.h"
#include "helpers.h" #include "helpers.h"
static void test_config_loader_loads_explicit_override(const char *fixture_path) { static void test_config_loader_loads_explicit_override(
const char *fixture_path
) {
config_test_clear_env(); config_test_clear_env();
config_loader_t loader = {0}; config_loader_t loader = {0};
@@ -22,9 +23,12 @@ static void test_config_loader_loads_explicit_override(const char *fixture_path)
} }
static void test_config_loader_override_has_priority_over_env( static void test_config_loader_override_has_priority_over_env(
const char *fixture_path) { const char *fixture_path
) {
config_test_clear_env(); config_test_clear_env();
assert(setenv("ZDWM_CONFIG_LIB", "/tmp/definitely-missing-config.so", 1) == 0); assert(
setenv("ZDWM_CONFIG_LIB", "/tmp/definitely-missing-config.so", 1) == 0
);
config_loader_t loader = {0}; config_loader_t loader = {0};
assert(config_loader_load(&loader, fixture_path)); assert(config_loader_load(&loader, fixture_path));
@@ -37,7 +41,8 @@ static void test_config_loader_override_has_priority_over_env(
} }
static void test_config_loader_uses_zdwm_config_lib_env( static void test_config_loader_uses_zdwm_config_lib_env(
const char *fixture_path) { const char *fixture_path
) {
config_test_clear_env(); config_test_clear_env();
assert(setenv("ZDWM_CONFIG_LIB", fixture_path, 1) == 0); assert(setenv("ZDWM_CONFIG_LIB", fixture_path, 1) == 0);
@@ -54,15 +59,22 @@ static void test_config_loader_uses_zdwm_config_lib_env(
static void test_config_loader_uses_xdg_config_home(const char *fixture_path) { static void test_config_loader_uses_xdg_config_home(const char *fixture_path) {
config_test_clear_env(); config_test_clear_env();
char temp_root[PATH_MAX] = {0}; char temp_root[PATH_MAX] = {0};
char config_dir[PATH_MAX] = {0}; char config_dir[PATH_MAX] = {0};
char config_path[PATH_MAX] = {0}; char config_path[PATH_MAX] = {0};
config_test_make_temp_dir(temp_root, sizeof(temp_root), config_test_make_temp_dir(
"zdwm-config-loader-xdg"); temp_root,
sizeof(temp_root),
"zdwm-config-loader-xdg"
);
config_test_join_path(config_dir, sizeof(config_dir), temp_root, "zdwm"); config_test_join_path(config_dir, sizeof(config_dir), temp_root, "zdwm");
config_test_join_path(config_path, sizeof(config_path), config_dir, config_test_join_path(
"config.so"); config_path,
sizeof(config_path),
config_dir,
"config.so"
);
config_test_mkdir(config_dir); config_test_mkdir(config_dir);
config_test_symlink(fixture_path, config_path); config_test_symlink(fixture_path, config_path);
assert(setenv("XDG_CONFIG_HOME", temp_root, 1) == 0); assert(setenv("XDG_CONFIG_HOME", temp_root, 1) == 0);
@@ -83,17 +95,24 @@ static void test_config_loader_uses_xdg_config_home(const char *fixture_path) {
static void test_config_loader_uses_home_fallback(const char *fixture_path) { static void test_config_loader_uses_home_fallback(const char *fixture_path) {
config_test_clear_env(); config_test_clear_env();
char temp_root[PATH_MAX] = {0}; char temp_root[PATH_MAX] = {0};
char config_root[PATH_MAX] = {0}; char config_root[PATH_MAX] = {0};
char zdwm_dir[PATH_MAX] = {0}; char zdwm_dir[PATH_MAX] = {0};
char config_path[PATH_MAX] = {0}; char config_path[PATH_MAX] = {0};
config_test_make_temp_dir(temp_root, sizeof(temp_root), config_test_make_temp_dir(
"zdwm-config-loader-home"); temp_root,
sizeof(temp_root),
"zdwm-config-loader-home"
);
config_test_join_path(config_root, sizeof(config_root), temp_root, ".config"); config_test_join_path(config_root, sizeof(config_root), temp_root, ".config");
config_test_join_path(zdwm_dir, sizeof(zdwm_dir), config_root, "zdwm"); config_test_join_path(zdwm_dir, sizeof(zdwm_dir), config_root, "zdwm");
config_test_join_path(config_path, sizeof(config_path), zdwm_dir, config_test_join_path(
"config.so"); config_path,
sizeof(config_path),
zdwm_dir,
"config.so"
);
config_test_mkdir(config_root); config_test_mkdir(config_root);
config_test_mkdir(zdwm_dir); config_test_mkdir(zdwm_dir);
config_test_symlink(fixture_path, config_path); config_test_symlink(fixture_path, config_path);
@@ -116,13 +135,20 @@ static void test_config_loader_uses_home_fallback(const char *fixture_path) {
static void test_config_loader_allows_missing_implicit_library(void) { static void test_config_loader_allows_missing_implicit_library(void) {
config_test_clear_env(); config_test_clear_env();
char temp_root[PATH_MAX] = {0}; char temp_root[PATH_MAX] = {0};
char expected_path[PATH_MAX] = {0}; char expected_path[PATH_MAX] = {0};
config_test_make_temp_dir(temp_root, sizeof(temp_root), config_test_make_temp_dir(
"zdwm-config-loader-missing"); temp_root,
config_test_join_path(expected_path, sizeof(expected_path), temp_root, sizeof(temp_root),
"zdwm/config.so"); "zdwm-config-loader-missing"
);
config_test_join_path(
expected_path,
sizeof(expected_path),
temp_root,
"zdwm/config.so"
);
assert(setenv("XDG_CONFIG_HOME", temp_root, 1) == 0); assert(setenv("XDG_CONFIG_HOME", temp_root, 1) == 0);
config_loader_t loader = {0}; config_loader_t loader = {0};
@@ -147,7 +173,8 @@ static void test_config_loader_rejects_missing_explicit_library(void) {
} }
static void test_config_loader_rejects_library_without_setup( static void test_config_loader_rejects_library_without_setup(
const char *fixture_path) { const char *fixture_path
) {
config_test_clear_env(); config_test_clear_env();
config_loader_t loader = {0}; config_loader_t loader = {0};

View File

@@ -1,28 +1,45 @@
#include <zdwm/config.h> #include <zdwm/config.h>
static bool fixture_layout(const zdwm_layout_ctx_t *ctx, static bool
zdwm_layout_result_t *out) { fixture_layout(const zdwm_layout_ctx_t *ctx, zdwm_layout_result_t *out) {
if (!ctx || !out) return false; if (!ctx || !out) return false;
zdwm_layout_result_reset(out); zdwm_layout_result_reset(out);
if (!ctx->window_ids || ctx->window_count == 0) return true; if (!ctx->window_ids || ctx->window_count == 0) return true;
zdwm_layout_result_push(out, (zdwm_layout_item_t){ zdwm_layout_result_push(
.window_id = ctx->window_ids[0], out,
.rect = ctx->workarea, (zdwm_layout_item_t){
}); .window_id = ctx->window_ids[0],
.rect = ctx->workarea,
}
);
return true; return true;
} }
bool setup(const zdwm_api_t *api, zdwm_config_builder_t *builder, bool setup(
const zdwm_output_info_t *outputs, size_t output_count) { const zdwm_api_t *api,
zdwm_config_builder_t *builder,
const zdwm_output_info_t *outputs,
size_t output_count
) {
if (!api || !builder || !outputs || output_count == 0) return false; if (!api || !builder || !outputs || output_count == 0) return false;
zdwm_layout_id_t layout_id = zdwm_layout_id_t layout_id = api->register_layout(
api->register_layout(builder, "test-only", "[T]", "fixture layout", builder,
fixture_layout); "test-only",
"[T]",
"fixture layout",
fixture_layout
);
if (layout_id == ZDWM_LAYOUT_ID_INVALID) return false; if (layout_id == ZDWM_LAYOUT_ID_INVALID) return false;
return api->define_workspace(builder, 0, "from-so", &layout_id, 1, return api->define_workspace(
layout_id) != ZDWM_WORKSPACE_ID_INVALID; builder,
0,
"from-so",
&layout_id,
1,
layout_id
) != ZDWM_WORKSPACE_ID_INVALID;
} }

View File

@@ -15,17 +15,20 @@ static inline void config_test_clear_env(void) {
assert(unsetenv("HOME") == 0); assert(unsetenv("HOME") == 0);
} }
static inline void config_test_make_temp_dir(char *path, size_t path_size, static inline void
const char *prefix) { config_test_make_temp_dir(char *path, size_t path_size, const char *prefix) {
int len = snprintf(path, path_size, "/tmp/%s-XXXXXX", prefix); int len = snprintf(path, path_size, "/tmp/%s-XXXXXX", prefix);
assert(len > 0); assert(len > 0);
assert((size_t)len < path_size); assert((size_t)len < path_size);
assert(mkdtemp(path) == path); assert(mkdtemp(path) == path);
} }
static inline void config_test_join_path(char *out, size_t out_size, static inline void config_test_join_path(
const char *base, char *out,
const char *suffix) { size_t out_size,
const char *base,
const char *suffix
) {
int len = snprintf(out, out_size, "%s/%s", base, suffix); int len = snprintf(out, out_size, "%s/%s", base, suffix);
assert(len > 0); assert(len > 0);
assert((size_t)len < out_size); assert((size_t)len < out_size);

View File

@@ -22,8 +22,11 @@ bool backend_next_event(backend_t *backend, event_t *event) {
return false; return false;
} }
bool backend_apply_effect(backend_t *backend, const effect_t *effects, bool backend_apply_effect(
size_t effect_count) { backend_t *backend,
const effect_t *effects,
size_t effect_count
) {
return false; return false;
} }
@@ -35,8 +38,8 @@ static void assert_default_layouts(const runtime_init_desc_t *desc) {
assert(desc); assert(desc);
assert(layout_registry_count(&desc->layouts) == 3); assert(layout_registry_count(&desc->layouts) == 3);
const layout_slot_t *tile = layout_registry_at(&desc->layouts, 0); const layout_slot_t *tile = layout_registry_at(&desc->layouts, 0);
const layout_slot_t *monocle = layout_registry_at(&desc->layouts, 1); const layout_slot_t *monocle = layout_registry_at(&desc->layouts, 1);
const layout_slot_t *floating = layout_registry_at(&desc->layouts, 2); const layout_slot_t *floating = layout_registry_at(&desc->layouts, 2);
assert(tile); assert(tile);
@@ -52,13 +55,13 @@ static void test_runtime_config_loads_user_library(const char *fixture_path) {
output_info_t outputs[] = { output_info_t outputs[] = {
{ {
.name = "HDMI-A-1", .name = "HDMI-A-1",
.geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080}, .geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080},
}, },
}; };
runtime_init_desc_t desc = { runtime_init_desc_t desc = {
.outputs = outputs, .outputs = outputs,
.output_count = 1, .output_count = 1,
}; };
assert(runtime_config_load(fixture_path, &desc)); assert(runtime_config_load(fixture_path, &desc));
@@ -79,20 +82,21 @@ static void test_runtime_config_loads_user_library(const char *fixture_path) {
} }
static void test_runtime_config_keeps_module_loaded_after_runtime_init( static void test_runtime_config_keeps_module_loaded_after_runtime_init(
const char *fixture_path) { const char *fixture_path
) {
config_test_clear_env(); config_test_clear_env();
output_info_t outputs[] = { output_info_t outputs[] = {
{ {
.name = "HDMI-A-1", .name = "HDMI-A-1",
.geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080}, .geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080},
}, },
}; };
window_id_t window_ids[] = {42}; window_id_t window_ids[] = {42};
runtime_init_desc_t desc = { runtime_init_desc_t desc = {
.backend = test_backend_create(), .backend = test_backend_create(),
.outputs = outputs, .outputs = outputs,
.output_count = 1, .output_count = 1,
}; };
assert(desc.backend); assert(desc.backend);
@@ -111,11 +115,11 @@ static void test_runtime_config_keeps_module_loaded_after_runtime_init(
layout_result_t result = {0}; layout_result_t result = {0};
layout_ctx_t ctx = { layout_ctx_t ctx = {
.workspace_id = 0, .workspace_id = 0,
.focused_window_id = window_ids[0], .focused_window_id = window_ids[0],
.workarea = {.x = 11, .y = 22, .width = 333, .height = 444}, .workarea = {.x = 11, .y = 22, .width = 333, .height = 444},
.window_ids = window_ids, .window_ids = window_ids,
.window_count = 1, .window_count = 1,
}; };
assert(layout(&ctx, &result)); assert(layout(&ctx, &result));
assert(result.item_count == 1); assert(result.item_count == 1);
@@ -132,27 +136,31 @@ static void test_runtime_config_keeps_module_loaded_after_runtime_init(
static void static void
test_runtime_config_falls_back_to_defaults_when_implicit_library_is_missing( test_runtime_config_falls_back_to_defaults_when_implicit_library_is_missing(
void) { void
) {
config_test_clear_env(); config_test_clear_env();
output_info_t outputs[] = { output_info_t outputs[] = {
{ {
.name = "eDP-1", .name = "eDP-1",
.geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080}, .geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080},
}, },
{ {
.name = "DP-1", .name = "DP-1",
.geometry = {.x = 1920, .y = 0, .width = 2560, .height = 1440}, .geometry = {.x = 1920, .y = 0, .width = 2560, .height = 1440},
}, },
}; };
char temp_root[PATH_MAX] = {0}; char temp_root[PATH_MAX] = {0};
config_test_make_temp_dir(temp_root, sizeof(temp_root), config_test_make_temp_dir(
"zdwm-runtime-config-missing"); temp_root,
sizeof(temp_root),
"zdwm-runtime-config-missing"
);
assert(setenv("XDG_CONFIG_HOME", temp_root, 1) == 0); assert(setenv("XDG_CONFIG_HOME", temp_root, 1) == 0);
runtime_init_desc_t desc = { runtime_init_desc_t desc = {
.outputs = outputs, .outputs = outputs,
.output_count = 2, .output_count = 2,
}; };
assert(runtime_config_load(nullptr, &desc)); assert(runtime_config_load(nullptr, &desc));
@@ -173,13 +181,13 @@ static void test_runtime_config_rejects_missing_explicit_library(void) {
output_info_t outputs[] = { output_info_t outputs[] = {
{ {
.name = "HDMI-A-1", .name = "HDMI-A-1",
.geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080}, .geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080},
}, },
}; };
runtime_init_desc_t desc = { runtime_init_desc_t desc = {
.outputs = outputs, .outputs = outputs,
.output_count = 1, .output_count = 1,
}; };
assert(!runtime_config_load("/tmp/definitely-missing-config.so", &desc)); assert(!runtime_config_load("/tmp/definitely-missing-config.so", &desc));
@@ -190,18 +198,19 @@ static void test_runtime_config_rejects_missing_explicit_library(void) {
} }
static void test_runtime_config_rejects_library_without_setup( static void test_runtime_config_rejects_library_without_setup(
const char *fixture_path) { const char *fixture_path
) {
config_test_clear_env(); config_test_clear_env();
output_info_t outputs[] = { output_info_t outputs[] = {
{ {
.name = "HDMI-A-1", .name = "HDMI-A-1",
.geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080}, .geometry = {.x = 0, .y = 0, .width = 1920, .height = 1080},
}, },
}; };
runtime_init_desc_t desc = { runtime_init_desc_t desc = {
.outputs = outputs, .outputs = outputs,
.output_count = 1, .output_count = 1,
}; };
assert(!runtime_config_load(fixture_path, &desc)); assert(!runtime_config_load(fixture_path, &desc));

View File

@@ -4,7 +4,7 @@
#include "core/runtime.h" #include "core/runtime.h"
static void bootstrap(runtime_t *runtime) { static void bootstrap(runtime_t *runtime) {
backend_t *backend = backend_create(nullptr); backend_t *backend = backend_create(nullptr);
backend_detect_t *detect = backend_detect(backend); backend_detect_t *detect = backend_detect(backend);
if (!backend || !detect || detect->output_count == 0) { if (!backend || !detect || detect->output_count == 0) {
@@ -12,8 +12,8 @@ static void bootstrap(runtime_t *runtime) {
} }
runtime_init_desc_t desc = { runtime_init_desc_t desc = {
.backend = backend, .backend = backend,
.outputs = detect->outputs, .outputs = detect->outputs,
.output_count = detect->output_count, .output_count = detect->output_count,
}; };
if (!runtime_config_load(nullptr, &desc)) { if (!runtime_config_load(nullptr, &desc)) {