oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
3,309 bytes raw
1
use std::io;
2
use std::process::Command;
3
4
use serde::Deserialize;
5
use x11rb::connection::Connection;
6
use x11rb::protocol::xproto::*;
7
8
use crate::errors::X11Error;
9
10
#[derive(Debug, Copy, Clone, Deserialize)]
11
pub enum KeyAction {
12
    Spawn,
13
    KillClient,
14
    FocusStack,
15
    Quit,
16
    Restart,
17
    Recompile,
18
    ViewTag,
19
    ToggleGaps,
20
    ToggleFullScreen,
21
    ToggleFloating,
22
    MoveToTag,
23
    None,
24
}
25
26
#[derive(Debug, Clone)]
27
pub enum Arg {
28
    None,
29
    Int(i32),
30
    Str(String),
31
    Array(Vec<String>),
32
}
33
34
impl Arg {
35
    pub const fn none() -> Self {
36
        Arg::None
37
    }
38
}
39
40
#[derive(Clone)]
41
pub struct Key {
42
    pub(crate) modifiers: Vec<KeyButMask>,
43
    pub(crate) key: Keycode,
44
    pub(crate) func: KeyAction,
45
    pub(crate) arg: Arg,
46
}
47
48
impl Key {
49
    pub fn new(modifiers: Vec<KeyButMask>, key: Keycode, func: KeyAction, arg: Arg) -> Self {
50
        Self {
51
            modifiers,
52
            key,
53
            func,
54
            arg,
55
        }
56
    }
57
}
58
59
fn modifiers_to_mask(modifiers: &[KeyButMask]) -> u16 {
60
    modifiers
61
        .iter()
62
        .fold(0u16, |acc, &modifier| acc | u16::from(modifier))
63
}
64
65
pub fn setup_keybinds(
66
    connection: &impl Connection,
67
    root: Window,
68
    keybindings: &[Key],
69
) -> Result<(), X11Error> {
70
    for keybinding in keybindings {
71
        let modifier_mask = modifiers_to_mask(&keybinding.modifiers);
72
73
        connection.grab_key(
74
            false,
75
            root,
76
            modifier_mask.into(),
77
            keybinding.key,
78
            GrabMode::ASYNC,
79
            GrabMode::ASYNC,
80
        )?;
81
    }
82
    Ok(())
83
}
84
85
pub fn handle_key_press(event: KeyPressEvent, keybindings: &[Key]) -> (KeyAction, Arg) {
86
    for keybinding in keybindings {
87
        let modifier_mask = modifiers_to_mask(&keybinding.modifiers);
88
89
        if event.detail == keybinding.key && event.state == modifier_mask.into() {
90
            return (keybinding.func, keybinding.arg.clone());
91
        }
92
    }
93
94
    (KeyAction::None, Arg::None)
95
}
96
97
pub fn handle_spawn_action(action: KeyAction, arg: &Arg) -> io::Result<()> {
98
    use io::ErrorKind;
99
    if let KeyAction::Spawn = action {
100
        match arg {
101
            Arg::Str(command) => match Command::new(command.as_str()).spawn() {
102
                Err(err) if err.kind() == ErrorKind::NotFound => {
103
                    eprintln!(
104
                        "KeyAction::Spawn failed: could not spawn \"{}\", command not found",
105
                        command
106
                    );
107
                }
108
                Err(err) => Err(err)?,
109
                _ => (),
110
            },
111
            Arg::Array(command) => {
112
                let Some((cmd, args)) = command.split_first() else {
113
                    return Ok(());
114
                };
115
116
                let args_str: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
117
                match Command::new(cmd.as_str()).args(&args_str).spawn() {
118
                    Err(err) if err.kind() == ErrorKind::NotFound => {
119
                        eprintln!(
120
                            "KeyAction::Spawn failed: could not spawn \"{}\", command not found",
121
                            cmd
122
                        );
123
                    }
124
                    Err(err) => Err(err)?,
125
                    _ => (),
126
                }
127
            }
128
            _ => {}
129
        }
130
    }
131
132
    Ok(())
133
}