#![feature(prelude_import)]
#[macro_use]
extern crate std;
#[prelude_import]
use std::prelude::rust_2024::*;
use xcb::x::Atom;
use xcb::{Xid, XidNew, randr, x};
pub mod err {
#[non_exhaustive]
pub enum Error {
#[display("{}", _0)]
#[from(xcb::Error, xcb::ConnError, xcb::ProtocolError)]
XcbError(xcb::Error),
#[display("invalid screen number: {}", _0)]
BadScreenNumber(i32),
#[display("unsupported visual class: {}-bit {:?}", _0, _1)]
UnsupportedVisual(u8, xcb::x::VisualClass),
#[display("could not find root visual: {}", _0)]
CouldNotFindRootVisual(xcb::x::Visualid),
#[display("image {}x{} too large", _0, _1)]
ImageTooLarge(u32, u32),
#[display("buffer {} does not match {}x{} image size", _0, _1, _2)]
BadBufferSize(usize, u16, u16),
}
#[automatically_derived]
impl ::core::fmt::Debug for Error {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Error::XcbError(__self_0) => {
::core::fmt::Formatter::debug_tuple_field1_finish(
f,
"XcbError",
&__self_0,
)
}
Error::BadScreenNumber(__self_0) => {
::core::fmt::Formatter::debug_tuple_field1_finish(
f,
"BadScreenNumber",
&__self_0,
)
}
Error::UnsupportedVisual(__self_0, __self_1) => {
::core::fmt::Formatter::debug_tuple_field2_finish(
f,
"UnsupportedVisual",
__self_0,
&__self_1,
)
}
Error::CouldNotFindRootVisual(__self_0) => {
::core::fmt::Formatter::debug_tuple_field1_finish(
f,
"CouldNotFindRootVisual",
&__self_0,
)
}
Error::ImageTooLarge(__self_0, __self_1) => {
::core::fmt::Formatter::debug_tuple_field2_finish(
f,
"ImageTooLarge",
__self_0,
&__self_1,
)
}
Error::BadBufferSize(__self_0, __self_1, __self_2) => {
::core::fmt::Formatter::debug_tuple_field3_finish(
f,
"BadBufferSize",
__self_0,
__self_1,
&__self_2,
)
}
}
}
}
#[allow(unreachable_code)]
#[automatically_derived]
impl derive_more::core::fmt::Display for Error {
fn fmt(
&self,
__derive_more_f: &mut derive_more::core::fmt::Formatter<'_>,
) -> derive_more::core::fmt::Result {
match self {
Self::XcbError(_0) => {
derive_more::core::fmt::Display::fmt(_0, __derive_more_f)
}
Self::BadScreenNumber(_0) => {
__derive_more_f
.write_fmt(format_args!("invalid screen number: {0}", _0))
}
Self::UnsupportedVisual(_0, _1) => {
__derive_more_f
.write_fmt(
format_args!(
"unsupported visual class: {0}-bit {1:?}",
_0,
_1,
),
)
}
Self::CouldNotFindRootVisual(_0) => {
__derive_more_f
.write_fmt(format_args!("could not find root visual: {0}", _0))
}
Self::ImageTooLarge(_0, _1) => {
__derive_more_f
.write_fmt(format_args!("image {0}x{1} too large", _0, _1))
}
Self::BadBufferSize(_0, _1, _2) => {
__derive_more_f
.write_fmt(
format_args!(
"buffer {0} does not match {1}x{2} image size",
_0,
_1,
_2,
),
)
}
}
}
}
#[allow(unreachable_code)]
#[automatically_derived]
impl derive_more::core::convert::From<xcb::Error> for Error {
#[inline]
fn from(value: xcb::Error) -> Self {
Error::XcbError(
<xcb::Error as derive_more::core::convert::From<xcb::Error>>::from(value),
)
}
}
#[allow(unreachable_code)]
#[automatically_derived]
impl derive_more::core::convert::From<xcb::ConnError> for Error {
#[inline]
fn from(value: xcb::ConnError) -> Self {
Error::XcbError(
<xcb::Error as derive_more::core::convert::From<
xcb::ConnError,
>>::from(value),
)
}
}
#[allow(unreachable_code)]
#[automatically_derived]
impl derive_more::core::convert::From<xcb::ProtocolError> for Error {
#[inline]
fn from(value: xcb::ProtocolError) -> Self {
Error::XcbError(
<xcb::Error as derive_more::core::convert::From<
xcb::ProtocolError,
>>::from(value),
)
}
}
#[display("invalid screen number: {}", _0)]
pub struct BadScreenNumber(pub i32);
#[automatically_derived]
impl ::core::fmt::Debug for BadScreenNumber {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(
f,
"BadScreenNumber",
&&self.0,
)
}
}
#[allow(unreachable_code)]
#[automatically_derived]
impl derive_more::core::fmt::Display for BadScreenNumber {
fn fmt(
&self,
__derive_more_f: &mut derive_more::core::fmt::Formatter<'_>,
) -> derive_more::core::fmt::Result {
let _0 = &self.0;
__derive_more_f.write_fmt(format_args!("invalid screen number: {0}", _0))
}
}
impl From<BadScreenNumber> for Error {
fn from(err: BadScreenNumber) -> Error {
Error::BadScreenNumber(err.0)
}
}
}
pub mod img {
#[display("RgbShifts({}, {}, {})", r, g, b)]
#[debug("{}", self)]
pub struct RgbShifts {
pub r: u8,
pub g: u8,
pub b: u8,
}
#[automatically_derived]
impl ::core::clone::Clone for RgbShifts {
#[inline]
fn clone(&self) -> RgbShifts {
let _: ::core::clone::AssertParamIsClone<u8>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for RgbShifts {}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for RgbShifts {}
#[automatically_derived]
impl ::core::cmp::PartialEq for RgbShifts {
#[inline]
fn eq(&self, other: &RgbShifts) -> bool {
self.r == other.r && self.g == other.g && self.b == other.b
}
}
#[automatically_derived]
impl ::core::cmp::Eq for RgbShifts {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<u8>;
}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for RgbShifts {
#[inline]
fn partial_cmp(
&self,
other: &RgbShifts,
) -> ::core::option::Option<::core::cmp::Ordering> {
match ::core::cmp::PartialOrd::partial_cmp(&self.r, &other.r) {
::core::option::Option::Some(::core::cmp::Ordering::Equal) => {
match ::core::cmp::PartialOrd::partial_cmp(&self.g, &other.g) {
::core::option::Option::Some(::core::cmp::Ordering::Equal) => {
::core::cmp::PartialOrd::partial_cmp(&self.b, &other.b)
}
cmp => cmp,
}
}
cmp => cmp,
}
}
}
#[automatically_derived]
impl ::core::cmp::Ord for RgbShifts {
#[inline]
fn cmp(&self, other: &RgbShifts) -> ::core::cmp::Ordering {
match ::core::cmp::Ord::cmp(&self.r, &other.r) {
::core::cmp::Ordering::Equal => {
match ::core::cmp::Ord::cmp(&self.g, &other.g) {
::core::cmp::Ordering::Equal => {
::core::cmp::Ord::cmp(&self.b, &other.b)
}
cmp => cmp,
}
}
cmp => cmp,
}
}
}
#[allow(unreachable_code)]
#[automatically_derived]
impl derive_more::core::fmt::Display for RgbShifts {
fn fmt(
&self,
__derive_more_f: &mut derive_more::core::fmt::Formatter<'_>,
) -> derive_more::core::fmt::Result {
let r = &self.r;
let g = &self.g;
let b = &self.b;
__derive_more_f.write_fmt(format_args!("RgbShifts({0}, {1}, {2})", r, g, b))
}
}
#[allow(unreachable_code)]
#[automatically_derived]
impl derive_more::core::fmt::Debug for RgbShifts {
#[inline]
fn fmt(
&self,
__derive_more_f: &mut derive_more::core::fmt::Formatter<'_>,
) -> derive_more::core::fmt::Result {
let r = &self.r;
let g = &self.g;
let b = &self.b;
derive_more::core::fmt::Display::fmt(&(self), __derive_more_f)
}
}
pub trait Subpixel: bytemuck::Pod {
fn to_u8(self) -> u8;
}
impl RgbShifts {
pub fn from_rgb<S: Subpixel>(&self, r: S, g: S, b: S) -> u32 {
(u32::from(r.to_u8()) << self.r) | (u32::from(g.to_u8()) << self.g)
| (u32::from(b.to_u8()) << self.b)
}
pub fn from_luma<S: Subpixel>(&self, luma: S) -> u32 {
u32::from(luma.to_u8()) * 0x0101_0101
}
}
impl Subpixel for u8 {
fn to_u8(self) -> u8 {
self
}
}
impl Subpixel for u16 {
fn to_u8(self) -> u8 {
(self >> 8) as u8
}
}
impl Subpixel for f32 {
fn to_u8(self) -> u8 {
if !(self < 1.0) {
255
} else if self <= 0.0 {
0
} else {
(self * 255.0).round() as u8
}
}
}
pub trait View {
fn dimensions(&self) -> (u32, u32);
fn as_rgb(&self) -> &[[u8; 3]];
}
impl<T: View> View for &T {
fn dimensions(&self) -> (u32, u32) {
(*self).dimensions()
}
fn as_rgb(&self) -> &[[u8; 3]] {
(*self).as_rgb()
}
}
pub struct Ref<'a> {
pub width: u32,
pub height: u32,
pub data: &'a [[u8; 3]],
}
impl<'a> Ref<'a> {
pub fn new(width: u32, height: u32, data: &'a [u8]) -> Option<Self> {
let dim = width.try_into().ok().zip(height.try_into().ok());
dim.and_then(|(w, h): (usize, usize)| w.checked_mul(h))
.and_then(|area| area.checked_mul(3))
.is_some_and(|len| len == data.len())
.then(|| Self {
width,
height,
data: bytemuck::cast_slice(data),
})
}
}
impl<'a> View for Ref<'a> {
#[inline]
fn dimensions(&self) -> (u32, u32) {
(self.width, self.height)
}
#[inline]
fn as_rgb(&self) -> &'a [[u8; 3]] {
self.data
}
}
impl View for image::RgbImage {
#[inline]
fn dimensions(&self) -> (u32, u32) {
self.dimensions()
}
#[inline]
fn as_rgb(&self) -> &[[u8; 3]] {
bytemuck::cast_slice(self.as_raw().as_slice())
}
}
}
pub use err::Error;
pub type Result<T = (), E = Error> = core::result::Result<T, E>;
pub struct Display {
conn: xcb::Connection,
screen_num: i32,
}
impl Display {
pub fn open() -> Result<Self> {
let (conn, screen_num) = xcb::Connection::connect(None)?;
Self::from_xcb(conn, screen_num)
}
pub fn from_xcb(conn: xcb::Connection, screen_num: i32) -> Result<Self> {
usize::try_from(screen_num)
.map(|_| Self { conn, screen_num })
.map_err(|_| Error::BadScreenNumber(screen_num))
}
pub fn into_xcb(self) -> (xcb::Connection, i32) {
(self.conn, self.screen_num)
}
pub fn conn(&self) -> &xcb::Connection {
&self.conn
}
pub fn default_screen_num(&self) -> i32 {
self.screen_num
}
pub fn default_screen(&self) -> Result<&x::Screen, err::BadScreenNumber> {
self.conn
.get_setup()
.roots()
.nth(self.screen_num as usize)
.ok_or(err::BadScreenNumber(self.screen_num))
}
pub fn monitors(&self) -> Result<Vec<Monitor>> {
let cookie = self
.conn
.send_request(
&randr::GetMonitors {
window: self.default_screen()?.root(),
get_active: true,
},
);
Ok(
self
.conn
.wait_for_reply(cookie)?
.monitors()
.map(|mon| Monitor {
name: self.get_atom_name(mon.name()),
primary: mon.primary(),
x: mon.x(),
y: mon.y(),
width: mon.width(),
height: mon.height(),
width_in_millimeters: mon.width_in_millimeters(),
height_in_millimeters: mon.height_in_millimeters(),
})
.collect(),
)
}
pub fn root_pixmap(&self) -> Result<RootPixmap<'_>> {
RootPixmap::new(self.conn(), self.default_screen()?)
}
fn get_atom_name(&self, atom: Atom) -> Option<String> {
let cookie = self.conn.send_request(&x::GetAtomName { atom });
let reply = self.conn.wait_for_reply(cookie).ok()?;
let name = reply.name();
(name.len() != 0).then(|| name.to_utf8().into_owned())
}
}
pub struct Monitor {
pub name: Option<String>,
pub primary: bool,
pub x: i16,
pub y: i16,
pub width: u16,
pub height: u16,
pub width_in_millimeters: u32,
pub height_in_millimeters: u32,
}
#[automatically_derived]
impl ::core::clone::Clone for Monitor {
#[inline]
fn clone(&self) -> Monitor {
Monitor {
name: ::core::clone::Clone::clone(&self.name),
primary: ::core::clone::Clone::clone(&self.primary),
x: ::core::clone::Clone::clone(&self.x),
y: ::core::clone::Clone::clone(&self.y),
width: ::core::clone::Clone::clone(&self.width),
height: ::core::clone::Clone::clone(&self.height),
width_in_millimeters: ::core::clone::Clone::clone(
&self.width_in_millimeters,
),
height_in_millimeters: ::core::clone::Clone::clone(
&self.height_in_millimeters,
),
}
}
}
#[automatically_derived]
impl ::core::fmt::Debug for Monitor {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ = &[
"name",
"primary",
"x",
"y",
"width",
"height",
"width_in_millimeters",
"height_in_millimeters",
];
let values: &[&dyn ::core::fmt::Debug] = &[
&self.name,
&self.primary,
&self.x,
&self.y,
&self.width,
&self.height,
&self.width_in_millimeters,
&&self.height_in_millimeters,
];
::core::fmt::Formatter::debug_struct_fields_finish(f, "Monitor", names, values)
}
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Monitor {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Monitor {
#[inline]
fn eq(&self, other: &Monitor) -> bool {
self.primary == other.primary && self.x == other.x && self.y == other.y
&& self.width == other.width && self.height == other.height
&& self.width_in_millimeters == other.width_in_millimeters
&& self.height_in_millimeters == other.height_in_millimeters
&& self.name == other.name
}
}
#[automatically_derived]
impl ::core::cmp::Eq for Monitor {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<Option<String>>;
let _: ::core::cmp::AssertParamIsEq<bool>;
let _: ::core::cmp::AssertParamIsEq<i16>;
let _: ::core::cmp::AssertParamIsEq<u16>;
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Monitor {
#[inline]
fn partial_cmp(
&self,
other: &Monitor,
) -> ::core::option::Option<::core::cmp::Ordering> {
match ::core::cmp::PartialOrd::partial_cmp(&self.name, &other.name) {
::core::option::Option::Some(::core::cmp::Ordering::Equal) => {
match ::core::cmp::PartialOrd::partial_cmp(
&self.primary,
&other.primary,
) {
::core::option::Option::Some(::core::cmp::Ordering::Equal) => {
match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) {
::core::option::Option::Some(
::core::cmp::Ordering::Equal,
) => {
match ::core::cmp::PartialOrd::partial_cmp(
&self.y,
&other.y,
) {
::core::option::Option::Some(
::core::cmp::Ordering::Equal,
) => {
match ::core::cmp::PartialOrd::partial_cmp(
&self.width,
&other.width,
) {
::core::option::Option::Some(
::core::cmp::Ordering::Equal,
) => {
match ::core::cmp::PartialOrd::partial_cmp(
&self.height,
&other.height,
) {
::core::option::Option::Some(
::core::cmp::Ordering::Equal,
) => {
match ::core::cmp::PartialOrd::partial_cmp(
&self.width_in_millimeters,
&other.width_in_millimeters,
) {
::core::option::Option::Some(
::core::cmp::Ordering::Equal,
) => {
::core::cmp::PartialOrd::partial_cmp(
&self.height_in_millimeters,
&other.height_in_millimeters,
)
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
}
#[automatically_derived]
impl ::core::cmp::Ord for Monitor {
#[inline]
fn cmp(&self, other: &Monitor) -> ::core::cmp::Ordering {
match ::core::cmp::Ord::cmp(&self.name, &other.name) {
::core::cmp::Ordering::Equal => {
match ::core::cmp::Ord::cmp(&self.primary, &other.primary) {
::core::cmp::Ordering::Equal => {
match ::core::cmp::Ord::cmp(&self.x, &other.x) {
::core::cmp::Ordering::Equal => {
match ::core::cmp::Ord::cmp(&self.y, &other.y) {
::core::cmp::Ordering::Equal => {
match ::core::cmp::Ord::cmp(&self.width, &other.width) {
::core::cmp::Ordering::Equal => {
match ::core::cmp::Ord::cmp(&self.height, &other.height) {
::core::cmp::Ordering::Equal => {
match ::core::cmp::Ord::cmp(
&self.width_in_millimeters,
&other.width_in_millimeters,
) {
::core::cmp::Ordering::Equal => {
::core::cmp::Ord::cmp(
&self.height_in_millimeters,
&other.height_in_millimeters,
)
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
cmp => cmp,
}
}
}
pub struct RootPixmap<'a> {
conn: &'a xcb::Connection,
screen: &'a x::Screen,
pixmap: x::Pixmap,
gc: x::Gcontext,
rgb_shifts: img::RgbShifts,
}
impl core::ops::Drop for RootPixmap<'_> {
fn drop(&mut self) {
self.conn.send_request(&x::FreeGc { gc: self.gc });
self.conn
.send_request(
&x::FreePixmap {
pixmap: self.pixmap,
},
);
}
}
impl<'a> RootPixmap<'a> {
pub fn new(conn: &'a xcb::Connection, scr: &'a x::Screen) -> Result<Self> {
let rgb_shifts = Self::get_rgb_shifts(scr)?;
let pixmap = conn.generate_id::<x::Pixmap>();
conn.send_and_check_request(
&x::CreatePixmap {
depth: scr.root_depth(),
pid: pixmap,
drawable: x::Drawable::Window(scr.root()),
width: scr.width_in_pixels(),
height: scr.height_in_pixels(),
},
)?;
let gc = conn.generate_id::<x::Gcontext>();
let cookie = conn
.send_request_checked(
&x::CreateGc {
cid: gc,
drawable: x::Drawable::Pixmap(pixmap),
value_list: &[],
},
);
conn.check_request(cookie)
.inspect_err(|_| {
conn.send_request(&x::FreePixmap { pixmap });
})?;
Ok(Self {
conn,
screen: scr,
pixmap,
gc,
rgb_shifts,
})
}
fn get_rgb_shifts(scr: &'a x::Screen) -> Result<img::RgbShifts> {
fn get_shift(mask: u32) -> Option<u8> {
let shift = mask.trailing_zeros();
((mask >> shift) == 0xff).then_some(shift as u8)
}
let root_depth = scr.root_depth();
let root_visual = scr.root_visual();
scr.allowed_depths()
.filter(|depth| depth.depth() == root_depth)
.flat_map(|depth| depth.visuals())
.find(|vis| vis.visual_id() == root_visual)
.ok_or(Error::CouldNotFindRootVisual(root_visual))
.and_then(|vis| {
if vis.class() == x::VisualClass::TrueColor
&& (root_depth == 24 || root_depth == 32)
{
let shifts = get_shift(vis.red_mask())
.zip(get_shift(vis.green_mask()))
.zip(get_shift(vis.blue_mask()));
if let Some(((r, g), b)) = shifts {
return Ok(img::RgbShifts { r, g, b });
}
}
Err(Error::UnsupportedVisual(root_depth, vis.class()))
})
}
pub fn rgb_shifts(&self) -> img::RgbShifts {
self.rgb_shifts
}
pub fn put_image(&self, x: i16, y: i16, img: impl img::View) -> Result {
let (img_width, img_height) = img.dimensions();
let dim = img_width.try_into().ok().zip(img_height.try_into().ok());
let (img_width, img_height): (u16, u16) = dim
.ok_or(Error::ImageTooLarge(img_width, img_height))?;
let img = img.as_rgb();
if usize::from(img_width) * usize::from(img_height) == img.len() {
let data = img
.iter()
.map(|&[r, g, b]| self.rgb_shifts.from_rgb(r, g, b))
.collect::<Vec<u32>>();
self.put_raw_impl(
x,
y,
img_width,
img_height,
bytemuck::must_cast_slice(data.as_slice()),
)
} else {
Err(Error::BadBufferSize(img.len(), img_width, img_height))
}
}
#[inline]
pub fn put_raw(
&self,
dst_x: i16,
dst_y: i16,
width: u16,
height: u16,
data: &[u32],
) -> Result {
if usize::from(width) * usize::from(height) == data.len() {
let data = bytemuck::must_cast_slice(data);
self.put_raw_impl(dst_x, dst_y, width, height, data)
} else {
Err(Error::BadBufferSize(data.len() * 4, width, height))
}
}
fn put_raw_impl(
&self,
dst_x: i16,
dst_y: i16,
width: u16,
height: u16,
data: &[u8],
) -> Result {
self.conn
.send_and_check_request(
&x::PutImage {
format: x::ImageFormat::ZPixmap,
drawable: x::Drawable::Pixmap(self.pixmap),
gc: self.gc,
width,
height,
dst_x,
dst_y,
left_pad: 0,
depth: self.screen.root_depth(),
data,
},
)
.map_err(Error::from)
}
pub fn set_background(&self) -> Result {
self.set_root_atoms();
self.conn.send_request(&x::KillClient { resource: 0 });
self.conn
.send_request(
&x::SetCloseDownMode {
mode: x::CloseDown::RetainTemporary,
},
);
self.conn
.send_and_check_request(
&x::ChangeWindowAttributes {
window: self.screen.root(),
value_list: &[x::Cw::BackPixmap(self.pixmap)],
},
)?;
self.conn
.send_request(
&x::ClearArea {
exposures: false,
window: self.screen.root(),
x: 0,
y: 0,
width: self.screen.width_in_pixels(),
height: self.screen.height_in_pixels(),
},
);
Ok(())
}
fn set_root_atoms(&self) {
let mut killed = None;
for name in ["_XROOTPMAP_ID", "ESETROOT_PMAP_ID"] {
let mut intern_request = x::InternAtom {
only_if_exists: true,
name: name.as_bytes(),
};
let cookie = self.conn.send_request(&intern_request);
let atom = self
.conn
.wait_for_reply(cookie)
.and_then(|reply| {
let atom = reply.atom();
if atom.is_none() {
intern_request.only_if_exists = false;
let cookie = self.conn.send_request(&intern_request);
self.conn.wait_for_reply(cookie).map(|reply| reply.atom())
} else {
self.clean_root_atom(atom, &mut killed);
Ok(atom)
}
});
let atom = match atom {
Err(_err) => {
return;
}
Ok(atom) if atom.is_none() => {
return;
}
Ok(atom) => atom,
};
self.conn
.send_request(
&x::ChangeProperty {
mode: x::PropMode::Replace,
window: self.screen.root(),
property: atom,
r#type: x::ATOM_PIXMAP,
data: &[self.pixmap.resource_id()],
},
);
}
}
fn clean_root_atom(&self, atom: Atom, prev_killed: &mut Option<u32>) {
let cookie = self
.conn
.send_request(
&x::GetProperty {
delete: false,
window: self.screen.root(),
property: atom,
r#type: x::ATOM_ANY,
long_offset: 0,
long_length: 1,
},
);
let reply = match self.conn.wait_for_reply(cookie) {
Ok(reply) => reply,
Err(_err) => {
return;
}
};
if reply.r#type() == x::ATOM_PIXMAP && reply.format() == 32
&& reply.length() == 1 && reply.bytes_after() == 0
{
let pixmap_id = reply.value::<u32>().first().copied().unwrap_or_default();
if pixmap_id != 0 && Some(pixmap_id) != *prev_killed {
let pixmap = unsafe { x::Pixmap::new(pixmap_id) };
self.conn
.send_request(
&x::KillClient {
resource: pixmap.resource_id(),
},
);
*prev_killed = Some(pixmap_id);
}
}
}
}