1
0
Fork 0
forked from wry/wry

config: add fullscreen window criteria

This commit is contained in:
Julian Orth 2025-05-01 18:49:39 +02:00
parent 91c948b219
commit e36ccd560c
14 changed files with 51 additions and 3 deletions

View file

@ -115,6 +115,7 @@ pub enum WindowCriterionIpc {
Visible, Visible,
Urgent, Urgent,
SeatFocus(Seat), SeatFocus(Seat),
Fullscreen,
} }
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)] #[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)]

View file

@ -1661,6 +1661,7 @@ impl ConfigClient {
WindowCriterion::Visible => WindowCriterionIpc::Visible, WindowCriterion::Visible => WindowCriterionIpc::Visible,
WindowCriterion::Urgent => WindowCriterionIpc::Urgent, WindowCriterion::Urgent => WindowCriterionIpc::Urgent,
WindowCriterion::Focus(seat) => WindowCriterionIpc::SeatFocus(seat), WindowCriterion::Focus(seat) => WindowCriterionIpc::SeatFocus(seat),
WindowCriterion::Fullscreen => WindowCriterionIpc::Fullscreen,
}; };
let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion }); let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion });
get_response!( get_response!(

View file

@ -253,6 +253,8 @@ pub enum WindowCriterion<'a> {
Urgent, Urgent,
/// Matches if the window has the keyboard focus of the seat. /// Matches if the window has the keyboard focus of the seat.
Focus(Seat), Focus(Seat),
/// Matches if the window is fullscreen.
Fullscreen,
} }
impl WindowCriterion<'_> { impl WindowCriterion<'_> {

View file

@ -2001,6 +2001,7 @@ impl ConfigProxyHandler {
WindowCriterionIpc::Visible => mgr.visible(), WindowCriterionIpc::Visible => mgr.visible(),
WindowCriterionIpc::Urgent => mgr.urgent(), WindowCriterionIpc::Urgent => mgr.urgent(),
WindowCriterionIpc::SeatFocus(seat) => mgr.seat_focus(&*self.get_seat(*seat)?), WindowCriterionIpc::SeatFocus(seat) => mgr.seat_focus(&*self.get_seat(*seat)?),
WindowCriterionIpc::Fullscreen => mgr.fullscreen(),
}; };
let cached = Rc::new(CachedCriterion { let cached = Rc::new(CachedCriterion {
crit: criterion.clone(), crit: criterion.clone(),

View file

@ -14,6 +14,7 @@ use {
tlm::tlm_matchers::{ tlm::tlm_matchers::{
tlmm_client::TlmMatchClient, tlmm_client::TlmMatchClient,
tlmm_floating::TlmMatchFloating, tlmm_floating::TlmMatchFloating,
tlmm_fullscreen::TlmMatchFullscreen,
tlmm_kind::TlmMatchKind, tlmm_kind::TlmMatchKind,
tlmm_seat_focus::TlmMatchSeatFocus, tlmm_seat_focus::TlmMatchSeatFocus,
tlmm_string::{TlmMatchAppId, TlmMatchTitle}, tlmm_string::{TlmMatchAppId, TlmMatchTitle},
@ -47,6 +48,7 @@ bitflags! {
TL_CHANGED_VISIBLE = 1 << 5, TL_CHANGED_VISIBLE = 1 << 5,
TL_CHANGED_URGENT = 1 << 6, TL_CHANGED_URGENT = 1 << 6,
TL_CHANGED_SEAT_FOCI = 1 << 7, TL_CHANGED_SEAT_FOCI = 1 << 7,
TL_CHANGED_FULLSCREEN = 1 << 8,
} }
type TlmFixedRootMatcher<T> = FixedRootMatcher<ToplevelData, T>; type TlmFixedRootMatcher<T> = FixedRootMatcher<ToplevelData, T>;
@ -59,6 +61,7 @@ pub struct TlMatcherManager {
floating: TlmFixedRootMatcher<TlmMatchFloating>, floating: TlmFixedRootMatcher<TlmMatchFloating>,
visible: TlmFixedRootMatcher<TlmMatchVisible>, visible: TlmFixedRootMatcher<TlmMatchVisible>,
urgent: TlmFixedRootMatcher<TlmMatchUrgent>, urgent: TlmFixedRootMatcher<TlmMatchUrgent>,
fullscreen: TlmFixedRootMatcher<TlmMatchFullscreen>,
matchers: Rc<RootMatchers>, matchers: Rc<RootMatchers>,
} }
@ -113,6 +116,7 @@ impl TlMatcherManager {
floating: bool!(TlmMatchFloating), floating: bool!(TlmMatchFloating),
visible: bool!(TlmMatchVisible), visible: bool!(TlmMatchVisible),
urgent: bool!(TlmMatchUrgent), urgent: bool!(TlmMatchUrgent),
fullscreen: bool!(TlmMatchFullscreen),
changes: Default::default(), changes: Default::default(),
leaf_events: Default::default(), leaf_events: Default::default(),
ids: ids.clone(), ids: ids.clone(),
@ -187,6 +191,7 @@ impl TlMatcherManager {
fixed_conditional!(TL_CHANGED_FLOATING, floating); fixed_conditional!(TL_CHANGED_FLOATING, floating);
fixed_conditional!(TL_CHANGED_VISIBLE, visible); fixed_conditional!(TL_CHANGED_VISIBLE, visible);
fixed_conditional!(TL_CHANGED_URGENT, urgent); fixed_conditional!(TL_CHANGED_URGENT, urgent);
fixed_conditional!(TL_CHANGED_FULLSCREEN, fullscreen);
false false
} }
@ -257,6 +262,7 @@ impl TlMatcherManager {
fixed_conditional!(TL_CHANGED_FLOATING, floating); fixed_conditional!(TL_CHANGED_FLOATING, floating);
fixed_conditional!(TL_CHANGED_VISIBLE, visible); fixed_conditional!(TL_CHANGED_VISIBLE, visible);
fixed_conditional!(TL_CHANGED_URGENT, urgent); fixed_conditional!(TL_CHANGED_URGENT, urgent);
fixed_conditional!(TL_CHANGED_FULLSCREEN, fullscreen);
} }
pub fn title(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> { pub fn title(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
@ -283,6 +289,10 @@ impl TlMatcherManager {
self.visible[true].clone() self.visible[true].clone()
} }
pub fn fullscreen(&self) -> Rc<TlmUpstreamNode> {
self.fullscreen[true].clone()
}
pub fn urgent(&self) -> Rc<TlmUpstreamNode> { pub fn urgent(&self) -> Rc<TlmUpstreamNode> {
self.urgent[true].clone() self.urgent[true].clone()
} }

View file

@ -19,6 +19,7 @@ macro_rules! fixed_root_criterion {
pub mod tlmm_client; pub mod tlmm_client;
pub mod tlmm_floating; pub mod tlmm_floating;
pub mod tlmm_fullscreen;
pub mod tlmm_kind; pub mod tlmm_kind;
pub mod tlmm_seat_focus; pub mod tlmm_seat_focus;
pub mod tlmm_string; pub mod tlmm_string;

View file

@ -0,0 +1,11 @@
use crate::{criteria::crit_graph::CritFixedRootCriterion, tree::ToplevelData};
pub struct TlmMatchFullscreen(pub bool);
fixed_root_criterion!(TlmMatchFullscreen, fullscreen);
impl CritFixedRootCriterion<ToplevelData> for TlmMatchFullscreen {
fn matches(&self, data: &ToplevelData) -> bool {
data.is_fullscreen.get()
}
}

View file

@ -4,8 +4,9 @@ use {
criteria::{ criteria::{
CritDestroyListener, CritMatcherId, CritDestroyListener, CritMatcherId,
tlm::{ tlm::{
TL_CHANGED_APP_ID, TL_CHANGED_DESTROYED, TL_CHANGED_FLOATING, TL_CHANGED_NEW, TL_CHANGED_APP_ID, TL_CHANGED_DESTROYED, TL_CHANGED_FLOATING,
TL_CHANGED_TITLE, TL_CHANGED_URGENT, TL_CHANGED_VISIBLE, TlMatcherChange, TL_CHANGED_FULLSCREEN, TL_CHANGED_NEW, TL_CHANGED_TITLE, TL_CHANGED_URGENT,
TL_CHANGED_VISIBLE, TlMatcherChange,
}, },
}, },
ifs::{ ifs::{
@ -579,6 +580,7 @@ impl ToplevelData {
}); });
drop(data); drop(data);
self.is_fullscreen.set(true); self.is_fullscreen.set(true);
self.property_changed(TL_CHANGED_FULLSCREEN);
node.tl_set_parent(ws.clone()); node.tl_set_parent(ws.clone());
ws.set_fullscreen_node(&node); ws.set_fullscreen_node(&node);
node.clone() node.clone()
@ -601,6 +603,7 @@ impl ToplevelData {
} }
}; };
self.is_fullscreen.set(false); self.is_fullscreen.set(false);
self.property_changed(TL_CHANGED_FULLSCREEN);
match fd.workspace.fullscreen.get() { match fd.workspace.fullscreen.get() {
None => { None => {
log::error!( log::error!(

View file

@ -263,6 +263,7 @@ pub struct WindowMatch {
pub visible: Option<bool>, pub visible: Option<bool>,
pub urgent: Option<bool>, pub urgent: Option<bool>,
pub focused: Option<bool>, pub focused: Option<bool>,
pub fullscreen: Option<bool>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -56,7 +56,7 @@ impl Parser for WindowMatchParser<'_> {
title, title,
title_regex, title_regex,
), ),
(app_id, app_id_regex, floating, visible, urgent, focused), (app_id, app_id_regex, floating, visible, urgent, focused, fullscreen),
) = ext.extract(( ) = ext.extract((
( (
opt(str("name")), opt(str("name")),
@ -76,6 +76,7 @@ impl Parser for WindowMatchParser<'_> {
opt(bol("visible")), opt(bol("visible")),
opt(bol("urgent")), opt(bol("urgent")),
opt(bol("focused")), opt(bol("focused")),
opt(bol("fullscreen")),
), ),
))?; ))?;
let mut not = None; let mut not = None;
@ -125,6 +126,7 @@ impl Parser for WindowMatchParser<'_> {
visible: visible.despan(), visible: visible.despan(),
urgent: urgent.despan(), urgent: urgent.despan(),
focused: focused.despan(), focused: focused.despan(),
fullscreen: fullscreen.despan(),
types, types,
client, client,
}) })

View file

@ -261,6 +261,7 @@ impl Rule for WindowRule {
bool!(Floating, floating); bool!(Floating, floating);
bool!(Visible, visible); bool!(Visible, visible);
bool!(Urgent, urgent); bool!(Urgent, urgent);
bool!(Fullscreen, fullscreen);
if let Some(value) = match_.focused { if let Some(value) = match_.focused {
let crit = WindowCriterion::Focus(state.persistent.seat); let crit = WindowCriterion::Focus(state.persistent.seat);
let matcher = match value { let matcher = match value {

View file

@ -1811,6 +1811,10 @@
"focused": { "focused": {
"type": "boolean", "type": "boolean",
"description": "Matches if the window has/hasn't the keyboard focus." "description": "Matches if the window has/hasn't the keyboard focus."
},
"fullscreen": {
"type": "boolean",
"description": "Matches if the window is/isn't fullscreen."
} }
}, },
"required": [] "required": []

View file

@ -4058,6 +4058,12 @@ The table has the following fields:
The value of this field should be a boolean. The value of this field should be a boolean.
- `fullscreen` (optional):
Matches if the window is/isn't fullscreen.
The value of this field should be a boolean.
<a name="types-WindowMatchExactly"></a> <a name="types-WindowMatchExactly"></a>
### `WindowMatchExactly` ### `WindowMatchExactly`

View file

@ -3499,6 +3499,10 @@ WindowMatch:
kind: boolean kind: boolean
required: false required: false
description: Matches if the window has/hasn't the keyboard focus. description: Matches if the window has/hasn't the keyboard focus.
fullscreen:
kind: boolean
required: false
description: Matches if the window is/isn't fullscreen.
WindowMatchExactly: WindowMatchExactly: