#![allow( clippy::cast_sign_loss, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_possible_truncation )] use anyhow::Result; use wayland_client::{ globals::registry_queue_init, protocol::{ wl_compositor::WlCompositor, wl_seat::WlSeat, wl_shm::{self, WlShm}, wl_surface::WlSurface, }, Connection, }; use wayland_protocols_wlr::layer_shell::v1::client::{ zwlr_layer_shell_v1::{self, ZwlrLayerShellV1}, zwlr_layer_surface_v1::{self, ZwlrLayerSurfaceV1}, }; use crate::{ key_map::KeyMap, wayland::{ ansi::Color, river::protocols::river_protocols::zriver_status_manager_v1::ZriverStatusManagerV1, shm::slot::{Buffer, SlotPool}, }, }; mod ansi; mod render; mod river; mod shm; mod dispatches; struct AppData { pool: SlotPool, window: (ZwlrLayerSurfaceV1, WlSurface), configured: bool, buffer: Option, width: u32, height: u32, max_px_width: u32, pixel_data: (Vec, Vec>), config: KeyMap, should_exit: bool, } impl AppData { #[allow(clippy::too_many_lines)] fn draw(&mut self) { let width = self.width; let height = self.height; let stride = self.width as i32 * 4; let buffer = self.buffer.get_or_insert_with(|| { self.pool .create_buffer( width as i32, height as i32, stride, wl_shm::Format::Argb8888, ) .expect("Works?") .0 }); let canvas = if let Some(canvas) = self.pool.canvas(buffer) { canvas } else { // This should be rare, but if the compositor has not released the previous // buffer, we need double-buffering. let (second_buffer, canvas) = self .pool .create_buffer( self.width as i32, self.height as i32, stride, wl_shm::Format::Argb8888, ) .expect("create buffer"); *buffer = second_buffer; canvas }; // Draw to the window. { canvas .chunks_exact_mut(stride as usize) .enumerate() .for_each(|(row_index, row)| { // let row_slice = row_slice(self.height, row_index as u32, 0.97); // let allowed_columns = (f64::from(self.width) * row_slice).ceil() as usize; row.chunks_exact_mut(4) .enumerate() .for_each(|(column_index, chunk)| { // const BACKGROUND_COLOR: u32 = 0xee58_5b70; const BACKGROUND_COLOR: u32 = 0xee00_0000; assert!(column_index as u32 <= self.width); // if column_index > allowed_columns // || column_index < (self.width as usize - allowed_columns) // { // let array: &mut [u8; 4] = chunk.try_into().unwrap(); // *array = 0u32.to_le_bytes(); // return; // } if column_index >= (self.max_px_width as usize) { let array: &mut [u8; 4] = chunk.try_into().unwrap(); *array = BACKGROUND_COLOR.to_le_bytes(); } else { assert!(column_index < self.max_px_width as usize); let position = column_index + row_index * self.max_px_width as usize; if let Some(coverage) = &self.pixel_data.0.get(position) { let a = (BACKGROUND_COLOR & (0xff << (6 * 4))) >> 24; let (r, g, b) = if let Some(color) = self .pixel_data .1 .get(position) .expect("If the pixel is set, the color will too") { let (r, g, b) = match color { Color::Black => (0, 0, 0), Color::Red => (0xff, 0, 0), Color::Green => (0, 0xff, 0), Color::Yellow => (0xff, 0xff, 0), Color::Blue => (0, 0, 0xff), Color::Purple => (0x80, 0, 0x80), Color::Cyan => (0, 0xff, 0xff), Color::White => (0xff, 0xff, 0xff), }; let r = (r as f32 * **coverage).ceil() as u32; let g = (g as f32 * **coverage).ceil() as u32; let b = (b as f32 * **coverage).ceil() as u32; (r, g, b) } else { let r = (255.0 * **coverage).ceil() as u32; let g = (255.0 * **coverage).ceil() as u32; let b = (255.0 * **coverage).ceil() as u32; (r, g, b) }; let color: u32 = (a << 24) + (r << 16) + (g << 8) + b; let array: &mut [u8; 4] = chunk.try_into().unwrap(); *array = color.to_le_bytes(); } else { let array: &mut [u8; 4] = chunk.try_into().unwrap(); *array = BACKGROUND_COLOR.to_le_bytes(); } } }); }); } self.window .1 .damage_buffer(0, 0, self.width as i32, self.height as i32); buffer.attach_to(&self.window.1).expect("works"); self.window.1.commit(); } } /// # Errors /// If a protocol error arises. pub fn main(config: KeyMap) -> Result<()> { let conn = Connection::connect_to_env()?; let (globals, mut queue) = registry_queue_init::(&conn)?; let qh = queue.handle(); let seat: WlSeat = globals.bind(&qh, 9..=9, ())?; let status_manager: ZriverStatusManagerV1 = globals.bind(&qh, 4..=4, ())?; let _seat_status = status_manager.get_river_seat_status(&seat, &qh, ()); let compositor: WlCompositor = globals.bind(&qh, 6..=6, ())?; let shm: WlShm = globals.bind(&qh, 1..=1, ())?; // let xdg_wm: XdgWmBase = globals.bind(&qh, 5..=5, ())?; let surface = compositor.create_surface(&qh, ()); let pool = SlotPool::new(1024 * 1024, &shm)?; let zwlr_layer_shell: ZwlrLayerShellV1 = globals.bind(&qh, 4..=4, ())?; let layer_surface = zwlr_layer_shell.get_layer_surface( &surface, None, zwlr_layer_shell_v1::Layer::Overlay, "river-mk-keymap which-key".to_owned(), &qh, (), ); layer_surface.set_size(256, 256); layer_surface .set_anchor(zwlr_layer_surface_v1::Anchor::Left | zwlr_layer_surface_v1::Anchor::Top); surface.commit(); let mut me = AppData { config, should_exit: false, configured: false, buffer: None, width: 256, height: 256, max_px_width: 0, pixel_data: (vec![], vec![]), window: (layer_surface, surface), pool, }; loop { queue.blocking_dispatch(&mut me)?; if me.should_exit { break; } } Ok(()) } // /// Calculate which amount of the current row (`i`) should be painted, if we want a corner // /// rounding of percent `p` and have an total of `n` rows. // fn row_slice(n_u32: u32, i_u32: u32, p: f64) -> f64 { // fn within_tolerance(a: f64, b: f64) -> bool { // const ALLOWED_ERROR: f64 = 0.000_000_1; // // (a - b).abs() < ALLOWED_ERROR // } // // let i = f64::from(i_u32); // let n = f64::from(n_u32); // // let out = p + (1.0 - p) * (PI * i / n).sin(); // // assert!(out >= 0.0); // assert!(out <= 1.0); // // if i_u32 == 0 || i_u32 == n_u32 { // assert!(within_tolerance(out, p)); // } // // if i_u32 < n_u32 / 2 { // assert!(within_tolerance(out, row_slice(n_u32, n_u32 - i_u32, p))); // } // // out // }