From dcf57db3df51970e6244966bacbd06cbf887b113 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 1 May 2025 18:35:29 +0200 Subject: [PATCH] config: add visibility window criteria --- jay-config/src/_private.rs | 1 + jay-config/src/_private/client.rs | 1 + jay-config/src/window.rs | 2 ++ src/config/handler.rs | 1 + src/criteria/tlm.rs | 10 ++++++++++ src/criteria/tlm/tlm_matchers.rs | 1 + src/criteria/tlm/tlm_matchers/tlmm_visible.rs | 11 +++++++++++ src/tree/toplevel.rs | 6 ++++-- toml-config/src/config.rs | 1 + toml-config/src/config/parsers/window_match.rs | 4 +++- toml-config/src/rules.rs | 1 + toml-spec/spec/spec.generated.json | 4 ++++ toml-spec/spec/spec.generated.md | 6 ++++++ toml-spec/spec/spec.yaml | 4 ++++ 14 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/criteria/tlm/tlm_matchers/tlmm_visible.rs diff --git a/jay-config/src/_private.rs b/jay-config/src/_private.rs index 534531db..6d0c1293 100644 --- a/jay-config/src/_private.rs +++ b/jay-config/src/_private.rs @@ -111,6 +111,7 @@ pub enum WindowCriterionIpc { Types(WindowType), Client(ClientMatcher), Floating, + Visible, } #[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)] diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index a0288cac..5ab093bd 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -1658,6 +1658,7 @@ impl ConfigClient { WindowCriterion::AppId(t) => string!(t, AppId, false), WindowCriterion::AppIdRegex(t) => string!(t, AppId, true), WindowCriterion::Floating => WindowCriterionIpc::Floating, + WindowCriterion::Visible => WindowCriterionIpc::Visible, }; let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion }); get_response!( diff --git a/jay-config/src/window.rs b/jay-config/src/window.rs index cbada630..9415fed9 100644 --- a/jay-config/src/window.rs +++ b/jay-config/src/window.rs @@ -246,6 +246,8 @@ pub enum WindowCriterion<'a> { AppIdRegex(&'a str), /// Matches if the window is floating. Floating, + /// Matches if the window is visible. + Visible, } impl WindowCriterion<'_> { diff --git a/src/config/handler.rs b/src/config/handler.rs index 6b03c7f2..a98b36fa 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -1998,6 +1998,7 @@ impl ConfigProxyHandler { mgr.client(&self.state, &self.get_client_matcher(*c)?.node) } WindowCriterionIpc::Floating => mgr.floating(), + WindowCriterionIpc::Visible => mgr.visible(), }; let cached = Rc::new(CachedCriterion { crit: criterion.clone(), diff --git a/src/criteria/tlm.rs b/src/criteria/tlm.rs index f8c5a88b..a24dfff9 100644 --- a/src/criteria/tlm.rs +++ b/src/criteria/tlm.rs @@ -16,6 +16,7 @@ use { tlmm_floating::TlmMatchFloating, tlmm_kind::TlmMatchKind, tlmm_string::{TlmMatchAppId, TlmMatchTitle}, + tlmm_visible::TlmMatchVisible, }, }, state::State, @@ -40,6 +41,7 @@ bitflags! { TL_CHANGED_TITLE = 1 << 2, TL_CHANGED_APP_ID = 1 << 3, TL_CHANGED_FLOATING = 1 << 4, + TL_CHANGED_VISIBLE = 1 << 5, } type TlmFixedRootMatcher = FixedRootMatcher; @@ -50,6 +52,7 @@ pub struct TlMatcherManager { leaf_events: Rc>>, constant: TlmFixedRootMatcher>, floating: TlmFixedRootMatcher, + visible: TlmFixedRootMatcher, matchers: Rc, } @@ -101,6 +104,7 @@ impl TlMatcherManager { Self { constant: CritMatchConstant::create(&matchers, ids), floating: bool!(TlmMatchFloating), + visible: bool!(TlmMatchVisible), changes: Default::default(), leaf_events: Default::default(), ids: ids.clone(), @@ -168,6 +172,7 @@ impl TlMatcherManager { conditional!(TL_CHANGED_TITLE, title); conditional!(TL_CHANGED_APP_ID, app_id); fixed_conditional!(TL_CHANGED_FLOATING, floating); + fixed_conditional!(TL_CHANGED_VISIBLE, visible); false } @@ -235,6 +240,7 @@ impl TlMatcherManager { conditional!(TL_CHANGED_TITLE, title); conditional!(TL_CHANGED_APP_ID, app_id); fixed_conditional!(TL_CHANGED_FLOATING, floating); + fixed_conditional!(TL_CHANGED_VISIBLE, visible); } pub fn title(&self, string: CritLiteralOrRegex) -> Rc { @@ -256,6 +262,10 @@ impl TlMatcherManager { pub fn client(&self, state: &Rc, client: &Rc) -> Rc { TlmMatchClient::new(state, client) } + + pub fn visible(&self) -> Rc { + self.visible[true].clone() + } } impl CritTarget for ToplevelData { diff --git a/src/criteria/tlm/tlm_matchers.rs b/src/criteria/tlm/tlm_matchers.rs index 44a5ab0f..bb84be5b 100644 --- a/src/criteria/tlm/tlm_matchers.rs +++ b/src/criteria/tlm/tlm_matchers.rs @@ -21,3 +21,4 @@ pub mod tlmm_client; pub mod tlmm_floating; pub mod tlmm_kind; pub mod tlmm_string; +pub mod tlmm_visible; diff --git a/src/criteria/tlm/tlm_matchers/tlmm_visible.rs b/src/criteria/tlm/tlm_matchers/tlmm_visible.rs new file mode 100644 index 00000000..1bdea414 --- /dev/null +++ b/src/criteria/tlm/tlm_matchers/tlmm_visible.rs @@ -0,0 +1,11 @@ +use crate::{criteria::crit_graph::CritFixedRootCriterion, tree::ToplevelData}; + +pub struct TlmMatchVisible(pub bool); + +fixed_root_criterion!(TlmMatchVisible, visible); + +impl CritFixedRootCriterion for TlmMatchVisible { + fn matches(&self, data: &ToplevelData) -> bool { + data.visible.get() + } +} diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index 6abfbd68..fc5886dc 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -5,7 +5,7 @@ use { CritDestroyListener, CritMatcherId, tlm::{ TL_CHANGED_APP_ID, TL_CHANGED_DESTROYED, TL_CHANGED_FLOATING, TL_CHANGED_NEW, - TL_CHANGED_TITLE, TlMatcherChange, + TL_CHANGED_TITLE, TL_CHANGED_VISIBLE, TlMatcherChange, }, }, ifs::{ @@ -631,7 +631,9 @@ impl ToplevelData { } pub fn set_visible(&self, node: &dyn Node, visible: bool) { - self.visible.set(visible); + if self.visible.replace(visible) != visible { + self.property_changed(TL_CHANGED_VISIBLE); + } self.seat_state.set_visible(node, visible); for sc in self.jay_screencasts.lock().values() { sc.update_latch_listener(); diff --git a/toml-config/src/config.rs b/toml-config/src/config.rs index f53f89a1..f84a4034 100644 --- a/toml-config/src/config.rs +++ b/toml-config/src/config.rs @@ -260,6 +260,7 @@ pub struct WindowMatch { pub app_id: Option, pub app_id_regex: Option, pub floating: Option, + pub visible: Option, } #[derive(Debug, Clone)] diff --git a/toml-config/src/config/parsers/window_match.rs b/toml-config/src/config/parsers/window_match.rs index c3107a46..1a2b1f3e 100644 --- a/toml-config/src/config/parsers/window_match.rs +++ b/toml-config/src/config/parsers/window_match.rs @@ -56,7 +56,7 @@ impl Parser for WindowMatchParser<'_> { title, title_regex, ), - (app_id, app_id_regex, floating), + (app_id, app_id_regex, floating, visible), ) = ext.extract(( ( opt(str("name")), @@ -73,6 +73,7 @@ impl Parser for WindowMatchParser<'_> { opt(str("app-id")), opt(str("app-id-regex")), opt(bol("floating")), + opt(bol("visible")), ), ))?; let mut not = None; @@ -119,6 +120,7 @@ impl Parser for WindowMatchParser<'_> { app_id: app_id.despan_into(), app_id_regex: app_id_regex.despan_into(), floating: floating.despan(), + visible: visible.despan(), types, client, }) diff --git a/toml-config/src/rules.rs b/toml-config/src/rules.rs index 93e59479..2a7de27a 100644 --- a/toml-config/src/rules.rs +++ b/toml-config/src/rules.rs @@ -259,6 +259,7 @@ impl Rule for WindowRule { value!(AppId, app_id); value!(AppIdRegex, app_id_regex); bool!(Floating, floating); + bool!(Visible, visible); Some(()) } diff --git a/toml-spec/spec/spec.generated.json b/toml-spec/spec/spec.generated.json index 3b2f52c3..6b21ec88 100644 --- a/toml-spec/spec/spec.generated.json +++ b/toml-spec/spec/spec.generated.json @@ -1799,6 +1799,10 @@ "floating": { "type": "boolean", "description": "Matches if the window is/isn't floating." + }, + "visible": { + "type": "boolean", + "description": "Matches if the window is/isn't visible." } }, "required": [] diff --git a/toml-spec/spec/spec.generated.md b/toml-spec/spec/spec.generated.md index 98db444c..cb55fd88 100644 --- a/toml-spec/spec/spec.generated.md +++ b/toml-spec/spec/spec.generated.md @@ -4040,6 +4040,12 @@ The table has the following fields: The value of this field should be a boolean. +- `visible` (optional): + + Matches if the window is/isn't visible. + + The value of this field should be a boolean. + ### `WindowMatchExactly` diff --git a/toml-spec/spec/spec.yaml b/toml-spec/spec/spec.yaml index 76ea9382..4bcdbd34 100644 --- a/toml-spec/spec/spec.yaml +++ b/toml-spec/spec/spec.yaml @@ -3487,6 +3487,10 @@ WindowMatch: kind: boolean required: false description: Matches if the window is/isn't floating. + visible: + kind: boolean + required: false + description: Matches if the window is/isn't visible. WindowMatchExactly: