Skip to main content

miracle_plugin/
output.rs

1use super::bindings;
2use super::core::{Point, Size};
3use super::host::*;
4use super::workspace::*;
5
6#[derive(Debug, Clone)]
7pub struct Output {
8    /// The position of the output.
9    pub position: Point,
10    /// The size of the output.
11    pub size: Size,
12    /// The name of the output.
13    pub name: String,
14    /// Whether this is the primary output.
15    pub is_primary: bool,
16    /// The number of workspaces on this output.
17    pub num_workspaces: u32,
18    /// Internal pointer for C interop.
19    internal: u64,
20}
21
22impl Output {
23    pub fn id(&self) -> u64 {
24        self.internal
25    }
26
27    /// Create from the C struct and a name string.
28    ///
29    /// The name is passed separately because the C struct doesn't contain
30    /// the name directly (it's written to a separate buffer by the host).
31    pub fn from_c_with_name(value: &bindings::miracle_output_t, name: String) -> Self {
32        Self {
33            position: value.position.into(),
34            size: value.size.into(),
35            name,
36            is_primary: value.is_primary != 0,
37            num_workspaces: value.num_workspaces,
38            internal: value.internal,
39        }
40    }
41
42    pub fn workspaces(&self) -> Vec<Workspace> {
43        (0..self.num_workspaces)
44            .filter_map(|i| self.workspace(i))
45            .collect()
46    }
47
48    pub fn workspace(&self, index: u32) -> Option<Workspace> {
49        if index >= self.num_workspaces {
50            return None;
51        }
52
53        const NAME_BUF_LEN: usize = 256;
54        let mut workspace = std::mem::MaybeUninit::<crate::bindings::miracle_workspace_t>::uninit();
55        let mut name_buf: [u8; NAME_BUF_LEN] = [0; NAME_BUF_LEN];
56
57        unsafe {
58            let result = miracle_output_get_workspace(
59                self.internal as i64,
60                index,
61                workspace.as_mut_ptr() as i32,
62                name_buf.as_mut_ptr() as i32,
63                NAME_BUF_LEN as i32,
64            );
65
66            if result != 0 {
67                return None;
68            }
69
70            let workspace = workspace.assume_init();
71
72            // Find the null terminator to get the actual string length
73            let name_len = name_buf
74                .iter()
75                .position(|&c| c == 0)
76                .unwrap_or(NAME_BUF_LEN);
77            let name = String::from_utf8_lossy(&name_buf[..name_len]).into_owned();
78
79            Some(Workspace::from_c_with_name(&workspace, name))
80        }
81    }
82}