From 98a2aa4b234798d3df5a377bc0aa041209894013 Mon Sep 17 00:00:00 2001 From: Csaba Date: Tue, 8 Oct 2024 19:02:55 +0200 Subject: [PATCH] feat(bar): add cpu widget This commit adds a CPU widget, following the patterns of the Memory widget. --- komorebi-bar/src/cpu.rs | 107 +++++++++++++++++++++++++++++++++++++ komorebi-bar/src/main.rs | 1 + komorebi-bar/src/widget.rs | 4 ++ 3 files changed, 112 insertions(+) create mode 100644 komorebi-bar/src/cpu.rs diff --git a/komorebi-bar/src/cpu.rs b/komorebi-bar/src/cpu.rs new file mode 100644 index 00000000..58f77db9 --- /dev/null +++ b/komorebi-bar/src/cpu.rs @@ -0,0 +1,107 @@ +use crate::widget::BarWidget; +use crate::WIDGET_SPACING; +use eframe::egui::text::LayoutJob; +use eframe::egui::Context; +use eframe::egui::FontId; +use eframe::egui::Label; +use eframe::egui::Sense; +use eframe::egui::TextFormat; +use eframe::egui::TextStyle; +use eframe::egui::Ui; +use schemars::JsonSchema; +use serde::Deserialize; +use serde::Serialize; +use std::process::Command; +use std::time::Duration; +use std::time::Instant; +use sysinfo::RefreshKind; +use sysinfo::System; + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct CpuConfig { + /// Enable the Cpu widget + pub enable: bool, + /// Data refresh interval (default: 10 seconds) + pub data_refresh_interval: Option, +} + +impl From for Cpu { + fn from(value: CpuConfig) -> Self { + let mut system = + System::new_with_specifics(RefreshKind::default().without_memory().without_processes()); + + system.refresh_cpu_usage(); + + Self { + enable: value.enable, + system, + data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + last_updated: Instant::now(), + } + } +} + +pub struct Cpu { + pub enable: bool, + system: System, + data_refresh_interval: u64, + last_updated: Instant, +} + +impl Cpu { + fn output(&mut self) -> String { + let now = Instant::now(); + if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) { + self.system.refresh_cpu_usage(); + self.last_updated = now; + } + + let used = self.system.global_cpu_usage(); + format!("CPU: {:.0}%", used) + } +} + +impl BarWidget for Cpu { + fn render(&mut self, ctx: &Context, ui: &mut Ui) { + if self.enable { + let output = self.output(); + if !output.is_empty() { + let font_id = ctx + .style() + .text_styles + .get(&TextStyle::Body) + .cloned() + .unwrap_or_else(FontId::default); + + let mut layout_job = LayoutJob::simple( + egui_phosphor::regular::CIRCUITRY.to_string(), + font_id.clone(), + ctx.style().visuals.selection.stroke.color, + 100.0, + ); + + layout_job.append( + &output, + 10.0, + TextFormat::simple(font_id, ctx.style().visuals.text_color()), + ); + + if ui + .add( + Label::new(layout_job) + .selectable(false) + .sense(Sense::click()), + ) + .clicked() + { + if let Err(error) = Command::new("cmd.exe").args(["/C", "taskmgr.exe"]).spawn() + { + eprintln!("{}", error) + } + } + } + + ui.add_space(WIDGET_SPACING); + } + } +} diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index c7f3aa26..d3d7033c 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -1,4 +1,5 @@ mod bar; +mod cpu; mod battery; mod config; mod date; diff --git a/komorebi-bar/src/widget.rs b/komorebi-bar/src/widget.rs index c8ba21c5..491443ab 100644 --- a/komorebi-bar/src/widget.rs +++ b/komorebi-bar/src/widget.rs @@ -1,5 +1,7 @@ use crate::battery::Battery; use crate::battery::BatteryConfig; +use crate::cpu::Cpu; +use crate::cpu::CpuConfig; use crate::date::Date; use crate::date::DateConfig; use crate::komorebi::Komorebi; @@ -27,6 +29,7 @@ pub trait BarWidget { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub enum WidgetConfig { Battery(BatteryConfig), + Cpu(CpuConfig), Date(DateConfig), Komorebi(KomorebiConfig), Media(MediaConfig), @@ -40,6 +43,7 @@ impl WidgetConfig { pub fn as_boxed_bar_widget(&self) -> Box { match self { WidgetConfig::Battery(config) => Box::new(Battery::from(*config)), + WidgetConfig::Cpu(config) => Box::new(Cpu::from(*config)), WidgetConfig::Date(config) => Box::new(Date::from(config.clone())), WidgetConfig::Komorebi(config) => Box::new(Komorebi::from(config)), WidgetConfig::Media(config) => Box::new(Media::from(*config)),