refactor: event-driven state mutation

This commit is contained in:
drendog 2025-11-11 20:54:28 +01:00
parent d2930a7a85
commit fe9df4fd1b
Signed by: dwenya
GPG key ID: 8DD77074645332D0
7 changed files with 182 additions and 12 deletions

View file

@ -0,0 +1,42 @@
use super::window_events::WindowStateEvent;
use std::cell::RefCell;
use std::rc::Rc;
type EventHandlerFn = Box<dyn Fn(&WindowStateEvent)>;
#[derive(Clone)]
pub struct EventBus {
handlers: Rc<RefCell<Vec<EventHandlerFn>>>,
}
impl Default for EventBus {
fn default() -> Self {
Self::new()
}
}
impl EventBus {
pub fn new() -> Self {
Self {
handlers: Rc::new(RefCell::new(Vec::new())),
}
}
pub fn subscribe<F>(&self, handler: F)
where
F: Fn(&WindowStateEvent) + 'static,
{
self.handlers.borrow_mut().push(Box::new(handler));
}
pub fn publish(&self, event: &WindowStateEvent) {
let handlers = self.handlers.borrow();
for handler in handlers.iter() {
handler(event);
}
}
pub fn clear(&self) {
self.handlers.borrow_mut().clear();
}
}

View file

@ -1,7 +1,9 @@
use crate::wayland::managed_proxies::ManagedWlPointer; use crate::wayland::managed_proxies::ManagedWlPointer;
use crate::wayland::services::popup_service::PopupService; use crate::wayland::services::popup_service::PopupService;
use crate::wayland::surfaces::event_bus::EventBus;
use crate::wayland::surfaces::event_router::EventRouter; use crate::wayland::surfaces::event_router::EventRouter;
use crate::wayland::surfaces::scale_coordinator::{ScaleCoordinator, SharedPointerSerial}; use crate::wayland::surfaces::scale_coordinator::{ScaleCoordinator, SharedPointerSerial};
use crate::wayland::surfaces::window_events::{ScaleSource, WindowStateEvent};
use slint::LogicalPosition; use slint::LogicalPosition;
use slint::platform::WindowEvent; use slint::platform::WindowEvent;
use std::rc::Rc; use std::rc::Rc;
@ -12,6 +14,7 @@ pub struct InteractionState {
pointer: ManagedWlPointer, pointer: ManagedWlPointer,
event_router: EventRouter, event_router: EventRouter,
scale_coordinator: ScaleCoordinator, scale_coordinator: ScaleCoordinator,
event_bus: EventBus,
} }
impl InteractionState { impl InteractionState {
@ -25,13 +28,24 @@ impl InteractionState {
pointer, pointer,
event_router, event_router,
scale_coordinator, scale_coordinator,
event_bus: EventBus::new(),
} }
} }
pub fn set_event_bus(&mut self, event_bus: EventBus) {
self.event_bus = event_bus;
}
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_possible_truncation)]
pub fn set_current_pointer_position(&mut self, physical_x: f64, physical_y: f64) { pub fn set_current_pointer_position(&mut self, physical_x: f64, physical_y: f64) {
self.scale_coordinator self.scale_coordinator
.set_current_pointer_position(physical_x, physical_y); .set_current_pointer_position(physical_x, physical_y);
self.event_bus
.publish(&WindowStateEvent::PointerPositionChanged {
physical_x,
physical_y,
});
} }
pub fn current_pointer_position(&self) -> LogicalPosition { pub fn current_pointer_position(&self) -> LogicalPosition {
@ -44,6 +58,9 @@ impl InteractionState {
pub fn set_last_pointer_serial(&mut self, serial: u32) { pub fn set_last_pointer_serial(&mut self, serial: u32) {
self.scale_coordinator.set_last_pointer_serial(serial); self.scale_coordinator.set_last_pointer_serial(serial);
self.event_bus
.publish(&WindowStateEvent::PointerSerialUpdated { serial });
} }
pub fn set_shared_pointer_serial(&mut self, shared_serial: Rc<SharedPointerSerial>) { pub fn set_shared_pointer_serial(&mut self, shared_serial: Rc<SharedPointerSerial>) {
@ -65,6 +82,14 @@ impl InteractionState {
#[allow(clippy::cast_precision_loss)] #[allow(clippy::cast_precision_loss)]
pub fn update_scale_factor(&mut self, scale_120ths: u32) -> f32 { pub fn update_scale_factor(&mut self, scale_120ths: u32) -> f32 {
self.scale_coordinator.update_scale_factor(scale_120ths) let new_scale = self.scale_coordinator.update_scale_factor(scale_120ths);
self.event_bus
.publish(&WindowStateEvent::ScaleFactorChanged {
new_scale,
source: ScaleSource::FractionalScale,
});
new_scale
} }
} }

View file

@ -1,5 +1,6 @@
pub mod component_state; pub mod component_state;
pub mod dimensions; pub mod dimensions;
pub mod event_bus;
pub mod event_router; pub mod event_router;
pub mod interaction_state; pub mod interaction_state;
pub mod layer_surface; pub mod layer_surface;
@ -10,4 +11,5 @@ pub mod rendering_state;
pub mod scale_coordinator; pub mod scale_coordinator;
pub mod surface_builder; pub mod surface_builder;
pub mod surface_state; pub mod surface_state;
pub mod window_events;
pub mod window_renderer; pub mod window_renderer;

View file

@ -1,11 +1,14 @@
use crate::wayland::services::popup_service::PopupService; use crate::wayland::services::popup_service::PopupService;
use crate::wayland::surfaces::event_bus::EventBus;
use crate::wayland::surfaces::popup_manager::PopupManager; use crate::wayland::surfaces::popup_manager::PopupManager;
use crate::wayland::surfaces::window_events::WindowStateEvent;
use slint::PhysicalSize; use slint::PhysicalSize;
use std::rc::Rc; use std::rc::Rc;
use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1; use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1;
pub struct PopupState { pub struct PopupState {
popup_service: Option<Rc<PopupService>>, popup_service: Option<Rc<PopupService>>,
event_bus: EventBus,
} }
impl Default for PopupState { impl Default for PopupState {
@ -16,24 +19,36 @@ impl Default for PopupState {
impl PopupState { impl PopupState {
#[must_use] #[must_use]
pub const fn new() -> Self { pub fn new() -> Self {
Self { Self {
popup_service: None, popup_service: None,
event_bus: EventBus::new(),
} }
} }
pub fn set_event_bus(&mut self, event_bus: EventBus) {
self.event_bus = event_bus;
}
pub fn set_popup_service(&mut self, popup_service: Rc<PopupService>) { pub fn set_popup_service(&mut self, popup_service: Rc<PopupService>) {
self.popup_service = Some(popup_service); self.popup_service = Some(popup_service);
self.event_bus
.publish(&WindowStateEvent::PopupConfigurationChanged);
} }
pub fn set_popup_manager(&mut self, popup_manager: Rc<PopupManager>) { pub fn set_popup_manager(&mut self, popup_manager: Rc<PopupManager>) {
self.popup_service = Some(Rc::new(PopupService::new(popup_manager))); self.popup_service = Some(Rc::new(PopupService::new(popup_manager)));
self.event_bus
.publish(&WindowStateEvent::PopupConfigurationChanged);
} }
pub fn update_output_size(&self, output_size: PhysicalSize) { pub fn update_output_size(&self, output_size: PhysicalSize) {
if let Some(popup_service) = &self.popup_service { if let Some(popup_service) = &self.popup_service {
popup_service.update_output_size(output_size); popup_service.update_output_size(output_size);
} }
self.event_bus
.publish(&WindowStateEvent::OutputSizeChanged { output_size });
} }
pub fn update_scale_factor(&self, scale_factor: f32) { pub fn update_scale_factor(&self, scale_factor: f32) {

View file

@ -2,12 +2,15 @@ use std::rc::Rc;
use crate::errors::Result; use crate::errors::Result;
use crate::rendering::femtovg::main_window::FemtoVGWindow; use crate::rendering::femtovg::main_window::FemtoVGWindow;
use crate::wayland::surfaces::window_renderer::{WindowRenderer, WindowRendererParams}; use crate::wayland::surfaces::window_renderer::{WindowRenderer, WindowRendererParams};
use crate::wayland::surfaces::event_bus::EventBus;
use crate::wayland::surfaces::window_events::WindowStateEvent;
use slint::PhysicalSize; use slint::PhysicalSize;
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1; use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
use crate::wayland::managed_proxies::ManagedWpFractionalScaleV1; use crate::wayland::managed_proxies::ManagedWpFractionalScaleV1;
pub struct RenderingState { pub struct RenderingState {
renderer: WindowRenderer, renderer: WindowRenderer,
event_bus: EventBus,
} }
impl RenderingState { impl RenderingState {
@ -15,15 +18,25 @@ impl RenderingState {
pub fn new(params: WindowRendererParams) -> Self { pub fn new(params: WindowRendererParams) -> Self {
Self { Self {
renderer: WindowRenderer::new(params), renderer: WindowRenderer::new(params),
event_bus: EventBus::new(),
} }
} }
pub fn set_event_bus(&mut self, event_bus: EventBus) {
self.event_bus = event_bus;
}
pub fn render_frame_if_dirty(&self) -> Result<()> { pub fn render_frame_if_dirty(&self) -> Result<()> {
self.renderer.render_frame_if_dirty() self.renderer.render_frame_if_dirty()
} }
pub fn update_size(&mut self, width: u32, height: u32, scale_factor: f32) { pub fn update_size(&mut self, width: u32, height: u32, scale_factor: f32) {
self.renderer.update_size(width, height, scale_factor); self.renderer.update_size(width, height, scale_factor);
self.event_bus.publish(&WindowStateEvent::SizeChanged {
logical_width: width,
logical_height: height,
});
} }
pub const fn size(&self) -> PhysicalSize { pub const fn size(&self) -> PhysicalSize {

View file

@ -9,6 +9,7 @@ use super::popup_state::PopupState;
use super::popup_manager::PopupManager; use super::popup_manager::PopupManager;
use super::scale_coordinator::{ScaleCoordinator, SharedPointerSerial}; use super::scale_coordinator::{ScaleCoordinator, SharedPointerSerial};
use super::window_renderer::WindowRendererParams; use super::window_renderer::WindowRendererParams;
use super::event_bus::EventBus;
use crate::wayland::managed_proxies::{ use crate::wayland::managed_proxies::{
ManagedWlPointer, ManagedWlSurface, ManagedZwlrLayerSurfaceV1, ManagedWlPointer, ManagedWlSurface, ManagedZwlrLayerSurfaceV1,
ManagedWpFractionalScaleV1, ManagedWpViewport, ManagedWpFractionalScaleV1, ManagedWpViewport,
@ -35,6 +36,8 @@ pub struct WindowState {
output_size: PhysicalSize, output_size: PhysicalSize,
active_popup_key: RefCell<Option<usize>>, active_popup_key: RefCell<Option<usize>>,
main_surface: Rc<WlSurface>, main_surface: Rc<WlSurface>,
#[allow(dead_code)]
event_bus: EventBus,
} }
impl WindowState { impl WindowState {
@ -91,7 +94,21 @@ impl WindowState {
let has_fractional_scale = fractional_scale.is_some(); let has_fractional_scale = fractional_scale.is_some();
let size = builder.size.unwrap_or_default(); let size = builder.size.unwrap_or_default();
let rendering = RenderingState::new(WindowRendererParams { let main_surface_id = (*surface_rc).id();
let event_router = EventRouter::new(Rc::clone(&window), main_surface_id);
let scale_coordinator = ScaleCoordinator::new(builder.scale_factor, has_fractional_scale);
let mut interaction = InteractionState::new(pointer, event_router, scale_coordinator);
let mut popup = PopupState::new();
let event_bus = EventBus::new();
let event_bus_clone_for_rendering = event_bus.clone();
let event_bus_clone_for_interaction = event_bus.clone();
let event_bus_clone_for_popup = event_bus.clone();
let mut rendering = RenderingState::new(WindowRendererParams {
window: Rc::clone(&window), window: Rc::clone(&window),
surface, surface,
layer_surface, layer_surface,
@ -102,15 +119,11 @@ impl WindowState {
size, size,
}); });
let main_surface_id = (*surface_rc).id(); rendering.set_event_bus(event_bus_clone_for_rendering);
let event_router = EventRouter::new(Rc::clone(&window), main_surface_id); interaction.set_event_bus(event_bus_clone_for_interaction);
let scale_coordinator = ScaleCoordinator::new(builder.scale_factor, has_fractional_scale); popup.set_event_bus(event_bus_clone_for_popup);
let interaction = InteractionState::new(pointer, event_router, scale_coordinator); let mut instance = Self {
let popup = PopupState::new();
Ok(Self {
component, component,
rendering, rendering,
interaction, interaction,
@ -118,9 +131,17 @@ impl WindowState {
output_size: builder.output_size.unwrap_or_default(), output_size: builder.output_size.unwrap_or_default(),
active_popup_key: RefCell::new(None), active_popup_key: RefCell::new(None),
main_surface: surface_rc, main_surface: surface_rc,
}) event_bus,
};
instance.setup_event_handlers();
Ok(instance)
} }
#[allow(clippy::unused_self)]
fn setup_event_handlers(&mut self) {}
pub fn update_size(&mut self, width: u32, height: u32) { pub fn update_size(&mut self, width: u32, height: u32) {
let scale_factor = self.interaction.scale_factor(); let scale_factor = self.interaction.scale_factor();
self.rendering.update_size(width, height, scale_factor); self.rendering.update_size(width, height, scale_factor);

View file

@ -0,0 +1,52 @@
use slint::PhysicalSize;
use wayland_client::backend::ObjectId;
#[derive(Debug, Clone)]
pub enum WindowStateEvent {
ScaleFactorChanged {
new_scale: f32,
source: ScaleSource,
},
SizeChanged {
logical_width: u32,
logical_height: u32,
},
OutputSizeChanged {
output_size: PhysicalSize,
},
PointerPositionChanged {
physical_x: f64,
physical_y: f64,
},
PointerSerialUpdated {
serial: u32,
},
SurfaceEntered {
surface_id: ObjectId,
},
SurfaceExited,
RenderRequested,
PopupConfigurationChanged,
}
#[derive(Debug, Clone, Copy)]
pub enum ScaleSource {
FractionalScale,
IntegerScale,
}
pub trait WindowStateEventHandler {
fn handle_event(&mut self, event: &WindowStateEvent);
}
pub trait WindowStateEventEmitter {
fn emit_event(&self, event: WindowStateEvent);
}