diff --git a/crates/eww/src/app.rs b/crates/eww/src/app.rs index 67550619..4cbb0957 100644 --- a/crates/eww/src/app.rs +++ b/crates/eww/src/app.rs @@ -7,27 +7,26 @@ use crate::{ paths::EwwPaths, script_var_handler::ScriptVarHandlerHandle, state::scope_graph::{ScopeGraph, ScopeIndex}, - *, + window_arguments::WindowArguments, + *, window_initiator::WindowInitiator, }; use anyhow::anyhow; use codespan_reporting::files::Files; -use eww_shared_util::{AttrName, Span, VarName}; +use eww_shared_util::{Span, VarName}; use glib::ObjectExt; use itertools::Itertools; use once_cell::sync::Lazy; -use simplexpr::{dynval::DynVal, SimplExpr}; +use simplexpr::dynval::DynVal; use std::{ cell::RefCell, collections::{HashMap, HashSet}, rc::Rc, - str::FromStr, }; use tokio::sync::mpsc::UnboundedSender; use yuck::{ config::{ monitor::MonitorIdentifier, script_var_definition::ScriptVarDefinition, - window_definition::WindowDefinition, window_geometry::{AnchorPoint, WindowGeometry}, }, error::DiagError, @@ -80,104 +79,6 @@ pub enum DaemonCommand { PrintWindows(DaemonResponseSender), } -#[derive(Debug, Clone)] -pub struct WindowInitiator { - pub config_name: String, - pub pos: Option, - pub size: Option, - pub monitor: Option, - pub anchor: Option, - pub args: Vec<(VarName, DynVal)>, -} - -impl WindowInitiator { - pub fn new( - config_name: String, - pos: Option, - size: Option, - monitor: Option, - anchor: Option, - args: Vec<(VarName, DynVal)>, - ) -> Self { - WindowInitiator { config_name, pos, size, monitor, anchor, args } - } - - pub fn new_from_args(config_name: String, mut args: Vec<(VarName, DynVal)>) -> Result { - let initiator = WindowInitiator { - config_name, - pos: WindowInitiator::extract_value_from_args::("pos", &mut args)?, - size: WindowInitiator::extract_value_from_args::("size", &mut args)?, - monitor: WindowInitiator::extract_value_from_args::("screen", &mut args)?, - anchor: WindowInitiator::extract_value_from_args::("anchor", &mut args)?, - args, - }; - - Ok(initiator) - } - - pub fn extract_value_from_args(name: &str, args: &mut Vec<(VarName, DynVal)>) -> Result, T::Err> { - let var_name = name.to_string(); - let pos = args.iter().position(|(n, _)| n.0 == var_name); - - if pos.is_some() { - let (_, val) = args.remove(pos.unwrap()); - let converted_val = T::from_str(&val.0)?; - Ok(Some(converted_val)) - } else { - Ok(None) - } - } - - pub fn get_local_window_variables(&self, id: &str, window_def: &WindowDefinition) -> Result> { - let expected_args: HashSet<&String> = window_def.expected_args.iter().map(|x| &x.name.0).collect(); - let mut local_variables: HashMap = HashMap::new(); - - // Inserts these first so they can be overridden - if expected_args.contains(&"id".to_string()) { - local_variables.insert(VarName::from("id"), DynVal::from(id)); - } - if self.monitor.is_some() && expected_args.contains(&"screen".to_string()) { - let mon_dyn = match self.monitor.clone().unwrap() { - MonitorIdentifier::Numeric(x) => DynVal::from(x), - MonitorIdentifier::Name(x) => DynVal::from(x), - }; - local_variables.insert(VarName::from("screen"), mon_dyn); - } - - local_variables.extend(self.args.clone().into_iter()); - - for attr in &window_def.expected_args { - let name = VarName::from(attr.name.clone()); - if !local_variables.contains_key(&name) { - if attr.optional { - local_variables.insert(name, DynVal::from(String::new())); - } else { - return Err(anyhow!( - "Error, {} was required when creating {} but was not given", - attr.name, - self.config_name - )); - } - } - } - - if local_variables.len() != window_def.expected_args.len() { - let unexpected_vars: Vec = local_variables - .iter() - .filter_map(|(n, _)| if !expected_args.contains(&n.0) { Some(n.clone()) } else { None }) - .collect(); - return Err(anyhow!( - "'{}' {} unexpectedly defined when creating window {}", - unexpected_vars.join(","), - if unexpected_vars.len() == 1 { "was" } else { "were" }, - self.config_name - )); - } - - Ok(local_variables) - } -} - /// An opened window. #[derive(Debug)] pub struct EwwWindow { @@ -208,7 +109,7 @@ pub struct App { pub eww_config: config::EwwConfig, /// Map of all currently open windows pub open_windows: HashMap, - pub window_initiators: HashMap, + pub window_argumentss: HashMap, /// Window names that are supposed to be open, but failed. /// When reloading the config, these should be opened again. pub failed_windows: HashSet, @@ -228,7 +129,7 @@ impl std::fmt::Debug for App { .field("eww_config", &self.eww_config) .field("open_windows", &self.open_windows) .field("failed_windows", &self.failed_windows) - .field("window_initiators", &self.window_initiators) + .field("window_argumentss", &self.window_argumentss) .field("paths", &self.paths) .finish() } @@ -291,14 +192,14 @@ impl App { let window_args: Vec<(VarName, DynVal)> = args.iter() .filter_map(|(win_id, n, v)| { - if win_id == "" || win_id == id { + if win_id.is_empty() || win_id == id { Some((n.clone(), v.clone())) } else { None } }) .collect(); - self.open_window(id, &WindowInitiator::new_from_args(config_name.clone(), window_args)?) + self.open_window(&WindowArguments::new_from_args(id.to_string(), config_name.clone(), window_args)?) } }) .filter_map(Result::err); @@ -315,14 +216,13 @@ impl App { sender, args, } => { - let id = instance_id.unwrap_or(window_name.clone()); + let id = instance_id.unwrap_or_else(|| window_name.clone()); let is_open = self.open_windows.contains_key(&id); let result = if !is_open { self.open_window( - &id, - &WindowInitiator::new(window_name, pos, size, monitor, anchor, args.unwrap_or(Vec::new())), + &WindowArguments::new(id, window_name, pos, size, monitor, anchor, args.unwrap_or_default()), ) } else if should_toggle { self.close_window(&id) @@ -443,31 +343,30 @@ impl App { self.script_var_handler.stop_for_variable(unused_var.clone()); } - self.window_initiators.remove(instance_id); + self.window_argumentss.remove(instance_id); Ok(()) } - fn open_window(&mut self, instance_id: &str, initiator: &WindowInitiator) -> Result<()> { + fn open_window(&mut self, window_args: &WindowArguments) -> Result<()> { + let instance_id = &window_args.id; self.failed_windows.remove(instance_id); - log::info!("Opening window {} as '{}'", initiator.config_name, instance_id); + log::info!("Opening window {} as '{}'", window_args.config_name, instance_id); // if an instance of this is already running, close it if self.open_windows.contains_key(instance_id) { self.close_window(instance_id)?; } - self.window_initiators.insert(instance_id.to_string(), initiator.clone()); + self.window_argumentss.insert(instance_id.to_string(), window_args.clone()); let open_result: Result<_> = try { - let window_name: &str = &initiator.config_name; + let window_name: &str = &window_args.config_name; - let mut window_def = self.eww_config.get_window(window_name)?.clone(); + let window_def = self.eww_config.get_window(window_name)?.clone(); assert_eq!(window_def.name, window_name, "window definition name did not equal the called window"); - window_def.geometry = - window_def.geometry.map(|x| x.override_if_given(initiator.anchor, initiator.pos, initiator.size)); - let local_variables = initiator.get_local_window_variables(instance_id, &window_def)?; + let initiator = WindowInitiator::new(&window_def, window_args)?; let root_index = self.scope_graph.borrow().root_index; @@ -475,24 +374,22 @@ impl App { window_name.to_string(), Some(root_index), root_index, - local_variables.iter().map(|(k, v)| (AttrName::from(k.clone()), SimplExpr::Literal(v.clone()))).collect(), + initiator.get_scoped_vars(), )?; let root_widget = crate::widgets::build_widget::build_gtk_widget( &mut self.scope_graph.borrow_mut(), Rc::new(self.eww_config.get_widget_definitions().clone()), window_scope, - window_def.widget.clone(), + window_def.widget, None, )?; - root_widget.style_context().add_class(&window_name.to_string()); + root_widget.style_context().add_class(window_name); - let monitor = initiator.monitor.clone().or(window_def.get_monitor(&local_variables)?); - - let monitor_geometry = get_monitor_geometry(monitor.clone())?; - let mut eww_window = initialize_window::(instance_id, monitor_geometry, root_widget, window_def, window_scope)?; - eww_window.gtk_window.style_context().add_class(&window_name.to_string()); + let monitor_geometry = get_monitor_geometry(initiator.monitor.clone())?; + let mut eww_window = initialize_window::(&initiator, monitor_geometry, root_widget, window_scope)?; + eww_window.gtk_window.style_context().add_class(window_name); // initialize script var handlers for variables. As starting a scriptvar with the script_var_handler is idempodent, // we can just start script vars that are already running without causing issues @@ -544,17 +441,17 @@ impl App { let instances: Vec = self.open_windows.keys().cloned().chain(self.failed_windows.iter().cloned()).dedup().collect(); - let initiators = self.window_initiators.clone(); + let initiators = self.window_argumentss.clone(); for instance_id in &instances { - let window_initiator; + let window_arguments; match initiators.get(instance_id) { - Some(x) => window_initiator = x, + Some(x) => window_arguments = x, None => { return Err(anyhow!("Cannot reopen window, initial parameters were not saved correctly for {}", instance_id)) } }; - self.open_window(instance_id, window_initiator)?; + self.open_window(window_arguments)?; } Ok(()) } @@ -583,20 +480,24 @@ impl App { } fn initialize_window( - instance_id: &str, + window_init: &WindowInitiator, monitor_geometry: gdk::Rectangle, root_widget: gtk::Widget, - window_def: WindowDefinition, window_scope: ScopeIndex, ) -> Result { - let window = B::initialize_window(&window_def, monitor_geometry) - .with_context(|| format!("monitor {} is unavailable", window_def.monitor.clone().unwrap()))?; - - window.set_title(&format!("Eww - {}", window_def.name)); + let window = B::initialize_window(window_init, monitor_geometry) + .with_context( + || format!( + "monitor {} is unavailable", + window_init.monitor.clone().unwrap() + ) + )?; + + window.set_title(&format!("Eww - {}", window_init.name)); window.set_position(gtk::WindowPosition::None); window.set_gravity(gdk::Gravity::Center); - if let Some(geometry) = window_def.geometry { + if let Some(geometry) = window_init.geometry { let actual_window_rect = get_window_rectangle(geometry, monitor_geometry); window.set_size_request(actual_window_rect.width(), actual_window_rect.height()); window.set_default_size(actual_window_rect.width(), actual_window_rect.height()); @@ -615,23 +516,23 @@ fn initialize_window( #[cfg(feature = "x11")] { - if let Some(geometry) = window_def.geometry { + if let Some(geometry) = window_init.geometry { let _ = apply_window_position(geometry, monitor_geometry, &window); - if window_def.backend_options.x11.window_type != yuck::config::backend_window_options::X11WindowType::Normal { + if window_init.backend_options.x11.window_type != yuck::config::backend_window_options::X11WindowType::Normal { window.connect_configure_event(move |window, _| { let _ = apply_window_position(geometry, monitor_geometry, window); false }); } } - display_backend::set_xprops(&window, monitor_geometry, &window_def)?; + display_backend::set_xprops(&window, monitor_geometry, window_init)?; } window.show_all(); Ok(EwwWindow { - instance_id: instance_id.to_string(), - name: window_def.name.clone(), + instance_id: window_init.id.clone(), + name: window_init.name.clone(), gtk_window: window, scope_index: window_scope, destroy_event_handler_id: None, diff --git a/crates/eww/src/display_backend.rs b/crates/eww/src/display_backend.rs index 834be571..325f30ac 100644 --- a/crates/eww/src/display_backend.rs +++ b/crates/eww/src/display_backend.rs @@ -1,4 +1,4 @@ -use yuck::config::window_definition::WindowDefinition; +use crate::window_initiator::WindowInitiator; #[cfg(feature = "wayland")] pub use platform_wayland::WaylandBackend; @@ -7,22 +7,23 @@ pub use platform_wayland::WaylandBackend; pub use platform_x11::{set_xprops, X11Backend}; pub trait DisplayBackend: Send + Sync + 'static { - fn initialize_window(window_def: &WindowDefinition, monitor: gdk::Rectangle) -> Option; + fn initialize_window(window_init: &WindowInitiator, monitor: gdk::Rectangle) -> Option; } pub struct NoBackend; impl DisplayBackend for NoBackend { - fn initialize_window(_window_def: &WindowDefinition, _monitor: gdk::Rectangle) -> Option { + fn initialize_window(_window_init: &WindowInitiator, _monitor: gdk::Rectangle) -> Option { Some(gtk::Window::new(gtk::WindowType::Toplevel)) } } #[cfg(feature = "wayland")] mod platform_wayland { + use crate::window_initiator::WindowInitiator; use gtk::prelude::*; use yuck::config::{ - window_definition::{WindowDefinition, WindowStacking}, + window_definition::WindowStacking, window_geometry::AnchorAlignment, }; @@ -31,12 +32,12 @@ mod platform_wayland { pub struct WaylandBackend; impl DisplayBackend for WaylandBackend { - fn initialize_window(window_def: &WindowDefinition, monitor: gdk::Rectangle) -> Option { + fn initialize_window(window_init: &WindowInitiator, monitor: gdk::Rectangle) -> Option { let window = gtk::Window::new(gtk::WindowType::Toplevel); // Initialising a layer shell surface gtk_layer_shell::init_for_window(&window); // Sets the monitor where the surface is shown - if let Some(ident) = window_def.monitor.clone() { + if let Some(ident) = window_init.monitor.clone() { let display = gdk::Display::default().expect("could not get default display"); if let Some(monitor) = crate::app::get_monitor_from_display(&display, &ident) { gtk_layer_shell::set_monitor(&window, &monitor); @@ -44,24 +45,24 @@ mod platform_wayland { return None; } }; - window.set_resizable(window_def.resizable); + window.set_resizable(window_init.resizable); // Sets the layer where the layer shell surface will spawn - match window_def.stacking { + match window_init.stacking { WindowStacking::Foreground => gtk_layer_shell::set_layer(&window, gtk_layer_shell::Layer::Top), WindowStacking::Background => gtk_layer_shell::set_layer(&window, gtk_layer_shell::Layer::Background), WindowStacking::Bottom => gtk_layer_shell::set_layer(&window, gtk_layer_shell::Layer::Bottom), WindowStacking::Overlay => gtk_layer_shell::set_layer(&window, gtk_layer_shell::Layer::Overlay), } - if let Some(namespace) = &window_def.backend_options.wayland.namespace { + if let Some(namespace) = &window_init.backend_options.wayland.namespace { gtk_layer_shell::set_namespace(&window, namespace); } // Sets the keyboard interactivity - gtk_layer_shell::set_keyboard_interactivity(&window, window_def.backend_options.wayland.focusable); + gtk_layer_shell::set_keyboard_interactivity(&window, window_init.backend_options.wayland.focusable); - if let Some(geometry) = window_def.geometry { + if let Some(geometry) = window_init.geometry { // Positioning surface let mut top = false; let mut left = false; @@ -98,7 +99,7 @@ mod platform_wayland { gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Top, yoffset); } } - if window_def.backend_options.wayland.exclusive { + if window_init.backend_options.wayland.exclusive { gtk_layer_shell::auto_exclusive_zone_enable(&window); } Some(window) @@ -108,6 +109,7 @@ mod platform_wayland { #[cfg(feature = "x11")] mod platform_x11 { + use crate::window_initiator::WindowInitiator; use anyhow::{Context, Result}; use gtk::{self, prelude::*}; use x11rb::protocol::xproto::ConnectionExt; @@ -120,24 +122,24 @@ mod platform_x11 { }; use yuck::config::{ backend_window_options::{Side, X11WindowType}, - window_definition::{WindowDefinition, WindowStacking}, + window_definition::WindowStacking, }; use super::DisplayBackend; pub struct X11Backend; impl DisplayBackend for X11Backend { - fn initialize_window(window_def: &WindowDefinition, _monitor: gdk::Rectangle) -> Option { + fn initialize_window(window_init: &WindowInitiator, _monitor: gdk::Rectangle) -> Option { let window_type = - if window_def.backend_options.x11.wm_ignore { gtk::WindowType::Popup } else { gtk::WindowType::Toplevel }; + if window_init.backend_options.x11.wm_ignore { gtk::WindowType::Popup } else { gtk::WindowType::Toplevel }; let window = gtk::Window::new(window_type); - let wm_class_name = format!("eww-{}", window_def.name); + let wm_class_name = format!("eww-{}", window_init.name); #[allow(deprecated)] window.set_wmclass(&wm_class_name, &wm_class_name); - window.set_resizable(window_def.resizable); - window.set_keep_above(window_def.stacking == WindowStacking::Foreground); - window.set_keep_below(window_def.stacking == WindowStacking::Background); - if window_def.backend_options.x11.sticky { + window.set_resizable(window_init.resizable); + window.set_keep_above(window_init.stacking == WindowStacking::Foreground); + window.set_keep_below(window_init.stacking == WindowStacking::Background); + if window_init.backend_options.x11.sticky { window.stick(); } else { window.unstick(); @@ -146,9 +148,9 @@ mod platform_x11 { } } - pub fn set_xprops(window: >k::Window, monitor: gdk::Rectangle, window_def: &WindowDefinition) -> Result<()> { + pub fn set_xprops(window: >k::Window, monitor: gdk::Rectangle, window_init: &WindowInitiator) -> Result<()> { let backend = X11BackendConnection::new()?; - backend.set_xprops_for(window, monitor, window_def)?; + backend.set_xprops_for(window, monitor, window_init)?; Ok(()) } @@ -170,12 +172,12 @@ mod platform_x11 { &self, window: >k::Window, monitor_rect: gdk::Rectangle, - window_def: &WindowDefinition, + window_init: &WindowInitiator, ) -> Result<()> { let gdk_window = window.window().context("Couldn't get gdk window from gtk window")?; let win_id = gdk_window.downcast_ref::().context("Failed to get x11 window for gtk window")?.xid() as u32; - let strut_def = window_def.backend_options.x11.struts; + let strut_def = window_init.backend_options.x11.struts; let root_window_geometry = self.conn.get_geometry(self.root_window)?.reply()?; let mon_end_x = (monitor_rect.x() + monitor_rect.width()) as u32 - 1u32; @@ -229,7 +231,7 @@ mod platform_x11 { win_id, self.atoms._NET_WM_WINDOW_TYPE, self.atoms.ATOM, - &[match window_def.backend_options.x11.window_type { + &[match window_init.backend_options.x11.window_type { X11WindowType::Dock => self.atoms._NET_WM_WINDOW_TYPE_DOCK, X11WindowType::Normal => self.atoms._NET_WM_WINDOW_TYPE_NORMAL, X11WindowType::Dialog => self.atoms._NET_WM_WINDOW_TYPE_DIALOG, diff --git a/crates/eww/src/main.rs b/crates/eww/src/main.rs index 1e61c3bf..8781a708 100644 --- a/crates/eww/src/main.rs +++ b/crates/eww/src/main.rs @@ -36,6 +36,8 @@ mod server; mod state; mod util; mod widgets; +mod window_arguments; +mod window_initiator; fn main() { let eww_binary_name = std::env::args().next().unwrap(); diff --git a/crates/eww/src/server.rs b/crates/eww/src/server.rs index 305b7ccb..2cabadbf 100644 --- a/crates/eww/src/server.rs +++ b/crates/eww/src/server.rs @@ -81,7 +81,7 @@ pub fn initialize_server( eww_config, open_windows: HashMap::new(), failed_windows: HashSet::new(), - window_initiators: HashMap::new(), + window_argumentss: HashMap::new(), css_provider: gtk::CssProvider::new(), script_var_handler, app_evt_send: ui_send.clone(), diff --git a/crates/eww/src/window_arguments.rs b/crates/eww/src/window_arguments.rs new file mode 100644 index 00000000..9250cea9 --- /dev/null +++ b/crates/eww/src/window_arguments.rs @@ -0,0 +1,124 @@ +use anyhow::{anyhow, Result}; +use eww_shared_util::VarName; +use simplexpr::dynval::DynVal; +use std::{ + collections::{HashMap, HashSet}, + str::FromStr, +}; +use yuck::{ + config::{ + monitor::MonitorIdentifier, + window_definition::WindowDefinition, + window_geometry::AnchorPoint, + }, + value::Coords, +}; + +/// This stores the arguments given in the command line to create a window +/// While creating a window, we combine this with information from the +/// WindowDefinition to create a WindowInitiator, which stores all the +/// information required to start a window +#[derive(Debug, Clone)] +pub struct WindowArguments { + pub anchor: Option, + pub args: Vec<(VarName, DynVal)>, + pub config_name: String, + pub id: String, + pub monitor: Option, + pub pos: Option, + pub size: Option, +} + +impl WindowArguments { + pub fn new( + id: String, + config_name: String, + pos: Option, + size: Option, + monitor: Option, + anchor: Option, + args: Vec<(VarName, DynVal)>, + ) -> Self { + WindowArguments { id, config_name, pos, size, monitor, anchor, args } + } + + pub fn new_from_args(id: String, config_name: String, mut args: Vec<(VarName, DynVal)>) -> Result { + let initiator = WindowArguments { + config_name, + id, + pos: WindowArguments::extract_value_from_args::("pos", &mut args)?, + size: WindowArguments::extract_value_from_args::("size", &mut args)?, + monitor: WindowArguments::extract_value_from_args::("screen", &mut args)?, + anchor: WindowArguments::extract_value_from_args::("anchor", &mut args)?, + args, + }; + + Ok(initiator) + } + + pub fn extract_value_from_args(name: &str, args: &mut Vec<(VarName, DynVal)>) -> Result, T::Err> { + let var_name = name.to_string(); + let pos = args.iter().position(|(n, _)| n.0 == var_name); + + if let Some(unwrapped_pos) = pos { + let (_, val) = args.remove(unwrapped_pos); + let converted_val = T::from_str(&val.0)?; + Ok(Some(converted_val)) + } else { + Ok(None) + } + } + + pub fn get_local_window_variables(&self, window_def: &WindowDefinition) -> Result> { + let expected_args: HashSet<&String> = window_def.expected_args.iter().map(|x| &x.name.0).collect(); + let mut local_variables: HashMap = HashMap::new(); + + // Inserts these first so they can be overridden + if expected_args.contains(&"id".to_string()) { + local_variables.insert(VarName::from("id"), DynVal::from(self.id.clone())); + } + if self.monitor.is_some() && expected_args.contains(&"screen".to_string()) { + let mon_dyn = match self.monitor.clone().unwrap() { + MonitorIdentifier::Numeric(x) => DynVal::from(x), + MonitorIdentifier::Name(x) => DynVal::from(x), + }; + local_variables.insert(VarName::from("screen"), mon_dyn); + } + + local_variables.extend(self.args.clone().into_iter()); + + for attr in &window_def.expected_args { + let name = VarName::from(attr.name.clone()); + + // This is here to get around the map_entry warning + let mut inserted = false; + local_variables.entry(name).or_insert_with(|| { + inserted = true; + DynVal::from_string(String::new()) + }); + + if inserted && !attr.optional { + return Err(anyhow!( + "Error, {} was required when creating {} but was not given", + attr.name, + self.config_name + )); + } + } + + if local_variables.len() != window_def.expected_args.len() { + let unexpected_vars: Vec = local_variables + .iter() + .filter_map(|(n, _)| if !expected_args.contains(&n.0) { Some(n.clone()) } else { None }) + .collect(); + return Err(anyhow!( + "'{}' {} unexpectedly defined when creating window {}", + unexpected_vars.join(","), + if unexpected_vars.len() == 1 { "was" } else { "were" }, + self.config_name + )); + } + + Ok(local_variables) + } +} diff --git a/crates/eww/src/window_initiator.rs b/crates/eww/src/window_initiator.rs new file mode 100644 index 00000000..61bba4cc --- /dev/null +++ b/crates/eww/src/window_initiator.rs @@ -0,0 +1,57 @@ +use anyhow::Result; +use eww_shared_util::{VarName, AttrName}; +use simplexpr::{dynval::DynVal, SimplExpr}; +use std::collections::HashMap; +use yuck::config::{ + monitor::MonitorIdentifier, + window_definition::{WindowDefinition, WindowStacking}, + window_geometry::WindowGeometry, backend_window_options::BackendWindowOptions, +}; + +use crate::window_arguments::WindowArguments; + +/// This stores all the information required to create a window and is created +/// via combining information from the WindowDefinition and the WindowInitiator +#[derive(Debug, Clone)] +pub struct WindowInitiator { + pub backend_options: BackendWindowOptions, + pub geometry: Option, + pub id: String, + pub local_variables: HashMap, + pub monitor: Option, + pub name: String, + pub resizable: bool, + pub stacking: WindowStacking, +} + +impl WindowInitiator { + pub fn new(window_def: &WindowDefinition, args: &WindowArguments) -> Result { + let vars = args.get_local_window_variables(window_def)?; + let geometry = window_def.geometry.map( + |x| x.override_if_given(args.anchor, args.pos, args.size) + ); + + let monitor = if args.monitor.is_none() { + window_def.get_monitor(&vars)? + } else { + args.monitor.clone() + }; + + Ok(WindowInitiator { + backend_options: window_def.backend_options.clone(), + geometry, + id: args.id.clone(), + local_variables: vars, + monitor, + name: window_def.name.clone(), + resizable: window_def.resizable, + stacking: window_def.stacking, + }) + } + + pub fn get_scoped_vars(&self) -> HashMap{ + self.local_variables.iter().map( + |(k, v)| (AttrName::from(k.clone()), SimplExpr::Literal(v.clone())) + ).collect() + } +} diff --git a/crates/yuck/src/config/window_definition.rs b/crates/yuck/src/config/window_definition.rs index 1616661b..b21b065b 100644 --- a/crates/yuck/src/config/window_definition.rs +++ b/crates/yuck/src/config/window_definition.rs @@ -1,4 +1,4 @@ -use std::fmt::Display; +use std::{collections::HashMap, fmt::Display}; use crate::{ config::monitor::MonitorIdentifier, @@ -10,7 +10,7 @@ use crate::{ }, }; use eww_shared_util::{Span, VarName}; -use simplexpr::eval::EvalError; +use simplexpr::{dynval::DynVal, eval::EvalError, SimplExpr}; use super::{ attributes::AttrSpec, backend_window_options::BackendWindowOptions, widget_use::WidgetUse, window_geometry::WindowGeometry,