diff options
Diffstat (limited to 'src/window/mod.rs')
| -rw-r--r-- | src/window/mod.rs | 107 |
1 files changed, 106 insertions, 1 deletions
diff --git a/src/window/mod.rs b/src/window/mod.rs index 124a62f3..25b3531f 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -1,3 +1,9 @@ +use niri_config::{Match, WindowRule}; +use smithay::wayland::compositor::with_states; +use smithay::wayland::shell::xdg::{ + ToplevelSurface, XdgToplevelSurfaceData, XdgToplevelSurfaceRoleAttributes, +}; + use crate::layout::workspace::ColumnWidth; pub mod mapped; @@ -7,7 +13,7 @@ pub mod unmapped; pub use unmapped::{InitialConfigureState, Unmapped}; /// Rules fully resolved for a window. -#[derive(Debug, Default)] +#[derive(Debug, Default, PartialEq)] pub struct ResolvedWindowRules { /// Default width for this window. /// @@ -24,4 +30,103 @@ pub struct ResolvedWindowRules { /// Whether the window should open fullscreen. pub open_fullscreen: Option<bool>, + + /// Extra bound on the minimum window width. + pub min_width: Option<u16>, + /// Extra bound on the minimum window height. + pub min_height: Option<u16>, + /// Extra bound on the maximum window width. + pub max_width: Option<u16>, + /// Extra bound on the maximum window height. + pub max_height: Option<u16>, +} + +impl ResolvedWindowRules { + pub fn compute(rules: &[WindowRule], toplevel: &ToplevelSurface) -> Self { + let _span = tracy_client::span!("ResolvedWindowRules::compute"); + + let mut resolved = ResolvedWindowRules::default(); + + with_states(toplevel.wl_surface(), |states| { + let role = states + .data_map + .get::<XdgToplevelSurfaceData>() + .unwrap() + .lock() + .unwrap(); + + let mut open_on_output = None; + + for rule in rules { + if !(rule.matches.is_empty() + || rule.matches.iter().any(|m| window_matches(&role, m))) + { + continue; + } + + if rule.excludes.iter().any(|m| window_matches(&role, m)) { + continue; + } + + if let Some(x) = rule + .default_column_width + .as_ref() + .map(|d| d.0.map(ColumnWidth::from)) + { + resolved.default_width = Some(x); + } + + if let Some(x) = rule.open_on_output.as_deref() { + open_on_output = Some(x); + } + + if let Some(x) = rule.open_maximized { + resolved.open_maximized = Some(x); + } + + if let Some(x) = rule.open_fullscreen { + resolved.open_fullscreen = Some(x); + } + + if let Some(x) = rule.min_width { + resolved.min_width = Some(x); + } + if let Some(x) = rule.min_height { + resolved.min_height = Some(x); + } + if let Some(x) = rule.max_width { + resolved.max_width = Some(x); + } + if let Some(x) = rule.max_height { + resolved.max_height = Some(x); + } + } + + resolved.open_on_output = open_on_output.map(|x| x.to_owned()); + }); + + resolved + } +} + +fn window_matches(role: &XdgToplevelSurfaceRoleAttributes, m: &Match) -> bool { + if let Some(app_id_re) = &m.app_id { + let Some(app_id) = &role.app_id else { + return false; + }; + if !app_id_re.is_match(app_id) { + return false; + } + } + + if let Some(title_re) = &m.title { + let Some(title) = &role.title else { + return false; + }; + if !title_re.is_match(title) { + return false; + } + } + + true } |
