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
69
70
71
72
73
74
75
76
77
78
79
80
|
use xcb::x::{
self, DeleteProperty, EnterNotifyEvent, FocusInEvent, InputFocus, NotifyDetail, NotifyMode,
SetInputFocus, Window,
};
use crate::{error::*, WM};
impl WM<'_> {
/// When a new window is entered, focus it.
pub 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(())
}
/// When a new window requests focus, focus it.
pub 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());
self.conn.flush()?;
}
Ok(())
}
/// Attempt to focus the given window, even if it isn't managed.
/// 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,
});
self.conn.send_request(&DeleteProperty {
window,
property: self.atoms.net_active_window,
});
}
}
/// Refocus on the client with the given co-ordinates, setting X11 properties as required.
/// If the given index is invalid, focus on the root instead.
/// 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
} else {
// TODO: focus on root
}
}
/// Unfocus the currently focused window, if it exists.
/// This function sends multiple requests without checking them, so `conn.flush()` should be called after.
pub fn unfocus(&mut self) {
if let Some(old) = self.clients.focused_mut() {
old.set_border(self.conn, self.colours.border_normal());
}
}
}
|