Compare commits
2 Commits
72151c1458
...
0827208a95
| Author | SHA1 | Date | |
|---|---|---|---|
|
0827208a95
|
|||
|
e78c847125
|
@@ -15,7 +15,7 @@ project(${APP_NAME}
|
||||
LANGUAGES C
|
||||
)
|
||||
|
||||
add_executable(${APP_NAME} main.c utils.c config.c)
|
||||
add_executable(${APP_NAME} main.c utils.c)
|
||||
|
||||
# use C17
|
||||
set_property(TARGET ${APP_NAME} PROPERTY C_STANDARD 17)
|
||||
@@ -51,6 +51,7 @@ target_include_directories(${APP_NAME} SYSTEM
|
||||
)
|
||||
target_include_directories(${APP_NAME}
|
||||
PRIVATE "${SOURCE_DIR}/include"
|
||||
PRIVATE "${SOURCE_DIR}"
|
||||
PRIVATE ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
|
||||
23
src/config.c
23
src/config.c
@@ -1,23 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const char *wallpager_list[] = {NULL};
|
||||
const uint32_t wallpaper_interval = 0;
|
||||
|
||||
const char *const *const *const monitor_tags[] = {
|
||||
(const char *const *const[]){
|
||||
(const char *const[]){"1", "2", "3", "4", "5", "6", NULL},
|
||||
NULL,
|
||||
},
|
||||
(const char *const *const[]){
|
||||
(const char *const[]){"1", "2", "3", NULL},
|
||||
(const char *const[]){"1", "2", "3", "4", "5", NULL},
|
||||
NULL,
|
||||
},
|
||||
NULL,
|
||||
};
|
||||
const char *const default_monitor_tags[] = {
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", NULL,
|
||||
};
|
||||
74
src/config.h
Normal file
74
src/config.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/* 壁纸列表,支持通配符和 shell 环境变量拼接,最后以 NULL 结尾 */
|
||||
const char *wallpapers[] = {};
|
||||
/* 壁纸切换间隔(单位:秒),0 表示不切换 */
|
||||
const uint32_t wallpaper_interval = 0;
|
||||
|
||||
/**
|
||||
* @brief 屏幕 tags 设置
|
||||
* @description 每个屏幕的 tags 配置为字符串数组,以 NULL 结束,如
|
||||
* {"1", "2", "3", "4", "5", "6", NULL}
|
||||
*
|
||||
* 每一项配置里面的数组个数表示对应的屏幕个数,并最后以 NULL 结束,
|
||||
*
|
||||
* 如一个屏幕应该配置为 {{"1", "2", "3", "4", NULL}, NULL},
|
||||
* 两个屏幕应该配置为 {{"1", "2", "3", NULL}, {"1", "2", NULL}, NULL},以此类推
|
||||
*/
|
||||
const char *const *const *const monitor_tags[] = {
|
||||
(const char *const *const[]){
|
||||
(const char *const[]){"1", "2", "3", "4", "5", "6", NULL},
|
||||
NULL,
|
||||
},
|
||||
(const char *const *const[]){
|
||||
(const char *const[]){"1", "2", "3", NULL},
|
||||
(const char *const[]){"1", "2", "3", "4", "5", NULL},
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
/**
|
||||
* @brief 默认屏幕 tags 设置
|
||||
* @description 若屏幕个数与 monitor_tags 中设置的所有配置项都不符,
|
||||
* 则所有屏幕的 tags 都使用这个默认配置
|
||||
*
|
||||
* 格式为字符串数组,以 NULL 标志结束,如 {"1", "2", "3", NULL}
|
||||
*/
|
||||
const char *const default_monitor_tags[] = {
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", NULL,
|
||||
};
|
||||
|
||||
/* 新建窗口规则,以 NULL 结束 */
|
||||
const rule_t rules[] = {
|
||||
/* client 固定规则 */
|
||||
{.class = "firefox", .maximize = true},
|
||||
{.class = "Google-chrome", .maximize = true},
|
||||
{.class = "mpv", .fullscreen = true},
|
||||
{.class = "Emacs", .switch_to_tag = true, .maximize = true},
|
||||
|
||||
/* client 默认 tag 规则 */
|
||||
{.class = "firefox", .monitor_index = 0, .tags = 1 << 1},
|
||||
{.class = "Google-chrome", .monitor_index = 0, .tags = 1 << 1},
|
||||
{.class = "mpv", .monitor_amount = 1, .monitor_index = 0, .tags = 1 << 3},
|
||||
{.class = "mpv", .monitor_amount = 2, .monitor_index = 1, .tags = 1 << 2},
|
||||
{.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";
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* 壁纸列表,支持通配符和 shell 环境变量拼接,最后以 NULL 结尾 */
|
||||
extern const char *wallpager_list[];
|
||||
/* 壁纸切换间隔(单位:秒),0 表示不切换 */
|
||||
extern const uint32_t wallpaper_interval;
|
||||
|
||||
/**
|
||||
* @brief 屏幕 tags 设置
|
||||
* @description 每个屏幕的 tags 配置为字符串数组,以 NULL 结束,如
|
||||
* {"1", "2", "3", "4", "5", "6", NULL}
|
||||
*
|
||||
* 每一项配置里面的数组个数表示对应的屏幕个数,并最后以 NULL 结束,
|
||||
*
|
||||
* 如一个屏幕应该配置为 {{"1", "2", "3", "4", NULL}, NULL},
|
||||
* 两个屏幕应该配置为 {{"1", "2", "3", NULL}, {"1", "2", NULL}, NULL},以此类推
|
||||
*/
|
||||
extern const char *const *const *const monitor_tags[];
|
||||
/**
|
||||
* @brief 默认屏幕 tags 设置
|
||||
* @description 若屏幕个数与 monitor_tags 中设置的所有配置项都不符,
|
||||
* 则所有屏幕的 tags 都使用这个默认配置
|
||||
*
|
||||
* 格式为字符串数组,以 NULL 标志结束,如 {"1", "2", "3", NULL}
|
||||
*/
|
||||
extern const char *const default_monitor_tags[];
|
||||
@@ -56,3 +56,41 @@ typedef struct wallpaper_config_t {
|
||||
uint32_t count;
|
||||
char **path_list;
|
||||
} wallpaper_config_t;
|
||||
|
||||
typedef struct rule_t {
|
||||
const char *class;
|
||||
const char *instance;
|
||||
const char *title;
|
||||
|
||||
/* 规则适用的屏幕总数,若设置为 0 ,则此条规则适用于任意屏幕数 */
|
||||
const uint32_t monitor_amount;
|
||||
|
||||
uint32_t tags;
|
||||
uint32_t monitor_index;
|
||||
|
||||
bool switch_to_tag;
|
||||
bool fullscreen;
|
||||
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;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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);
|
||||
|
||||
72
src/main.c
72
src/main.c
@@ -19,8 +19,10 @@ static char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index);
|
||||
static void init_wallpaper(void);
|
||||
static gboolean update_wallpaper(gpointer user_data);
|
||||
static void set_wallpaper_by_index(uint32_t index);
|
||||
static wallpaper_config_t *parse_wallpaper_config(const char **wallpapers);
|
||||
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");
|
||||
@@ -98,14 +122,11 @@ void init_monitors(void) {
|
||||
}
|
||||
|
||||
char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index) {
|
||||
int config_count = 0;
|
||||
while (monitor_tags[config_count]) config_count++;
|
||||
|
||||
GStrvBuilder *builder = g_strv_builder_new();
|
||||
const char *const *tags = NULL;
|
||||
|
||||
/* 倒序遍历,达到后面的配置覆盖前面相同配置的效果 */
|
||||
for (int i = config_count - 1; i >= 0; i--) {
|
||||
for (int i = LENGTH(monitor_tags) - 1; i >= 0; i--) {
|
||||
const char *const *const *config = monitor_tags[i];
|
||||
|
||||
uint32_t monitor_count_in_tags_config = 0;
|
||||
@@ -128,7 +149,7 @@ char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index) {
|
||||
}
|
||||
|
||||
void init_wallpaper(void) {
|
||||
wallpaper_config = parse_wallpaper_config(wallpager_list);
|
||||
wallpaper_config = parse_wallpaper_config();
|
||||
if (!wallpaper_config) return;
|
||||
|
||||
update_wallpaper(wallpaper_config);
|
||||
@@ -171,13 +192,13 @@ void set_wallpaper_by_index(uint32_t index) {
|
||||
free(screen_size);
|
||||
}
|
||||
|
||||
wallpaper_config_t *parse_wallpaper_config(const char **wallpapers) {
|
||||
if (!wallpapers) return NULL;
|
||||
wallpaper_config_t *parse_wallpaper_config(void) {
|
||||
if (!LENGTH(wallpapers)) return NULL;
|
||||
|
||||
wallpaper_config_t *wc = ecalloc(1, sizeof(wallpaper_config_t));
|
||||
|
||||
GStrvBuilder *builder = g_strv_builder_new();
|
||||
for (int i = 0; wallpapers && wallpapers[i]; i++) {
|
||||
for (int i = 0; i < LENGTH(wallpapers); i++) {
|
||||
wordexp_t p;
|
||||
if (wordexp(wallpapers[i], &p, 0)) continue;
|
||||
|
||||
@@ -208,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);
|
||||
@@ -233,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) {
|
||||
@@ -255,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);
|
||||
|
||||
|
||||
50
src/utils.c
50
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user