config: add WM_WINDOW_ROLE window criteria
This commit is contained in:
parent
faa0b27ef8
commit
5ad6ca4dd3
14 changed files with 81 additions and 6 deletions
|
|
@ -126,4 +126,5 @@ pub enum WindowCriterionStringField {
|
||||||
Tag,
|
Tag,
|
||||||
XClass,
|
XClass,
|
||||||
XInstance,
|
XInstance,
|
||||||
|
XRole,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1669,6 +1669,8 @@ impl ConfigClient {
|
||||||
WindowCriterion::XClassRegex(t) => string!(t, XClass, true),
|
WindowCriterion::XClassRegex(t) => string!(t, XClass, true),
|
||||||
WindowCriterion::XInstance(t) => string!(t, XInstance, false),
|
WindowCriterion::XInstance(t) => string!(t, XInstance, false),
|
||||||
WindowCriterion::XInstanceRegex(t) => string!(t, XInstance, true),
|
WindowCriterion::XInstanceRegex(t) => string!(t, XInstance, true),
|
||||||
|
WindowCriterion::XRole(t) => string!(t, XRole, false),
|
||||||
|
WindowCriterion::XRoleRegex(t) => string!(t, XRole, true),
|
||||||
};
|
};
|
||||||
let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion });
|
let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion });
|
||||||
get_response!(
|
get_response!(
|
||||||
|
|
|
||||||
|
|
@ -272,6 +272,10 @@ pub enum WindowCriterion<'a> {
|
||||||
XInstance(&'a str),
|
XInstance(&'a str),
|
||||||
/// Matches the X instance of the window with a regular expression.
|
/// Matches the X instance of the window with a regular expression.
|
||||||
XInstanceRegex(&'a str),
|
XInstanceRegex(&'a str),
|
||||||
|
/// Matches the X role of the window verbatim.
|
||||||
|
XRole(&'a str),
|
||||||
|
/// Matches the X role of the window with a regular expression.
|
||||||
|
XRoleRegex(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowCriterion<'_> {
|
impl WindowCriterion<'_> {
|
||||||
|
|
|
||||||
|
|
@ -1993,6 +1993,7 @@ impl ConfigProxyHandler {
|
||||||
WindowCriterionStringField::Tag => mgr.tag(needle),
|
WindowCriterionStringField::Tag => mgr.tag(needle),
|
||||||
WindowCriterionStringField::XClass => mgr.class(needle),
|
WindowCriterionStringField::XClass => mgr.class(needle),
|
||||||
WindowCriterionStringField::XInstance => mgr.instance(needle),
|
WindowCriterionStringField::XInstance => mgr.instance(needle),
|
||||||
|
WindowCriterionStringField::XRole => mgr.role(needle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowCriterionIpc::Types(t) => mgr.kind(*t),
|
WindowCriterionIpc::Types(t) => mgr.kind(*t),
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ use {
|
||||||
tlmm_kind::TlmMatchKind,
|
tlmm_kind::TlmMatchKind,
|
||||||
tlmm_seat_focus::TlmMatchSeatFocus,
|
tlmm_seat_focus::TlmMatchSeatFocus,
|
||||||
tlmm_string::{
|
tlmm_string::{
|
||||||
TlmMatchAppId, TlmMatchClass, TlmMatchInstance, TlmMatchTag, TlmMatchTitle,
|
TlmMatchAppId, TlmMatchClass, TlmMatchInstance, TlmMatchRole, TlmMatchTag,
|
||||||
|
TlmMatchTitle,
|
||||||
},
|
},
|
||||||
tlmm_urgent::TlmMatchUrgent,
|
tlmm_urgent::TlmMatchUrgent,
|
||||||
tlmm_visible::TlmMatchVisible,
|
tlmm_visible::TlmMatchVisible,
|
||||||
|
|
@ -55,6 +56,7 @@ bitflags! {
|
||||||
TL_CHANGED_JUST_MAPPED = 1 << 9,
|
TL_CHANGED_JUST_MAPPED = 1 << 9,
|
||||||
TL_CHANGED_TAG = 1 << 10,
|
TL_CHANGED_TAG = 1 << 10,
|
||||||
TL_CHANGED_CLASS_INST = 1 << 11,
|
TL_CHANGED_CLASS_INST = 1 << 11,
|
||||||
|
TL_CHANGED_ROLE = 1 << 12,
|
||||||
}
|
}
|
||||||
|
|
||||||
type TlmFixedRootMatcher<T> = FixedRootMatcher<ToplevelData, T>;
|
type TlmFixedRootMatcher<T> = FixedRootMatcher<ToplevelData, T>;
|
||||||
|
|
@ -85,6 +87,7 @@ pub struct RootMatchers {
|
||||||
seat_foci: TlmRootMatcherMap<TlmMatchSeatFocus>,
|
seat_foci: TlmRootMatcherMap<TlmMatchSeatFocus>,
|
||||||
class: TlmRootMatcherMap<TlmMatchClass>,
|
class: TlmRootMatcherMap<TlmMatchClass>,
|
||||||
instance: TlmRootMatcherMap<TlmMatchInstance>,
|
instance: TlmRootMatcherMap<TlmMatchInstance>,
|
||||||
|
role: TlmRootMatcherMap<TlmMatchRole>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_tl_changes(state: Rc<State>) {
|
pub async fn handle_tl_changes(state: Rc<State>) {
|
||||||
|
|
@ -215,6 +218,7 @@ impl TlMatcherManager {
|
||||||
conditional!(TL_CHANGED_TAG, tag);
|
conditional!(TL_CHANGED_TAG, tag);
|
||||||
conditional!(TL_CHANGED_CLASS_INST, class);
|
conditional!(TL_CHANGED_CLASS_INST, class);
|
||||||
conditional!(TL_CHANGED_CLASS_INST, instance);
|
conditional!(TL_CHANGED_CLASS_INST, instance);
|
||||||
|
conditional!(TL_CHANGED_ROLE, role);
|
||||||
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);
|
||||||
|
|
@ -290,6 +294,7 @@ impl TlMatcherManager {
|
||||||
conditional!(TL_CHANGED_TAG, tag);
|
conditional!(TL_CHANGED_TAG, tag);
|
||||||
conditional!(TL_CHANGED_CLASS_INST, class);
|
conditional!(TL_CHANGED_CLASS_INST, class);
|
||||||
conditional!(TL_CHANGED_CLASS_INST, instance);
|
conditional!(TL_CHANGED_CLASS_INST, instance);
|
||||||
|
conditional!(TL_CHANGED_ROLE, role);
|
||||||
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);
|
||||||
|
|
@ -355,6 +360,10 @@ impl TlMatcherManager {
|
||||||
pub fn instance(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
pub fn instance(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
||||||
self.root(TlmMatchInstance::new(string))
|
self.root(TlmMatchInstance::new(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn role(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
||||||
|
self.root(TlmMatchRole::new(string))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CritTarget for ToplevelData {
|
impl CritTarget for ToplevelData {
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,14 @@ pub type TlmMatchAppId = TlmMatchString<AppIdAccess>;
|
||||||
pub type TlmMatchTag = TlmMatchString<TagAccess>;
|
pub type TlmMatchTag = TlmMatchString<TagAccess>;
|
||||||
pub type TlmMatchClass = TlmMatchString<ClassAccess>;
|
pub type TlmMatchClass = TlmMatchString<ClassAccess>;
|
||||||
pub type TlmMatchInstance = TlmMatchString<InstanceAccess>;
|
pub type TlmMatchInstance = TlmMatchString<InstanceAccess>;
|
||||||
|
pub type TlmMatchRole = TlmMatchString<RoleAccess>;
|
||||||
|
|
||||||
pub struct TitleAccess;
|
pub struct TitleAccess;
|
||||||
pub struct AppIdAccess;
|
pub struct AppIdAccess;
|
||||||
pub struct TagAccess;
|
pub struct TagAccess;
|
||||||
pub struct ClassAccess;
|
pub struct ClassAccess;
|
||||||
pub struct InstanceAccess;
|
pub struct InstanceAccess;
|
||||||
|
pub struct RoleAccess;
|
||||||
|
|
||||||
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 {
|
||||||
|
|
@ -78,3 +80,16 @@ impl StringAccess<ToplevelData> for InstanceAccess {
|
||||||
&roots.instance
|
&roots.instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StringAccess<ToplevelData> for RoleAccess {
|
||||||
|
fn with_string(data: &ToplevelData, f: impl FnOnce(&str) -> bool) -> bool {
|
||||||
|
if let ToplevelType::XWindow(data) = &data.kind {
|
||||||
|
return f(&data.info.role.borrow().as_deref().unwrap_or_default());
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nodes(roots: &RootMatchers) -> &TlmRootMatcherMap<TlmMatchString<Self>> {
|
||||||
|
&roots.role
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ pub struct XwindowInfo {
|
||||||
pub instance: RefCell<Option<String>>,
|
pub instance: RefCell<Option<String>>,
|
||||||
pub class: RefCell<Option<String>>,
|
pub class: RefCell<Option<String>>,
|
||||||
pub title: RefCell<Option<String>>,
|
pub title: RefCell<Option<String>>,
|
||||||
pub role: RefCell<Option<BString>>,
|
pub role: RefCell<Option<String>>,
|
||||||
pub protocols: CopyHashMap<u32, ()>,
|
pub protocols: CopyHashMap<u32, ()>,
|
||||||
pub window_types: CopyHashMap<u32, ()>,
|
pub window_types: CopyHashMap<u32, ()>,
|
||||||
pub never_focus: Cell<bool>,
|
pub never_focus: Cell<bool>,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
client::Client,
|
client::Client,
|
||||||
criteria::tlm::TL_CHANGED_CLASS_INST,
|
criteria::tlm::{TL_CHANGED_CLASS_INST, TL_CHANGED_ROLE},
|
||||||
ifs::{
|
ifs::{
|
||||||
ipc::{
|
ipc::{
|
||||||
DataOfferId, DataSourceId, DynDataOffer, DynDataSource, IpcLocation, IpcVtable,
|
DataOfferId, DataSourceId, DynDataOffer, DynDataSource, IpcLocation, IpcVtable,
|
||||||
|
|
@ -60,7 +60,7 @@ use {
|
||||||
xwayland::{XWaylandError, XWaylandEvent},
|
xwayland::{XWaylandError, XWaylandEvent},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
bstr::ByteSlice,
|
bstr::{ByteSlice, ByteVec},
|
||||||
futures_util::{FutureExt, select},
|
futures_util::{FutureExt, select},
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -1086,6 +1086,11 @@ impl Wm {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_window_wm_window_role(&self, data: &Rc<XwindowData>) {
|
async fn load_window_wm_window_role(&self, data: &Rc<XwindowData>) {
|
||||||
|
let property_changed = || {
|
||||||
|
if let Some(window) = data.window.get() {
|
||||||
|
window.toplevel_data.property_changed(TL_CHANGED_ROLE);
|
||||||
|
}
|
||||||
|
};
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
match self
|
match self
|
||||||
.c
|
.c
|
||||||
|
|
@ -1101,6 +1106,7 @@ impl Wm {
|
||||||
}
|
}
|
||||||
Err(XconError::PropertyUnavailable) => {
|
Err(XconError::PropertyUnavailable) => {
|
||||||
data.info.role.borrow_mut().take();
|
data.info.role.borrow_mut().take();
|
||||||
|
property_changed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -1112,7 +1118,8 @@ impl Wm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// log::info!("{} role {}", data.window_id, buf.as_bstr());
|
// log::info!("{} role {}", data.window_id, buf.as_bstr());
|
||||||
*data.info.role.borrow_mut() = Some(buf.into());
|
*data.info.role.borrow_mut() = Some(buf.into_string_lossy());
|
||||||
|
property_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_window_wm_class(&self, data: &Rc<XwindowData>) {
|
async fn load_window_wm_class(&self, data: &Rc<XwindowData>) {
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,8 @@ pub struct WindowMatch {
|
||||||
pub x_class_regex: Option<String>,
|
pub x_class_regex: Option<String>,
|
||||||
pub x_instance: Option<String>,
|
pub x_instance: Option<String>,
|
||||||
pub x_instance_regex: Option<String>,
|
pub x_instance_regex: Option<String>,
|
||||||
|
pub x_role: Option<String>,
|
||||||
|
pub x_role_regex: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ impl Parser for WindowMatchParser<'_> {
|
||||||
tag,
|
tag,
|
||||||
tag_regex,
|
tag_regex,
|
||||||
),
|
),
|
||||||
(x_class, x_class_regex, x_instance, x_instance_regex),
|
(x_class, x_class_regex, x_instance, x_instance_regex, x_role, x_role_regex),
|
||||||
) = ext.extract((
|
) = ext.extract((
|
||||||
(
|
(
|
||||||
opt(str("name")),
|
opt(str("name")),
|
||||||
|
|
@ -98,6 +98,8 @@ impl Parser for WindowMatchParser<'_> {
|
||||||
opt(str("x-class-regex")),
|
opt(str("x-class-regex")),
|
||||||
opt(str("x-instance")),
|
opt(str("x-instance")),
|
||||||
opt(str("x-instance-regex")),
|
opt(str("x-instance-regex")),
|
||||||
|
opt(str("x-role")),
|
||||||
|
opt(str("x-role-regex")),
|
||||||
),
|
),
|
||||||
))?;
|
))?;
|
||||||
let mut not = None;
|
let mut not = None;
|
||||||
|
|
@ -155,6 +157,8 @@ impl Parser for WindowMatchParser<'_> {
|
||||||
x_class_regex: x_class_regex.despan_into(),
|
x_class_regex: x_class_regex.despan_into(),
|
||||||
x_instance: x_instance.despan_into(),
|
x_instance: x_instance.despan_into(),
|
||||||
x_instance_regex: x_instance_regex.despan_into(),
|
x_instance_regex: x_instance_regex.despan_into(),
|
||||||
|
x_role: x_role.despan_into(),
|
||||||
|
x_role_regex: x_role_regex.despan_into(),
|
||||||
types,
|
types,
|
||||||
client,
|
client,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,8 @@ impl Rule for WindowRule {
|
||||||
value!(XClassRegex, x_class_regex);
|
value!(XClassRegex, x_class_regex);
|
||||||
value!(XInstance, x_instance);
|
value!(XInstance, x_instance);
|
||||||
value!(XInstanceRegex, x_instance_regex);
|
value!(XInstanceRegex, x_instance_regex);
|
||||||
|
value!(XRole, x_role);
|
||||||
|
value!(XRoleRegex, x_role_regex);
|
||||||
bool!(Floating, floating);
|
bool!(Floating, floating);
|
||||||
bool!(Visible, visible);
|
bool!(Visible, visible);
|
||||||
bool!(Urgent, urgent);
|
bool!(Urgent, urgent);
|
||||||
|
|
|
||||||
|
|
@ -1843,6 +1843,14 @@
|
||||||
"x-instance-regex": {
|
"x-instance-regex": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Matches the X instance of the window with a regular expression."
|
"description": "Matches the X instance of the window with a regular expression."
|
||||||
|
},
|
||||||
|
"x-role": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Matches the X role of the window verbatim."
|
||||||
|
},
|
||||||
|
"x-role-regex": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Matches the X role of the window with a regular expression."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|
|
||||||
|
|
@ -4109,6 +4109,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.
|
||||||
|
|
||||||
|
- `x-role` (optional):
|
||||||
|
|
||||||
|
Matches the X role of the window verbatim.
|
||||||
|
|
||||||
|
The value of this field should be a string.
|
||||||
|
|
||||||
|
- `x-role-regex` (optional):
|
||||||
|
|
||||||
|
Matches the X role 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`
|
||||||
|
|
|
||||||
|
|
@ -3535,6 +3535,14 @@ WindowMatch:
|
||||||
kind: string
|
kind: string
|
||||||
required: false
|
required: false
|
||||||
description: Matches the X instance of the window with a regular expression.
|
description: Matches the X instance of the window with a regular expression.
|
||||||
|
x-role:
|
||||||
|
kind: string
|
||||||
|
required: false
|
||||||
|
description: Matches the X role of the window verbatim.
|
||||||
|
x-role-regex:
|
||||||
|
kind: string
|
||||||
|
required: false
|
||||||
|
description: Matches the X role of the window with a regular expression.
|
||||||
|
|
||||||
|
|
||||||
WindowMatchExactly:
|
WindowMatchExactly:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue