layer_shika_adapters/wayland/surfaces/
surface_state.rs

1use std::rc::Rc;
2use std::cell::RefCell;
3use super::surface_builder::SurfaceStateBuilder;
4use super::component_state::ComponentState;
5use super::rendering_state::RenderingState;
6use super::event_context::{EventContext, SharedPointerSerial};
7use super::popup_manager::PopupManager;
8use super::surface_renderer::SurfaceRendererParams;
9use super::display_metrics::{DisplayMetrics, SharedDisplayMetrics};
10use crate::wayland::managed_proxies::{
11    ManagedWlPointer, ManagedWlSurface, ManagedZwlrLayerSurfaceV1,
12    ManagedWpFractionalScaleV1, ManagedWpViewport,
13};
14use crate::rendering::femtovg::main_window::FemtoVGWindow;
15use crate::errors::{LayerShikaError, Result};
16use core::result::Result as CoreResult;
17use layer_shika_domain::errors::DomainError;
18use layer_shika_domain::ports::shell::ShellContextPort;
19use slint::{LogicalPosition, PhysicalSize};
20use slint::platform::WindowEvent;
21use slint_interpreter::{ComponentInstance, CompilationResult};
22use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
23use wayland_client::{
24    Proxy,
25    backend::ObjectId,
26    protocol::{wl_pointer, wl_surface::WlSurface},
27};
28use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1;
29
30pub struct SurfaceState {
31    component: ComponentState,
32    rendering: RenderingState<FemtoVGWindow>,
33    event_context: RefCell<EventContext>,
34    display_metrics: SharedDisplayMetrics,
35    #[allow(dead_code)]
36    pointer: ManagedWlPointer,
37}
38
39impl SurfaceState {
40    pub fn new(builder: SurfaceStateBuilder) -> Result<Self> {
41        let component_definition =
42            builder
43                .component_definition
44                .ok_or_else(|| LayerShikaError::InvalidInput {
45                    message: "Component definition is required".into(),
46                })?;
47        let window = builder
48            .window
49            .ok_or_else(|| LayerShikaError::InvalidInput {
50                message: "Window is required".into(),
51            })?;
52
53        let component =
54            ComponentState::new(component_definition, builder.compilation_result, &window)?;
55
56        let connection = builder
57            .connection
58            .ok_or_else(|| LayerShikaError::InvalidInput {
59                message: "Connection is required".into(),
60            })?;
61
62        let surface_rc = builder
63            .surface
64            .ok_or_else(|| LayerShikaError::InvalidInput {
65                message: "Surface is required".into(),
66            })?;
67        let layer_surface_rc =
68            builder
69                .layer_surface
70                .ok_or_else(|| LayerShikaError::InvalidInput {
71                    message: "Layer surface is required".into(),
72                })?;
73        let pointer_rc = builder
74            .pointer
75            .ok_or_else(|| LayerShikaError::InvalidInput {
76                message: "Pointer is required".into(),
77            })?;
78
79        let viewport = builder
80            .viewport
81            .map(|vp| ManagedWpViewport::new(vp, Rc::clone(&connection)));
82        let fractional_scale = builder
83            .fractional_scale
84            .map(|fs| ManagedWpFractionalScaleV1::new(fs, Rc::clone(&connection)));
85        let layer_surface =
86            ManagedZwlrLayerSurfaceV1::new(layer_surface_rc, Rc::clone(&connection));
87        let surface = ManagedWlSurface::new(Rc::clone(&surface_rc), Rc::clone(&connection));
88        let pointer = ManagedWlPointer::new(pointer_rc, Rc::clone(&connection));
89
90        let has_fractional_scale = fractional_scale.is_some();
91        let size = builder.size.unwrap_or_default();
92
93        let main_surface_id = (*surface_rc).id();
94
95        let display_metrics = Rc::new(RefCell::new(
96            DisplayMetrics::new(builder.scale_factor, has_fractional_scale)
97                .with_output_size(builder.output_size.unwrap_or_default()),
98        ));
99
100        let event_context = EventContext::new(
101            Rc::clone(&window),
102            main_surface_id,
103            Rc::clone(&display_metrics),
104        );
105
106        let rendering = RenderingState::new(SurfaceRendererParams {
107            window: Rc::clone(&window),
108            surface,
109            layer_surface,
110            viewport,
111            fractional_scale,
112            height: builder.height,
113            size,
114        });
115
116        Ok(Self {
117            component,
118            rendering,
119            event_context: RefCell::new(event_context),
120            display_metrics,
121            pointer,
122        })
123    }
124
125    pub fn update_size(&mut self, width: u32, height: u32) {
126        let scale_factor = self.event_context.borrow().scale_factor();
127        self.rendering.update_size(width, height, scale_factor);
128    }
129
130    #[allow(clippy::cast_precision_loss)]
131    #[allow(clippy::cast_possible_truncation)]
132    #[allow(clippy::cast_sign_loss)]
133    pub fn update_size_with_compositor_logic(
134        &mut self,
135        requested_width: u32,
136        requested_height: u32,
137    ) {
138        let scale_factor = self.event_context.borrow().scale_factor();
139        let output_width = self.output_size().width;
140
141        let target_width = if requested_width == 0 || (requested_width == 1 && output_width > 1) {
142            if scale_factor > 1.0 {
143                (output_width as f32 / scale_factor).round() as u32
144            } else {
145                output_width
146            }
147        } else {
148            requested_width
149        };
150
151        let target_height = if requested_height > 0 {
152            requested_height
153        } else {
154            let h = self.height();
155            if scale_factor > 1.0 {
156                (h as f32 / scale_factor).round() as u32
157            } else {
158                h
159            }
160        };
161
162        self.rendering
163            .update_size(target_width, target_height, scale_factor);
164    }
165
166    #[allow(clippy::cast_possible_truncation)]
167    pub fn set_current_pointer_position(&mut self, physical_x: f64, physical_y: f64) {
168        self.event_context
169            .borrow_mut()
170            .set_current_pointer_position(physical_x, physical_y);
171    }
172
173    pub fn size(&self) -> PhysicalSize {
174        self.rendering.size()
175    }
176
177    pub fn current_pointer_position(&self) -> LogicalPosition {
178        self.event_context.borrow().current_pointer_position()
179    }
180
181    pub(crate) fn window(&self) -> Rc<FemtoVGWindow> {
182        Rc::clone(self.rendering.window())
183    }
184
185    pub fn layer_surface(&self) -> Rc<ZwlrLayerSurfaceV1> {
186        self.rendering.layer_surface()
187    }
188
189    pub fn commit_surface(&self) {
190        self.rendering.commit_surface();
191    }
192
193    pub fn height(&self) -> u32 {
194        self.rendering.height()
195    }
196
197    pub fn set_output_size(&mut self, output_size: PhysicalSize) {
198        self.display_metrics
199            .borrow_mut()
200            .update_output_size(output_size);
201        self.event_context.borrow().update_output_size(output_size);
202    }
203
204    pub fn output_size(&self) -> PhysicalSize {
205        self.display_metrics.borrow().output_size()
206    }
207
208    pub const fn component_instance(&self) -> &ComponentInstance {
209        self.component.component_instance()
210    }
211
212    #[must_use]
213    pub fn compilation_result(&self) -> Option<Rc<CompilationResult>> {
214        self.component.compilation_result()
215    }
216
217    pub fn render_frame_if_dirty(&self) -> Result<()> {
218        self.rendering.render_frame_if_dirty()
219    }
220
221    #[allow(clippy::cast_precision_loss)]
222    pub fn update_scale_factor(&mut self, scale_120ths: u32) {
223        self.event_context
224            .borrow_mut()
225            .update_scale_factor(scale_120ths);
226
227        let current_logical_size = self.rendering.logical_size();
228        if current_logical_size.width > 0 && current_logical_size.height > 0 {
229            self.update_size(current_logical_size.width, current_logical_size.height);
230        }
231    }
232
233    pub fn scale_factor(&self) -> f32 {
234        self.event_context.borrow().scale_factor()
235    }
236
237    pub const fn display_metrics(&self) -> &SharedDisplayMetrics {
238        &self.display_metrics
239    }
240
241    pub fn last_pointer_serial(&self) -> u32 {
242        self.event_context.borrow().last_pointer_serial()
243    }
244
245    pub fn set_last_pointer_serial(&mut self, serial: u32) {
246        self.event_context
247            .borrow_mut()
248            .set_last_pointer_serial(serial);
249    }
250
251    pub fn set_shared_pointer_serial(&mut self, shared_serial: Rc<SharedPointerSerial>) {
252        self.event_context
253            .borrow_mut()
254            .set_shared_pointer_serial(shared_serial);
255    }
256
257    pub fn set_popup_manager(&mut self, popup_manager: Rc<PopupManager>) {
258        self.event_context
259            .borrow_mut()
260            .set_popup_manager(popup_manager);
261    }
262
263    pub fn set_entered_surface(&self, surface: &WlSurface) {
264        self.event_context.borrow_mut().set_entered_surface(surface);
265    }
266
267    pub fn clear_entered_surface(&self) {
268        self.event_context.borrow_mut().clear_entered_surface();
269    }
270
271    pub fn is_popup_active(&self) -> bool {
272        self.event_context.borrow().is_popup_active()
273    }
274
275    pub fn dispatch_to_active_window(&self, event: WindowEvent) {
276        self.event_context.borrow().dispatch_to_active_window(event);
277    }
278
279    pub fn dispatch_to_surface(&self, surface_id: &ObjectId, event: WindowEvent) {
280        self.event_context
281            .borrow()
282            .dispatch_to_surface(surface_id, event);
283    }
284
285    pub fn set_axis_source(&self, axis_source: wl_pointer::AxisSource) {
286        self.event_context.borrow_mut().set_axis_source(axis_source);
287    }
288
289    pub fn accumulate_axis(&self, axis: wl_pointer::Axis, value: f64) {
290        self.event_context.borrow_mut().accumulate_axis(axis, value);
291    }
292
293    pub fn accumulate_axis_discrete(&self, axis: wl_pointer::Axis, discrete: i32) {
294        self.event_context
295            .borrow_mut()
296            .accumulate_axis_discrete(axis, discrete);
297    }
298
299    pub fn take_accumulated_axis(&self) -> (f32, f32) {
300        self.event_context.borrow_mut().take_accumulated_axis()
301    }
302
303    #[allow(clippy::cast_precision_loss)]
304    pub fn update_scale_for_fractional_scale_object(
305        &mut self,
306        fractional_scale_proxy: &WpFractionalScaleV1,
307        scale_120ths: u32,
308    ) {
309        let fractional_scale_id = fractional_scale_proxy.id();
310
311        if let Some(main_fractional_scale) = self.rendering.fractional_scale() {
312            if (**main_fractional_scale.inner()).id() == fractional_scale_id {
313                self.update_scale_factor(scale_120ths);
314                return;
315            }
316        }
317
318        self.event_context
319            .borrow()
320            .update_scale_for_fractional_scale_object(fractional_scale_proxy, scale_120ths);
321    }
322
323    pub fn popup_manager(&self) -> Option<Rc<PopupManager>> {
324        self.event_context.borrow().popup_manager().cloned()
325    }
326}
327
328impl ShellContextPort for SurfaceState {
329    fn render_frame_if_dirty(&mut self) -> CoreResult<(), DomainError> {
330        SurfaceState::render_frame_if_dirty(self).map_err(|e| DomainError::Adapter {
331            source: Box::new(e),
332        })
333    }
334}