use serde::Serialize;
use smithay_client_toolkit::reexports::client::{
Connection, EventQueue, QueueHandle, globals::registry_queue_init, protocol::wl_output,
};
use smithay_client_toolkit::{
delegate_output, delegate_registry,
output::{OutputHandler, OutputState},
registry::{ProvidesRegistryState, RegistryState},
registry_handlers,
};
use std::fmt;
struct ListOutputs {
registry_state: RegistryState,
output_state: OutputState,
needs_recalc: bool,
}
impl OutputHandler for ListOutputs {
fn output_state(&mut self) -> &mut OutputState {
&mut self.output_state
}
fn new_output(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
self.needs_recalc = true
}
fn update_output(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
self.needs_recalc = true
}
fn output_destroyed(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
self.needs_recalc = true
}
}
impl ProvidesRegistryState for ListOutputs {
fn registry(&mut self) -> &mut RegistryState {
&mut self.registry_state
}
registry_handlers! {
OutputState,
}
}
#[derive(Serialize, Clone)]
pub struct Monitor {
pub name: String,
pub width: u32,
pub height: u32,
pub initial_width: u32,
pub initial_height: u32,
pub x: i32,
pub y: i32,
}
impl fmt::Display for Monitor {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"\x1B[32m{}\x1B[39m: {}x{} at {}:{}",
self.name, self.width, self.height, self.x, self.y
)
}
}
pub struct Wayland {
lo: ListOutputs,
eq: EventQueue<ListOutputs>,
}
impl Wayland {
pub fn connect() -> Result<Self, String> {
let conn = Connection::connect_to_env().map_err(|_| "wayland: failed to connect")?;
let (globals, event_queue) =
registry_queue_init(&conn).map_err(|_| "wayland: failed to init queue")?;
let qh = event_queue.handle();
let registry_state = RegistryState::new(&globals);
let output_delegate = OutputState::new(&globals, &qh);
let list_outputs = ListOutputs {
registry_state,
output_state: output_delegate,
needs_recalc: false,
};
Ok(Self {
lo: list_outputs,
eq: event_queue,
})
}
pub fn get_monitors(&mut self) -> Result<Vec<Monitor>, String> {
self.eq
.roundtrip(&mut self.lo)
.map_err(|_| "wayland: roundtrip failed")?;
let mut result: Vec<Monitor> = Vec::with_capacity(self.lo.output_state.outputs().count());
for output in self.lo.output_state.outputs() {
match self.lo.output_state.info(&output) {
Some(monitor_info) => {
result.push(Monitor {
name: monitor_info
.name
.as_ref()
.ok_or("wayland: compositor reports no monitor name")?
.to_string(),
initial_width: monitor_info
.logical_size
.ok_or("wayland: compositor reports no monitor width")?
.0 as u32,
initial_height: monitor_info
.logical_size
.ok_or("wayland: compositor reports no monitor height")?
.1 as u32,
width: monitor_info
.logical_size
.ok_or("wayland: compositor reports no monitor width")?
.0 as u32,
height: monitor_info
.logical_size
.ok_or("wayland: compositor reports no monitor height")?
.1 as u32,
x: monitor_info
.logical_position
.ok_or("wayland: compositor reports no monitor x")?
.0,
y: monitor_info
.logical_position
.ok_or("wayland: compositor reports no monitor y")?
.1,
})
}
_ => {
return Err("wayland: compositor reports no monitor info".to_string());
}
}
}
Ok(result)
}
pub fn refresh(&mut self) -> Result<bool, String> {
self.eq
.roundtrip(&mut self.lo)
.map_err(|_| "wayland: roundtrip failed")?;
self.eq.flush().map_err(|_| "wayland: flush failed")?;
self.eq
.blocking_dispatch(&mut self.lo)
.map_err(|_| "wayland: event dispatch failed")?;
Ok(self.lo.needs_recalc)
}
}
delegate_output!(ListOutputs);
delegate_registry!(ListOutputs);