Add battery readout

This commit is contained in:
Wojciech Kozlowski 2018-12-26 02:16:54 +05:30
parent ed816fa7ad
commit abd8b6bb1b
3 changed files with 127 additions and 7 deletions

1
Cargo.lock generated
View File

@ -12,6 +12,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "rwmstatus" name = "rwmstatus"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)", "x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -7,4 +7,5 @@ links = "X11"
build = "build.rs" build = "build.rs"
[dependencies] [dependencies]
x11 = "2" x11 = "2"
libc = "0.2"

View File

@ -1,14 +1,130 @@
//! # rwmstatus
//!
//! Status monitor bar for the dwm/rwm window manager (or any WM which uses
//! WM_NAME of the X11 root window as its status bar). It is a direct port of
//! [dwmstatus](https://dwm.suckless.org/status_monitor/) to Rust.
//!
//! This is part of a larger project to port various
//! [suckless.org](https://suckless.org/) programs to Rust, a programming
//! language that sucks less.
extern crate x11; extern crate x11;
extern crate libc;
use x11::xlib::Display; // std module imports
use x11::xlib::{XDefaultRootWindow, XOpenDisplay, XStoreName, XSync}; use std::io;
use std::io::prelude::*;
use std::ptr;
use std::process; use std::process;
use std::ptr;
use std::thread; use std::thread;
use std::time; use std::time;
// std type imports
use std::ffi::CString; use std::ffi::CString;
use std::fs::File;
// x11 imports
use x11::xlib::Display;
use x11::xlib::{XDefaultRootWindow, XOpenDisplay, XStoreName, XSync};
/// Convert a Rust string to a CString and panic if it fails.
#[inline]
fn cstring(string: &str) -> CString {
CString::new(string).expect(&format!("CString::new({}) failed.", string))
}
/// Read the contents of the file base/filename and return as a String.
#[inline]
fn read_file(base: &str, filename: &str) -> io::Result<String> {
let mut file = File::open([base, filename].join("/"))?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
/// Return the three load average values.
fn get_load_avgs() -> String {
let mut avgs: [libc::c_double; 3] = [0.0; 3];
let rc: libc::c_int;
unsafe {
rc = libc::getloadavg(&mut avgs[0] as *mut libc::c_double, 3);
}
if rc < 0 {
return format!("");
}
format!("{:.2} {:.2} {:.2}", avgs[0], avgs[1], avgs[2])
}
const BATT_PATH: &'static str = "/sys/class/power_supply";
const BATTS: [&'static str; 2] = ["BAT0", "BAT1"];
/// Return battery status for all batteries.
fn get_batteries() -> String {
let mut batt_strs: Vec<String> = vec![];
for batt in BATTS.iter() {
batt_strs.push(get_battery(&[BATT_PATH, batt].join("/")));
}
batt_strs.join("|")
}
/// Return battery status for the battery at the provided path.
fn get_battery(batt_base: &str) -> String {
match read_file(&batt_base, "present") {
Ok(contents) => {
if !contents.starts_with('1') {
return format!("not present");
}
}
Err(_) => return format!(""),
};
let co = match read_file(&batt_base, "charge_full_design") {
Ok(contents) => contents,
Err(_) => {
match read_file(&batt_base, "energy_full_design") {
Ok(contents) => contents,
Err(_) => return format!(""),
}
}
};
let desired_capacity: u64 = co.trim().parse().expect(&format!("Not a number: {}", co));
let co = match read_file(&batt_base, "charge_now") {
Ok(contents) => contents,
Err(_) => {
match read_file(&batt_base, "energy_now") {
Ok(contents) => contents,
Err(_) => return format!(""),
}
}
};
let remaining_capacity: u64 = co.trim().parse().expect(&format!("Invalid number: {}", co));
let status: char = match read_file(&batt_base, "status") {
Ok(contents) => {
match &contents.trim()[..] {
"Full" => 'F',
"Discharging" => '-',
"Charging" => '+',
_ => '?',
}
}
Err(_) => '?',
};
format!(
"{:.0}%{}",
((remaining_capacity as f64) / (desired_capacity as f64)) * 100.0,
status
)
}
fn main() { fn main() {
let display: *mut Display; let display: *mut Display;
@ -23,13 +139,15 @@ fn main() {
} }
loop { loop {
let status = CString::new("Hello!").expect("CString::new failed when setting status."); let avgs = get_load_avgs();
let batts = get_batteries();
let status = cstring(&format!("L:{} B:{}", avgs, batts));
unsafe { unsafe {
XStoreName(display, XDefaultRootWindow(display), status.as_ptr()); XStoreName(display, XDefaultRootWindow(display), status.as_ptr());
XSync(display, false as i32); XSync(display, false as i32);
} }
thread::sleep(time::Duration::from_secs(1)); thread::sleep(time::Duration::from_secs(60));
} }
} }