Skip to main content

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: 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
53/// Application data.
54struct 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}