use std::fs::File; use std::os::unix::prelude::AsFd; use calloop::EventLoop; use calloop_wayland_source::WaylandSource; use wayland_client::protocol::{ wl_buffer, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool, wl_surface, }; use wayland_client::{delegate_noop, Connection, Dispatch, QueueHandle, WEnum}; use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base}; fn main() { let conn = Connection::connect_to_env().unwrap(); let event_queue = conn.new_event_queue(); let qhandle = event_queue.handle(); let display = conn.display(); display.get_registry(&qhandle, ()); let mut event_loop: EventLoop = EventLoop::try_new().expect("Failed to initialize the event loop!"); let loop_handle = event_loop.handle(); WaylandSource::new(conn, event_queue).insert(loop_handle).unwrap(); let stop_handle = event_loop.get_signal(); let mut state = State { running: true, base_surface: None, buffer: None, wm_base: None, xdg_surface: None, configured: false, stop_handle, }; println!("Starting the example window app, press to quit."); event_loop.run(None, &mut state, |_| {}).unwrap(); } struct State { running: bool, base_surface: Option, buffer: Option, wm_base: Option, xdg_surface: Option<(xdg_surface::XdgSurface, xdg_toplevel::XdgToplevel)>, configured: bool, stop_handle: calloop::LoopSignal, } impl Dispatch for State { fn event( state: &mut Self, registry: &wl_registry::WlRegistry, event: wl_registry::Event, _: &(), _: &Connection, qh: &QueueHandle, ) { if let wl_registry::Event::Global { name, interface, .. } = event { match &interface[..] { "wl_compositor" => { let compositor = registry.bind::(name, 1, qh, ()); let surface = compositor.create_surface(qh, ()); state.base_surface = Some(surface); if state.wm_base.is_some() && state.xdg_surface.is_none() { state.init_xdg_surface(qh); } }, "wl_shm" => { let shm = registry.bind::(name, 1, qh, ()); let (init_w, init_h) = (320, 240); let mut file = tempfile::tempfile().unwrap(); draw(&mut file, (init_w, init_h)); let pool = shm.create_pool(file.as_fd(), (init_w * init_h * 4) as i32, qh, ()); let buffer = pool.create_buffer( 0, init_w as i32, init_h as i32, (init_w * 4) as i32, wl_shm::Format::Argb8888, qh, (), ); state.buffer = Some(buffer.clone()); if state.configured { let surface = state.base_surface.as_ref().unwrap(); surface.attach(Some(&buffer), 0, 0); surface.commit(); } }, "wl_seat" => { registry.bind::(name, 1, qh, ()); }, "xdg_wm_base" => { let wm_base = registry.bind::(name, 1, qh, ()); state.wm_base = Some(wm_base); if state.base_surface.is_some() && state.xdg_surface.is_none() { state.init_xdg_surface(qh); } }, _ => {}, } } } } // Ignore events from these object types in this example. delegate_noop!(State: ignore wl_compositor::WlCompositor); delegate_noop!(State: ignore wl_surface::WlSurface); delegate_noop!(State: ignore wl_shm::WlShm); delegate_noop!(State: ignore wl_shm_pool::WlShmPool); delegate_noop!(State: ignore wl_buffer::WlBuffer); fn draw(tmp: &mut File, (buf_x, buf_y): (u32, u32)) { use std::cmp::min; use std::io::Write; let mut buf = std::io::BufWriter::new(tmp); for y in 0..buf_y { for x in 0..buf_x { let a = 0xFF; let r = min(((buf_x - x) * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y); let g = min((x * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y); let b = min(((buf_x - x) * 0xFF) / buf_x, (y * 0xFF) / buf_y); let color = (a << 24) + (r << 16) + (g << 8) + b; buf.write_all(&color.to_ne_bytes()).unwrap(); } } buf.flush().unwrap(); } impl State { fn init_xdg_surface(&mut self, qh: &QueueHandle) { let wm_base = self.wm_base.as_ref().unwrap(); let base_surface = self.base_surface.as_ref().unwrap(); let xdg_surface = wm_base.get_xdg_surface(base_surface, qh, ()); let toplevel = xdg_surface.get_toplevel(qh, ()); toplevel.set_title("A fantastic window!".into()); base_surface.commit(); self.xdg_surface = Some((xdg_surface, toplevel)); } } impl Dispatch for State { fn event( _: &mut Self, wm_base: &xdg_wm_base::XdgWmBase, event: xdg_wm_base::Event, _: &(), _: &Connection, _: &QueueHandle, ) { if let xdg_wm_base::Event::Ping { serial } = event { wm_base.pong(serial); } } } impl Dispatch for State { fn event( state: &mut Self, xdg_surface: &xdg_surface::XdgSurface, event: xdg_surface::Event, _: &(), _: &Connection, _: &QueueHandle, ) { if let xdg_surface::Event::Configure { serial, .. } = event { xdg_surface.ack_configure(serial); state.configured = true; let surface = state.base_surface.as_ref().unwrap(); if let Some(ref buffer) = state.buffer { surface.attach(Some(buffer), 0, 0); surface.commit(); } } } } impl Dispatch for State { fn event( state: &mut Self, _: &xdg_toplevel::XdgToplevel, event: xdg_toplevel::Event, _: &(), _: &Connection, _: &QueueHandle, ) { if let xdg_toplevel::Event::Close {} = event { state.running = false; } } } impl Dispatch for State { fn event( _: &mut Self, seat: &wl_seat::WlSeat, event: wl_seat::Event, _: &(), _: &Connection, qh: &QueueHandle, ) { if let wl_seat::Event::Capabilities { capabilities: WEnum::Value(capabilities) } = event { if capabilities.contains(wl_seat::Capability::Keyboard) { seat.get_keyboard(qh, ()); } } } } impl Dispatch for State { fn event( state: &mut Self, _: &wl_keyboard::WlKeyboard, event: wl_keyboard::Event, _: &(), _: &Connection, _: &QueueHandle, ) { if let wl_keyboard::Event::Key { key, .. } = event { if key == 1 { // ESC key state.stop_handle.stop(); } } } }