feat: 状态栏配置接入配置系统
This commit is contained in:
@@ -45,6 +45,9 @@ add_executable(${APP_NAME}
|
||||
${SOURCE_DIR}/audio.c
|
||||
${SOURCE_DIR}/rect.c
|
||||
${SOURCE_DIR}/wallpaper.c
|
||||
${SOURCE_DIR}/config.c
|
||||
${SOURCE_DIR}/renderer.c
|
||||
${SOURCE_DIR}/image.c
|
||||
)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
81
src/config.c
Normal file
81
src/config.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "default_config.h"
|
||||
#include "utils.h"
|
||||
|
||||
void config_status_set_gap(config_status_t *status_config, uint32_t gap,
|
||||
uint32_t item_gap) {
|
||||
if (!status_config) fatal("no valid status config");
|
||||
status_config->status_gap = gap;
|
||||
status_config->status_item_gap = item_gap;
|
||||
}
|
||||
|
||||
void config_status_add_item(config_status_t **status_config,
|
||||
config_status_item_t status_item) {
|
||||
const auto item_count = (*status_config)->status_count + 1;
|
||||
const auto new_size =
|
||||
sizeof(config_status_t) + item_count * sizeof(config_status_item_t);
|
||||
xrealloc((void **)status_config, (ssize_t)new_size);
|
||||
(*status_config)->list[item_count - 1] = status_item;
|
||||
(*status_config)->status_count = item_count;
|
||||
}
|
||||
|
||||
void config_status_filter_item(config_status_t **status_config,
|
||||
status_item_filter filter) {
|
||||
if (!status_config || !*status_config) fatal("no valid status config");
|
||||
if (!filter) return;
|
||||
|
||||
config_status_t *config = *status_config;
|
||||
size_t write_idx = 0;
|
||||
size_t item_count = config->status_count;
|
||||
|
||||
for (size_t read_idx = 0; read_idx < item_count; read_idx++) {
|
||||
config_status_item_t *item = &config->list[read_idx];
|
||||
if (!filter(item)) continue;
|
||||
if (write_idx != read_idx) {
|
||||
config->list[write_idx] = *item;
|
||||
}
|
||||
write_idx++;
|
||||
}
|
||||
|
||||
if (write_idx == item_count) return;
|
||||
|
||||
config->status_count = write_idx;
|
||||
size_t new_size =
|
||||
sizeof(config_status_t) + write_idx * sizeof(config_status_item_t);
|
||||
xrealloc((void **)status_config, (ssize_t)new_size);
|
||||
}
|
||||
|
||||
static config_status_t *config_create_default_status(void) {
|
||||
size_t item_count = countof(status_list);
|
||||
size_t size = sizeof(config_status_t) + item_count * sizeof(status_list[0]);
|
||||
config_status_t *status = xmalloc((ssize_t)size);
|
||||
|
||||
status->status_gap = status_config.status_gap;
|
||||
status->status_item_gap = status_config.status_item_gap;
|
||||
status->status_count = item_count;
|
||||
memcpy(status->list, status_list, item_count * sizeof(status_list[0]));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static config_t runtime_config = {};
|
||||
|
||||
const config_t *init_config(void) {
|
||||
if (!runtime_config.status) {
|
||||
runtime_config.status = config_create_default_status();
|
||||
}
|
||||
if (!runtime_config.status_renderer) {
|
||||
runtime_config.status_renderer = renderer_render_status;
|
||||
}
|
||||
return &runtime_config;
|
||||
}
|
||||
|
||||
void config_set_custom_status_renderer(config_t *config,
|
||||
status_renderer_t status_renderer) {
|
||||
if (!config) fatal("no valid config");
|
||||
config->status_renderer =
|
||||
status_renderer ? status_renderer : renderer_render_status;
|
||||
}
|
||||
57
src/config.h
Normal file
57
src/config.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "renderer.h"
|
||||
#include "status.h"
|
||||
|
||||
typedef struct config_status_item_t {
|
||||
status_type_t type;
|
||||
icon_type_t icon_type;
|
||||
const char *icon;
|
||||
const char *color;
|
||||
} config_status_item_t;
|
||||
|
||||
typedef struct config_status_t {
|
||||
uint32_t status_gap;
|
||||
uint32_t status_item_gap;
|
||||
size_t status_count;
|
||||
config_status_item_t list[];
|
||||
} config_status_t;
|
||||
|
||||
void config_status_set_gap(config_status_t *status_config, uint32_t gap,
|
||||
uint32_t item_gap);
|
||||
|
||||
void config_status_add_item(config_status_t **status_config,
|
||||
config_status_item_t status_item);
|
||||
|
||||
typedef bool (*status_item_filter)(config_status_item_t *item);
|
||||
/**
|
||||
* @brief 按过滤条件原地筛选 status 项并保持原有顺序
|
||||
*
|
||||
* 当 filter(item) 返回 true 时保留该项,返回 false 时删除该项。
|
||||
* 筛选后会压缩 list、更新 status_count,并收缩配置对象内存。
|
||||
*
|
||||
* @param status_config 配置指针地址(函数内部会重分配内存)
|
||||
* @param filter 过滤函数
|
||||
*/
|
||||
void config_status_filter_item(config_status_t **status_config,
|
||||
status_item_filter filter);
|
||||
|
||||
typedef void (*status_renderer_t)(config_status_t *config, size_t config_count,
|
||||
status_t *status, renderer_status_t *output);
|
||||
|
||||
typedef struct config_t {
|
||||
config_status_t *status;
|
||||
status_renderer_t status_renderer;
|
||||
} config_t;
|
||||
|
||||
/**
|
||||
* @brief 初始化配置对象
|
||||
* @return 返回静态变量指针,不需要释放
|
||||
*/
|
||||
const config_t *init_config(void);
|
||||
|
||||
void config_set_custom_status_renderer(config_t *config,
|
||||
status_renderer_t status_renderer);
|
||||
@@ -5,7 +5,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "action.h"
|
||||
#include "config.h"
|
||||
#include "layout.h"
|
||||
#include "renderer.h"
|
||||
#include "status.h"
|
||||
#include "types.h"
|
||||
|
||||
static const char *const font_family = "monospace";
|
||||
@@ -27,6 +30,55 @@ static const char *const active_tag_color = "#eeeeee";
|
||||
static const char *const border_color = "#444444";
|
||||
static const char *const active_border_color = "#005577";
|
||||
|
||||
static const config_status_item_t status_list[] = {
|
||||
{
|
||||
.type = status_net_down,
|
||||
.icon_type = icon_type_image,
|
||||
.icon = "/home/zedhugh/develop/zswm/src/resources/icons/"
|
||||
"corner-left-down-line.png",
|
||||
.color = "#87af5f",
|
||||
},
|
||||
{
|
||||
.type = status_net_up,
|
||||
.icon_type = icon_type_image,
|
||||
.icon =
|
||||
"/home/zedhugh/develop/zswm/src/resources/icons/corner-right-up-line.png",
|
||||
.color = "#e54c62",
|
||||
},
|
||||
{
|
||||
.type = status_audio,
|
||||
.icon_type = icon_type_image,
|
||||
.icon = "/home/zedhugh/develop/zswm/src/resources/icons/volume-up-fill.png",
|
||||
.color = "#7493d2",
|
||||
},
|
||||
{
|
||||
.type = status_memory,
|
||||
.icon_type = icon_type_image,
|
||||
.icon = "/home/zedhugh/develop/zswm/src/resources/icons/ram-line.png",
|
||||
.color = "#e0da37",
|
||||
},
|
||||
{
|
||||
.type = status_cpu,
|
||||
.icon_type = icon_type_image,
|
||||
.icon = "/home/zedhugh/develop/zswm/src/resources/icons/cpu-line.png",
|
||||
.color = "#e33a6e",
|
||||
},
|
||||
{
|
||||
.type = status_time,
|
||||
.icon_type = icon_type_image,
|
||||
.icon = "/home/zedhugh/develop/zswm/src/resources/icons/time-line.png",
|
||||
.color = "#7788af",
|
||||
},
|
||||
};
|
||||
static const config_status_t status_config = {
|
||||
.status_gap = 10,
|
||||
.status_item_gap = 5,
|
||||
};
|
||||
|
||||
static const config_t config = {
|
||||
.status = (config_status_t *)&status_config,
|
||||
};
|
||||
|
||||
static const button_t button_list[] = {
|
||||
{click_tag, modifier_none, button_left, select_tag_of_current_monitor, {0}},
|
||||
{
|
||||
@@ -140,6 +192,6 @@ static const rule_t rules[] = {
|
||||
{.class = "Emacs", .tag_index = 10, .switch_to_tag = true, .maximize = true},
|
||||
};
|
||||
|
||||
/* static const char *const wallpapers[] = {"~/bg/\*", "~/Downloads/bg/\*"}; */
|
||||
static const char *const wallpapers[] = {};
|
||||
static const uint32_t wallpaper_interval = 10;
|
||||
static const char *const wallpapers[] = {"~/bg/*", "~/Downloads/bg/*"};
|
||||
/* static const char *const wallpapers[] = {}; */
|
||||
static const uint32_t wallpaper_interval = 0;
|
||||
|
||||
170
src/image.c
Normal file
170
src/image.c
Normal file
@@ -0,0 +1,170 @@
|
||||
#include "image.h"
|
||||
|
||||
#include <Imlib2.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
typedef struct image_cache_entry_t {
|
||||
char *path;
|
||||
cairo_surface_t *surface;
|
||||
int width;
|
||||
int height;
|
||||
} image_cache_entry_t;
|
||||
|
||||
static image_cache_entry_t *image_cache = nullptr;
|
||||
static size_t image_cache_count = 0;
|
||||
static cairo_user_data_key_t image_surface_data_key;
|
||||
|
||||
static inline uint32_t premultiply_argb(uint32_t pixel) {
|
||||
uint8_t a = (pixel >> 24) & 0xff;
|
||||
uint8_t r = (pixel >> 16) & 0xff;
|
||||
uint8_t g = (pixel >> 8) & 0xff;
|
||||
uint8_t b = pixel & 0xff;
|
||||
r = (uint8_t)((r * a + 127) / 255);
|
||||
g = (uint8_t)((g * a + 127) / 255);
|
||||
b = (uint8_t)((b * a + 127) / 255);
|
||||
return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) |
|
||||
(uint32_t)b;
|
||||
}
|
||||
|
||||
static bool image_load_surface(const char *path, cairo_surface_t **surface,
|
||||
int *width, int *height) {
|
||||
if (!path || !*path || !surface || !width || !height) return false;
|
||||
|
||||
Imlib_Image image = imlib_load_image(path);
|
||||
if (!image) return false;
|
||||
|
||||
imlib_context_set_image(image);
|
||||
int img_width = imlib_image_get_width();
|
||||
int img_height = imlib_image_get_height();
|
||||
if (img_width <= 0 || img_height <= 0) {
|
||||
imlib_free_image();
|
||||
return false;
|
||||
}
|
||||
|
||||
DATA32 *src = imlib_image_get_data_for_reading_only();
|
||||
if (!src) {
|
||||
imlib_free_image();
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t pixel_count = (size_t)img_width * (size_t)img_height;
|
||||
uint32_t *dst = xmalloc((ssize_t)(pixel_count * sizeof(uint32_t)));
|
||||
for (size_t i = 0; i < pixel_count; i++) {
|
||||
dst[i] = premultiply_argb(src[i]);
|
||||
}
|
||||
|
||||
cairo_surface_t *img_surface = cairo_image_surface_create_for_data(
|
||||
(unsigned char *)dst, CAIRO_FORMAT_ARGB32, img_width, img_height,
|
||||
img_width * (int)sizeof(uint32_t));
|
||||
cairo_status_t status = cairo_surface_status(img_surface);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
cairo_surface_destroy(img_surface);
|
||||
p_delete(&dst);
|
||||
imlib_free_image();
|
||||
return false;
|
||||
}
|
||||
|
||||
cairo_surface_set_user_data(img_surface, &image_surface_data_key, dst, free);
|
||||
*surface = img_surface;
|
||||
*width = img_width;
|
||||
*height = img_height;
|
||||
|
||||
imlib_free_image();
|
||||
return true;
|
||||
}
|
||||
|
||||
static image_cache_entry_t *image_cache_find(const char *path) {
|
||||
if (!path || !*path) return nullptr;
|
||||
for (size_t i = 0; i < image_cache_count; i++) {
|
||||
image_cache_entry_t *entry = &image_cache[i];
|
||||
if (!entry->path) continue;
|
||||
if (strcmp(entry->path, path) == 0) return entry;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static image_cache_entry_t *image_cache_add(const char *path) {
|
||||
if (!path || !*path) return nullptr;
|
||||
|
||||
size_t new_count = image_cache_count + 1;
|
||||
xrealloc((void **)&image_cache,
|
||||
(ssize_t)(new_count * sizeof(image_cache_entry_t)));
|
||||
image_cache_entry_t *entry = &image_cache[image_cache_count];
|
||||
entry->path = strdup(path);
|
||||
entry->surface = nullptr;
|
||||
entry->width = 0;
|
||||
entry->height = 0;
|
||||
image_cache_count = new_count;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static image_cache_entry_t *image_cache_get(const char *path) {
|
||||
image_cache_entry_t *entry = image_cache_find(path);
|
||||
if (entry && entry->surface) return entry;
|
||||
if (!entry) entry = image_cache_add(path);
|
||||
if (!entry) return nullptr;
|
||||
|
||||
if (entry->surface) {
|
||||
cairo_surface_destroy(entry->surface);
|
||||
entry->surface = nullptr;
|
||||
}
|
||||
|
||||
if (!image_load_surface(path, &entry->surface, &entry->width, &entry->height)) {
|
||||
return nullptr;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool image_get_scaled_size(const char *path, int32_t target_height, int *width,
|
||||
int *height) {
|
||||
if (!width || !height || target_height <= 0) return false;
|
||||
image_cache_entry_t *entry = image_cache_get(path);
|
||||
if (!entry || !entry->surface || entry->width <= 0 || entry->height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*height = target_height;
|
||||
*width = (entry->width * target_height + entry->height / 2) / entry->height;
|
||||
if (*width <= 0) *width = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool image_draw(cairo_t *cr, const char *path, int32_t x, int32_t y,
|
||||
int32_t width, int32_t height) {
|
||||
if (!cr || width <= 0 || height <= 0) return false;
|
||||
image_cache_entry_t *entry = image_cache_get(path);
|
||||
if (!entry || !entry->surface || entry->width <= 0 || entry->height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cairo_save(cr);
|
||||
cairo_translate(cr, (double)x, (double)y);
|
||||
cairo_scale(cr, (double)width / (double)entry->width,
|
||||
(double)height / (double)entry->height);
|
||||
cairo_set_source_surface(cr, entry->surface, 0, 0);
|
||||
cairo_paint(cr);
|
||||
cairo_restore(cr);
|
||||
return true;
|
||||
}
|
||||
|
||||
void image_cache_clean(void) {
|
||||
if (!image_cache) return;
|
||||
|
||||
for (size_t i = 0; i < image_cache_count; i++) {
|
||||
image_cache_entry_t *entry = &image_cache[i];
|
||||
if (entry->surface) {
|
||||
cairo_surface_destroy(entry->surface);
|
||||
entry->surface = nullptr;
|
||||
}
|
||||
p_delete(&entry->path);
|
||||
entry->width = 0;
|
||||
entry->height = 0;
|
||||
}
|
||||
|
||||
p_delete(&image_cache);
|
||||
image_cache_count = 0;
|
||||
}
|
||||
36
src/image.h
Normal file
36
src/image.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <cairo.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief 获取图片按目标高度缩放后的尺寸
|
||||
*
|
||||
* @param path 图片路径
|
||||
* @param target_height 目标高度(像素)
|
||||
* @param width 返回缩放后的宽度
|
||||
* @param height 返回缩放后的高度
|
||||
* @return 加载并计算成功返回 true
|
||||
*/
|
||||
bool image_get_scaled_size(const char *path, int32_t target_height, int *width,
|
||||
int *height);
|
||||
|
||||
/**
|
||||
* @brief 在 cairo 上下文中绘制图片
|
||||
*
|
||||
* @param cr cairo 上下文
|
||||
* @param path 图片路径
|
||||
* @param x 绘制起始 x
|
||||
* @param y 绘制起始 y
|
||||
* @param width 绘制宽度
|
||||
* @param height 绘制高度
|
||||
* @return 绘制成功返回 true
|
||||
*/
|
||||
bool image_draw(cairo_t *cr, const char *path, int32_t x, int32_t y,
|
||||
int32_t width, int32_t height);
|
||||
|
||||
/**
|
||||
* @brief 释放图片缓存
|
||||
*/
|
||||
void image_cache_clean(void);
|
||||
116
src/monitor.c
116
src/monitor.c
@@ -12,6 +12,9 @@
|
||||
#include "base.h"
|
||||
#include "client.h"
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
#include "image.h"
|
||||
#include "renderer.h"
|
||||
#include "status.h"
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
@@ -237,49 +240,108 @@ static void monitor_draw_layout_symbol(monitor_t *monitor) {
|
||||
}
|
||||
|
||||
static void monitor_draw_status(monitor_t *monitor, status_t *status) {
|
||||
static renderer_status_t *rendered_status = nullptr;
|
||||
static size_t rendered_status_capacity = 0;
|
||||
|
||||
monitor->status_extent.end = monitor->geometry.width;
|
||||
monitor->status_extent.start = monitor->geometry.width;
|
||||
int16_t end = monitor->layout_symbol_extent.end;
|
||||
int32_t end = monitor->layout_symbol_extent.end;
|
||||
|
||||
if (status == nullptr) return;
|
||||
if (status == nullptr || !wm.config || !wm.config->status) return;
|
||||
|
||||
char cpu[16], mem[64], volume[300];
|
||||
snprintf(cpu, sizeof(cpu), "%.1lf", status->cpu_usage_percent);
|
||||
snprintf(mem, sizeof(mem), "%s(%.1f%%)", status->mem_usage.mem_used_text,
|
||||
status->mem_usage.mem_percent);
|
||||
if (status->pulse) {
|
||||
snprintf(volume, sizeof(volume), "%d%%%s%s%s",
|
||||
status->pulse->volume_percent, status->pulse->mute ? "M" : "",
|
||||
strlen(status->pulse->device_name) ? "|" : "",
|
||||
status->pulse->device_name);
|
||||
} else {
|
||||
snprintf(volume, sizeof(volume), "0%%");
|
||||
config_status_t *status_config = wm.config->status;
|
||||
size_t item_count = status_config->status_count;
|
||||
if (item_count == 0) return;
|
||||
|
||||
if (rendered_status_capacity < item_count) {
|
||||
size_t size =
|
||||
sizeof(renderer_status_t) + item_count * sizeof(renderer_status_item_t);
|
||||
xrealloc((void **)&rendered_status, (ssize_t)size);
|
||||
rendered_status_capacity = item_count;
|
||||
}
|
||||
|
||||
char *status_items[] = {
|
||||
status->net_speed.down, status->net_speed.up, volume, mem, cpu,
|
||||
status->time,
|
||||
};
|
||||
int16_t start = monitor->status_extent.start;
|
||||
for (int i = countof(status_items) - 1; i >= 0; i--) {
|
||||
const char *text = status_items[i];
|
||||
if (!text || !strlen(text)) continue;
|
||||
status_renderer_t renderer = wm.config->status_renderer;
|
||||
if (!renderer) renderer = renderer_render_status;
|
||||
|
||||
renderer(status_config, item_count, status, rendered_status);
|
||||
item_count = MIN(item_count, rendered_status->item_count);
|
||||
|
||||
int32_t start = monitor->status_extent.start;
|
||||
int32_t icon_target_height =
|
||||
(int32_t)wm.bar_height - (int32_t)wm.padding.bar_y * 2;
|
||||
if (icon_target_height <= 0) icon_target_height = wm.bar_height;
|
||||
|
||||
for (size_t ri = item_count; ri > 0; ri--) {
|
||||
size_t i = ri - 1;
|
||||
renderer_status_item_t *item = &rendered_status->item_list[i];
|
||||
bool has_text = item->text[0] != '\0';
|
||||
int text_width = 0;
|
||||
if (has_text) text_get_size(item->text, &text_width, nullptr);
|
||||
|
||||
bool has_text_icon = false;
|
||||
int icon_text_width = 0;
|
||||
if (item->icon_type == icon_type_text && item->icon_text &&
|
||||
item->icon_text[0]) {
|
||||
has_text_icon = true;
|
||||
text_get_size(item->icon_text, &icon_text_width, nullptr);
|
||||
}
|
||||
|
||||
bool has_image_icon = false;
|
||||
int icon_width = 0;
|
||||
int icon_height = 0;
|
||||
if (item->icon_type == icon_type_image && item->icon_path &&
|
||||
item->icon_path[0]) {
|
||||
has_image_icon = image_get_scaled_size(
|
||||
item->icon_path, icon_target_height, &icon_width, &icon_height);
|
||||
}
|
||||
bool has_icon = has_text_icon || has_image_icon;
|
||||
|
||||
int width = 0;
|
||||
text_get_size(text, &width, nullptr);
|
||||
if (has_text_icon) width += icon_text_width;
|
||||
if (has_image_icon) width += icon_width;
|
||||
if (has_text) width += text_width;
|
||||
if (has_icon && has_text) width += (int)rendered_status->item_gap;
|
||||
if (!width) continue;
|
||||
|
||||
start -= width;
|
||||
if (start <= end) return;
|
||||
color_t *color = &wm.color_set.tag_color;
|
||||
area_t rect = {.x = start, .y = 0, .width = width, .height = wm.bar_height};
|
||||
draw_text(monitor->bar_cr, text, color, rect, true);
|
||||
monitor->status_extent.start = start;
|
||||
|
||||
start -= wm.padding.tag_x;
|
||||
color_t *color = item->color ? item->color : &wm.color_set.tag_color;
|
||||
int32_t draw_x = start;
|
||||
if (has_text_icon && icon_text_width > 0) {
|
||||
area_t icon_rect = {
|
||||
.x = (int16_t)draw_x,
|
||||
.y = 0,
|
||||
.width = (uint16_t)icon_text_width,
|
||||
.height = wm.bar_height,
|
||||
};
|
||||
draw_text(monitor->bar_cr, item->icon_text, color, icon_rect, true);
|
||||
draw_x += icon_text_width;
|
||||
} else if (has_image_icon) {
|
||||
int32_t icon_y = ((int32_t)wm.bar_height - icon_height) / 2;
|
||||
image_draw(monitor->bar_cr, item->icon_path, draw_x, icon_y, icon_width,
|
||||
icon_height);
|
||||
draw_x += icon_width;
|
||||
}
|
||||
if (has_icon && has_text) draw_x += (int32_t)rendered_status->item_gap;
|
||||
|
||||
if (has_text && text_width > 0) {
|
||||
area_t rect = {
|
||||
.x = (int16_t)draw_x,
|
||||
.y = 0,
|
||||
.width = (uint16_t)text_width,
|
||||
.height = wm.bar_height,
|
||||
};
|
||||
draw_text(monitor->bar_cr, item->text, color, rect, true);
|
||||
}
|
||||
monitor->status_extent.start = (int16_t)start;
|
||||
|
||||
if (ri > 1) {
|
||||
start -= (int32_t)rendered_status->gap;
|
||||
if (start < end) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void monitor_draw_tasks(monitor_t *monitor) {
|
||||
task_in_tag_t *task_list = monitor->selected_tag->task_list;
|
||||
|
||||
90
src/renderer.c
Normal file
90
src/renderer.c
Normal file
@@ -0,0 +1,90 @@
|
||||
#include "renderer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
#include "status.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void status_text_from_data(status_type_t type, const status_t *status,
|
||||
char *text, size_t text_size) {
|
||||
if (!text || text_size == 0) return;
|
||||
text[0] = '\0';
|
||||
if (!status) return;
|
||||
|
||||
switch (type) {
|
||||
case status_net_down:
|
||||
snprintf(text, text_size, "%s", status->net_speed.down);
|
||||
break;
|
||||
case status_net_up:
|
||||
snprintf(text, text_size, "%s", status->net_speed.up);
|
||||
break;
|
||||
case status_audio:
|
||||
if (status->pulse) {
|
||||
snprintf(text, text_size, "%d%%%s%s%s", status->pulse->volume_percent,
|
||||
status->pulse->mute ? "M" : "",
|
||||
strlen(status->pulse->device_name) ? "|" : "",
|
||||
status->pulse->device_name);
|
||||
} else {
|
||||
snprintf(text, text_size, "0%%");
|
||||
}
|
||||
break;
|
||||
case status_memory:
|
||||
snprintf(text, text_size, "%s(%.1f%%)", status->mem_usage.mem_used_text,
|
||||
status->mem_usage.mem_percent);
|
||||
break;
|
||||
case status_cpu:
|
||||
snprintf(text, text_size, "%.1lf", status->cpu_usage_percent);
|
||||
break;
|
||||
case status_time:
|
||||
snprintf(text, text_size, "%s", status->time);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void renderer_render_status(config_status_t *config, size_t config_count,
|
||||
status_t *status, renderer_status_t *output) {
|
||||
static color_t *color_cache = nullptr;
|
||||
static size_t color_cache_count = 0;
|
||||
|
||||
if (!config || !output) return;
|
||||
|
||||
size_t item_count = config->status_count;
|
||||
if (config_count && config_count < item_count) item_count = config_count;
|
||||
|
||||
output->gap = config->status_gap;
|
||||
output->item_gap = config->status_item_gap;
|
||||
output->item_count = item_count;
|
||||
|
||||
if (item_count == 0) return;
|
||||
|
||||
if (color_cache_count < item_count) {
|
||||
xrealloc((void **)&color_cache, (ssize_t)(sizeof(color_t) * item_count));
|
||||
color_cache_count = item_count;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < item_count; i++) {
|
||||
const config_status_item_t *config_item = &config->list[i];
|
||||
renderer_status_item_t *output_item = &output->item_list[i];
|
||||
memset(output_item, 0, sizeof(*output_item));
|
||||
|
||||
output_item->icon_type = config_item->icon_type;
|
||||
if (config_item->icon_type == icon_type_text) {
|
||||
output_item->icon_text = config_item->icon;
|
||||
} else if (config_item->icon_type == icon_type_image) {
|
||||
output_item->icon_path = config_item->icon;
|
||||
}
|
||||
|
||||
status_text_from_data(config_item->type, status, output_item->text,
|
||||
sizeof(output_item->text));
|
||||
|
||||
if (config_item->color && *config_item->color) {
|
||||
color_parse(config_item->color, &color_cache[i]);
|
||||
output_item->color = &color_cache[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/renderer.h
Normal file
41
src/renderer.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "color.h"
|
||||
|
||||
typedef struct config_status_t config_status_t;
|
||||
typedef struct status_t status_t;
|
||||
|
||||
typedef enum icon_type_t {
|
||||
icon_type_none,
|
||||
icon_type_text,
|
||||
icon_type_image,
|
||||
} icon_type_t;
|
||||
|
||||
typedef struct renderer_status_item_t {
|
||||
icon_type_t icon_type;
|
||||
char text[124];
|
||||
const char *icon_text;
|
||||
const char *icon_path;
|
||||
color_t *color;
|
||||
} renderer_status_item_t;
|
||||
|
||||
typedef struct renderer_status_t {
|
||||
uint32_t gap;
|
||||
uint32_t item_gap;
|
||||
size_t item_count;
|
||||
renderer_status_item_t item_list[];
|
||||
} renderer_status_t;
|
||||
|
||||
/**
|
||||
* @brief 根据 status 配置和实时状态生成可绘制的 status 数据
|
||||
*
|
||||
* @param config status 配置
|
||||
* @param config_count 最大输出项数,传 0 表示使用 config->status_count
|
||||
* @param status 实时状态数据
|
||||
* @param output 渲染输出缓冲
|
||||
*/
|
||||
void renderer_render_status(config_status_t *config, size_t config_count,
|
||||
status_t *status, renderer_status_t *output);
|
||||
@@ -30,6 +30,15 @@ typedef struct net_speed_t {
|
||||
char down[64];
|
||||
} net_speed_t;
|
||||
|
||||
typedef enum status_type_t {
|
||||
status_net_down,
|
||||
status_net_up,
|
||||
status_audio,
|
||||
status_memory,
|
||||
status_cpu,
|
||||
status_time,
|
||||
} status_type_t;
|
||||
|
||||
typedef struct status_t {
|
||||
net_speed_t net_speed;
|
||||
memory_usage_t mem_usage;
|
||||
|
||||
6
src/wm.c
6
src/wm.c
@@ -26,8 +26,10 @@
|
||||
#include "buffer.h"
|
||||
#include "client.h"
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
#include "default_config.h"
|
||||
#include "event.h"
|
||||
#include "image.h"
|
||||
#include "monitor.h"
|
||||
#include "status.h"
|
||||
#include "text.h"
|
||||
@@ -384,6 +386,7 @@ void wm_clean(void) {
|
||||
|
||||
clean_status();
|
||||
text_clean_pango_layout();
|
||||
image_cache_clean();
|
||||
|
||||
{
|
||||
client_t *c = wm.client_stack_list;
|
||||
@@ -417,6 +420,9 @@ void wm_clean(void) {
|
||||
}
|
||||
|
||||
static void wm_setup(void) {
|
||||
wm.config = init_config();
|
||||
if (!wm.config) fatal("cannot init config");
|
||||
|
||||
wm.layout_list = layout_list;
|
||||
wm.layout_count = (uint16_t)countof(layout_list);
|
||||
|
||||
|
||||
3
src/wm.h
3
src/wm.h
@@ -10,6 +10,8 @@
|
||||
#include "types.h"
|
||||
#include "wallpaper.h"
|
||||
|
||||
typedef struct config_t config_t;
|
||||
|
||||
typedef struct wm_t {
|
||||
padding_t padding;
|
||||
uint16_t border_width;
|
||||
@@ -19,6 +21,7 @@ typedef struct wm_t {
|
||||
bool need_restart;
|
||||
GMainLoop *loop;
|
||||
status_t *status;
|
||||
const config_t *config;
|
||||
|
||||
client_t *client_list;
|
||||
client_t *client_stack_list;
|
||||
|
||||
Reference in New Issue
Block a user