config: add app-id window criteria
This commit is contained in:
parent
6ef7655dbd
commit
da64166e82
13 changed files with 102 additions and 24 deletions
|
|
@ -115,4 +115,5 @@ pub enum WindowCriterionIpc {
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub enum WindowCriterionStringField {
|
pub enum WindowCriterionStringField {
|
||||||
Title,
|
Title,
|
||||||
|
AppId,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1655,6 +1655,8 @@ impl ConfigClient {
|
||||||
}
|
}
|
||||||
WindowCriterion::Title(t) => string!(t, Title, false),
|
WindowCriterion::Title(t) => string!(t, Title, false),
|
||||||
WindowCriterion::TitleRegex(t) => string!(t, Title, true),
|
WindowCriterion::TitleRegex(t) => string!(t, Title, true),
|
||||||
|
WindowCriterion::AppId(t) => string!(t, AppId, false),
|
||||||
|
WindowCriterion::AppIdRegex(t) => string!(t, AppId, true),
|
||||||
};
|
};
|
||||||
let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion });
|
let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion });
|
||||||
get_response!(
|
get_response!(
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,10 @@ pub enum WindowCriterion<'a> {
|
||||||
Title(&'a str),
|
Title(&'a str),
|
||||||
/// Matches the title of the window with a regular expression.
|
/// Matches the title of the window with a regular expression.
|
||||||
TitleRegex(&'a str),
|
TitleRegex(&'a str),
|
||||||
|
/// Matches the app-id of the window verbatim.
|
||||||
|
AppId(&'a str),
|
||||||
|
/// Matches the app-id of the window with a regular expression.
|
||||||
|
AppIdRegex(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowCriterion<'_> {
|
impl WindowCriterion<'_> {
|
||||||
|
|
|
||||||
|
|
@ -1989,6 +1989,7 @@ impl ConfigProxyHandler {
|
||||||
};
|
};
|
||||||
match *field {
|
match *field {
|
||||||
WindowCriterionStringField::Title => mgr.title(needle),
|
WindowCriterionStringField::Title => mgr.title(needle),
|
||||||
|
WindowCriterionStringField::AppId => mgr.app_id(needle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowCriterionIpc::Types(t) => mgr.kind(*t),
|
WindowCriterionIpc::Types(t) => mgr.kind(*t),
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ use {
|
||||||
crit_leaf::{CritLeafEvent, CritLeafMatcher},
|
crit_leaf::{CritLeafEvent, CritLeafMatcher},
|
||||||
crit_matchers::critm_constant::CritMatchConstant,
|
crit_matchers::critm_constant::CritMatchConstant,
|
||||||
tlm::tlm_matchers::{
|
tlm::tlm_matchers::{
|
||||||
tlmm_client::TlmMatchClient, tlmm_kind::TlmMatchKind, tlmm_string::TlmMatchTitle,
|
tlmm_client::TlmMatchClient,
|
||||||
|
tlmm_kind::TlmMatchKind,
|
||||||
|
tlmm_string::{TlmMatchAppId, TlmMatchTitle},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
state::State,
|
state::State,
|
||||||
|
|
@ -29,6 +31,7 @@ bitflags! {
|
||||||
TL_CHANGED_DESTROYED = 1 << 0,
|
TL_CHANGED_DESTROYED = 1 << 0,
|
||||||
TL_CHANGED_NEW = 1 << 1,
|
TL_CHANGED_NEW = 1 << 1,
|
||||||
TL_CHANGED_TITLE = 1 << 2,
|
TL_CHANGED_TITLE = 1 << 2,
|
||||||
|
TL_CHANGED_APP_ID = 1 << 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
type TlmFixedRootMatcher<T> = FixedRootMatcher<ToplevelData, T>;
|
type TlmFixedRootMatcher<T> = FixedRootMatcher<ToplevelData, T>;
|
||||||
|
|
@ -48,6 +51,7 @@ pub struct RootMatchers {
|
||||||
kinds: TlmRootMatcherMap<TlmMatchKind>,
|
kinds: TlmRootMatcherMap<TlmMatchKind>,
|
||||||
clients: CopyHashMap<CritMatcherId, Weak<TlmMatchClient>>,
|
clients: CopyHashMap<CritMatcherId, Weak<TlmMatchClient>>,
|
||||||
title: TlmRootMatcherMap<TlmMatchTitle>,
|
title: TlmRootMatcherMap<TlmMatchTitle>,
|
||||||
|
app_id: TlmRootMatcherMap<TlmMatchAppId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_tl_changes(state: Rc<State>) {
|
pub async fn handle_tl_changes(state: Rc<State>) {
|
||||||
|
|
@ -143,6 +147,7 @@ impl TlMatcherManager {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
conditional!(TL_CHANGED_TITLE, title);
|
conditional!(TL_CHANGED_TITLE, title);
|
||||||
|
conditional!(TL_CHANGED_APP_ID, app_id);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,12 +215,17 @@ impl TlMatcherManager {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
conditional!(TL_CHANGED_TITLE, title);
|
conditional!(TL_CHANGED_TITLE, title);
|
||||||
|
conditional!(TL_CHANGED_APP_ID, app_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
pub fn title(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
||||||
self.root(TlmMatchTitle::new(string))
|
self.root(TlmMatchTitle::new(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn app_id(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
||||||
|
self.root(TlmMatchAppId::new(string))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn kind(&self, kind: WindowType) -> Rc<TlmUpstreamNode> {
|
pub fn kind(&self, kind: WindowType) -> Rc<TlmUpstreamNode> {
|
||||||
self.root(TlmMatchKind::new(kind))
|
self.root(TlmMatchKind::new(kind))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,10 @@ use crate::{
|
||||||
pub type TlmMatchString<T> = CritMatchString<ToplevelData, T>;
|
pub type TlmMatchString<T> = CritMatchString<ToplevelData, T>;
|
||||||
|
|
||||||
pub type TlmMatchTitle = TlmMatchString<TitleAccess>;
|
pub type TlmMatchTitle = TlmMatchString<TitleAccess>;
|
||||||
|
pub type TlmMatchAppId = TlmMatchString<AppIdAccess>;
|
||||||
|
|
||||||
pub struct TitleAccess;
|
pub struct TitleAccess;
|
||||||
|
pub struct AppIdAccess;
|
||||||
|
|
||||||
impl StringAccess<ToplevelData> for TitleAccess {
|
impl StringAccess<ToplevelData> for TitleAccess {
|
||||||
fn with_string(data: &ToplevelData, f: impl FnOnce(&str) -> bool) -> bool {
|
fn with_string(data: &ToplevelData, f: impl FnOnce(&str) -> bool) -> bool {
|
||||||
|
|
@ -21,3 +23,13 @@ impl StringAccess<ToplevelData> for TitleAccess {
|
||||||
&roots.title
|
&roots.title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StringAccess<ToplevelData> for AppIdAccess {
|
||||||
|
fn with_string(data: &ToplevelData, f: impl FnOnce(&str) -> bool) -> bool {
|
||||||
|
f(&data.app_id.borrow())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nodes(roots: &RootMatchers) -> &TlmRootMatcherMap<TlmMatchString<Self>> {
|
||||||
|
&roots.app_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ use {
|
||||||
client::{Client, ClientId},
|
client::{Client, ClientId},
|
||||||
criteria::{
|
criteria::{
|
||||||
CritDestroyListener, CritMatcherId,
|
CritDestroyListener, CritMatcherId,
|
||||||
tlm::{TL_CHANGED_DESTROYED, TL_CHANGED_NEW, TL_CHANGED_TITLE, TlMatcherChange},
|
tlm::{
|
||||||
|
TL_CHANGED_APP_ID, TL_CHANGED_DESTROYED, TL_CHANGED_NEW, TL_CHANGED_TITLE,
|
||||||
|
TlMatcherChange,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ifs::{
|
ifs::{
|
||||||
ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||||
|
|
@ -498,11 +501,16 @@ impl ToplevelData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_app_id(&self, app_id: &str) {
|
pub fn set_app_id(&self, app_id: &str) {
|
||||||
*self.app_id.borrow_mut() = app_id.to_string();
|
let dst = &mut *self.app_id.borrow_mut();
|
||||||
|
if *dst == app_id {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*dst = app_id.to_string();
|
||||||
for handle in self.handles.lock().values() {
|
for handle in self.handles.lock().values() {
|
||||||
handle.send_app_id(app_id);
|
handle.send_app_id(app_id);
|
||||||
handle.send_done();
|
handle.send_done();
|
||||||
}
|
}
|
||||||
|
self.property_changed(TL_CHANGED_APP_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_fullscreen(
|
pub fn set_fullscreen(
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,8 @@ pub struct WindowMatch {
|
||||||
pub client: Option<ClientMatch>,
|
pub client: Option<ClientMatch>,
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
pub title_regex: Option<String>,
|
pub title_regex: Option<String>,
|
||||||
|
pub app_id: Option<String>,
|
||||||
|
pub app_id_regex: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -44,27 +44,33 @@ impl Parser for WindowMatchParser<'_> {
|
||||||
table: &IndexMap<Spanned<String>, Spanned<Value>>,
|
table: &IndexMap<Spanned<String>, Spanned<Value>>,
|
||||||
) -> ParseResult<Self> {
|
) -> ParseResult<Self> {
|
||||||
let mut ext = Extractor::new(self.0, span, table);
|
let mut ext = Extractor::new(self.0, span, table);
|
||||||
let ((
|
let (
|
||||||
name,
|
(
|
||||||
not_val,
|
name,
|
||||||
all_val,
|
not_val,
|
||||||
any_val,
|
all_val,
|
||||||
exactly_val,
|
any_val,
|
||||||
types_val,
|
exactly_val,
|
||||||
client_val,
|
types_val,
|
||||||
title,
|
client_val,
|
||||||
title_regex,
|
title,
|
||||||
),) = ext.extract(((
|
title_regex,
|
||||||
opt(str("name")),
|
),
|
||||||
opt(val("not")),
|
(app_id, app_id_regex),
|
||||||
opt(arr("all")),
|
) = ext.extract((
|
||||||
opt(arr("any")),
|
(
|
||||||
opt(val("exactly")),
|
opt(str("name")),
|
||||||
opt(val("types")),
|
opt(val("not")),
|
||||||
opt(val("client")),
|
opt(arr("all")),
|
||||||
opt(str("title")),
|
opt(arr("any")),
|
||||||
opt(str("title-regex")),
|
opt(val("exactly")),
|
||||||
),))?;
|
opt(val("types")),
|
||||||
|
opt(val("client")),
|
||||||
|
opt(str("title")),
|
||||||
|
opt(str("title-regex")),
|
||||||
|
),
|
||||||
|
(opt(str("app-id")), opt(str("app-id-regex"))),
|
||||||
|
))?;
|
||||||
let mut not = None;
|
let mut not = None;
|
||||||
if let Some(value) = not_val {
|
if let Some(value) = not_val {
|
||||||
not = Some(Box::new(value.parse(&mut WindowMatchParser(self.0))?));
|
not = Some(Box::new(value.parse(&mut WindowMatchParser(self.0))?));
|
||||||
|
|
@ -106,6 +112,8 @@ impl Parser for WindowMatchParser<'_> {
|
||||||
},
|
},
|
||||||
title: title.despan_into(),
|
title: title.despan_into(),
|
||||||
title_regex: title_regex.despan_into(),
|
title_regex: title_regex.despan_into(),
|
||||||
|
app_id: app_id.despan_into(),
|
||||||
|
app_id_regex: app_id_regex.despan_into(),
|
||||||
types,
|
types,
|
||||||
client,
|
client,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,8 @@ impl Rule for WindowRule {
|
||||||
}
|
}
|
||||||
value!(Title, title);
|
value!(Title, title);
|
||||||
value!(TitleRegex, title_regex);
|
value!(TitleRegex, title_regex);
|
||||||
|
value!(AppId, app_id);
|
||||||
|
value!(AppIdRegex, app_id_regex);
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1787,6 +1787,14 @@
|
||||||
"title-regex": {
|
"title-regex": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Matches the title of the window with a regular expression."
|
"description": "Matches the title of the window with a regular expression."
|
||||||
|
},
|
||||||
|
"app-id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Matches the app-id of the window verbatim."
|
||||||
|
},
|
||||||
|
"app-id-regex": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Matches the app-id of the window with a regular expression."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|
|
||||||
|
|
@ -4022,6 +4022,18 @@ The table has the following fields:
|
||||||
|
|
||||||
The value of this field should be a string.
|
The value of this field should be a string.
|
||||||
|
|
||||||
|
- `app-id` (optional):
|
||||||
|
|
||||||
|
Matches the app-id of the window verbatim.
|
||||||
|
|
||||||
|
The value of this field should be a string.
|
||||||
|
|
||||||
|
- `app-id-regex` (optional):
|
||||||
|
|
||||||
|
Matches the app-id of the window with a regular expression.
|
||||||
|
|
||||||
|
The value of this field should be a string.
|
||||||
|
|
||||||
|
|
||||||
<a name="types-WindowMatchExactly"></a>
|
<a name="types-WindowMatchExactly"></a>
|
||||||
### `WindowMatchExactly`
|
### `WindowMatchExactly`
|
||||||
|
|
|
||||||
|
|
@ -3475,6 +3475,14 @@ WindowMatch:
|
||||||
kind: string
|
kind: string
|
||||||
required: false
|
required: false
|
||||||
description: Matches the title of the window with a regular expression.
|
description: Matches the title of the window with a regular expression.
|
||||||
|
app-id:
|
||||||
|
kind: string
|
||||||
|
required: false
|
||||||
|
description: Matches the app-id of the window verbatim.
|
||||||
|
app-id-regex:
|
||||||
|
kind: string
|
||||||
|
required: false
|
||||||
|
description: Matches the app-id of the window with a regular expression.
|
||||||
|
|
||||||
|
|
||||||
WindowMatchExactly:
|
WindowMatchExactly:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue