use breadx::{display::DisplayConnection, prelude::*, protocol::xproto};
use breadx_image::Image;
use std::{boxed::Box, error::Error, io::Cursor};
const EISENHOWER: &[u8] = include_bytes!("../images/eisenhower.png");
#[cfg(feature = "std")]
fn main() -> Result<(), Box<dyn Error>> {
tracing_subscriber::fmt::init();
use breadx::protocol::Event;
use breadx_image::DisplayExt;
let mut conn = DisplayConnection::connect(None)?;
let events = xproto::EventMask::EXPOSURE;
let background = conn.default_screen().white_pixel;
let parent = conn.default_screen().root;
let img = image::io::Reader::with_format(Cursor::new(EISENHOWER), image::ImageFormat::Png)
.decode()?;
let img = img.to_rgb8();
let wid = conn.generate_xid()?;
conn.create_window_checked(
0, wid,
parent,
0,
0,
img.width() as _,
img.height() as _,
0,
xproto::WindowClass::COPY_FROM_PARENT,
0,
xproto::CreateWindowAux::new()
.event_mask(events)
.background_pixel(background),
)?;
conn.map_window_checked(wid)?;
let title = "Eisenhower";
conn.change_property(
xproto::PropMode::REPLACE,
wid,
xproto::AtomEnum::WM_NAME.into(),
xproto::AtomEnum::STRING.into(),
8,
title.len() as u32,
title,
)?;
let window_gc = conn.generate_xid()?;
conn.create_gc(
window_gc,
wid,
xproto::CreateGCAux::new().graphics_exposures(0),
)?;
let depth = conn.get_geometry_immediate(wid)?.depth;
let format = xproto::ImageFormat::XY_PIXMAP;
let len =
breadx_image::storage_bytes(img.width() as _, img.height() as _, depth, None, format, 32);
let mut ximage = Image::with_display(
vec![0; len],
img.width() as _,
img.height() as _,
format,
depth,
conn.setup(),
)?;
for (x, y, pixel) in img.enumerate_pixels() {
let [r, g, b] = pixel.0;
let channel = ((r as u32) << 16) | ((g as u32) << 8) | b as u32;
ximage.set_pixel(x as _, y as _, channel);
}
let pixmap = conn.generate_xid()?;
let pixmap_gc = conn.generate_xid()?;
conn.create_pixmap_checked(depth, pixmap, wid, img.width() as _, img.height() as _)?;
conn.create_gc_checked(
pixmap_gc,
pixmap,
xproto::CreateGCAux::new()
.foreground(conn.default_screen().black_pixel)
.graphics_exposures(0),
)?;
conn.put_ximage_checked(&ximage, pixmap, pixmap_gc, 0, 0)?;
let wm_protocols = conn.intern_atom(false, "WM_PROTOCOLS")?;
let wm_delete_window = conn.intern_atom(false, "WM_DELETE_WINDOW")?;
let wm_protocols = conn.wait_for_reply(wm_protocols)?.atom;
let wm_delete_window = conn.wait_for_reply(wm_delete_window)?.atom;
conn.change_property(
xproto::PropMode::REPLACE,
wid,
wm_protocols,
xproto::AtomEnum::ATOM.into(),
32,
1,
&wm_delete_window,
)?;
loop {
let event = conn.wait_for_event()?;
match event {
Event::Expose(_) => {
conn.copy_area_checked(
pixmap,
wid,
window_gc,
0,
0,
0,
0,
img.width() as _,
img.height() as _,
)?;
}
Event::ClientMessage(cme) => {
if cme.data.as_data32()[0] == wm_delete_window {
break;
}
}
_ => {}
}
}
Ok(())
}
#[cfg(not(feature = "std"))]
fn main() {
println!("This example requires the `std` feature to be enabled");
}