diff --git a/CMakeLists.txt b/CMakeLists.txt index 379b33b..6a9597e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ option(BUILD_TESTING "Build tests" OFF) add_executable(${APP_NAME} ${SOURCE_DIR}/wm.c - ${SOURCE_DIR}/utils.c + ${SOURCE_DIR}/base/log.c ${SOURCE_DIR}/buffer.c ${SOURCE_DIR}/backtrace.c ${SOURCE_DIR}/monitor.c diff --git a/src/backend/output_utils.c b/src/backend/output_utils.c index 30a798a..d2abd8d 100644 --- a/src/backend/output_utils.c +++ b/src/backend/output_utils.c @@ -3,9 +3,9 @@ #include #include +#include "base/memory.h" #include "core/backend.h" #include "core/types.h" -#include "utils.h" static inline int32_t right(rect_t a) { return a.x + a.width; } static inline int32_t bottom(rect_t a) { return a.y + a.height; } diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index ae5dc9f..be25fb3 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -12,8 +12,9 @@ #include #include "backend/output_utils.h" +#include "base/log.h" +#include "base/memory.h" #include "core/types.h" -#include "utils.h" struct backend_t { xcb_connection_t *conn; diff --git a/src/utils.c b/src/base/log.c similarity index 89% rename from src/utils.c rename to src/base/log.c index d64f68f..bc5a667 100644 --- a/src/utils.c +++ b/src/base/log.c @@ -1,4 +1,4 @@ -#include "utils.h" +#include "base/log.h" #include #include @@ -19,9 +19,6 @@ const char *current_time_str(void) { return buffer; } -/** - * Print error and exit with EXIT_FAILURE code. - */ void _fatal(int line, const char *fct, const char *file, const char *fmt, ...) { va_list ap; @@ -34,9 +31,6 @@ void _fatal(int line, const char *fct, const char *file, const char *fmt, ...) { exit(EXIT_FAILURE); } -/** - * Print error message on stderr - */ void _warn(int line, const char *fct, const char *file, const char *fmt, ...) { va_list ap; diff --git a/src/base/log.h b/src/base/log.h new file mode 100644 index 0000000..af5ff3f --- /dev/null +++ b/src/base/log.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#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 diff --git a/src/base/macros.h b/src/base/macros.h new file mode 100644 index 0000000..2ae2e8d --- /dev/null +++ b/src/base/macros.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +#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 diff --git a/src/base/memory.h b/src/base/memory.h new file mode 100644 index 0000000..705d1da --- /dev/null +++ b/src/base/memory.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include + +#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; +} diff --git a/src/config/loader.c b/src/config/loader.c index ec07854..7eb7c70 100644 --- a/src/config/loader.c +++ b/src/config/loader.c @@ -4,7 +4,8 @@ #include #include -#include "utils.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; diff --git a/src/core/layout.c b/src/core/layout.c index 535e64d..0561a47 100644 --- a/src/core/layout.c +++ b/src/core/layout.c @@ -4,7 +4,7 @@ #include #include -#include "utils.h" +#include "base/memory.h" void layout_result_init(layout_result_t *result) { result->item_count = 0; diff --git a/src/core/runtime.c b/src/core/runtime.c index 1943eb9..2815d0f 100644 --- a/src/core/runtime.c +++ b/src/core/runtime.c @@ -2,10 +2,10 @@ #include +#include "base/memory.h" #include "core/backend.h" #include "core/state.h" #include "core/wm_desc.h" -#include "utils.h" static bool runtime_workspace_desc_has_valid_layouts( const layout_registry_t *layouts, const workspace_desc_t *workspace) { diff --git a/src/core/state.c b/src/core/state.c index 987cb2b..f91ddfb 100644 --- a/src/core/state.c +++ b/src/core/state.c @@ -3,9 +3,10 @@ #include #include +#include "base/log.h" +#include "base/memory.h" #include "core/types.h" #include "core/wm_desc.h" -#include "utils.h" void state_init(state_t *state, const output_info_t *outputs, size_t output_count, const workspace_desc_t *workspaces, diff --git a/src/core/state.h b/src/core/state.h index 568ee7f..0bbb66a 100644 --- a/src/core/state.h +++ b/src/core/state.h @@ -85,8 +85,8 @@ typedef struct state_t { * workspace;若某个 output 没有任何归属 workspace,state_init() 会失败。 */ void state_init(state_t *state, const output_info_t *outputs, - size_t output_count, const workspace_desc_t *workspaces, - size_t workspace_count); + size_t output_count, const workspace_desc_t *workspaces, + size_t workspace_count); void state_cleanup(state_t *state); /* @@ -95,20 +95,18 @@ void state_cleanup(state_t *state); * 这组接口对外只提供只读访问。 * workspace 的运行期可变状态必须通过专门的 state 级更新接口修改。 */ -const workspace_t *state_workspace_get(const state_t *state, - workspace_id_t id); +const workspace_t *state_workspace_get(const state_t *state, workspace_id_t id); const workspace_t *state_workspace_at(const state_t *state, size_t index); -bool state_workspace_cycle_layout(state_t *state, - workspace_id_t workspace_id); +bool state_workspace_cycle_layout(state_t *state, workspace_id_t workspace_id); bool state_workspace_set_layout_by_index(state_t *state, - workspace_id_t workspace_id, - size_t index); -bool state_workspace_set_layout_by_id(state_t *state, workspace_id_t workspace_id, - layout_id_t layout_id); + size_t index); +bool state_workspace_set_layout_by_id(state_t *state, + workspace_id_t workspace_id, + layout_id_t layout_id); void state_workspace_set_focused_window(state_t *state, - workspace_id_t workspace_id, - window_id_t window_id); + workspace_id_t workspace_id, + window_id_t window_id); size_t state_workspace_count(const state_t *state); bool state_workspace_valid(const state_t *state, workspace_id_t id); @@ -121,10 +119,9 @@ bool state_workspace_valid(const state_t *state, workspace_id_t id); const output_t *state_output_get(const state_t *state, output_id_t id); const output_t *state_output_at(const state_t *state, size_t index); void state_output_set_workarea(state_t *state, output_id_t output_id, - rect_t workarea); -void state_output_set_current_workspace(state_t *state, - output_id_t output_id, - workspace_id_t workspace_id); + rect_t workarea); +void state_output_set_current_workspace(state_t *state, output_id_t output_id, + workspace_id_t workspace_id); size_t state_output_count(const state_t *state); bool state_output_valid(const state_t *state, output_id_t id); @@ -142,8 +139,7 @@ bool state_output_valid(const state_t *state, output_id_t id); * info 提供 backend 已探测到的窗口基础信息。 * workspace 归属与其他策略相关字段由后续 state_window_* 接口设置。 */ -const window_t *state_window_add(state_t *state, - const window_info_t *info); +const window_t *state_window_add(state_t *state, const window_info_t *info); const window_t *state_window_get(const state_t *state, window_id_t id); const window_t *state_window_at(const state_t *state, size_t index); /* 删除窗口,并同步从 stack_order[] 中移除。 */ @@ -152,31 +148,31 @@ size_t state_window_count(const state_t *state); /* state 持有的单个 window 状态更新接口 */ void state_window_set_workspace(state_t *state, window_id_t window_id, - workspace_id_t workspace_id); + workspace_id_t workspace_id); void state_window_set_geometry_mode(state_t *state, window_id_t window_id, - window_geometry_mode_t geometry_mode); + window_geometry_mode_t geometry_mode); void state_window_set_floating(state_t *state, window_id_t window_id, - bool floating); + bool floating); void state_window_set_sticky(state_t *state, window_id_t window_id, - bool sticky); + bool sticky); void state_window_set_urgent(state_t *state, window_id_t window_id, - bool urgent); + bool urgent); void state_window_set_fixed_size(state_t *state, 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, - bool skip_taskbar); + bool skip_taskbar); void state_window_set_float_rect(state_t *state, window_id_t window_id, - rect_t float_rect); + rect_t float_rect); void state_window_set_frame_rect(state_t *state, window_id_t window_id, - rect_t frame_rect); + rect_t frame_rect); bool state_window_set_title(state_t *state, window_id_t window_id, - const char *title); + const char *title); bool state_window_set_app_id(state_t *state, window_id_t window_id, - const char *app_id); + const char *app_id); bool state_window_set_class(state_t *state, window_id_t window_id, - const char *class_name); + const char *class_name); bool state_window_set_instance(state_t *state, window_id_t window_id, - const char *instance_name); + const char *instance_name); /* * state 持有的堆叠顺序接口 diff --git a/src/core/wm_desc.h b/src/core/wm_desc.h index 5ef22bf..e9eb2d6 100644 --- a/src/core/wm_desc.h +++ b/src/core/wm_desc.h @@ -51,7 +51,7 @@ static inline bool workspace_desc_layouts_valid( } 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->output_index >= output_count) return false; diff --git a/src/utils.h b/src/utils.h index 8f56875..1b01031 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,131 +1,8 @@ #pragma once -#include -#include -#include -#include -#include +/* Compatibility umbrella header. Prefer including headers from src/base in new + * code. */ -#define ssizeof(foo) (ssize_t)sizeof(foo) -#define countof(foo) (ssizeof(foo) / ssizeof(foo[0])) - -#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 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(); - } -} - -/** - * @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; -} +#include "base/log.h" +#include "base/macros.h" +#include "base/memory.h" diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt index 4a93e6f..d7d176c 100644 --- a/tests/core/CMakeLists.txt +++ b/tests/core/CMakeLists.txt @@ -2,7 +2,7 @@ set(TEST_APP_NAME "zdwm-tests") add_executable(${TEST_APP_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.c - ${SOURCE_DIR}/utils.c + ${SOURCE_DIR}/base/log.c ${SOURCE_DIR}/backend/output_utils.c ${SOURCE_DIR}/backend/x11/backend.c ${SOURCE_DIR}/core/layout.c