1use crate::event_loop::{EventLoopHandle, FromAppState};
2use crate::layer_surface::LayerSurfaceHandle;
3use crate::popup_builder::PopupBuilder;
4use crate::shell_config::{CompiledUiSource, ShellConfig};
5use crate::shell_runtime::ShellRuntime;
6use crate::surface_registry::{SurfaceDefinition, SurfaceEntry, SurfaceRegistry};
7use crate::system::{
8 CallbackContext, EventDispatchContext, PopupCommand, ShellCommand, ShellControl,
9 SurfaceCommand, SurfaceTarget,
10};
11use crate::value_conversion::IntoValue;
12use crate::{Error, Result};
13use layer_shika_adapters::errors::EventLoopError;
14use layer_shika_adapters::platform::calloop::channel;
15use layer_shika_adapters::platform::slint_interpreter::{
16 CompilationResult, Compiler, ComponentInstance, Value,
17};
18use layer_shika_adapters::{
19 AppState, ShellSurfaceConfig, SurfaceState, WaylandSurfaceConfig, WaylandSystemOps,
20};
21use layer_shika_domain::config::SurfaceConfig;
22use layer_shika_domain::entities::output_registry::OutputRegistry;
23use layer_shika_domain::errors::DomainError;
24use layer_shika_domain::prelude::{
25 AnchorEdges, KeyboardInteractivity, Layer, Margins, OutputPolicy, ScaleFactor, SurfaceDimension,
26};
27use layer_shika_domain::value_objects::handle::SurfaceHandle;
28use layer_shika_domain::value_objects::output_handle::OutputHandle;
29use layer_shika_domain::value_objects::output_info::OutputInfo;
30use layer_shika_domain::value_objects::surface_instance_id::SurfaceInstanceId;
31use spin_on::spin_on;
32use std::cell::RefCell;
33use std::path::{Path, PathBuf};
34use std::rc::Rc;
35
36pub const DEFAULT_COMPONENT_NAME: &str = "Main";
38
39enum CompilationSource {
40 File { path: PathBuf, compiler: Compiler },
41 Source { code: String, compiler: Compiler },
42 Compiled(Rc<CompilationResult>),
43}
44
45pub struct ShellBuilder {
50 compilation: CompilationSource,
51 surfaces: Vec<SurfaceDefinition>,
52}
53
54impl ShellBuilder {
55 pub fn surface(self, component: impl Into<String>) -> SurfaceConfigBuilder {
57 SurfaceConfigBuilder {
58 shell_builder: self,
59 component: component.into(),
60 config: SurfaceConfig::default(),
61 }
62 }
63
64 #[must_use]
66 pub fn discover_surfaces(
67 mut self,
68 components: impl IntoIterator<Item = impl Into<String>>,
69 ) -> Self {
70 for component in components {
71 self.surfaces.push(SurfaceDefinition {
72 component: component.into(),
73 config: SurfaceConfig::default(),
74 });
75 }
76 self
77 }
78
79 pub fn build(self) -> Result<Shell> {
81 let surfaces = if self.surfaces.is_empty() {
82 vec![SurfaceDefinition {
83 component: DEFAULT_COMPONENT_NAME.to_string(),
84 config: SurfaceConfig::default(),
85 }]
86 } else {
87 self.surfaces
88 };
89
90 let compilation_result = match self.compilation {
91 CompilationSource::File { path, compiler } => {
92 let result = spin_on(compiler.build_from_path(&path));
93 let diagnostics: Vec<_> = result.diagnostics().collect();
94 if !diagnostics.is_empty() {
95 let messages: Vec<String> =
96 diagnostics.iter().map(ToString::to_string).collect();
97 return Err(DomainError::Configuration {
98 message: format!(
99 "Failed to compile Slint file '{}':\n{}",
100 path.display(),
101 messages.join("\n")
102 ),
103 }
104 .into());
105 }
106 Rc::new(result)
107 }
108 CompilationSource::Source { code, compiler } => {
109 let result = spin_on(compiler.build_from_source(code, PathBuf::default()));
110 let diagnostics: Vec<_> = result.diagnostics().collect();
111 if !diagnostics.is_empty() {
112 let messages: Vec<String> =
113 diagnostics.iter().map(ToString::to_string).collect();
114 return Err(DomainError::Configuration {
115 message: format!(
116 "Failed to compile Slint source:\n{}",
117 messages.join("\n")
118 ),
119 }
120 .into());
121 }
122 Rc::new(result)
123 }
124 CompilationSource::Compiled(result) => result,
125 };
126
127 Shell::new(compilation_result, surfaces)
128 }
129}
130
131pub struct SurfaceConfigBuilder {
136 shell_builder: ShellBuilder,
137 component: String,
138 config: SurfaceConfig,
139}
140
141impl SurfaceConfigBuilder {
142 #[must_use]
144 pub fn size(mut self, width: u32, height: u32) -> Self {
145 self.config.dimensions = SurfaceDimension::new(width, height);
146 self
147 }
148
149 #[must_use]
151 pub fn height(mut self, height: u32) -> Self {
152 self.config.dimensions = SurfaceDimension::new(self.config.dimensions.width(), height);
153 self
154 }
155
156 #[must_use]
158 pub fn width(mut self, width: u32) -> Self {
159 self.config.dimensions = SurfaceDimension::new(width, self.config.dimensions.height());
160 self
161 }
162
163 #[must_use]
165 pub const fn layer(mut self, layer: Layer) -> Self {
166 self.config.layer = layer;
167 self
168 }
169
170 #[must_use]
172 pub fn margin(mut self, margin: impl Into<Margins>) -> Self {
173 self.config.margin = margin.into();
174 self
175 }
176
177 #[must_use]
179 pub const fn anchor(mut self, anchor: AnchorEdges) -> Self {
180 self.config.anchor = anchor;
181 self
182 }
183
184 #[must_use]
189 pub const fn exclusive_zone(mut self, zone: i32) -> Self {
190 self.config.exclusive_zone = zone;
191 self
192 }
193
194 #[must_use]
196 pub fn namespace(mut self, namespace: impl Into<String>) -> Self {
197 self.config.namespace = namespace.into();
198 self
199 }
200
201 #[must_use]
203 pub fn scale_factor(mut self, sf: impl TryInto<ScaleFactor, Error = DomainError>) -> Self {
204 self.config.scale_factor = sf.try_into().unwrap_or_default();
205 self
206 }
207
208 #[must_use]
210 pub const fn keyboard_interactivity(mut self, mode: KeyboardInteractivity) -> Self {
211 self.config.keyboard_interactivity = mode;
212 self
213 }
214
215 #[must_use]
219 pub fn output_policy(mut self, policy: OutputPolicy) -> Self {
220 self.config.output_policy = policy;
221 self
222 }
223
224 #[must_use]
226 pub fn surface(self, component: impl Into<String>) -> SurfaceConfigBuilder {
227 let shell_builder = self.complete();
228 shell_builder.surface(component)
229 }
230
231 pub fn build(self) -> Result<Shell> {
233 self.complete().build()
234 }
235
236 pub fn run(self) -> Result<()> {
238 let mut shell = self.build()?;
239 shell.run()
240 }
241
242 fn complete(mut self) -> ShellBuilder {
243 self.shell_builder.surfaces.push(SurfaceDefinition {
244 component: self.component,
245 config: self.config,
246 });
247 self.shell_builder
248 }
249}
250
251type OutputConnectedHandler = Box<dyn Fn(&OutputInfo)>;
252type OutputDisconnectedHandler = Box<dyn Fn(OutputHandle)>;
253
254pub struct Shell {
261 inner: Rc<RefCell<dyn WaylandSystemOps>>,
262 registry: SurfaceRegistry,
263 compilation_result: Rc<CompilationResult>,
264 command_sender: channel::Sender<ShellCommand>,
265 output_connected_handlers: Rc<RefCell<Vec<OutputConnectedHandler>>>,
266 output_disconnected_handlers: Rc<RefCell<Vec<OutputDisconnectedHandler>>>,
267}
268
269impl Shell {
270 pub fn from_file(path: impl AsRef<Path>) -> ShellBuilder {
272 ShellBuilder {
273 compilation: CompilationSource::File {
274 path: path.as_ref().to_path_buf(),
275 compiler: Compiler::default(),
276 },
277 surfaces: Vec::new(),
278 }
279 }
280
281 pub fn from_file_with_compiler(path: impl AsRef<Path>, compiler: Compiler) -> ShellBuilder {
285 ShellBuilder {
286 compilation: CompilationSource::File {
287 path: path.as_ref().to_path_buf(),
288 compiler,
289 },
290 surfaces: Vec::new(),
291 }
292 }
293
294 pub fn from_source(code: impl Into<String>) -> ShellBuilder {
296 ShellBuilder {
297 compilation: CompilationSource::Source {
298 code: code.into(),
299 compiler: Compiler::default(),
300 },
301 surfaces: Vec::new(),
302 }
303 }
304
305 pub fn from_source_with_compiler(code: impl Into<String>, compiler: Compiler) -> ShellBuilder {
307 ShellBuilder {
308 compilation: CompilationSource::Source {
309 code: code.into(),
310 compiler,
311 },
312 surfaces: Vec::new(),
313 }
314 }
315
316 pub fn from_compilation(result: Rc<CompilationResult>) -> ShellBuilder {
318 ShellBuilder {
319 compilation: CompilationSource::Compiled(result),
320 surfaces: Vec::new(),
321 }
322 }
323
324 pub fn builder() -> ShellBuilder {
326 ShellBuilder {
327 compilation: CompilationSource::Source {
328 code: String::new(),
329 compiler: Compiler::default(),
330 },
331 surfaces: Vec::new(),
332 }
333 }
334
335 pub fn compile_file(path: impl AsRef<Path>) -> Result<Rc<CompilationResult>> {
337 let compiler = Compiler::default();
338 let result = spin_on(compiler.build_from_path(path.as_ref()));
339 let diagnostics: Vec<_> = result.diagnostics().collect();
340 if !diagnostics.is_empty() {
341 let messages: Vec<String> = diagnostics.iter().map(ToString::to_string).collect();
342 return Err(DomainError::Configuration {
343 message: format!(
344 "Failed to compile Slint file '{}':\n{}",
345 path.as_ref().display(),
346 messages.join("\n")
347 ),
348 }
349 .into());
350 }
351 Ok(Rc::new(result))
352 }
353
354 pub fn compile_source(code: impl Into<String>) -> Result<Rc<CompilationResult>> {
356 let compiler = Compiler::default();
357 let result = spin_on(compiler.build_from_source(code.into(), PathBuf::default()));
358 let diagnostics: Vec<_> = result.diagnostics().collect();
359 if !diagnostics.is_empty() {
360 let messages: Vec<String> = diagnostics.iter().map(ToString::to_string).collect();
361 return Err(DomainError::Configuration {
362 message: format!("Failed to compile Slint source:\n{}", messages.join("\n")),
363 }
364 .into());
365 }
366 Ok(Rc::new(result))
367 }
368
369 pub fn from_config(config: ShellConfig) -> Result<Self> {
371 let compilation_result = match config.ui_source {
372 CompiledUiSource::File(path) => Self::compile_file(&path)?,
373 CompiledUiSource::Source(code) => Self::compile_source(code)?,
374 CompiledUiSource::Compiled(result) => result,
375 };
376
377 let surfaces: Vec<SurfaceDefinition> = if config.surfaces.is_empty() {
378 vec![SurfaceDefinition {
379 component: DEFAULT_COMPONENT_NAME.to_string(),
380 config: SurfaceConfig::default(),
381 }]
382 } else {
383 config
384 .surfaces
385 .into_iter()
386 .map(|s| SurfaceDefinition {
387 component: s.component,
388 config: s.config,
389 })
390 .collect()
391 };
392
393 Self::new(compilation_result, surfaces)
394 }
395
396 pub(crate) fn new(
397 compilation_result: Rc<CompilationResult>,
398 definitions: Vec<SurfaceDefinition>,
399 ) -> Result<Self> {
400 log::info!("Creating Shell with {} windows", definitions.len());
401
402 if definitions.is_empty() {
403 return Err(Error::Domain(DomainError::Configuration {
404 message: "At least one window definition is required".to_string(),
405 }));
406 }
407
408 let is_single_window = definitions.len() == 1;
409
410 if is_single_window {
411 let definition = definitions.into_iter().next().ok_or_else(|| {
412 Error::Domain(DomainError::Configuration {
413 message: "Expected at least one window definition".to_string(),
414 })
415 })?;
416 Self::new_single_window(compilation_result, definition)
417 } else {
418 Self::new_multi_window(compilation_result, &definitions)
419 }
420 }
421
422 fn new_single_window(
423 compilation_result: Rc<CompilationResult>,
424 definition: SurfaceDefinition,
425 ) -> Result<Self> {
426 let component_definition = compilation_result
427 .component(&definition.component)
428 .ok_or_else(|| {
429 Error::Domain(DomainError::Configuration {
430 message: format!(
431 "Component '{}' not found in compilation result",
432 definition.component
433 ),
434 })
435 })?;
436
437 let handle = SurfaceHandle::new();
438 let wayland_config = WaylandSurfaceConfig::from_domain_config(
439 handle,
440 &definition.component,
441 component_definition,
442 Some(Rc::clone(&compilation_result)),
443 definition.config.clone(),
444 );
445
446 let inner = layer_shika_adapters::WaylandShellSystem::new(&wayland_config)?;
447 let inner_rc: Rc<RefCell<dyn WaylandSystemOps>> = Rc::new(RefCell::new(inner));
448
449 let (sender, receiver) = channel::channel();
450
451 let mut registry = SurfaceRegistry::new();
452 let entry = SurfaceEntry::new(handle, definition.component.clone(), definition);
453 registry.insert(entry)?;
454
455 let shell = Self {
456 inner: Rc::clone(&inner_rc),
457 registry,
458 compilation_result,
459 command_sender: sender,
460 output_connected_handlers: Rc::new(RefCell::new(Vec::new())),
461 output_disconnected_handlers: Rc::new(RefCell::new(Vec::new())),
462 };
463
464 shell.setup_command_handler(receiver)?;
465
466 log::info!("Shell created (single-window mode)");
467
468 Ok(shell)
469 }
470
471 fn new_multi_window(
472 compilation_result: Rc<CompilationResult>,
473 definitions: &[SurfaceDefinition],
474 ) -> Result<Self> {
475 let shell_configs_with_handles: Vec<(SurfaceHandle, ShellSurfaceConfig)> = definitions
476 .iter()
477 .map(|def| {
478 let component_definition = compilation_result
479 .component(&def.component)
480 .ok_or_else(|| {
481 Error::Domain(DomainError::Configuration {
482 message: format!(
483 "Component '{}' not found in compilation result",
484 def.component
485 ),
486 })
487 })?;
488
489 let handle = SurfaceHandle::new();
490 let wayland_config = WaylandSurfaceConfig::from_domain_config(
491 handle,
492 &def.component,
493 component_definition,
494 Some(Rc::clone(&compilation_result)),
495 def.config.clone(),
496 );
497
498 Ok((
499 handle,
500 ShellSurfaceConfig {
501 name: def.component.clone(),
502 config: wayland_config,
503 },
504 ))
505 })
506 .collect::<Result<Vec<_>>>()?;
507
508 let shell_configs: Vec<ShellSurfaceConfig> = shell_configs_with_handles
509 .iter()
510 .map(|(_, cfg)| cfg.clone())
511 .collect();
512
513 let inner = layer_shika_adapters::WaylandShellSystem::new_multi(&shell_configs)?;
514 let inner_rc: Rc<RefCell<dyn WaylandSystemOps>> = Rc::new(RefCell::new(inner));
515
516 let (sender, receiver) = channel::channel();
517
518 let mut registry = SurfaceRegistry::new();
519 for ((handle, _), definition) in shell_configs_with_handles.iter().zip(definitions.iter()) {
520 let entry =
521 SurfaceEntry::new(*handle, definition.component.clone(), definition.clone());
522 registry.insert(entry)?;
523 }
524
525 let shell = Self {
526 inner: Rc::clone(&inner_rc),
527 registry,
528 compilation_result,
529 command_sender: sender,
530 output_connected_handlers: Rc::new(RefCell::new(Vec::new())),
531 output_disconnected_handlers: Rc::new(RefCell::new(Vec::new())),
532 };
533
534 shell.setup_command_handler(receiver)?;
535
536 log::info!(
537 "Shell created (multi-surface mode) with surfaces: {:?}",
538 shell.surface_names()
539 );
540
541 Ok(shell)
542 }
543
544 fn setup_command_handler(&self, receiver: channel::Channel<ShellCommand>) -> Result<()> {
545 let loop_handle = self.inner.borrow().event_loop_handle();
546 let control = self.control();
547
548 loop_handle
549 .insert_source(receiver, move |event, (), app_state| {
550 if let channel::Event::Msg(command) = event {
551 let mut ctx = crate::system::EventDispatchContext::from_app_state(app_state);
552
553 match command {
554 ShellCommand::Popup(popup_cmd) => {
555 Self::handle_popup_command(popup_cmd, &mut ctx, &control);
556 }
557 ShellCommand::Surface(surface_cmd) => {
558 Self::handle_surface_command(surface_cmd, &mut ctx);
559 }
560 ShellCommand::Render => {
561 if let Err(e) = ctx.render_frame_if_dirty() {
562 log::error!("Failed to render frame: {}", e);
563 }
564 }
565 }
566 }
567 })
568 .map_err(|e| {
569 Error::Adapter(
570 EventLoopError::InsertSource {
571 message: format!("Failed to setup command handler: {e:?}"),
572 }
573 .into(),
574 )
575 })?;
576
577 Ok(())
578 }
579
580 fn handle_popup_command(
581 command: PopupCommand,
582 ctx: &mut EventDispatchContext<'_>,
583 control: &ShellControl,
584 ) {
585 match command {
586 PopupCommand::Show(request) => {
587 if let Err(e) = ctx.show_popup(&request, Some(control.clone())) {
588 log::error!("Failed to show popup: {}", e);
589 }
590 }
591 PopupCommand::Close(handle) => {
592 if let Err(e) = ctx.close_popup(handle) {
593 log::error!("Failed to close popup: {}", e);
594 }
595 }
596 PopupCommand::Resize {
597 handle,
598 width,
599 height,
600 } => {
601 if let Err(e) = ctx.resize_popup(handle, width, height) {
602 log::error!("Failed to resize popup: {}", e);
603 }
604 }
605 }
606 }
607
608 fn resolve_surface_target<'a>(
609 ctx: &'a mut EventDispatchContext<'_>,
610 target: &SurfaceTarget,
611 ) -> Vec<&'a mut SurfaceState> {
612 match target {
613 SurfaceTarget::ByInstance(id) => {
614 if let Some(surface) = ctx.surface_by_instance_mut(id.surface(), id.output()) {
615 vec![surface]
616 } else {
617 log::warn!(
618 "Surface instance not found: handle {:?} on output {:?}",
619 id.surface(),
620 id.output()
621 );
622 vec![]
623 }
624 }
625 SurfaceTarget::ByHandle(handle) => ctx.surfaces_by_handle_mut(*handle),
626 SurfaceTarget::ByName(name) => ctx.surfaces_by_name_mut(name),
627 SurfaceTarget::ByNameAndOutput { name, output } => {
628 ctx.surfaces_by_name_and_output_mut(name, *output)
629 }
630 }
631 }
632
633 fn apply_surface_resize(
634 ctx: &mut EventDispatchContext<'_>,
635 target: &SurfaceTarget,
636 width: u32,
637 height: u32,
638 ) {
639 log::debug!(
640 "Surface command: Resize {:?} to {}x{}",
641 target,
642 width,
643 height
644 );
645 for surface in Self::resolve_surface_target(ctx, target) {
646 let handle = LayerSurfaceHandle::from_window_state(surface);
647 handle.set_size(width, height);
648 handle.commit();
649 surface.update_size_with_compositor_logic(width, height);
650 }
651 }
652
653 fn apply_surface_config_change<F>(
654 ctx: &mut EventDispatchContext<'_>,
655 target: &SurfaceTarget,
656 operation: &str,
657 apply: F,
658 ) where
659 F: Fn(&LayerSurfaceHandle<'_>),
660 {
661 log::debug!("Surface command: {} {:?}", operation, target);
662 for surface in Self::resolve_surface_target(ctx, target) {
663 let handle = LayerSurfaceHandle::from_window_state(surface);
664 apply(&handle);
665 handle.commit();
666 }
667 }
668
669 fn apply_full_config(
670 ctx: &mut EventDispatchContext<'_>,
671 target: &SurfaceTarget,
672 config: &SurfaceConfig,
673 ) {
674 log::debug!("Surface command: ApplyConfig {:?}", target);
675 for surface in Self::resolve_surface_target(ctx, target) {
676 let handle = LayerSurfaceHandle::from_window_state(surface);
677
678 handle.set_size(config.dimensions.width(), config.dimensions.height());
679 handle.set_anchor_edges(config.anchor);
680 handle.set_exclusive_zone(config.exclusive_zone);
681 handle.set_margins(config.margin);
682 handle.set_layer(config.layer);
683 handle.set_keyboard_interactivity(config.keyboard_interactivity);
684 handle.commit();
685
686 surface.update_size_with_compositor_logic(
687 config.dimensions.width(),
688 config.dimensions.height(),
689 );
690 }
691 }
692
693 fn handle_surface_command(command: SurfaceCommand, ctx: &mut EventDispatchContext<'_>) {
694 match command {
695 SurfaceCommand::Resize {
696 target,
697 width,
698 height,
699 } => {
700 Self::apply_surface_resize(ctx, &target, width, height);
701 }
702 SurfaceCommand::SetAnchor { target, anchor } => {
703 Self::apply_surface_config_change(ctx, &target, "SetAnchor", |handle| {
704 handle.set_anchor_edges(anchor);
705 });
706 }
707 SurfaceCommand::SetExclusiveZone { target, zone } => {
708 Self::apply_surface_config_change(ctx, &target, "SetExclusiveZone", |handle| {
709 handle.set_exclusive_zone(zone);
710 });
711 }
712 SurfaceCommand::SetMargins { target, margins } => {
713 Self::apply_surface_config_change(ctx, &target, "SetMargins", |handle| {
714 handle.set_margins(margins);
715 });
716 }
717 SurfaceCommand::SetLayer { target, layer } => {
718 Self::apply_surface_config_change(ctx, &target, "SetLayer", |handle| {
719 handle.set_layer(layer);
720 });
721 }
722 SurfaceCommand::SetKeyboardInteractivity { target, mode } => {
723 Self::apply_surface_config_change(
724 ctx,
725 &target,
726 "SetKeyboardInteractivity",
727 |handle| {
728 handle.set_keyboard_interactivity(mode);
729 },
730 );
731 }
732 SurfaceCommand::SetOutputPolicy { target, policy } => {
733 log::debug!(
734 "Surface command: SetOutputPolicy {:?} to {:?}",
735 target,
736 policy
737 );
738 log::warn!(
739 "SetOutputPolicy is not yet implemented - requires runtime surface spawning"
740 );
741 }
742 SurfaceCommand::SetScaleFactor { target, factor } => {
743 log::debug!(
744 "Surface command: SetScaleFactor {:?} to {:?}",
745 target,
746 factor
747 );
748 log::warn!(
749 "SetScaleFactor is not yet implemented - requires runtime surface property updates"
750 );
751 }
752 SurfaceCommand::ApplyConfig { target, config } => {
753 Self::apply_full_config(ctx, &target, &config);
754 }
755 }
756
757 if let Err(e) = ctx.render_frame_if_dirty() {
758 log::error!("Failed to render frame after surface command: {}", e);
759 }
760 }
761
762 #[must_use]
764 pub fn control(&self) -> ShellControl {
765 ShellControl::new(self.command_sender.clone())
766 }
767
768 pub fn surface_names(&self) -> Vec<&str> {
770 self.registry.surface_names()
771 }
772
773 pub fn has_surface(&self, name: &str) -> bool {
775 self.registry.contains_name(name)
776 }
777
778 pub fn event_loop_handle(&self) -> EventLoopHandle {
780 EventLoopHandle::new(Rc::downgrade(&self.inner))
781 }
782
783 pub fn run(&mut self) -> Result<()> {
785 log::info!(
786 "Starting Shell event loop with {} windows",
787 self.registry.len()
788 );
789 self.inner.borrow_mut().run()?;
790 Ok(())
791 }
792
793 pub fn spawn_surface(&mut self, definition: SurfaceDefinition) -> Result<Vec<SurfaceHandle>> {
797 let component_definition = self
798 .compilation_result
799 .component(&definition.component)
800 .ok_or_else(|| {
801 Error::Domain(DomainError::Configuration {
802 message: format!(
803 "Component '{}' not found in compilation result",
804 definition.component
805 ),
806 })
807 })?;
808
809 let handle = SurfaceHandle::new();
810 let wayland_config = WaylandSurfaceConfig::from_domain_config(
811 handle,
812 &definition.component,
813 component_definition,
814 Some(Rc::clone(&self.compilation_result)),
815 definition.config.clone(),
816 );
817
818 let shell_config = ShellSurfaceConfig {
819 name: definition.component.clone(),
820 config: wayland_config,
821 };
822
823 let mut system = self.inner.borrow_mut();
824 let handles = system.spawn_surface(&shell_config)?;
825
826 let surface_handle = SurfaceHandle::new();
827 let entry = SurfaceEntry::new(surface_handle, definition.component.clone(), definition);
828 self.registry.insert(entry)?;
829
830 log::info!(
831 "Spawned surface with handle {:?}, created {} output instances",
832 surface_handle,
833 handles.len()
834 );
835
836 Ok(vec![surface_handle])
837 }
838
839 pub fn despawn_surface(&mut self, handle: SurfaceHandle) -> Result<()> {
841 let entry = self.registry.remove(handle).ok_or_else(|| {
842 Error::Domain(DomainError::Configuration {
843 message: format!("Surface handle {:?} not found", handle),
844 })
845 })?;
846
847 let mut system = self.inner.borrow_mut();
848 system.despawn_surface(&entry.name)?;
849
850 log::info!(
851 "Despawned surface '{}' with handle {:?}",
852 entry.name,
853 handle
854 );
855
856 Ok(())
857 }
858
859 pub fn on_output_connected<F>(&mut self, handler: F) -> Result<()>
863 where
864 F: Fn(&OutputInfo) + 'static,
865 {
866 self.output_connected_handlers
867 .borrow_mut()
868 .push(Box::new(handler));
869 Ok(())
870 }
871
872 pub fn on_output_disconnected<F>(&mut self, handler: F) -> Result<()>
874 where
875 F: Fn(OutputHandle) + 'static,
876 {
877 self.output_disconnected_handlers
878 .borrow_mut()
879 .push(Box::new(handler));
880 Ok(())
881 }
882
883 pub fn get_surface_handle(&self, name: &str) -> Option<SurfaceHandle> {
885 self.registry.handle_by_name(name)
886 }
887
888 pub fn get_surface_name(&self, handle: SurfaceHandle) -> Option<&str> {
890 self.registry.name_by_handle(handle)
891 }
892
893 pub fn with_surface<F, R>(&self, name: &str, f: F) -> Result<R>
895 where
896 F: FnOnce(&ComponentInstance) -> R,
897 {
898 if !self.registry.contains_name(name) {
899 return Err(Error::Domain(DomainError::Configuration {
900 message: format!("Window '{}' not found", name),
901 }));
902 }
903
904 let system = self.inner.borrow();
905
906 system
907 .app_state()
908 .surfaces_by_name(name)
909 .first()
910 .map(|surface| f(surface.component_instance()))
911 .ok_or_else(|| {
912 Error::Domain(DomainError::Configuration {
913 message: format!("No instance found for window '{}'", name),
914 })
915 })
916 }
917
918 pub fn with_all_surfaces<F>(&self, mut f: F)
920 where
921 F: FnMut(&str, &ComponentInstance),
922 {
923 let system = self.inner.borrow();
924
925 for name in self.registry.surface_names() {
926 for surface in system.app_state().surfaces_by_name(name) {
927 f(name, surface.component_instance());
928 }
929 }
930 }
931
932 pub fn with_output<F, R>(&self, handle: OutputHandle, f: F) -> Result<R>
934 where
935 F: FnOnce(&ComponentInstance) -> R,
936 {
937 let system = self.inner.borrow();
938 let window = system
939 .app_state()
940 .get_output_by_handle(handle)
941 .ok_or_else(|| {
942 Error::Domain(DomainError::Configuration {
943 message: format!("Output with handle {:?} not found", handle),
944 })
945 })?;
946 Ok(f(window.component_instance()))
947 }
948
949 pub fn with_all_outputs<F>(&self, mut f: F)
951 where
952 F: FnMut(OutputHandle, &ComponentInstance),
953 {
954 let system = self.inner.borrow();
955 for (handle, surface) in system.app_state().outputs_with_handles() {
956 f(handle, surface.component_instance());
957 }
958 }
959
960 #[must_use]
962 pub fn compilation_result(&self) -> &Rc<CompilationResult> {
963 &self.compilation_result
964 }
965
966 #[must_use]
968 pub fn popup(&self, component_name: impl Into<String>) -> PopupBuilder<'_> {
969 PopupBuilder::new(self, component_name.into())
970 }
971
972 pub fn output_registry(&self) -> OutputRegistry {
974 let system = self.inner.borrow();
975 system.app_state().output_registry().clone()
976 }
977
978 pub fn get_output_info(&self, handle: OutputHandle) -> Option<OutputInfo> {
980 let system = self.inner.borrow();
981 system.app_state().get_output_info(handle).cloned()
982 }
983
984 pub fn all_output_info(&self) -> Vec<OutputInfo> {
986 let system = self.inner.borrow();
987 system.app_state().all_output_info().cloned().collect()
988 }
989
990 pub fn select(&self, selector: impl Into<crate::Selector>) -> crate::Selection<'_> {
992 crate::Selection::new(self, selector.into())
993 }
994
995 fn get_output_handles(&self) -> (Option<OutputHandle>, Option<OutputHandle>) {
996 let registry = &self.output_registry();
997 (registry.primary_handle(), registry.active_handle())
998 }
999
1000 pub(crate) fn on_internal<F, R>(
1001 &self,
1002 selector: &crate::Selector,
1003 callback_name: &str,
1004 handler: F,
1005 ) where
1006 F: Fn(CallbackContext) -> R + Clone + 'static,
1007 R: IntoValue,
1008 {
1009 let control = self.control();
1010 let handler = Rc::new(handler);
1011 let system = self.inner.borrow();
1012 let (primary, active) = self.get_output_handles();
1013
1014 for (key, surface) in system.app_state().surfaces_with_keys() {
1015 let surface_handle = key.surface_handle;
1016 let output_handle = key.output_handle;
1017
1018 let surface_name = self.registry.by_handle(surface_handle).map_or_else(
1019 || format!("Unknown-{}", surface_handle.id()),
1020 |entry| entry.name.clone(),
1021 );
1022
1023 let surface_info = crate::SurfaceInfo {
1024 name: surface_name.clone(),
1025 output: output_handle,
1026 };
1027
1028 let output_info = system.app_state().get_output_info(output_handle);
1029
1030 if selector.matches(&surface_info, output_info, primary, active) {
1031 let instance_id = SurfaceInstanceId::new(surface_handle, output_handle);
1032
1033 let handler_rc = Rc::clone(&handler);
1034 let control_clone = control.clone();
1035 let surface_name_clone = surface_name.clone();
1036
1037 if let Err(e) =
1038 surface
1039 .component_instance()
1040 .set_callback(callback_name, move |_args| {
1041 let ctx = CallbackContext::new(
1042 instance_id,
1043 surface_name_clone.clone(),
1044 control_clone.clone(),
1045 );
1046 handler_rc(ctx).into_value()
1047 })
1048 {
1049 log::error!(
1050 "Failed to register callback '{}' on surface '{}': {}",
1051 callback_name,
1052 surface_name,
1053 e
1054 );
1055 }
1056 }
1057 }
1058 }
1059
1060 pub(crate) fn on_with_args_internal<F, R>(
1061 &self,
1062 selector: &crate::Selector,
1063 callback_name: &str,
1064 handler: F,
1065 ) where
1066 F: Fn(&[Value], CallbackContext) -> R + Clone + 'static,
1067 R: IntoValue,
1068 {
1069 let control = self.control();
1070 let handler = Rc::new(handler);
1071 let system = self.inner.borrow();
1072 let (primary, active) = self.get_output_handles();
1073
1074 for (key, surface) in system.app_state().surfaces_with_keys() {
1075 let surface_handle = key.surface_handle;
1076 let output_handle = key.output_handle;
1077
1078 let surface_name = self.registry.by_handle(surface_handle).map_or_else(
1079 || format!("Unknown-{}", surface_handle.id()),
1080 |entry| entry.name.clone(),
1081 );
1082
1083 let surface_info = crate::SurfaceInfo {
1084 name: surface_name.clone(),
1085 output: output_handle,
1086 };
1087
1088 let output_info = system.app_state().get_output_info(output_handle);
1089
1090 if selector.matches(&surface_info, output_info, primary, active) {
1091 let instance_id = SurfaceInstanceId::new(surface_handle, output_handle);
1092
1093 let handler_rc = Rc::clone(&handler);
1094 let control_clone = control.clone();
1095 let surface_name_clone = surface_name.clone();
1096
1097 if let Err(e) =
1098 surface
1099 .component_instance()
1100 .set_callback(callback_name, move |args| {
1101 let ctx = CallbackContext::new(
1102 instance_id,
1103 surface_name_clone.clone(),
1104 control_clone.clone(),
1105 );
1106 handler_rc(args, ctx).into_value()
1107 })
1108 {
1109 log::error!(
1110 "Failed to register callback '{}' on surface '{}': {}",
1111 callback_name,
1112 surface_name,
1113 e
1114 );
1115 }
1116 }
1117 }
1118 }
1119
1120 pub(crate) fn with_selected<F>(&self, selector: &crate::Selector, mut f: F)
1121 where
1122 F: FnMut(&str, &ComponentInstance),
1123 {
1124 let system = self.inner.borrow();
1125 let (primary, active) = self.get_output_handles();
1126
1127 for (key, surface) in system.app_state().surfaces_with_keys() {
1128 let surface_name = system
1129 .app_state()
1130 .get_surface_name(key.surface_handle)
1131 .unwrap_or("unknown");
1132 let surface_info = crate::SurfaceInfo {
1133 name: surface_name.to_string(),
1134 output: key.output_handle,
1135 };
1136
1137 let output_info = system.app_state().get_output_info(key.output_handle);
1138
1139 if selector.matches(&surface_info, output_info, primary, active) {
1140 f(surface_name, surface.component_instance());
1141 }
1142 }
1143 }
1144
1145 pub(crate) fn configure_selected<F>(&self, selector: &crate::Selector, mut f: F)
1146 where
1147 F: FnMut(&ComponentInstance, LayerSurfaceHandle<'_>),
1148 {
1149 let system = self.inner.borrow();
1150 let (primary, active) = self.get_output_handles();
1151
1152 for (key, surface) in system.app_state().surfaces_with_keys() {
1153 let surface_name = system
1154 .app_state()
1155 .get_surface_name(key.surface_handle)
1156 .unwrap_or("unknown");
1157 let surface_info = crate::SurfaceInfo {
1158 name: surface_name.to_string(),
1159 output: key.output_handle,
1160 };
1161
1162 let output_info = system.app_state().get_output_info(key.output_handle);
1163
1164 if selector.matches(&surface_info, output_info, primary, active) {
1165 let surface_handle = LayerSurfaceHandle::from_window_state(surface);
1166 f(surface.component_instance(), surface_handle);
1167 }
1168 }
1169 }
1170
1171 pub(crate) fn count_selected(&self, selector: &crate::Selector) -> usize {
1172 let system = self.inner.borrow();
1173 let (primary, active) = self.get_output_handles();
1174
1175 system
1176 .app_state()
1177 .surfaces_with_keys()
1178 .filter(|(key, _)| {
1179 let surface_name = system
1180 .app_state()
1181 .get_surface_name(key.surface_handle)
1182 .unwrap_or("unknown");
1183 let surface_info = crate::SurfaceInfo {
1184 name: surface_name.to_string(),
1185 output: key.output_handle,
1186 };
1187
1188 let output_info = system.app_state().get_output_info(key.output_handle);
1189
1190 selector.matches(&surface_info, output_info, primary, active)
1191 })
1192 .count()
1193 }
1194
1195 pub(crate) fn get_selected_info(&self, selector: &crate::Selector) -> Vec<crate::SurfaceInfo> {
1196 let system = self.inner.borrow();
1197 let (primary, active) = self.get_output_handles();
1198
1199 system
1200 .app_state()
1201 .surfaces_with_keys()
1202 .filter_map(|(key, _)| {
1203 let surface_name = system
1204 .app_state()
1205 .get_surface_name(key.surface_handle)
1206 .unwrap_or("unknown");
1207 let surface_info = crate::SurfaceInfo {
1208 name: surface_name.to_string(),
1209 output: key.output_handle,
1210 };
1211
1212 let output_info = system.app_state().get_output_info(key.output_handle);
1213
1214 if selector.matches(&surface_info, output_info, primary, active) {
1215 Some(surface_info)
1216 } else {
1217 None
1218 }
1219 })
1220 .collect()
1221 }
1222}
1223
1224impl ShellRuntime for Shell {
1225 type LoopHandle = EventLoopHandle;
1226 type Context<'a> = ShellEventContext<'a>;
1227
1228 fn event_loop_handle(&self) -> Self::LoopHandle {
1229 EventLoopHandle::new(Rc::downgrade(&self.inner))
1230 }
1231
1232 fn with_component<F>(&self, name: &str, mut f: F)
1233 where
1234 F: FnMut(&ComponentInstance),
1235 {
1236 let system = self.inner.borrow();
1237
1238 if self.registry.contains_name(name) {
1239 for surface in system.app_state().surfaces_by_name(name) {
1240 f(surface.component_instance());
1241 }
1242 }
1243 }
1244
1245 fn with_all_components<F>(&self, mut f: F)
1246 where
1247 F: FnMut(&str, &ComponentInstance),
1248 {
1249 let system = self.inner.borrow();
1250
1251 for name in self.registry.surface_names() {
1252 for surface in system.app_state().surfaces_by_name(name) {
1253 f(name, surface.component_instance());
1254 }
1255 }
1256 }
1257
1258 fn run(&mut self) -> Result<()> {
1259 self.inner.borrow_mut().run()?;
1260 Ok(())
1261 }
1262}
1263
1264pub struct ShellEventContext<'a> {
1268 app_state: &'a mut AppState,
1269}
1270
1271impl<'a> FromAppState<'a> for ShellEventContext<'a> {
1272 fn from_app_state(app_state: &'a mut AppState) -> Self {
1273 Self { app_state }
1274 }
1275}
1276
1277impl ShellEventContext<'_> {
1278 pub fn get_surface_component(&self, name: &str) -> Option<&ComponentInstance> {
1280 self.app_state
1281 .surfaces_by_name(name)
1282 .first()
1283 .map(|s| s.component_instance())
1284 }
1285
1286 pub fn all_surface_components(&self) -> impl Iterator<Item = &ComponentInstance> {
1288 self.app_state
1289 .all_outputs()
1290 .map(SurfaceState::component_instance)
1291 }
1292
1293 pub fn render_frame_if_dirty(&mut self) -> Result<()> {
1295 for surface in self.app_state.all_outputs() {
1296 surface.render_frame_if_dirty()?;
1297 }
1298 Ok(())
1299 }
1300
1301 #[must_use]
1303 pub fn primary_output_handle(&self) -> Option<OutputHandle> {
1304 self.app_state.primary_output_handle()
1305 }
1306
1307 #[must_use]
1309 pub fn active_output_handle(&self) -> Option<OutputHandle> {
1310 self.app_state.active_output_handle()
1311 }
1312
1313 pub fn output_registry(&self) -> &OutputRegistry {
1315 self.app_state.output_registry()
1316 }
1317
1318 pub fn outputs(&self) -> impl Iterator<Item = (OutputHandle, &ComponentInstance)> {
1320 self.app_state
1321 .outputs_with_handles()
1322 .map(|(handle, surface)| (handle, surface.component_instance()))
1323 }
1324
1325 pub fn get_output_component(&self, handle: OutputHandle) -> Option<&ComponentInstance> {
1327 self.app_state
1328 .get_output_by_handle(handle)
1329 .map(SurfaceState::component_instance)
1330 }
1331
1332 pub fn get_output_info(&self, handle: OutputHandle) -> Option<&OutputInfo> {
1334 self.app_state.get_output_info(handle)
1335 }
1336
1337 pub fn all_output_info(&self) -> impl Iterator<Item = &OutputInfo> {
1339 self.app_state.all_output_info()
1340 }
1341
1342 pub fn outputs_with_info(&self) -> impl Iterator<Item = (&OutputInfo, &ComponentInstance)> {
1344 self.app_state
1345 .outputs_with_info()
1346 .map(|(info, surface)| (info, surface.component_instance()))
1347 }
1348
1349 #[must_use]
1351 pub fn compilation_result(&self) -> Option<Rc<CompilationResult>> {
1352 self.app_state
1353 .primary_output()
1354 .and_then(SurfaceState::compilation_result)
1355 }
1356}