状态栏绘制添加图标和色彩设置

This commit is contained in:
2025-09-01 00:56:45 +08:00
parent 1b0ed3b9b8
commit 91950dc2f4
14 changed files with 244 additions and 29 deletions

View File

@@ -45,6 +45,14 @@ pkg_check_modules(PULSE REQUIRED libpulse-mainloop-glib)
add_subdirectory(xcb)
add_subdirectory(renderer)
# status icons(all from https://remixicon.com/)
set(NET_UP_ICON "${SOURCE_DIR}/resources/icons/corner-right-up-line.png")
set(NET_DOWN_ICON "${SOURCE_DIR}/resources/icons/corner-left-down-line.png")
set(SPEAKER_ICON "${SOURCE_DIR}/resources/icons/volume-up-fill.png")
set(MEM_ICON "${SOURCE_DIR}/resources/icons/ram-line.png")
set(CPU_ICON "${SOURCE_DIR}/resources/icons/cpu-line.png")
set(CLOCK_ICON "${SOURCE_DIR}/resources/icons/time-line.png")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/app.h.in"
"${CMAKE_BINARY_DIR}/app.h"

View File

@@ -1,3 +1,10 @@
#pragma once
#define APP_NAME "@APP_NAME@"
#define NET_UP_ICON "@NET_UP_ICON@"
#define NET_DOWN_ICON "@NET_DOWN_ICON@"
#define SPEAKER_ICON "@SPEAKER_ICON@"
#define MEM_ICON "@MEM_ICON@"
#define CPU_ICON "@CPU_ICON@"
#define CLOCK_ICON "@CLOCK_ICON@"

View File

@@ -152,7 +152,12 @@ const char *const client_name_bg = "#222222";
const char *const client_name_color = "#bbbbbb";
const char *const active_client_name_bg = "#005577";
const char *const active_client_name_color = "#eeeeee";
const char *const status_color = "#bbbbbb";
const char *const status_net_recv_color = "#87af5f";
const char *const status_net_send_color = "#e54c62";
const char *const status_volume_color = "#7493d2";
const char *const status_memory_color = "#e0da37";
const char *const status_cpu_color = "#e33a6e";
const char *const status_datetime_color = "#7788af";
const char *const border_color = "#444444";
const char *const active_border_color = "#005577";
@@ -164,5 +169,6 @@ const uint32_t bar_y_padding = 1;
const uint32_t tag_x_padding = 10;
const uint32_t layout_symbol_x_padding = 10;
const uint32_t client_name_x_padding = 10;
const uint32_t status_x_padding = 6;
const uint32_t status_x_padding = 4;
const uint32_t status_icon_padding = 2;
const uint32_t border_width = 1;

View File

@@ -1,5 +1,6 @@
#pragma once
#include <cairo.h>
#include <stdbool.h>
#include <stdint.h>
@@ -9,11 +10,13 @@ uint32_t *generate_wallpaper(const wallpaper_config_t *wallpaper_config,
const monitor_t *monitors, const uint32_t index,
const uint32_t screen_width,
const uint32_t screen_height);
uint32_t *generate_icon_pixels(const char *image_path, uint32_t width,
uint32_t height, uint32_t padding);
uint32_t get_font_height(const char *font_family, const uint32_t font_size,
const uint32_t dpi);
void draw_bar(monitor_t *monitor, bool is_current_monitor, status_t *status,
color_set_t *color_set, uint32_t height, uint32_t tag_x_padding,
uint32_t layout_x_padding, uint32_t client_name_x_padding,
uint32_t status_x_padding);
icons_t *icons, color_set_t *color_set, uint32_t height,
uint32_t tag_x_padding, uint32_t layout_x_padding,
uint32_t client_name_x_padding, uint32_t status_x_padding);
void clean_pango_context(void);

View File

@@ -115,7 +115,12 @@ typedef struct color_set_t {
color_t client_name_color;
color_t active_client_name_bg;
color_t active_client_name_color;
color_t status_color;
color_t status_net_recv_color;
color_t status_net_send_color;
color_t status_volume_color;
color_t status_memory_color;
color_t status_cpu_color;
color_t status_datetime_color;
color_t border_color;
color_t active_border_color;
} color_set_t;
@@ -160,3 +165,21 @@ typedef struct {
double cpu_usage_percent;
char time[256];
} status_t;
typedef struct icons_t {
/* 像素数据 */
uint32_t *net_down_pixels;
uint32_t *net_up_pixels;
uint32_t *volume_pixels;
uint32_t *memory_pixels;
uint32_t *cpu_pixels;
uint32_t *clock_pixels;
/* cairo_t * 类型,为避免引入 cairo 库使用 void * 类型代替 */
void *net_down;
void *net_up;
void *volume;
void *memory;
void *cpu;
void *clock;
} icons_t;

View File

@@ -13,6 +13,7 @@
#include <xcb/xproto.h>
#include "action.h"
#include "app.h"
#include "config.h"
#include "event-adapter.h"
#include "layout.h"
@@ -30,6 +31,8 @@ static void set_wallpaper_by_index(uint32_t index, wallpaper_config_t *config,
cairo_t *cr);
static wallpaper_config_t *parse_wallpaper_config(void);
static void free_wallpaper_config(wallpaper_config_t *wallpaper_config);
static void init_icons(void);
static void clean_icons(void);
static void init_color_set(void);
static void parse_color(const char *hex, color_t *color);
static void init_monitor_bar(void);
@@ -82,6 +85,7 @@ static monitor_t *monitors = NULL;
static monitor_t *current_monitor = NULL;
static cairo_t *wallpaper_cr = NULL;
static wallpaper_config_t *wallpaper_config = NULL;
static icons_t *icons = NULL;
static color_set_t *color_set = NULL;
static status_t *status = NULL;
static GMainLoop *loop = NULL;
@@ -94,6 +98,7 @@ static uint32_t tag_x_pad = tag_x_padding;
static uint32_t layout_symbol_x_pad = layout_symbol_x_padding;
static uint32_t client_name_x_pad = client_name_x_padding;
static uint32_t status_x_pad = status_x_padding;
static uint32_t status_icon_pad = status_icon_padding;
static uint32_t bar_height = 0;
static uint32_t border_px = border_width;
@@ -253,7 +258,12 @@ static void print_color_set(color_set_t *set) {
print_color("== client name color:", &set->client_name_color);
print_color("== active client name bg:", &set->active_client_name_bg);
print_color("== active client name color:", &set->active_client_name_color);
print_color("== status color:", &set->status_color);
print_color("== status net recv color:", &set->status_net_recv_color);
print_color("== status net send color:", &set->status_net_send_color);
print_color("== status volume color:", &set->status_volume_color);
print_color("== status memory color:", &set->status_memory_color);
print_color("== status cpu color:", &set->status_cpu_color);
print_color("== status datetime color:", &set->status_datetime_color);
print_color("== border color:", &set->border_color);
print_color("== active border color:", &set->active_border_color);
}
@@ -489,6 +499,66 @@ void free_wallpaper_config(wallpaper_config_t *wallpaper_config) {
free(wallpaper_config);
}
void init_icons(void) {
typedef struct {
const char *img_path;
cairo_surface_t **icon;
uint32_t **pixels;
} icon_path_surface_map_t;
if (icons) return;
icons = ecalloc(1, sizeof(icons_t));
icon_path_surface_map_t map[] = {
{NET_DOWN_ICON, (cairo_surface_t **)&icons->net_down,
&icons->net_down_pixels},
{NET_UP_ICON, (cairo_surface_t **)&icons->net_up, &icons->net_up_pixels},
{SPEAKER_ICON, (cairo_surface_t **)&icons->volume, &icons->volume_pixels},
{MEM_ICON, (cairo_surface_t **)&icons->memory, &icons->memory_pixels},
{CPU_ICON, (cairo_surface_t **)&icons->cpu, &icons->cpu_pixels},
{CLOCK_ICON, (cairo_surface_t **)&icons->clock, &icons->clock_pixels},
};
for (int i = 0; i < LENGTH(map); i++) {
const char *path = map[i].img_path;
uint32_t **pixels_addr = map[i].pixels;
cairo_surface_t **surface_addr = map[i].icon;
if (path && strlen(path)) {
*pixels_addr =
generate_icon_pixels(path, bar_height, bar_height, status_icon_pad);
cairo_format_t format = CAIRO_FORMAT_ARGB32;
int stride = cairo_format_stride_for_width(format, bar_height);
cairo_surface_t *surface = cairo_image_surface_create_for_data(
(uint8_t *)*pixels_addr, format, bar_height, bar_height, stride);
if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS) {
*surface_addr = surface;
} else {
cairo_surface_destroy(surface);
}
}
}
}
void clean_icons(void) {
if (!icons) return;
if (icons->net_down) cairo_surface_destroy(icons->net_down);
if (icons->net_up) cairo_surface_destroy(icons->net_up);
if (icons->volume) cairo_surface_destroy(icons->volume);
if (icons->memory) cairo_surface_destroy(icons->memory);
if (icons->cpu) cairo_surface_destroy(icons->cpu);
if (icons->clock) cairo_surface_destroy(icons->clock);
if (icons->net_down_pixels) free(icons->net_down);
if (icons->net_up_pixels) free(icons->net_up);
if (icons->volume_pixels) free(icons->volume);
if (icons->memory_pixels) free(icons->memory);
if (icons->cpu_pixels) free(icons->cpu);
if (icons->clock_pixels) free(icons->clock);
free(icons);
icons = NULL;
}
void init_color_set(void) {
color_set = ecalloc(1, sizeof(color_set_t));
char *bar_background = NULL;
@@ -501,7 +571,12 @@ void init_color_set(void) {
char *client_name = NULL;
char *active_client_name_background = NULL;
char *active_client_name = NULL;
char *status = NULL;
char *status_net_recv = NULL;
char *status_net_send = NULL;
char *status_volume = NULL;
char *status_memory = NULL;
char *status_cpu = NULL;
char *status_datetime = NULL;
char *border = NULL;
char *active_border = NULL;
@@ -520,7 +595,17 @@ void init_color_set(void) {
&active_client_name_background, active_client_name_bg);
get_xresource_string("zswm.color.active_client_name_color",
&active_client_name, active_client_name_color);
get_xresource_string("zswm.color.status", &status, status_color);
get_xresource_string("zswm.color.status_net_recv", &status_net_recv,
status_net_recv_color);
get_xresource_string("zswm.color.status_net_send", &status_net_send,
status_net_send_color);
get_xresource_string("zswm.color.status_volume", &status_volume,
status_volume_color);
get_xresource_string("zswm.color.status_memory", &status_memory,
status_memory_color);
get_xresource_string("zswm.color.status_cpu", &status_cpu, status_cpu_color);
get_xresource_string("zswm.color.status_datetime", &status_datetime,
status_datetime_color);
get_xresource_string("zswm.color.border", &border, border_color);
get_xresource_string("zswm.color.active_border", &active_border,
active_border_color);
@@ -535,7 +620,12 @@ void init_color_set(void) {
parse_color(client_name, &color_set->client_name_color);
parse_color(active_client_name_background, &color_set->active_client_name_bg);
parse_color(active_client_name, &color_set->active_client_name_color);
parse_color(status, &color_set->status_color);
parse_color(status_net_recv, &color_set->status_net_recv_color);
parse_color(status_net_send, &color_set->status_net_send_color);
parse_color(status_volume, &color_set->status_volume_color);
parse_color(status_memory, &color_set->status_memory_color);
parse_color(status_cpu, &color_set->status_cpu_color);
parse_color(status_datetime, &color_set->status_datetime_color);
parse_color(border, &color_set->border_color);
parse_color(active_border, &color_set->active_border_color);
@@ -549,7 +639,12 @@ void init_color_set(void) {
free(client_name);
free(active_client_name_background);
free(active_client_name);
free(status);
free(status_net_recv);
free(status_net_send);
free(status_volume);
free(status_memory);
free(status_cpu);
free(status_datetime);
free(border);
free(active_border);
}
@@ -602,6 +697,7 @@ void get_xresource_config(void) {
get_xresource_uint32("zswm.layout_symbol_x_padding", &layout_symbol_x_pad);
get_xresource_uint32("zswm.client_name_x_padding", &client_name_x_pad);
get_xresource_uint32("zswm.status_x_padding", &status_x_pad);
get_xresource_uint32("zswm.status_icon_padding", &status_icon_pad);
get_xresource_uint32("zswm.border_width", &border_px);
logger("dpi: %u, font family: %s, font size: %u\n", dpi, font_family,
@@ -619,8 +715,8 @@ void draw_all_monitor_bars(void) {
}
void draw_monitor_bar(monitor_t *m) {
draw_bar(m, m == current_monitor, status, color_set, bar_height, tag_x_pad,
layout_symbol_x_pad, client_name_x_pad, status_x_pad);
draw_bar(m, m == current_monitor, status, icons, color_set, bar_height,
tag_x_pad, layout_symbol_x_pad, client_name_x_pad, status_x_pad);
flush_xcb_connection();
}
@@ -1294,6 +1390,8 @@ void cleanup(bool will_restart) {
free(color_set);
color_set = NULL;
clean_icons();
free(font_family);
font_family = NULL;
@@ -1317,6 +1415,7 @@ int main(int argc, char *argv[]) {
init_monitor_bar();
change_window_cursor(get_root_window(), cursor_normal);
init_wallpaper();
init_icons();
init_status(g_main_loop_get_context(loop), update_status);
draw_all_monitor_bars();

View File

@@ -1,7 +1,9 @@
#include <Imlib2.h>
#include <cairo.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -11,7 +13,7 @@
/**
* @brief 生成需要由 xcb 绘制的壁纸数据
* @returns 壁纸数据,使用后记得释放
* @returns 壁纸像素数据( RGBA 顺序),使用后记得使用 free 释放
*/
uint32_t *generate_wallpaper(const wallpaper_config_t *wallpaper_config,
const monitor_t *monitors, const uint32_t index,
@@ -89,3 +91,47 @@ uint32_t *generate_wallpaper(const wallpaper_config_t *wallpaper_config,
return result;
}
/**
* 生成图标像素数据
* @returns 图标像素数据( RGBA 顺序),使用后记得使用 free 释放
*/
uint32_t *generate_icon_pixels(const char *image_path, uint32_t width,
uint32_t height, uint32_t padding) {
uint32_t dst_width = width - padding * 2;
uint32_t dst_height = height - padding * 2;
if (dst_width <= 0 || dst_height <= 0) return NULL;
Imlib_Image img = imlib_load_image(image_path);
imlib_context_set_image(img);
int w = imlib_image_get_width();
int h = imlib_image_get_height();
float width_ratio = (float)dst_width / w;
float height_ratio = (float)dst_height / h;
float scale = MAX(width_ratio, height_ratio);
int src_width = dst_width / scale;
int src_height = dst_height / scale;
int src_x = (w - src_width) / 2;
int src_y = (h - src_height) / 2;
Imlib_Image target_img = imlib_create_image(width, height);
imlib_context_set_image(target_img);
imlib_image_set_has_alpha(false);
imlib_context_set_color(0, 0, 0, 255);
imlib_image_fill_rectangle(0, 0, width, height);
imlib_blend_image_onto_image(img, 1, src_x, src_y, src_width, src_height,
padding, padding, dst_width, dst_height);
uint32_t *data = imlib_image_get_data_for_reading_only();
uint32_t data_size = width * height * sizeof(uint32_t);
uint32_t *pixels = ecalloc(1, data_size);
if (pixels) memcpy(pixels, data, data_size);
imlib_free_image_and_decache();
imlib_context_set_image(img);
imlib_free_image_and_decache();
return pixels;
}

View File

@@ -137,33 +137,56 @@ static void draw_rect(cairo_t *cr, int32_t x, int32_t y, uint32_t width,
}
}
static int32_t draw_status(monitor_t *monitor, status_t *status,
static int32_t draw_status(monitor_t *monitor, status_t *status, icons_t *icons,
color_set_t *color_set, uint32_t height,
uint32_t x_padding, int32_t end) {
char cpu[16], mem[64], volume[600], net_down[140], net_up[140];
sprintf(cpu, ":%.1f", status->cpu_usage_percent);
sprintf(mem, ":%s(%.1f%%)", status->mem_usage.mem_used_text,
typedef struct {
const char *const text;
color_t *color;
cairo_surface_t *surface;
} status_item_t;
char cpu[16], mem[64], volume[600];
sprintf(cpu, "%.1f", status->cpu_usage_percent);
sprintf(mem, "%s(%.1f%%)", status->mem_usage.mem_used_text,
status->mem_usage.mem_percent);
sprintf(volume, ":%d%%%s%s%s", status->pulse.avg_volume,
sprintf(volume, "%d%%%s%s%s", status->pulse.avg_volume,
status->pulse.mute ? "M" : "",
strlen(status->pulse.device) ? "|" : "", status->pulse.device);
sprintf(net_down, ":%s", status->net_speed.down);
sprintf(net_up, ":%s", status->net_speed.up);
char *info[] = {net_down, net_up, volume, mem, cpu, status->time};
status_item_t items[] = {
{status->net_speed.down, &color_set->status_net_recv_color,
icons->net_down},
{status->net_speed.up, &color_set->status_net_send_color, icons->net_up},
{volume, &color_set->status_volume_color, icons->volume},
{mem, &color_set->status_memory_color, icons->memory},
{cpu, &color_set->status_cpu_color, icons->cpu},
{status->time, &color_set->status_datetime_color, icons->clock},
};
int32_t x = monitor->monitor_width;
color_t *color = &color_set->status_color;
for (int i = LENGTH(info) - 1; i >= 0; i--) {
char *text = info[i];
for (int i = LENGTH(items) - 1; i >= 0; i--) {
const char *text = items[i].text;
if (!strlen(text)) continue;
color_t *color = items[i].color;
uint32_t width = get_text_width(text);
x -= width + x_padding;
if (x < end) return x + (width + x_padding);
draw_text(monitor->cr, text, color, x, 0, width, height, false);
cairo_surface_t *surface = items[i].surface;
if (surface) {
if (x - height < end) return x;
x -= height;
cairo_set_source_surface(monitor->cr, surface, x, 0);
cairo_paint(monitor->cr);
/* refresh_window(monitor->bar_window); */
}
x -= x_padding;
if (x < end) return x + x_padding;
}
@@ -171,9 +194,9 @@ static int32_t draw_status(monitor_t *monitor, status_t *status,
};
void draw_bar(monitor_t *monitor, bool is_current_monitor, status_t *status,
color_set_t *color_set, uint32_t height, uint32_t tag_x_padding,
uint32_t layout_x_padding, uint32_t client_name_x_padding,
uint32_t status_x_padding) {
icons_t *icons, color_set_t *color_set, uint32_t height,
uint32_t tag_x_padding, uint32_t layout_x_padding,
uint32_t client_name_x_padding, uint32_t status_x_padding) {
cairo_t *cr = monitor->cr;
int32_t x = 0;
uint32_t width = 0;
@@ -218,7 +241,7 @@ void draw_bar(monitor_t *monitor, bool is_current_monitor, status_t *status,
/* 绘制状态栏信息 */
int32_t status_start =
draw_status(monitor, status, color_set, height, status_x_padding, x);
draw_status(monitor, status, icons, color_set, height, status_x_padding, x);
/* 绘制 client name 列表 */
if (visible_client_count) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB