oxwm

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