ltk/platform/wayland/
output_probe.rsuse smithay_client_toolkit::reexports::client::{ Connection, Dispatch, Proxy, QueueHandle, WEnum };
use smithay_client_toolkit::reexports::client::globals::GlobalList;
use smithay_client_toolkit::reexports::client::protocol::wl_output::{ self, WlOutput };
use wayland_protocols::xdg::xdg_output::zv1::client::zxdg_output_manager_v1::ZxdgOutputManagerV1;
use wayland_protocols::xdg::xdg_output::zv1::client::zxdg_output_v1::{ self, ZxdgOutputV1 };
struct Output
{
mode: Option<( i32, i32 )>,
scale: i32,
logical: Option<( i32, i32 )>,
}
struct Probe
{
outputs: Vec<Output>,
}
pub( crate ) fn output_logical_size( conn: &Connection, globals: &GlobalList ) -> Option<( u32, u32 )>
{
let mut queue = conn.new_event_queue::<Probe>();
let qh = queue.handle();
let registry = globals.registry();
let ( outputs, manager ) = globals.contents().with_list( |list|
{
let outputs: Vec<WlOutput> = list.iter()
.filter( |g| g.interface == WlOutput::interface().name )
.enumerate()
.map( |( i, g )| registry.bind::<WlOutput, _, _>( g.name, g.version.min( 4 ), &qh, i ) )
.collect();
let manager = list.iter()
.find( |g| g.interface == ZxdgOutputManagerV1::interface().name )
.map( |g| registry.bind::<ZxdgOutputManagerV1, _, _>( g.name, g.version.min( 3 ), &qh, () ) );
( outputs, manager )
} );
if outputs.is_empty()
{
return None;
}
let mut xdg_outputs = Vec::new();
if let Some( manager ) = &manager
{
for ( i, output ) in outputs.iter().enumerate()
{
xdg_outputs.push( manager.get_xdg_output( output, &qh, i ) );
}
}
let mut probe = Probe { outputs: outputs.iter().map( |_| Output { mode: None, scale: 1, logical: None } ).collect() };
let answered = queue.roundtrip( &mut probe ).is_ok();
for xdg_output in xdg_outputs
{
xdg_output.destroy();
}
if let Some( manager ) = manager
{
manager.destroy();
}
for output in outputs
{
if output.version() >= 3
{
output.release();
}
}
if !answered
{
return None;
}
probe.outputs.iter().find_map( |o|
{
let scale = o.scale.max( 1 );
let ( w, h ) = o.logical.or_else( || o.mode.map( |( w, h )| ( w / scale, h / scale ) ) )?;
( w > 0 && h > 0 ).then_some( ( w as u32, h as u32 ) )
} )
}
impl Dispatch<WlOutput, usize> for Probe
{
fn event( state: &mut Self, _: &WlOutput, event: wl_output::Event, index: &usize, _: &Connection, _: &QueueHandle<Self> )
{
let Some( output ) = state.outputs.get_mut( *index ) else { return };
match event
{
wl_output::Event::Mode { flags: WEnum::Value( flags ), width, height, .. } if flags.contains( wl_output::Mode::Current ) =>
{
output.mode = Some( ( width, height ) );
}
wl_output::Event::Scale { factor } => output.scale = factor,
_ => {}
}
}
}
impl Dispatch<ZxdgOutputManagerV1, ()> for Probe
{
fn event( _: &mut Self, _: &ZxdgOutputManagerV1, _: <ZxdgOutputManagerV1 as Proxy>::Event, _: &(), _: &Connection, _: &QueueHandle<Self> ) {}
}
impl Dispatch<ZxdgOutputV1, usize> for Probe
{
fn event( state: &mut Self, _: &ZxdgOutputV1, event: zxdg_output_v1::Event, index: &usize, _: &Connection, _: &QueueHandle<Self> )
{
if let ( Some( output ), zxdg_output_v1::Event::LogicalSize { width, height } ) = ( state.outputs.get_mut( *index ), event )
{
output.logical = Some( ( width, height ) );
}
}
}