From 2b3048facaa981d81c227f9867d408eac8c20e92 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 12 Jan 2025 22:50:00 +0100 Subject: [PATCH] Rework the initial wayland init a bit --- src/buffer.rs | 9 +- src/main.rs | 26 ++++- src/state.rs | 291 ++++++++++++++++++++++++++++---------------------- 3 files changed, 192 insertions(+), 134 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index e63363a..e015914 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -82,16 +82,18 @@ pub struct ShmBuffer { pub mmap: MmapMut, pub buffer: wl_buffer::WlBuffer, pub refcnt: u32, + pub id: u32, } impl ShmBuffer { - pub fn new( + fn new( shm: &wl_shm::WlShm, qh: &QueueHandle, width: i32, height: i32, stride: i32, format: wl_shm::Format, + id: u32, ) -> io::Result where D: Dispatch + Dispatch + 'static, @@ -108,6 +110,7 @@ impl ShmBuffer { file, mmap, buffer, + id, }) } @@ -122,12 +125,14 @@ impl ShmBuffer { pub struct BufferManager { pub buffers: Vec, + pub next_id: u32, } impl BufferManager { pub fn new() -> BufferManager { BufferManager { buffers: Vec::new(), + next_id: 0, } } @@ -162,8 +167,10 @@ impl BufferManager { dimensions.1, dimensions.0 * 4, wl_shm::Format::Argb8888, + self.next_id, ) .expect("unable to add buffer"); + self.next_id += 1; BufferView::new(&mut buf.mmap, (dimensions.0 as u32, dimensions.1 as u32)); self.buffers.push(buf); } diff --git a/src/main.rs b/src/main.rs index a189eba..d1a6dae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -82,6 +82,7 @@ fn main() { let display = conn.display(); display.get_registry(&qhandle, ()); + display.sync(&qhandle, ()); let (ping_sender, ping_source) = calloop::ping::make_ping().unwrap(); let (keyrepeat_sender, keyrepeat_channel) = calloop::channel::channel::(); @@ -224,12 +225,21 @@ fn main() { damage.push(Geometry::new()); } + // Initial setup + // + while state.running && !state.ready { + event_loop + .dispatch(None, &mut state) + .expect("Could not dispatch event loop"); + } + state.check_registry(&qhandle); + while state.running { event_loop .dispatch(None, &mut state) .expect("Could not dispatch event loop"); - if !state.configured || !state.dirty { + if !state.configured || !state.dirty || !state.ready { continue; } @@ -243,8 +253,16 @@ fn main() { let buf = match state.bufmgr.next_buffer() { Some(b) => b, None => { - // We are still waiting for our buffer - continue; + if state.bufmgr.buffers.len() >= 3 { + continue; + } + state.add_buffer(&qhandle); + match state.bufmgr.next_buffer() { + Some(b) => b, + None => { + continue; + } + } } }; @@ -297,7 +315,9 @@ fn main() { } } + state.ready = false; surface.attach(Some(&buf.buffer), 0, 0); + surface.frame(&qhandle, ()); surface.commit(); conn.flush().unwrap(); diff --git a/src/state.rs b/src/state.rs index 0aea95d..da2a611 100644 --- a/src/state.rs +++ b/src/state.rs @@ -9,7 +9,7 @@ use std::{ use wayland_client::{ protocol::{ wl_buffer, wl_compositor, wl_keyboard, wl_pointer, wl_registry, wl_seat, wl_shm, - wl_shm_pool, wl_subcompositor, wl_subsurface, wl_surface, + wl_shm_pool, wl_subcompositor, wl_subsurface, wl_surface, wl_callback, }, Connection, Dispatch, QueueHandle, WEnum, }; @@ -54,9 +54,14 @@ pub struct BackgroundSurface { #[derive(Default)] pub struct Protocols { + wl_compositor: Option, + wl_subcompositor: Option, wl_shm: Option, + xdg_wm_base: Option, xdg_activation: Option, + zwlr_layer_shell: Option, viewporter: Option, + wp_single_pixel_buffer_manager: Option, } pub struct State { @@ -66,6 +71,7 @@ pub struct State { pub bg_surface: BackgroundSurface, pub protocols: Protocols, pub running: bool, + pub ready: bool, pub dirty: bool, activated: bool, pub configured: bool, @@ -109,6 +115,7 @@ impl State { fonts, events, layout, + ready: false, } } @@ -155,6 +162,84 @@ impl WidgetUpdater for State { } } +impl State { + pub fn check_registry(&mut self, qh: &QueueHandle) { + let wl_compositor = self.protocols.wl_compositor.as_ref().expect("wl_compositor missing"); + let main_surface = wl_compositor.create_surface(qh, ()); + let bg_surface = wl_compositor.create_surface(qh, ()); + self.main_surface.wl_surface = Some(main_surface.clone()); + self.bg_surface.wl_surface = Some(bg_surface.clone()); + self.activate(qh); + + let wl_subcompositor = self.protocols.wl_subcompositor.as_ref().expect("wl_subcompositor missing"); + let subsurface = wl_subcompositor.get_subsurface(&bg_surface, &main_surface, qh, ()); + subsurface.place_below(&main_surface); + self.bg_surface.subsurface = Some(subsurface.clone()); + + match self.mode { + OperationMode::XdgToplevel => { + self.fonts.resolve(); + let xdg_wm_base = self.protocols.xdg_wm_base.as_ref().expect("xdg_wm_base missing"); + let xdg_surface = xdg_wm_base.get_xdg_surface(&main_surface, qh, ()); + let toplevel = xdg_surface.get_toplevel(qh, ()); + toplevel.set_title("wldash".into()); + main_surface.commit(); + + self.main_surface.xdg_surface = Some((xdg_surface, toplevel)); + } + OperationMode::LayerSurface(size) => { + self.fonts.resolve(); + let layer_shell = self.protocols.zwlr_layer_shell.as_ref().expect("zwlr_layer_shell_v1 missing"); + let layer_surface = layer_shell.get_layer_surface( + &main_surface, + None, + zwlr_layer_shell_v1::Layer::Top, + "launcher".to_string(), + qh, + (), + ); + let fonts = self.fonts.unwrap(); + let layout = self.layout.clone(); + let min_size = layout.minimum_size(&mut fonts.borrow_mut(), self); + layer_surface.set_keyboard_interactivity( + zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive, + ); + layer_surface.set_anchor( + zwlr_layer_surface_v1::Anchor::Left + .union(zwlr_layer_surface_v1::Anchor::Bottom) + .union(zwlr_layer_surface_v1::Anchor::Right) + .union(zwlr_layer_surface_v1::Anchor::Top) + ); + layer_surface.set_size( + max(size.0, min_size.width), + max(size.1, min_size.height), + ); + + main_surface.commit(); + self.main_surface.layer_surface = Some(layer_surface); + } + } + + let viewporter = self.protocols.viewporter.as_ref().expect("wp_viewporter missing"); + let viewport = viewporter.get_viewport(&bg_surface, qh, ()); + self.bg_surface.viewport = Some(viewport); + + if let Some(background) = self.background { + let wp_single_pixel_buffer_manager = self.protocols.wp_single_pixel_buffer_manager.as_ref().expect("wp_single_pixel_buffer_manager_v1 missing"); + let buffer = wp_single_pixel_buffer_manager.create_u32_rgba_buffer( + 0, + 0, + 0, + background, + qh, + (), + ); + bg_surface.attach(Some(&buffer), 0, 0); + bg_surface.damage_buffer(0, 0, 1, 1); + } + } +} + impl Dispatch for State { fn event( state: &mut Self, @@ -170,26 +255,12 @@ impl Dispatch for State { { match &interface[..] { "wl_compositor" => { - let compositor = - registry.bind::(name, 5, qh, ()); - let main_surface = compositor.create_surface(qh, ()); - let bg_surface = compositor.create_surface(qh, ()); - state.main_surface.wl_surface = Some(main_surface); - state.bg_surface.wl_surface = Some(bg_surface); - state.activate(qh); + state.protocols.wl_compositor = + Some(registry.bind::(name, 5, qh, ())); } "wl_subcompositor" => { - let subcompositor = - registry.bind::(name, 1, qh, ()); - - match (&state.main_surface.wl_surface, &state.bg_surface.wl_surface) { - (Some(parent), Some(child)) => { - let subsurface = subcompositor.get_subsurface(child, parent, qh, ()); - subsurface.place_below(parent); - state.bg_surface.subsurface = Some(subsurface); - } - _ => todo!("handle early subcompositor creation"), - } + state.protocols.wl_subcompositor = + Some(registry.bind::(name, 1, qh, ())); } "wl_shm" => { state.protocols.wl_shm = @@ -200,84 +271,27 @@ impl Dispatch for State { } "xdg_wm_base" => { if let OperationMode::XdgToplevel = state.mode { - let wm_base = - registry.bind::(name, 2, qh, ()); - match &state.main_surface.wl_surface { - Some(surface) => { - let xdg_surface = wm_base.get_xdg_surface(surface, qh, ()); - let toplevel = xdg_surface.get_toplevel(qh, ()); - toplevel.set_title("wldash".into()); - - surface.commit(); - - state.main_surface.xdg_surface = Some((xdg_surface, toplevel)); - } - _ => todo!("handle early xdg_shell creation"), - } + state.protocols.xdg_wm_base = + Some(registry.bind::(name, 2, qh, ())); } } "xdg_activation_v1" => { state.protocols.xdg_activation = Some( registry.bind::(name, 1, qh, ()), ); - state.activate(qh); } "zwlr_layer_shell_v1" => { - if let OperationMode::LayerSurface(size) = state.mode { - let layer_shell = registry - .bind::(name, 4, qh, ()); - state.fonts.resolve(); - let fonts = state.fonts.unwrap(); - let layout = state.layout.clone(); - let min_size = layout.minimum_size(&mut fonts.borrow_mut(), state); - match &state.main_surface.wl_surface { - Some(surface) => { - let layer_surface = layer_shell.get_layer_surface( - surface, - None, - zwlr_layer_shell_v1::Layer::Top, - "launcher".to_string(), - qh, - (), - ); - layer_surface.set_keyboard_interactivity( - zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive, - ); - layer_surface.set_size( - max(size.0, min_size.width), - max(size.1, min_size.height), - ); - - surface.commit(); - state.main_surface.layer_surface = Some(layer_surface); - } - _ => todo!("handle early layer_shell creation"), - } + if let OperationMode::LayerSurface(_) = state.mode { + state.protocols.zwlr_layer_shell = Some(registry + .bind::(name, 4, qh, ())); } } "wp_viewporter" => { - let viewporter = - registry.bind::(name, 1, qh, ()); - match &state.bg_surface.wl_surface { - Some(surface) => { - state.bg_surface.viewport = - Some(viewporter.get_viewport(surface, qh, ())); - } - _ => todo!("handle early viewporter creation"), - } - state.protocols.viewporter = Some(viewporter); + state.protocols.viewporter = + Some(registry.bind::(name, 1, qh, ())); } - "wp_single_pixel_buffer_manager_v1" if state.background.is_some() => { - let singlepixel = registry.bind::(name, 1, qh, ()); - match &state.bg_surface.wl_surface { - Some(surface) => { - let buffer = - singlepixel.create_u32_rgba_buffer(0, 0, 0, state.background.unwrap(), qh, ()); - surface.attach(Some(&buffer), 0, 0); - surface.damage_buffer(0, 0, 1, 1); - } - _ => todo!("handle early single_pixel_buffer creation"), - } + "wp_single_pixel_buffer_manager_v1" => { + state.protocols.wp_single_pixel_buffer_manager = Some(registry.bind::(name, 1, qh, ())); } _ => {} } @@ -285,6 +299,24 @@ impl Dispatch for State { } } +impl Dispatch for State { + fn event( + state: &mut Self, + _: &wl_callback::WlCallback, + event: wl_callback::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + match event { + wl_callback::Event::Done { callback_data: _ } => { + state.ready = true + }, + _ => {}, + } + } +} + impl Dispatch for State { fn event( _: &mut Self, @@ -395,49 +427,51 @@ impl Dispatch for State { _: &Connection, _: &QueueHandle, ) { - if let zwlr_layer_surface_v1::Event::Configure { - serial, - mut width, - mut height, - } = event - { - if (width, height) == (0, 0) { - if state.configured { + match event { + zwlr_layer_surface_v1::Event::Configure { + serial, + mut width, + mut height, + } => { + if (width, height) == (0, 0) { + if state.configured { + return; + } + (width, height) = (640, 480); + } + layer_surface.ack_configure(serial); + state.configured = true; + state.dirty = true; + + let dim = (width as i32, height as i32); + + if state.configured && state.dimensions == dim { return; } - (width, height) = (640, 480); - } - layer_surface.ack_configure(serial); - state.configured = true; - state.dirty = true; + state.bufmgr.clear_buffers(); + state.dimensions = dim; + let fonts = state.fonts.unwrap(); + let layout = state.layout.clone(); + layout.geometry_update( + &mut fonts.borrow_mut(), + &Geometry { + x: 0, + y: 0, + width: width as u32, + height: height as u32, + }, + state, + ); - let dim = (width as i32, height as i32); - - if state.configured && state.dimensions == dim { - return; + let surface = state.bg_surface.wl_surface.as_ref().expect("bg surface was not ready"); + let viewport = state.bg_surface.viewport.as_ref().expect("bg viewport was not ready"); + viewport.set_destination(dim.0, dim.1); + surface.commit(); } - state.bufmgr.clear_buffers(); - state.dimensions = dim; - let fonts = state.fonts.unwrap(); - let layout = state.layout.clone(); - layout.geometry_update( - &mut fonts.borrow_mut(), - &Geometry { - x: 0, - y: 0, - width: width as u32, - height: height as u32, - }, - state, - ); - - match (&state.bg_surface.wl_surface, &state.bg_surface.viewport) { - (Some(surface), Some(viewport)) => { - viewport.set_destination(dim.0, dim.1); - surface.commit(); - } - _ => todo!("handle early layer shell creation"), + zwlr_layer_surface_v1::Event::Closed => { + std::process::exit(0); } + _ => (), } } } @@ -511,13 +545,10 @@ impl Dispatch for State { } if !state.configured || state.dimensions != (width, height) { - match (&state.bg_surface.wl_surface, &state.bg_surface.viewport) { - (Some(surface), Some(viewport)) => { - viewport.set_destination(width, height); - surface.commit(); - } - _ => todo!("handle early xdg creation"), - } + let surface = state.bg_surface.wl_surface.as_ref().expect("bg surface was not ready"); + let viewport = state.bg_surface.viewport.as_ref().expect("bg viewportw as not ready"); + viewport.set_destination(width, height); + surface.commit(); state.bufmgr.clear_buffers(); state.dimensions = (width, height);