config: add toplevel-tag window criteria
This commit is contained in:
parent
5f1268cada
commit
6d3d4dcabb
15 changed files with 106 additions and 8 deletions
|
|
@ -123,4 +123,5 @@ pub enum WindowCriterionIpc {
|
|||
pub enum WindowCriterionStringField {
|
||||
Title,
|
||||
AppId,
|
||||
Tag,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1663,6 +1663,8 @@ impl ConfigClient {
|
|||
WindowCriterion::Focus(seat) => WindowCriterionIpc::SeatFocus(seat),
|
||||
WindowCriterion::Fullscreen => WindowCriterionIpc::Fullscreen,
|
||||
WindowCriterion::JustMapped => WindowCriterionIpc::JustMapped,
|
||||
WindowCriterion::Tag(t) => string!(t, Tag, false),
|
||||
WindowCriterion::TagRegex(t) => string!(t, Tag, true),
|
||||
};
|
||||
let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion });
|
||||
get_response!(
|
||||
|
|
|
|||
|
|
@ -260,6 +260,10 @@ pub enum WindowCriterion<'a> {
|
|||
/// This is true for one iteration of the compositor's main loop immediately after the
|
||||
/// window has been mapped.
|
||||
JustMapped,
|
||||
/// Matches the toplevel-tag of the window verbatim.
|
||||
Tag(&'a str),
|
||||
/// Matches the toplevel-tag of the window with a regular expression.
|
||||
TagRegex(&'a str),
|
||||
}
|
||||
|
||||
impl WindowCriterion<'_> {
|
||||
|
|
|
|||
|
|
@ -1990,6 +1990,7 @@ impl ConfigProxyHandler {
|
|||
match *field {
|
||||
WindowCriterionStringField::Title => mgr.title(needle),
|
||||
WindowCriterionStringField::AppId => mgr.app_id(needle),
|
||||
WindowCriterionStringField::Tag => mgr.tag(needle),
|
||||
}
|
||||
}
|
||||
WindowCriterionIpc::Types(t) => mgr.kind(*t),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use {
|
|||
tlmm_just_mapped::TlmMatchJustMapped,
|
||||
tlmm_kind::TlmMatchKind,
|
||||
tlmm_seat_focus::TlmMatchSeatFocus,
|
||||
tlmm_string::{TlmMatchAppId, TlmMatchTitle},
|
||||
tlmm_string::{TlmMatchAppId, TlmMatchTag, TlmMatchTitle},
|
||||
tlmm_urgent::TlmMatchUrgent,
|
||||
tlmm_visible::TlmMatchVisible,
|
||||
},
|
||||
|
|
@ -51,6 +51,7 @@ bitflags! {
|
|||
TL_CHANGED_SEAT_FOCI = 1 << 7,
|
||||
TL_CHANGED_FULLSCREEN = 1 << 8,
|
||||
TL_CHANGED_JUST_MAPPED = 1 << 9,
|
||||
TL_CHANGED_TAG = 1 << 10,
|
||||
}
|
||||
|
||||
type TlmFixedRootMatcher<T> = FixedRootMatcher<ToplevelData, T>;
|
||||
|
|
@ -76,6 +77,7 @@ pub struct RootMatchers {
|
|||
kinds: TlmRootMatcherMap<TlmMatchKind>,
|
||||
clients: CopyHashMap<CritMatcherId, Weak<TlmMatchClient>>,
|
||||
title: TlmRootMatcherMap<TlmMatchTitle>,
|
||||
tag: TlmRootMatcherMap<TlmMatchTag>,
|
||||
app_id: TlmRootMatcherMap<TlmMatchAppId>,
|
||||
seat_foci: TlmRootMatcherMap<TlmMatchSeatFocus>,
|
||||
}
|
||||
|
|
@ -205,6 +207,7 @@ impl TlMatcherManager {
|
|||
conditional!(TL_CHANGED_TITLE, title);
|
||||
conditional!(TL_CHANGED_APP_ID, app_id);
|
||||
conditional!(TL_CHANGED_SEAT_FOCI, seat_foci);
|
||||
conditional!(TL_CHANGED_TAG, tag);
|
||||
fixed_conditional!(TL_CHANGED_FLOATING, floating);
|
||||
fixed_conditional!(TL_CHANGED_VISIBLE, visible);
|
||||
fixed_conditional!(TL_CHANGED_URGENT, urgent);
|
||||
|
|
@ -277,6 +280,7 @@ impl TlMatcherManager {
|
|||
conditional!(TL_CHANGED_TITLE, title);
|
||||
conditional!(TL_CHANGED_APP_ID, app_id);
|
||||
conditional!(TL_CHANGED_SEAT_FOCI, seat_foci);
|
||||
conditional!(TL_CHANGED_TAG, tag);
|
||||
fixed_conditional!(TL_CHANGED_FLOATING, floating);
|
||||
fixed_conditional!(TL_CHANGED_VISIBLE, visible);
|
||||
fixed_conditional!(TL_CHANGED_URGENT, urgent);
|
||||
|
|
@ -299,6 +303,10 @@ impl TlMatcherManager {
|
|||
self.root(TlmMatchAppId::new(string))
|
||||
}
|
||||
|
||||
pub fn tag(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
||||
self.root(TlmMatchTag::new(string))
|
||||
}
|
||||
|
||||
pub fn floating(&self) -> Rc<TlmUpstreamNode> {
|
||||
self.floating[true].clone()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,18 @@ use crate::{
|
|||
crit_matchers::critm_string::{CritMatchString, StringAccess},
|
||||
tlm::{RootMatchers, TlmRootMatcherMap},
|
||||
},
|
||||
tree::ToplevelData,
|
||||
tree::{ToplevelData, ToplevelType},
|
||||
};
|
||||
|
||||
pub type TlmMatchString<T> = CritMatchString<ToplevelData, T>;
|
||||
|
||||
pub type TlmMatchTitle = TlmMatchString<TitleAccess>;
|
||||
pub type TlmMatchAppId = TlmMatchString<AppIdAccess>;
|
||||
pub type TlmMatchTag = TlmMatchString<TagAccess>;
|
||||
|
||||
pub struct TitleAccess;
|
||||
pub struct AppIdAccess;
|
||||
pub struct TagAccess;
|
||||
|
||||
impl StringAccess<ToplevelData> for TitleAccess {
|
||||
fn with_string(data: &ToplevelData, f: impl FnOnce(&str) -> bool) -> bool {
|
||||
|
|
@ -33,3 +35,16 @@ impl StringAccess<ToplevelData> for AppIdAccess {
|
|||
&roots.app_id
|
||||
}
|
||||
}
|
||||
|
||||
impl StringAccess<ToplevelData> for TagAccess {
|
||||
fn with_string(data: &ToplevelData, f: impl FnOnce(&str) -> bool) -> bool {
|
||||
if let ToplevelType::XdgToplevel(data) = &data.kind {
|
||||
return f(&data.tag.borrow());
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn nodes(roots: &RootMatchers) -> &TlmRootMatcherMap<TlmMatchString<Self>> {
|
||||
&roots.tag
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@ pub enum Decoration {
|
|||
Server,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XdgToplevelToplevelData {
|
||||
pub tag: RefCell<String>,
|
||||
}
|
||||
|
||||
pub struct XdgToplevel {
|
||||
pub id: XdgToplevelId,
|
||||
pub state: Rc<State>,
|
||||
|
|
@ -112,6 +117,7 @@ pub struct XdgToplevel {
|
|||
is_mapped: Cell<bool>,
|
||||
dialog: CloneCell<Option<Rc<XdgDialogV1>>>,
|
||||
extents_set: Cell<bool>,
|
||||
pub data: Rc<XdgToplevelToplevelData>,
|
||||
}
|
||||
|
||||
impl Debug for XdgToplevel {
|
||||
|
|
@ -135,6 +141,9 @@ impl XdgToplevel {
|
|||
}
|
||||
let state = &surface.surface.client.state;
|
||||
let node_id = state.node_ids.next();
|
||||
let data = Rc::new(XdgToplevelToplevelData {
|
||||
tag: Default::default(),
|
||||
});
|
||||
Self {
|
||||
id,
|
||||
state: state.clone(),
|
||||
|
|
@ -154,7 +163,7 @@ impl XdgToplevel {
|
|||
state,
|
||||
String::new(),
|
||||
Some(surface.surface.client.clone()),
|
||||
ToplevelType::XdgToplevel,
|
||||
ToplevelType::XdgToplevel(data.clone()),
|
||||
node_id,
|
||||
slf,
|
||||
),
|
||||
|
|
@ -162,6 +171,7 @@ impl XdgToplevel {
|
|||
is_mapped: Cell::new(false),
|
||||
dialog: Default::default(),
|
||||
extents_set: Cell::new(false),
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
criteria::tlm::TL_CHANGED_TAG,
|
||||
globals::{Global, GlobalName},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
tree::ToplevelNodeBase,
|
||||
wire::{XdgToplevelTagManagerV1Id, xdg_toplevel_tag_manager_v1::*},
|
||||
},
|
||||
std::rc::Rc,
|
||||
|
|
@ -72,9 +74,17 @@ impl XdgToplevelTagManagerV1RequestHandler for XdgToplevelTagManagerV1 {
|
|||
|
||||
fn set_toplevel_tag(
|
||||
&self,
|
||||
_req: SetToplevelTag<'_>,
|
||||
req: SetToplevelTag<'_>,
|
||||
_slf: &Rc<Self>,
|
||||
) -> Result<(), Self::Error> {
|
||||
let tl = self.client.lookup(req.toplevel)?;
|
||||
let tag = &mut *tl.data.tag.borrow_mut();
|
||||
if tag == req.tag {
|
||||
return Ok(());
|
||||
}
|
||||
tag.clear();
|
||||
tag.push_str(req.tag);
|
||||
tl.tl_data().property_changed(TL_CHANGED_TAG);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use {
|
|||
jay_screencast::JayScreencast,
|
||||
jay_toplevel::JayToplevel,
|
||||
wl_seat::{NodeSeatState, SeatId, collect_kb_foci, collect_kb_foci2},
|
||||
wl_surface::WlSurface,
|
||||
wl_surface::{WlSurface, xdg_surface::xdg_toplevel::XdgToplevelToplevelData},
|
||||
},
|
||||
rect::Rect,
|
||||
state::State,
|
||||
|
|
@ -277,7 +277,7 @@ impl ToplevelOpt {
|
|||
pub enum ToplevelType {
|
||||
Container,
|
||||
Placeholder,
|
||||
XdgToplevel,
|
||||
XdgToplevel(Rc<XdgToplevelToplevelData>),
|
||||
XWindow,
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +286,7 @@ impl ToplevelType {
|
|||
match self {
|
||||
ToplevelType::Container => window::CONTAINER,
|
||||
ToplevelType::Placeholder => window::PLACEHOLDER,
|
||||
ToplevelType::XdgToplevel => window::XDG_TOPLEVEL,
|
||||
ToplevelType::XdgToplevel { .. } => window::XDG_TOPLEVEL,
|
||||
ToplevelType::XWindow => window::X_WINDOW,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,6 +265,8 @@ pub struct WindowMatch {
|
|||
pub focused: Option<bool>,
|
||||
pub fullscreen: Option<bool>,
|
||||
pub just_mapped: Option<bool>,
|
||||
pub tag: Option<String>,
|
||||
pub tag_regex: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -56,7 +56,18 @@ impl Parser for WindowMatchParser<'_> {
|
|||
title,
|
||||
title_regex,
|
||||
),
|
||||
(app_id, app_id_regex, floating, visible, urgent, focused, fullscreen, just_mapped),
|
||||
(
|
||||
app_id,
|
||||
app_id_regex,
|
||||
floating,
|
||||
visible,
|
||||
urgent,
|
||||
focused,
|
||||
fullscreen,
|
||||
just_mapped,
|
||||
tag,
|
||||
tag_regex,
|
||||
),
|
||||
) = ext.extract((
|
||||
(
|
||||
opt(str("name")),
|
||||
|
|
@ -78,6 +89,8 @@ impl Parser for WindowMatchParser<'_> {
|
|||
opt(bol("focused")),
|
||||
opt(bol("fullscreen")),
|
||||
opt(bol("just-mapped")),
|
||||
opt(str("tag")),
|
||||
opt(str("tag-regex")),
|
||||
),
|
||||
))?;
|
||||
let mut not = None;
|
||||
|
|
@ -129,6 +142,8 @@ impl Parser for WindowMatchParser<'_> {
|
|||
focused: focused.despan(),
|
||||
fullscreen: fullscreen.despan(),
|
||||
just_mapped: just_mapped.despan(),
|
||||
tag: tag.despan_into(),
|
||||
tag_regex: tag_regex.despan_into(),
|
||||
types,
|
||||
client,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -258,6 +258,8 @@ impl Rule for WindowRule {
|
|||
value!(TitleRegex, title_regex);
|
||||
value!(AppId, app_id);
|
||||
value!(AppIdRegex, app_id_regex);
|
||||
value!(Tag, tag);
|
||||
value!(TagRegex, tag_regex);
|
||||
bool!(Floating, floating);
|
||||
bool!(Visible, visible);
|
||||
bool!(Urgent, urgent);
|
||||
|
|
|
|||
|
|
@ -1819,6 +1819,14 @@
|
|||
"just-mapped": {
|
||||
"type": "boolean",
|
||||
"description": "Matches if the window has/hasn't just been mapped.\n\nThis is true for one iteration of the compositor's main loop immediately after the\nwindow has been mapped.\n"
|
||||
},
|
||||
"tag": {
|
||||
"type": "string",
|
||||
"description": "Matches the toplevel-tag of the window verbatim."
|
||||
},
|
||||
"tag-regex": {
|
||||
"type": "string",
|
||||
"description": "Matches the toplevel-tag of the window with a regular expression."
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
|
|
|||
|
|
@ -4073,6 +4073,18 @@ The table has the following fields:
|
|||
|
||||
The value of this field should be a boolean.
|
||||
|
||||
- `tag` (optional):
|
||||
|
||||
Matches the toplevel-tag of the window verbatim.
|
||||
|
||||
The value of this field should be a string.
|
||||
|
||||
- `tag-regex` (optional):
|
||||
|
||||
Matches the toplevel-tag of the window with a regular expression.
|
||||
|
||||
The value of this field should be a string.
|
||||
|
||||
|
||||
<a name="types-WindowMatchExactly"></a>
|
||||
### `WindowMatchExactly`
|
||||
|
|
|
|||
|
|
@ -3511,6 +3511,14 @@ WindowMatch:
|
|||
|
||||
This is true for one iteration of the compositor's main loop immediately after the
|
||||
window has been mapped.
|
||||
tag:
|
||||
kind: string
|
||||
required: false
|
||||
description: Matches the toplevel-tag of the window verbatim.
|
||||
tag-regex:
|
||||
kind: string
|
||||
required: false
|
||||
description: Matches the toplevel-tag of the window with a regular expression.
|
||||
|
||||
|
||||
WindowMatchExactly:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue