layer_shika_adapters/wayland/
shell_adapter.rs

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        // first roundtrip to receive initial output, globals, and surface configure events
688        // second roundtrip handles any cascading configure events like fractional scaling and layer surface configures
689        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}