From c17cd5df4ef11c5a9484c7a47124462554a9c8a5 Mon Sep 17 00:00:00 2001 From: stickynotememo Date: Fri, 2 Jan 2026 09:07:43 +1100 Subject: [PATCH] Reinit --- src/main.rs | 351 +--------------------------------------------------- 1 file changed, 2 insertions(+), 349 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0548313..2105cf9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,350 +1,3 @@ -#![feature(more_qualified_paths)] -use std::fs::File; -use std::ffi::CString; -use std::os::fd::BorrowedFd; - -use memmap2::{MmapMut, MmapOptions}; - -use wayland_client::{ - Connection, Dispatch, EventQueue, Proxy, delegate_noop, protocol::{ - wl_buffer::WlBuffer, - wl_compositor::{self, WlCompositor}, - wl_registry, - wl_shm::{self, Format, WlShm}, - wl_shm_pool::{self, WlShmPool}, - wl_surface::WlSurface, - } -}; - -use libc::{O_CREAT, O_RDWR, S_IROTH, S_IRWXU, ftruncate, shm_open}; - -use wayland_protocols::xdg::shell::client::{ - xdg_surface::XdgSurface, - xdg_toplevel::XdgToplevel, - xdg_wm_base::{self, XdgWmBase}, - }; - -const WIDTH: i32 = 960; -const HEIGHT: i32 = 540; - -#[derive(Debug)] -struct State { - exit: bool, - _ready: bool, - compositor: Option, - surface: Option, - shm: Option, - formats: Vec, - buffer: Option, - wm_base: Option, - xdg_surface: Option, - toplevel_surface: Option, - pool: Option, - memory_map: Option, -} - -impl Dispatch for State { - fn event( - state: &mut Self, - proxy: &wl_registry::WlRegistry, - event: ::Event, - data: &(), - _conn: &Connection, - qhandle: &wayland_client::QueueHandle, - ) { - // Iterate over the globals given by the registry. - // Use the details from the global (name & version) to bind the proxy to the state - // variable, specifying which global is beiong bound in the turbofish of proxy.bind() - if let wl_registry::Event::Global { - name, - interface, - version, - } = event - { - match interface.as_str() { - "wl_compositor" => { - let compositor = proxy - .bind::(name, version, qhandle, *data); - let surface = compositor.create_surface(qhandle, *data); - state.compositor = Some(compositor); - state.surface = Some(surface); - } - "wl_shm" => { - let shm = proxy.bind::(name, version, qhandle, *data); - state.shm = Some(shm); - } - "xdg_wm_base" => { - let wm_base = - proxy.bind::(name, version, qhandle, *data); - state.wm_base = Some(wm_base); - } - _ => { - // do nothing - } - }; - } - } -} - -impl Dispatch for State { - fn event( - state: &mut Self, - proxy: &WlShm, - event: ::Event, - data: &(), - _conn: &Connection, - qhandle: &wayland_client::QueueHandle, - ) { - if let ::Event::Format { format } = event { - if let None = state.pool { - state.formats.push( - format - .into_result() - .expect("Couldn't understand format, or it was unknown"), - ); - // Any wayland client must support Xrgb8888 and Argb8888 - let channels: i32 = if state.formats.contains(&Format::Xrgb8888) { - 4 - } else { - 4 - }; // we know that the supported formats are only the two above, so we can safely assume that any format which is not Xrgb8888 is Argb8888, requiring 4 channels. - // FIX: 3 channels won't work, even with Xrgb8888 for some reason - // TODO: Update for more channels - - let size: i32 = (WIDTH * HEIGHT * channels * 2).try_into().unwrap(); - let name = CString::new("/wolf_renderer_buffer").expect("CString::new() failed"); // CString::new can only fail if a null byte is in the string. This string should never cause errors - - let shm_fd = unsafe { - // SAFETY: We know that that at least a few megabytes of memory - // should be able to be allocated for the virtual buffer. - // Data races should not be possible as the compositor will - // not modify the buffer. (Non owners do not have write - // permissions) - // - // TODO: Use shared_memory and implement FD return - - let fildes = shm_open(name.as_ptr(), O_RDWR | O_CREAT, S_IRWXU | S_IROTH); - if fildes <= 0 { - panic!("Could not open SHM object. Error code: N/A") // TODO: implement errno reading - }; - ftruncate(fildes, size.into()); - BorrowedFd::borrow_raw(fildes) - }; - - let shm_file = File::from(shm_fd.try_clone_to_owned().unwrap()); // Converts borrowed - // to owned. Are there problems with this? - - let mmap = unsafe { - // SAFETY: This effectively creates a memory map from a raw - // pointer. As above, as long as the compositor does not - // mutate the underlying shared memory pool, mutations - // should be safe and not cause data races [undefined.race] - // https://doc.rust-lang.org/reference/behavior-considered-undefined.html#r-undefined.alias - MmapOptions::new() - .len(size as usize) - .map_mut(&shm_file) - .unwrap() - }; - - state.memory_map = Some(mmap); - let shm_pool = proxy.create_pool(shm_fd, size.try_into().unwrap(), qhandle, *data); - // TODO: Move drawing logic to event loop (double flush) - state.pool = Some(shm_pool); - }; - } else { - unimplemented!() - } - } -} - -impl Dispatch for State { - fn event( - _state: &mut Self, - _proxy: &WlBuffer, - _event: ::Event, - _data: &(), - _conn: &Connection, - _qhandle: &wayland_client::QueueHandle, - ) { - } -} - -impl Dispatch for State { - fn event( - state: &mut Self, - _proxy: &XdgWmBase, - event: ::Event, - _data: &(), - _conn: &Connection, - _qhandle: &wayland_client::QueueHandle, - ) { - if let xdg_wm_base::Event::Ping { serial } = event { - state.wm_base.as_ref().unwrap().pong(serial); // Ok to unwrap as a ping won't be recieved until - // all the globals are bound (including xdg_wm_base) - // TODO: figure out as_ref - } else { - unreachable!(); - }; - } -} - -impl Dispatch for State { - fn event( - _state: &mut Self, - proxy: &XdgSurface, - event: ::Event, - _data: &(), - _conn: &Connection, - _qhandle: &wayland_client::QueueHandle, - ) { - if let ::Event::Configure { serial } = event { - proxy.ack_configure(serial); - } - } -} - -impl Dispatch for State { - fn event( - _state: &mut Self, - _proxy: &XdgToplevel, - event: ::Event, - _data: &(), - _conn: &Connection, - _qhandle: &wayland_client::QueueHandle, - ) { - if let ::Event::Configure { - width: _, - height: _, - states: _, - } = event - { - // state.xdg_surface.unwrap().ack_configure(serial); - // FIX: Figure out what serial I need for ack_configure with a toplevel - // xdg_surface - } - } -} - -impl Dispatch for State { - fn event( - _state: &mut Self, - _proxy: &WlSurface, - _event: ::Event, - _data: &(), - _conn: &Connection, - _qhandle: &wayland_client::QueueHandle, - ) { - } -} -delegate_noop!(State: wl_shm_pool::WlShmPool); -delegate_noop!(State: wl_compositor::WlCompositor); - -fn main() { - let Ok(conn) = Connection::connect_to_env() else { - panic!("Couldn't connect to Wayland environment"); - }; - - let mut state = State { - exit: false, - _ready: false, - formats: vec![], - compositor: None, - surface: None, - shm: None, - buffer: None, - wm_base: None, - xdg_surface: None, - toplevel_surface: None, - pool: None, - memory_map: None - }; - - let mut event_queue: EventQueue = conn.new_event_queue(); - - let display = conn.display(); - let qh = &event_queue.handle(); - - display.get_registry(&qh, ()); - while !state.exit { - event_queue.roundtrip(&mut state).unwrap(); - event_queue.flush().expect("hopefully flushed"); // TODO: expect - // Assign roles to the surface as required, then attach the buffer, damage and commit - if let None = &state.toplevel_surface { - if let (Some(base), Some(surface), Some(buffer)) = - (&state.wm_base, &state.surface, &state.buffer) - { - // Buffer is required because it is to be attached to the surface. - let xdg_surface = base.get_xdg_surface(surface, qh, ()); // HACK: udata =/ () - let toplevel_surface = xdg_surface.get_toplevel(qh, ()); // HACK: udata =/ () - - state.xdg_surface = Some(xdg_surface); - state.toplevel_surface = Some(toplevel_surface); - - surface.attach(Some(buffer), 0, 0); - surface.damage(0, 0, WIDTH, HEIGHT); - surface.commit(); - }; - } - - if let Some(shm_pool) = &state.pool { - let format = if state.formats.contains(&Format::Xrgb8888) { - Format::Xrgb8888 - } else { - Format::Argb8888 - }; - - let channel_count = match format { - Format::Xrgb8888 => 4, - Format::Argb8888 => 4, - _ => unimplemented!("Other formats not supported") - }; - // FIX: 3 channels won't work, even with Xrgb8888 for some reason - // TODO: Update for more channels - - let _size: i32 = (WIDTH * HEIGHT * channel_count * 2).try_into().unwrap(); - - let buffer = shm_pool.create_buffer( - 0, - WIDTH.try_into().unwrap(), - HEIGHT.try_into().unwrap(), - (WIDTH * channel_count).try_into().unwrap(), - if state.formats.contains(&Format::Xrgb8888) { - Format::Xrgb8888 - } else { - Format::Argb8888 - }, - qh, - (), - ); - state.buffer = Some(buffer.clone()); - } - - state._ready = if let (Some(_), Some(_), Some(_), Some(_), Some(_), Some(mmap)) = ( - &state.compositor, - &state.surface, - &state.shm, - &state.buffer, - &state.wm_base, - &mut state.memory_map, - ) { - draw(mmap); - true - } else { - false - }; - } -} - -fn draw(memory_map: &mut MmapMut) { // TODO: WlCallback on frame - let mut pixel: u64 = 0; - - for byte in &mut **memory_map { - let pixel_offset = (pixel % 4) as u8; - pixel += 1; - - *byte = match pixel_offset { - 1 => 0, - _ => 255 - }; - }; +fn main () { + println!("Hello World!"); }