diff --git a/crates/popcorn-d/src/main.rs b/crates/popcorn-d/src/main.rs index c80d785..7049e2c 100644 --- a/crates/popcorn-d/src/main.rs +++ b/crates/popcorn-d/src/main.rs @@ -1,7 +1,18 @@ -mod show_popup; +mod osd; + +use osd::OsdUi; +use popcorn_conf::PopcornConfig; fn main() -> Result<(), Box> { + let cfg = PopcornConfig::load_or_default(); + let osd = OsdUi::new(&cfg)?; + + // start IPC loop here + // for each message: + // osd.update(&args, &cfg) + // reset timer + + let _ = slint::run_event_loop(); - //show_popup::show_popup(/*&parsed_args*/)?; Ok(()) } diff --git a/crates/popcorn-d/src/show_popup.rs b/crates/popcorn-d/src/osd.rs similarity index 58% rename from crates/popcorn-d/src/show_popup.rs rename to crates/popcorn-d/src/osd.rs index a067e79..c5d07dd 100644 --- a/crates/popcorn-d/src/show_popup.rs +++ b/crates/popcorn-d/src/osd.rs @@ -1,4 +1,3 @@ -use crate::args::OsdArgs; use popcorn_conf::PopcornConfig; use i_slint_backend_winit::{ @@ -23,13 +22,68 @@ fn parse_hex_color(s: &str) -> Result { } } +struct OsdArgs { + value: Option, + icon: Option, + color: Option, +} + +pub struct OsdUi { + ui: OSDpopup, +} + +impl OsdUi { + /// Create and display the OSD popup window. + /// Loads config, applies X11 window attributes, sets UI props, and runs the Slint event loop. + pub fn new(cfg: &PopcornConfig) -> Result> { + // Configure X11 window attributes before Slint creates the window. + let window_attrs = |attrs: WindowAttributes| { + attrs + // Present the window as a dock so most WMs avoid decorations and normal window rules. + .with_x11_window_type(vec![WindowType::Dock]) + // Make the window unmanaged. This prevents tiling WMs from reserving space or moving it. + .with_override_redirect(true) + }; + + // Build and activate backend with X11 window-attribute hook. + let backend = Backend::builder() + .with_window_attributes_hook(window_attrs) + .build()?; + slint::platform::set_platform(Box::new(backend))?; + + // Build UI and apply all properties + let ui = OSDpopup::new()?; + + // Apply statis config + let _ = apply_static_props(&ui, &cfg); + + // Start with OSD popup hidden + let _ = ui.window().hide(); + + Ok(Self { ui }) + } + + pub fn update( + &self, + args: &OsdArgs, + cfg: &PopcornConfig, + ) -> Result<(), Box> { + apply_dynamic_props(&self.ui, cfg, args)?; + let _ = self.ui.window().show(); + Ok(()) + } + + pub fn hide(&self) { + let _ = self.ui.window().hide(); + } +} + /// Apply all UI properties to the Slint component. /// Uses the config for static styling and CLI args for dynamic values. #[allow(clippy::cast_precision_loss, clippy::cast_possible_wrap)] -fn set_ui_props( +fn apply_static_props( ui: &OSDpopup, cfg: &PopcornConfig, - args: &OsdArgs, ) -> Result<(), Box> { // Window placement from config ui.window().set_position(LogicalPosition::new( @@ -50,22 +104,31 @@ fn set_ui_props( // Background color ui.set_osd_bg_color(parse_hex_color(&cfg.ui.bg_col)?); - // Fill color: CLI overrides config fallback - let fill_color_hex = args.color.as_deref().unwrap_or(&cfg.ui.default_fill_color); - ui.set_fill_color(parse_hex_color(fill_color_hex)?); - // Percentage value styling ui.set_value_font_size(cfg.percent_value.font_size as i32); ui.set_value_font_color(parse_hex_color(&cfg.percent_value.font_color)?); ui.set_value_font(SharedString::from(cfg.percent_value.font.as_str())); - let percent_value = i32::from(args.value.unwrap_or(0)).clamp(0, 100); - ui.set_percent_value(percent_value); // Icon styling ui.set_icon_size(cfg.icon.size as i32); ui.set_icon_font_color(parse_hex_color(&cfg.icon.color)?); ui.set_icon_font(SharedString::from(cfg.icon.font.as_str())); + Ok(()) +} + +fn apply_dynamic_props( + ui: &OSDpopup, + cfg: &PopcornConfig, + args: &OsdArgs, +) -> Result<(), Box> { + // Fill color: CLI overrides config fallback + let fill_color_hex = args.color.as_deref().unwrap_or(&cfg.ui.default_fill_color); + ui.set_fill_color(parse_hex_color(fill_color_hex)?); + + let percent_value = i32::from(args.value.unwrap_or(0)).clamp(0, 100); + ui.set_percent_value(percent_value); + // Icon glyph: CLI overrides config fallback let icon_glyph = args .icon @@ -73,37 +136,5 @@ fn set_ui_props( .unwrap_or(cfg.icon.default_icon.as_str()); ui.set_icon_glyph(SharedString::from(icon_glyph)); - - Ok(()) -} - -/// Create and display the OSD popup window. -/// Loads config, applies X11 window attributes, sets UI props, and runs the Slint event loop. -pub fn show_popup(args: &OsdArgs) -> Result<(), Box> { - // Load configs. - let cfg = PopcornConfig::load_or_default(); - - // Configure X11 window attributes before Slint creates the window. - let window_attrs = |attrs: WindowAttributes| { - attrs - // Present the window as a dock so most WMs avoid decorations and normal window rules. - .with_x11_window_type(vec![WindowType::Dock]) - // Make the window unmanaged. This prevents tiling WMs from reserving space or moving it. - .with_override_redirect(true) - }; - - // Build and activate backend with X11 window-attribute hook. - let backend = Backend::builder() - .with_window_attributes_hook(window_attrs) - .build()?; - slint::platform::set_platform(Box::new(backend))?; - - // Build UI and apply all properties - let ui = OSDpopup::new()?; - set_ui_props(&ui, &cfg, args)?; - - // Run! - ui.run()?; - Ok(()) } diff --git a/crates/popcorn/src/main.rs b/crates/popcorn/src/main.rs index 69289d7..ab05d7f 100644 --- a/crates/popcorn/src/main.rs +++ b/crates/popcorn/src/main.rs @@ -8,5 +8,4 @@ fn main() { let parsed_args: OsdArgs = cli.into(); // Communicate with daemon - }