use crate::{
contrib::actions::update_monitors_via_xrandr,
core::{
data_types::RelativePosition,
helpers::spawn,
hooks::Hook,
manager::WindowManager,
ring::Selector,
xconnection::{XConn, Xid},
},
Result,
};
use std::collections::HashMap;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ActiveClientAsRootName {}
impl ActiveClientAsRootName {
pub fn new() -> Box<Self> {
Box::new(Self {})
}
}
impl<X: XConn> Hook<X> for ActiveClientAsRootName {
fn new_client(&mut self, wm: &mut WindowManager<X>, id: Xid) -> Result<()> {
let c = wm.client(&Selector::WinId(id)).unwrap();
wm.set_root_window_name(c.wm_name())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct LayoutSymbolAsRootName {}
impl LayoutSymbolAsRootName {
pub fn new() -> Box<Self> {
Box::new(Self {})
}
}
impl<X: XConn> Hook<X> for LayoutSymbolAsRootName {
fn layout_change(&mut self, wm: &mut WindowManager<X>, _: usize, _: usize) -> Result<()> {
wm.set_root_window_name(wm.current_layout_symbol())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DefaultWorkspace {
defaults: Vec<String>,
layout: String,
name: String,
}
impl DefaultWorkspace {
pub fn new(
name: impl Into<String>,
layout: impl Into<String>,
defaults: Vec<impl Into<String>>,
) -> Box<Self> {
Box::new(Self {
name: name.into(),
layout: layout.into(),
defaults: defaults.into_iter().map(|d| d.into()).collect(),
})
}
}
impl<X: XConn> Hook<X> for DefaultWorkspace {
fn workspace_change(&mut self, wm: &mut WindowManager<X>, _: usize, new: usize) -> Result<()> {
if let Some(ws) = wm.workspace_mut(&Selector::Index(new)) {
if ws.name() == self.name && ws.is_empty() {
ws.try_set_layout(&self.layout);
return self.defaults.iter().try_for_each(spawn);
}
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct RemoveEmptyWorkspaces {
protected: Vec<String>,
}
impl RemoveEmptyWorkspaces {
pub fn new(protected: Vec<impl Into<String>>) -> Box<Self> {
Box::new(Self {
protected: protected.into_iter().map(|d| d.into()).collect(),
})
}
}
impl<X: XConn> Hook<X> for RemoveEmptyWorkspaces {
fn workspace_change(&mut self, wm: &mut WindowManager<X>, old: usize, _: usize) -> Result<()> {
let sel = Selector::Index(old);
if let Some(ws) = wm.workspace(&sel) {
if !self.protected.iter().any(|p| p == ws.name()) && ws.is_empty() {
wm.remove_workspace(&sel)?;
}
};
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum SpawnRule<'a> {
ClassName(&'a str, usize),
WMName(&'a str, usize),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClientSpawnRules {
class_rules: HashMap<String, usize>,
name_rules: HashMap<String, usize>,
}
impl ClientSpawnRules {
pub fn new(rules: Vec<SpawnRule<'_>>) -> Box<Self> {
let mut class_rules = HashMap::new();
let mut name_rules = HashMap::new();
for rule in rules.into_iter() {
match rule {
SpawnRule::ClassName(s, i) => class_rules.insert(s.into(), i),
SpawnRule::WMName(s, i) => name_rules.insert(s.into(), i),
};
}
Box::new(Self {
class_rules,
name_rules,
})
}
}
impl<X: XConn> Hook<X> for ClientSpawnRules {
fn new_client(&mut self, wm: &mut WindowManager<X>, id: Xid) -> Result<()> {
let c = wm.client_mut(&Selector::WinId(id)).unwrap();
if let Some(wix) = self.class_rules.get(c.wm_class()) {
c.set_workspace(*wix);
} else if let Some(wix) = self.name_rules.get(c.wm_name()) {
c.set_workspace(*wix);
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct AutoSetMonitorsViaXrandr {
primary: String,
secondary: String,
position: RelativePosition,
}
impl AutoSetMonitorsViaXrandr {
pub fn new(
primary: impl Into<String>,
secondary: impl Into<String>,
position: RelativePosition,
) -> Box<Self> {
Box::new(Self {
primary: primary.into(),
secondary: secondary.into(),
position,
})
}
}
impl<X> Hook<X> for AutoSetMonitorsViaXrandr
where
X: XConn,
{
fn randr_notify(&mut self, _: &mut WindowManager<X>) -> Result<()> {
update_monitors_via_xrandr(&self.primary, &self.secondary, self.position)
}
}
#[derive(Debug)]
pub struct ManageExistingClients {}
impl ManageExistingClients {
pub fn new() -> Box<Self> {
Box::new(Self {})
}
}
impl<X> Hook<X> for ManageExistingClients
where
X: XConn,
{
fn startup(&mut self, wm: &mut WindowManager<X>) -> Result<()> {
wm.try_manage_existing_windows()
}
}