From 146148a7cdb343501ed099c9fe9dd150e2cd0c0a Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Sun, 11 May 2025 22:23:47 -0500 Subject: [PATCH] updates to a basic thing if it can find hyprland --- Cargo.lock | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 4 +- justfile | 4 +- src/main.rs | 244 ++++++++++++++++++++++++++++++++++++++------ 4 files changed, 498 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9fccf3..5df08cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,6 +53,7 @@ dependencies = [ "cfg-if", "getrandom", "once_cell", + "serde", "version_check", "zerocopy", ] @@ -325,6 +326,28 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] + [[package]] name = "async-task" version = "4.7.1" @@ -998,6 +1021,27 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", + "unicode-xid", +] + [[package]] name = "detect-desktop-environment" version = "0.2.0" @@ -1548,7 +1592,7 @@ dependencies = [ "presser", "thiserror", "winapi", - "windows", + "windows 0.52.0", ] [[package]] @@ -1670,6 +1714,37 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "hyprland" +version = "0.4.0-beta.2" +source = "git+https://github.com/hyprland-community/hyprland-rs?branch=master#552c77353f89fcb101935b151c47aa925682077e" +dependencies = [ + "ahash 0.8.11", + "async-stream", + "derive_more", + "either", + "futures-lite", + "hyprland-macros", + "num-traits", + "once_cell", + "paste", + "phf", + "serde", + "serde_json", + "serde_repr", + "tokio", +] + +[[package]] +name = "hyprland-macros" +version = "0.4.0-beta.2" +source = "git+https://github.com/hyprland-community/hyprland-rs?branch=master#552c77353f89fcb101935b151c47aa925682077e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -1681,7 +1756,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -1737,6 +1812,7 @@ dependencies = [ "iced_core", "log", "rustc-hash 2.1.0", + "tokio", "wasm-bindgen-futures", "wasm-timer", ] @@ -2046,9 +2122,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" @@ -2243,6 +2319,17 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "naga" version = "0.19.2" @@ -2336,6 +2423,15 @@ dependencies = [ "memoffset", ] +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2479,6 +2575,15 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "objc2-core-image" version = "0.2.2" @@ -2522,6 +2627,16 @@ dependencies = [ "objc2", ] +[[package]] +name = "objc2-io-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "objc2-link-presentation" version = "0.2.2" @@ -3261,6 +3376,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + [[package]] name = "same-file" version = "1.0.6" @@ -3321,6 +3442,18 @@ dependencies = [ "syn 2.0.92", ] +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.19" @@ -3360,6 +3493,7 @@ dependencies = [ "clap", "crisp", "dirs 5.0.1", + "hyprland", "iced", "iced_layershell", "iced_runtime", @@ -3367,6 +3501,7 @@ dependencies = [ "pretty_assertions", "ron", "serde", + "sysinfo", "tokio", "tracing", "tracing-subscriber", @@ -3478,6 +3613,16 @@ dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "softbuffer" version = "0.4.6" @@ -3606,6 +3751,20 @@ dependencies = [ "libc", ] +[[package]] +name = "sysinfo" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows 0.61.1", +] + [[package]] name = "tempfile" version = "3.14.0" @@ -3772,7 +3931,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", + "bytes", + "libc", + "mio", "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", ] [[package]] @@ -4389,10 +4565,32 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", + "windows-core 0.52.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +dependencies = [ + "windows-collections", + "windows-core 0.61.0", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.0", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -4402,6 +4600,85 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index a8c360e..017f9b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ description = "A shell for a computadora" [dependencies] clap = { version = "4.5.20", features = ["debug", "derive"] } -iced = { version = "0.13" } +iced = { version = "0.13", features = ["tokio", "advanced"]} iced_runtime = { version = "0.13", features = [ "multi-window" ] } miette = { version = "7.2.0", features = ["fancy"] } pretty_assertions = "1.4.1" @@ -21,4 +21,6 @@ tokio = "1.41.1" crisp = { git = "https://git.tfcconnection.org/chris/crisp", version = "0.1.3" } iced_layershell = "0.13.0" chrono = "0.4.39" +sysinfo = "0.35.0" +hyprland = { git = "https://github.com/hyprland-community/hyprland-rs", branch = "master" } diff --git a/justfile b/justfile index 79c3dd7..1ea4720 100644 --- a/justfile +++ b/justfile @@ -2,13 +2,13 @@ default: list run: - cargo run + RUST_LOG=debug cargo run build: cargo build watch: - cargo watch -- cargo run + RUST_LOG=debug cargo watch -- cargo run diff --git a/src/main.rs b/src/main.rs index a6ac96e..0d6e6e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,32 +1,81 @@ +use std::cmp; + use chrono::prelude::*; -use iced::widget::{container, row, text}; -use iced::{Background, Border, Color, Element, Font, Length, Task}; +use hyprland::data::Workspaces; +use hyprland::event_listener; +use hyprland::shared::{HyprData, WorkspaceType}; +use iced::font::Weight; +use iced::widget::{container, horizontal_space, row, text, Text}; +use iced::{ + time, Background, Border, Color, Element, Event, Font, Length, Shadow, Subscription, Task, + Theme, Vector, +}; use iced_layershell::build_pattern::{application, MainSettings}; -use iced_layershell::reexport::Anchor; +use iced_layershell::reexport::{Anchor, KeyboardInteractivity}; use iced_layershell::settings::LayerShellSettings; use iced_layershell::to_layer_message; +use iced_runtime::futures::event; +use sysinfo::{Disks, System}; +use tracing::level_filters::LevelFilter; +use tracing::{debug, error}; +use tracing_subscriber::EnvFilter; fn main() -> iced_layershell::Result { + let timer = + tracing_subscriber::fmt::time::ChronoLocal::new("%Y-%m-%d_%I:%M:%S%.6f %P".to_owned()); + let filter = EnvFilter::builder() + .with_default_directive(LevelFilter::WARN.into()) + .parse_lossy("shelly=debug"); + tracing_subscriber::FmtSubscriber::builder() + .pretty() + .with_line_number(true) + .with_level(true) + .with_target(true) + .with_env_filter(filter) + .with_target(true) + .with_timer(timer) + .init(); + + debug!("Starting shelly"); + + let mut font = Font::with_name("VictorMono Nerd Font"); + font.weight = Weight::Bold; let settings = MainSettings { layer_settings: LayerShellSettings { - size: Some((1200, 30)), - anchor: Anchor::Bottom, - margin: (0, 0, 10, 0), - exclusive_zone: 40, + size: Some((1400, 60)), + anchor: Anchor::Bottom | Anchor::Left | Anchor::Right, + margin: (0, 0, 0, 0), + exclusive_zone: 60, + keyboard_interactivity: KeyboardInteractivity::None, ..Default::default() }, - default_font: Font::with_name("VictorMono Nerd Font"), + default_font: font, + // antialiasing: true, ..Default::default() }; application(Panel::namespace, Panel::update, Panel::view) + .subscription(Panel::subscription) + .subscription(|_| { + time::every(time::Duration::from_millis(1000)).map(|_| Message::Time(Local::now())) + }) .settings(settings) .style(Panel::style) .run_with(Panel::new) } +#[derive(Debug)] struct Panel { + time: String, + cpu: String, + memory: String, + battery: String, + disk: String, + system: System, + disks: Disks, + workspaces: Workspaces, + active_workspace: i32, apps: Vec, } @@ -34,47 +83,156 @@ struct Panel { #[derive(Debug, Clone)] enum Message { Launch(usize), + Time(DateTime), + IcedEvent(Event), + WorkspaceChange(WorkspaceType), } impl Panel { fn new() -> (Self, Task) { - (Self { apps: vec![] }, Task::none()) + let workspaces = Workspaces::get().map_err(|e| { + error!("Couldn't get hyprland info: {}", e); + e + }); + ( + Self { + system: System::new_all(), + disks: Disks::new_with_refreshed_list(), + workspaces: workspaces.unwrap(), + active_workspace: 1, + time: String::new(), + cpu: String::new(), + memory: String::new(), + battery: String::new(), + disk: String::new(), + apps: vec![String::new()], + }, + Task::none(), + ) } fn namespace(&self) -> String { - String::from("bottom panel") + String::from("panel") } fn update(&mut self, message: Message) -> Task { match message { - Message::Launch(index) => Task::none(), + Message::Launch(index) => {} + Message::Time(instant) => { + self.system.refresh_memory(); + self.system.refresh_cpu_usage(); + // disk.refresh(); + // let used_space = disk.available_space() - disk.total_space(); + let disk = self.disks.first_mut(); + if let Some(disk) = disk { + self.disk = format!( + "󰋊 {}", + convert((disk.total_space() - disk.available_space()) as f64) + ); + }; + // let used_space = 393; + // self.disk = format!("󰋊 {}", used_space); + self.cpu = format!(" {}%", self.system.global_cpu_usage().round()); + let memory = ((self.system.used_memory() as f64 + / self.system.total_memory() as f64) + .fract() + * 100.0) + .trunc(); + self.memory = format!(" {}%", memory); + self.time = instant.format("%a %b %d, %I:%M %p").to_string(); + } + Message::AnchorChange(anchor) => todo!(), + Message::AnchorSizeChange(anchor, _) => todo!(), + Message::LayerChange(layer) => todo!(), + Message::MarginChange(_) => todo!(), + Message::SizeChange(_) => todo!(), + Message::VirtualKeyboardPressed { time, key } => todo!(), + Message::IcedEvent(event) => { + debug!(?event) + } _ => unreachable!(), + Message::WorkspaceChange(workspace_type) => todo!(), } + Task::none() } + fn subscription(&self) -> Subscription { + event::listen().map(Message::IcedEvent) + } + + // fn hyprland_subscription(&self) -> Subscription { + // let mut event_listener = event_listener::EventListener::new(); + // event_listener.add_workspace_changed_handler(|x| Message::WorkspaceChange(x)); + // Subscription::run(|| event_listener.start_listener()) + // } + fn view(&self) -> Element { - // let bottom_vec: Vec> = self - // .apps - // .iter() - // .enumerate() - // .map(|(index, app)| app.view(index, false)) - // .collect(); - - let datetime: DateTime = Local::now(); - - let clock = text!("{}", datetime.format("%a %b %e, %r")); - let clock = clock.color(Color::parse("#e2e4e5").unwrap()); - - // let row = row(bottom_vec); - container(clock) - .style(|t: &iced::Theme| { - container::rounded_box(t) - .border(Border::default().rounded(20)) - .background( - Background::Color(Color::parse("#282a36").unwrap()).scale_alpha(0.95), - ) + let workspaces: Vec> = self + .workspaces + .iter() + .map(|w| { + text!("{}", { + match w.id { + 1 => "".to_owned(), + 2 => "".to_owned(), + 3 => "󰈙".to_owned(), + 4 => "󰭹".to_owned(), + 5 => "".to_owned(), + 6 => "".to_owned(), + 7 => "󰕧".to_owned(), + 8 => "󰭹".to_owned(), + 9 => "".to_owned(), + _ => w.name.clone(), + } + }) + .color({ + if w.id == self.active_workspace { + Color::parse("#ff6ac1").unwrap() + } else { + Color::parse("#57c7ff").unwrap() + } + }) + .into() }) - .center(Length::Fill) - .into() + .collect(); + let workspaces = row(workspaces).spacing(20).padding([0, 5]); + let disk = text!("{}", self.disk).color(Color::parse("#ff9f43").unwrap()); + let mem = text!("{}", self.memory).color(Color::parse("#f3f99d").unwrap()); + let cpu = text!("{}", self.cpu).color(Color::parse("#57c7ff").unwrap()); + let clock = text!("{}", self.time); + let clock = clock.color(Color::parse("#5af78e").unwrap()); + + let row = row!( + container(workspaces), + container(horizontal_space()), + container(clock), + container(row!(horizontal_space(), disk, cpu, mem).spacing(5)) + ) + .spacing(5) + .padding([0, 20]); + let mut shadow = Shadow::default(); + shadow.color = Color::BLACK; + shadow.offset = Vector::new(4.5, 4.5); + shadow.blur_radius = 18.5; + container( + container(row) + .style(move |t: &iced::Theme| { + container::rounded_box(t) + .border(Border::default().rounded(20)) + .background( + Background::Color(Color::parse("#282a36").unwrap()).scale_alpha(0.95), + ) + .shadow(shadow) + }) + .center(Length::Fill), + ) + .padding([15, 20]) + .center(Length::Fill) + .style(move |t: &iced::Theme| { + container::rounded_box(t) + .border(Border::default().rounded(20)) + .background(Background::Color(Color::TRANSPARENT)) + }) + .into() } fn style(&self, theme: &iced::Theme) -> iced_layershell::Appearance { @@ -85,3 +243,23 @@ impl Panel { } } } + +pub fn convert(num: f64) -> String { + let negative = if num.is_sign_positive() { "" } else { "-" }; + let num = num.abs(); + let units = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + if num < 1_f64 { + return format!("{}{} {}", negative, num, "B"); + } + let delimiter = 1000_f64; + let exponent = cmp::min( + (num.ln() / delimiter.ln()).floor() as i32, + (units.len() - 1) as i32, + ); + let pretty_bytes = format!("{:.2}", num / delimiter.powi(exponent)) + .parse::() + .unwrap() + * 1_f64; + let unit = units[exponent as usize]; + format!("{}{} {}", negative, pretty_bytes, unit) +}