summaryrefslogtreecommitdiff
path: root/src/focus.rs
blob: a237e24cb5ae18e1261b3958fc315ae284abd738 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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());
        }
    }
}