config: add workspace window criteria
This commit is contained in:
parent
5ad6ca4dd3
commit
51e752992f
13 changed files with 88 additions and 3 deletions
|
|
@ -5,6 +5,7 @@ pub(crate) mod string_error;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
Workspace,
|
||||||
client::ClientMatcher,
|
client::ClientMatcher,
|
||||||
input::Seat,
|
input::Seat,
|
||||||
video::Mode,
|
video::Mode,
|
||||||
|
|
@ -117,6 +118,7 @@ pub enum WindowCriterionIpc {
|
||||||
SeatFocus(Seat),
|
SeatFocus(Seat),
|
||||||
Fullscreen,
|
Fullscreen,
|
||||||
JustMapped,
|
JustMapped,
|
||||||
|
Workspace(Workspace),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
|
|
@ -127,4 +129,5 @@ pub enum WindowCriterionStringField {
|
||||||
XClass,
|
XClass,
|
||||||
XInstance,
|
XInstance,
|
||||||
XRole,
|
XRole,
|
||||||
|
Workspace,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1671,6 +1671,9 @@ impl ConfigClient {
|
||||||
WindowCriterion::XInstanceRegex(t) => string!(t, XInstance, true),
|
WindowCriterion::XInstanceRegex(t) => string!(t, XInstance, true),
|
||||||
WindowCriterion::XRole(t) => string!(t, XRole, false),
|
WindowCriterion::XRole(t) => string!(t, XRole, false),
|
||||||
WindowCriterion::XRoleRegex(t) => string!(t, XRole, true),
|
WindowCriterion::XRoleRegex(t) => string!(t, XRole, true),
|
||||||
|
WindowCriterion::Workspace(t) => WindowCriterionIpc::Workspace(t),
|
||||||
|
WindowCriterion::WorkspaceName(t) => string!(t, Workspace, false),
|
||||||
|
WindowCriterion::WorkspaceNameRegex(t) => string!(t, Workspace, true),
|
||||||
};
|
};
|
||||||
let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion });
|
let res = self.send_with_response(&ClientMessage::CreateWindowMatcher { criterion });
|
||||||
get_response!(
|
get_response!(
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,12 @@ pub enum WindowCriterion<'a> {
|
||||||
XRole(&'a str),
|
XRole(&'a str),
|
||||||
/// Matches the X role of the window with a regular expression.
|
/// Matches the X role of the window with a regular expression.
|
||||||
XRoleRegex(&'a str),
|
XRoleRegex(&'a str),
|
||||||
|
/// Matches the workspace the window.
|
||||||
|
Workspace(Workspace),
|
||||||
|
/// Matches the workspace name of the window verbatim.
|
||||||
|
WorkspaceName(&'a str),
|
||||||
|
/// Matches the workspace name of the window with a regular expression.
|
||||||
|
WorkspaceNameRegex(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowCriterion<'_> {
|
impl WindowCriterion<'_> {
|
||||||
|
|
|
||||||
|
|
@ -1994,6 +1994,7 @@ impl ConfigProxyHandler {
|
||||||
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),
|
WindowCriterionStringField::XRole => mgr.role(needle),
|
||||||
|
WindowCriterionStringField::Workspace => mgr.workspace(needle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowCriterionIpc::Types(t) => mgr.kind(*t),
|
WindowCriterionIpc::Types(t) => mgr.kind(*t),
|
||||||
|
|
@ -2007,6 +2008,9 @@ impl ConfigProxyHandler {
|
||||||
WindowCriterionIpc::SeatFocus(seat) => mgr.seat_focus(&*self.get_seat(*seat)?),
|
WindowCriterionIpc::SeatFocus(seat) => mgr.seat_focus(&*self.get_seat(*seat)?),
|
||||||
WindowCriterionIpc::Fullscreen => mgr.fullscreen(),
|
WindowCriterionIpc::Fullscreen => mgr.fullscreen(),
|
||||||
WindowCriterionIpc::JustMapped => mgr.just_mapped(),
|
WindowCriterionIpc::JustMapped => mgr.just_mapped(),
|
||||||
|
WindowCriterionIpc::Workspace(w) => mgr.workspace(CritLiteralOrRegex::Literal(
|
||||||
|
self.get_workspace(*w)?.to_string(),
|
||||||
|
)),
|
||||||
};
|
};
|
||||||
let cached = Rc::new(CachedCriterion {
|
let cached = Rc::new(CachedCriterion {
|
||||||
crit: criterion.clone(),
|
crit: criterion.clone(),
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use {
|
||||||
tlmm_seat_focus::TlmMatchSeatFocus,
|
tlmm_seat_focus::TlmMatchSeatFocus,
|
||||||
tlmm_string::{
|
tlmm_string::{
|
||||||
TlmMatchAppId, TlmMatchClass, TlmMatchInstance, TlmMatchRole, TlmMatchTag,
|
TlmMatchAppId, TlmMatchClass, TlmMatchInstance, TlmMatchRole, TlmMatchTag,
|
||||||
TlmMatchTitle,
|
TlmMatchTitle, TlmMatchWorkspace,
|
||||||
},
|
},
|
||||||
tlmm_urgent::TlmMatchUrgent,
|
tlmm_urgent::TlmMatchUrgent,
|
||||||
tlmm_visible::TlmMatchVisible,
|
tlmm_visible::TlmMatchVisible,
|
||||||
|
|
@ -57,6 +57,7 @@ bitflags! {
|
||||||
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,
|
TL_CHANGED_ROLE = 1 << 12,
|
||||||
|
TL_CHANGED_WORKSPACE = 1 << 13,
|
||||||
}
|
}
|
||||||
|
|
||||||
type TlmFixedRootMatcher<T> = FixedRootMatcher<ToplevelData, T>;
|
type TlmFixedRootMatcher<T> = FixedRootMatcher<ToplevelData, T>;
|
||||||
|
|
@ -88,6 +89,7 @@ pub struct RootMatchers {
|
||||||
class: TlmRootMatcherMap<TlmMatchClass>,
|
class: TlmRootMatcherMap<TlmMatchClass>,
|
||||||
instance: TlmRootMatcherMap<TlmMatchInstance>,
|
instance: TlmRootMatcherMap<TlmMatchInstance>,
|
||||||
role: TlmRootMatcherMap<TlmMatchRole>,
|
role: TlmRootMatcherMap<TlmMatchRole>,
|
||||||
|
workspace: TlmRootMatcherMap<TlmMatchWorkspace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_tl_changes(state: Rc<State>) {
|
pub async fn handle_tl_changes(state: Rc<State>) {
|
||||||
|
|
@ -219,6 +221,7 @@ impl TlMatcherManager {
|
||||||
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);
|
conditional!(TL_CHANGED_ROLE, role);
|
||||||
|
conditional!(TL_CHANGED_WORKSPACE, workspace);
|
||||||
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);
|
||||||
|
|
@ -295,6 +298,7 @@ impl TlMatcherManager {
|
||||||
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);
|
conditional!(TL_CHANGED_ROLE, role);
|
||||||
|
conditional!(TL_CHANGED_WORKSPACE, workspace);
|
||||||
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);
|
||||||
|
|
@ -364,6 +368,10 @@ impl TlMatcherManager {
|
||||||
pub fn role(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
pub fn role(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
||||||
self.root(TlmMatchRole::new(string))
|
self.root(TlmMatchRole::new(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn workspace(&self, string: CritLiteralOrRegex) -> Rc<TlmUpstreamNode> {
|
||||||
|
self.root(TlmMatchWorkspace::new(string))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CritTarget for ToplevelData {
|
impl CritTarget for ToplevelData {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ 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 type TlmMatchRole = TlmMatchString<RoleAccess>;
|
||||||
|
pub type TlmMatchWorkspace = TlmMatchString<WorkspaceAccess>;
|
||||||
|
|
||||||
pub struct TitleAccess;
|
pub struct TitleAccess;
|
||||||
pub struct AppIdAccess;
|
pub struct AppIdAccess;
|
||||||
|
|
@ -21,6 +22,7 @@ pub struct TagAccess;
|
||||||
pub struct ClassAccess;
|
pub struct ClassAccess;
|
||||||
pub struct InstanceAccess;
|
pub struct InstanceAccess;
|
||||||
pub struct RoleAccess;
|
pub struct RoleAccess;
|
||||||
|
pub struct WorkspaceAccess;
|
||||||
|
|
||||||
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 {
|
||||||
|
|
@ -93,3 +95,16 @@ impl StringAccess<ToplevelData> for RoleAccess {
|
||||||
&roots.role
|
&roots.role
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StringAccess<ToplevelData> for WorkspaceAccess {
|
||||||
|
fn with_string(data: &ToplevelData, f: impl FnOnce(&str) -> bool) -> bool {
|
||||||
|
if let Some(ws) = data.workspace.get() {
|
||||||
|
return f(&ws.name);
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nodes(roots: &RootMatchers) -> &TlmRootMatcherMap<TlmMatchString<Self>> {
|
||||||
|
&roots.workspace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use {
|
||||||
tlm::{
|
tlm::{
|
||||||
TL_CHANGED_APP_ID, TL_CHANGED_DESTROYED, TL_CHANGED_FLOATING,
|
TL_CHANGED_APP_ID, TL_CHANGED_DESTROYED, TL_CHANGED_FLOATING,
|
||||||
TL_CHANGED_FULLSCREEN, TL_CHANGED_NEW, TL_CHANGED_TITLE, TL_CHANGED_URGENT,
|
TL_CHANGED_FULLSCREEN, TL_CHANGED_NEW, TL_CHANGED_TITLE, TL_CHANGED_URGENT,
|
||||||
TL_CHANGED_VISIBLE, TlMatcherChange,
|
TL_CHANGED_VISIBLE, TL_CHANGED_WORKSPACE, TlMatcherChange,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ifs::{
|
ifs::{
|
||||||
|
|
@ -131,6 +131,7 @@ impl<T: ToplevelNodeBase> ToplevelNode for T {
|
||||||
let data = self.tl_data();
|
let data = self.tl_data();
|
||||||
let prev = data.workspace.set(Some(ws.clone()));
|
let prev = data.workspace.set(Some(ws.clone()));
|
||||||
self.tl_set_workspace_ext(ws);
|
self.tl_set_workspace_ext(ws);
|
||||||
|
self.tl_data().property_changed(TL_CHANGED_WORKSPACE);
|
||||||
let prev_id = prev.map(|p| p.output.get().id);
|
let prev_id = prev.map(|p| p.output.get().id);
|
||||||
let new_id = Some(ws.output.get().id);
|
let new_id = Some(ws.output.get().id);
|
||||||
if prev_id != new_id {
|
if prev_id != new_id {
|
||||||
|
|
|
||||||
|
|
@ -273,6 +273,8 @@ pub struct WindowMatch {
|
||||||
pub x_instance_regex: Option<String>,
|
pub x_instance_regex: Option<String>,
|
||||||
pub x_role: Option<String>,
|
pub x_role: Option<String>,
|
||||||
pub x_role_regex: Option<String>,
|
pub x_role_regex: Option<String>,
|
||||||
|
pub workspace: Option<String>,
|
||||||
|
pub workspace_regex: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,16 @@ impl Parser for WindowMatchParser<'_> {
|
||||||
tag,
|
tag,
|
||||||
tag_regex,
|
tag_regex,
|
||||||
),
|
),
|
||||||
(x_class, x_class_regex, x_instance, x_instance_regex, x_role, x_role_regex),
|
(
|
||||||
|
x_class,
|
||||||
|
x_class_regex,
|
||||||
|
x_instance,
|
||||||
|
x_instance_regex,
|
||||||
|
x_role,
|
||||||
|
x_role_regex,
|
||||||
|
workspace,
|
||||||
|
workspace_regex,
|
||||||
|
),
|
||||||
) = ext.extract((
|
) = ext.extract((
|
||||||
(
|
(
|
||||||
opt(str("name")),
|
opt(str("name")),
|
||||||
|
|
@ -100,6 +109,8 @@ impl Parser for WindowMatchParser<'_> {
|
||||||
opt(str("x-instance-regex")),
|
opt(str("x-instance-regex")),
|
||||||
opt(str("x-role")),
|
opt(str("x-role")),
|
||||||
opt(str("x-role-regex")),
|
opt(str("x-role-regex")),
|
||||||
|
opt(str("workspace")),
|
||||||
|
opt(str("workspace-regex")),
|
||||||
),
|
),
|
||||||
))?;
|
))?;
|
||||||
let mut not = None;
|
let mut not = None;
|
||||||
|
|
@ -159,6 +170,8 @@ impl Parser for WindowMatchParser<'_> {
|
||||||
x_instance_regex: x_instance_regex.despan_into(),
|
x_instance_regex: x_instance_regex.despan_into(),
|
||||||
x_role: x_role.despan_into(),
|
x_role: x_role.despan_into(),
|
||||||
x_role_regex: x_role_regex.despan_into(),
|
x_role_regex: x_role_regex.despan_into(),
|
||||||
|
workspace: workspace.despan_into(),
|
||||||
|
workspace_regex: workspace_regex.despan_into(),
|
||||||
types,
|
types,
|
||||||
client,
|
client,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,8 @@ impl Rule for WindowRule {
|
||||||
value!(XInstanceRegex, x_instance_regex);
|
value!(XInstanceRegex, x_instance_regex);
|
||||||
value!(XRole, x_role);
|
value!(XRole, x_role);
|
||||||
value!(XRoleRegex, x_role_regex);
|
value!(XRoleRegex, x_role_regex);
|
||||||
|
value!(WorkspaceName, workspace);
|
||||||
|
value!(WorkspaceNameRegex, workspace_regex);
|
||||||
bool!(Floating, floating);
|
bool!(Floating, floating);
|
||||||
bool!(Visible, visible);
|
bool!(Visible, visible);
|
||||||
bool!(Urgent, urgent);
|
bool!(Urgent, urgent);
|
||||||
|
|
|
||||||
|
|
@ -1851,6 +1851,14 @@
|
||||||
"x-role-regex": {
|
"x-role-regex": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Matches the X role of the window with a regular expression."
|
"description": "Matches the X role of the window with a regular expression."
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Matches the workspace of the window verbatim."
|
||||||
|
},
|
||||||
|
"workspace-regex": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Matches the workspace of the window with a regular expression."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|
|
||||||
|
|
@ -4121,6 +4121,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.
|
||||||
|
|
||||||
|
- `workspace` (optional):
|
||||||
|
|
||||||
|
Matches the workspace of the window verbatim.
|
||||||
|
|
||||||
|
The value of this field should be a string.
|
||||||
|
|
||||||
|
- `workspace-regex` (optional):
|
||||||
|
|
||||||
|
Matches the workspace 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`
|
||||||
|
|
|
||||||
|
|
@ -3543,6 +3543,14 @@ WindowMatch:
|
||||||
kind: string
|
kind: string
|
||||||
required: false
|
required: false
|
||||||
description: Matches the X role of the window with a regular expression.
|
description: Matches the X role of the window with a regular expression.
|
||||||
|
workspace:
|
||||||
|
kind: string
|
||||||
|
required: false
|
||||||
|
description: Matches the workspace of the window verbatim.
|
||||||
|
workspace-regex:
|
||||||
|
kind: string
|
||||||
|
required: false
|
||||||
|
description: Matches the workspace of the window with a regular expression.
|
||||||
|
|
||||||
|
|
||||||
WindowMatchExactly:
|
WindowMatchExactly:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue