diff --git a/src/config.h b/src/config.h index aba3167..5ee89b4 100644 --- a/src/config.h +++ b/src/config.h @@ -58,3 +58,17 @@ const rule_t rules[] = { {.class = "Emacs", .monitor_amount = 1, .monitor_index = 0, .tags = 1 << 2}, {.class = "Emacs", .monitor_amount = 2, .monitor_index = 0, .tags = 1 << 1}, }; + +const char *const bar_bg = "#222222"; +const char *const tag_color = "#bbbbbb"; +const char *const layout_color = "#bbbbbb"; +const char *const client_name_color = "#bbbbbb"; +const char *const status_color = "#bbbbbb"; +const char *const border_color = "#444444"; + +const char *const active_bar_bg = "#eeeeee"; +const char *const active_tag_color = "#005577"; +const char *const active_layout_color = "#005577"; +const char *const active_client_name_color = "#005577"; +const char *const active_status_color = "#005577"; +const char *const active_border_color = "#005577"; diff --git a/src/include/types.h b/src/include/types.h index 75007da..398136a 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -73,3 +73,24 @@ typedef struct rule_t { bool maximize; bool floating; } rule_t; + +typedef struct color_t { + uint32_t rgba; + uint32_t argb; + double red; + double green; + double blue; + double alpha; +} color_t; +typedef struct color_set_t { + color_t bar_bg; + color_t tag_color; + color_t layout_color; + color_t client_name_color; + color_t status_color; + color_t border_color; +} color_set_t; +typedef struct color_scheme_t { + color_set_t normal; + color_set_t active; +} color_scheme_t; diff --git a/src/include/utils.h b/src/include/utils.h index 22917d9..84685e1 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -2,6 +2,7 @@ #include #include +#include #define LENGTH(X) (sizeof(X) / sizeof(X)[0]) @@ -12,3 +13,28 @@ void die(const char *format, ...); void *ecalloc(size_t number_of_member, size_t member_size); bool file_exist(const char *path); + +/** + * @brief 将 16 进制的颜色配置转换成 uint32 格式的 rgba数据 + * + * @param hex 16 进制的颜色表示,支持的格式有 + * RGB/RGBA/RRGGBB/RRGGBBAA/#RGB/#RGBA/#RRGGBB/#RRGGBBAA + * @param rgba 返回数据的指针,解析结果会放到这个指针指向的内存中 + * @return 如果 hex 是一个能正常解析的颜色,返回 true ,否则返回 false + */ +bool hex_color_to_rgba(const char *hex, uint32_t *rgba); +/** + * @brief 将 rgba 通道顺序的颜色转换成 argb 顺序 + * @description xcb 库用到的颜色需要是 argb 通道顺序 + */ +uint32_t rgba_to_argb(uint32_t rgba); +/** + * @brief 提取颜色中的各个颜色通道数值 + * @param rgba uint32 表示的颜色 + * @param red red channel, range 0~1 + * @param green green channel, range 0~1 + * @param blue blue channel, range 0~1 + * @param alpha alpha channel, range 0~1 + */ +void extract_color_channel(const uint32_t rgba, double *red, double *green, + double *blue, double *alpha); diff --git a/src/main.c b/src/main.c index b2b4f66..4109680 100644 --- a/src/main.c +++ b/src/main.c @@ -21,6 +21,8 @@ static gboolean update_wallpaper(gpointer user_data); static void set_wallpaper_by_index(uint32_t index); static wallpaper_config_t *parse_wallpaper_config(void); static void free_wallpaper_config(wallpaper_config_t *wallpaper_config); +static void init_color_scheme(void); +static void parse_color(const char *hex, color_t *color); static void init_xcb_event_loop(void); static gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition, gpointer userdata); @@ -28,6 +30,7 @@ static void cleanup(void); static monitor_t *monitors = NULL; static wallpaper_config_t *wallpaper_config = NULL; +static color_scheme_t *color_scheme = NULL; static GMainLoop *loop = NULL; /* 调试函数,开发完成后删除 */ @@ -45,6 +48,27 @@ static void print_monitor_list_info(monitor_t *monitor_list) { } printf("======================= monitor info end =======================\n"); } +static void print_color(const char *prompt, const color_t *color) { + const char *p = strlen(prompt) ? " " : ""; + printf("%s%srgba: #%08x, argb: #%08x\n", prompt, p, color->rgba, color->argb); +} +static void print_color_set(color_set_t *set) { + print_color("== bar bg:", &set->bar_bg); + print_color("== tag color:", &set->tag_color); + print_color("== layout bg:", &set->layout_color); + print_color("== client name color:", &set->client_name_color); + print_color("== status color:", &set->status_color); + print_color("== border color:", &set->border_color); +} +static void print_color_scheme(color_scheme_t *scheme) { + printf("================== normal colors ==================\n"); + print_color_set(&scheme->normal); + printf("================ normal colors end ================\n"); + + printf("================== active colors ==================\n"); + print_color_set(&scheme->active); + printf("================ active colors end ================\n"); +} static void print_wallpaper_config(wallpaper_config_t *config) { if (!config) { printf("no wallpaper\n"); @@ -205,6 +229,34 @@ void free_wallpaper_config(wallpaper_config_t *wallpaper_config) { free(wallpaper_config); } +void init_color_scheme(void) { + color_scheme = ecalloc(1, sizeof(color_scheme_t)); + + parse_color(bar_bg, &color_scheme->normal.bar_bg); + parse_color(tag_color, &color_scheme->normal.tag_color); + parse_color(layout_color, &color_scheme->normal.layout_color); + parse_color(client_name_color, &color_scheme->normal.client_name_color); + parse_color(status_color, &color_scheme->normal.status_color); + parse_color(border_color, &color_scheme->normal.border_color); + + parse_color(active_bar_bg, &color_scheme->active.bar_bg); + parse_color(active_tag_color, &color_scheme->active.tag_color); + parse_color(active_layout_color, &color_scheme->active.layout_color); + parse_color(active_client_name_color, + &color_scheme->active.client_name_color); + parse_color(active_status_color, &color_scheme->active.status_color); + parse_color(active_border_color, &color_scheme->active.border_color); +} + +void parse_color(const char *hex, color_t *color) { + bool success = hex_color_to_rgba(hex, &color->rgba); + if (!success) die("invalid hex color: %s", hex); + + color->argb = rgba_to_argb(color->rgba); + extract_color_channel(color->rgba, &color->red, &color->green, &color->blue, + &color->alpha); +} + void init_xcb_event_loop(void) { GIOChannel *channel = g_io_channel_unix_new(get_xcb_connection_fd()); g_io_channel_set_encoding(channel, NULL, NULL); @@ -230,6 +282,9 @@ void cleanup(void) { free_wallpaper_config(wallpaper_config); wallpaper_config = NULL; + free(color_scheme); + color_scheme = NULL; + monitor_t *m = monitors; client_t *c = m->clients; while (m) { @@ -252,11 +307,13 @@ int main(int argc, char *argv[]) { } init_monitors(); + init_color_scheme(); init_wallpaper(); window_list_t *window_list = scan_window_list(); print_monitor_list_info(monitors); + print_color_scheme(color_scheme); print_wallpaper_config(wallpaper_config); print_window_list(window_list); diff --git a/src/utils.c b/src/utils.c index d911534..812a7c0 100644 --- a/src/utils.c +++ b/src/utils.c @@ -37,3 +37,53 @@ bool file_exist(const char *path) { if (!path || !*path) return false; return access(path, R_OK) == 0; } + +bool hex_color_to_rgba(const char *hex, uint32_t *rgba) { + if (hex[0] == '#') hex++; + + size_t len = strlen(hex); + char extended[9] = {0}; + uint32_t color = 0x00000000; + + if (len == 3 || len == 4) { + extended[0] = extended[1] = hex[0]; + extended[2] = extended[3] = hex[1]; + extended[4] = extended[5] = hex[2]; + if (len == 3) { + extended[6] = extended[7] = 'F'; + } else { + extended[6] = extended[7] = hex[3]; + } + } else if (len == 6) { + strncpy(extended, hex, len); + extended[6] = extended[7] = 'F'; + } else if (len == 8) { + strncpy(extended, hex, len); + } else { + return false; + } + + color = strtoul(extended, NULL, 16) & 0xffffffff; + *rgba = color; + return true; +} + +#define EXTRACE_COLOR_BIT(C, R) (((C) >> (R)) & 0xff) +uint32_t rgba_to_argb(uint32_t rgba) { + uint32_t r = EXTRACE_COLOR_BIT(rgba, 24); + uint32_t g = EXTRACE_COLOR_BIT(rgba, 16); + uint32_t b = EXTRACE_COLOR_BIT(rgba, 8); + uint32_t a = EXTRACE_COLOR_BIT(rgba, 0); + + uint32_t argb = (a << 24) | (r << 16) | (g << 8) | b; + return argb; +} + +#define COLOR_SPLIT(C, R) (EXTRACE_COLOR_BIT((C), (R)) / (double)0xff) +void extract_color_channel(const uint32_t rgba, double *red, double *green, + double *blue, double *alpha) { + *red = COLOR_SPLIT(rgba, 24); + *green = COLOR_SPLIT(rgba, 16); + *blue = COLOR_SPLIT(rgba, 8); + *alpha = COLOR_SPLIT(rgba, 0); +}