diff --git a/src/app.rs b/src/app.rs index 12a8041..ade6afd 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,9 +1,9 @@ use crate::widget::{Message, PanelWidget}; use crate::widgets::battery::BatteryWidget; use crate::widgets::clock::ClockWidget; +use crate::widgets::focused_window::FocusedWindowWidget; use crate::widgets::powerbutton::ShutdownWidget; use crate::widgets::spacer::Spacer; - use iced::Color; use iced::Element; use iced::Subscription; @@ -24,6 +24,7 @@ impl App { Box::new(ShutdownWidget::new()), Box::new(Spacer::new(iced::Length::Fill)), Box::new(BatteryWidget::new()), + Box::new(FocusedWindowWidget::new()), ], } } diff --git a/src/main.rs b/src/main.rs index 28a7691..3ca9b28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,28 +1,22 @@ -use iced::Color; -use iced::Element; -use iced::Task; -use iced::widget::button; -use iced::widget::container; -use iced::widget::row; -use iced::widget::text; use iced_layershell::daemon; use iced_layershell::reexport::Anchor; -use iced_layershell::reexport::NewLayerShellSettings; use iced_layershell::settings::LayerShellSettings; use iced_layershell::settings::Settings; -use iced_layershell::to_layer_message; -use std::collections::HashMap; -use std::time::Duration; + +mod app; +mod widget; +mod widgets; +use app::App; pub fn main() -> Result<(), iced_layershell::Error> { - daemon(App::default, App::name, App::update, App::view) + daemon(App::new, App::name, App::update, App::view) .style(App::style) .theme(App::theme) .subscription(App::subscription) .settings(Settings { layer_settings: LayerShellSettings { - size: Some((0, 32)), - exclusive_zone: 32, + size: Some((0, App::WINDOW_HEIGHT)), + exclusive_zone: App::WINDOW_HEIGHT as i32, anchor: Anchor::Top | Anchor::Left | Anchor::Right, start_mode: iced_layershell::settings::StartMode::AllScreens, ..Default::default() @@ -32,224 +26,3 @@ pub fn main() -> Result<(), iced_layershell::Error> { .run() } -struct App { - popups: HashMap, - power_off_widget: PowerOffWidget, - time_widget: TimeWidget, - battery_widget: BatteryWidget, -} - -enum PopupKind { - PowerOff, -} - -impl Default for App { - fn default() -> Self { - let mut output = Self { - popups: HashMap::new(), - power_off_widget: PowerOffWidget(None, false), - time_widget: Default::default(), - battery_widget: Default::default(), - }; - let _ = output.update(Message::Clock); - - output - } -} - -impl App { - fn name() -> String { - "wayland_panel".into() - } - - fn close_popup(&mut self, id: iced::window::Id) -> Task { - self.popups.remove(&id); - Task::done(Message::RemoveWindow(id)) - } - - fn view(&self, id: iced::window::Id) -> Element<'_, Message> { - if let Some(kind) = self.popups.get(&id) { - return match kind { - PopupKind::PowerOff => container( - row![ - text("Shut down?"), - button("✓").on_press(Message::PowerOffConfirm), - button("✗").on_press(Message::PowerOffCancel), - ] - .spacing(8) - .align_y(iced::Alignment::Center), - ) - .center(iced::Length::Fill) - .into(), - }; - } - - // default: the bar - let content = row![ - self.time_widget.view(), - iced::widget::space().width(iced::Length::Fill), - self.power_off_widget.view(), - iced::widget::space().width(iced::Length::Fill), - self.battery_widget.view(), - ] - .padding(iced::Padding::from([0, 5])) - .height(iced::Length::Fill) - .width(iced::Length::Fill) - .align_y(iced::Alignment::Center); - - container(content).into() - } - - fn update(&mut self, message: Message) -> Task { - match message { - Message::Clock => { - self.time_widget.update(); - self.battery_widget.update(); - - Task::none() - } - Message::PowerOff => { - let id = iced::window::Id::unique(); - self.popups.insert(id, PopupKind::PowerOff); - - self.power_off_widget.0 = Some(id); - - Task::done(Message::NewLayerShell { - settings: NewLayerShellSettings { - size: Some((220, 40)), - anchor: Anchor::Top, - layer: iced_layershell::reexport::Layer::Overlay, - keyboard_interactivity: - iced_layershell::reexport::KeyboardInteractivity::OnDemand, - exclusive_zone: None, - ..Default::default() - }, - id, - }) - } - Message::PowerOffConfirm => { - std::process::Command::new("poweroff").spawn().ok(); - Task::none() - } - Message::PowerOffCancel => self.close_popup(self.power_off_widget.0.unwrap()), - _ => Task::none(), - } - } - - fn style(&self, theme: &iced::Theme) -> iced::theme::Style { - iced::theme::Style { - background_color: Color::TRANSPARENT, - text_color: theme.palette().text, - } - } - - fn theme(&self, _id: iced::window::Id) -> iced::Theme { - iced::Theme::GruvboxDark - } - - fn subscription(&self) -> iced::Subscription { - iced::time::every(Duration::from_secs(1)).map(|_| Message::Clock) - } -} - -trait PanelWidget { - fn update(&mut self); - fn view(&self) -> Element<'_, Message>; -} - -#[derive(Default)] -struct BatteryWidget { - battery: Option, -} - -impl PanelWidget for BatteryWidget { - fn update(&mut self) { - let file_content = std::fs::read_to_string(std::path::Path::new( - "/sys/class/power_supply/BAT0/capacity", - )); - - let Ok(file_string) = file_content else { - self.battery = None; - return; - }; - - let file_string = file_string.trim(); - - let Ok(value) = file_string.parse::() else { - self.battery = None; - return; - }; - - self.battery = Some(value); - } - - fn view(&self) -> Element<'_, Message> { - match self.battery { - Some(battery) => text!("{} {}", battery.to_string(), Self::get_icon(battery)), - None => text("󰂃"), - } - .into() - } -} - -impl BatteryWidget { - fn get_icon(battery: usize) -> &'static str { - match battery { - 0..6 => "󰂎", - 6..11 => "󰁺", - 11..21 => "󰁻", - 21..31 => "󰁼", - 31..41 => "󰁽", - 41..51 => "󰁾", - 51..61 => "󰁿", - 61..71 => "󰂀", - 71..81 => "󰂁", - 81..91 => "󰂂", - 91..101 => "󰁹", - _ => "󰂃", - } - } -} - -#[derive(Default)] -struct TimeWidget { - current_time: chrono::DateTime, -} - -impl PanelWidget for TimeWidget { - fn update(&mut self) { - self.current_time = chrono::Local::now(); - } - - fn view(&self) -> Element<'_, Message> { - text!("{}", self.current_time.format("%H:%m")).into() - } -} - -#[derive(Default)] -struct PowerOffWidget(Option, bool); - -impl PanelWidget for PowerOffWidget { - fn update(&mut self) { - self.1 = !self.1; - } - - fn view(&self) -> Element<'_, Message> { - button("⏻") - .on_press(if self.1 { - Message::PowerOffCancel - } else { - Message::PowerOff - }) - .into() - } -} - -#[to_layer_message(multi)] -#[derive(Debug, Clone)] -pub enum Message { - Clock, - PowerOff, - PowerOffConfirm, - PowerOffCancel, -} diff --git a/src/widgets/focused_window.rs b/src/widgets/focused_window.rs new file mode 100644 index 0000000..53d4c37 --- /dev/null +++ b/src/widgets/focused_window.rs @@ -0,0 +1,30 @@ +use iced::{Subscription, Task}; +use wayland_protocols_wlr::foreign_toplevel; + +use crate::widget::PanelWidget; + +pub struct FocusedWindowWidget { + focused_window: String, +} + +impl FocusedWindowWidget { + pub fn new() -> Self { + Self { + focused_window: foreign_toplevel::v1::client::zwlr_foreign_toplevel_manager_v1::Event, + } + } +} + +impl PanelWidget for FocusedWindowWidget { + fn update(&mut self, _message: &crate::widget::Message) -> iced::Task { + Task::none() + } + + fn subscribe(&self) -> iced::Subscription { + Subscription::none() + } + + fn view(&self, _id: iced::window::Id) -> iced::Element<'_, crate::widget::Message> { + iced::widget::text!("{}", self.focused_window).into() + } +} diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index 22184f7..ae671a2 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -1,4 +1,5 @@ pub mod battery; pub mod clock; +pub mod focused_window; pub mod powerbutton; pub mod spacer;