From 91950dc2f4f8c8375d489bc2306c3c21116b300c Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Mon, 1 Sep 2025 00:56:45 +0800 Subject: [PATCH] =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=A0=8F=E7=BB=98=E5=88=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=BE=E6=A0=87=E5=92=8C=E8=89=B2=E5=BD=A9?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CMakeLists.txt | 8 ++ src/app.h.in | 7 ++ src/config.h | 10 +- src/include/renderer.h | 9 +- src/include/types.h | 25 +++- src/main.c | 113 ++++++++++++++++-- src/renderer/image.c | 48 +++++++- src/renderer/text.c | 53 +++++--- src/resources/icons/corner-left-down-line.png | Bin 0 -> 766 bytes src/resources/icons/corner-right-up-line.png | Bin 0 -> 786 bytes src/resources/icons/cpu-line.png | Bin 0 -> 769 bytes src/resources/icons/ram-line.png | Bin 0 -> 564 bytes src/resources/icons/time-line.png | Bin 0 -> 2485 bytes src/resources/icons/volume-up-fill.png | Bin 0 -> 1965 bytes 14 files changed, 244 insertions(+), 29 deletions(-) create mode 100644 src/resources/icons/corner-left-down-line.png create mode 100644 src/resources/icons/corner-right-up-line.png create mode 100644 src/resources/icons/cpu-line.png create mode 100644 src/resources/icons/ram-line.png create mode 100644 src/resources/icons/time-line.png create mode 100644 src/resources/icons/volume-up-fill.png diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index abee543..566a00d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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" diff --git a/src/app.h.in b/src/app.h.in index 30f51d9..9d31fd4 100644 --- a/src/app.h.in +++ b/src/app.h.in @@ -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@" diff --git a/src/config.h b/src/config.h index 4ee184a..7d23518 100644 --- a/src/config.h +++ b/src/config.h @@ -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; diff --git a/src/include/renderer.h b/src/include/renderer.h index ddc01a9..e53f31b 100644 --- a/src/include/renderer.h +++ b/src/include/renderer.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -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); diff --git a/src/include/types.h b/src/include/types.h index 0193481..2efe7b3 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -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; diff --git a/src/main.c b/src/main.c index e690af3..3cfe514 100644 --- a/src/main.c +++ b/src/main.c @@ -13,6 +13,7 @@ #include #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(); diff --git a/src/renderer/image.c b/src/renderer/image.c index 429727c..a4db5a7 100644 --- a/src/renderer/image.c +++ b/src/renderer/image.c @@ -1,7 +1,9 @@ #include +#include #include #include #include +#include #include #include @@ -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; +} diff --git a/src/renderer/text.c b/src/renderer/text.c index f862e96..a344941 100644 --- a/src/renderer/text.c +++ b/src/renderer/text.c @@ -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) { diff --git a/src/resources/icons/corner-left-down-line.png b/src/resources/icons/corner-left-down-line.png new file mode 100644 index 0000000000000000000000000000000000000000..acb77e31834de9821c548cda831ff77ff4b1d4e2 GIT binary patch literal 766 zcmVEkZ_r05AOuT5h*osf(87wOtatz<7Rf5DNNC@oQcJRH+CVnx28e*F z5|7a*VAD2@ATb_L_?dWq?AV@;=4P9T?eqEEa~%(mn13MV`UwI+2gIBJmO#u6fFXz_ zfF%%f0$2huH-Nb=P^_kB34yn|fCG?5HdPWH-&hIkRMRU2tS`C%P)fh%mP;$5<0Al3 zVzSSp1L9r+#r@1{pipr-h}G_~tgG(-F0vt*P3;=XAs%RBle=XA0zd~~2^cFw%m5An zWArfuT@FIn1+WWX7ciDX*aff)^b#;;KWu~82Kje_kv<0$_SVON(uv&i?kB%X4Yv!C zpa6>1Okw!4xxKksY5L72^1XBhysxf3rC>GKWJyZsn_Q|~_L^8W1M-cz!AIv$>g>j6 zkr4W`m9!S}^Pm5Ti1d0^3V5A2*Ln*#osQ>6M`rJ zzIgQzgaPc-G83c?4famyaj&)9ogf0hTl}@*ehghUpQ*?LVF0#h83;iEm=teokpdtC zAqW7|;`;(13c(LR7~=Z|5Cj7A*hcnc>7y5bu*53?U=LFGwl-0ZHwM6-hzB8T@kRkSA^Z>GjRUYJEbgagfLiZb7k^*nS1Z4Rb_iY1X={VJ7OZ+) w1fZH|)W$;xL~X}ZuNNJlnrPI@~ literal 0 HcmV?d00001 diff --git a/src/resources/icons/corner-right-up-line.png b/src/resources/icons/corner-right-up-line.png new file mode 100644 index 0000000000000000000000000000000000000000..c6d9cf4f6971df7baaacf2e052d064a425234ff9 GIT binary patch literal 786 zcmV+t1MU2YP)0O_TQImk>m4gCZE)oAp*mqxc;}q~AkrSH0GQ;5JdDP>+fzdhqI{ z4dO*bJtf_7Hk!KK-MBl`_a+1T_PR4K@Bf?k{xg{cQSb)}u3s-j1g}g!bAXMh_?#CI)I$wtwFE~KvVoa1hEI_XS!?eD2&k>07LOZ%~Fc*5I}^71;ClK{*^*>RRWje@1&3&5YSAWquQY)#l?DO z{SAgEkO9bCc`0Aie|>89s;ByKAtfP~WFU^q65JaH0m~Ce0OS=9+uMWPg|;e$gHH&c z=6jEO&6OL}5YPeWh!16_0gy7dHoN&?BYaN{0TqC*_&fmiA%M86yd;tDVRr{K04Cz| z0{8==wJZT1VnaXyU@Be*02Kr@0DI->u3DXQN!OPCjPEUu+p_*=f@yPhue7hLd#w8@ z?|!Hw^PKK!5e2~TxH{iD(yPGMfj$54Ru{Ux4uGf$rp=4DgYto|3QA+vUw^NAHb4WA zfRIDHZVN=kjUY$?-_%vw*;?28s4G4kj|yPer;9g_3faF^_q{uL64GsfXw02vyHySb zZ%;gX^dZl0rHw%cpqoh6IY2j_?sx{EOALEFS3t^tfvjBsa}l@&Flm~^;uhc*NZtpq z2Sn}zOxj9k4x6A3EsC*hf^33pf{9yU-UWCU_;)Q%VZ70pM%$or?p5{qs)3Q5`UEx? zk2Cr(f)PI}h7o|Bg_RAJ_|>f7rth8i00zJnQ1BMOG{H2Vm;$j{d+NP3^$?wTMkc89 z1Fnx{0IshPb$(m{)P!A+&lTYM3Q_0B6+lhc_4r%?uCEYvep~_6gk6vS8$k3FUmx6F QegFUf07*qoM6N<$f~UD;^#A|> literal 0 HcmV?d00001 diff --git a/src/resources/icons/cpu-line.png b/src/resources/icons/cpu-line.png new file mode 100644 index 0000000000000000000000000000000000000000..0dbef30e82e365ac815d9e28b3e35b3a8a6f4e86 GIT binary patch literal 769 zcmV+c1OEJpP)HC|53xo9~l8w0S#v$$PyT@c6TD? zTNB(8y-7yBhX~)k_DGBqOc(;%o!yA&&O{>2FOsysfh0Hfv`1nX0e={<3ec1biuEmF zUwbsq0;jHk!y6AS{ob&EJS{kq28ic*jj~DDl750Dg3SEc&C20~n-Y6*_QbXNMu0*?tO8I5YzfF0EC1zj*fhX2K)4%3*LoSwG{7`K zyj>0=g1-HLncoU)RD3=ULkbl)0)(!xrh?#)gW@Y-9U+MURZGmXA29PxQQv+5T-Ij* z4DuN?0t5y$9icOrSlESCfZYz)d_4}=YK6c`o1ztt3l0^8fSGzEmGkZ7eg7507<{$; zeWkN}yg;82r*&iKIJ?@~8+<|XfC(s^joaO!ds_;<_(p<N?@?l=c+!QEN0v(ZLruH35io-^b3r_DGH=7$ZQ#7K-(qL0@|`Pg?@P zG@$8!n$nbD-Pj-^Sofeb@r?itTl0u*d00000NkvXXu0mjf^nG9Y literal 0 HcmV?d00001 diff --git a/src/resources/icons/ram-line.png b/src/resources/icons/ram-line.png new file mode 100644 index 0000000000000000000000000000000000000000..f79e4668f89a6892fec30bfd88a0c74fe9c7e1dd GIT binary patch literal 564 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 literal 0 HcmV?d00001 diff --git a/src/resources/icons/volume-up-fill.png b/src/resources/icons/volume-up-fill.png new file mode 100644 index 0000000000000000000000000000000000000000..3537e777896808d1c1ea3ef4b0ea4f23fe5038f5 GIT binary patch literal 1965 zcmV;e2U7TnP)U4^dP^2_%AvLqh>wWR2q=hxiALIPaYB?J;Ux?s+ZY?`J$|>LO?zMMxV_z)waK#N-gD3S{l4@4 zp65_9$bWQ@>rYYuq!=*B5lET9ASXb|38qY-KTN>B%`=Mh(zTRu2dd5aKlX=LQJ-ofhN5SY*>3fDPOK9NF8`xd#g^k`qV^0M>?MQ#hXc1tygxo*N+S1PH66 zfuJh@Hn%sAGV(bDoU9~>7661f?QYL*?EVXK^D{>6PD_DP4Fuf)fbxr>{D*S86E2We z0B(Tr9zc-YZ9gH#TC>ro1cELAK>3YO{w*laMWbLm0H~~FTzjtfAf@zSi761``FnK1 ztUW6!u#o=Z3P9zqlS4Y%+jm3pmC+QBXA}_TDywP9<X#d8RY<5U4CZ)_RE{Qgp;sBh80 z|7Mks#sDF`<*0u@#^nfOA=h!5M&>z+O#i5@X>)r@Ab*`?45iB)#RZ>)KaVg0eE0`G zoT5dczJ9CZ0|FTyV+X`xlreVLX)(=HTgU7=k)27q{*!Tr-@q9@E(?II!TSh8*TKFj zpmn?w0I+2jcE>C?KbWBC)q~@0F7Gb*q!&fsUmGzZE2nbRo!5fTLkzIFJj>z1_h?n9 zuivXh0lUjnPbjs>IJ6F$#wM$o0({d#u;*Lxw>-}+s42<+E-3&IghU1TG5$Rz0fDj2 zFooCD0LQmNMHs3)1Ac^&O>l;5{V)|N11{6w_h*EEazh{J; zMm{hpX&4{~DzG3e&G4^8QN~~mO*vVDet|3C&wI4Y?GdCE_%DK0#oYyiBC?b;Bzo9v{+Y`RN{0Tu4naXjgfW{#9S z;3ziz909;U_5p&R$WzuJPuVVVgq<*f5lR58*?x9dcF(0w@q74zCGZ1ZB^Lnoo|h;` z-;Ho+jC3QUMTEKV_s9q{kr9THp3pnSo&<1vlL`RD^fw`JD1HmVBc@*f0ArLG003?W z0Ft_aQ8M3IY&?`yJ^-2O`^Z$E7ct-{0GO);Kv`qU-3H!&Lj0a*Tw#qR-;*=|l+~Ob zYDm9)F1+;}P>Qi_pzcwmd>9lBab^0f5czYovrpY#dFIE|NK9l5_3UON#bi-~1TI z@dqTpG5RzPON0tD@Cz}(-r${!p3_fC6YBL`sTe{pU@Lk7MRMx`fLKc5o%nW@`1`Az zA#3aU=^YXPga_!t{0>C&^io!C-afa)2ss4m&sURCu_Y#RXd2NIEUEL2PUDD;5PtRm zZHk`Cpc%8a6i;hY0|0Ecg3XdML73C>YO^V#I@EkFpm$pwo$5l~@86HIwwL(1MUK(} zubT3K)9CKbzr<%0F}1~Smil@hj0k4~=_I4A%A9vLnvB>GCp?=~CTi$&FcMs7ARLVa zHiGa!fYuSr7HWnbGV~7Jj>du@^ylHIQ21n!E{|~cNWA+zCB-$x#zr~zX!ZeelLk^y zo^49l@pw~9M*DgHVJLr}L>@-Gr^Xb_Ovv$g_~L;=glA2N<-^tNHkPJn40bPE#E?Cb zNAqJE!e*<|9J(+d0f>y?Gpzs!^MqfNME!rF*PlMWuIyekP@?}53V z7$)}&DF!6>{%My!#Q^OXCie^}1|;|XX_x+g5eyA(o-Xo_00000NkvXXu0mjfKVFPf literal 0 HcmV?d00001