diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b8ad175..f93a74ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ All notable changes to eww will be listed here, starting at changes since versio - Add trigonometric functions (`sin`, `cos`, `tan`, `cot`) and degree/radian conversions (`degtorad`, `radtodeg`) (By: end-4) - Add `substring` function to simplexpr - Add `--duration` flag to `eww open` +- Add support for referring to monitor with `` +- Add support for multiple matchers in `monitor` field ## [0.4.0] (04.09.2022) diff --git a/crates/eww/src/app.rs b/crates/eww/src/app.rs index 3b306be7..57cf1b1b 100644 --- a/crates/eww/src/app.rs +++ b/crates/eww/src/app.rs @@ -560,31 +560,16 @@ fn get_monitor_geometry(identifier: Option) -> Result { let mon = get_monitor_from_display(&display, &ident); - - #[cfg(feature = "x11")] - { - mon.with_context(|| { - let head = format!("Failed to get monitor {}\nThe available monitors are:", ident); - let mut body = String::new(); - for m in 0..display.n_monitors() { - if let Some(model) = display.monitor(m).and_then(|x| x.model()) { - body.push_str(format!("\n\t[{}] {}", m, model).as_str()); - } + mon.with_context(|| { + let head = format!("Failed to get monitor {}\nThe available monitors are:", ident); + let mut body = String::new(); + for m in 0..display.n_monitors() { + if let Some(model) = display.monitor(m).and_then(|x| x.model()) { + body.push_str(format!("\n\t[{}] {}", m, model).as_str()); } - format!("{}{}", head, body) - })? - } - - #[cfg(not(feature = "x11"))] - { - mon.with_context(|| { - if ident.is_numeric() { - format!("Failed to get monitor {}", ident) - } else { - format!("Using ouput names (\"{}\" in the configuration) is not supported outside of x11 yet", ident) - } - })? - } + } + format!("{}{}", head, body) + })? } None => display .primary_monitor() @@ -597,12 +582,16 @@ fn get_monitor_geometry(identifier: Option) -> Result Option { match identifier { + MonitorIdentifier::List(list) => { + for ident in list { + if let Some(monitor) = get_monitor_from_display(display, ident) { + return Some(monitor); + } + } + None + } + MonitorIdentifier::Primary => display.primary_monitor(), MonitorIdentifier::Numeric(num) => display.monitor(*num), - - #[cfg(not(feature = "x11"))] - MonitorIdentifier::Name(_) => return None, - - #[cfg(feature = "x11")] MonitorIdentifier::Name(name) => { for m in 0..display.n_monitors() { if let Some(model) = display.monitor(m).and_then(|x| x.model()) { diff --git a/crates/yuck/src/config/monitor.rs b/crates/yuck/src/config/monitor.rs index 53d6a393..a6432912 100644 --- a/crates/yuck/src/config/monitor.rs +++ b/crates/yuck/src/config/monitor.rs @@ -5,8 +5,10 @@ use serde::{Deserialize, Serialize}; /// The type of the identifier used to select a monitor #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum MonitorIdentifier { + List(Vec), Numeric(i32), Name(String), + Primary, } impl MonitorIdentifier { @@ -18,8 +20,10 @@ impl MonitorIdentifier { impl fmt::Display for MonitorIdentifier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { + Self::List(l) => write!(f, "[{}]", l.iter().map(|x| x.to_string()).collect::>().join(" ")), Self::Numeric(n) => write!(f, "{}", n), Self::Name(n) => write!(f, "{}", n), + Self::Primary => write!(f, ""), } } } @@ -30,7 +34,13 @@ impl str::FromStr for MonitorIdentifier { fn from_str(s: &str) -> Result { match s.parse::() { Ok(n) => Ok(Self::Numeric(n)), - Err(_) => Ok(Self::Name(s.to_owned())), + Err(_) => { + if &s.to_lowercase() == "" { + Ok(Self::Primary) + } else { + Ok(Self::Name(s.to_owned())) + } + } } } } diff --git a/crates/yuck/src/config/window_definition.rs b/crates/yuck/src/config/window_definition.rs index afe3fd52..f62ed364 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::{fmt::Display, str::FromStr}; use crate::{ config::monitor::MonitorIdentifier, @@ -24,13 +24,22 @@ pub struct WindowDefinition { pub backend_options: BackendWindowOptions, } +impl FromAst for MonitorIdentifier { + fn from_ast(x: Ast) -> DiagResult { + match x { + Ast::Array(_, x) => Ok(Self::List(x.into_iter().map(MonitorIdentifier::from_ast).collect::>()?)), + other => Ok(Self::from_str(&String::from_ast(other)?).unwrap()), + } + } +} + impl FromAstElementContent for WindowDefinition { const ELEMENT_NAME: &'static str = "defwindow"; fn from_tail>(_span: Span, mut iter: AstIterator) -> DiagResult { let (_, name) = iter.expect_symbol()?; let mut attrs = iter.expect_key_values()?; - let monitor = attrs.primitive_optional("monitor")?; + let monitor = attrs.ast_optional::("monitor")?; let resizable = attrs.primitive_optional("resizable")?.unwrap_or(true); let stacking = attrs.primitive_optional("stacking")?.unwrap_or(WindowStacking::Foreground); let geometry = attrs.ast_optional("geometry")?; diff --git a/crates/yuck/src/parser/ast.rs b/crates/yuck/src/parser/ast.rs index d80d208f..5a901299 100644 --- a/crates/yuck/src/parser/ast.rs +++ b/crates/yuck/src/parser/ast.rs @@ -71,6 +71,8 @@ impl Ast { as_func!(AstType::List, as_list as_list_ref> = Ast::List(_, x) => x); + as_func!(AstType::Array, as_array as_array_ref> = Ast::Array(_, x) => x); + pub fn expr_type(&self) -> AstType { match self { Ast::List(..) => AstType::List, diff --git a/docs/src/configuration.md b/docs/src/configuration.md index af7397e8..975099b5 100644 --- a/docs/src/configuration.md +++ b/docs/src/configuration.md @@ -50,10 +50,20 @@ You can now open your first window by running `eww open example`! Glorious! | Property | Description | | ---------: | ------------------------------------------------------------ | -| `monitor` | Which monitor this window should be displayed on. Can be either a number (X11 and Wayland) or an output name (X11 only). | +| `monitor` | Which monitor this window should be displayed on. See below for details.| | `geometry` | Geometry of the window. | +**`monitor`-property** + +This field can be: + +- the string ``, in which case eww tries to identify the primary display (which may fail, especially on wayland) +- an integer, declaring the monitor index +- the name of the monitor +- an array of monitor matchers, such as: `["" "HDMI-A-1" "PHL 345B1C" 0]`. Eww will try to find a match in order, allowing you to specify fallbacks. + + **`geometry`-properties** | Property | Description |