use xcb::x::{ self, ChangeWindowAttributes, Cw, EnterNotifyEvent, FocusInEvent, InputFocus, NotifyDetail, NotifyMode, SetInputFocus, Window, }; use crate::{clients::Client, error::*, WM}; impl WM<'_> { 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(&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(()) } /// 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()); } } }