Skip to content

Commit

Permalink
hardware monitoring widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
it-a-me committed Jun 1, 2023
1 parent f4dacee commit af2e368
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 0 deletions.
36 changes: 36 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[workspace]
members = [
"embargo",
"embargo_widget",
"hyprland_workspaces",
]
2 changes: 2 additions & 0 deletions embargo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ edition = "2021"
anyhow = "1.0.71"
chrono = "0.4.25"
env_logger = "0.10.0"
human-repr = "1.1.0"
hyprland_workspaces = { version = "0.1.0", path = "../hyprland_workspaces" }
slint = { version = "1.0.2", default-features = false, features = ["std", "compat-1-0"] }
smithay-client-toolkit = "0.17.0"
sysinfo = "0.29.0"
thiserror = "1.0.40"
tracing = "0.1.37"
wayland-client = "0.30.1"
Expand Down
104 changes: 104 additions & 0 deletions embargo/src/hardware_mon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use std::time::{Duration, Instant};
use sysinfo::{CpuExt, NetworkExt, SystemExt};

use sysinfo::System;

pub struct HardwareMonitor {
system: System,
modules: Vec<HardwareModule>,
interface_name: String,
network_refresh_frequency: Duration,
}

impl HardwareMonitor {
pub fn new(interface_name: String) -> Self {
let network_refresh_frequency = Duration::from_secs(2);
let modules = vec![
HardwareModule::new(Duration::from_millis(500), Box::new(System::refresh_cpu)),
HardwareModule::new(
Duration::from_millis(1000),
Box::new(System::refresh_memory),
),
HardwareModule::new(
network_refresh_frequency,
Box::new(System::refresh_networks),
),
HardwareModule::new(
Duration::from_secs(10),
Box::new(System::refresh_networks_list),
),
];
Self {
system: System::new(),
modules,
network_refresh_frequency,
interface_name,
}
}
pub fn update(&mut self) {
for module in &mut self.modules {
module.update(&mut self.system);
}
}
pub fn cpu_usage(&self) -> f32 {
self.system.global_cpu_info().cpu_usage()
}
pub fn used_mem(&self) -> u64 {
self.system.used_memory()
}
pub fn total_mem(&self) -> u64 {
self.system.total_memory()
}
pub fn uploaded_bytes(&self) -> u64 {
match self
.system
.networks()
.into_iter()
.find(|(name, _)| **name == self.interface_name)
.map(|(_, network)| network.transmitted())
{
Some(bytes) => bytes / self.network_refresh_frequency.as_secs(),
None => {
tracing::warn!("unable to locate interface '{}'", self.interface_name);
0
}
}
}
pub fn downloaded_bytes(&self) -> u64 {
match self
.system
.networks()
.into_iter()
.find(|(name, _)| **name == self.interface_name)
.map(|(_, network)| network.received())
{
Some(bytes) => bytes / self.network_refresh_frequency.as_secs(),
None => {
tracing::warn!("unable to locate interface '{}'", self.interface_name);
0
}
}
}
}

pub struct HardwareModule {
last_update: Instant,
frequency: Duration,
refresh: Box<dyn Fn(&mut System)>,
}

impl HardwareModule {
pub fn new(frequency: Duration, refresh: Box<dyn Fn(&mut System)>) -> Self {
Self {
last_update: Instant::now() - frequency,
frequency,
refresh,
}
}
pub fn update(&mut self, system: &mut System) {
if self.last_update.elapsed() > self.frequency {
self.last_update = Instant::now();
(self.refresh)(system);
}
}
}
32 changes: 32 additions & 0 deletions embargo/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use human_repr::HumanCount;
use hyprland_workspaces::WorkspaceState;
use slint::{
platform::software_renderer::MinimalSoftwareWindow, Color, ComponentHandle, ModelRc,
Expand All @@ -7,6 +8,7 @@ use smithay_client_toolkit::shell::wlr_layer::Anchor;
use wayland_client::Connection;

mod error;
mod hardware_mon;
mod ui;
mod window;
slint::include_modules!();
Expand All @@ -31,17 +33,47 @@ fn main() -> anyhow::Result<()> {
width,
height,
)?;
let mut hw_mon = hardware_mon::HardwareMonitor::new("enp6s0".into());
hw_mon.update();
let mut workspaces;
let mut formatted_time;
let mut time;
ui.global::<HardwareMonitor>().set_totalmemory(
HumanCount::human_count_bytes(hw_mon.total_mem())
.to_string()
.into(),
);
loop {
event_queue.blocking_dispatch(&mut bar)?;
slint::platform::update_timers_and_animations();
hw_mon.update();
workspaces = Workspaces::new()?;

time = chrono::Local::now();
formatted_time = time.format("%I:%M%P -- %d of %b, %Y").to_string();

ui.set_workspaces(ModelRc::new(workspaces.as_modal()));
ui.set_time(formatted_time.into());
ui.global::<HardwareMonitor>().set_cpu_usage(
((hw_mon.cpu_usage() * 10.0).round() / 10.0)
.to_string()
.into(),
);
ui.global::<HardwareMonitor>().set_used_memory(
HumanCount::human_count_bytes(hw_mon.used_mem())
.to_string()
.into(),
);
ui.global::<HardwareMonitor>().set_network_up(
human_repr::HumanThroughput::human_throughput_bytes(hw_mon.uploaded_bytes())
.to_string()
.into(),
);
ui.global::<HardwareMonitor>().set_network_down(
human_repr::HumanThroughput::human_throughput_bytes(hw_mon.downloaded_bytes())
.to_string()
.into(),
);
window.draw_if_needed(|renderer| {
renderer.render(&mut bar.software_buffer, width as usize);
});
Expand Down
34 changes: 34 additions & 0 deletions embargo/ui/main.slint
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
export global Hyprland {
pure callback change_workspace(int);
}
export global HardwareMonitor {
in-out property <string> used_memory;
in-out property <string> totalmemory;
in-out property <string> cpu_usage;
in-out property <string> network_up;
in-out property <string> network_down;
}
export component Workspace inherits Rectangle {
height: 34px;
width: self.height;
Expand Down Expand Up @@ -40,4 +47,31 @@ export component MainUi inherits Window {
font-size: 17px;
x: root.width / 2 - self.width / 2;
}
Hw := HorizontalLayout {
alignment: end;
spacing: 20px;
padding: 10px;
Text {
font-size: 16px;
color: whitesmoke;
text: "Cpu:\{HardwareMonitor.cpu-usage}";
}
Text {
font-size: 16px;
color: whitesmoke;
text: "Mem:\{HardwareMonitor.used-memory}/\{HardwareMonitor.totalmemory}";
}
Text {
font-size: 16px;
color: whitesmoke;
width: 100px;
text: "Up: \{HardwareMonitor.network-up}";
}
Text {
font-size: 16px;
width: 140px;
color: whitesmoke;
text: "Down: \{HardwareMonitor.network-down}";
}
}
}
8 changes: 8 additions & 0 deletions embargo_widget/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "embargo_widget"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
7 changes: 7 additions & 0 deletions embargo_widget/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
///trait that allows a struct to function as a slint widget
pub trait Widget {
///update internal state. It is recomended to maintain an internal timer that limits the frequency of updates
fn update(&mut self) -> Result<(), Box<dyn std::error::Error>>;
///the value to be displaye by the widget
fn value_str(&self) -> &str;
}

0 comments on commit af2e368

Please sign in to comment.