oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
4,508 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 layout_symbol: String,
11
    pub master_factor: f32,
12
    pub num_master: i32,
13
    pub monitor_number: usize,
14
    pub bar_y_position: i32,
15
    pub screen_x: i32,
16
    pub screen_y: i32,
17
    pub screen_width: i32,
18
    pub screen_height: i32,
19
    pub window_area_x: i32,
20
    pub window_area_y: i32,
21
    pub window_area_width: i32,
22
    pub window_area_height: i32,
23
    pub gap_inner_horizontal: i32,
24
    pub gap_inner_vertical: i32,
25
    pub gap_outer_horizontal: i32,
26
    pub gap_outer_vertical: i32,
27
    pub selected_tags_index: usize,
28
    pub selected_layout_index: usize,
29
    pub tagset: [u32; 2],
30
    pub show_bar: bool,
31
    pub top_bar: bool,
32
    pub clients_head: Option<Window>,
33
    pub selected_client: Option<Window>,
34
    pub stack_head: Option<Window>,
35
    pub bar_window: Option<Window>,
36
    pub layout_indices: [usize; 2],
37
}
38
39
impl Monitor {
40
    pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
41
        Self {
42
            layout_symbol: String::from("[]"),
43
            master_factor: 0.55,
44
            num_master: 1,
45
            monitor_number: 0,
46
            bar_y_position: 0,
47
            screen_x: x,
48
            screen_y: y,
49
            screen_width: width as i32,
50
            screen_height: height as i32,
51
            window_area_x: x,
52
            window_area_y: y,
53
            window_area_width: width as i32,
54
            window_area_height: height as i32,
55
            gap_inner_horizontal: 3,
56
            gap_inner_vertical: 3,
57
            gap_outer_horizontal: 3,
58
            gap_outer_vertical: 3,
59
            selected_tags_index: 0,
60
            selected_layout_index: 0,
61
            tagset: [1, 1],
62
            show_bar: true,
63
            top_bar: true,
64
            clients_head: None,
65
            selected_client: None,
66
            stack_head: None,
67
            bar_window: None,
68
            layout_indices: [0, 1],
69
        }
70
    }
71
72
    pub fn contains_point(&self, x: i32, y: i32) -> bool {
73
        x >= self.screen_x
74
            && x < self.screen_x + self.screen_width
75
            && y >= self.screen_y
76
            && y < self.screen_y + self.screen_height
77
    }
78
}
79
80
pub fn detect_monitors(
81
    connection: &RustConnection,
82
    screen: &Screen,
83
    _root: Window,
84
) -> WmResult<Vec<Monitor>> {
85
    let fallback_monitors = || {
86
        vec![Monitor::new(
87
            0,
88
            0,
89
            screen.width_in_pixels as u32,
90
            screen.height_in_pixels as u32,
91
        )]
92
    };
93
94
    let mut monitors = Vec::<Monitor>::new();
95
96
    let xinerama_active = connection
97
        .xinerama_is_active()
98
        .ok()
99
        .and_then(|cookie| cookie.reply().ok())
100
        .map_or(false, |reply| reply.state != 0);
101
102
    if xinerama_active {
103
        let Ok(xinerama_cookie) = connection.xinerama_query_screens() else {
104
            return Ok(fallback_monitors());
105
        };
106
        let Ok(xinerama_reply) = xinerama_cookie.reply() else {
107
            return Ok(fallback_monitors());
108
        };
109
110
        for screen_info in &xinerama_reply.screen_info {
111
            let has_valid_dimensions = screen_info.width > 0 && screen_info.height > 0;
112
            if !has_valid_dimensions {
113
                continue;
114
            }
115
116
            let x_position = screen_info.x_org as i32;
117
            let y_position = screen_info.y_org as i32;
118
            let width_in_pixels = screen_info.width as u32;
119
            let height_in_pixels = screen_info.height as u32;
120
121
            let is_duplicate_monitor = monitors.iter().any(|monitor| {
122
                monitor.screen_x == x_position
123
                    && monitor.screen_y == y_position
124
                    && monitor.screen_width == width_in_pixels as i32
125
                    && monitor.screen_height == height_in_pixels as i32
126
            });
127
128
            if !is_duplicate_monitor {
129
                monitors.push(Monitor::new(
130
                    x_position,
131
                    y_position,
132
                    width_in_pixels,
133
                    height_in_pixels,
134
                ));
135
            }
136
        }
137
    }
138
139
    if monitors.is_empty() {
140
        monitors = fallback_monitors();
141
    }
142
143
    monitors.sort_by(|a, b| match a.screen_y.cmp(&b.screen_y) {
144
        std::cmp::Ordering::Equal => a.screen_x.cmp(&b.screen_x),
145
        other => other,
146
    });
147
148
    Ok(monitors)
149
}