1use sctk::reexports::client::protocol::wl_output::WlOutput;
2use sctk::reexports::client::Proxy;
3
4use sctk::output::OutputData;
5
6use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
7use crate::platform_impl::platform::VideoMode as PlatformVideoMode;
8
9use super::event_loop::EventLoopWindowTarget;
10
11impl<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)]
29pub struct MonitorHandle {
30 pub(crate) proxy: WlOutput,
31}
32
33impl 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
118impl PartialEq for MonitorHandle {
119 fn eq(&self, other: &Self) -> bool {
120 self.native_identifier() == other.native_identifier()
121 }
122}
123
124impl Eq for MonitorHandle {}
125
126impl PartialOrd for MonitorHandle {
127 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
128 Some(self.cmp(other))
129 }
130}
131
132impl Ord for MonitorHandle {
133 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
134 self.native_identifier().cmp(&other.native_identifier())
135 }
136}
137
138impl 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)]
145pub 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
152impl 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