1use crate::wayland::{
2 config::{LayerSurfaceConfig, ShellSurfaceConfig, WaylandSurfaceConfig},
3 globals::context::GlobalContext,
4 managed_proxies::{ManagedWlKeyboard, ManagedWlPointer},
5 ops::WaylandSystemOps,
6 outputs::{OutputManager, OutputManagerContext},
7 rendering::RenderableSet,
8 session_lock::{LockPropertyOperation, OutputFilter},
9 surfaces::layer_surface::{SurfaceCtx, SurfaceSetupParams},
10 surfaces::popup_manager::{PopupContext, PopupManager},
11 surfaces::{
12 app_state::AppState,
13 event_context::SharedPointerSerial,
14 surface_builder::{PlatformWrapper, SurfaceStateBuilder},
15 surface_state::SurfaceState,
16 },
17};
18use layer_shika_domain::value_objects::handle::SurfaceHandle;
19use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
20use crate::{
21 errors::{EventLoopError, LayerShikaError, RenderingError, Result},
22 rendering::{
23 egl::context_factory::RenderContextFactory,
24 femtovg::{main_window::FemtoVGWindow, renderable_window::RenderableWindow},
25 slint_integration::platform::CustomSlintPlatform,
26 },
27};
28use core::result::Result as CoreResult;
29use layer_shika_domain::errors::DomainError;
30use layer_shika_domain::ports::shell::ShellSystemPort;
31use layer_shika_domain::value_objects::lock_config::LockConfig;
32use layer_shika_domain::value_objects::lock_state::LockState;
33use layer_shika_domain::value_objects::output_handle::OutputHandle;
34use layer_shika_domain::value_objects::output_info::OutputInfo;
35use log::{error, info};
36use slint::{
37 LogicalPosition, PhysicalSize, PlatformError, WindowPosition,
38 platform::{WindowAdapter, femtovg_renderer::FemtoVGRenderer, set_platform, update_timers_and_animations},
39};
40use slint_interpreter::{ComponentInstance, CompilationResult};
41use smithay_client_toolkit::reexports::calloop::{
42 EventLoop, Interest, LoopHandle, Mode, PostAction, generic::Generic,
43};
44use std::cell::RefCell;
45use std::rc::Rc;
46use wayland_client::{
47 Connection, EventQueue, Proxy, QueueHandle,
48 backend::ObjectId,
49 protocol::{wl_pointer::WlPointer, wl_surface::WlSurface},
50};
51
52type PopupManagersAndSurfaces = (Vec<Rc<PopupManager>>, Vec<Rc<ZwlrLayerSurfaceV1>>);
53
54struct OutputSetup {
55 output_id: ObjectId,
56 main_surface_id: ObjectId,
57 window: Rc<FemtoVGWindow>,
58 builder: SurfaceStateBuilder,
59 surface_handle: SurfaceHandle,
60 shell_surface_name: String,
61}
62
63struct OutputManagerParams<'a> {
64 config: &'a WaylandSurfaceConfig,
65 global_ctx: &'a GlobalContext,
66 connection: &'a Connection,
67 layer_surface_config: LayerSurfaceConfig,
68 render_factory: &'a Rc<RenderContextFactory>,
69 popup_context: &'a PopupContext,
70 pointer: &'a Rc<WlPointer>,
71 shared_serial: &'a Rc<SharedPointerSerial>,
72}
73
74pub struct WaylandShellSystem {
75 state: AppState,
76 connection: Rc<Connection>,
77 event_queue: EventQueue<AppState>,
78 event_loop: EventLoop<'static, AppState>,
79}
80
81impl WaylandShellSystem {
82 pub fn new(config: &WaylandSurfaceConfig) -> Result<Self> {
83 info!("Initializing WindowingSystem");
84 let (connection, mut event_queue) = Self::init_wayland_connection()?;
85 let event_loop =
86 EventLoop::try_new().map_err(|e| EventLoopError::Creation { source: e })?;
87
88 let state = Self::init_state(config, &connection, &mut event_queue)?;
89
90 Ok(Self {
91 state,
92 connection,
93 event_queue,
94 event_loop,
95 })
96 }
97
98 pub fn new_multi(configs: &[ShellSurfaceConfig]) -> Result<Self> {
99 if configs.is_empty() {
100 return Self::new_minimal();
101 }
102
103 info!(
104 "Initializing WindowingSystem with {} surface configs",
105 configs.len()
106 );
107 let (connection, mut event_queue) = Self::init_wayland_connection()?;
108 let event_loop =
109 EventLoop::try_new().map_err(|e| EventLoopError::Creation { source: e })?;
110
111 let state = Self::init_state_multi(configs, &connection, &mut event_queue)?;
112
113 Ok(Self {
114 state,
115 connection,
116 event_queue,
117 event_loop,
118 })
119 }
120
121 pub fn new_minimal() -> Result<Self> {
122 info!("Initializing WindowingSystem in minimal mode (no layer surfaces)");
123 let (connection, mut event_queue) = Self::init_wayland_connection()?;
124 let event_loop =
125 EventLoop::try_new().map_err(|e| EventLoopError::Creation { source: e })?;
126
127 let state = Self::init_state_minimal(&connection, &mut event_queue)?;
128
129 Ok(Self {
130 state,
131 connection,
132 event_queue,
133 event_loop,
134 })
135 }
136
137 fn init_wayland_connection() -> Result<(Rc<Connection>, EventQueue<AppState>)> {
138 let connection = Rc::new(Connection::connect_to_env()?);
139 let event_queue = connection.new_event_queue();
140 Ok((connection, event_queue))
141 }
142
143 fn create_layer_surface_config(config: &WaylandSurfaceConfig) -> LayerSurfaceConfig {
144 LayerSurfaceConfig {
145 anchor: config.anchor,
146 margin: config.margin,
147 exclusive_zone: config.exclusive_zone,
148 keyboard_interactivity: config.keyboard_interactivity,
149 height: config.height,
150 width: config.width,
151 }
152 }
153
154 fn create_output_setups(
155 config: &WaylandSurfaceConfig,
156 global_ctx: &GlobalContext,
157 connection: &Connection,
158 event_queue: &mut EventQueue<AppState>,
159 pointer: &Rc<WlPointer>,
160 layer_surface_config: &LayerSurfaceConfig,
161 ) -> Result<Vec<OutputSetup>> {
162 let layer_shell =
163 global_ctx
164 .layer_shell
165 .as_ref()
166 .ok_or_else(|| LayerShikaError::InvalidInput {
167 message:
168 "wlr-layer-shell protocol not available - cannot create layer surfaces"
169 .into(),
170 })?;
171
172 let mut setups = Vec::new();
173
174 for (index, output) in global_ctx.outputs.iter().enumerate() {
175 let is_primary = index == 0;
176
177 let mut temp_info = OutputInfo::new(OutputHandle::new());
178 temp_info.set_primary(is_primary);
179
180 if !config.output_policy.should_render(&temp_info) {
181 info!("Skipping output {} due to output policy", index);
182 continue;
183 }
184
185 let output_id = output.id();
186
187 let setup_params = SurfaceSetupParams {
188 compositor: &global_ctx.compositor,
189 output,
190 layer_shell,
191 fractional_scale_manager: global_ctx.fractional_scale_manager.as_ref(),
192 viewporter: global_ctx.viewporter.as_ref(),
193 queue_handle: &event_queue.handle(),
194 layer: config.layer,
195 namespace: config.namespace.clone(),
196 };
197
198 let surface_ctx = SurfaceCtx::setup(&setup_params, layer_surface_config);
199 let main_surface_id = surface_ctx.surface.id();
200
201 let render_factory =
202 RenderContextFactory::new(Rc::clone(&global_ctx.render_context_manager));
203
204 let window = Self::initialize_renderer(&surface_ctx.surface, config, &render_factory)?;
205
206 let mut builder = SurfaceStateBuilder::new()
207 .with_component_definition(config.component_definition.clone())
208 .with_compilation_result(config.compilation_result.clone())
209 .with_surface(Rc::clone(&surface_ctx.surface))
210 .with_layer_surface(Rc::clone(&surface_ctx.layer_surface))
211 .with_scale_factor(config.scale_factor)
212 .with_height(config.height)
213 .with_width(config.width)
214 .with_exclusive_zone(config.exclusive_zone)
215 .with_connection(Rc::new(connection.clone()))
216 .with_pointer(Rc::clone(pointer))
217 .with_window(Rc::clone(&window));
218
219 if let Some(fs) = &surface_ctx.fractional_scale {
220 builder = builder.with_fractional_scale(Rc::clone(fs));
221 }
222
223 if let Some(vp) = &surface_ctx.viewport {
224 builder = builder.with_viewport(Rc::clone(vp));
225 }
226
227 setups.push(OutputSetup {
228 output_id,
229 main_surface_id,
230 window,
231 builder,
232 surface_handle: config.surface_handle,
233 shell_surface_name: config.surface_name.clone(),
234 });
235 }
236
237 Ok(setups)
238 }
239
240 fn setup_platform(setups: &[OutputSetup]) -> Result<Rc<CustomSlintPlatform>> {
241 let first_setup = setups
242 .first()
243 .ok_or_else(|| LayerShikaError::InvalidInput {
244 message: "No outputs available".into(),
245 })?;
246
247 let platform = CustomSlintPlatform::new(&first_setup.window);
248
249 for setup in setups.iter().skip(1) {
250 platform.add_window(Rc::clone(&setup.window));
251 }
252
253 set_platform(Box::new(PlatformWrapper(Rc::clone(&platform))))
254 .map_err(|e| LayerShikaError::PlatformSetup { source: e })?;
255
256 Ok(platform)
257 }
258
259 fn create_window_states(
260 setups: Vec<OutputSetup>,
261 popup_context: &PopupContext,
262 shared_serial: &Rc<SharedPointerSerial>,
263 app_state: &mut AppState,
264 ) -> Result<PopupManagersAndSurfaces> {
265 let mut popup_managers = Vec::new();
266 let mut layer_surfaces = Vec::new();
267
268 for setup in setups {
269 let mut per_output_surface = SurfaceState::new(setup.builder).map_err(|e| {
270 LayerShikaError::WindowConfiguration {
271 message: e.to_string(),
272 }
273 })?;
274
275 let popup_manager = Rc::new(PopupManager::new(
276 popup_context.clone(),
277 Rc::clone(per_output_surface.display_metrics()),
278 ));
279
280 per_output_surface.set_popup_manager(Rc::clone(&popup_manager));
281 per_output_surface.set_shared_pointer_serial(Rc::clone(shared_serial));
282
283 popup_managers.push(Rc::clone(&popup_manager));
284 layer_surfaces.push(per_output_surface.layer_surface());
285
286 app_state.add_shell_surface(
287 &setup.output_id,
288 setup.surface_handle,
289 &setup.shell_surface_name,
290 setup.main_surface_id,
291 per_output_surface,
292 );
293 }
294
295 Ok((popup_managers, layer_surfaces))
296 }
297
298 fn init_state(
299 config: &WaylandSurfaceConfig,
300 connection: &Connection,
301 event_queue: &mut EventQueue<AppState>,
302 ) -> Result<AppState> {
303 let global_ctx = Rc::new(GlobalContext::initialize(
304 connection,
305 &event_queue.handle(),
306 )?);
307 let layer_surface_config = Self::create_layer_surface_config(config);
308
309 let pointer = Rc::new(global_ctx.seat.get_pointer(&event_queue.handle(), ()));
310 let keyboard = Rc::new(global_ctx.seat.get_keyboard(&event_queue.handle(), ()));
311 let shared_serial = Rc::new(SharedPointerSerial::new());
312
313 let mut app_state = AppState::new(
314 ManagedWlPointer::new(Rc::clone(&pointer), Rc::new(connection.clone())),
315 ManagedWlKeyboard::new(Rc::clone(&keyboard), Rc::new(connection.clone())),
316 Rc::clone(&shared_serial),
317 );
318
319 app_state.set_queue_handle(event_queue.handle());
320
321 let render_factory =
322 RenderContextFactory::new(Rc::clone(&global_ctx.render_context_manager));
323
324 let popup_context = PopupContext::new(
325 global_ctx.compositor.clone(),
326 global_ctx.xdg_wm_base.clone(),
327 global_ctx.seat.clone(),
328 global_ctx.fractional_scale_manager.clone(),
329 global_ctx.viewporter.clone(),
330 Rc::new(connection.clone()),
331 Rc::clone(&render_factory),
332 );
333
334 let setups = Self::create_output_setups(
335 config,
336 global_ctx.as_ref(),
337 connection,
338 event_queue,
339 &pointer,
340 &layer_surface_config,
341 )?;
342
343 let platform = Self::setup_platform(&setups)?;
344 app_state.set_slint_platform(Rc::clone(&platform));
345
346 let (popup_managers, layer_surfaces) =
347 Self::create_window_states(setups, &popup_context, &shared_serial, &mut app_state)?;
348
349 Self::setup_shared_popup_creator(
350 popup_managers,
351 layer_surfaces,
352 &platform,
353 &event_queue.handle(),
354 &shared_serial,
355 );
356
357 let output_manager = Self::create_output_manager(&OutputManagerParams {
358 config,
359 global_ctx: global_ctx.as_ref(),
360 connection,
361 layer_surface_config,
362 render_factory: &render_factory,
363 popup_context: &popup_context,
364 pointer: &pointer,
365 shared_serial: &shared_serial,
366 });
367
368 app_state.set_output_manager(Rc::new(RefCell::new(output_manager)));
369 app_state.set_global_context(Rc::clone(&global_ctx));
370
371 Ok(app_state)
372 }
373
374 fn init_state_multi(
375 configs: &[ShellSurfaceConfig],
376 connection: &Connection,
377 event_queue: &mut EventQueue<AppState>,
378 ) -> Result<AppState> {
379 let global_ctx = Rc::new(GlobalContext::initialize(
380 connection,
381 &event_queue.handle(),
382 )?);
383
384 let pointer = Rc::new(global_ctx.seat.get_pointer(&event_queue.handle(), ()));
385 let keyboard = Rc::new(global_ctx.seat.get_keyboard(&event_queue.handle(), ()));
386 let shared_serial = Rc::new(SharedPointerSerial::new());
387
388 let mut app_state = AppState::new(
389 ManagedWlPointer::new(Rc::clone(&pointer), Rc::new(connection.clone())),
390 ManagedWlKeyboard::new(Rc::clone(&keyboard), Rc::new(connection.clone())),
391 Rc::clone(&shared_serial),
392 );
393
394 app_state.set_queue_handle(event_queue.handle());
395
396 let render_factory =
397 RenderContextFactory::new(Rc::clone(&global_ctx.render_context_manager));
398
399 let popup_context = PopupContext::new(
400 global_ctx.compositor.clone(),
401 global_ctx.xdg_wm_base.clone(),
402 global_ctx.seat.clone(),
403 global_ctx.fractional_scale_manager.clone(),
404 global_ctx.viewporter.clone(),
405 Rc::new(connection.clone()),
406 Rc::clone(&render_factory),
407 );
408
409 let setups = Self::create_output_setups_multi(
410 configs,
411 global_ctx.as_ref(),
412 connection,
413 event_queue,
414 &pointer,
415 )?;
416
417 let platform = Self::setup_platform(&setups)?;
418 app_state.set_slint_platform(Rc::clone(&platform));
419
420 let (popup_managers, layer_surfaces) =
421 Self::create_window_states(setups, &popup_context, &shared_serial, &mut app_state)?;
422
423 Self::setup_shared_popup_creator(
424 popup_managers,
425 layer_surfaces,
426 &platform,
427 &event_queue.handle(),
428 &shared_serial,
429 );
430
431 let primary_config = configs.first().map(|c| &c.config);
432 if let Some(config) = primary_config {
433 let layer_surface_config = Self::create_layer_surface_config(config);
434 let output_manager = Self::create_output_manager(&OutputManagerParams {
435 config,
436 global_ctx: global_ctx.as_ref(),
437 connection,
438 layer_surface_config,
439 render_factory: &render_factory,
440 popup_context: &popup_context,
441 pointer: &pointer,
442 shared_serial: &shared_serial,
443 });
444
445 app_state.set_output_manager(Rc::new(RefCell::new(output_manager)));
446 }
447
448 app_state.set_global_context(Rc::clone(&global_ctx));
449
450 Ok(app_state)
451 }
452
453 fn init_state_minimal(
454 connection: &Connection,
455 event_queue: &mut EventQueue<AppState>,
456 ) -> Result<AppState> {
457 let global_ctx = Rc::new(GlobalContext::initialize(
458 connection,
459 &event_queue.handle(),
460 )?);
461
462 let pointer = Rc::new(global_ctx.seat.get_pointer(&event_queue.handle(), ()));
463 let keyboard = Rc::new(global_ctx.seat.get_keyboard(&event_queue.handle(), ()));
464 let shared_serial = Rc::new(SharedPointerSerial::new());
465
466 let mut app_state = AppState::new(
467 ManagedWlPointer::new(Rc::clone(&pointer), Rc::new(connection.clone())),
468 ManagedWlKeyboard::new(Rc::clone(&keyboard), Rc::new(connection.clone())),
469 Rc::clone(&shared_serial),
470 );
471
472 app_state.set_queue_handle(event_queue.handle());
473 app_state.set_global_context(Rc::clone(&global_ctx));
474
475 let platform = CustomSlintPlatform::new_empty();
476 set_platform(Box::new(PlatformWrapper(Rc::clone(&platform))))
477 .map_err(|e| LayerShikaError::PlatformSetup { source: e })?;
478 app_state.set_slint_platform(Rc::clone(&platform));
479
480 info!(
481 "Minimal state initialized successfully (no layer surfaces, empty Slint platform for session locks)"
482 );
483
484 Ok(app_state)
485 }
486
487 fn create_output_setups_multi(
488 configs: &[ShellSurfaceConfig],
489 global_ctx: &GlobalContext,
490 connection: &Connection,
491 event_queue: &mut EventQueue<AppState>,
492 pointer: &Rc<WlPointer>,
493 ) -> Result<Vec<OutputSetup>> {
494 let layer_shell =
495 global_ctx
496 .layer_shell
497 .as_ref()
498 .ok_or_else(|| LayerShikaError::InvalidInput {
499 message:
500 "wlr-layer-shell protocol not available - cannot create layer surfaces"
501 .into(),
502 })?;
503
504 let mut setups = Vec::new();
505
506 for (output_index, output) in global_ctx.outputs.iter().enumerate() {
507 let is_primary = output_index == 0;
508 let output_id = output.id();
509
510 for shell_config in configs {
511 let config = &shell_config.config;
512
513 let mut temp_info = OutputInfo::new(OutputHandle::new());
514 temp_info.set_primary(is_primary);
515
516 if !config.output_policy.should_render(&temp_info) {
517 info!(
518 "Skipping shell surface '{}' on output {} due to output policy",
519 shell_config.name, output_index
520 );
521 continue;
522 }
523
524 let layer_surface_config = Self::create_layer_surface_config(config);
525
526 let setup_params = SurfaceSetupParams {
527 compositor: &global_ctx.compositor,
528 output,
529 layer_shell,
530 fractional_scale_manager: global_ctx.fractional_scale_manager.as_ref(),
531 viewporter: global_ctx.viewporter.as_ref(),
532 queue_handle: &event_queue.handle(),
533 layer: config.layer,
534 namespace: config.namespace.clone(),
535 };
536
537 let surface_ctx = SurfaceCtx::setup(&setup_params, &layer_surface_config);
538 let main_surface_id = surface_ctx.surface.id();
539
540 let render_factory =
541 RenderContextFactory::new(Rc::clone(&global_ctx.render_context_manager));
542
543 let window =
544 Self::initialize_renderer(&surface_ctx.surface, config, &render_factory)?;
545
546 let mut builder = SurfaceStateBuilder::new()
547 .with_component_definition(config.component_definition.clone())
548 .with_compilation_result(config.compilation_result.clone())
549 .with_surface(Rc::clone(&surface_ctx.surface))
550 .with_layer_surface(Rc::clone(&surface_ctx.layer_surface))
551 .with_scale_factor(config.scale_factor)
552 .with_height(config.height)
553 .with_width(config.width)
554 .with_exclusive_zone(config.exclusive_zone)
555 .with_connection(Rc::new(connection.clone()))
556 .with_pointer(Rc::clone(pointer))
557 .with_window(Rc::clone(&window));
558
559 if let Some(fs) = &surface_ctx.fractional_scale {
560 builder = builder.with_fractional_scale(Rc::clone(fs));
561 }
562
563 if let Some(vp) = &surface_ctx.viewport {
564 builder = builder.with_viewport(Rc::clone(vp));
565 }
566
567 info!(
568 "Created setup for shell surface '{}' on output {}",
569 shell_config.name, output_index
570 );
571
572 setups.push(OutputSetup {
573 output_id: output_id.clone(),
574 main_surface_id,
575 window,
576 builder,
577 surface_handle: shell_config.config.surface_handle,
578 shell_surface_name: shell_config.name.clone(),
579 });
580 }
581 }
582
583 Ok(setups)
584 }
585
586 fn create_output_manager(params: &OutputManagerParams<'_>) -> OutputManager {
587 let manager_context = OutputManagerContext {
588 compositor: params.global_ctx.compositor.clone(),
589 layer_shell: params.global_ctx.layer_shell.clone(),
590 fractional_scale_manager: params.global_ctx.fractional_scale_manager.clone(),
591 viewporter: params.global_ctx.viewporter.clone(),
592 render_factory: Rc::clone(params.render_factory),
593 popup_context: params.popup_context.clone(),
594 pointer: Rc::clone(params.pointer),
595 shared_serial: Rc::clone(params.shared_serial),
596 connection: Rc::new(params.connection.clone()),
597 };
598
599 OutputManager::new(
600 manager_context,
601 params.config.clone(),
602 params.layer_surface_config,
603 )
604 }
605
606 fn setup_shared_popup_creator(
607 popup_managers: Vec<Rc<PopupManager>>,
608 layer_surfaces: Vec<Rc<ZwlrLayerSurfaceV1>>,
609 platform: &Rc<CustomSlintPlatform>,
610 queue_handle: &QueueHandle<AppState>,
611 shared_serial: &Rc<SharedPointerSerial>,
612 ) {
613 let Some(first_manager) = popup_managers.first() else {
614 info!("No popup managers available");
615 return;
616 };
617
618 if !first_manager.has_xdg_shell() {
619 info!("xdg-shell not available, popups will not be supported");
620 return;
621 }
622
623 info!(
624 "Setting up shared popup creator for {} output(s)",
625 popup_managers.len()
626 );
627
628 let queue_handle_clone = queue_handle.clone();
629 let serial_holder = Rc::clone(shared_serial);
630
631 platform.set_popup_creator(move || {
632 info!("Popup creator called! Searching for pending popup...");
633
634 let serial = serial_holder.get();
635
636 for (idx, (popup_manager, layer_surface)) in
637 popup_managers.iter().zip(layer_surfaces.iter()).enumerate()
638 {
639 if popup_manager.has_pending_popup() {
640 info!("Found pending popup in output #{}", idx);
641
642 let popup_surface = popup_manager
643 .create_pending_popup(&queue_handle_clone, layer_surface, serial)
644 .map_err(|e| {
645 PlatformError::Other(format!("Failed to create popup: {e}"))
646 })?;
647
648 info!("Popup created successfully for output #{}", idx);
649 return Ok(popup_surface as Rc<dyn WindowAdapter>);
650 }
651 }
652
653 Err(PlatformError::Other(
654 "No pending popup request found in any output".into(),
655 ))
656 });
657 }
658
659 pub(crate) fn initialize_renderer(
660 surface: &Rc<WlSurface>,
661 config: &WaylandSurfaceConfig,
662 render_factory: &Rc<RenderContextFactory>,
663 ) -> Result<Rc<FemtoVGWindow>> {
664 let init_size = PhysicalSize::new(1, 1);
665
666 let context = render_factory.create_context(&surface.id(), init_size)?;
667
668 let renderer = FemtoVGRenderer::new(context)
669 .map_err(|e| LayerShikaError::FemtoVGRendererCreation { source: e })?;
670
671 let femtovg_window = FemtoVGWindow::new(renderer);
672 femtovg_window.set_size(slint::WindowSize::Physical(init_size));
673 femtovg_window.set_scale_factor(config.scale_factor);
674 femtovg_window.set_position(WindowPosition::Logical(LogicalPosition::new(0., 0.)));
675
676 Ok(femtovg_window)
677 }
678
679 pub fn event_loop_handle(&self) -> LoopHandle<'static, AppState> {
680 self.event_loop.handle()
681 }
682
683 pub fn run(&mut self) -> Result<()> {
684 info!("Starting WindowingSystem main loop");
685
686 info!("Processing initial Wayland configuration events");
687 for i in 0..2 {
690 let dispatched = self.event_queue.roundtrip(&mut self.state)?;
691 info!("Roundtrip {} dispatched {} events", i + 1, dispatched);
692
693 self.connection
694 .flush()
695 .map_err(|e| LayerShikaError::WaylandProtocol { source: e })?;
696
697 update_timers_and_animations();
698
699 self.state.render_all_dirty()?;
700 if let Some(lock_manager) = self.state.lock_manager() {
701 lock_manager.render_all_dirty()?;
702 }
703 }
704
705 info!("Initial configuration complete, requesting final render");
706 for surface in self.state.all_outputs() {
707 RenderableWindow::request_redraw(surface.window().as_ref());
708 }
709 update_timers_and_animations();
710 self.state.render_all_dirty()?;
711 if let Some(lock_manager) = self.state.lock_manager() {
712 lock_manager.render_all_dirty()?;
713 }
714 self.connection
715 .flush()
716 .map_err(|e| LayerShikaError::WaylandProtocol { source: e })?;
717
718 self.setup_wayland_event_source()?;
719
720 let event_queue = &mut self.event_queue;
721 let connection = &self.connection;
722
723 self.event_loop
724 .run(None, &mut self.state, move |shared_data| {
725 if let Err(e) = Self::process_events(connection, event_queue, shared_data) {
726 error!("Error processing events: {e}");
727 }
728 })
729 .map_err(|e| EventLoopError::Execution { source: e })?;
730
731 Ok(())
732 }
733
734 fn setup_wayland_event_source(&self) -> Result<()> {
735 let connection = Rc::clone(&self.connection);
736
737 self.event_loop
738 .handle()
739 .insert_source(
740 Generic::new(connection, Interest::READ, Mode::Level),
741 move |_, _connection, _shared_data| Ok(PostAction::Continue),
742 )
743 .map_err(|e| EventLoopError::InsertSource {
744 message: format!("{e:?}"),
745 })?;
746
747 Ok(())
748 }
749
750 fn process_events(
751 connection: &Connection,
752 event_queue: &mut EventQueue<AppState>,
753 shared_data: &mut AppState,
754 ) -> Result<()> {
755 if let Some(guard) = event_queue.prepare_read() {
756 guard
757 .read()
758 .map_err(|e| LayerShikaError::WaylandProtocol { source: e })?;
759 }
760
761 event_queue.dispatch_pending(shared_data)?;
762
763 update_timers_and_animations();
764
765 if let Some(lock_manager) = shared_data.lock_manager_mut() {
766 lock_manager.initialize_pending_components()?;
767 }
768
769 for surface in shared_data.all_outputs() {
770 surface
771 .window()
772 .render_frame_if_dirty()
773 .map_err(|e| RenderingError::Operation {
774 message: e.to_string(),
775 })?;
776
777 if let Some(popup_manager) = surface.popup_manager() {
778 popup_manager
779 .render_popups()
780 .map_err(|e| RenderingError::Operation {
781 message: e.to_string(),
782 })?;
783 }
784 }
785
786 if let Some(lock_manager) = shared_data.lock_manager() {
787 lock_manager.render_all_dirty()?;
788 }
789
790 connection
791 .flush()
792 .map_err(|e| LayerShikaError::WaylandProtocol { source: e })?;
793
794 Ok(())
795 }
796
797 pub fn component_instance(&self) -> Result<&ComponentInstance> {
798 self.state
799 .primary_output()
800 .ok_or_else(|| LayerShikaError::InvalidInput {
801 message: "No outputs available".into(),
802 })
803 .map(SurfaceState::component_instance)
804 }
805
806 pub fn state(&self) -> Result<&SurfaceState> {
807 self.state
808 .primary_output()
809 .ok_or_else(|| LayerShikaError::InvalidInput {
810 message: "No outputs available".into(),
811 })
812 }
813
814 pub fn app_state(&self) -> &AppState {
815 &self.state
816 }
817
818 pub fn app_state_mut(&mut self) -> &mut AppState {
819 &mut self.state
820 }
821
822 pub fn spawn_surface(&mut self, config: &ShellSurfaceConfig) -> Result<Vec<OutputHandle>> {
823 log::info!("Spawning new surface '{}'", config.name);
824
825 let mut handles = Vec::new();
826
827 for (output_handle, _surface) in self.state.outputs_with_handles() {
828 handles.push(output_handle);
829 }
830
831 log::info!(
832 "Surface '{}' would spawn on {} outputs (dynamic spawning not yet fully implemented)",
833 config.name,
834 handles.len()
835 );
836
837 Ok(handles)
838 }
839
840 pub fn despawn_surface(&mut self, surface_name: &str) -> Result<()> {
841 log::info!("Despawning surface '{}'", surface_name);
842
843 let removed = self.state.remove_surfaces_by_name(surface_name);
844
845 log::info!(
846 "Removed {} surface instances for '{}'",
847 removed.len(),
848 surface_name
849 );
850
851 Ok(())
852 }
853}
854
855impl ShellSystemPort for WaylandShellSystem {
856 fn run(&mut self) -> CoreResult<(), DomainError> {
857 WaylandShellSystem::run(self).map_err(|e| DomainError::Adapter {
858 source: Box::new(e),
859 })
860 }
861}
862
863impl WaylandSystemOps for WaylandShellSystem {
864 fn run(&mut self) -> Result<()> {
865 WaylandShellSystem::run(self)
866 }
867
868 fn spawn_surface(&mut self, config: &ShellSurfaceConfig) -> Result<Vec<OutputHandle>> {
869 WaylandShellSystem::spawn_surface(self, config)
870 }
871
872 fn despawn_surface(&mut self, name: &str) -> Result<()> {
873 WaylandShellSystem::despawn_surface(self, name)
874 }
875
876 fn set_compilation_result(&mut self, compilation_result: Rc<CompilationResult>) {
877 self.state.set_compilation_result(compilation_result);
878 }
879
880 fn activate_session_lock(&mut self, component_name: &str, config: LockConfig) -> Result<()> {
881 self.state.activate_session_lock(component_name, config)
882 }
883
884 fn deactivate_session_lock(&mut self) -> Result<()> {
885 self.state.deactivate_session_lock()
886 }
887
888 fn is_session_lock_available(&self) -> bool {
889 self.state.is_session_lock_available()
890 }
891
892 fn session_lock_state(&self) -> Option<LockState> {
893 self.state.current_lock_state()
894 }
895
896 fn register_session_lock_callback(
897 &mut self,
898 callback_name: &str,
899 handler: Rc<dyn Fn(&[slint_interpreter::Value]) -> slint_interpreter::Value>,
900 ) {
901 self.state
902 .register_session_lock_callback(callback_name, handler);
903 }
904
905 fn register_session_lock_callback_with_filter(
906 &mut self,
907 callback_name: &str,
908 handler: Rc<dyn Fn(&[slint_interpreter::Value]) -> slint_interpreter::Value>,
909 filter: OutputFilter,
910 ) {
911 self.state
912 .register_session_lock_callback_with_filter(callback_name, handler, filter);
913 }
914
915 fn register_session_lock_property_operation(
916 &mut self,
917 property_operation: LockPropertyOperation,
918 ) {
919 self.state
920 .register_session_lock_property_operation(property_operation);
921 }
922
923 fn session_lock_component_name(&self) -> Option<String> {
924 self.state.session_lock_component_name()
925 }
926
927 fn iter_lock_surfaces(&self, f: &mut dyn FnMut(OutputHandle, &ComponentInstance)) {
928 self.state.iter_lock_surfaces(f);
929 }
930
931 fn count_lock_surfaces(&self) -> usize {
932 self.state.count_lock_surfaces()
933 }
934
935 fn app_state(&self) -> &AppState {
936 WaylandShellSystem::app_state(self)
937 }
938
939 fn app_state_mut(&mut self) -> &mut AppState {
940 WaylandShellSystem::app_state_mut(self)
941 }
942
943 fn event_loop_handle(&self) -> LoopHandle<'static, AppState> {
944 WaylandShellSystem::event_loop_handle(self)
945 }
946
947 fn component_instance(&self) -> Result<&ComponentInstance> {
948 WaylandShellSystem::component_instance(self)
949 }
950}