use std::rc::Rc;
use anyhow::{anyhow, Error};
use x11rb::connection::RequestConnection;
use x11rb::errors::ReplyError;
use x11rb::protocol::randr::{ConnectionExt, ModeFlag};
use x11rb::protocol::render::{self, ConnectionExt as _};
use x11rb::protocol::xproto::{Screen, Visualid, Visualtype, Window};
use x11rb::xcb_ffi::XCBConnection;
pub fn refresh_rate(conn: &Rc<XCBConnection>, window_id: Window) -> Option<f64> {
let try_refresh_rate = || -> Result<f64, Error> {
let reply = conn.randr_get_screen_resources(window_id)?.reply()?;
reply
.modes
.first()
.ok_or_else(|| anyhow!("didn't get any modes"))
.and_then(|mode_info| {
let flags = mode_info.mode_flags;
let vtotal = {
let mut val = mode_info.vtotal;
if (flags & u32::from(ModeFlag::DOUBLE_SCAN)) != 0 {
val *= 2;
}
if (flags & u32::from(ModeFlag::INTERLACE)) != 0 {
val /= 2;
}
val
};
if vtotal != 0 && mode_info.htotal != 0 {
Ok((mode_info.dot_clock as f64) / (vtotal as f64 * mode_info.htotal as f64))
} else {
Err(anyhow!("got nonsensical mode values"))
}
})
};
match try_refresh_rate() {
Err(e) => {
tracing::error!("failed to find refresh rate: {}", e);
None
}
Ok(r) => Some(r),
}
}
fn find_visual_from_screen(screen: &Screen, visual_id: u32) -> Option<Visualtype> {
for depth in &screen.allowed_depths {
for visual in &depth.visuals {
if visual.visual_id == visual_id {
return Some(*visual);
}
}
}
None
}
pub fn get_visual_from_screen(screen: &Screen) -> Option<Visualtype> {
find_visual_from_screen(screen, screen.root_visual)
}
pub fn get_argb_visual_type(
conn: &XCBConnection,
screen: &Screen,
) -> Result<Option<Visualtype>, ReplyError> {
fn find_visual_for_format(
reply: &render::QueryPictFormatsReply,
id: render::Pictformat,
) -> Option<Visualid> {
let find_in_depth = |depth: &render::Pictdepth| {
depth
.visuals
.iter()
.find(|visual| visual.format == id)
.map(|visual| visual.visual)
};
let find_in_screen =
|screen: &render::Pictscreen| screen.depths.iter().find_map(find_in_depth);
reply.screens.iter().find_map(find_in_screen)
}
if conn
.extension_information(render::X11_EXTENSION_NAME)?
.is_none()
{
Ok(None)
} else {
let pict_formats = conn.render_query_pict_formats()?.reply()?;
let res = pict_formats
.formats
.iter()
.find(|format| {
format.type_ == render::PictType::DIRECT
&& format.depth == 32
&& format.direct.red_shift == 16
&& format.direct.red_mask == 0xff
&& format.direct.green_shift == 8
&& format.direct.green_mask == 0xff
&& format.direct.blue_shift == 0
&& format.direct.blue_mask == 0xff
&& format.direct.alpha_shift == 24
&& format.direct.alpha_mask == 0xff
})
.and_then(|format| find_visual_for_format(&pict_formats, format.id))
.and_then(|visual_id| find_visual_from_screen(screen, visual_id));
Ok(res)
}
}
macro_rules! log_x11 {
($val:expr) => {
if let Err(e) = $val {
tracing::error!("X11 error: {}", e);
}
};
}