display_info/linux/
wayland.rs1use smithay_client_toolkit::output::{OutputHandler, OutputInfo, OutputState};
2use smithay_client_toolkit::reexports::client::globals::registry_queue_init;
3use smithay_client_toolkit::reexports::client::protocol::wl_output;
4use smithay_client_toolkit::reexports::client::{Connection, QueueHandle};
5use smithay_client_toolkit::registry::{ProvidesRegistryState, RegistryState};
6use smithay_client_toolkit::{delegate_output, delegate_registry, registry_handlers};
7use xcb::XidNew;
8
9use crate::DisplayInfo;
10use crate::error::{DIError, DIResult};
11
12impl From<&OutputInfo> for DisplayInfo {
13 fn from(info: &OutputInfo) -> Self {
14 let scale_factor = info.scale_factor as f32;
15 let rotation = match info.transform {
16 wl_output::Transform::_90 | wl_output::Transform::Flipped90 => 90.,
17 wl_output::Transform::_180 | wl_output::Transform::Flipped180 => 180.,
18 wl_output::Transform::_270 | wl_output::Transform::Flipped270 => 270.,
19 _ => 0.,
20 };
21 let frequency = info
22 .modes
23 .iter()
24 .find(|m| m.current || m.preferred)
25 .map(|m| m.refresh_rate as f32 / 1000.0)
26 .unwrap_or(0.);
27 let (x, y) = info.logical_position.unwrap_or(info.location);
28 let (w, h) = info.logical_size.unwrap_or(info.physical_size);
29 let (width_mm, height_mm) = info.physical_size;
30 DisplayInfo {
31 id: info.id,
32 name: info.name.clone().unwrap_or_default(),
33 friendly_name: info
34 .name
35 .clone()
36 .unwrap_or(format!("Unknown Display {}", info.id)),
37 raw_handle: xcb::randr::Output::new(info.id),
38 x: ((x as f32) / scale_factor) as i32,
39 y: ((y as f32) / scale_factor) as i32,
40 width: ((w as f32) / scale_factor) as u32,
41 height: ((h as f32) / scale_factor) as u32,
42 width_mm,
43 height_mm,
44 rotation,
45 scale_factor,
46 frequency,
47 is_primary: false,
48 is_builtin: false,
49 }
50 }
51}
52
53struct ListOutputs {
55 registry_state: RegistryState,
56 output_state: OutputState,
57}
58
59impl OutputHandler for ListOutputs {
60 fn output_state(&mut self) -> &mut OutputState {
61 &mut self.output_state
62 }
63
64 fn new_output(
65 &mut self,
66 _conn: &Connection,
67 _qh: &QueueHandle<Self>,
68 _output: wl_output::WlOutput,
69 ) {
70 }
71
72 fn update_output(
73 &mut self,
74 _conn: &Connection,
75 _qh: &QueueHandle<Self>,
76 _output: wl_output::WlOutput,
77 ) {
78 }
79
80 fn output_destroyed(
81 &mut self,
82 _conn: &Connection,
83 _qh: &QueueHandle<Self>,
84 _output: wl_output::WlOutput,
85 ) {
86 }
87}
88
89delegate_output!(ListOutputs);
90delegate_registry!(ListOutputs);
91
92impl ProvidesRegistryState for ListOutputs {
93 fn registry(&mut self) -> &mut RegistryState {
94 &mut self.registry_state
95 }
96
97 registry_handlers! {
98 OutputState,
99 }
100}
101
102pub fn get_all() -> DIResult<Vec<DisplayInfo>> {
103 let conn = Connection::connect_to_env()?;
104
105 let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
106 let qh = event_queue.handle();
107
108 let registry_state = RegistryState::new(&globals);
109
110 let output_delegate = OutputState::new(&globals, &qh);
111
112 let mut list_outputs = ListOutputs {
113 registry_state,
114 output_state: output_delegate,
115 };
116
117 event_queue.roundtrip(&mut list_outputs)?;
118
119 list_outputs
120 .output_state
121 .outputs()
122 .map(|output| {
123 list_outputs
124 .output_state
125 .info(&output)
126 .map(|o| DisplayInfo::from(&o))
127 .ok_or(DIError::new("Cannot get info from Output in Wayland"))
128 })
129 .collect::<DIResult<Vec<DisplayInfo>>>()
130}
131
132pub fn get_from_point(x: i32, y: i32) -> DIResult<DisplayInfo> {
133 let display_infos = get_all()?;
134
135 display_infos
136 .iter()
137 .find(|&d| {
138 x >= d.x
139 && x - (d.width as i32) < d.x + d.width as i32
140 && y >= d.y
141 && y - (d.height as i32) < d.y + d.height as i32
142 })
143 .cloned()
144 .ok_or_else(|| DIError::new("Get display info failed"))
145}