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: unsafe { 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 }
49 }
50}
51
52struct ListOutputs {
54 registry_state: RegistryState,
55 output_state: OutputState,
56}
57
58impl OutputHandler for ListOutputs {
59 fn output_state(&mut self) -> &mut OutputState {
60 &mut self.output_state
61 }
62
63 fn new_output(
64 &mut self,
65 _conn: &Connection,
66 _qh: &QueueHandle<Self>,
67 _output: wl_output::WlOutput,
68 ) {
69 }
70
71 fn update_output(
72 &mut self,
73 _conn: &Connection,
74 _qh: &QueueHandle<Self>,
75 _output: wl_output::WlOutput,
76 ) {
77 }
78
79 fn output_destroyed(
80 &mut self,
81 _conn: &Connection,
82 _qh: &QueueHandle<Self>,
83 _output: wl_output::WlOutput,
84 ) {
85 }
86}
87
88delegate_output!(ListOutputs);
89delegate_registry!(ListOutputs);
90
91impl ProvidesRegistryState for ListOutputs {
92 fn registry(&mut self) -> &mut RegistryState {
93 &mut self.registry_state
94 }
95
96 registry_handlers! {
97 OutputState,
98 }
99}
100
101pub fn get_all() -> DIResult<Vec<DisplayInfo>> {
102 let conn = Connection::connect_to_env()?;
103
104 let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
105 let qh = event_queue.handle();
106
107 let registry_state = RegistryState::new(&globals);
108
109 let output_delegate = OutputState::new(&globals, &qh);
110
111 let mut list_outputs = ListOutputs {
112 registry_state,
113 output_state: output_delegate,
114 };
115
116 event_queue.roundtrip(&mut list_outputs)?;
117
118 list_outputs
119 .output_state
120 .outputs()
121 .map(|output| {
122 list_outputs
123 .output_state
124 .info(&output)
125 .map(|o| DisplayInfo::from(&o))
126 .ok_or(DIError::new("Cannot get info from Output in Wayland"))
127 })
128 .collect::<DIResult<Vec<DisplayInfo>>>()
129}
130
131pub fn get_from_point(x: i32, y: i32) -> DIResult<DisplayInfo> {
132 let display_infos = get_all()?;
133
134 display_infos
135 .iter()
136 .find(|&d| {
137 x >= d.x
138 && x - (d.width as i32) < d.x + d.width as i32
139 && y >= d.y
140 && y - (d.height as i32) < d.y + d.height as i32
141 })
142 .cloned()
143 .ok_or_else(|| DIError::new("Get display info failed"))
144}