oxwm

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