diff options
author | tcmal <me@aria.rip> | 2024-06-06 21:39:23 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-06-06 21:39:23 +0100 |
commit | 66e3423828892a72e5e525f2dc8d5ad91e634445 (patch) | |
tree | 5dfd94005edbde91adc7a18e5b9a81a5c87816ec /src/focus.rs | |
parent | 266d39668bcee886cc7fecdb0f2c7b0b3302b20e (diff) |
track focus and draw borders
Diffstat (limited to 'src/focus.rs')
-rw-r--r-- | src/focus.rs | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/src/focus.rs b/src/focus.rs index ea4f021..a237e24 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -1,20 +1,68 @@ -use xcb::x::{EnterNotifyEvent, FocusInEvent, MotionNotifyEvent}; +use xcb::x::{ + self, ChangeWindowAttributes, Cw, EnterNotifyEvent, FocusInEvent, InputFocus, NotifyDetail, + NotifyMode, SetInputFocus, Window, +}; -use crate::{error::*, WM}; +use crate::{clients::Client, error::*, WM}; impl WM<'_> { - pub(crate) fn handle_enter_notify(&self, _e: EnterNotifyEvent) -> Result<()> { - // todo!() + pub(crate) fn handle_enter_notify(&mut self, e: EnterNotifyEvent) -> Result<()> { + if (e.mode() != NotifyMode::Normal || e.detail() == NotifyDetail::Inferior) + && e.event() != self.root + { + return Ok(()); + } + + self.focus_window(e.event()); + self.conn.flush()?; + Ok(()) } - pub(crate) fn handle_focus_in(&self, _e: FocusInEvent) -> Result<()> { - // todo!() + pub(crate) fn handle_focus_in(&mut self, e: FocusInEvent) -> Result<()> { + if self + .clients + .focused_mut() + .map(|c| c.window() != e.event()) + .unwrap_or(true) + { + self.focus_window(e.event()); + } Ok(()) } - pub(crate) fn handle_motion_notify(&self, _e: MotionNotifyEvent) -> Result<()> { - // todo!() - Ok(()) + /// Attempt to focus the given window, falling back to the root if the window isn't our client. + /// This function sends multiple requests without checking them, so conn.flush() should be called after. + pub fn focus_window(&mut self, window: Window) { + if let Some((mon, i)) = self.clients.find_client_pos(window) { + self.refocus(mon, i); + } else { + self.conn.send_request(&SetInputFocus { + revert_to: InputFocus::PointerRoot, + focus: window, + time: x::CURRENT_TIME, + }); + // TODO: XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + } + + /// Refocus on the client with the given co-ordinates, setting the X11 properties as required. + /// This function sends multiple requests without checking them, so conn.flush() should be called after. + pub fn refocus(&mut self, mon: usize, i: usize) { + self.unfocus(); + if let Some(new) = self.clients.set_focused(mon, i) { + new.set_border(self.conn, self.colours.border_focused()); + // TODO: reset urgent flag + // TODO: something to do with grabbuttons + // TODO: set input focus + // TODO: set active window + // TODO: send wmtakefocus event + } + } + + pub fn unfocus(&mut self) { + if let Some(old) = self.clients.focused_mut() { + old.set_border(self.conn, self.colours.border_normal()); + } } } |