diff --git a/src/config/backend_window_options.rs b/src/config/backend_window_options.rs new file mode 100644 index 0000000..99918cd --- /dev/null +++ b/src/config/backend_window_options.rs @@ -0,0 +1,123 @@ +use std::str::FromStr; + +use anyhow::*; + +use crate::{ + enum_parse, + error::AstResult, + parser::{ + ast::{Ast, AstIterator, Span}, + from_ast::FromAstElementContent, + }, + value::NumWithUnit, +}; + +use super::{attributes::Attributes, window_definition::EnumParseError}; + +pub type BackendWindowOptions = X11WindowOptions; + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)] +pub struct X11WindowOptions { + pub wm_ignore: bool, + pub sticky: bool, + pub window_type: EwwWindowType, + pub struts: StrutDefinition, +} + +impl X11WindowOptions { + pub fn from_attrs(attrs: &mut Attributes) -> AstResult { + let struts = attrs.ast_optional("reserve")?; + let window_type = attrs.primitive_optional("windowtype")?; + Ok(X11WindowOptions { + wm_ignore: attrs.primitive_optional("wm-ignore")?.unwrap_or(window_type.is_none() && struts.is_none()), + window_type: window_type.unwrap_or_default(), + sticky: attrs.primitive_optional("sticky")?.unwrap_or(true), + struts: struts.unwrap_or_default(), + }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, smart_default::SmartDefault, serde::Serialize)] +pub enum EwwWindowType { + #[default] + Dock, + Dialog, + Toolbar, + Normal, + Utility, +} +impl FromStr for EwwWindowType { + type Err = EnumParseError; + + fn from_str(s: &str) -> Result { + enum_parse! { "window type", s, + "dock" => Self::Dock, + "toolbar" => Self::Toolbar, + "dialog" => Self::Dialog, + "normal" => Self::Normal, + "utility" => Self::Utility, + } + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, smart_default::SmartDefault, serde::Serialize)] +pub enum Side { + #[default] + Top, + Left, + Right, + Bottom, +} + +impl std::str::FromStr for Side { + type Err = EnumParseError; + + fn from_str(s: &str) -> Result { + enum_parse! { "side", s, + "l" | "left" => Side::Left, + "r" | "right" => Side::Right, + "t" | "top" => Side::Top, + "b" | "bottom" => Side::Bottom, + } + } +} + +// Surface definition if the backend for X11 is enable +#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, serde::Serialize)] +pub struct StrutDefinition { + pub side: Side, + pub dist: NumWithUnit, +} + +impl FromAstElementContent for StrutDefinition { + fn get_element_name() -> &'static str { + "struts" + } + + fn from_tail>(span: Span, mut iter: AstIterator) -> AstResult { + let mut attrs = iter.expect_key_values()?; + Ok(StrutDefinition { side: attrs.primitive_required("side")?, dist: attrs.primitive_required("distance")? }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)] +pub struct WaylandWindowOptions { + pub exclusive: bool, + pub focusable: bool, +} +impl WaylandWindowOptions { + pub fn from_attrs(attrs: &mut Attributes) -> AstResult { + Ok(WaylandWindowOptions { + exclusive: attrs.primitive_optional("exclusive")?.unwrap_or(false), + focusable: attrs.primitive_optional("focusable")?.unwrap_or(false), + }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)] +pub struct NoBackendWindowOptions; +impl NoBackendWindowOptions { + pub fn from_attrs(attrs: &mut Attributes) -> Result { + Ok(NoBackendWindowOptions) + } +} diff --git a/src/config/config.rs b/src/config/config.rs index b86b28f..8cd5f7c 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -4,7 +4,7 @@ use simplexpr::SimplExpr; use super::{ script_var_definition::ScriptVarDefinition, var_definition::VarDefinition, widget_definition::WidgetDefinition, - widget_use::WidgetUse, + widget_use::WidgetUse, window_definition::WindowDefinition, }; use crate::{ config::script_var_definition::{PollScriptVar, TailScriptVar}, @@ -21,6 +21,7 @@ pub enum TopLevel { VarDefinition(VarDefinition), ScriptVarDefinition(ScriptVarDefinition), WidgetDefinition(WidgetDefinition), + WindowDefinition(WindowDefinition), } impl FromAst for TopLevel { @@ -40,6 +41,9 @@ impl FromAst for TopLevel { x if x == TailScriptVar::get_element_name() => { Self::ScriptVarDefinition(ScriptVarDefinition::Tail(TailScriptVar::from_tail(span, iter)?)) } + x if x == WindowDefinition::get_element_name() => { + Self::WindowDefinition(WindowDefinition::from_tail(span, iter)?) + } x => return Err(AstError::UnknownToplevel(Some(sym_span), x.to_string())), } }) @@ -49,6 +53,7 @@ impl FromAst for TopLevel { #[derive(Debug, PartialEq, Eq, Clone, serde::Serialize)] pub struct Config { widget_definitions: HashMap, + window_definitions: HashMap, var_definitions: HashMap, script_vars: HashMap, } @@ -56,8 +61,12 @@ pub struct Config { impl FromAst for Config { fn from_ast(e: Ast) -> AstResult { let list = e.as_list()?; - let mut config = - Self { widget_definitions: HashMap::new(), var_definitions: HashMap::new(), script_vars: HashMap::new() }; + let mut config = Self { + widget_definitions: HashMap::new(), + window_definitions: HashMap::new(), + var_definitions: HashMap::new(), + script_vars: HashMap::new(), + }; for element in list { match TopLevel::from_ast(element)? { TopLevel::VarDefinition(x) => { @@ -69,6 +78,9 @@ impl FromAst for Config { TopLevel::WidgetDefinition(x) => { config.widget_definitions.insert(x.name.clone(), x); } + TopLevel::WindowDefinition(x) => { + config.window_definitions.insert(x.name.clone(), x); + } } } Ok(config) diff --git a/src/config/mod.rs b/src/config/mod.rs index 03d20a8..2b3a558 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,4 +1,5 @@ pub mod attributes; +pub mod backend_window_options; mod config; pub mod config_parse_error; pub mod script_var_definition; diff --git a/src/config/snapshots/eww_config__config__test__config.snap b/src/config/snapshots/eww_config__config__test__config.snap index d7ba933..4316d36 100644 --- a/src/config/snapshots/eww_config__config__test__config.snap +++ b/src/config/snapshots/eww_config__config__test__config.snap @@ -13,9 +13,15 @@ Config( ], widget: WidgetUse( name: "text", - attrs: { - AttrName("text"): Literal(Span(99, 104, 0), DynVal("bla", None)), - }, + attrs: Attributes( + span: Span(99, 104, 0), + attrs: { + AttrName("text"): AttrEntry( + key_span: Span(99, 104, 0), + value: Literal(Span(99, 104, 0), DynVal("bla", None)), + ), + }, + ), children: [], span: Span(99, 104, 0), ), @@ -29,9 +35,15 @@ Config( ], widget: WidgetUse( name: "text", - attrs: { - AttrName("text"): Literal(Span(44, 51, 0), DynVal("heyho", None)), - }, + attrs: Attributes( + span: Span(44, 51, 0), + attrs: { + AttrName("text"): AttrEntry( + key_span: Span(44, 51, 0), + value: Literal(Span(44, 51, 0), DynVal("heyho", None)), + ), + }, + ), children: [], span: Span(44, 51, 0), ), @@ -39,6 +51,51 @@ Config( args_span: Span(26, 31, 0), ), }, + window_definitions: { + "some-window": WindowDefinition( + name: "some-window", + geometry: Some(WindowGeometry( + anchor_point: AnchorPoint( + x: START, + y: START, + ), + offset: Coords( + x: Pixels(0), + y: Pixels(0), + ), + size: Coords( + x: Percent(12), + y: Pixels(20), + ), + )), + stacking: Foreground, + monitor_number: Some(12), + widget: WidgetUse( + name: "foo", + attrs: Attributes( + span: Span(509, 509, 513), + attrs: { + AttrName("arg"): AttrEntry( + key_span: Span(514, 518, 0), + value: Literal(Span(519, 524, 0), DynVal("bla", None)), + ), + }, + ), + children: [], + span: Span(509, 525, 0), + ), + resizable: true, + backend_options: X11WindowOptions( + wm_ignore: false, + sticky: true, + window_type: Dock, + struts: StrutDefinition( + side: Left, + dist: Pixels(30), + ), + ), + ), + }, var_definitions: { VarName("some_var"): VarDefinition( name: VarName("some_var"), diff --git a/src/config/test.rs b/src/config/test.rs index 593a683..bd34c77 100644 --- a/src/config/test.rs +++ b/src/config/test.rs @@ -18,6 +18,13 @@ fn test_config() { (defvar some_var "bla") (defpollvar stuff :interval "12s" "date") (deftailvar stuff "tail -f stuff") + (defwindow some-window + :stacking "fg" + :monitor 12 + :resizable true + :geometry (geometry :width "12%" :height "20px") + :reserve (struts :side "left" :distance "30px") + (foo :arg "bla")) "#; let lexer = Lexer::new(0, input.to_string()); diff --git a/src/config/window_definition.rs b/src/config/window_definition.rs index b19fb9c..bc792b8 100644 --- a/src/config/window_definition.rs +++ b/src/config/window_definition.rs @@ -12,20 +12,20 @@ use crate::{ value::{AttrName, NumWithUnit, VarName}, }; -use super::{widget_use::WidgetUse, window_geometry::WindowGeometry}; +use super::{backend_window_options::BackendWindowOptions, widget_use::WidgetUse, window_geometry::WindowGeometry}; -#[derive(Debug, Clone, serde::Serialize)] -pub struct EwwWindowDefinition { +#[derive(Debug, Clone, serde::Serialize, PartialEq, Eq)] +pub struct WindowDefinition { pub name: String, pub geometry: Option, pub stacking: WindowStacking, pub monitor_number: Option, pub widget: WidgetUse, pub resizable: bool, - // pub backend_options: BackendWindowOptions, + pub backend_options: BackendWindowOptions, } -impl FromAstElementContent for EwwWindowDefinition { +impl FromAstElementContent for WindowDefinition { fn get_element_name() -> &'static str { "defwindow" } @@ -37,8 +37,9 @@ impl FromAstElementContent for EwwWindowDefinition { 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")?; + let backend_options = BackendWindowOptions::from_attrs(&mut attrs)?; let widget = iter.expect_any()?; - Ok(Self { name, monitor_number, resizable, widget, stacking, geometry }) + Ok(Self { name, monitor_number, resizable, widget, stacking, geometry, backend_options }) } } @@ -76,69 +77,6 @@ macro_rules! enum_parse { }; } -#[derive(Debug, Clone, PartialEq, Eq, smart_default::SmartDefault)] -pub enum EwwWindowType { - #[default] - Dock, - Dialog, - Toolbar, - Normal, - Utility, -} -impl FromStr for EwwWindowType { - type Err = EnumParseError; - - fn from_str(s: &str) -> Result { - enum_parse! { "window type", s, - "dock" => Self::Dock, - "toolbar" => Self::Toolbar, - "dialog" => Self::Dialog, - "normal" => Self::Normal, - "utility" => Self::Utility, - } - } -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq, smart_default::SmartDefault)] -pub enum Side { - #[default] - Top, - Left, - Right, - Bottom, -} - -impl std::str::FromStr for Side { - type Err = EnumParseError; - - fn from_str(s: &str) -> Result { - enum_parse! { "side", s, - "l" | "left" => Side::Left, - "r" | "right" => Side::Right, - "t" | "top" => Side::Top, - "b" | "bottom" => Side::Bottom, - } - } -} - -// Surface definition if the backend for X11 is enable -#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] -pub struct StrutDefinition { - pub side: Side, - pub dist: NumWithUnit, -} - -impl FromAstElementContent for StrutDefinition { - fn get_element_name() -> &'static str { - "struts" - } - - fn from_tail>(span: Span, mut iter: AstIterator) -> AstResult { - let mut attrs = iter.expect_key_values()?; - Ok(StrutDefinition { side: attrs.primitive_required("side")?, dist: attrs.primitive_required("distance")? }) - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display, smart_default::SmartDefault, serde::Serialize)] pub enum WindowStacking { #[default]