oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
5,807 bytes raw
1
use crate::client::TagMask;
2
use crate::errors::WmError;
3
use x11rb::protocol::xinerama::ConnectionExt as _;
4
use x11rb::protocol::xproto::{Screen, Window};
5
use x11rb::rust_connection::RustConnection;
6
7
type WmResult<T> = Result<T, WmError>;
8
9
#[derive(Debug, Clone)]
10
pub struct Pertag {
11
    pub current_tag: usize,
12
    pub previous_tag: usize,
13
    pub num_masters: Vec<i32>,
14
    pub master_factors: Vec<f32>,
15
    pub layouts: Vec<String>,
16
    pub show_bars: Vec<bool>,
17
}
18
19
impl Pertag {
20
    pub fn new(
21
        num_tags: usize,
22
        default_num_master: i32,
23
        default_master_factor: f32,
24
        default_show_bar: bool,
25
        default_layout: &str,
26
    ) -> Self {
27
        let len = num_tags + 1;
28
        Self {
29
            current_tag: 1,
30
            previous_tag: 1,
31
            num_masters: vec![default_num_master; len],
32
            master_factors: vec![default_master_factor; len],
33
            layouts: vec![default_layout.to_string(); len],
34
            show_bars: vec![default_show_bar; len],
35
        }
36
    }
37
}
38
39
#[derive(Debug, Clone)]
40
pub struct Monitor {
41
    pub layout_symbol: String,
42
    pub master_factor: f32,
43
    pub num_master: i32,
44
    pub monitor_number: usize,
45
    pub bar_y_position: i32,
46
    pub screen_x: i32,
47
    pub screen_y: i32,
48
    pub screen_width: i32,
49
    pub screen_height: i32,
50
    pub window_area_x: i32,
51
    pub window_area_y: i32,
52
    pub window_area_width: i32,
53
    pub window_area_height: i32,
54
    pub gap_inner_horizontal: i32,
55
    pub gap_inner_vertical: i32,
56
    pub gap_outer_horizontal: i32,
57
    pub gap_outer_vertical: i32,
58
    pub selected_tags_index: usize,
59
    pub selected_layout_index: usize,
60
    pub tagset: [u32; 2],
61
    pub show_bar: bool,
62
    pub top_bar: bool,
63
    pub clients_head: Option<Window>,
64
    pub selected_client: Option<Window>,
65
    pub stack_head: Option<Window>,
66
    pub bar_window: Option<Window>,
67
    pub layout_indices: [usize; 2],
68
    pub scroll_offset: i32,
69
    pub pertag: Option<Pertag>,
70
}
71
72
impl Monitor {
73
    pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
74
        Self {
75
            layout_symbol: String::from("[]"),
76
            master_factor: 0.55,
77
            num_master: 1,
78
            monitor_number: 0,
79
            bar_y_position: 0,
80
            screen_x: x,
81
            screen_y: y,
82
            screen_width: width as i32,
83
            screen_height: height as i32,
84
            window_area_x: x,
85
            window_area_y: y,
86
            window_area_width: width as i32,
87
            window_area_height: height as i32,
88
            gap_inner_horizontal: 3,
89
            gap_inner_vertical: 3,
90
            gap_outer_horizontal: 3,
91
            gap_outer_vertical: 3,
92
            selected_tags_index: 0,
93
            selected_layout_index: 0,
94
            tagset: [1, 1],
95
            show_bar: true,
96
            top_bar: true,
97
            clients_head: None,
98
            selected_client: None,
99
            stack_head: None,
100
            bar_window: None,
101
            layout_indices: [0, 1],
102
            scroll_offset: 0,
103
            pertag: None,
104
        }
105
    }
106
107
    pub fn init_pertag(&mut self, num_tags: usize, default_layout: &str) {
108
        self.pertag = Some(Pertag::new(
109
            num_tags,
110
            self.num_master,
111
            self.master_factor,
112
            self.show_bar,
113
            default_layout,
114
        ));
115
    }
116
117
    pub fn contains_point(&self, x: i32, y: i32) -> bool {
118
        x >= self.screen_x
119
            && x < self.screen_x + self.screen_width
120
            && y >= self.screen_y
121
            && y < self.screen_y + self.screen_height
122
    }
123
124
    pub fn get_selected_tag(&self) -> TagMask {
125
        self.tagset[self.selected_tags_index]
126
    }
127
}
128
129
pub fn detect_monitors(
130
    connection: &RustConnection,
131
    screen: &Screen,
132
    _root: Window,
133
) -> WmResult<Vec<Monitor>> {
134
    let fallback_monitors = || {
135
        vec![Monitor::new(
136
            0,
137
            0,
138
            screen.width_in_pixels as u32,
139
            screen.height_in_pixels as u32,
140
        )]
141
    };
142
143
    let mut monitors = Vec::<Monitor>::new();
144
145
    let xinerama_active = connection
146
        .xinerama_is_active()
147
        .ok()
148
        .and_then(|cookie| cookie.reply().ok())
149
        .is_some_and(|reply| reply.state != 0);
150
151
    if xinerama_active {
152
        let Ok(xinerama_cookie) = connection.xinerama_query_screens() else {
153
            return Ok(fallback_monitors());
154
        };
155
        let Ok(xinerama_reply) = xinerama_cookie.reply() else {
156
            return Ok(fallback_monitors());
157
        };
158
159
        for screen_info in &xinerama_reply.screen_info {
160
            let has_valid_dimensions = screen_info.width > 0 && screen_info.height > 0;
161
            if !has_valid_dimensions {
162
                continue;
163
            }
164
165
            let x_position = screen_info.x_org as i32;
166
            let y_position = screen_info.y_org as i32;
167
            let width_in_pixels = screen_info.width as u32;
168
            let height_in_pixels = screen_info.height as u32;
169
170
            let is_duplicate_monitor = monitors.iter().any(|monitor| {
171
                monitor.screen_x == x_position
172
                    && monitor.screen_y == y_position
173
                    && monitor.screen_width == width_in_pixels as i32
174
                    && monitor.screen_height == height_in_pixels as i32
175
            });
176
177
            if !is_duplicate_monitor {
178
                monitors.push(Monitor::new(
179
                    x_position,
180
                    y_position,
181
                    width_in_pixels,
182
                    height_in_pixels,
183
                ));
184
            }
185
        }
186
    }
187
188
    if monitors.is_empty() {
189
        monitors = fallback_monitors();
190
    }
191
192
    monitors.sort_by(|a, b| match a.screen_y.cmp(&b.screen_y) {
193
        std::cmp::Ordering::Equal => a.screen_x.cmp(&b.screen_x),
194
        other => other,
195
    });
196
197
    Ok(monitors)
198
}