From 0759b688cf26f3b57d1c70bd4382f9784f64b257 Mon Sep 17 00:00:00 2001 From: drendog Date: Tue, 20 Aug 2024 12:18:56 +0200 Subject: [PATCH] refactor: state builder to get rid of option fields --- src/windowing/mod.rs | 146 ++++++++++-------------------- src/windowing/state/builder.rs | 98 ++++++++++++++++++++ src/windowing/state/dispatches.rs | 54 ++++------- src/windowing/state/mod.rs | 146 +++++++++++------------------- 4 files changed, 217 insertions(+), 227 deletions(-) create mode 100644 src/windowing/state/builder.rs diff --git a/src/windowing/mod.rs b/src/windowing/mod.rs index 0443a72..80be180 100644 --- a/src/windowing/mod.rs +++ b/src/windowing/mod.rs @@ -4,9 +4,8 @@ use crate::{ rendering::{egl_context::EGLContext, femtovg_window::FemtoVGWindow}, }; use anyhow::{Context, Result}; -use config::WindowConfig; use log::{debug, error, info}; -use slint::{platform::femtovg_renderer::FemtoVGRenderer, LogicalPosition}; +use slint::{platform::femtovg_renderer::FemtoVGRenderer, LogicalPosition, PhysicalSize}; use slint_interpreter::ComponentInstance; use smithay_client_toolkit::reexports::{ calloop::{self, EventLoop, Interest, LoopHandle, Mode, PostAction}, @@ -14,6 +13,7 @@ use smithay_client_toolkit::reexports::{ zwlr_layer_shell_v1::ZwlrLayerShellV1, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, }, }; +use state::builder::WindowStateBuilder; use std::rc::Rc; use wayland_client::{ globals::{registry_queue_init, GlobalList}, @@ -37,32 +37,46 @@ pub struct WindowingSystem { } impl WindowingSystem { - fn new(config: &mut WindowConfig) -> Result { + fn new(config: &mut config::WindowConfig) -> Result { info!("Initializing WindowingSystem"); let connection = Rc::new(Connection::connect_to_env()?); let global_list = Self::initialize_registry(&connection)?; - let mut event_queue = connection.new_event_queue(); + let event_queue = connection.new_event_queue(); let (compositor, output, layer_shell, seat) = Self::bind_globals(&global_list, &event_queue.handle())?; - let mut state = WindowState::new(config)?; - - Self::setup_surface( - &compositor, - &output, - &layer_shell, - &seat, + let surface = Rc::new(compositor.create_surface(&event_queue.handle(), ())); + let layer_surface = Rc::new(layer_shell.get_layer_surface( + &surface, + Some(&output), + config.layer, + config.namespace.clone(), &event_queue.handle(), - &mut state, - config, - ); + (), + )); - Self::wait_for_configure(&mut event_queue, &mut state)?; + let pointer = Rc::new(seat.get_pointer(&event_queue.handle(), ())); + + Self::configure_layer_surface(&layer_surface, &surface, config); + + let mut state_builder = WindowStateBuilder::new() + .component_definition(config.component_definition.take().unwrap()) + .surface(Rc::clone(&surface)) + .layer_surface(Rc::clone(&layer_surface)) + .pointer(Rc::clone(&pointer)) + .scale_factor(config.scale_factor) + .height(config.height) + .exclusive_zone(config.exclusive_zone); + + //Self::wait_for_configure(&mut event_queue, &mut state_builder)?; let display = connection.display(); - Self::initialize_renderer(&mut state, &display, config)?; + let window = Self::initialize_renderer(&state_builder, &display, config)?; + state_builder = state_builder.window(window); + + let state = state_builder.build()?; let event_loop = EventLoop::try_new().context("Failed to create event loop")?; @@ -94,38 +108,10 @@ impl WindowingSystem { ) } - fn setup_surface( - compositor: &WlCompositor, - output: &WlOutput, - layer_shell: &ZwlrLayerShellV1, - seat: &WlSeat, - queue_handle: &QueueHandle, - state: &mut WindowState, - config: &WindowConfig, - ) { - let surface = Rc::new(compositor.create_surface(queue_handle, ())); - let layer_surface = Rc::new(layer_shell.get_layer_surface( - &surface, - Some(output), - config.layer, - config.namespace.clone(), - queue_handle, - (), - )); - - let pointer = Rc::new(seat.get_pointer(queue_handle, ())); - - state.set_surface(Rc::clone(&surface)); - state.set_layer_surface(Rc::clone(&layer_surface)); - state.set_pointer(pointer); - - Self::configure_layer_surface(&layer_surface, &surface, config); - } - fn configure_layer_surface( layer_surface: &Rc, surface: &WlSurface, - config: &WindowConfig, + config: &config::WindowConfig, ) { layer_surface.set_anchor(config.anchor); layer_surface.set_margin( @@ -141,29 +127,14 @@ impl WindowingSystem { surface.commit(); } - fn wait_for_configure( - event_queue: &mut EventQueue, - state: &mut WindowState, - ) -> Result<()> { - info!("Waiting for surface to be configured..."); - event_queue - .blocking_dispatch(state) - .context("Failed to dispatch events")?; - info!("Blocking dispatch completed"); - let size = state.output_size(); - if size.width > 1 && size.height > 1 { - info!("Configured output size: {:?}", size); - } else { - return Err(anyhow::anyhow!("Invalid output size: {:?}", size)); - } - debug!("Surface configuration complete"); - Ok(()) - } - - fn create_renderer(state: &WindowState, display: &WlDisplay) -> Result { - let size = state.size(); - let surface = state - .surface() + fn create_renderer( + state_builder: &WindowStateBuilder, + display: &WlDisplay, + ) -> Result { + let size = state_builder.size.unwrap_or(PhysicalSize::new(1, 1)); + let surface = state_builder + .surface + .as_ref() .ok_or_else(|| anyhow::anyhow!("Failed to get surface"))?; debug!("Creating EGL context with size: {:?}", size); @@ -179,14 +150,14 @@ impl WindowingSystem { } fn initialize_renderer( - state: &mut WindowState, + state_builder: &WindowStateBuilder, display: &WlDisplay, - config: &WindowConfig, - ) -> Result<()> { - let renderer = Self::create_renderer(state, display)?; + config: &config::WindowConfig, + ) -> Result> { + let renderer = Self::create_renderer(state_builder, display)?; let femtovg_window = FemtoVGWindow::new(renderer); - let size = state.size(); + let size = state_builder.size.unwrap_or_default(); info!("Initializing UI with size: {:?}", size); femtovg_window.set_size(slint::WindowSize::Physical(size)); femtovg_window.set_scale_factor(config.scale_factor); @@ -194,9 +165,7 @@ impl WindowingSystem { debug!("Creating Slint component instance"); - state.set_window(Rc::clone(&femtovg_window)); - - Ok(()) + Ok(femtovg_window) } pub fn event_loop_handle(&self) -> LoopHandle<'static, WindowState> { @@ -206,7 +175,7 @@ impl WindowingSystem { pub fn run(&mut self) -> Result<()> { info!("Starting WindowingSystem main loop"); - self.initialize_component()?; + self.state.window().render_frame_if_dirty()?; self.setup_wayland_event_source()?; let connection = Rc::clone(&self.connection); @@ -223,17 +192,6 @@ impl WindowingSystem { .map_err(|e| anyhow::anyhow!("Failed to run event loop: {}", e)) } - fn initialize_component(&mut self) -> Result<()> { - if let Some(window) = &self.state.window() { - window.render_frame_if_dirty()?; - } else { - return Err(anyhow::anyhow!("Window not initialized")); - } - - self.state.show_component()?; - Ok(()) - } - fn setup_wayland_event_source(&self) -> Result<()> { debug!("Setting up Wayland event source"); @@ -267,21 +225,17 @@ impl WindowingSystem { slint::platform::update_timers_and_animations(); - if let Some(window) = shared_data.window() { - window.render_frame_if_dirty()?; - } else { - return Err(anyhow::anyhow!("Window not initialized")); - } + shared_data.window().render_frame_if_dirty()?; Ok(()) } - pub const fn component_instance(&self) -> Option<&ComponentInstance> { + pub const fn component_instance(&self) -> &ComponentInstance { self.state.component_instance() } - pub fn window(&self) -> Option> { - self.state().window().as_ref().map(Rc::clone) + pub fn window(&self) -> Rc { + self.state.window() } pub const fn state(&self) -> &WindowState { diff --git a/src/windowing/state/builder.rs b/src/windowing/state/builder.rs new file mode 100644 index 0000000..c2000da --- /dev/null +++ b/src/windowing/state/builder.rs @@ -0,0 +1,98 @@ +use std::rc::Rc; +use slint::PhysicalSize; +use slint_interpreter::ComponentDefinition; +use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1; +use wayland_client::protocol::{wl_pointer::WlPointer, wl_surface::WlSurface}; +use crate::rendering::{femtovg_window::FemtoVGWindow, slint_platform::CustomSlintPlatform}; +use anyhow::Result; + +use super::WindowState; + +#[derive(Clone)] +pub struct WindowStateBuilder { + pub component_definition: Option, + pub surface: Option>, + pub layer_surface: Option>, + pub size: Option, + pub output_size: Option, + pub pointer: Option>, + pub window: Option>, + pub scale_factor: f32, + pub height: u32, + pub exclusive_zone: i32, +} + +impl WindowStateBuilder { + pub const fn new() -> Self { + Self { + component_definition: None, + surface: None, + layer_surface: None, + size: None, + output_size: None, + pointer: None, + window: None, + scale_factor: 1.0, + height: 30, + exclusive_zone: -1, + } + } + + pub fn surface(mut self, surface: Rc) -> Self { + self.surface = Some(surface); + self + } + + pub fn layer_surface(mut self, layer_surface: Rc) -> Self { + self.layer_surface = Some(layer_surface); + self + } + + pub const fn size(mut self, size: PhysicalSize) -> Self { + self.size = Some(size); + self + } + + pub const fn output_size(mut self, output_size: PhysicalSize) -> Self { + self.output_size = Some(output_size); + self + } + + pub fn pointer(mut self, pointer: Rc) -> Self { + self.pointer = Some(pointer); + self + } + + pub fn window(mut self, window: Rc) -> Self { + self.window = Some(window); + self + } + + pub const fn scale_factor(mut self, scale_factor: f32) -> Self { + self.scale_factor = scale_factor; + self + } + + pub const fn height(mut self, height: u32) -> Self { + self.height = height; + self + } + + pub const fn exclusive_zone(mut self, exclusive_zone: i32) -> Self { + self.exclusive_zone = exclusive_zone; + self + } + + pub fn component_definition(mut self, component_definition: ComponentDefinition) -> Self { + self.component_definition = Some(component_definition); + self + } + + pub fn build(self) -> Result { + let platform = CustomSlintPlatform::new(Rc::clone(self.window.as_ref().unwrap())); + slint::platform::set_platform(Box::new(platform)) + .map_err(|e| anyhow::anyhow!("Failed to set platform: {:?}", e))?; + + WindowState::new(self) + } +} diff --git a/src/windowing/state/dispatches.rs b/src/windowing/state/dispatches.rs index 301fcaf..1842f0d 100644 --- a/src/windowing/state/dispatches.rs +++ b/src/windowing/state/dispatches.rs @@ -1,5 +1,5 @@ use crate::impl_empty_dispatch; -use log::{info, warn}; +use log::info; use slint::{ platform::{PointerEventButton, WindowEvent}, PhysicalSize, @@ -42,20 +42,10 @@ impl Dispatch for WindowState { info!("Layer surface configured with size: {}x{}", width, height); layer_surface.ack_configure(serial); if width > 0 && height > 0 { - state - .update_size(state.output_size().width, state.height()) - .unwrap_or(warn!( - "Failed to update window size with width: {} and height: {}", - width, height - )); + state.update_size(state.output_size().width, state.height()); } else { let current_size = state.output_size(); - state - .update_size(current_size.width, current_size.height) - .unwrap_or(warn!( - "Failed to update window size with width: {} and height: {}", - width, height - )); + state.update_size(current_size.width, current_size.height); } } zwlr_layer_surface_v1::Event::Closed => { @@ -125,33 +115,23 @@ impl Dispatch for WindowState { surface_x, surface_y, .. - } => { - state.set_current_pointer_position(surface_x, surface_y); - let logical_position = state.current_pointer_position(); - if let Some(window) = state.window() { - window.dispatch_event(WindowEvent::PointerMoved { - position: logical_position, - }); - } } - wl_pointer::Event::Leave { .. } => { - if let Some(window) = state.window() { - window.dispatch_event(WindowEvent::PointerExited); - } - } - wl_pointer::Event::Motion { + | wl_pointer::Event::Motion { surface_x, surface_y, .. } => { state.set_current_pointer_position(surface_x, surface_y); - if let Some(window) = state.window() { - let logical_position = state.current_pointer_position(); - window.dispatch_event(WindowEvent::PointerMoved { - position: logical_position, - }); - } + let logical_position = state.current_pointer_position(); + state.window().dispatch_event(WindowEvent::PointerMoved { + position: *logical_position, + }); } + + wl_pointer::Event::Leave { .. } => { + state.window().dispatch_event(WindowEvent::PointerExited); + } + wl_pointer::Event::Button { state: button_state, .. @@ -159,16 +139,14 @@ impl Dispatch for WindowState { let event = match button_state { WEnum::Value(wl_pointer::ButtonState::Pressed) => WindowEvent::PointerPressed { button: PointerEventButton::Left, - position: state.current_pointer_position(), + position: *state.current_pointer_position(), }, _ => WindowEvent::PointerReleased { button: PointerEventButton::Left, - position: state.current_pointer_position(), + position: *state.current_pointer_position(), }, }; - if let Some(window) = state.window() { - window.dispatch_event(event); - } + state.window().dispatch_event(event); } _ => {} } diff --git a/src/windowing/state/mod.rs b/src/windowing/state/mod.rs index 493a313..a79596c 100644 --- a/src/windowing/state/mod.rs +++ b/src/windowing/state/mod.rs @@ -1,24 +1,23 @@ use std::rc::Rc; +use builder::WindowStateBuilder; use log::info; use slint::{LogicalPosition, PhysicalSize, ComponentHandle}; -use slint_interpreter::{ComponentDefinition, ComponentInstance}; +use slint_interpreter::ComponentInstance; use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1; -use wayland_client::protocol::{wl_pointer::WlPointer, wl_surface::WlSurface}; -use crate::rendering::{femtovg_window::FemtoVGWindow, slint_platform::CustomSlintPlatform}; -use super::WindowConfig; -use anyhow::Result; +use wayland_client::protocol::wl_surface::WlSurface; +use crate::rendering::femtovg_window::FemtoVGWindow; +use anyhow::{Context, Result}; +pub mod builder; pub mod dispatches; pub struct WindowState { - component_definition: ComponentDefinition, - component_instance: Option, - surface: Option>, - layer_surface: Option>, + component_instance: ComponentInstance, + surface: Rc, + layer_surface: Rc, size: PhysicalSize, output_size: PhysicalSize, - pointer: Option>, - window: Option>, + window: Rc, current_pointer_position: LogicalPosition, scale_factor: f32, height: u32, @@ -26,68 +25,42 @@ pub struct WindowState { } impl WindowState { - pub fn new(config: &mut WindowConfig) -> Result { - let component_definition = config + pub fn new(builder: WindowStateBuilder) -> Result { + let component_definition = builder .component_definition - .take() - .ok_or_else(|| anyhow::anyhow!("Component definition is required"))?; - + .context("Component definition is required")?; + let component_instance = component_definition + .create() + .context("Failed to create component instance")?; + component_instance + .show() + .context("Failed to show component")?; Ok(Self { - surface: None, - layer_surface: None, - size: PhysicalSize::default(), - output_size: PhysicalSize::default(), - pointer: None, - window: None, + component_instance, + surface: builder.surface.context("Surface is required")?, + layer_surface: builder.layer_surface.context("Layer surface is required")?, + size: builder.size.unwrap_or_default(), + output_size: builder.output_size.unwrap_or_default(), + window: builder.window.context("Window is required")?, current_pointer_position: LogicalPosition::default(), - scale_factor: config.scale_factor, - height: config.height, - exclusive_zone: config.exclusive_zone, - component_definition, - component_instance: None, + scale_factor: builder.scale_factor, + height: builder.height, + exclusive_zone: builder.exclusive_zone, }) } - pub fn show_component(&mut self) -> Result<()> { - if let Some(window) = &self.window { - let platform = CustomSlintPlatform::new(Rc::clone(window)); - slint::platform::set_platform(Box::new(platform)) - .map_err(|e| anyhow::anyhow!("Failed to set platform: {:?}", e))?; - } - - self.component_instance = Some(self.component_definition.create()?); - - if let Some(component_instance) = &self.component_instance { - component_instance.show()?; - } else { - return Err(anyhow::anyhow!("Component instance not initialized")); - } - - Ok(()) - } - - pub fn update_size(&mut self, width: u32, height: u32) -> Result<()> { + pub fn update_size(&mut self, width: u32, height: u32) { let new_size = PhysicalSize::new(width, height); - if let Some(window) = &self.window() { - info!("Updating window size to {}x{}", width, height); - window.set_size(slint::WindowSize::Physical(new_size)); - window.set_scale_factor(self.scale_factor); - } + info!("Updating window size to {}x{}", width, height); + self.window.set_size(slint::WindowSize::Physical(new_size)); + self.window.set_scale_factor(self.scale_factor); - if let Some(layer_surface) = &self.layer_surface() { - info!("Updating layer surface size to {}x{}", width, height); - layer_surface.set_size(width, height); - layer_surface.set_exclusive_zone(self.exclusive_zone); - } + info!("Updating layer surface size to {}x{}", width, height); + self.layer_surface.set_size(width, height); + self.layer_surface.set_exclusive_zone(self.exclusive_zone); - match self.surface.as_ref() { - Some(surface) => surface.commit(), - None => { - return Err(anyhow::anyhow!("Surface not initialized")); - } - } + self.surface.commit(); self.size = new_size; - Ok(()) } pub fn set_current_pointer_position(&mut self, physical_x: f64, physical_y: f64) { @@ -99,22 +72,24 @@ impl WindowState { self.current_pointer_position = logical_position; } - pub const fn size(&self) -> PhysicalSize { - self.size + pub const fn size(&self) -> &PhysicalSize { + &self.size } - pub const fn current_pointer_position(&self) -> LogicalPosition { - self.current_pointer_position - } - pub fn window(&self) -> Option> { - self.window.clone() + pub const fn current_pointer_position(&self) -> &LogicalPosition { + &self.current_pointer_position } - pub fn layer_surface(&self) -> Option> { - self.layer_surface.clone() + pub fn window(&self) -> Rc { + Rc::clone(&self.window) } - pub fn surface(&self) -> Option> { - self.surface.clone() + + pub fn layer_surface(&self) -> Rc { + Rc::clone(&self.layer_surface) + } + + pub fn surface(&self) -> Rc { + Rc::clone(&self.surface) } pub const fn height(&self) -> u32 { @@ -125,26 +100,11 @@ impl WindowState { self.output_size = output_size; } - pub const fn output_size(&self) -> PhysicalSize { - self.output_size + pub const fn output_size(&self) -> &PhysicalSize { + &self.output_size } - pub fn set_window(&mut self, window: Rc) { - self.window = Some(window); - } - - pub fn set_layer_surface(&mut self, layer_surface: Rc) { - self.layer_surface = Some(layer_surface); - } - - pub fn set_surface(&mut self, surface: Rc) { - self.surface = Some(surface); - } - pub fn set_pointer(&mut self, pointer: Rc) { - self.pointer = Some(pointer); - } - - pub const fn component_instance(&self) -> Option<&ComponentInstance> { - self.component_instance.as_ref() + pub const fn component_instance(&self) -> &ComponentInstance { + &self.component_instance } }