1 | use sctk::reexports::client::protocol::wl_output::WlOutput; |
2 | use sctk::reexports::client::Proxy; |
3 | |
4 | use sctk::output::OutputData; |
5 | |
6 | use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; |
7 | use crate::platform_impl::platform::VideoMode as PlatformVideoMode; |
8 | |
9 | use super::event_loop::EventLoopWindowTarget; |
10 | |
11 | impl<T> EventLoopWindowTarget<T> { |
12 | #[inline ] |
13 | pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> { |
14 | self.state |
15 | .borrow() |
16 | .output_state |
17 | .outputs() |
18 | .map(MonitorHandle::new) |
19 | } |
20 | |
21 | #[inline ] |
22 | pub fn primary_monitor(&self) -> Option<MonitorHandle> { |
23 | // There's no primary monitor on Wayland. |
24 | None |
25 | } |
26 | } |
27 | |
28 | #[derive (Clone, Debug)] |
29 | pub struct MonitorHandle { |
30 | pub(crate) proxy: WlOutput, |
31 | } |
32 | |
33 | impl MonitorHandle { |
34 | #[inline ] |
35 | pub(crate) fn new(proxy: WlOutput) -> Self { |
36 | Self { proxy } |
37 | } |
38 | |
39 | #[inline ] |
40 | pub fn name(&self) -> Option<String> { |
41 | let output_data = self.proxy.data::<OutputData>().unwrap(); |
42 | output_data.with_output_info(|info| info.name.clone()) |
43 | } |
44 | |
45 | #[inline ] |
46 | pub fn native_identifier(&self) -> u32 { |
47 | let output_data = self.proxy.data::<OutputData>().unwrap(); |
48 | output_data.with_output_info(|info| info.id) |
49 | } |
50 | |
51 | #[inline ] |
52 | pub fn size(&self) -> PhysicalSize<u32> { |
53 | let output_data = self.proxy.data::<OutputData>().unwrap(); |
54 | let dimensions = output_data.with_output_info(|info| { |
55 | info.modes |
56 | .iter() |
57 | .find_map(|mode| mode.current.then_some(mode.dimensions)) |
58 | }); |
59 | |
60 | match dimensions { |
61 | Some((width, height)) => (width as u32, height as u32), |
62 | _ => (0, 0), |
63 | } |
64 | .into() |
65 | } |
66 | |
67 | #[inline ] |
68 | pub fn position(&self) -> PhysicalPosition<i32> { |
69 | let output_data = self.proxy.data::<OutputData>().unwrap(); |
70 | output_data.with_output_info(|info| { |
71 | info.logical_position.map_or_else( |
72 | || { |
73 | LogicalPosition::<i32>::from(info.location) |
74 | .to_physical(info.scale_factor as f64) |
75 | }, |
76 | |logical_position| { |
77 | LogicalPosition::<i32>::from(logical_position) |
78 | .to_physical(info.scale_factor as f64) |
79 | }, |
80 | ) |
81 | }) |
82 | } |
83 | |
84 | #[inline ] |
85 | pub fn refresh_rate_millihertz(&self) -> Option<u32> { |
86 | let output_data = self.proxy.data::<OutputData>().unwrap(); |
87 | output_data.with_output_info(|info| { |
88 | info.modes |
89 | .iter() |
90 | .find_map(|mode| mode.current.then_some(mode.refresh_rate as u32)) |
91 | }) |
92 | } |
93 | |
94 | #[inline ] |
95 | pub fn scale_factor(&self) -> i32 { |
96 | let output_data = self.proxy.data::<OutputData>().unwrap(); |
97 | output_data.scale_factor() |
98 | } |
99 | |
100 | #[inline ] |
101 | pub fn video_modes(&self) -> impl Iterator<Item = PlatformVideoMode> { |
102 | let output_data = self.proxy.data::<OutputData>().unwrap(); |
103 | let modes = output_data.with_output_info(|info| info.modes.clone()); |
104 | |
105 | let monitor = self.clone(); |
106 | |
107 | modes.into_iter().map(move |mode| { |
108 | PlatformVideoMode::Wayland(VideoMode { |
109 | size: (mode.dimensions.0 as u32, mode.dimensions.1 as u32).into(), |
110 | refresh_rate_millihertz: mode.refresh_rate as u32, |
111 | bit_depth: 32, |
112 | monitor: monitor.clone(), |
113 | }) |
114 | }) |
115 | } |
116 | } |
117 | |
118 | impl PartialEq for MonitorHandle { |
119 | fn eq(&self, other: &Self) -> bool { |
120 | self.native_identifier() == other.native_identifier() |
121 | } |
122 | } |
123 | |
124 | impl Eq for MonitorHandle {} |
125 | |
126 | impl PartialOrd for MonitorHandle { |
127 | fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { |
128 | Some(self.cmp(other)) |
129 | } |
130 | } |
131 | |
132 | impl Ord for MonitorHandle { |
133 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { |
134 | self.native_identifier().cmp(&other.native_identifier()) |
135 | } |
136 | } |
137 | |
138 | impl std::hash::Hash for MonitorHandle { |
139 | fn hash<H: std::hash::Hasher>(&self, state: &mut H) { |
140 | self.native_identifier().hash(state); |
141 | } |
142 | } |
143 | |
144 | #[derive (Debug, Clone, PartialEq, Eq, Hash)] |
145 | pub struct VideoMode { |
146 | pub(crate) size: PhysicalSize<u32>, |
147 | pub(crate) bit_depth: u16, |
148 | pub(crate) refresh_rate_millihertz: u32, |
149 | pub(crate) monitor: MonitorHandle, |
150 | } |
151 | |
152 | impl VideoMode { |
153 | #[inline ] |
154 | pub fn size(&self) -> PhysicalSize<u32> { |
155 | self.size |
156 | } |
157 | |
158 | #[inline ] |
159 | pub fn bit_depth(&self) -> u16 { |
160 | self.bit_depth |
161 | } |
162 | |
163 | #[inline ] |
164 | pub fn refresh_rate_millihertz(&self) -> u32 { |
165 | self.refresh_rate_millihertz |
166 | } |
167 | |
168 | pub fn monitor(&self) -> MonitorHandle { |
169 | self.monitor.clone() |
170 | } |
171 | } |
172 | |