1
0
Fork 0
forked from wry/wry

config: add window-rule infrastructure

This commit is contained in:
Julian Orth 2025-05-01 17:49:21 +02:00
parent a6257910bb
commit 59f8acdfde
26 changed files with 1829 additions and 38 deletions

View file

@ -14,7 +14,7 @@ use {
config::{
Action, ClientRule, Config, ConfigConnector, ConfigDrmDevice, ConfigKeymap,
ConnectorMatch, DrmDeviceMatch, Exec, Input, InputMatch, Output, OutputMatch, Shortcut,
SimpleCommand, Status, Theme, parse_config,
SimpleCommand, Status, Theme, WindowRule, parse_config,
},
rules::{MatcherTemp, RuleMapper},
},
@ -47,6 +47,7 @@ use {
on_new_connector, on_new_drm_device, set_direct_scanout_enabled, set_gfx_api,
set_tearing_mode, set_vrr_cursor_hz, set_vrr_mode,
},
window::Window,
xwayland::set_x_scaling_mode,
},
run_on_drop::on_drop,
@ -100,24 +101,39 @@ impl Action {
}};
}
let s = state.persistent.seat;
macro_rules! window_or_seat {
($name:ident, $expr:expr) => {{
let state = state.clone();
B::new(move || {
if let Some($name) = state.window.get() {
if let Some($name) = $name {
$expr;
}
} else {
let $name = s;
$expr;
}
})
}};
}
match self {
Action::SimpleCommand { cmd } => match cmd {
SimpleCommand::Focus(dir) => B::new(move || s.focus(dir)),
SimpleCommand::Move(dir) => B::new(move || s.move_(dir)),
SimpleCommand::Split(axis) => B::new(move || s.create_split(axis)),
SimpleCommand::ToggleSplit => B::new(move || s.toggle_split()),
SimpleCommand::SetSplit(b) => B::new(move || s.set_split(b)),
SimpleCommand::ToggleMono => B::new(move || s.toggle_mono()),
SimpleCommand::SetMono(b) => B::new(move || s.set_mono(b)),
SimpleCommand::ToggleFullscreen => B::new(move || s.toggle_fullscreen()),
SimpleCommand::SetFullscreen(b) => B::new(move || s.set_fullscreen(b)),
SimpleCommand::Move(dir) => window_or_seat!(s, s.move_(dir)),
SimpleCommand::Split(axis) => window_or_seat!(s, s.create_split(axis)),
SimpleCommand::ToggleSplit => window_or_seat!(s, s.toggle_split()),
SimpleCommand::SetSplit(b) => window_or_seat!(s, s.set_split(b)),
SimpleCommand::ToggleMono => window_or_seat!(s, s.toggle_mono()),
SimpleCommand::SetMono(b) => window_or_seat!(s, s.set_mono(b)),
SimpleCommand::ToggleFullscreen => window_or_seat!(s, s.toggle_fullscreen()),
SimpleCommand::SetFullscreen(b) => window_or_seat!(s, s.set_fullscreen(b)),
SimpleCommand::FocusParent => B::new(move || s.focus_parent()),
SimpleCommand::Close => B::new(move || s.close()),
SimpleCommand::Close => window_or_seat!(s, s.close()),
SimpleCommand::DisablePointerConstraint => {
B::new(move || s.disable_pointer_constraint())
}
SimpleCommand::ToggleFloating => B::new(move || s.toggle_floating()),
SimpleCommand::SetFloating(b) => B::new(move || s.set_floating(b)),
SimpleCommand::ToggleFloating => window_or_seat!(s, s.toggle_floating()),
SimpleCommand::SetFloating(b) => window_or_seat!(s, s.set_floating(b)),
SimpleCommand::Quit => B::new(quit),
SimpleCommand::ReloadConfigToml => {
let persistent = state.persistent.clone();
@ -133,8 +149,10 @@ impl Action {
B::new(move || set_float_above_fullscreen(bool))
}
SimpleCommand::ToggleFloatAboveFullscreen => B::new(toggle_float_above_fullscreen),
SimpleCommand::SetFloatPinned(pinned) => B::new(move || s.set_float_pinned(pinned)),
SimpleCommand::ToggleFloatPinned => B::new(move || s.toggle_float_pinned()),
SimpleCommand::SetFloatPinned(pinned) => {
window_or_seat!(s, s.set_float_pinned(pinned))
}
SimpleCommand::ToggleFloatPinned => window_or_seat!(s, s.toggle_float_pinned()),
SimpleCommand::KillClient => client_action!(c, c.kill()),
},
Action::Multi { actions } => {
@ -153,7 +171,7 @@ impl Action {
}
Action::MoveToWorkspace { name } => {
let workspace = get_workspace(&name);
B::new(move || s.set_workspace(workspace))
window_or_seat!(s, s.set_workspace(workspace))
}
Action::ConfigureConnector { con } => B::new(move || {
for c in connectors() {
@ -689,6 +707,8 @@ struct State {
action_depth: Cell<u64>,
client: Cell<Option<Client>>,
window: Cell<Option<Option<Window>>>,
}
impl Drop for State {
@ -897,13 +917,23 @@ impl State {
fn with_client(&self, client: Client, check: bool, f: impl FnOnce()) {
let mut opt = Some(client);
if check && client.does_not_exist() {
if client.0 == 0 || (check && client.does_not_exist()) {
opt = None;
}
self.client.set(opt);
f();
self.client.set(None);
}
fn with_window(&self, window: Window, check: bool, f: impl FnOnce()) {
let mut w = Some(window);
if check && !window.exists() {
w = None;
}
self.window.set(Some(w));
f();
self.window.set(None);
}
}
#[derive(Eq, PartialEq, Hash)]
@ -922,6 +952,7 @@ struct PersistentState {
actions: RefCell<AHashMap<Rc<String>, Rc<dyn Fn()>>>,
client_rules: Cell<Vec<MatcherTemp<ClientRule>>>,
client_rule_mapper: RefCell<Option<RuleMapper<ClientRule>>>,
window_rules: Cell<Vec<MatcherTemp<WindowRule>>>,
}
fn load_config(initial_load: bool, persistent: &Rc<PersistentState>) {
@ -1003,10 +1034,13 @@ fn load_config(initial_load: bool, persistent: &Rc<PersistentState>) {
action_depth_max: config.max_action_depth,
action_depth: Cell::new(0),
client: Default::default(),
window: Default::default(),
});
let (client_rules, client_rule_mapper) = state.create_rules(&config.client_rules);
persistent.client_rules.set(client_rules);
*state.persistent.client_rule_mapper.borrow_mut() = Some(client_rule_mapper);
let (window_rules, _) = state.create_rules(&config.window_rules);
persistent.window_rules.set(window_rules);
state.set_status(&config.status);
persistent.actions.borrow_mut().clear();
for a in config.named_actions {
@ -1231,6 +1265,7 @@ pub fn configure() {
actions: Default::default(),
client_rules: Default::default(),
client_rule_mapper: Default::default(),
window_rules: Default::default(),
});
{
let p = persistent.clone();