summaryrefslogtreecommitdiff
path: root/src/focus.rs
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-06-06 21:39:23 +0100
committertcmal <me@aria.rip>2024-06-06 21:39:23 +0100
commit66e3423828892a72e5e525f2dc8d5ad91e634445 (patch)
tree5dfd94005edbde91adc7a18e5b9a81a5c87816ec /src/focus.rs
parent266d39668bcee886cc7fecdb0f2c7b0b3302b20e (diff)
track focus and draw borders
Diffstat (limited to 'src/focus.rs')
-rw-r--r--src/focus.rs66
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());
+ }
}
}