lefthk_core/worker/
mod.rs1pub mod context;
2
3use crate::child::Children;
4use crate::config::{Keybind, command};
5use crate::errors::{self, Error, LeftError};
6use crate::ipc::Pipe;
7use crate::xkeysym_lookup;
8use crate::xwrap::XWrap;
9use x11_dl::xlib;
10use xdg::BaseDirectories;
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub enum Status {
14 Reload,
15 Kill,
16 Continue,
17}
18
19pub struct Worker {
20 keybinds: Vec<Keybind>,
21 base_directory: BaseDirectories,
22
23 pub xwrap: XWrap,
24 pub children: Children,
25 pub status: Status,
26
27 pub chord_ctx: context::Chord,
29}
30
31impl Worker {
32 #[must_use]
33 pub fn new(keybinds: Vec<Keybind>, base_directory: BaseDirectories) -> Self {
34 Self {
35 status: Status::Continue,
36 keybinds,
37 base_directory,
38 xwrap: XWrap::new(),
39 children: Children::default(),
40 chord_ctx: context::Chord::new(),
41 }
42 }
43
44 pub async fn event_loop(mut self) -> Status {
45 self.xwrap.grab_keys(&self.keybinds);
46 let mut pipe = self.get_pipe().await;
47
48 while self.status == Status::Continue {
49 self.xwrap.flush();
50
51 self.evaluate_chord();
52
53 tokio::select! {
54 () = self.children.wait_readable() => {
55 self.children.reap();
56 }
57 () = self.xwrap.wait_readable() => {
58 let event_in_queue = self.xwrap.queue_len();
59 for _ in 0..event_in_queue {
60 let xlib_event = self.xwrap.get_next_event();
61 self.handle_event(&xlib_event);
62 }
63 }
64 Some(command) = pipe.get_next_command() => {
65 errors::log_on_error!(command.execute(&mut self));
66 }
67 };
68 }
69
70 self.status
71 }
72
73 async fn get_pipe(&self) -> Pipe {
74 let pipe_name = Pipe::pipe_name();
75 let pipe_file = errors::exit_on_error!(self.base_directory.place_runtime_file(pipe_name));
76 errors::exit_on_error!(Pipe::new(pipe_file).await)
77 }
78
79 fn handle_event(&mut self, xlib_event: &xlib::XEvent) {
80 let error = match xlib_event.get_type() {
81 xlib::KeyPress => self.handle_key_press(&xlib::XKeyEvent::from(xlib_event)),
82 xlib::MappingNotify => {
83 self.handle_mapping_notify(&mut xlib::XMappingEvent::from(xlib_event))
84 }
85 _ => return,
86 };
87 errors::log_on_error!(error);
88 }
89
90 fn handle_key_press(&mut self, event: &xlib::XKeyEvent) -> Error {
91 let key = self.xwrap.keycode_to_keysym(event.keycode)?;
92 let mask = xkeysym_lookup::clean_mask(event.state);
93 if let Some(keybind) = self.get_keybind((mask, key)) {
94 if let Ok(command) = command::denormalize(&keybind.command) {
95 return command.execute(self);
96 }
97 } else {
98 return Err(LeftError::CommandNotFound);
99 }
100 Ok(())
101 }
102
103 fn get_keybind(&self, mask_key_pair: (u32, u32)) -> Option<Keybind> {
104 let keybinds = if let Some(keybinds) = &self.chord_ctx.keybinds {
105 keybinds
106 } else {
107 &self.keybinds
108 };
109 keybinds
110 .iter()
111 .find(|keybind| {
112 if let Some(key) = xkeysym_lookup::into_keysym(&keybind.key) {
113 let mask = xkeysym_lookup::into_modmask(&keybind.modifier);
114 return mask_key_pair == (mask, key);
115 }
116 false
117 })
118 .cloned()
119 }
120
121 fn handle_mapping_notify(&self, event: &mut xlib::XMappingEvent) -> Error {
122 if event.request == xlib::MappingModifier || event.request == xlib::MappingKeyboard {
123 return self.xwrap.refresh_keyboard(event);
124 }
125 Ok(())
126 }
127}