summaryrefslogtreecommitdiff
path: root/src/clients.rs
blob: 70a44fa77c3f6e11c6b4b87ea5e892215ca9609d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use xcb::{
    xinerama::{self, ScreenInfo},
    Extension,
};

use crate::{Error, Result, WM};

#[derive(Debug, Default)]
pub struct ClientList(Vec<MonitorInfo>);

impl ClientList {
    /// Set the new amount of screens, moving clients away if necessary
    pub fn truncate_screens(&mut self, new_size: usize) {
        // hack: double borrow stuff
        let mut moved_clients = vec![];
        for old in self.0.drain(new_size - self.0.len()..self.0.len()) {
            moved_clients.extend(old.clients.into_iter());
        }
        self.0[0].clients.extend(moved_clients.into_iter());
    }

    pub fn set_screen_info(&mut self, i: usize, info: ScreenInfo) {
        while i >= self.0.len() {
            self.0.push(MonitorInfo::default())
        }
        self.0[i].screen_info = info;
    }

    pub fn len(&self) -> usize {
        self.0.len()
    }
}

#[derive(Debug)]
pub struct MonitorInfo {
    clients: Vec<Client>,
    screen_info: ScreenInfo,
}

impl Default for MonitorInfo {
    fn default() -> Self {
        Self {
            clients: vec![],
            screen_info: ScreenInfo {
                x_org: 0,
                y_org: 0,
                width: 0,
                height: 0,
            },
        }
    }
}

#[derive(Debug)]
pub struct Client {}

impl WM<'_> {
    /// Update the client list's recorded monitors and monitor sizes
    pub(crate) fn update_geometry(&mut self) -> Result<()> {
        if self
            .conn
            .active_extensions()
            .any(|e| e == Extension::Xinerama)
        {
            let reply = self
                .conn
                .wait_for_reply(self.conn.send_request(&xinerama::QueryScreens {}))?;

            // Monitor removed, move its clients away
            if reply.screen_info().len() > self.clients.len() {
                self.clients.truncate_screens(reply.screen_info().len());
            }

            // Update screen info & add new client lists if needed
            for (i, monitor) in reply.screen_info().iter().enumerate() {
                self.clients.set_screen_info(i, monitor.clone());
            }
        } else {
            // Only one screen
            if self.clients.len() > 1 {
                self.clients.truncate_screens(1);
            }

            // TODO: it looks like this won't actually update when the screen size changes?
            let setup = self.conn.get_setup();
            let screen = setup
                .roots()
                .nth(self.screen_num as usize)
                .ok_or(Error::NoSuchScreen)?;

            self.clients.set_screen_info(
                0,
                ScreenInfo {
                    x_org: 0,
                    y_org: 0,
                    width: screen.width_in_pixels(),
                    height: screen.height_in_pixels(),
                },
            );
        }

        Ok(())
    }
}