summaryrefslogtreecommitdiff
path: root/src/clients.rs
blob: 341f73c27d5a92969a7168a2accb5dd7b252f808 (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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use xcb::{
    x::{
        ConfigureNotifyEvent, ConfigureRequestEvent, DestroyNotifyEvent, MapRequestEvent,
        UnmapNotifyEvent,
    },
    xinerama::{self, ScreenInfo},
    Extension,
};

use crate::{error::*, WM};

impl WM<'_> {
    /// Update the client state'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.monitor_count() {
                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);
            }
        } else {
            // Only one screen
            if self.clients.monitor_count() > 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(())
    }

    pub(crate) fn handle_configure_request(&mut self, _e: ConfigureRequestEvent) -> Result<()> {
        todo!()
    }
    pub(crate) fn handle_configure_notify(&mut self, _e: ConfigureNotifyEvent) -> Result<()> {
        todo!()
    }
    pub(crate) fn handle_destroy_notify(&mut self, _e: DestroyNotifyEvent) -> Result<()> {
        todo!()
    }
    pub(crate) fn handle_map_request(&mut self, _e: MapRequestEvent) -> Result<()> {
        todo!()
    }
    pub(crate) fn handle_unmap_notify(&mut self, _e: UnmapNotifyEvent) -> Result<()> {
        todo!()
    }
}

/// Holds state related to the window manager's clients
/// This contains a list of clients per monitor, alongside info on that monitor's screen size.
#[derive(Debug, Default)]
pub struct ClientState(Vec<MonitorInfo>);

/// Info stored for a single monitor
#[derive(Debug)]
pub struct MonitorInfo {
    /// Clients attached to that monitor
    clients: Vec<Client>,

    /// The monitor's geometry
    screen_info: ScreenInfo,
}

/// Information about a single client / window
#[derive(Debug)]
pub struct Client {
    // TODO
}

impl ClientState {
    /// 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);
    }

    /// Set the info for the given screen, resizing the monitor list if necessary.
    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;
    }

    /// Get the amount of monitors this state is currently aware of
    pub fn monitor_count(&self) -> usize {
        self.0.len()
    }
}

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