Skip to content

Commit

Permalink
Switch to x11rb from xcb
Browse files Browse the repository at this point in the history
xcb is unmaintained and has several soundness issues
(rustsec/advisory-db#653).
x11rb provides an equivalent API and also avoids the dependency on
libxcb, allowing the build and distribution of an entirely static
executable.
  • Loading branch information
FallenWarrior2k committed May 31, 2021
1 parent 7cab1da commit 3cdb0a5
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 67 deletions.
92 changes: 72 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ edition = "2018"
anyhow = "1.0.40"
image = { version = "0.23.14", default-features = false, features = ["png"] }
imageproc = { version = "0.22.0", default-features = false }
xcb = "0.9.0"
x11rb = "0.8.1"
89 changes: 43 additions & 46 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use anyhow::{anyhow, bail, Context};
use image::{Bgra, DynamicImage, ImageBuffer, ImageOutputFormat, Rgb, Rgba};
use imageproc::map::map_pixels;
use std::{convert::TryInto, env::args_os, io::stdout};
use xcb::{
ffi::XCB_IMAGE_FORMAT_Z_PIXMAP, get_geometry, get_image, get_property, intern_atom, Pixmap,
ATOM_PIXMAP,
use std::{env::args_os, io::stdout};
use x11rb::{
connection::Connection,
protocol::xproto::{AtomEnum, ConnectionExt, ImageFormat, Pixmap},
};

const RGBA_DEPTH: u8 = 32;
Expand All @@ -30,58 +30,55 @@ fn main() -> anyhow::Result<()> {
return Ok(());
}

let (c, _) = &xcb::Connection::connect(None)?;
let (c, screen_num) = x11rb::connect(None)?;
let root = c.setup().roots[screen_num].root;

let root = c
.get_setup()
.roots()
.next()
.ok_or_else(|| anyhow!("No screen???"))?
.root();

let bg_atom = intern_atom(c, true, "_XROOTPMAP_ID")
.get_reply()
let bg_atom = c
.intern_atom(true, b"_XROOTPMAP_ID")
.context("Failed to create cookie to retrieve background atom ID")?
.reply()
.context("Failed to get background atom ID")?
.atom();
.atom;

let prop = get_property(c, false, root, bg_atom, ATOM_PIXMAP, 0, 1)
.get_reply()
let prop = c
.get_property(false, root, bg_atom, AtomEnum::PIXMAP, 0, 1)
.context("Failed to create cookie to get background pixmap")?
.reply()
.context("Failed to get background pixmap")?;

// This is what Polybar does and it works
if prop.format() != 32 {
bail!("Unexpected pixmap reply format: {}", prop.format());
}
if prop.value_len() != 1 {
bail!("Unexpected pixmap reply length: {}", prop.value_len());
let mut value_iter = prop
.value32()
.with_context(|| format!("Unexpected pixmap reply format {}", prop.format))?;
let pixmap: Pixmap = value_iter.next().context("No background pixmap set")?;
if value_iter.next() != None {
bail!("Unexpected pixmap reply length: {}", prop.value_len);
}

let pixmap: Pixmap = prop.value()[0];
let geometry = get_geometry(c, pixmap)
.get_reply()
let geometry = c
.get_geometry(pixmap)
.context("Failed to create cookie to retrieve background geometry")?
.reply()
.context("Failed to grab background geometry")?;

let image = get_image(
c,
XCB_IMAGE_FORMAT_Z_PIXMAP.try_into().unwrap(),
pixmap,
geometry.x(),
geometry.y(),
geometry.width(),
geometry.height(),
!0, // All planes; X doesn't about extra bits
)
.get_reply()
.context("Failed to grab background contents")?;

let raw_image = BgraImage::from_raw(
geometry.width().into(),
geometry.height().into(),
image.data().into(),
)
.ok_or_else(|| anyhow!("Failed to create image"))?;

let image = match image.depth() {
let image = c
.get_image(
ImageFormat::Z_PIXMAP,
pixmap,
geometry.x,
geometry.y,
geometry.width,
geometry.height,
!0, // All planes; X doesn't about extra bits
)
.context("Failed to create cookie to retrieve background contents")?
.reply()
.context("Failed to grab background contents")?;

let raw_image = BgraImage::from_raw(geometry.width.into(), geometry.height.into(), image.data)
.ok_or_else(|| anyhow!("Failed to create image"))?;

let image = match image.depth {
// I haven't actually tested this; it's just conjecture from 24-bit being BGR0
RGBA_DEPTH => {
DynamicImage::ImageRgba8(map_pixels(&raw_image, |_, _, Bgra([b, g, r, a])| {
Expand Down

0 comments on commit 3cdb0a5

Please sign in to comment.