display_info/linux/
wayland.rs

1use 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
52/// Application data.
53struct 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}