oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
2,931 bytes raw
1
use crate::errors::WmError;
2
use x11rb::protocol::xinerama::ConnectionExt as _;
3
use x11rb::protocol::xproto::{Screen, Window};
4
use x11rb::rust_connection::RustConnection;
5
6
type WmResult<T> = Result<T, WmError>;
7
8
#[derive(Debug, Clone)]
9
pub struct Monitor {
10
    pub x: i32,
11
    pub y: i32,
12
    pub width: u32,
13
    pub height: u32,
14
    pub selected_tags: u32,
15
    pub focused_window: Option<Window>,
16
}
17
18
impl Monitor {
19
    pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
20
        Self {
21
            x,
22
            y,
23
            width,
24
            height,
25
            selected_tags: 1,
26
            focused_window: None,
27
        }
28
    }
29
30
    pub fn contains_point(&self, x: i32, y: i32) -> bool {
31
        x >= self.x
32
            && x < self.x + self.width as i32
33
            && y >= self.y
34
            && y < self.y + self.height as i32
35
    }
36
}
37
38
pub fn detect_monitors(
39
    connection: &RustConnection,
40
    screen: &Screen,
41
    _root: Window,
42
) -> WmResult<Vec<Monitor>> {
43
    let fallback_monitors = || {
44
        vec![Monitor::new(
45
            0,
46
            0,
47
            screen.width_in_pixels as u32,
48
            screen.height_in_pixels as u32,
49
        )]
50
    };
51
52
    let mut monitors = Vec::<Monitor>::new();
53
54
    let xinerama_active = connection
55
        .xinerama_is_active()
56
        .ok()
57
        .and_then(|cookie| cookie.reply().ok())
58
        .map_or(false, |reply| reply.state != 0);
59
60
    if xinerama_active {
61
        let Ok(xinerama_cookie) = connection.xinerama_query_screens() else {
62
            return Ok(fallback_monitors());
63
        };
64
        let Ok(xinerama_reply) = xinerama_cookie.reply() else {
65
            return Ok(fallback_monitors());
66
        };
67
68
        for screen_info in &xinerama_reply.screen_info {
69
            let has_valid_dimensions = screen_info.width > 0 && screen_info.height > 0;
70
            if !has_valid_dimensions {
71
                continue;
72
            }
73
74
            let x_position = screen_info.x_org as i32;
75
            let y_position = screen_info.y_org as i32;
76
            let width_in_pixels = screen_info.width as u32;
77
            let height_in_pixels = screen_info.height as u32;
78
79
            let is_duplicate_monitor = monitors.iter().any(|monitor| {
80
                monitor.x == x_position
81
                    && monitor.y == y_position
82
                    && monitor.width == width_in_pixels
83
                    && monitor.height == height_in_pixels
84
            });
85
86
            if !is_duplicate_monitor {
87
                monitors.push(Monitor::new(
88
                    x_position,
89
                    y_position,
90
                    width_in_pixels,
91
                    height_in_pixels,
92
                ));
93
            }
94
        }
95
    }
96
97
    if monitors.is_empty() {
98
        monitors = fallback_monitors();
99
    }
100
101
    monitors.sort_by(|a, b| match a.y.cmp(&b.y) {
102
        std::cmp::Ordering::Equal => a.x.cmp(&b.x),
103
        other => other,
104
    });
105
106
    Ok(monitors)
107
}