Skip to main content

miracle_plugin/
workspace.rs

1use super::bindings;
2use super::container::*;
3use super::core::Rectangle;
4use super::host::*;
5use super::output::*;
6
7/// Represents one workspace on an output.
8///
9/// Each workspace hosts a tree of [`crate::container::Container`]s. Use [`Workspace::trees`]
10/// to get the top-level containers, and [`Workspace::output`] to find the display this
11/// workspace is hosted on.
12#[derive(Debug, Clone)]
13pub struct Workspace {
14    /// The workspace number (if set).
15    pub number: Option<u32>,
16    /// The workspace name (if set).
17    pub name: Option<String>,
18    /// The current area of the workspace.
19    pub rectangle: Rectangle,
20    internal: u64,
21}
22
23impl Workspace {
24    /// Returns the opaque internal ID used to refer to this workspace across API calls.
25    pub fn id(&self) -> u64 {
26        self.internal
27    }
28
29    #[doc(hidden)]
30    pub unsafe fn from_c_with_name(value: &bindings::miracle_workspace_t, name: String) -> Self {
31        Self {
32            number: if value.has_number != 0 {
33                Some(value.number)
34            } else {
35                None
36            },
37            name: if value.has_name != 0 {
38                Some(name)
39            } else {
40                None
41            },
42            internal: value.internal,
43            rectangle: Rectangle {
44                x: value.position.x,
45                y: value.position.y,
46                width: value.size.w,
47                height: value.size.h,
48            },
49        }
50    }
51
52    /// Get the output that this workspace is on.
53    pub fn output(&self) -> Option<Output> {
54        const NAME_BUF_LEN: usize = 256;
55        let mut output = std::mem::MaybeUninit::<crate::bindings::miracle_output_t>::uninit();
56        let mut name_buf: [u8; NAME_BUF_LEN] = [0; NAME_BUF_LEN];
57
58        unsafe {
59            let result = miracle_workspace_get_output(
60                self.internal as i64,
61                output.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 output = output.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(Output::from_c_with_name(&output, name))
80        }
81    }
82
83    /// Get a tree from the workspace by index.
84    ///
85    /// Returns `None` if the index is out of bounds.
86    pub fn tree(&self) -> Option<Container> {
87        let mut container = std::mem::MaybeUninit::<crate::bindings::miracle_container_t>::uninit();
88        unsafe {
89            let result = miracle_workspace_get_tree(
90                self.internal as i64,
91                container.as_mut_ptr() as i32,
92            );
93
94            if result != 0 {
95                return None;
96            }
97
98            let container = container.assume_init();
99            Some(Container::from(container))
100        }
101    }
102}