Compare commits
9 Commits
ac22a2b529
...
67f0c169f5
| Author | SHA1 | Date | |
|---|---|---|---|
|
67f0c169f5
|
|||
|
fa93b3d733
|
|||
|
a4dcb1eb8b
|
|||
|
32679b354a
|
|||
|
fb3bb10eab
|
|||
|
34017fb5da
|
|||
|
38572bd5f7
|
|||
|
577c5bc3b2
|
|||
|
6c77d9f151
|
30
.clang-tidy
Normal file
30
.clang-tidy
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# -*- mode: yaml; -*-
|
||||||
|
|
||||||
|
Checks: >-
|
||||||
|
-*,
|
||||||
|
clang-analyzer-*,
|
||||||
|
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
|
||||||
|
cert-err34-c,
|
||||||
|
bugprone-assert-side-effect,
|
||||||
|
bugprone-assignment-in-if-condition,
|
||||||
|
bugprone-branch-clone,
|
||||||
|
bugprone-infinite-loop,
|
||||||
|
bugprone-macro-parentheses,
|
||||||
|
bugprone-macro-repeated-side-effects,
|
||||||
|
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||||
|
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||||
|
bugprone-not-null-terminated-result,
|
||||||
|
bugprone-posix-return,
|
||||||
|
bugprone-sizeof-expression,
|
||||||
|
bugprone-suspicious-memory-comparison,
|
||||||
|
bugprone-suspicious-memset-usage,
|
||||||
|
bugprone-suspicious-missing-comma,
|
||||||
|
bugprone-suspicious-semicolon,
|
||||||
|
bugprone-swapped-arguments,
|
||||||
|
bugprone-undefined-memory-manipulation,
|
||||||
|
bugprone-unsafe-functions,
|
||||||
|
bugprone-unused-return-value
|
||||||
|
WarningsAsErrors: ''
|
||||||
|
HeaderFilterRegex: '^(src|include|tests)/'
|
||||||
|
FormatStyle: file
|
||||||
|
SystemHeaders: false
|
||||||
51
.githooks/pre-commit
Executable file
51
.githooks/pre-commit
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(git rev-parse --show-toplevel)"
|
||||||
|
cd "$repo_root"
|
||||||
|
|
||||||
|
if ! command -v clang-format >/dev/null 2>&1; then
|
||||||
|
echo "pre-commit: clang-format not found in PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git clang-format -h >/dev/null 2>&1; then
|
||||||
|
echo "pre-commit: git clang-format is not available" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mapfile -d '' staged_files < <(
|
||||||
|
git diff --cached --name-only --diff-filter=ACMR -z -- \
|
||||||
|
'*.c' '*.h' '*.cc' '*.cpp' '*.cxx' '*.hh' '*.hpp' '*.hxx'
|
||||||
|
)
|
||||||
|
|
||||||
|
if ((${#staged_files[@]} == 0)); then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if git rev-parse --verify HEAD >/dev/null 2>&1; then
|
||||||
|
base_commit=HEAD
|
||||||
|
else
|
||||||
|
empty_tree="$(git hash-object -t tree /dev/null)"
|
||||||
|
base_commit="$(
|
||||||
|
printf 'pre-commit empty base\n' | \
|
||||||
|
GIT_AUTHOR_NAME=pre-commit \
|
||||||
|
GIT_AUTHOR_EMAIL=pre-commit@example.invalid \
|
||||||
|
GIT_COMMITTER_NAME=pre-commit \
|
||||||
|
GIT_COMMITTER_EMAIL=pre-commit@example.invalid \
|
||||||
|
git commit-tree "$empty_tree"
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
|
git clang-format --staged --binary clang-format --quiet "$base_commit" -- \
|
||||||
|
"${staged_files[@]}"
|
||||||
|
status=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ $status -ne 0 && $status -ne 1 ]]; then
|
||||||
|
exit "$status"
|
||||||
|
fi
|
||||||
|
|
||||||
|
git add -- "${staged_files[@]}"
|
||||||
@@ -7,6 +7,7 @@ set(CMAKE_C_EXTENSIONS ON)
|
|||||||
|
|
||||||
set(APP_NAME "zdwm")
|
set(APP_NAME "zdwm")
|
||||||
set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
set(INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
set(BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
set(BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
|
||||||
add_compile_definitions(LOG_FILE="$ENV{HOME}/${APP_NAME}-log.txt")
|
add_compile_definitions(LOG_FILE="$ENV{HOME}/${APP_NAME}-log.txt")
|
||||||
@@ -28,7 +29,7 @@ option(BUILD_TESTING "Build tests" OFF)
|
|||||||
|
|
||||||
add_executable(${APP_NAME}
|
add_executable(${APP_NAME}
|
||||||
${SOURCE_DIR}/wm.c
|
${SOURCE_DIR}/wm.c
|
||||||
${SOURCE_DIR}/utils.c
|
${SOURCE_DIR}/base/log.c
|
||||||
${SOURCE_DIR}/buffer.c
|
${SOURCE_DIR}/buffer.c
|
||||||
${SOURCE_DIR}/backtrace.c
|
${SOURCE_DIR}/backtrace.c
|
||||||
${SOURCE_DIR}/monitor.c
|
${SOURCE_DIR}/monitor.c
|
||||||
@@ -82,6 +83,7 @@ pkg_check_modules(deps REQUIRED
|
|||||||
|
|
||||||
target_include_directories(${APP_NAME} SYSTEM
|
target_include_directories(${APP_NAME} SYSTEM
|
||||||
PRIVATE ${deps_INCLUDE_DIRS}
|
PRIVATE ${deps_INCLUDE_DIRS}
|
||||||
|
PRIVATE ${INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
target_include_directories(${APP_NAME}
|
target_include_directories(${APP_NAME}
|
||||||
PRIVATE ${SOURCE_DIR}
|
PRIVATE ${SOURCE_DIR}
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -44,4 +44,8 @@ test:
|
|||||||
cmake --build $(BUILD_DIR)
|
cmake --build $(BUILD_DIR)
|
||||||
ctest --test-dir $(BUILD_DIR)
|
ctest --test-dir $(BUILD_DIR)
|
||||||
|
|
||||||
.PHONY: clean run wm prepare build install uninstall reinstall test
|
install-hooks:
|
||||||
|
chmod +x $(MAKEFILE_DIR).githooks/pre-commit
|
||||||
|
git -C $(MAKEFILE_DIR) config core.hooksPath $(MAKEFILE_DIR).githooks
|
||||||
|
|
||||||
|
.PHONY: clean run wm prepare build install uninstall reinstall test install-hooks
|
||||||
|
|||||||
80
include/zdwm/config.h
Normal file
80
include/zdwm/config.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#ifndef ZDWM_CONFIG_H
|
||||||
|
#define ZDWM_CONFIG_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <zdwm/layout.h>
|
||||||
|
#include <zdwm/types.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ZDWM_CONFIG_ABI_VERSION 1u
|
||||||
|
|
||||||
|
typedef struct zdwm_config_builder_t zdwm_config_builder_t;
|
||||||
|
|
||||||
|
typedef struct zdwm_builtin_layouts_t {
|
||||||
|
zdwm_layout_fn tile;
|
||||||
|
zdwm_layout_fn monocle;
|
||||||
|
} zdwm_builtin_layouts_t;
|
||||||
|
|
||||||
|
typedef struct zdwm_api_t {
|
||||||
|
uint32_t abi_version;
|
||||||
|
zdwm_builtin_layouts_t builtin_layouts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户调用这个函数注册布局算法
|
||||||
|
* @param builder 配置构建上下文
|
||||||
|
* @param name 布局算法名称,不能为 nullptr
|
||||||
|
* @param symbol 布局算法标志符号,用于在状态栏中显示,不能为 nullptr
|
||||||
|
* @param description 布局算法描述,可以为 nullptr
|
||||||
|
* @param fn 布局算法,可以为 nullptr ,如果为 nullptr 则代表不自动布局
|
||||||
|
* @returns 返回布局算法对应的布局 id ,如果注册失败,返回
|
||||||
|
* ZDWM_LAYOUT_ID_INVALID
|
||||||
|
*/
|
||||||
|
zdwm_layout_id_t (*register_layout)(zdwm_config_builder_t *builder,
|
||||||
|
const char *name, const char *symbol,
|
||||||
|
const char *description,
|
||||||
|
zdwm_layout_fn fn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户调用这个函数添加 output 中的工作空间
|
||||||
|
* @param builder 配置构建上下文
|
||||||
|
* @param output_index 该工作空间归属的 output 索引
|
||||||
|
* @param name 工作空间名称,用于状态栏显示,不能为 nullptr
|
||||||
|
* @param layout_ids 该工作空间支持的布局算法列表
|
||||||
|
* @param layout_count 支持的布局算法总数
|
||||||
|
* @param initial_layout_id 初始布局算法 id
|
||||||
|
* @returns 返回工作空间 id 。如果注册失败,返回 ZDWM_WORKSPACE_ID_INVALID
|
||||||
|
*/
|
||||||
|
zdwm_workspace_id_t (*define_workspace)(zdwm_config_builder_t *builder,
|
||||||
|
size_t output_index, const char *name,
|
||||||
|
const zdwm_layout_id_t *layout_ids,
|
||||||
|
size_t layout_count,
|
||||||
|
zdwm_layout_id_t initial_layout_id);
|
||||||
|
} zdwm_api_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户配置入口函数类型定义
|
||||||
|
* @param api 用户自定义时可以使用的 api 接口及数据,api
|
||||||
|
* 中的函数和信息只能在函数内部使用,如果用户将其保存后在函数外使用是未定义行为
|
||||||
|
* @param builder 配置构建上下文
|
||||||
|
* @param outputs 屏幕信息列表
|
||||||
|
* @param output_count 屏幕个数
|
||||||
|
* @returns 用户配置成功返回 true ,配置失败返回 false
|
||||||
|
*/
|
||||||
|
typedef bool zdwm_config_setup_fn(const zdwm_api_t *api,
|
||||||
|
zdwm_config_builder_t *builder,
|
||||||
|
const zdwm_output_info_t *outputs,
|
||||||
|
size_t output_count);
|
||||||
|
|
||||||
|
/* 用户在自己的动态链接库配置中必须实现该函数 */
|
||||||
|
extern zdwm_config_setup_fn setup;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ZDWM_CONFIG_H */
|
||||||
61
include/zdwm/layout.h
Normal file
61
include/zdwm/layout.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#ifndef ZDWM_LAYOUT_H
|
||||||
|
#define ZDWM_LAYOUT_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <zdwm/types.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct zdwm_layout_ctx_t {
|
||||||
|
zdwm_workspace_id_t workspace_id;
|
||||||
|
zdwm_window_id_t focused_window_id;
|
||||||
|
zdwm_rect_t workarea;
|
||||||
|
const zdwm_window_id_t *window_ids;
|
||||||
|
size_t window_count;
|
||||||
|
} zdwm_layout_ctx_t;
|
||||||
|
|
||||||
|
typedef struct zdwm_layout_item_t {
|
||||||
|
zdwm_window_id_t window_id;
|
||||||
|
zdwm_rect_t rect;
|
||||||
|
} zdwm_layout_item_t;
|
||||||
|
|
||||||
|
typedef struct zdwm_layout_result_t {
|
||||||
|
zdwm_layout_item_t *items;
|
||||||
|
size_t item_count;
|
||||||
|
size_t item_capacity;
|
||||||
|
} zdwm_layout_result_t;
|
||||||
|
|
||||||
|
typedef bool (*zdwm_layout_fn)(const zdwm_layout_ctx_t *ctx,
|
||||||
|
zdwm_layout_result_t *out);
|
||||||
|
|
||||||
|
static inline void zdwm_layout_result_reset(zdwm_layout_result_t *result) {
|
||||||
|
if (!result) abort();
|
||||||
|
result->item_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void zdwm_layout_result_push(zdwm_layout_result_t *result,
|
||||||
|
zdwm_layout_item_t item) {
|
||||||
|
if (!result) abort();
|
||||||
|
|
||||||
|
if (result->item_count == result->item_capacity) {
|
||||||
|
size_t capacity = result->item_capacity ? result->item_capacity * 2u : 4u;
|
||||||
|
zdwm_layout_item_t *items =
|
||||||
|
realloc(result->items, capacity * sizeof(*result->items));
|
||||||
|
if (!items) abort();
|
||||||
|
result->items = items;
|
||||||
|
result->item_capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->items[result->item_count++] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ZDWM_LAYOUT_H */
|
||||||
36
include/zdwm/types.h
Normal file
36
include/zdwm/types.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef ZDWM_TYPES_H
|
||||||
|
#define ZDWM_TYPES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef uint32_t zdwm_layout_id_t;
|
||||||
|
typedef uint32_t zdwm_window_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_WINDOW_ID_INVALID ((zdwm_window_id_t)0)
|
||||||
|
#define ZDWM_WORKSPACE_ID_INVALID ((zdwm_workspace_id_t)UINT32_MAX)
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
typedef struct zdwm_rect_t {
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
} zdwm_rect_t;
|
||||||
|
|
||||||
|
typedef struct zdwm_output_info_t {
|
||||||
|
const char *name;
|
||||||
|
zdwm_rect_t geometry;
|
||||||
|
} zdwm_output_info_t;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ZDWM_TYPES_H */
|
||||||
@@ -3,20 +3,19 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "base/memory.h"
|
||||||
#include "core/backend.h"
|
#include "core/backend.h"
|
||||||
#include "core/types.h"
|
#include "core/types.h"
|
||||||
#include "core/wm_desc.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
static inline int32_t right(wm_rect_t a) { return a.x + a.width; }
|
static inline int32_t right(rect_t a) { return a.x + a.width; }
|
||||||
static inline int32_t bottom(wm_rect_t a) { return a.y + a.height; }
|
static inline int32_t bottom(rect_t a) { return a.y + a.height; }
|
||||||
static inline bool fully_contains(wm_rect_t outer, wm_rect_t inner) {
|
static inline bool fully_contains(rect_t outer, rect_t inner) {
|
||||||
return inner.x >= outer.x && inner.y >= outer.y &&
|
return inner.x >= outer.x && inner.y >= outer.y &&
|
||||||
right(inner) <= right(outer) && bottom(inner) <= bottom(outer);
|
right(inner) <= right(outer) && bottom(inner) <= bottom(outer);
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_backend_detect_t *output_remove_duplication(const wm_output_info_t *output,
|
backend_detect_t *output_remove_duplication(const output_info_t *output,
|
||||||
const size_t count) {
|
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 +41,14 @@ wm_backend_detect_t *output_remove_duplication(const wm_output_info_t *output,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_output_info_t *list = p_new(wm_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);
|
||||||
wm_backend_detect_t *detect = p_new(wm_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;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "core/backend.h"
|
#include "core/backend.h"
|
||||||
#include "core/wm_desc.h"
|
#include "core/types.h"
|
||||||
|
|
||||||
wm_backend_detect_t *output_remove_duplication(const wm_output_info_t *output,
|
backend_detect_t *output_remove_duplication(const output_info_t *output,
|
||||||
const size_t count);
|
const size_t count);
|
||||||
|
|||||||
@@ -12,17 +12,18 @@
|
|||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
#include "backend/output_utils.h"
|
#include "backend/output_utils.h"
|
||||||
#include "core/wm_desc.h"
|
#include "base/log.h"
|
||||||
#include "utils.h"
|
#include "base/memory.h"
|
||||||
|
#include "core/types.h"
|
||||||
|
|
||||||
struct wm_backend_t {
|
struct backend_t {
|
||||||
xcb_connection_t *conn;
|
xcb_connection_t *conn;
|
||||||
xcb_screen_t *screen;
|
xcb_screen_t *screen;
|
||||||
int screenp;
|
int screenp;
|
||||||
bool have_xfixes;
|
bool have_xfixes;
|
||||||
};
|
};
|
||||||
|
|
||||||
wm_backend_t *wm_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);
|
||||||
@@ -46,7 +47,7 @@ wm_backend_t *wm_backend_create(const char *display_name) {
|
|||||||
"SubstructureRedirect)");
|
"SubstructureRedirect)");
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_backend_t *backend = p_new(wm_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;
|
||||||
@@ -71,7 +72,7 @@ wm_backend_t *wm_backend_create(const char *display_name) {
|
|||||||
return backend;
|
return backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_backend_destroy(wm_backend_t *backend) {
|
void backend_destroy(backend_t *backend) {
|
||||||
if (!backend) return;
|
if (!backend) return;
|
||||||
|
|
||||||
xcb_disconnect(backend->conn);
|
xcb_disconnect(backend->conn);
|
||||||
@@ -79,8 +80,8 @@ void wm_backend_destroy(wm_backend_t *backend) {
|
|||||||
free(backend);
|
free(backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool detect_monitor_by_randr(const wm_backend_t *backend,
|
static bool detect_monitor_by_randr(const backend_t *backend,
|
||||||
wm_output_info_t **outputs, size_t *count) {
|
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);
|
||||||
@@ -116,11 +117,11 @@ static bool detect_monitor_by_randr(const wm_backend_t *backend,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_output_info_t *output_list = p_new(wm_output_info_t, len);
|
output_info_t *output_list = p_new(output_info_t, len);
|
||||||
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++) {
|
||||||
wm_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;
|
||||||
@@ -152,9 +153,8 @@ static bool detect_monitor_by_randr(const wm_backend_t *backend,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool detect_monitor_by_xinerama(const wm_backend_t *backend,
|
static bool detect_monitor_by_xinerama(const backend_t *backend,
|
||||||
wm_output_info_t **outputs,
|
output_info_t **outputs, size_t *count) {
|
||||||
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);
|
||||||
@@ -195,9 +195,9 @@ static bool detect_monitor_by_xinerama(const wm_backend_t *backend,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_output_info_t *output_list = p_new(wm_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++) {
|
||||||
wm_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;
|
||||||
@@ -216,35 +216,35 @@ static bool detect_monitor_by_xinerama(const wm_backend_t *backend,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_backend_detect_t *wm_backend_detect(wm_backend_t *backend) {
|
backend_detect_t *backend_detect(backend_t *backend) {
|
||||||
wm_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)) {
|
||||||
wm_backend_detect_t *detect = output_remove_duplication(outputs, count);
|
backend_detect_t *detect = output_remove_duplication(outputs, count);
|
||||||
p_delete(&outputs);
|
p_delete(&outputs);
|
||||||
return detect;
|
return detect;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (detect_monitor_by_xinerama(backend, &outputs, &count)) {
|
if (detect_monitor_by_xinerama(backend, &outputs, &count)) {
|
||||||
wm_backend_detect_t *detect = output_remove_duplication(outputs, count);
|
backend_detect_t *detect = output_remove_duplication(outputs, count);
|
||||||
p_delete(&outputs);
|
p_delete(&outputs);
|
||||||
return detect;
|
return detect;
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_output_info_t *output = p_new(wm_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;
|
||||||
|
|
||||||
wm_backend_detect_t *detect = p_new(wm_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_backend_detect_destroy(wm_backend_detect_t *detect) {
|
void backend_detect_destroy(backend_detect_t *detect) {
|
||||||
if (!detect) return;
|
if (!detect) return;
|
||||||
|
|
||||||
for (size_t i = 0; i < detect->output_count; i++) {
|
for (size_t i = 0; i < detect->output_count; i++) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "utils.h"
|
#include "base/log.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -19,9 +19,6 @@ const char *current_time_str(void) {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Print error and exit with EXIT_FAILURE code.
|
|
||||||
*/
|
|
||||||
void _fatal(int line, const char *fct, const char *file, const char *fmt, ...) {
|
void _fatal(int line, const char *fct, const char *file, const char *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@@ -34,9 +31,6 @@ void _fatal(int line, const char *fct, const char *file, const char *fmt, ...) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Print error message on stderr
|
|
||||||
*/
|
|
||||||
void _warn(int line, const char *fct, const char *file, const char *fmt, ...) {
|
void _warn(int line, const char *fct, const char *file, const char *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
32
src/base/log.h
Normal file
32
src/base/log.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define fatal(format, ...) \
|
||||||
|
_fatal(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__)
|
||||||
|
void _fatal(int line, const char *function, const char *file,
|
||||||
|
const char *format, ...) __attribute__((noreturn))
|
||||||
|
__attribute__((format(printf, 4, 5)));
|
||||||
|
|
||||||
|
#define warn(format, ...) \
|
||||||
|
_warn(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__)
|
||||||
|
void _warn(int line, const char *function, const char *file, const char *format,
|
||||||
|
...) __attribute__((format(printf, 4, 5)));
|
||||||
|
|
||||||
|
const char *current_time_str(void);
|
||||||
|
|
||||||
|
#if defined(RELEASE)
|
||||||
|
#define logger(format, ...)
|
||||||
|
#elif defined(LOG_FILE)
|
||||||
|
static inline void logger(const char *format, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
FILE *log_file = fopen(LOG_FILE, "a+t");
|
||||||
|
vfprintf(log_file, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
fclose(log_file);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define logger(format, ...) printf(format, ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
29
src/base/macros.h
Normal file
29
src/base/macros.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define ssizeof(foo) (ssize_t)sizeof(foo)
|
||||||
|
#define countof(foo) (ssizeof(foo) / ssizeof(foo[0]))
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define likely(expr) __builtin_expect(!!(expr), 1)
|
||||||
|
#define unlikely(expr) __builtin_expect((expr), 0)
|
||||||
|
#else
|
||||||
|
#define likely(expr) expr
|
||||||
|
#define unlikely(expr) expr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MIN
|
||||||
|
#undef MIN
|
||||||
|
#endif
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MAX
|
||||||
|
#undef MAX
|
||||||
|
#endif
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
73
src/base/memory.h
Normal file
73
src/base/memory.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "base/macros.h"
|
||||||
|
|
||||||
|
#define p_alloc_nr(x) (((x) + 16) * 3 / 2)
|
||||||
|
#define p_new(type, count) ((type *)xmalloc(sizeof(type) * (count)))
|
||||||
|
#define p_clear(p, count) ((void)memset((p), 0, sizeof(*(p)) * (count)))
|
||||||
|
#define p_realloc(pp, count) xrealloc((void *)(pp), sizeof(**(pp)) * (count))
|
||||||
|
#define p_copy(src, count) xmemcopy((src), sizeof(*(src)) * (count))
|
||||||
|
|
||||||
|
#define p_delete(mem_p) \
|
||||||
|
do { \
|
||||||
|
void **__ptr = (void **)(mem_p); \
|
||||||
|
free(*__ptr); \
|
||||||
|
*(void **)__ptr = nullptr; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static inline char *p_strdup(const char *text) {
|
||||||
|
char *r = strdup(text);
|
||||||
|
if (!r) abort();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char *p_strdup_nullable(const char *text) {
|
||||||
|
if (!text) return nullptr;
|
||||||
|
return p_strdup(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *__attribute__((malloc)) xmalloc(ssize_t size) {
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
if (size <= 0) return nullptr;
|
||||||
|
|
||||||
|
ptr = calloc(1, size);
|
||||||
|
|
||||||
|
if (!ptr) abort();
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *xmemcopy(const void *src, size_t n) {
|
||||||
|
if (!n) return nullptr;
|
||||||
|
|
||||||
|
void *mem = xmalloc(n);
|
||||||
|
void *ret = memcpy(mem, src, n);
|
||||||
|
if (ret != mem) abort();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void xrealloc(void **ptr, ssize_t newsize) {
|
||||||
|
if (newsize <= 0)
|
||||||
|
p_delete(ptr);
|
||||||
|
else {
|
||||||
|
*ptr = realloc(*ptr, newsize);
|
||||||
|
if (!*ptr) abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unlike strlen(), a_strlen() accepts nullptr and returns 0 in that case.
|
||||||
|
*/
|
||||||
|
static inline ssize_t a_strlen(const char *s) { return s ? strlen(s) : 0; }
|
||||||
|
|
||||||
|
static constexpr size_t INIT_CAPACITY = 4;
|
||||||
|
static inline size_t next_capacity(size_t capacity) {
|
||||||
|
if (capacity) return capacity * 2;
|
||||||
|
return INIT_CAPACITY;
|
||||||
|
}
|
||||||
103
src/config/loader.c
Normal file
103
src/config/loader.c
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#include "config/loader.h"
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "base/log.h"
|
||||||
|
#include "base/memory.h"
|
||||||
|
|
||||||
|
static char *config_loader_join_path(const char *base, const char *suffix) {
|
||||||
|
if (!base || !suffix) return nullptr;
|
||||||
|
|
||||||
|
size_t base_len = strlen(base);
|
||||||
|
size_t suffix_len = strlen(suffix);
|
||||||
|
char *path = p_new(char, base_len + suffix_len + 1);
|
||||||
|
memcpy(path, base, base_len);
|
||||||
|
memcpy(path + base_len, suffix, suffix_len + 1);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool config_loader_resolve_path(char **out_path, bool *out_is_explicit,
|
||||||
|
const char *override_path) {
|
||||||
|
const char *path = override_path;
|
||||||
|
if (path && *path) {
|
||||||
|
*out_path = p_strdup(path);
|
||||||
|
*out_is_explicit = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = getenv("ZDWM_CONFIG_LIB");
|
||||||
|
if (path && *path) {
|
||||||
|
*out_path = p_strdup(path);
|
||||||
|
*out_is_explicit = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = getenv("XDG_CONFIG_HOME");
|
||||||
|
if (path && *path) {
|
||||||
|
*out_path = config_loader_join_path(path, "/zdwm/config.so");
|
||||||
|
*out_is_explicit = false;
|
||||||
|
return *out_path != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = getenv("HOME");
|
||||||
|
if (path && *path) {
|
||||||
|
*out_path = config_loader_join_path(path, "/.config/zdwm/config.so");
|
||||||
|
*out_is_explicit = false;
|
||||||
|
return *out_path != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool config_loader_load(config_loader_t *loader, const char *override_path) {
|
||||||
|
if (!loader) return false;
|
||||||
|
config_loader_cleanup(loader);
|
||||||
|
|
||||||
|
char *path = nullptr;
|
||||||
|
bool is_explicit = false;
|
||||||
|
if (!config_loader_resolve_path(&path, &is_explicit, override_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
loader->path = path;
|
||||||
|
|
||||||
|
if (access(path, F_OK) != 0) {
|
||||||
|
if (is_explicit) {
|
||||||
|
warn("config library not found: %s", path);
|
||||||
|
config_loader_cleanup(loader);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
loader->handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if (!loader->handle) {
|
||||||
|
warn("failed to load config library %s: %s", path, dlerror());
|
||||||
|
config_loader_cleanup(loader);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dlerror();
|
||||||
|
loader->setup = (zdwm_config_setup_fn *)dlsym(loader->handle, "setup");
|
||||||
|
const char *error = dlerror();
|
||||||
|
if (error) {
|
||||||
|
warn("failed to resolve setup from %s: %s", path, error);
|
||||||
|
config_loader_cleanup(loader);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_loader_cleanup(config_loader_t *loader) {
|
||||||
|
if (!loader) return;
|
||||||
|
|
||||||
|
loader->setup = nullptr;
|
||||||
|
|
||||||
|
if (loader->handle) dlclose(loader->handle);
|
||||||
|
loader->handle = nullptr;
|
||||||
|
|
||||||
|
p_delete(&loader->path);
|
||||||
|
}
|
||||||
12
src/config/loader.h
Normal file
12
src/config/loader.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <zdwm/config.h>
|
||||||
|
|
||||||
|
typedef struct config_loader_t {
|
||||||
|
char *path;
|
||||||
|
void *handle;
|
||||||
|
zdwm_config_setup_fn *setup;
|
||||||
|
} config_loader_t;
|
||||||
|
|
||||||
|
bool config_loader_load(config_loader_t *loader, const char *override_path);
|
||||||
|
void config_loader_cleanup(config_loader_t *loader);
|
||||||
@@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "core/wm_desc.h"
|
#include "core/types.h"
|
||||||
|
|
||||||
typedef struct wm_backend_t wm_backend_t;
|
typedef struct backend_t backend_t;
|
||||||
|
|
||||||
typedef struct wm_backend_detect_t {
|
typedef struct backend_detect_t {
|
||||||
wm_output_info_t *outputs;
|
output_info_t *outputs;
|
||||||
size_t output_count;
|
size_t output_count;
|
||||||
} wm_backend_detect_t;
|
} backend_detect_t;
|
||||||
|
|
||||||
wm_backend_t *wm_backend_create(const char *display_name);
|
backend_t *backend_create(const char *display_name);
|
||||||
void wm_backend_destroy(wm_backend_t *backend);
|
void backend_destroy(backend_t *backend);
|
||||||
|
|
||||||
wm_backend_detect_t *wm_backend_detect(wm_backend_t *backend);
|
backend_detect_t *backend_detect(backend_t *backend);
|
||||||
void wm_backend_detect_destroy(wm_backend_detect_t *detect);
|
void backend_detect_destroy(backend_detect_t *detect);
|
||||||
|
|||||||
255
src/core/event.h
255
src/core/event.h
@@ -2,173 +2,174 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "core/types.h"
|
||||||
#include "core/wm_desc.h"
|
#include "core/wm_desc.h"
|
||||||
|
|
||||||
typedef enum wm_event_type_t {
|
typedef enum event_type_t {
|
||||||
WM_EVENT_KEY_PRESS,
|
ZDWM_EVENT_KEY_PRESS,
|
||||||
WM_EVENT_POINTER_BUTTON_PRESS,
|
ZDWM_EVENT_POINTER_BUTTON_PRESS,
|
||||||
WM_EVENT_POINTER_BUTTON_RELEASE,
|
ZDWM_EVENT_POINTER_BUTTON_RELEASE,
|
||||||
WM_EVENT_POINTER_MOTION,
|
ZDWM_EVENT_POINTER_MOTION,
|
||||||
WM_EVENT_POINTER_ENTER,
|
ZDWM_EVENT_POINTER_ENTER,
|
||||||
WM_EVENT_WINDOW_MAP_REQUEST,
|
ZDWM_EVENT_WINDOW_MAP_REQUEST,
|
||||||
WM_EVENT_WINDOW_REMOVE,
|
ZDWM_EVENT_WINDOW_REMOVE,
|
||||||
WM_EVENT_WINDOW_METADATA_CHANGED,
|
ZDWM_EVENT_WINDOW_METADATA_CHANGED,
|
||||||
WM_EVENT_WINDOW_HINTS_CHANGED,
|
ZDWM_EVENT_WINDOW_HINTS_CHANGED,
|
||||||
WM_EVENT_WINDOW_ACTIVATE_REQUEST,
|
ZDWM_EVENT_WINDOW_ACTIVATE_REQUEST,
|
||||||
WM_EVENT_WINDOW_STATE_REQUEST,
|
ZDWM_EVENT_WINDOW_STATE_REQUEST,
|
||||||
WM_EVENT_CONFIGURE_REQUEST,
|
ZDWM_EVENT_CONFIGURE_REQUEST,
|
||||||
} wm_event_type_t;
|
} event_type_t;
|
||||||
|
|
||||||
typedef enum wm_modifier_bit_t {
|
typedef enum modifier_bit_t {
|
||||||
WM_MOD_SHIFT = 1u << 0,
|
ZDWM_MOD_SHIFT = 1u << 0,
|
||||||
WM_MOD_CTRL = 1u << 1,
|
ZDWM_MOD_CTRL = 1u << 1,
|
||||||
WM_MOD_ALT = 1u << 2,
|
ZDWM_MOD_ALT = 1u << 2,
|
||||||
WM_MOD_SUPER = 1u << 3,
|
ZDWM_MOD_SUPER = 1u << 3,
|
||||||
} wm_modifier_bit_t;
|
} modifier_bit_t;
|
||||||
|
|
||||||
typedef uint32_t wm_modifier_mask_t;
|
typedef uint32_t modifier_mask_t;
|
||||||
typedef uint32_t wm_keysym_t;
|
typedef uint32_t keysym_t;
|
||||||
|
|
||||||
typedef struct wm_key_press_event_t {
|
typedef struct key_press_event_t {
|
||||||
wm_modifier_mask_t modifiers;
|
modifier_mask_t modifiers;
|
||||||
wm_keysym_t keysym;
|
keysym_t keysym;
|
||||||
uint32_t keycode;
|
uint32_t keycode;
|
||||||
} wm_key_press_event_t;
|
} key_press_event_t;
|
||||||
|
|
||||||
typedef enum wm_button_t {
|
typedef enum button_t {
|
||||||
WM_BUTTON_LEFT,
|
ZDWM_BUTTON_LEFT,
|
||||||
WM_BUTTON_RIGHT,
|
ZDWM_BUTTON_RIGHT,
|
||||||
WM_BUTTON_MIDDLE,
|
ZDWM_BUTTON_MIDDLE,
|
||||||
} wm_button_t;
|
} button_t;
|
||||||
|
|
||||||
typedef struct wm_pointer_button_event_t {
|
typedef struct pointer_button_event_t {
|
||||||
wm_modifier_mask_t modifiers;
|
modifier_mask_t modifiers;
|
||||||
wm_button_t button;
|
button_t button;
|
||||||
wm_window_id_t window;
|
window_id_t window;
|
||||||
wm_point_t root;
|
point_t root;
|
||||||
wm_point_t local;
|
point_t local;
|
||||||
} wm_pointer_button_event_t;
|
} pointer_button_event_t;
|
||||||
|
|
||||||
typedef struct wm_pointer_motion_event_t {
|
typedef struct pointer_motion_event_t {
|
||||||
wm_window_id_t window;
|
window_id_t window;
|
||||||
wm_point_t root;
|
point_t root;
|
||||||
wm_point_t local;
|
point_t local;
|
||||||
} wm_pointer_motion_event_t;
|
} pointer_motion_event_t;
|
||||||
|
|
||||||
typedef struct wm_pointer_enter_event_t {
|
typedef struct pointer_enter_event_t {
|
||||||
wm_window_id_t window;
|
window_id_t window;
|
||||||
wm_point_t root;
|
point_t root;
|
||||||
wm_point_t local;
|
point_t local;
|
||||||
} wm_pointer_enter_event_t;
|
} pointer_enter_event_t;
|
||||||
|
|
||||||
typedef struct wm_window_map_request_event_t {
|
typedef struct window_map_request_event_t {
|
||||||
wm_window_info_t info;
|
window_info_t info;
|
||||||
wm_window_id_t transient_for;
|
window_id_t transient_for;
|
||||||
bool is_dialog;
|
bool is_dialog;
|
||||||
} wm_window_map_request_event_t;
|
} window_map_request_event_t;
|
||||||
|
|
||||||
typedef enum wm_window_remove_reason_t {
|
typedef enum window_remove_reason_t {
|
||||||
WM_WINDOW_REMOVE_WITHDRAWN,
|
ZDWM_WINDOW_REMOVE_WITHDRAWN,
|
||||||
WM_WINDOW_REMOVE_DESTROY,
|
ZDWM_WINDOW_REMOVE_DESTROY,
|
||||||
} wm_window_remove_reason_t;
|
} window_remove_reason_t;
|
||||||
|
|
||||||
typedef struct wm_window_remove_event_t {
|
typedef struct window_remove_event_t {
|
||||||
wm_window_id_t window;
|
window_id_t window;
|
||||||
wm_window_remove_reason_t reason;
|
window_remove_reason_t reason;
|
||||||
} wm_window_remove_event_t;
|
} window_remove_event_t;
|
||||||
|
|
||||||
typedef enum wm_window_metadata_change_flags_t {
|
typedef enum window_metadata_change_flags_t {
|
||||||
WM_WINDOW_METADATA_CHANGE_TITLE = 1u << 0,
|
ZDWM_WINDOW_METADATA_CHANGE_TITLE = 1u << 0,
|
||||||
WM_WINDOW_METADATA_CHANGE_APP_ID = 1u << 1,
|
ZDWM_WINDOW_METADATA_CHANGE_APP_ID = 1u << 1,
|
||||||
WM_WINDOW_METADATA_CHANGE_CLASS = 1u << 2,
|
ZDWM_WINDOW_METADATA_CHANGE_CLASS = 1u << 2,
|
||||||
WM_WINDOW_METADATA_CHANGE_INSTANCE = 1u << 3,
|
ZDWM_WINDOW_METADATA_CHANGE_INSTANCE = 1u << 3,
|
||||||
} wm_window_metadata_change_flags_t;
|
} window_metadata_change_flags_t;
|
||||||
|
|
||||||
typedef struct wm_window_metadata_change_event_t {
|
typedef struct window_metadata_change_event_t {
|
||||||
wm_window_id_t window;
|
window_id_t window;
|
||||||
uint32_t changed_fields;
|
uint32_t changed_fields;
|
||||||
const char *title;
|
const char *title;
|
||||||
const char *app_id;
|
const char *app_id;
|
||||||
const char *class_name;
|
const char *class_name;
|
||||||
const char *instance_name;
|
const char *instance_name;
|
||||||
} wm_window_metadata_change_event_t;
|
} window_metadata_change_event_t;
|
||||||
|
|
||||||
typedef enum wm_window_hint_changed_flags_t {
|
typedef enum window_hint_changed_flags_t {
|
||||||
WM_WINDOW_HINT_CHANGED_NONE = 0,
|
ZDWM_WINDOW_HINT_CHANGED_NONE = 0,
|
||||||
WM_WINDOW_HINT_CHANGED_URGENT = 1u << 0,
|
ZDWM_WINDOW_HINT_CHANGED_URGENT = 1u << 0,
|
||||||
WM_WINDOW_HINT_CHANGED_FIXED_SIZE = 1u << 1,
|
ZDWM_WINDOW_HINT_CHANGED_FIXED_SIZE = 1u << 1,
|
||||||
WM_WINDOW_HINT_CHANGED_SKIP_TASKBAR = 1u << 2,
|
ZDWM_WINDOW_HINT_CHANGED_SKIP_TASKBAR = 1u << 2,
|
||||||
} wm_window_hint_changed_flags_t;
|
} window_hint_changed_flags_t;
|
||||||
|
|
||||||
typedef struct wm_window_hints_changed_event_t {
|
typedef struct window_hints_changed_event_t {
|
||||||
wm_window_id_t window;
|
window_id_t window;
|
||||||
uint32_t changed_fields;
|
uint32_t changed_fields;
|
||||||
bool urgent;
|
bool urgent;
|
||||||
bool fixed_size;
|
bool fixed_size;
|
||||||
bool skip_taskbar;
|
bool skip_taskbar;
|
||||||
} wm_window_hints_changed_event_t;
|
} window_hints_changed_event_t;
|
||||||
|
|
||||||
typedef enum wm_window_activation_source_t {
|
typedef enum window_activation_source_t {
|
||||||
WM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0,
|
ZDWM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0,
|
||||||
WM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1,
|
ZDWM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1,
|
||||||
WM_WINDOW_ACTIVATION_SOURCE_PAGER = 2,
|
ZDWM_WINDOW_ACTIVATION_SOURCE_PAGER = 2,
|
||||||
} wm_window_activation_source_t;
|
} window_activation_source_t;
|
||||||
|
|
||||||
typedef struct wm_window_activate_request_event_t {
|
typedef struct window_activate_request_event_t {
|
||||||
wm_window_id_t window;
|
window_id_t window;
|
||||||
wm_window_activation_source_t source;
|
window_activation_source_t source;
|
||||||
} wm_window_activate_request_event_t;
|
} window_activate_request_event_t;
|
||||||
|
|
||||||
typedef enum wm_window_state_request_kind_t {
|
typedef enum window_state_request_kind_t {
|
||||||
WM_WINDOW_STATE_REQUEST_FULLSCREEN,
|
ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN,
|
||||||
WM_WINDOW_STATE_REQUEST_MAXIMIZED,
|
ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED,
|
||||||
WM_WINDOW_STATE_REQUEST_MINIMIZED,
|
ZDWM_WINDOW_STATE_REQUEST_MINIMIZED,
|
||||||
} wm_window_state_request_kind_t;
|
} window_state_request_kind_t;
|
||||||
|
|
||||||
typedef enum wm_window_state_request_action_t {
|
typedef enum window_state_request_action_t {
|
||||||
WM_WINDOW_STATE_REQUEST_ACTION_ADD,
|
ZDWM_WINDOW_STATE_REQUEST_ACTION_ADD,
|
||||||
WM_WINDOW_STATE_REQUEST_ACTION_REMOVE,
|
ZDWM_WINDOW_STATE_REQUEST_ACTION_REMOVE,
|
||||||
WM_WINDOW_STATE_REQUEST_ACTION_TOGGLE,
|
ZDWM_WINDOW_STATE_REQUEST_ACTION_TOGGLE,
|
||||||
} wm_window_state_request_action_t;
|
} window_state_request_action_t;
|
||||||
|
|
||||||
typedef struct wm_window_state_request_event_t {
|
typedef struct window_state_request_event_t {
|
||||||
wm_window_id_t window;
|
window_id_t window;
|
||||||
wm_window_state_request_kind_t kind;
|
window_state_request_kind_t kind;
|
||||||
wm_window_state_request_action_t action;
|
window_state_request_action_t action;
|
||||||
} wm_window_state_request_event_t;
|
} window_state_request_event_t;
|
||||||
|
|
||||||
typedef enum wm_configure_request_field_t {
|
typedef enum configure_request_field_t {
|
||||||
WM_CONFIGURE_REQUEST_FIELD_NONE = 0,
|
ZDWM_CONFIGURE_REQUEST_FIELD_NONE = 0,
|
||||||
WM_CONFIGURE_REQUEST_FIELD_X = 1u << 0,
|
ZDWM_CONFIGURE_REQUEST_FIELD_X = 1u << 0,
|
||||||
WM_CONFIGURE_REQUEST_FIELD_Y = 1u << 1,
|
ZDWM_CONFIGURE_REQUEST_FIELD_Y = 1u << 1,
|
||||||
WM_CONFIGURE_REQUEST_FIELD_WIDTH = 1u << 2,
|
ZDWM_CONFIGURE_REQUEST_FIELD_WIDTH = 1u << 2,
|
||||||
WM_CONFIGURE_REQUEST_FIELD_HEIGHT = 1u << 3,
|
ZDWM_CONFIGURE_REQUEST_FIELD_HEIGHT = 1u << 3,
|
||||||
} wm_configure_request_field_t;
|
} configure_request_field_t;
|
||||||
|
|
||||||
typedef struct wm_configure_request_event_t {
|
typedef struct configure_request_event_t {
|
||||||
wm_window_id_t window;
|
window_id_t window;
|
||||||
uint32_t changed_fields;
|
uint32_t changed_fields;
|
||||||
int32_t x;
|
int32_t x;
|
||||||
int32_t y;
|
int32_t y;
|
||||||
int32_t width;
|
int32_t width;
|
||||||
int32_t height;
|
int32_t height;
|
||||||
} wm_configure_request_event_t;
|
} configure_request_event_t;
|
||||||
|
|
||||||
typedef struct wm_event_t {
|
typedef struct event_t {
|
||||||
wm_event_type_t type;
|
event_type_t type;
|
||||||
uint32_t time_ms;
|
uint32_t time_ms;
|
||||||
union {
|
union {
|
||||||
wm_key_press_event_t key_press;
|
key_press_event_t key_press;
|
||||||
wm_pointer_button_event_t pointer_button_press;
|
pointer_button_event_t pointer_button_press;
|
||||||
wm_pointer_button_event_t pointer_button_release;
|
pointer_button_event_t pointer_button_release;
|
||||||
wm_pointer_motion_event_t pointer_motion;
|
pointer_motion_event_t pointer_motion;
|
||||||
wm_pointer_enter_event_t pointer_enter;
|
pointer_enter_event_t pointer_enter;
|
||||||
wm_window_map_request_event_t window_map_request;
|
window_map_request_event_t window_map_request;
|
||||||
wm_window_remove_event_t window_remove;
|
window_remove_event_t window_remove;
|
||||||
wm_window_metadata_change_event_t window_metadata_change;
|
window_metadata_change_event_t window_metadata_change;
|
||||||
wm_window_hints_changed_event_t window_hints_changed;
|
window_hints_changed_event_t window_hints_changed;
|
||||||
wm_window_activate_request_event_t window_activate_request;
|
window_activate_request_event_t window_activate_request;
|
||||||
wm_window_state_request_event_t window_state_request;
|
window_state_request_event_t window_state_request;
|
||||||
wm_configure_request_event_t configure_request;
|
configure_request_event_t configure_request;
|
||||||
} data;
|
} data;
|
||||||
} wm_event_t;
|
} event_t;
|
||||||
|
|||||||
@@ -4,25 +4,21 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "base/memory.h"
|
||||||
|
|
||||||
void wm_layout_result_init(wm_layout_result_t *result) {
|
void layout_result_init(layout_result_t *result) {
|
||||||
result->item_count = 0;
|
result->item_count = 0;
|
||||||
result->item_capacity = INIT_CAPACITY;
|
result->item_capacity = INIT_CAPACITY;
|
||||||
result->items = p_new(wm_layout_item_t, result->item_capacity);
|
result->items = p_new(layout_item_t, result->item_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_layout_result_reset(wm_layout_result_t *result) {
|
void layout_result_cleanup(layout_result_t *result) {
|
||||||
result->item_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wm_layout_result_cleanup(wm_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_layout_result_push(wm_layout_result_t *result, wm_layout_item_t item) {
|
void layout_result_push(layout_result_t *result, layout_item_t item) {
|
||||||
if (result->item_count == result->item_capacity) {
|
if (result->item_count == result->item_capacity) {
|
||||||
size_t new_capacity = next_capacity(result->item_capacity);
|
size_t new_capacity = next_capacity(result->item_capacity);
|
||||||
p_realloc(&result->items, new_capacity);
|
p_realloc(&result->items, new_capacity);
|
||||||
@@ -32,68 +28,81 @@ void wm_layout_result_push(wm_layout_result_t *result, wm_layout_item_t item) {
|
|||||||
result->items[result->item_count++] = item;
|
result->items[result->item_count++] = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_layout_registry_init(wm_layout_registry_t *registry) {
|
void layout_registry_init(layout_registry_t *registry) {
|
||||||
registry->slot_count = 0;
|
registry->slot_count = 0;
|
||||||
registry->slot_capacity = INIT_CAPACITY;
|
registry->slot_capacity = INIT_CAPACITY;
|
||||||
registry->slots = p_new(wm_layout_slot_t, registry->slot_capacity);
|
registry->slots = p_new(layout_slot_t, registry->slot_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_layout_registry_cleanup(wm_layout_registry_t *registry) {
|
void layout_registry_cleanup(layout_registry_t *registry) {
|
||||||
while (registry->slot_count > 0) {
|
while (registry->slot_count > 0) {
|
||||||
wm_layout_slot_t *r = ®istry->slots[--registry->slot_count];
|
layout_slot_t *r = ®istry->slots[--registry->slot_count];
|
||||||
p_delete(&r->name);
|
p_delete(&r->name);
|
||||||
p_delete(&r->symbol);
|
p_delete(&r->symbol);
|
||||||
p_delete(&r->description);
|
p_delete(&r->description);
|
||||||
r->fn = nullptr;
|
r->fn = nullptr;
|
||||||
r->id = WM_LAYOUT_ID_INVALID;
|
r->id = ZDWM_LAYOUT_ID_INVALID;
|
||||||
}
|
}
|
||||||
p_delete(®istry->slots);
|
p_delete(®istry->slots);
|
||||||
registry->slot_count = 0;
|
registry->slot_count = 0;
|
||||||
registry->slot_capacity = 0;
|
registry->slot_capacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t wm_layout_registry_count(const wm_layout_registry_t *registry) {
|
bool layout_registry_move(layout_registry_t *src, layout_registry_t *dest) {
|
||||||
|
if (!src || !dest) return false;
|
||||||
|
|
||||||
|
dest->slots = src->slots;
|
||||||
|
dest->slot_count = src->slot_count;
|
||||||
|
dest->slot_capacity = src->slot_capacity;
|
||||||
|
|
||||||
|
src->slots = nullptr;
|
||||||
|
src->slot_count = 0;
|
||||||
|
src->slot_capacity = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t layout_registry_count(const layout_registry_t *registry) {
|
||||||
return registry->slot_count;
|
return registry->slot_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_layout_slot_t *wm_layout_registry_at(
|
const layout_slot_t *layout_registry_at(const layout_registry_t *registry,
|
||||||
const wm_layout_registry_t *registry, size_t index) {
|
size_t index) {
|
||||||
if (index >= registry->slot_count) return nullptr;
|
if (index >= registry->slot_count) return nullptr;
|
||||||
return ®istry->slots[index];
|
return ®istry->slots[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_layout_id_t wm_layout_register(wm_layout_registry_t *registry,
|
layout_id_t layout_register(layout_registry_t *registry, const char *name,
|
||||||
const char *name, const char *symbol,
|
const char *symbol, const char *description,
|
||||||
const char *description, wm_layout_fn fn) {
|
layout_fn fn) {
|
||||||
if (!name || !symbol) return WM_LAYOUT_ID_INVALID;
|
if (!name || !symbol) return ZDWM_LAYOUT_ID_INVALID;
|
||||||
|
|
||||||
if (registry->slot_count == registry->slot_capacity) {
|
if (registry->slot_count == registry->slot_capacity) {
|
||||||
size_t new_capacity = next_capacity(registry->slot_capacity);
|
size_t new_capacity = next_capacity(registry->slot_capacity);
|
||||||
p_realloc(®istry->slots, new_capacity);
|
p_realloc(®istry->slots, new_capacity);
|
||||||
registry->slot_capacity = new_capacity;
|
registry->slot_capacity = new_capacity;
|
||||||
}
|
}
|
||||||
wm_layout_id_t id = (wm_layout_id_t)registry->slot_count;
|
layout_id_t id = (layout_id_t)registry->slot_count;
|
||||||
|
|
||||||
wm_layout_slot_t *r = ®istry->slots[registry->slot_count];
|
layout_slot_t *r = ®istry->slots[registry->slot_count];
|
||||||
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 = description ? p_strdup(description) : nullptr;
|
r->description = p_strdup_nullable(description);
|
||||||
r->fn = fn;
|
r->fn = fn;
|
||||||
|
|
||||||
registry->slot_count++;
|
registry->slot_count++;
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_layout_fn wm_layout_get(const wm_layout_registry_t *registry,
|
layout_fn layout_get(const layout_registry_t *registry, layout_id_t id) {
|
||||||
wm_layout_id_t id) {
|
const layout_slot_t *layout_slot = layout_slot_get(registry, id);
|
||||||
const wm_layout_slot_t *layout_slot = wm_layout_slot_get(registry, id);
|
|
||||||
if (layout_slot) return layout_slot->fn;
|
if (layout_slot) return layout_slot->fn;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_layout_slot_t *wm_layout_slot_get(const wm_layout_registry_t *registry,
|
const layout_slot_t *layout_slot_get(const layout_registry_t *registry,
|
||||||
wm_layout_id_t id) {
|
layout_id_t id) {
|
||||||
if (id >= registry->slot_count) return nullptr;
|
if (id >= registry->slot_count) return nullptr;
|
||||||
return ®istry->slots[id];
|
return ®istry->slots[id];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <zdwm/layout.h>
|
||||||
|
|
||||||
#include "core/types.h"
|
#include "core/types.h"
|
||||||
|
|
||||||
typedef struct wm_layout_ctx_t {
|
typedef zdwm_layout_ctx_t layout_ctx_t;
|
||||||
wm_output_id_t output_id;
|
typedef zdwm_layout_item_t layout_item_t;
|
||||||
wm_workspace_id_t workspace_id;
|
typedef zdwm_layout_result_t layout_result_t;
|
||||||
wm_window_id_t focused_window_id;
|
typedef zdwm_layout_fn layout_fn;
|
||||||
wm_rect_t workarea;
|
|
||||||
/*
|
|
||||||
* 参与本次布局计算的窗口 ID 列表。
|
|
||||||
*
|
|
||||||
* 调用方负责在进入 layout 前完成筛选;这里不包含 floating、sticky、
|
|
||||||
* fullscreen、minimized 等不参与平铺计算的窗口。
|
|
||||||
*
|
|
||||||
* 数组顺序具有语义,layout 应按该顺序解释窗口排列优先级。
|
|
||||||
*/
|
|
||||||
const wm_window_id_t *window_ids;
|
|
||||||
size_t window_count;
|
|
||||||
} wm_layout_ctx_t;
|
|
||||||
|
|
||||||
typedef struct wm_layout_item_t {
|
typedef struct layout_slot_t {
|
||||||
wm_window_id_t window_id;
|
layout_id_t id;
|
||||||
wm_rect_t rect; /* 平铺窗口的目标外框矩形(包含边框) */
|
|
||||||
} wm_layout_item_t;
|
|
||||||
|
|
||||||
typedef struct wm_layout_result_t {
|
|
||||||
wm_layout_item_t *items;
|
|
||||||
size_t item_count;
|
|
||||||
size_t item_capacity;
|
|
||||||
} wm_layout_result_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 返回 true 表示成功生成合法的布局结果。
|
|
||||||
* 返回 false 表示布局计算失败,调用方应丢弃本次结果。
|
|
||||||
*
|
|
||||||
* 该返回值不表示窗口最终几何是否发生变化;
|
|
||||||
* 是否有改动应由调用方在比较当前状态与布局结果后决定。
|
|
||||||
*/
|
|
||||||
typedef bool (*wm_layout_fn)(const wm_layout_ctx_t *ctx,
|
|
||||||
wm_layout_result_t *out);
|
|
||||||
|
|
||||||
typedef struct wm_layout_slot_t {
|
|
||||||
wm_layout_id_t id;
|
|
||||||
/*
|
/*
|
||||||
* 布局名称,用于:
|
* 布局名称,用于:
|
||||||
* - 配置引用
|
* - 配置引用
|
||||||
@@ -70,14 +38,14 @@ typedef struct wm_layout_slot_t {
|
|||||||
*
|
*
|
||||||
* fn == NULL 表示 floating 布局,即该布局不参与平铺计算。
|
* fn == NULL 表示 floating 布局,即该布局不参与平铺计算。
|
||||||
*/
|
*/
|
||||||
wm_layout_fn fn;
|
layout_fn fn;
|
||||||
} wm_layout_slot_t;
|
} layout_slot_t;
|
||||||
|
|
||||||
typedef struct wm_layout_registry_t {
|
typedef struct layout_registry_t {
|
||||||
wm_layout_slot_t *slots;
|
layout_slot_t *slots;
|
||||||
size_t slot_count;
|
size_t slot_count;
|
||||||
size_t slot_capacity;
|
size_t slot_capacity;
|
||||||
} wm_layout_registry_t;
|
} layout_registry_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 调用约束:
|
* 调用约束:
|
||||||
@@ -85,11 +53,10 @@ typedef struct wm_layout_registry_t {
|
|||||||
* - 除 init 之外,其余 result 相关接口都要求 result 已初始化
|
* - 除 init 之外,其余 result 相关接口都要求 result 已初始化
|
||||||
* - 传入空指针或未初始化对象属于调用方错误
|
* - 传入空指针或未初始化对象属于调用方错误
|
||||||
*/
|
*/
|
||||||
void wm_layout_result_init(wm_layout_result_t *result);
|
void layout_result_init(layout_result_t *result);
|
||||||
void wm_layout_result_reset(wm_layout_result_t *result);
|
void layout_result_cleanup(layout_result_t *result);
|
||||||
void wm_layout_result_cleanup(wm_layout_result_t *result);
|
|
||||||
|
|
||||||
void wm_layout_result_push(wm_layout_result_t *result, wm_layout_item_t item);
|
void layout_result_push(layout_result_t *result, layout_item_t item);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 调用约束:
|
* 调用约束:
|
||||||
@@ -97,11 +64,12 @@ void wm_layout_result_push(wm_layout_result_t *result, wm_layout_item_t item);
|
|||||||
* - 除 init 之外,其余 registry 相关接口都要求 registry 已初始化
|
* - 除 init 之外,其余 registry 相关接口都要求 registry 已初始化
|
||||||
* - 传入空指针或未初始化对象属于调用方错误
|
* - 传入空指针或未初始化对象属于调用方错误
|
||||||
*/
|
*/
|
||||||
void wm_layout_registry_init(wm_layout_registry_t *registry);
|
void layout_registry_init(layout_registry_t *registry);
|
||||||
void wm_layout_registry_cleanup(wm_layout_registry_t *registry);
|
void layout_registry_cleanup(layout_registry_t *registry);
|
||||||
size_t wm_layout_registry_count(const wm_layout_registry_t *registry);
|
bool layout_registry_move(layout_registry_t *src, layout_registry_t *dest);
|
||||||
const wm_layout_slot_t *wm_layout_registry_at(
|
size_t layout_registry_count(const layout_registry_t *registry);
|
||||||
const wm_layout_registry_t *registry, size_t index);
|
const layout_slot_t *layout_registry_at(const layout_registry_t *registry,
|
||||||
|
size_t index);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 注册一个布局并返回其稳定 ID。
|
* 注册一个布局并返回其稳定 ID。
|
||||||
@@ -117,13 +85,13 @@ const wm_layout_slot_t *wm_layout_registry_at(
|
|||||||
*
|
*
|
||||||
* 返回值:
|
* 返回值:
|
||||||
* - 成功时返回新注册布局的 ID
|
* - 成功时返回新注册布局的 ID
|
||||||
* - name 或 symbol 非法时返回 WM_LAYOUT_ID_INVALID
|
* - name 或 symbol 非法时返回 ZDWM_LAYOUT_ID_INVALID
|
||||||
*
|
*
|
||||||
* 注册成功后,布局 ID 与其在 registry 中的槽位索引保持一致。
|
* 注册成功后,布局 ID 与其在 registry 中的槽位索引保持一致。
|
||||||
*/
|
*/
|
||||||
wm_layout_id_t wm_layout_register(wm_layout_registry_t *registry,
|
layout_id_t layout_register(layout_registry_t *registry, const char *name,
|
||||||
const char *name, const char *symbol,
|
const char *symbol, const char *description,
|
||||||
const char *description, wm_layout_fn fn);
|
layout_fn fn);
|
||||||
/*
|
/*
|
||||||
* 获取可执行的布局函数。
|
* 获取可执行的布局函数。
|
||||||
*
|
*
|
||||||
@@ -132,7 +100,6 @@ wm_layout_id_t wm_layout_register(wm_layout_registry_t *registry,
|
|||||||
* - id 对应的 slot 不存在
|
* - id 对应的 slot 不存在
|
||||||
* - slot 存在,但 fn == NULL(表示 floating 布局)
|
* - slot 存在,但 fn == NULL(表示 floating 布局)
|
||||||
*/
|
*/
|
||||||
wm_layout_fn wm_layout_get(const wm_layout_registry_t *registry,
|
layout_fn layout_get(const layout_registry_t *registry, layout_id_t id);
|
||||||
wm_layout_id_t id);
|
const layout_slot_t *layout_slot_get(const layout_registry_t *registry,
|
||||||
const wm_layout_slot_t *wm_layout_slot_get(const wm_layout_registry_t *registry,
|
layout_id_t id);
|
||||||
wm_layout_id_t id);
|
|
||||||
|
|||||||
@@ -2,50 +2,101 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "base/memory.h"
|
||||||
#include "core/backend.h"
|
#include "core/backend.h"
|
||||||
#include "core/state.h"
|
#include "core/state.h"
|
||||||
#include "core/types.h"
|
|
||||||
#include "core/wm_desc.h"
|
#include "core/wm_desc.h"
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
bool wm_runtime_init(wm_runtime_t *runtime) {
|
static bool runtime_workspace_desc_has_valid_layouts(
|
||||||
p_clear(runtime, 1);
|
const layout_registry_t *layouts, const workspace_desc_t *workspace) {
|
||||||
|
if (!layouts || !workspace) return false;
|
||||||
|
|
||||||
wm_backend_t *backend = wm_backend_create(nullptr);
|
for (size_t i = 0; i < workspace->layout_count; i++) {
|
||||||
if (!backend) return false;
|
if (!layout_slot_get(layouts, workspace->layout_ids[i])) return false;
|
||||||
|
|
||||||
runtime->backend = backend;
|
|
||||||
|
|
||||||
wm_backend_detect_t *detect = wm_backend_detect(backend);
|
|
||||||
if (!detect || detect->output_count <= 0) {
|
|
||||||
wm_backend_destroy(backend);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_workspace_desc_t *workspaces =
|
|
||||||
p_new(wm_workspace_desc_t, detect->output_count);
|
|
||||||
static wm_layout_id_t ids[] = {0, 1, 2};
|
|
||||||
for (size_t i = 0; i < detect->output_count; i++) {
|
|
||||||
wm_workspace_desc_t *desc = &workspaces[i];
|
|
||||||
desc->output_index = i;
|
|
||||||
desc->name = "web";
|
|
||||||
desc->layout_ids = ids;
|
|
||||||
desc->layout_count = countof(ids);
|
|
||||||
desc->initial_layout_id = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wm_state_init(&runtime->state, detect->outputs, detect->output_count,
|
|
||||||
workspaces, detect->output_count);
|
|
||||||
p_delete(&workspaces);
|
|
||||||
wm_backend_detect_destroy(detect);
|
|
||||||
detect = nullptr;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_runtime_shutdown(wm_runtime_t *runtime) {
|
static bool runtime_init_desc_valid(const runtime_init_desc_t *desc) {
|
||||||
|
if (!desc || !desc->backend || !desc->outputs || desc->output_count == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!desc->layouts.slots || desc->layouts.slot_count == 0) return false;
|
||||||
|
if (!desc->workspaces || desc->workspace_count == 0) return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < desc->workspace_count; i++) {
|
||||||
|
const workspace_desc_t *workspace = &desc->workspaces[i];
|
||||||
|
if (!workspace_desc_valid(workspace, desc->output_count)) return false;
|
||||||
|
if (!runtime_workspace_desc_has_valid_layouts(&desc->layouts, workspace)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void runtime_workspace_desc_list_cleanup(workspace_desc_t **list,
|
||||||
|
size_t *count) {
|
||||||
|
if (!list || !count) return;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < *count; i++) {
|
||||||
|
workspace_desc_t *workspace = &(*list)[i];
|
||||||
|
p_delete(&workspace->name);
|
||||||
|
p_delete(&workspace->layout_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_delete(list);
|
||||||
|
*count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc) {
|
||||||
|
if (!runtime || !runtime_init_desc_valid(desc)) return false;
|
||||||
|
|
||||||
|
p_clear(runtime, 1);
|
||||||
|
runtime->backend = desc->backend;
|
||||||
|
runtime->layouts = desc->layouts;
|
||||||
|
|
||||||
|
desc->backend = nullptr;
|
||||||
|
p_clear(&desc->layouts, 1);
|
||||||
|
|
||||||
|
state_init(&runtime->state, desc->outputs, desc->output_count,
|
||||||
|
desc->workspaces, desc->workspace_count);
|
||||||
|
|
||||||
|
runtime_workspace_desc_list_cleanup(&desc->workspaces,
|
||||||
|
&desc->workspace_count);
|
||||||
|
desc->outputs = nullptr;
|
||||||
|
desc->output_count = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void runtime_init_desc_cleanup(runtime_init_desc_t *desc) {
|
||||||
|
if (!desc) return;
|
||||||
|
|
||||||
|
if (desc->backend) {
|
||||||
|
backend_destroy(desc->backend);
|
||||||
|
desc->backend = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc->layouts.slots || desc->layouts.slot_count ||
|
||||||
|
desc->layouts.slot_capacity) {
|
||||||
|
layout_registry_cleanup(&desc->layouts);
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime_workspace_desc_list_cleanup(&desc->workspaces,
|
||||||
|
&desc->workspace_count);
|
||||||
|
desc->outputs = nullptr;
|
||||||
|
desc->output_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void runtime_shutdown(runtime_t *runtime) {
|
||||||
runtime->running = false;
|
runtime->running = false;
|
||||||
wm_state_cleanup(&runtime->state);
|
if (runtime->layouts.slots || runtime->layouts.slot_count ||
|
||||||
wm_backend_destroy(runtime->backend);
|
runtime->layouts.slot_capacity) {
|
||||||
|
layout_registry_cleanup(&runtime->layouts);
|
||||||
|
}
|
||||||
|
state_cleanup(&runtime->state);
|
||||||
|
backend_destroy(runtime->backend);
|
||||||
runtime->backend = nullptr;
|
runtime->backend = nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/backend.h"
|
#include "core/backend.h"
|
||||||
|
#include "core/layout.h"
|
||||||
#include "core/state.h"
|
#include "core/state.h"
|
||||||
|
|
||||||
typedef struct wm_runtime_t {
|
typedef struct runtime_init_desc_t {
|
||||||
|
backend_t *backend;
|
||||||
|
output_info_t *outputs;
|
||||||
|
size_t output_count;
|
||||||
|
|
||||||
|
layout_registry_t layouts;
|
||||||
|
workspace_desc_t *workspaces;
|
||||||
|
size_t workspace_count;
|
||||||
|
} runtime_init_desc_t;
|
||||||
|
|
||||||
|
typedef struct runtime_t {
|
||||||
bool running;
|
bool running;
|
||||||
bool will_restart;
|
bool will_restart;
|
||||||
|
|
||||||
wm_state_t state;
|
state_t state;
|
||||||
wm_backend_t *backend;
|
layout_registry_t layouts;
|
||||||
} wm_runtime_t;
|
backend_t *backend;
|
||||||
|
} runtime_t;
|
||||||
|
|
||||||
bool wm_runtime_init(wm_runtime_t *runtime);
|
bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc);
|
||||||
void wm_runtime_shutdown(wm_runtime_t *runtime);
|
void runtime_init_desc_cleanup(runtime_init_desc_t *desc);
|
||||||
|
void runtime_shutdown(runtime_t *runtime);
|
||||||
|
|||||||
309
src/core/state.c
309
src/core/state.c
@@ -3,63 +3,64 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "base/log.h"
|
||||||
|
#include "base/memory.h"
|
||||||
#include "core/types.h"
|
#include "core/types.h"
|
||||||
#include "core/wm_desc.h"
|
#include "core/wm_desc.h"
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
void wm_state_init(wm_state_t *state, const wm_output_info_t *outputs,
|
void state_init(state_t *state, const output_info_t *outputs,
|
||||||
size_t output_count, const wm_workspace_desc_t *workspaces,
|
size_t output_count, const workspace_desc_t *workspaces,
|
||||||
size_t workspace_count) {
|
size_t workspace_count) {
|
||||||
p_clear(state, 1);
|
p_clear(state, 1);
|
||||||
|
|
||||||
state->outputs = p_new(wm_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 wm_output_info_t *output_info = &outputs[i];
|
const output_info_t *output_info = &outputs[i];
|
||||||
wm_output_t *output = &state->outputs[i];
|
output_t *output = &state->outputs[i];
|
||||||
|
|
||||||
output->id = (wm_output_id_t)i;
|
output->id = (output_id_t)i;
|
||||||
output->current_workspace_id = WM_WORKSPACE_ID_INVALID;
|
output->current_workspace_id = ZDWM_WORKSPACE_ID_INVALID;
|
||||||
output->name = p_strdup(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;
|
||||||
|
|
||||||
state->workspaces = p_new(wm_workspace_t, workspace_count);
|
state->workspaces = p_new(workspace_t, workspace_count);
|
||||||
for (size_t i = 0; i < workspace_count; i++) {
|
for (size_t i = 0; i < workspace_count; i++) {
|
||||||
const wm_workspace_desc_t *workspace_desc = &workspaces[i];
|
const workspace_desc_t *workspace_desc = &workspaces[i];
|
||||||
if (!wm_workspace_desc_valid(workspace_desc, output_count)) {
|
if (!workspace_desc_valid(workspace_desc, output_count)) {
|
||||||
fatal("workspace desc at index %zu invalid", i);
|
fatal("workspace desc at index %zu invalid", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_output_t *output = &state->outputs[workspace_desc->output_index];
|
output_t *output = &state->outputs[workspace_desc->output_index];
|
||||||
wm_workspace_t *workspace = &state->workspaces[i];
|
workspace_t *workspace = &state->workspaces[i];
|
||||||
workspace->id = (wm_workspace_id_t)i;
|
workspace->id = (workspace_id_t)i;
|
||||||
workspace->output_id = output->id;
|
workspace->output_id = output->id;
|
||||||
workspace->focused_window_id = WM_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 == WM_WORKSPACE_ID_INVALID) {
|
if (output->current_workspace_id == ZDWM_WORKSPACE_ID_INVALID) {
|
||||||
output->current_workspace_id = workspace->id;
|
output->current_workspace_id = workspace->id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state->workspace_count = workspace_count;
|
state->workspace_count = workspace_count;
|
||||||
|
|
||||||
for (size_t i = 0; i < state->output_count; i++) {
|
for (size_t i = 0; i < state->output_count; i++) {
|
||||||
const wm_output_t *output = &state->outputs[i];
|
const output_t *output = &state->outputs[i];
|
||||||
if (output->current_workspace_id == WM_WORKSPACE_ID_INVALID) {
|
if (output->current_workspace_id == ZDWM_WORKSPACE_ID_INVALID) {
|
||||||
fatal("output at index %zu has no workspace", i);
|
fatal("output at index %zu has no workspace", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_cleanup(wm_state_t *state) {
|
void state_cleanup(state_t *state) {
|
||||||
for (size_t i = 0; i < state->window_count; i++) {
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
wm_window_t *window = &state->windows[i];
|
window_t *window = &state->windows[i];
|
||||||
p_delete(&window->title);
|
p_delete(&window->title);
|
||||||
p_delete(&window->app_id);
|
p_delete(&window->app_id);
|
||||||
p_delete(&window->class_name);
|
p_delete(&window->class_name);
|
||||||
@@ -71,7 +72,7 @@ void wm_state_cleanup(wm_state_t *state) {
|
|||||||
state->window_capacity = 0;
|
state->window_capacity = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < state->workspace_count; i++) {
|
for (size_t i = 0; i < state->workspace_count; i++) {
|
||||||
wm_workspace_t *workspace = &state->workspaces[i];
|
workspace_t *workspace = &state->workspaces[i];
|
||||||
p_delete(&workspace->name);
|
p_delete(&workspace->name);
|
||||||
p_delete(&workspace->available_layouts);
|
p_delete(&workspace->available_layouts);
|
||||||
workspace->layout_count = 0;
|
workspace->layout_count = 0;
|
||||||
@@ -80,7 +81,7 @@ void wm_state_cleanup(wm_state_t *state) {
|
|||||||
state->workspace_count = 0;
|
state->workspace_count = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < state->output_count; i++) {
|
for (size_t i = 0; i < state->output_count; i++) {
|
||||||
wm_output_t *output = &state->outputs[i];
|
output_t *output = &state->outputs[i];
|
||||||
p_delete(&output->name);
|
p_delete(&output->name);
|
||||||
}
|
}
|
||||||
p_delete(&state->outputs);
|
p_delete(&state->outputs);
|
||||||
@@ -89,44 +90,42 @@ void wm_state_cleanup(wm_state_t *state) {
|
|||||||
p_clear(state, 1);
|
p_clear(state, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_workspace_t *wm_state_workspace_get(const wm_state_t *state,
|
const workspace_t *state_workspace_get(const state_t *state,
|
||||||
wm_workspace_id_t id) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_workspace_t *wm_state_workspace_at(const wm_state_t *state,
|
const workspace_t *state_workspace_at(const state_t *state, size_t index) {
|
||||||
size_t index) {
|
|
||||||
if (index < state->workspace_count) return &state->workspaces[index];
|
if (index < state->workspace_count) return &state->workspaces[index];
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wm_state_workspace_adjust_focused_window(
|
static void state_workspace_adjust_focused_window(const state_t *state,
|
||||||
const wm_state_t *state, wm_workspace_id_t workspace_id) {
|
workspace_id_t workspace_id) {
|
||||||
wm_workspace_t *workspace =
|
workspace_t *workspace =
|
||||||
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
(workspace_t *)state_workspace_get(state, workspace_id);
|
||||||
if (!workspace) return;
|
if (!workspace) return;
|
||||||
|
|
||||||
const wm_window_t *window =
|
const window_t *window =
|
||||||
wm_state_window_get(state, workspace->focused_window_id);
|
state_window_get(state, workspace->focused_window_id);
|
||||||
if (window && window->workspace_id == workspace_id) return;
|
if (window && window->workspace_id == workspace_id) return;
|
||||||
|
|
||||||
for (size_t i = state->window_count; i > 0; i--) {
|
for (size_t i = state->window_count; i > 0; i--) {
|
||||||
wm_window_id_t window_id = state->stack_order[i - 1];
|
window_id_t window_id = state->stack_order[i - 1];
|
||||||
const wm_window_t *window = wm_state_window_get(state, window_id);
|
const window_t *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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace->focused_window_id = WM_WINDOW_ID_INVALID;
|
workspace->focused_window_id = ZDWM_WINDOW_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_state_workspace_cycle_layout(wm_state_t *state,
|
bool state_workspace_cycle_layout(state_t *state, workspace_id_t workspace_id) {
|
||||||
wm_workspace_id_t workspace_id) {
|
workspace_t *workspace =
|
||||||
wm_workspace_t *workspace =
|
(workspace_t *)state_workspace_get(state, workspace_id);
|
||||||
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
|
||||||
if (!workspace) return false;
|
if (!workspace) return false;
|
||||||
|
|
||||||
size_t next_index = 0;
|
size_t next_index = 0;
|
||||||
@@ -146,11 +145,11 @@ bool wm_state_workspace_cycle_layout(wm_state_t *state,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_state_workspace_set_layout_by_index(wm_state_t *state,
|
bool state_workspace_set_layout_by_index(state_t *state,
|
||||||
wm_workspace_id_t workspace_id,
|
workspace_id_t workspace_id,
|
||||||
size_t index) {
|
size_t index) {
|
||||||
wm_workspace_t *workspace =
|
workspace_t *workspace =
|
||||||
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
(workspace_t *)state_workspace_get(state, workspace_id);
|
||||||
if (!workspace) return false;
|
if (!workspace) return false;
|
||||||
if (index >= workspace->layout_count) return false;
|
if (index >= workspace->layout_count) return false;
|
||||||
|
|
||||||
@@ -158,11 +157,11 @@ bool wm_state_workspace_set_layout_by_index(wm_state_t *state,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_state_workspace_set_layout_by_id(wm_state_t *state,
|
bool state_workspace_set_layout_by_id(state_t *state,
|
||||||
wm_workspace_id_t workspace_id,
|
workspace_id_t workspace_id,
|
||||||
wm_layout_id_t layout_id) {
|
layout_id_t layout_id) {
|
||||||
wm_workspace_t *workspace =
|
workspace_t *workspace =
|
||||||
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
(workspace_t *)state_workspace_get(state, workspace_id);
|
||||||
if (!workspace) return false;
|
if (!workspace) return false;
|
||||||
for (size_t i = 0; i < workspace->layout_count; i++) {
|
for (size_t i = 0; i < workspace->layout_count; i++) {
|
||||||
if (workspace->available_layouts[i] == layout_id) {
|
if (workspace->available_layouts[i] == layout_id) {
|
||||||
@@ -174,29 +173,29 @@ bool wm_state_workspace_set_layout_by_id(wm_state_t *state,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_workspace_set_focused_window(wm_state_t *state,
|
void state_workspace_set_focused_window(state_t *state,
|
||||||
wm_workspace_id_t workspace_id,
|
workspace_id_t workspace_id,
|
||||||
wm_window_id_t window_id) {
|
window_id_t window_id) {
|
||||||
wm_workspace_t *workspace =
|
workspace_t *workspace =
|
||||||
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
(workspace_t *)state_workspace_get(state, workspace_id);
|
||||||
if (!workspace) return;
|
if (!workspace) return;
|
||||||
|
|
||||||
for (size_t i = 0; i < state->window_count; i++) {
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
wm_window_t *window = &state->windows[i];
|
window_t *window = &state->windows[i];
|
||||||
if (window->id == window_id && window->workspace_id == workspace_id) {
|
if (window->id == window_id && window->workspace_id == workspace_id) {
|
||||||
workspace->focused_window_id = window_id;
|
workspace->focused_window_id = window_id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_state_workspace_adjust_focused_window(state, workspace_id);
|
state_workspace_adjust_focused_window(state, workspace_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t wm_state_workspace_count(const wm_state_t *state) {
|
size_t state_workspace_count(const state_t *state) {
|
||||||
return state->workspace_count;
|
return state->workspace_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_state_workspace_valid(const wm_state_t *state, wm_workspace_id_t id) {
|
bool state_workspace_valid(const state_t *state, workspace_id_t id) {
|
||||||
return id < state->workspace_count;
|
return id < state->workspace_count;
|
||||||
|
|
||||||
/* 线性扫描作为备用 */
|
/* 线性扫描作为备用 */
|
||||||
@@ -211,39 +210,35 @@ bool wm_state_workspace_valid(const wm_state_t *state, wm_workspace_id_t id) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_output_t *wm_state_output_get(const wm_state_t *state,
|
const output_t *state_output_get(const state_t *state, output_id_t id) {
|
||||||
wm_output_id_t id) {
|
|
||||||
if (id < state->output_count) return &state->outputs[id];
|
if (id < state->output_count) return &state->outputs[id];
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_output_t *wm_state_output_at(const wm_state_t *state, size_t index) {
|
const output_t *state_output_at(const state_t *state, size_t index) {
|
||||||
if (index < state->output_count) return &state->outputs[index];
|
if (index < state->output_count) return &state->outputs[index];
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_output_set_workarea(wm_state_t *state, wm_output_id_t output_id,
|
void state_output_set_workarea(state_t *state, output_id_t output_id,
|
||||||
wm_rect_t workarea) {
|
rect_t workarea) {
|
||||||
wm_output_t *output = (wm_output_t *)wm_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 wm_state_output_set_current_workspace(wm_state_t *state,
|
void state_output_set_current_workspace(state_t *state, output_id_t output_id,
|
||||||
wm_output_id_t output_id,
|
workspace_id_t workspace_id) {
|
||||||
wm_workspace_id_t workspace_id) {
|
output_t *output = (output_t *)state_output_get(state, output_id);
|
||||||
wm_output_t *output = (wm_output_t *)wm_state_output_get(state, output_id);
|
|
||||||
if (!output) return;
|
if (!output) return;
|
||||||
const wm_workspace_t *workspace = wm_state_workspace_get(state, workspace_id);
|
const workspace_t *workspace = state_workspace_get(state, workspace_id);
|
||||||
if (!workspace || workspace->output_id != output_id) return;
|
if (!workspace || workspace->output_id != output_id) return;
|
||||||
|
|
||||||
output->current_workspace_id = workspace_id;
|
output->current_workspace_id = workspace_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t wm_state_output_count(const wm_state_t *state) {
|
size_t state_output_count(const state_t *state) { return state->output_count; }
|
||||||
return state->output_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wm_state_output_valid(const wm_state_t *state, wm_output_id_t id) {
|
bool state_output_valid(const state_t *state, output_id_t id) {
|
||||||
return id < state->output_count;
|
return id < state->output_count;
|
||||||
|
|
||||||
/* 线性扫描作为备用 */
|
/* 线性扫描作为备用 */
|
||||||
@@ -258,10 +253,9 @@ bool wm_state_output_valid(const wm_state_t *state, wm_output_id_t id) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_window_t *wm_state_window_add(wm_state_t *state,
|
const window_t *state_window_add(state_t *state, const window_info_t *info) {
|
||||||
const wm_window_info_t *info) {
|
window_id_t id = info->id;
|
||||||
wm_window_id_t id = info->id;
|
window_t *window = (window_t *)state_window_get(state, id);
|
||||||
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, id);
|
|
||||||
if (!window) {
|
if (!window) {
|
||||||
if (state->window_count == state->window_capacity) {
|
if (state->window_count == state->window_capacity) {
|
||||||
size_t capacity = next_capacity(state->window_capacity);
|
size_t capacity = next_capacity(state->window_capacity);
|
||||||
@@ -272,27 +266,26 @@ const wm_window_t *wm_state_window_add(wm_state_t *state,
|
|||||||
window = &state->windows[state->window_count];
|
window = &state->windows[state->window_count];
|
||||||
p_clear(window, 1);
|
p_clear(window, 1);
|
||||||
window->id = id;
|
window->id = id;
|
||||||
window->workspace_id = WM_WORKSPACE_ID_INVALID;
|
window->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
|
||||||
|
|
||||||
state->stack_order[state->window_count] = id;
|
state->stack_order[state->window_count] = id;
|
||||||
state->window_count++;
|
state->window_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_state_window_set_geometry_mode(state, id, info->geometry_mode);
|
state_window_set_geometry_mode(state, id, info->geometry_mode);
|
||||||
wm_state_window_set_urgent(state, id, info->urgent);
|
state_window_set_urgent(state, id, info->urgent);
|
||||||
wm_state_window_set_fixed_size(state, id, info->fixed_size);
|
state_window_set_fixed_size(state, id, info->fixed_size);
|
||||||
wm_state_window_set_frame_rect(state, id, info->frame_rect);
|
state_window_set_frame_rect(state, id, info->frame_rect);
|
||||||
wm_state_window_set_title(state, id, info->title);
|
state_window_set_title(state, id, info->title);
|
||||||
wm_state_window_set_app_id(state, id, info->app_id);
|
state_window_set_app_id(state, id, info->app_id);
|
||||||
wm_state_window_set_class(state, id, info->class_name);
|
state_window_set_class(state, id, info->class_name);
|
||||||
wm_state_window_set_instance(state, id, info->instance_name);
|
state_window_set_instance(state, id, info->instance_name);
|
||||||
wm_state_window_set_skip_taskbar(state, id, info->skip_taskbar);
|
state_window_set_skip_taskbar(state, id, info->skip_taskbar);
|
||||||
|
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_window_t *wm_state_window_get(const wm_state_t *state,
|
const window_t *state_window_get(const state_t *state, window_id_t id) {
|
||||||
wm_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) return &state->windows[i];
|
if (state->windows[i].id == id) return &state->windows[i];
|
||||||
}
|
}
|
||||||
@@ -300,13 +293,13 @@ const wm_window_t *wm_state_window_get(const wm_state_t *state,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_window_t *wm_state_window_at(const wm_state_t *state, size_t index) {
|
const window_t *state_window_at(const state_t *state, size_t index) {
|
||||||
if (index < state->window_count) return &state->windows[index];
|
if (index < state->window_count) return &state->windows[index];
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_window_remove(wm_state_t *state, wm_window_id_t id) {
|
void state_window_remove(state_t *state, window_id_t id) {
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (size_t i = 0; i < state->window_count; i++) {
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
@@ -318,8 +311,8 @@ void wm_state_window_remove(wm_state_t *state, wm_window_id_t id) {
|
|||||||
}
|
}
|
||||||
if (!matched) return;
|
if (!matched) return;
|
||||||
|
|
||||||
wm_window_t *window = &state->windows[index];
|
window_t *window = &state->windows[index];
|
||||||
wm_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);
|
||||||
p_delete(&window->class_name);
|
p_delete(&window->class_name);
|
||||||
@@ -330,8 +323,8 @@ void wm_state_window_remove(wm_state_t *state, wm_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 = WM_WINDOW_ID_INVALID;
|
window->id = ZDWM_WINDOW_ID_INVALID;
|
||||||
window->workspace_id = WM_WORKSPACE_ID_INVALID;
|
window->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
|
||||||
|
|
||||||
matched = false;
|
matched = false;
|
||||||
for (size_t i = 0; i < state->window_count; i++) {
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
@@ -345,158 +338,154 @@ void wm_state_window_remove(wm_state_t *state, wm_window_id_t id) {
|
|||||||
for (size_t i = index + 1; i < state->window_count; i++) {
|
for (size_t i = index + 1; i < state->window_count; i++) {
|
||||||
state->stack_order[i - 1] = state->stack_order[i];
|
state->stack_order[i - 1] = state->stack_order[i];
|
||||||
}
|
}
|
||||||
state->stack_order[state->window_count - 1] = WM_WINDOW_ID_INVALID;
|
state->stack_order[state->window_count - 1] = ZDWM_WINDOW_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->window_count--;
|
state->window_count--;
|
||||||
|
|
||||||
wm_workspace_t *workspace =
|
workspace_t *workspace =
|
||||||
(wm_workspace_t *)wm_state_workspace_get(state, workspace_id);
|
(workspace_t *)state_workspace_get(state, workspace_id);
|
||||||
if (workspace && workspace->focused_window_id == id) {
|
if (workspace && workspace->focused_window_id == id) {
|
||||||
wm_state_workspace_adjust_focused_window(state, workspace_id);
|
state_workspace_adjust_focused_window(state, workspace_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t wm_state_window_count(const wm_state_t *state) {
|
size_t state_window_count(const state_t *state) { return state->window_count; }
|
||||||
return state->window_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wm_state_window_set_workspace(wm_state_t *state, wm_window_id_t window_id,
|
void state_window_set_workspace(state_t *state, window_id_t window_id,
|
||||||
wm_workspace_id_t workspace_id) {
|
workspace_id_t workspace_id) {
|
||||||
const wm_workspace_t *workspace = wm_state_workspace_get(state, workspace_id);
|
const workspace_t *workspace = state_workspace_get(state, workspace_id);
|
||||||
wm_window_t *window = (wm_window_t *)wm_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 = wm_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) {
|
||||||
wm_state_workspace_adjust_focused_window(state, workspace->id);
|
state_workspace_adjust_focused_window(state, workspace->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_state_workspace_adjust_focused_window(state, workspace_id);
|
state_workspace_adjust_focused_window(state, workspace_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_window_set_geometry_mode(
|
void state_window_set_geometry_mode(state_t *state, window_id_t window_id,
|
||||||
wm_state_t *state, wm_window_id_t window_id,
|
window_geometry_mode_t geometry_mode) {
|
||||||
wm_window_geometry_mode_t geometry_mode) {
|
window_t *window = (window_t *)state_window_get(state, window_id);
|
||||||
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
|
|
||||||
window->geometry_mode = geometry_mode;
|
window->geometry_mode = geometry_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_window_set_floating(wm_state_t *state, wm_window_id_t window_id,
|
void state_window_set_floating(state_t *state, window_id_t window_id,
|
||||||
bool floating) {
|
bool floating) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
window_t *window = (window_t *)state_window_get(state, window_id);
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
|
|
||||||
window->floating = floating;
|
window->floating = floating;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_window_set_sticky(wm_state_t *state, wm_window_id_t window_id,
|
void state_window_set_sticky(state_t *state, window_id_t window_id,
|
||||||
bool sticky) {
|
bool sticky) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
window_t *window = (window_t *)state_window_get(state, window_id);
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
|
|
||||||
window->sticky = sticky;
|
window->sticky = sticky;
|
||||||
if (window->sticky) wm_state_window_set_floating(state, window_id, true);
|
if (window->sticky) state_window_set_floating(state, window_id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_window_set_urgent(wm_state_t *state, wm_window_id_t window_id,
|
void state_window_set_urgent(state_t *state, window_id_t window_id,
|
||||||
bool urgent) {
|
bool urgent) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
window_t *window = (window_t *)state_window_get(state, window_id);
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
|
|
||||||
window->urgent = urgent;
|
window->urgent = urgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_window_set_fixed_size(wm_state_t *state, wm_window_id_t window_id,
|
void state_window_set_fixed_size(state_t *state, window_id_t window_id,
|
||||||
bool fixed_size) {
|
bool fixed_size) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
window_t *window = (window_t *)state_window_get(state, window_id);
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
|
|
||||||
window->fixed_size = fixed_size;
|
window->fixed_size = fixed_size;
|
||||||
if (fixed_size) wm_state_window_set_floating(state, window_id, true);
|
if (fixed_size) state_window_set_floating(state, window_id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_window_set_skip_taskbar(wm_state_t *state,
|
void state_window_set_skip_taskbar(state_t *state, window_id_t window_id,
|
||||||
wm_window_id_t window_id,
|
bool skip_taskbar) {
|
||||||
bool skip_taskbar) {
|
window_t *window = (window_t *)state_window_get(state, window_id);
|
||||||
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
|
|
||||||
window->skip_taskbar = skip_taskbar;
|
window->skip_taskbar = skip_taskbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_window_set_float_rect(wm_state_t *state, wm_window_id_t window_id,
|
void state_window_set_float_rect(state_t *state, window_id_t window_id,
|
||||||
wm_rect_t float_rect) {
|
rect_t float_rect) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
window_t *window = (window_t *)state_window_get(state, window_id);
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
|
|
||||||
window->float_rect = float_rect;
|
window->float_rect = float_rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_state_window_set_frame_rect(wm_state_t *state, wm_window_id_t window_id,
|
void state_window_set_frame_rect(state_t *state, window_id_t window_id,
|
||||||
wm_rect_t frame_rect) {
|
rect_t frame_rect) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_state_window_get(state, window_id);
|
window_t *window = (window_t *)state_window_get(state, window_id);
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
|
|
||||||
window->frame_rect = frame_rect;
|
window->frame_rect = frame_rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_state_window_set_title(wm_state_t *state, wm_window_id_t window_id,
|
bool state_window_set_title(state_t *state, window_id_t window_id,
|
||||||
const char *title) {
|
const char *title) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_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;
|
||||||
|
|
||||||
p_delete(&window->title);
|
p_delete(&window->title);
|
||||||
if (title) window->title = p_strdup(title);
|
window->title = p_strdup_nullable(title);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_state_window_set_app_id(wm_state_t *state, wm_window_id_t window_id,
|
bool state_window_set_app_id(state_t *state, window_id_t window_id,
|
||||||
const char *app_id) {
|
const char *app_id) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_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;
|
||||||
|
|
||||||
p_delete(&window->app_id);
|
p_delete(&window->app_id);
|
||||||
if (app_id) window->app_id = p_strdup(app_id);
|
window->app_id = p_strdup_nullable(app_id);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool wm_state_window_set_class(wm_state_t *state, wm_window_id_t window_id,
|
bool state_window_set_class(state_t *state, window_id_t window_id,
|
||||||
const char *class_name) {
|
const char *class_name) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_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;
|
||||||
|
|
||||||
p_delete(&window->class_name);
|
p_delete(&window->class_name);
|
||||||
if (class_name) window->class_name = p_strdup(class_name);
|
window->class_name = p_strdup_nullable(class_name);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool wm_state_window_set_instance(wm_state_t *state, wm_window_id_t window_id,
|
bool state_window_set_instance(state_t *state, window_id_t window_id,
|
||||||
const char *instance_name) {
|
const char *instance_name) {
|
||||||
wm_window_t *window = (wm_window_t *)wm_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;
|
||||||
|
|
||||||
p_delete(&window->instance_name);
|
p_delete(&window->instance_name);
|
||||||
if (instance_name) window->instance_name = p_strdup(instance_name);
|
window->instance_name = p_strdup_nullable(instance_name);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wm_window_id_t *wm_state_stack_order(const wm_state_t *state) {
|
const window_id_t *state_stack_order(const state_t *state) {
|
||||||
return state->stack_order;
|
return state->stack_order;
|
||||||
}
|
}
|
||||||
|
|
||||||
wm_window_id_t wm_state_stack_at(const wm_state_t *state, size_t index) {
|
window_id_t state_stack_at(const state_t *state, size_t index) {
|
||||||
if (index >= state->window_count) return WM_WINDOW_ID_INVALID;
|
if (index >= state->window_count) return ZDWM_WINDOW_ID_INVALID;
|
||||||
return state->stack_order[index];
|
return state->stack_order[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_state_stack_raise(wm_state_t *state, wm_window_id_t window_id) {
|
bool state_stack_raise(state_t *state, window_id_t window_id) {
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (size_t i = 0; i < state->window_count; i++) {
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
@@ -517,7 +506,7 @@ bool wm_state_stack_raise(wm_state_t *state, wm_window_id_t window_id) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_state_stack_lower(wm_state_t *state, wm_window_id_t window_id) {
|
bool state_stack_lower(state_t *state, window_id_t window_id) {
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (size_t i = 0; i < state->window_count; i++) {
|
for (size_t i = 0; i < state->window_count; i++) {
|
||||||
|
|||||||
199
src/core/state.h
199
src/core/state.h
@@ -6,19 +6,19 @@
|
|||||||
#include "core/wm_desc.h"
|
#include "core/wm_desc.h"
|
||||||
|
|
||||||
/* 核心实体定义 */
|
/* 核心实体定义 */
|
||||||
typedef struct wm_window_t {
|
typedef struct window_t {
|
||||||
wm_window_id_t id;
|
window_id_t id;
|
||||||
wm_workspace_id_t workspace_id;
|
workspace_id_t workspace_id;
|
||||||
|
|
||||||
wm_window_geometry_mode_t geometry_mode;
|
window_geometry_mode_t geometry_mode;
|
||||||
bool floating;
|
bool floating;
|
||||||
bool sticky;
|
bool sticky;
|
||||||
bool urgent;
|
bool urgent;
|
||||||
bool fixed_size;
|
bool fixed_size;
|
||||||
|
|
||||||
/* 几何信息(均为包含边框后的外框矩形) */
|
/* 几何信息(均为包含边框后的外框矩形) */
|
||||||
wm_rect_t float_rect; /* floating 模式下记忆的外框矩形 */
|
rect_t float_rect; /* floating 模式下记忆的外框矩形 */
|
||||||
wm_rect_t frame_rect; /* 当前外框矩形(由 layout 或 float_rect 解析) */
|
rect_t frame_rect; /* 当前外框矩形(由 layout 或 float_rect 解析) */
|
||||||
|
|
||||||
/* 元数据(核心算法不依赖,仅用于规则匹配和信息展示) */
|
/* 元数据(核心算法不依赖,仅用于规则匹配和信息展示) */
|
||||||
const char *title;
|
const char *title;
|
||||||
@@ -27,67 +27,67 @@ typedef struct wm_window_t {
|
|||||||
const char *instance_name;
|
const char *instance_name;
|
||||||
|
|
||||||
bool skip_taskbar;
|
bool skip_taskbar;
|
||||||
} wm_window_t;
|
} window_t;
|
||||||
|
|
||||||
typedef struct wm_workspace_t {
|
typedef struct workspace_t {
|
||||||
wm_workspace_id_t id;
|
workspace_id_t id;
|
||||||
wm_output_id_t output_id; /* 固定归属某个输出 */
|
output_id_t output_id; /* 固定归属某个输出 */
|
||||||
wm_layout_id_t layout_id; /* 当前活动布局(可用布局列表中的一个) */
|
layout_id_t layout_id; /* 当前活动布局(可用布局列表中的一个) */
|
||||||
wm_window_id_t focused_window_id;
|
window_id_t focused_window_id;
|
||||||
|
|
||||||
/* 当前 workspace 的可用布局列表 */
|
/* 当前 workspace 的可用布局列表 */
|
||||||
const wm_layout_id_t *available_layouts;
|
const layout_id_t *available_layouts;
|
||||||
size_t layout_count;
|
size_t layout_count;
|
||||||
|
|
||||||
/* 名称(核心算法不依赖) */
|
/* 名称(核心算法不依赖) */
|
||||||
const char *name;
|
const char *name;
|
||||||
} wm_workspace_t;
|
} workspace_t;
|
||||||
|
|
||||||
typedef struct wm_output_t {
|
typedef struct output_t {
|
||||||
wm_output_id_t id;
|
output_id_t id;
|
||||||
wm_workspace_id_t current_workspace_id;
|
workspace_id_t current_workspace_id;
|
||||||
const char *name;
|
const char *name;
|
||||||
wm_rect_t geometry; /* 输出完整几何 */
|
rect_t geometry; /* 输出完整几何 */
|
||||||
wm_rect_t workarea; /* 可用区域(排除面板等) */
|
rect_t workarea; /* 可用区域(排除面板等) */
|
||||||
} wm_output_t;
|
} output_t;
|
||||||
|
|
||||||
/* 全局状态容器 */
|
/* 全局状态容器 */
|
||||||
typedef struct wm_state_t {
|
typedef struct state_t {
|
||||||
/* 按 id 稳定引用的 workspace / output 集合 */
|
/* 按 id 稳定引用的 workspace / output 集合 */
|
||||||
wm_workspace_t *workspaces;
|
workspace_t *workspaces;
|
||||||
size_t workspace_count;
|
size_t workspace_count;
|
||||||
|
|
||||||
wm_output_t *outputs;
|
output_t *outputs;
|
||||||
size_t output_count;
|
size_t output_count;
|
||||||
|
|
||||||
wm_window_t *windows;
|
window_t *windows;
|
||||||
size_t window_count;
|
size_t window_count;
|
||||||
size_t window_capacity;
|
size_t window_capacity;
|
||||||
|
|
||||||
/* 与 windows[] 一一对应的堆叠顺序视图,长度等于 window_count */
|
/* 与 windows[] 一一对应的堆叠顺序视图,长度等于 window_count */
|
||||||
wm_window_id_t *stack_order;
|
window_id_t *stack_order;
|
||||||
|
|
||||||
} wm_state_t;
|
} state_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 调用约束:
|
* 调用约束:
|
||||||
* - state 必须是有效的非空指针
|
* - state 必须是有效的非空指针
|
||||||
* - wm_state_init() / wm_state_cleanup() 必须成对调用
|
* - state_init() / state_cleanup() 必须成对调用
|
||||||
* - 同一个 state 生命周期内,wm_state_init() 不允许重复调用
|
* - 同一个 state 生命周期内,state_init() 不允许重复调用
|
||||||
* - 除 wm_state_init() 外,其余 state 相关接口都要求 state 已初始化
|
* - 除 state_init() 外,其余 state 相关接口都要求 state 已初始化
|
||||||
* - workspaces[i] 必须满足 wm_workspace_desc_valid(&workspaces[i],
|
* - workspaces[i] 必须满足 workspace_desc_valid(&workspaces[i],
|
||||||
* output_count)
|
* output_count)
|
||||||
* - 传入空指针、未初始化对象或违反前置条件属于调用方错误
|
* - 传入空指针、未初始化对象或违反前置条件属于调用方错误
|
||||||
*
|
*
|
||||||
* 初始化时根据描述表构建 outputs[] 与 workspaces[]。
|
* 初始化时根据描述表构建 outputs[] 与 workspaces[]。
|
||||||
* workspace_id 由 state 按描述表顺序分配并保持稳定,不从 desc 中读取。
|
* workspace_id 由 state 按描述表顺序分配并保持稳定,不从 desc 中读取。
|
||||||
* 每个 output 的 current_workspace_id 会自动设置为首个归属到该 output 的
|
* 每个 output 的 current_workspace_id 会自动设置为首个归属到该 output 的
|
||||||
* workspace;若某个 output 没有任何归属 workspace,wm_state_init() 会失败。
|
* workspace;若某个 output 没有任何归属 workspace,state_init() 会失败。
|
||||||
*/
|
*/
|
||||||
void wm_state_init(wm_state_t *state, const wm_output_info_t *outputs,
|
void state_init(state_t *state, const output_info_t *outputs,
|
||||||
size_t output_count, const wm_workspace_desc_t *workspaces,
|
size_t output_count, const workspace_desc_t *workspaces,
|
||||||
size_t workspace_count);
|
size_t workspace_count);
|
||||||
void wm_state_cleanup(wm_state_t *state);
|
void state_cleanup(state_t *state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* state 持有的 workspace 集合接口
|
* state 持有的 workspace 集合接口
|
||||||
@@ -95,23 +95,20 @@ void wm_state_cleanup(wm_state_t *state);
|
|||||||
* 这组接口对外只提供只读访问。
|
* 这组接口对外只提供只读访问。
|
||||||
* workspace 的运行期可变状态必须通过专门的 state 级更新接口修改。
|
* workspace 的运行期可变状态必须通过专门的 state 级更新接口修改。
|
||||||
*/
|
*/
|
||||||
const wm_workspace_t *wm_state_workspace_get(const wm_state_t *state,
|
const workspace_t *state_workspace_get(const state_t *state, workspace_id_t id);
|
||||||
wm_workspace_id_t id);
|
const workspace_t *state_workspace_at(const state_t *state, size_t index);
|
||||||
const wm_workspace_t *wm_state_workspace_at(const wm_state_t *state,
|
bool state_workspace_cycle_layout(state_t *state, workspace_id_t workspace_id);
|
||||||
size_t index);
|
bool state_workspace_set_layout_by_index(state_t *state,
|
||||||
bool wm_state_workspace_cycle_layout(wm_state_t *state,
|
workspace_id_t workspace_id,
|
||||||
wm_workspace_id_t workspace_id);
|
size_t index);
|
||||||
bool wm_state_workspace_set_layout_by_index(wm_state_t *state,
|
bool state_workspace_set_layout_by_id(state_t *state,
|
||||||
wm_workspace_id_t workspace_id,
|
workspace_id_t workspace_id,
|
||||||
size_t index);
|
layout_id_t layout_id);
|
||||||
bool wm_state_workspace_set_layout_by_id(wm_state_t *state,
|
void state_workspace_set_focused_window(state_t *state,
|
||||||
wm_workspace_id_t workspace_id,
|
workspace_id_t workspace_id,
|
||||||
wm_layout_id_t layout_id);
|
window_id_t window_id);
|
||||||
void wm_state_workspace_set_focused_window(wm_state_t *state,
|
size_t state_workspace_count(const state_t *state);
|
||||||
wm_workspace_id_t workspace_id,
|
bool state_workspace_valid(const state_t *state, workspace_id_t id);
|
||||||
wm_window_id_t window_id);
|
|
||||||
size_t wm_state_workspace_count(const wm_state_t *state);
|
|
||||||
bool wm_state_workspace_valid(const wm_state_t *state, wm_workspace_id_t id);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* state 持有的 output 集合接口
|
* state 持有的 output 集合接口
|
||||||
@@ -119,21 +116,19 @@ bool wm_state_workspace_valid(const wm_state_t *state, wm_workspace_id_t id);
|
|||||||
* 这组接口对外只提供只读访问。
|
* 这组接口对外只提供只读访问。
|
||||||
* output 的运行期可变状态必须通过专门的 state 级更新接口修改。
|
* output 的运行期可变状态必须通过专门的 state 级更新接口修改。
|
||||||
*/
|
*/
|
||||||
const wm_output_t *wm_state_output_get(const wm_state_t *state,
|
const output_t *state_output_get(const state_t *state, output_id_t id);
|
||||||
wm_output_id_t id);
|
const output_t *state_output_at(const state_t *state, size_t index);
|
||||||
const wm_output_t *wm_state_output_at(const wm_state_t *state, size_t index);
|
void state_output_set_workarea(state_t *state, output_id_t output_id,
|
||||||
void wm_state_output_set_workarea(wm_state_t *state, wm_output_id_t output_id,
|
rect_t workarea);
|
||||||
wm_rect_t workarea);
|
void state_output_set_current_workspace(state_t *state, output_id_t output_id,
|
||||||
void wm_state_output_set_current_workspace(wm_state_t *state,
|
workspace_id_t workspace_id);
|
||||||
wm_output_id_t output_id,
|
size_t state_output_count(const state_t *state);
|
||||||
wm_workspace_id_t workspace_id);
|
bool state_output_valid(const state_t *state, output_id_t id);
|
||||||
size_t wm_state_output_count(const wm_state_t *state);
|
|
||||||
bool wm_state_output_valid(const wm_state_t *state, wm_output_id_t id);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* state 持有的 window 集合接口
|
* state 持有的 window 集合接口
|
||||||
*
|
*
|
||||||
* 这组接口负责管理 wm_state_t.windows[] 容器本身,并保持
|
* 这组接口负责管理 state_t.windows[] 容器本身,并保持
|
||||||
* stack_order[] 与 windows[] 同步。
|
* stack_order[] 与 windows[] 同步。
|
||||||
* 对外只提供只读访问。
|
* 对外只提供只读访问。
|
||||||
* window 的运行期可变状态必须通过专门的 state 级更新接口修改。
|
* window 的运行期可变状态必须通过专门的 state 级更新接口修改。
|
||||||
@@ -142,54 +137,50 @@ bool wm_state_output_valid(const wm_state_t *state, wm_output_id_t id);
|
|||||||
* 添加窗口,并将其追加到 stack_order[] 顶部。
|
* 添加窗口,并将其追加到 stack_order[] 顶部。
|
||||||
*
|
*
|
||||||
* info 提供 backend 已探测到的窗口基础信息。
|
* info 提供 backend 已探测到的窗口基础信息。
|
||||||
* workspace 归属与其他策略相关字段由后续 wm_state_window_* 接口设置。
|
* workspace 归属与其他策略相关字段由后续 state_window_* 接口设置。
|
||||||
*/
|
*/
|
||||||
const wm_window_t *wm_state_window_add(wm_state_t *state,
|
const window_t *state_window_add(state_t *state, const window_info_t *info);
|
||||||
const wm_window_info_t *info);
|
const window_t *state_window_get(const state_t *state, window_id_t id);
|
||||||
const wm_window_t *wm_state_window_get(const wm_state_t *state,
|
const window_t *state_window_at(const state_t *state, size_t index);
|
||||||
wm_window_id_t id);
|
|
||||||
const wm_window_t *wm_state_window_at(const wm_state_t *state, size_t index);
|
|
||||||
/* 删除窗口,并同步从 stack_order[] 中移除。 */
|
/* 删除窗口,并同步从 stack_order[] 中移除。 */
|
||||||
void wm_state_window_remove(wm_state_t *state, wm_window_id_t id);
|
void state_window_remove(state_t *state, window_id_t id);
|
||||||
size_t wm_state_window_count(const wm_state_t *state);
|
size_t state_window_count(const state_t *state);
|
||||||
|
|
||||||
/* state 持有的单个 window 状态更新接口 */
|
/* state 持有的单个 window 状态更新接口 */
|
||||||
void wm_state_window_set_workspace(wm_state_t *state, wm_window_id_t window_id,
|
void state_window_set_workspace(state_t *state, window_id_t window_id,
|
||||||
wm_workspace_id_t workspace_id);
|
workspace_id_t workspace_id);
|
||||||
void wm_state_window_set_geometry_mode(wm_state_t *state,
|
void state_window_set_geometry_mode(state_t *state, window_id_t window_id,
|
||||||
wm_window_id_t window_id,
|
window_geometry_mode_t geometry_mode);
|
||||||
wm_window_geometry_mode_t geometry_mode);
|
void state_window_set_floating(state_t *state, window_id_t window_id,
|
||||||
void wm_state_window_set_floating(wm_state_t *state, wm_window_id_t window_id,
|
bool floating);
|
||||||
bool floating);
|
void state_window_set_sticky(state_t *state, window_id_t window_id,
|
||||||
void wm_state_window_set_sticky(wm_state_t *state, wm_window_id_t window_id,
|
bool sticky);
|
||||||
bool sticky);
|
void state_window_set_urgent(state_t *state, window_id_t window_id,
|
||||||
void wm_state_window_set_urgent(wm_state_t *state, wm_window_id_t window_id,
|
bool urgent);
|
||||||
bool urgent);
|
void state_window_set_fixed_size(state_t *state, window_id_t window_id,
|
||||||
void wm_state_window_set_fixed_size(wm_state_t *state, wm_window_id_t window_id,
|
bool fixed_size);
|
||||||
bool fixed_size);
|
void state_window_set_skip_taskbar(state_t *state, window_id_t window_id,
|
||||||
void wm_state_window_set_skip_taskbar(wm_state_t *state,
|
bool skip_taskbar);
|
||||||
wm_window_id_t window_id,
|
void state_window_set_float_rect(state_t *state, window_id_t window_id,
|
||||||
bool skip_taskbar);
|
rect_t float_rect);
|
||||||
void wm_state_window_set_float_rect(wm_state_t *state, wm_window_id_t window_id,
|
void state_window_set_frame_rect(state_t *state, window_id_t window_id,
|
||||||
wm_rect_t float_rect);
|
rect_t frame_rect);
|
||||||
void wm_state_window_set_frame_rect(wm_state_t *state, wm_window_id_t window_id,
|
bool state_window_set_title(state_t *state, window_id_t window_id,
|
||||||
wm_rect_t frame_rect);
|
const char *title);
|
||||||
bool wm_state_window_set_title(wm_state_t *state, wm_window_id_t window_id,
|
bool state_window_set_app_id(state_t *state, window_id_t window_id,
|
||||||
const char *title);
|
const char *app_id);
|
||||||
bool wm_state_window_set_app_id(wm_state_t *state, wm_window_id_t window_id,
|
bool state_window_set_class(state_t *state, window_id_t window_id,
|
||||||
const char *app_id);
|
const char *class_name);
|
||||||
bool wm_state_window_set_class(wm_state_t *state, wm_window_id_t window_id,
|
bool state_window_set_instance(state_t *state, window_id_t window_id,
|
||||||
const char *class_name);
|
const char *instance_name);
|
||||||
bool wm_state_window_set_instance(wm_state_t *state, wm_window_id_t window_id,
|
|
||||||
const char *instance_name);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* state 持有的堆叠顺序接口
|
* state 持有的堆叠顺序接口
|
||||||
*
|
*
|
||||||
* stack_order[] 是全局 z-order 的唯一真相,从下到上排列。
|
* stack_order[] 是全局 z-order 的唯一真相,从下到上排列。
|
||||||
* 其长度恒等于 wm_state_window_count(state),因此不提供单独的 count 接口。
|
* 其长度恒等于 state_window_count(state),因此不提供单独的 count 接口。
|
||||||
*/
|
*/
|
||||||
const wm_window_id_t *wm_state_stack_order(const wm_state_t *state);
|
const window_id_t *state_stack_order(const state_t *state);
|
||||||
wm_window_id_t wm_state_stack_at(const wm_state_t *state, size_t index);
|
window_id_t state_stack_at(const state_t *state, size_t index);
|
||||||
bool wm_state_stack_raise(wm_state_t *state, wm_window_id_t window_id);
|
bool state_stack_raise(state_t *state, window_id_t window_id);
|
||||||
bool wm_state_stack_lower(wm_state_t *state, wm_window_id_t window_id);
|
bool state_stack_lower(state_t *state, window_id_t window_id);
|
||||||
|
|||||||
@@ -1,45 +1,38 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <zdwm/types.h>
|
||||||
typedef uint32_t wm_window_id_t;
|
|
||||||
typedef uint32_t wm_workspace_id_t;
|
|
||||||
typedef uint32_t wm_output_id_t;
|
|
||||||
typedef uint32_t wm_layout_id_t;
|
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
/* 无效 ID 标记 */
|
typedef zdwm_layout_id_t layout_id_t;
|
||||||
#define WM_WINDOW_ID_INVALID ((wm_window_id_t)0)
|
typedef zdwm_window_id_t window_id_t;
|
||||||
#define WM_WORKSPACE_ID_INVALID ((wm_workspace_id_t)UINT32_MAX)
|
typedef zdwm_workspace_id_t workspace_id_t;
|
||||||
#define WM_OUTPUT_ID_INVALID ((wm_output_id_t)UINT32_MAX)
|
typedef uint32_t output_id_t;
|
||||||
#define WM_LAYOUT_ID_INVALID ((wm_layout_id_t)UINT32_MAX)
|
|
||||||
|
typedef zdwm_rect_t rect_t;
|
||||||
|
typedef zdwm_output_info_t output_info_t;
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
typedef struct wm_point_t {
|
#define ZDWM_OUTPUT_ID_INVALID ((output_id_t)UINT32_MAX)
|
||||||
|
|
||||||
|
typedef struct point_t {
|
||||||
int32_t x;
|
int32_t x;
|
||||||
int32_t y;
|
int32_t y;
|
||||||
} wm_point_t;
|
} point_t;
|
||||||
|
|
||||||
typedef struct wm_rect_t {
|
typedef enum window_geometry_mode_t {
|
||||||
int32_t x;
|
ZDWM_GEOMETRY_NORMAL,
|
||||||
int32_t y;
|
ZDWM_GEOMETRY_MAXIMIZED,
|
||||||
int32_t width;
|
ZDWM_GEOMETRY_FULLSCREEN,
|
||||||
int32_t height;
|
ZDWM_GEOMETRY_MINIMIZED,
|
||||||
} wm_rect_t;
|
} window_geometry_mode_t;
|
||||||
|
|
||||||
typedef enum wm_window_geometry_mode_t {
|
typedef enum focus_direction_t {
|
||||||
WM_GEOMETRY_NORMAL,
|
ZDWM_FOCUS_PREV,
|
||||||
WM_GEOMETRY_MAXIMIZED,
|
ZDWM_FOCUS_NEXT,
|
||||||
WM_GEOMETRY_FULLSCREEN,
|
} focus_direction_t;
|
||||||
WM_GEOMETRY_MINIMIZED,
|
|
||||||
} wm_window_geometry_mode_t;
|
|
||||||
|
|
||||||
typedef enum wm_focus_direction_t {
|
typedef enum cross_output_policy_t {
|
||||||
WM_FOCUS_PREV,
|
ZDWM_CROSS_OUTPUT_KEEP_WORKSPACE,
|
||||||
WM_FOCUS_NEXT,
|
ZDWM_CROSS_OUTPUT_MOVE_TO_TARGET_WORKSPACE,
|
||||||
} wm_focus_direction_t;
|
} cross_output_policy_t;
|
||||||
|
|
||||||
typedef enum wm_cross_output_policy_t {
|
|
||||||
WM_CROSS_OUTPUT_KEEP_WORKSPACE,
|
|
||||||
WM_CROSS_OUTPUT_MOVE_TO_TARGET_WORKSPACE,
|
|
||||||
} wm_cross_output_policy_t;
|
|
||||||
|
|||||||
@@ -4,46 +4,41 @@
|
|||||||
|
|
||||||
#include "core/types.h"
|
#include "core/types.h"
|
||||||
|
|
||||||
typedef struct wm_output_info_t {
|
|
||||||
char *name;
|
|
||||||
wm_rect_t geometry;
|
|
||||||
} wm_output_info_t;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 由 backend 提供的窗口基础信息。
|
* 由 backend 提供的窗口基础信息。
|
||||||
*
|
*
|
||||||
* 这些字符串由调用方提供;state 如需长期持有,应自行复制。
|
* 这些字符串由调用方提供;state 如需长期持有,应自行复制。
|
||||||
*/
|
*/
|
||||||
typedef struct wm_window_info_t {
|
typedef struct window_info_t {
|
||||||
wm_window_id_t id;
|
window_id_t id;
|
||||||
wm_rect_t frame_rect;
|
rect_t frame_rect;
|
||||||
|
|
||||||
const char *title;
|
const char *title;
|
||||||
const char *app_id;
|
const char *app_id;
|
||||||
const char *class_name;
|
const char *class_name;
|
||||||
const char *instance_name;
|
const char *instance_name;
|
||||||
|
|
||||||
wm_window_geometry_mode_t geometry_mode;
|
window_geometry_mode_t geometry_mode;
|
||||||
bool urgent;
|
bool urgent;
|
||||||
bool fixed_size;
|
bool fixed_size;
|
||||||
bool skip_taskbar;
|
bool skip_taskbar;
|
||||||
} wm_window_info_t;
|
} window_info_t;
|
||||||
|
|
||||||
typedef struct wm_workspace_desc_t {
|
typedef struct workspace_desc_t {
|
||||||
size_t output_index; /* 对应 wm_state_init() 中 outputs[] 的索引 */
|
size_t output_index; /* 对应 state_init() 中 outputs[] 的索引 */
|
||||||
const char *name;
|
const char *name;
|
||||||
const wm_layout_id_t *layout_ids;
|
const layout_id_t *layout_ids;
|
||||||
size_t layout_count;
|
size_t layout_count;
|
||||||
wm_layout_id_t initial_layout_id;
|
layout_id_t initial_layout_id;
|
||||||
} wm_workspace_desc_t;
|
} workspace_desc_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* workspace 描述校验接口。
|
* workspace 描述校验接口。
|
||||||
*
|
*
|
||||||
* 这组接口只校验描述表自身的一致性,不访问 state。
|
* 这组接口只校验描述表自身的一致性,不访问 state。
|
||||||
*/
|
*/
|
||||||
static inline bool wm_workspace_desc_layouts_valid(
|
static inline bool workspace_desc_layouts_valid(
|
||||||
const wm_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;
|
||||||
}
|
}
|
||||||
@@ -55,10 +50,10 @@ static inline bool wm_workspace_desc_layouts_valid(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool wm_workspace_desc_valid(const wm_workspace_desc_t *workspace,
|
static inline bool workspace_desc_valid(const workspace_desc_t *workspace,
|
||||||
size_t output_count) {
|
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;
|
||||||
|
|
||||||
return wm_workspace_desc_layouts_valid(workspace);
|
return workspace_desc_layouts_valid(workspace);
|
||||||
}
|
}
|
||||||
|
|||||||
128
src/utils.h
128
src/utils.h
@@ -1,126 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdarg.h>
|
/* Compatibility umbrella header. Prefer including headers from src/base in new
|
||||||
#include <stddef.h>
|
* code. */
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define ssizeof(foo) (ssize_t)sizeof(foo)
|
#include "base/log.h"
|
||||||
#define countof(foo) (ssizeof(foo) / ssizeof(foo[0]))
|
#include "base/macros.h"
|
||||||
|
#include "base/memory.h"
|
||||||
#define p_alloc_nr(x) (((x) + 16) * 3 / 2)
|
|
||||||
#define p_new(type, count) ((type *)xmalloc(sizeof(type) * (count)))
|
|
||||||
#define p_clear(p, count) ((void)memset((p), 0, sizeof(*(p)) * (count)))
|
|
||||||
#define p_realloc(pp, count) xrealloc((void *)(pp), sizeof(**(pp)) * (count))
|
|
||||||
#define p_copy(src, count) xmemcopy((src), sizeof(*(src)) * (count))
|
|
||||||
|
|
||||||
#define p_delete(mem_p) \
|
|
||||||
do { \
|
|
||||||
void **__ptr = (void **)(mem_p); \
|
|
||||||
free(*__ptr); \
|
|
||||||
*(void **)__ptr = nullptr; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#define likely(expr) __builtin_expect(!!(expr), 1)
|
|
||||||
#define unlikely(expr) __builtin_expect((expr), 0)
|
|
||||||
#else
|
|
||||||
#define likely(expr) expr
|
|
||||||
#define unlikely(expr) expr
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline char *p_strdup(const char *text) {
|
|
||||||
char *r = strdup(text);
|
|
||||||
if (!r) abort();
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *__attribute__((malloc)) xmalloc(ssize_t size) {
|
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
if (size <= 0) return nullptr;
|
|
||||||
|
|
||||||
ptr = calloc(1, size);
|
|
||||||
|
|
||||||
if (!ptr) abort();
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *xmemcopy(const void *src, size_t n) {
|
|
||||||
if (!n) return nullptr;
|
|
||||||
|
|
||||||
void *mem = xmalloc(n);
|
|
||||||
void *ret = memcpy(mem, src, n);
|
|
||||||
if (ret != mem) abort();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void xrealloc(void **ptr, ssize_t newsize) {
|
|
||||||
if (newsize <= 0)
|
|
||||||
p_delete(ptr);
|
|
||||||
else {
|
|
||||||
*ptr = realloc(*ptr, newsize);
|
|
||||||
if (!*ptr) abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief nullptr resistant strlen.
|
|
||||||
*
|
|
||||||
* Unlike it's libc sibling, a_strlen returns a ssize_t, and supports its
|
|
||||||
* argument being nullptr.
|
|
||||||
*
|
|
||||||
* @param s the string.
|
|
||||||
* @return the string length (or 0 if s is nullptr).
|
|
||||||
*/
|
|
||||||
static inline ssize_t a_strlen(const char *s) { return s ? strlen(s) : 0; }
|
|
||||||
|
|
||||||
#define fatal(format, ...) \
|
|
||||||
_fatal(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__)
|
|
||||||
void _fatal(int line, const char *function, const char *file,
|
|
||||||
const char *format, ...) __attribute__((noreturn))
|
|
||||||
__attribute__((format(printf, 4, 5)));
|
|
||||||
|
|
||||||
#define warn(format, ...) \
|
|
||||||
_warn(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__)
|
|
||||||
void _warn(int line, const char *function, const char *file, const char *format,
|
|
||||||
...) __attribute__((format(printf, 4, 5)));
|
|
||||||
|
|
||||||
const char *current_time_str(void);
|
|
||||||
|
|
||||||
#if defined(RELEASE)
|
|
||||||
#define logger(format, ...)
|
|
||||||
#elif defined(LOG_FILE)
|
|
||||||
static inline void logger(const char *format, ...) {
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, format);
|
|
||||||
FILE *log_file = fopen(LOG_FILE, "a+t");
|
|
||||||
vfprintf(log_file, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
fclose(log_file);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define logger(format, ...) printf(format, ##__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MIN
|
|
||||||
#undef MIN
|
|
||||||
#endif
|
|
||||||
#ifndef MIN
|
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MAX
|
|
||||||
#undef MAX
|
|
||||||
#endif
|
|
||||||
#ifndef MAX
|
|
||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static constexpr size_t INIT_CAPACITY = 4;
|
|
||||||
static inline size_t next_capacity(size_t capacity) {
|
|
||||||
if (capacity) return capacity * 2;
|
|
||||||
return INIT_CAPACITY;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ add_executable(${OUTPUT_UTILS_TEST_APP_NAME}
|
|||||||
${SOURCE_DIR}/backend/output_utils.c
|
${SOURCE_DIR}/backend/output_utils.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_include_directories(${OUTPUT_UTILS_TEST_APP_NAME} SYSTEM
|
||||||
|
PRIVATE ${INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
target_include_directories(${OUTPUT_UTILS_TEST_APP_NAME}
|
target_include_directories(${OUTPUT_UTILS_TEST_APP_NAME}
|
||||||
PRIVATE ${SOURCE_DIR}
|
PRIVATE ${SOURCE_DIR}
|
||||||
PRIVATE ${BUILD_DIR}
|
PRIVATE ${BUILD_DIR}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
|
#include "backend/output_utils.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "backend/output_utils.h"
|
#include "core/types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
static void assert_output_geometry(const wm_output_info_t *output, int32_t x,
|
static void assert_output_geometry(const output_info_t *output, int32_t x,
|
||||||
int32_t y, int32_t width,
|
int32_t y, int32_t width, int32_t height) {
|
||||||
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);
|
||||||
@@ -14,7 +15,7 @@ static void assert_output_geometry(const wm_output_info_t *output, int32_t x,
|
|||||||
assert(output->geometry.height == height);
|
assert(output->geometry.height == height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_detect_result(wm_backend_detect_t *detect) {
|
static void destroy_detect_result(backend_detect_t *detect) {
|
||||||
assert(detect);
|
assert(detect);
|
||||||
for (size_t i = 0; i < detect->output_count; i++) {
|
for (size_t i = 0; i < detect->output_count; i++) {
|
||||||
p_delete(&detect->outputs[i].name);
|
p_delete(&detect->outputs[i].name);
|
||||||
@@ -24,14 +25,14 @@ static void destroy_detect_result(wm_backend_detect_t *detect) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_output_remove_duplication_invalid_input(void) {
|
static void test_output_remove_duplication_invalid_input(void) {
|
||||||
wm_output_info_t output = {0};
|
output_info_t output = {0};
|
||||||
|
|
||||||
assert(output_remove_duplication(nullptr, 0) == nullptr);
|
assert(output_remove_duplication(nullptr, 0) == nullptr);
|
||||||
assert(output_remove_duplication(&output, 0) == nullptr);
|
assert(output_remove_duplication(&output, 0) == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_output_remove_duplication_keeps_non_nested_outputs(void) {
|
static void test_output_remove_duplication_keeps_non_nested_outputs(void) {
|
||||||
wm_output_info_t outputs[] = {
|
output_info_t outputs[] = {
|
||||||
{
|
{
|
||||||
.geometry = {.x = 0, .y = 0, .width = 3840, .height = 1080},
|
.geometry = {.x = 0, .y = 0, .width = 3840, .height = 1080},
|
||||||
},
|
},
|
||||||
@@ -46,7 +47,7 @@ static void test_output_remove_duplication_keeps_non_nested_outputs(void) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
wm_backend_detect_t *detect =
|
backend_detect_t *detect =
|
||||||
output_remove_duplication(outputs, countof(outputs));
|
output_remove_duplication(outputs, countof(outputs));
|
||||||
assert(detect);
|
assert(detect);
|
||||||
assert(detect->output_count == 2);
|
assert(detect->output_count == 2);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ set(TEST_APP_NAME "zdwm-tests")
|
|||||||
|
|
||||||
add_executable(${TEST_APP_NAME}
|
add_executable(${TEST_APP_NAME}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/main.c
|
${CMAKE_CURRENT_SOURCE_DIR}/main.c
|
||||||
${SOURCE_DIR}/utils.c
|
${SOURCE_DIR}/base/log.c
|
||||||
${SOURCE_DIR}/backend/output_utils.c
|
${SOURCE_DIR}/backend/output_utils.c
|
||||||
${SOURCE_DIR}/backend/x11/backend.c
|
${SOURCE_DIR}/backend/x11/backend.c
|
||||||
${SOURCE_DIR}/core/layout.c
|
${SOURCE_DIR}/core/layout.c
|
||||||
@@ -12,6 +12,7 @@ add_executable(${TEST_APP_NAME}
|
|||||||
|
|
||||||
target_include_directories(${TEST_APP_NAME} SYSTEM
|
target_include_directories(${TEST_APP_NAME} SYSTEM
|
||||||
PRIVATE ${deps_INCLUDE_DIRS}
|
PRIVATE ${deps_INCLUDE_DIRS}
|
||||||
|
PRIVATE ${INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
target_include_directories(${TEST_APP_NAME}
|
target_include_directories(${TEST_APP_NAME}
|
||||||
PRIVATE ${SOURCE_DIR}
|
PRIVATE ${SOURCE_DIR}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#include "core/runtime.h"
|
#include "core/runtime.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
wm_runtime_t runtime = {0};
|
runtime_t runtime = {0};
|
||||||
wm_runtime_init(&runtime);
|
runtime_init(&runtime, nullptr);
|
||||||
|
|
||||||
wm_runtime_shutdown(&runtime);
|
runtime_shutdown(&runtime);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user