1use super::application::*;
2use super::bindings;
3use super::core::{self, *};
4use super::host::*;
5use super::workspace::*;
6use glam::Mat4;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9#[repr(u32)]
10pub enum WindowAttrib {
11 Type = 0,
12 State = 1,
13 Focus = 3,
14 Dpi = 4,
15 Visibility = 5,
16 PreferredOrientation = 6,
17}
18
19impl From<WindowAttrib> for bindings::MirWindowAttrib {
20 fn from(value: WindowAttrib) -> Self {
21 value as bindings::MirWindowAttrib
22 }
23}
24
25impl TryFrom<bindings::MirWindowAttrib> for WindowAttrib {
26 type Error = ();
27
28 fn try_from(value: bindings::MirWindowAttrib) -> Result<Self, Self::Error> {
29 match value {
30 0 => Ok(Self::Type),
31 1 => Ok(Self::State),
32 3 => Ok(Self::Focus),
33 4 => Ok(Self::Dpi),
34 5 => Ok(Self::Visibility),
35 6 => Ok(Self::PreferredOrientation),
36 _ => Err(()),
37 }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
43#[repr(u32)]
44pub enum WindowType {
45 #[default]
47 Normal = 0,
48 Utility = 1,
50 Dialog = 2,
51 Gloss = 3,
52 Freestyle = 4,
53 Menu = 5,
54 InputMethod = 6,
56 Satellite = 7,
58 Tip = 8,
60 Decoration = 9,
61}
62
63impl From<WindowType> for bindings::MirWindowType {
64 fn from(value: WindowType) -> Self {
65 value as bindings::MirWindowType
66 }
67}
68
69impl TryFrom<bindings::MirWindowType> for WindowType {
70 type Error = ();
71
72 fn try_from(value: bindings::MirWindowType) -> Result<Self, Self::Error> {
73 match value {
74 0 => Ok(Self::Normal),
75 1 => Ok(Self::Utility),
76 2 => Ok(Self::Dialog),
77 3 => Ok(Self::Gloss),
78 4 => Ok(Self::Freestyle),
79 5 => Ok(Self::Menu),
80 6 => Ok(Self::InputMethod),
81 7 => Ok(Self::Satellite),
82 8 => Ok(Self::Tip),
83 9 => Ok(Self::Decoration),
84 _ => Err(()),
85 }
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
91#[repr(u32)]
92pub enum WindowState {
93 #[default]
94 Unknown = 0,
95 Restored = 1,
96 Minimized = 2,
97 Maximized = 3,
98 VertMaximized = 4,
99 Fullscreen = 5,
100 HorizMaximized = 6,
101 Hidden = 7,
102 Attached = 8,
104}
105
106impl From<WindowState> for bindings::MirWindowState {
107 fn from(value: WindowState) -> Self {
108 value as bindings::MirWindowState
109 }
110}
111
112impl TryFrom<bindings::MirWindowState> for WindowState {
113 type Error = ();
114
115 fn try_from(value: bindings::MirWindowState) -> Result<Self, Self::Error> {
116 match value {
117 0 => Ok(Self::Unknown),
118 1 => Ok(Self::Restored),
119 2 => Ok(Self::Minimized),
120 3 => Ok(Self::Maximized),
121 4 => Ok(Self::VertMaximized),
122 5 => Ok(Self::Fullscreen),
123 6 => Ok(Self::HorizMaximized),
124 7 => Ok(Self::Hidden),
125 8 => Ok(Self::Attached),
126 _ => Err(()),
127 }
128 }
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
133#[repr(u32)]
134pub enum WindowFocusState {
135 #[default]
137 Unfocused = 0,
138 Focused = 1,
140 Active = 2,
142}
143
144impl From<WindowFocusState> for bindings::MirWindowFocusState {
145 fn from(value: WindowFocusState) -> Self {
146 value as bindings::MirWindowFocusState
147 }
148}
149
150impl TryFrom<bindings::MirWindowFocusState> for WindowFocusState {
151 type Error = ();
152
153 fn try_from(value: bindings::MirWindowFocusState) -> Result<Self, Self::Error> {
154 match value {
155 0 => Ok(Self::Unfocused),
156 1 => Ok(Self::Focused),
157 2 => Ok(Self::Active),
158 _ => Err(()),
159 }
160 }
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
165#[repr(u32)]
166pub enum WindowVisibility {
167 #[default]
168 Occluded = 0,
169 Exposed = 1,
170}
171
172impl From<WindowVisibility> for bindings::MirWindowVisibility {
173 fn from(value: WindowVisibility) -> Self {
174 value as bindings::MirWindowVisibility
175 }
176}
177
178impl TryFrom<bindings::MirWindowVisibility> for WindowVisibility {
179 type Error = ();
180
181 fn try_from(value: bindings::MirWindowVisibility) -> Result<Self, Self::Error> {
182 match value {
183 0 => Ok(Self::Occluded),
184 1 => Ok(Self::Exposed),
185 _ => Err(()),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
191#[repr(u32)]
192pub enum DepthLayer {
193 Background = 0,
195 Below = 1,
197 #[default]
199 Application = 2,
200 AlwaysOnTop = 3,
202 Above = 4,
204 Overlay = 5,
206}
207
208impl From<DepthLayer> for bindings::MirDepthLayer {
209 fn from(value: DepthLayer) -> Self {
210 value as bindings::MirDepthLayer
211 }
212}
213
214impl TryFrom<bindings::MirDepthLayer> for DepthLayer {
215 type Error = ();
216
217 fn try_from(value: bindings::MirDepthLayer) -> Result<Self, Self::Error> {
218 match value {
219 0 => Ok(Self::Background),
220 1 => Ok(Self::Below),
221 2 => Ok(Self::Application),
222 3 => Ok(Self::AlwaysOnTop),
223 4 => Ok(Self::Above),
224 5 => Ok(Self::Overlay),
225 _ => Err(()),
226 }
227 }
228}
229
230#[derive(Debug)]
231pub struct WindowInfo {
232 pub window_type: WindowType,
234 pub state: WindowState,
236 pub top_left: Point,
238 pub size: Size,
240 pub depth_layer: DepthLayer,
242 pub name: String,
244 pub transform: Mat4,
246 pub alpha: f32,
248 internal: u64,
250}
251
252impl WindowInfo {
253 pub unsafe fn from_c_with_name(value: &bindings::miracle_window_info_t, name: String) -> Self {
258 Self {
259 window_type: WindowType::try_from(value.window_type).unwrap_or_default(),
260 state: WindowState::try_from(value.state).unwrap_or_default(),
261 top_left: value.top_left.into(),
262 size: value.size.into(),
263 depth_layer: DepthLayer::try_from(value.depth_layer).unwrap_or_default(),
264 name,
265 transform: core::mat4_from_f32_array(value.transform),
266 alpha: value.alpha,
267 internal: value.internal,
268 }
269 }
270
271 pub fn id(&self) -> u64 {
276 self.internal
277 }
278
279 pub fn application(&self) -> Option<ApplicationInfo> {
281 const NAME_BUF_LEN: usize = 256;
282 let mut name_buf: [u8; NAME_BUF_LEN] = [0; NAME_BUF_LEN];
283
284 unsafe {
285 let internal = miracle_window_info_get_application(
286 self.internal as i64,
287 name_buf.as_mut_ptr() as i32,
288 NAME_BUF_LEN as i32,
289 );
290
291 if internal == -1 {
292 return None;
293 }
294
295 let name_len = name_buf
297 .iter()
298 .position(|&c| c == 0)
299 .unwrap_or(NAME_BUF_LEN);
300 let name = String::from_utf8_lossy(&name_buf[..name_len]).into_owned();
301
302 Some(ApplicationInfo {
303 name,
304 internal: internal as u64,
305 })
306 }
307 }
308
309 pub fn workspace(&self) -> Option<Workspace> {
311 const NAME_BUF_LEN: usize = 256;
312 let mut workspace = std::mem::MaybeUninit::<crate::bindings::miracle_workspace_t>::uninit();
313 let mut name_buf: [u8; NAME_BUF_LEN] = [0; NAME_BUF_LEN];
314
315 unsafe {
316 let result = miracle_window_info_get_workspace(
317 self.internal as i64,
318 workspace.as_mut_ptr() as i32,
319 name_buf.as_mut_ptr() as i32,
320 NAME_BUF_LEN as i32,
321 );
322
323 if result != 0 {
324 return None;
325 }
326
327 let workspace = workspace.assume_init();
328 if workspace.is_set == 0 {
329 return None;
330 }
331
332 let name_len = name_buf
334 .iter()
335 .position(|&c| c == 0)
336 .unwrap_or(NAME_BUF_LEN);
337 let name = String::from_utf8_lossy(&name_buf[..name_len]).into_owned();
338
339 Some(Workspace::from_c_with_name(&workspace, name))
340 }
341 }
342}
343
344impl PartialEq for WindowInfo {
345 fn eq(&self, other: &Self) -> bool {
346 self.internal == other.internal
347 }
348}
349
350#[derive(Debug)]
356pub struct PluginWindow {
357 info: WindowInfo,
358}
359
360impl PluginWindow {
361 pub fn from_window_info(info: WindowInfo) -> Self {
362 Self { info }
363 }
364
365 pub fn set_state(&self, state: WindowState) -> Result<(), ()> {
367 let r = unsafe { miracle_window_set_state(self.info.internal as i64, state as i32) };
368 if r == 0 { Ok(()) } else { Err(()) }
369 }
370
371 pub fn set_workspace(&self, workspace: &Workspace) -> Result<(), ()> {
373 let r = unsafe {
374 miracle_window_set_workspace(self.info.internal as i64, workspace.id() as i64)
375 };
376 if r == 0 { Ok(()) } else { Err(()) }
377 }
378
379 pub fn set_rectangle(&self, rect: Rectangle, animate: bool) -> Result<(), ()> {
381 let r = unsafe {
382 miracle_window_set_rectangle(
383 self.info.internal as i64,
384 rect.x,
385 rect.y,
386 rect.width,
387 rect.height,
388 if animate { 1 } else { 0 },
389 )
390 };
391 if r == 0 { Ok(()) } else { Err(()) }
392 }
393
394 pub fn set_transform(&self, transform: Mat4) -> Result<(), ()> {
396 let arr = transform.to_cols_array();
397 let r =
398 unsafe { miracle_window_set_transform(self.info.internal as i64, arr.as_ptr() as i32) };
399 if r == 0 { Ok(()) } else { Err(()) }
400 }
401
402 pub fn set_alpha(&self, alpha: f32) -> Result<(), ()> {
404 let r = unsafe {
405 miracle_window_set_alpha(self.info.internal as i64, (&alpha as *const f32) as i32)
406 };
407 if r == 0 { Ok(()) } else { Err(()) }
408 }
409
410 pub fn request_focus(&self) -> Result<(), ()> {
412 let r = unsafe { miracle_window_request_focus(self.info.internal as i64) };
413 if r == 0 { Ok(()) } else { Err(()) }
414 }
415}
416
417impl std::ops::Deref for PluginWindow {
418 type Target = WindowInfo;
419
420 fn deref(&self) -> &Self::Target {
421 &self.info
422 }
423}
424
425impl PartialEq for PluginWindow {
426 fn eq(&self, other: &Self) -> bool {
427 self.info == other.info
428 }
429}