1use crate::event_loop::{EventLoopHandle, FromAppState};
2use crate::layer_surface::LayerSurfaceHandle;
3use crate::session_lock::{SessionLock, SessionLockBuilder};
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, SessionLockCommand, ShellCommand,
9 ShellControl, 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, Weak};
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> {
84 let surfaces = self.surfaces;
85
86 let compilation_result = match self.compilation {
87 CompilationSource::File { path, compiler } => {
88 let result = spin_on(compiler.build_from_path(&path));
89 let diagnostics: Vec<_> = result.diagnostics().collect();
90 if !diagnostics.is_empty() {
91 let messages: Vec<String> =
92 diagnostics.iter().map(ToString::to_string).collect();
93 return Err(DomainError::Configuration {
94 message: format!(
95 "Failed to compile Slint file '{}':\n{}",
96 path.display(),
97 messages.join("\n")
98 ),
99 }
100 .into());
101 }
102 Rc::new(result)
103 }
104 CompilationSource::Source { code, compiler } => {
105 let result = spin_on(compiler.build_from_source(code, PathBuf::default()));
106 let diagnostics: Vec<_> = result.diagnostics().collect();
107 if !diagnostics.is_empty() {
108 let messages: Vec<String> =
109 diagnostics.iter().map(ToString::to_string).collect();
110 return Err(DomainError::Configuration {
111 message: format!(
112 "Failed to compile Slint source:\n{}",
113 messages.join("\n")
114 ),
115 }
116 .into());
117 }
118 Rc::new(result)
119 }
120 CompilationSource::Compiled(result) => result,
121 };
122
123 Shell::new(compilation_result, surfaces)
124 }
125}
126
127pub struct SurfaceConfigBuilder {
132 shell_builder: ShellBuilder,
133 component: String,
134 config: SurfaceConfig,
135}
136
137impl SurfaceConfigBuilder {
138 #[must_use]
140 pub fn size(mut self, width: u32, height: u32) -> Self {
141 self.config.dimensions = SurfaceDimension::new(width, height);
142 self
143 }
144
145 #[must_use]
147 pub fn height(mut self, height: u32) -> Self {
148 self.config.dimensions = SurfaceDimension::new(self.config.dimensions.width(), height);
149 self
150 }
151
152 #[must_use]
154 pub fn width(mut self, width: u32) -> Self {
155 self.config.dimensions = SurfaceDimension::new(width, self.config.dimensions.height());
156 self
157 }
158
159 #[must_use]
161 pub const fn layer(mut self, layer: Layer) -> Self {
162 self.config.layer = layer;
163 self
164 }
165
166 #[must_use]
168 pub fn margin(mut self, margin: impl Into<Margins>) -> Self {
169 self.config.margin = margin.into();
170 self
171 }
172
173 #[must_use]
175 pub const fn anchor(mut self, anchor: AnchorEdges) -> Self {
176 self.config.anchor = anchor;
177 self
178 }
179
180 #[must_use]
185 pub const fn exclusive_zone(mut self, zone: i32) -> Self {
186 self.config.exclusive_zone = zone;
187 self
188 }
189
190 #[must_use]
192 pub fn namespace(mut self, namespace: impl Into<String>) -> Self {
193 self.config.namespace = namespace.into();
194 self
195 }
196
197 #[must_use]
199 pub fn scale_factor(mut self, sf: impl TryInto<ScaleFactor, Error = DomainError>) -> Self {
200 self.config.scale_factor = sf.try_into().unwrap_or_default();
201 self
202 }
203
204 #[must_use]
206 pub const fn keyboard_interactivity(mut self, mode: KeyboardInteractivity) -> Self {
207 self.config.keyboard_interactivity = mode;
208 self
209 }
210
211 #[must_use]
215 pub fn output_policy(mut self, policy: OutputPolicy) -> Self {
216 self.config.output_policy = policy;
217 self
218 }
219
220 #[must_use]
222 pub fn surface(self, component: impl Into<String>) -> SurfaceConfigBuilder {
223 let shell_builder = self.complete();
224 shell_builder.surface(component)
225 }
226
227 pub fn build(self) -> Result<Shell> {
229 self.complete().build()
230 }
231
232 pub fn run(self) -> Result<()> {
234 let mut shell = self.build()?;
235 shell.run()
236 }
237
238 fn complete(mut self) -> ShellBuilder {
239 self.shell_builder.surfaces.push(SurfaceDefinition {
240 component: self.component,
241 config: self.config,
242 });
243 self.shell_builder
244 }
245}
246
247type OutputConnectedHandler = Box<dyn Fn(&OutputInfo)>;
248type OutputDisconnectedHandler = Box<dyn Fn(OutputHandle)>;
249
250pub struct Shell {
257 inner: Rc<RefCell<dyn WaylandSystemOps>>,
258 registry: SurfaceRegistry,
259 compilation_result: Rc<CompilationResult>,
260 command_sender: channel::Sender<ShellCommand>,
261 output_connected_handlers: Rc<RefCell<Vec<OutputConnectedHandler>>>,
262 output_disconnected_handlers: Rc<RefCell<Vec<OutputDisconnectedHandler>>>,
263}
264
265impl Shell {
266 pub fn from_file(path: impl AsRef<Path>) -> ShellBuilder {
268 ShellBuilder {
269 compilation: CompilationSource::File {
270 path: path.as_ref().to_path_buf(),
271 compiler: Compiler::default(),
272 },
273 surfaces: Vec::new(),
274 }
275 }
276
277 pub fn from_file_with_compiler(path: impl AsRef<Path>, compiler: Compiler) -> ShellBuilder {
281 ShellBuilder {
282 compilation: CompilationSource::File {
283 path: path.as_ref().to_path_buf(),
284 compiler,
285 },
286 surfaces: Vec::new(),
287 }
288 }
289
290 pub fn from_source(code: impl Into<String>) -> ShellBuilder {
292 ShellBuilder {
293 compilation: CompilationSource::Source {
294 code: code.into(),
295 compiler: Compiler::default(),
296 },
297 surfaces: Vec::new(),
298 }
299 }
300
301 pub fn from_source_with_compiler(code: impl Into<String>, compiler: Compiler) -> ShellBuilder {
303 ShellBuilder {
304 compilation: CompilationSource::Source {
305 code: code.into(),
306 compiler,
307 },
308 surfaces: Vec::new(),
309 }
310 }
311
312 pub fn from_compilation(result: Rc<CompilationResult>) -> ShellBuilder {
314 ShellBuilder {
315 compilation: CompilationSource::Compiled(result),
316 surfaces: Vec::new(),
317 }
318 }
319
320 pub fn builder() -> ShellBuilder {
322 ShellBuilder {
323 compilation: CompilationSource::Source {
324 code: String::new(),
325 compiler: Compiler::default(),
326 },
327 surfaces: Vec::new(),
328 }
329 }
330
331 pub fn compile_file(path: impl AsRef<Path>) -> Result<Rc<CompilationResult>> {
333 let compiler = Compiler::default();
334 let result = spin_on(compiler.build_from_path(path.as_ref()));
335 let diagnostics: Vec<_> = result.diagnostics().collect();
336 if !diagnostics.is_empty() {
337 let messages: Vec<String> = diagnostics.iter().map(ToString::to_string).collect();
338 return Err(DomainError::Configuration {
339 message: format!(
340 "Failed to compile Slint file '{}':\n{}",
341 path.as_ref().display(),
342 messages.join("\n")
343 ),
344 }
345 .into());
346 }
347 Ok(Rc::new(result))
348 }
349
350 pub fn compile_source(code: impl Into<String>) -> Result<Rc<CompilationResult>> {
352 let compiler = Compiler::default();
353 let result = spin_on(compiler.build_from_source(code.into(), PathBuf::default()));
354 let diagnostics: Vec<_> = result.diagnostics().collect();
355 if !diagnostics.is_empty() {
356 let messages: Vec<String> = diagnostics.iter().map(ToString::to_string).collect();
357 return Err(DomainError::Configuration {
358 message: format!("Failed to compile Slint source:\n{}", messages.join("\n")),
359 }
360 .into());
361 }
362 Ok(Rc::new(result))
363 }
364
365 pub fn from_config(config: ShellConfig) -> Result<Self> {
367 let compilation_result = match config.ui_source {
368 CompiledUiSource::File(path) => Self::compile_file(&path)?,
369 CompiledUiSource::Source(code) => Self::compile_source(code)?,
370 CompiledUiSource::Compiled(result) => result,
371 };
372
373 let surfaces: Vec<SurfaceDefinition> = if config.surfaces.is_empty() {
374 vec![SurfaceDefinition {
375 component: DEFAULT_COMPONENT_NAME.to_string(),
376 config: SurfaceConfig::default(),
377 }]
378 } else {
379 config
380 .surfaces
381 .into_iter()
382 .map(|s| SurfaceDefinition {
383 component: s.component,
384 config: s.config,
385 })
386 .collect()
387 };
388
389 Self::new(compilation_result, surfaces)
390 }
391
392 pub(crate) fn new(
393 compilation_result: Rc<CompilationResult>,
394 definitions: Vec<SurfaceDefinition>,
395 ) -> Result<Self> {
396 log::info!("Creating Shell with {} windows", definitions.len());
397
398 for def in &definitions {
399 def.config.validate().map_err(Error::Domain)?;
400 }
401
402 match definitions.len() {
403 0 => {
404 log::info!("Creating minimal shell without layer surfaces");
405 Self::new_minimal(compilation_result)
406 }
407 1 => {
408 let definition = definitions.into_iter().next().ok_or_else(|| {
409 Error::Domain(DomainError::Configuration {
410 message: "Expected at least one window definition".to_string(),
411 })
412 })?;
413 Self::new_single_window(compilation_result, definition)
414 }
415 _ => Self::new_multi_window(compilation_result, &definitions),
416 }
417 }
418
419 fn new_single_window(
420 compilation_result: Rc<CompilationResult>,
421 definition: SurfaceDefinition,
422 ) -> Result<Self> {
423 let component_definition = compilation_result
424 .component(&definition.component)
425 .ok_or_else(|| {
426 Error::Domain(DomainError::ComponentNotFound {
427 name: definition.component.clone(),
428 })
429 })?;
430
431 let handle = SurfaceHandle::new();
432 let wayland_config = WaylandSurfaceConfig::from_domain_config(
433 handle,
434 &definition.component,
435 component_definition,
436 Some(Rc::clone(&compilation_result)),
437 definition.config.clone(),
438 );
439
440 let inner = layer_shika_adapters::WaylandShellSystem::new(&wayland_config)?;
441 let inner_rc: Rc<RefCell<dyn WaylandSystemOps>> = Rc::new(RefCell::new(inner));
442
443 let (sender, receiver) = channel::channel();
444
445 let mut registry = SurfaceRegistry::new();
446 let entry = SurfaceEntry::new(handle, definition.component.clone(), definition);
447 registry.insert(entry)?;
448
449 let shell = Self {
450 inner: Rc::clone(&inner_rc),
451 registry,
452 compilation_result,
453 command_sender: sender,
454 output_connected_handlers: Rc::new(RefCell::new(Vec::new())),
455 output_disconnected_handlers: Rc::new(RefCell::new(Vec::new())),
456 };
457
458 shell.setup_command_handler(receiver)?;
459
460 log::info!("Shell created (single-window mode)");
461
462 Ok(shell)
463 }
464
465 fn new_multi_window(
466 compilation_result: Rc<CompilationResult>,
467 definitions: &[SurfaceDefinition],
468 ) -> Result<Self> {
469 let shell_configs_with_handles: Vec<(SurfaceHandle, ShellSurfaceConfig)> = definitions
470 .iter()
471 .map(|def| {
472 let component_definition = compilation_result
473 .component(&def.component)
474 .ok_or_else(|| {
475 Error::Domain(DomainError::ComponentNotFound {
476 name: def.component.clone(),
477 })
478 })?;
479
480 let handle = SurfaceHandle::new();
481 let wayland_config = WaylandSurfaceConfig::from_domain_config(
482 handle,
483 &def.component,
484 component_definition,
485 Some(Rc::clone(&compilation_result)),
486 def.config.clone(),
487 );
488
489 Ok((
490 handle,
491 ShellSurfaceConfig {
492 name: def.component.clone(),
493 config: wayland_config,
494 },
495 ))
496 })
497 .collect::<Result<Vec<_>>>()?;
498
499 let shell_configs: Vec<ShellSurfaceConfig> = shell_configs_with_handles
500 .iter()
501 .map(|(_, cfg)| cfg.clone())
502 .collect();
503
504 let inner = layer_shika_adapters::WaylandShellSystem::new_multi(&shell_configs)?;
505 let inner_rc: Rc<RefCell<dyn WaylandSystemOps>> = Rc::new(RefCell::new(inner));
506
507 let (sender, receiver) = channel::channel();
508
509 let mut registry = SurfaceRegistry::new();
510 for ((handle, _), definition) in shell_configs_with_handles.iter().zip(definitions.iter()) {
511 let entry =
512 SurfaceEntry::new(*handle, definition.component.clone(), definition.clone());
513 registry.insert(entry)?;
514 }
515
516 let shell = Self {
517 inner: Rc::clone(&inner_rc),
518 registry,
519 compilation_result,
520 command_sender: sender,
521 output_connected_handlers: Rc::new(RefCell::new(Vec::new())),
522 output_disconnected_handlers: Rc::new(RefCell::new(Vec::new())),
523 };
524
525 shell.setup_command_handler(receiver)?;
526
527 log::info!(
528 "Shell created (multi-surface mode) with surfaces: {:?}",
529 shell.surface_names()
530 );
531
532 Ok(shell)
533 }
534
535 fn new_minimal(compilation_result: Rc<CompilationResult>) -> Result<Self> {
536 let inner = layer_shika_adapters::WaylandShellSystem::new_minimal()?;
537 let inner_rc: Rc<RefCell<dyn WaylandSystemOps>> = Rc::new(RefCell::new(inner));
538
539 inner_rc
540 .borrow_mut()
541 .set_compilation_result(Rc::clone(&compilation_result));
542
543 let (sender, receiver) = channel::channel();
544
545 let registry = SurfaceRegistry::new();
546
547 let shell = Self {
548 inner: Rc::clone(&inner_rc),
549 registry,
550 compilation_result,
551 command_sender: sender,
552 output_connected_handlers: Rc::new(RefCell::new(Vec::new())),
553 output_disconnected_handlers: Rc::new(RefCell::new(Vec::new())),
554 };
555
556 shell.setup_command_handler(receiver)?;
557
558 log::info!("Shell created (minimal mode - no layer surfaces)");
559
560 Ok(shell)
561 }
562
563 fn setup_command_handler(&self, receiver: channel::Channel<ShellCommand>) -> Result<()> {
564 let loop_handle = self.inner.borrow().event_loop_handle();
565 let control = self.control();
566 let system = Rc::downgrade(&self.inner);
567
568 loop_handle
569 .insert_source(receiver, move |event, (), app_state| {
570 if let channel::Event::Msg(command) = event {
571 let mut ctx = crate::system::EventDispatchContext::from_app_state(app_state);
572
573 match command {
574 ShellCommand::Popup(popup_cmd) => {
575 Self::handle_popup_command(popup_cmd, &mut ctx, &control);
576 }
577 ShellCommand::Surface(surface_cmd) => {
578 Self::handle_surface_command(surface_cmd, &mut ctx);
579 }
580 ShellCommand::SessionLock(lock_cmd) => {
581 Self::handle_session_lock_command(&lock_cmd, &mut ctx, &system);
582 }
583 ShellCommand::Render => {
584 if let Err(e) = ctx.render_frame_if_dirty() {
585 log::error!("Failed to render frame: {}", e);
586 }
587 }
588 }
589 }
590 })
591 .map_err(|e| {
592 Error::Adapter(
593 EventLoopError::InsertSource {
594 message: format!("Failed to setup command handler: {e:?}"),
595 }
596 .into(),
597 )
598 })?;
599
600 Ok(())
601 }
602
603 fn handle_popup_command(
604 command: PopupCommand,
605 ctx: &mut EventDispatchContext<'_>,
606 _control: &ShellControl,
607 ) {
608 match command {
609 PopupCommand::Show { handle, config } => {
610 if let Err(e) = ctx.show_popup(handle, &config) {
611 log::error!("Failed to show popup: {}", e);
612 }
613 }
614 PopupCommand::Close(handle) => {
615 if let Err(e) = ctx.close_popup(handle) {
616 log::error!("Failed to close popup: {}", e);
617 }
618 }
619 PopupCommand::Resize {
620 handle,
621 width,
622 height,
623 } => {
624 if let Err(e) = ctx.resize_popup(handle, width, height) {
625 log::error!("Failed to resize popup: {}", e);
626 }
627 }
628 }
629 }
630
631 fn handle_session_lock_command(
632 command: &SessionLockCommand,
633 ctx: &mut EventDispatchContext<'_>,
634 _system: &Weak<RefCell<dyn WaylandSystemOps>>,
635 ) {
636 match command {
637 SessionLockCommand::Activate {
638 component_name,
639 config,
640 } => {
641 log::info!("Processing SessionLockCommand::Activate");
642 if let Err(e) = ctx.activate_session_lock(component_name, config.clone()) {
643 log::error!("Failed to activate session lock: {}", e);
644 } else {
645 log::info!("Session lock activated successfully");
646 }
647 }
648 SessionLockCommand::Deactivate => {
649 log::info!("Processing SessionLockCommand::Deactivate");
650 if let Err(e) = ctx.deactivate_session_lock() {
651 log::error!("Failed to deactivate session lock: {}", e);
652 } else {
653 log::info!("Session lock deactivated successfully");
654 }
655 }
656 }
657 }
658
659 fn resolve_surface_target<'a>(
660 ctx: &'a mut EventDispatchContext<'_>,
661 target: &SurfaceTarget,
662 ) -> Vec<&'a mut SurfaceState> {
663 match target {
664 SurfaceTarget::ByInstance(id) => {
665 if let Some(surface) = ctx.surface_by_instance_mut(id.surface(), id.output()) {
666 vec![surface]
667 } else {
668 log::warn!(
669 "Surface instance not found: handle {:?} on output {:?}",
670 id.surface(),
671 id.output()
672 );
673 vec![]
674 }
675 }
676 SurfaceTarget::ByHandle(handle) => ctx.surfaces_by_handle_mut(*handle),
677 SurfaceTarget::ByName(name) => ctx.surfaces_by_name_mut(name),
678 SurfaceTarget::ByNameAndOutput { name, output } => {
679 ctx.surfaces_by_name_and_output_mut(name, *output)
680 }
681 }
682 }
683
684 fn apply_surface_resize(
685 ctx: &mut EventDispatchContext<'_>,
686 target: &SurfaceTarget,
687 width: u32,
688 height: u32,
689 ) {
690 log::debug!(
691 "Surface command: Resize {:?} to {}x{}",
692 target,
693 width,
694 height
695 );
696 for surface in Self::resolve_surface_target(ctx, target) {
697 let handle = LayerSurfaceHandle::from_window_state(surface);
698 handle.set_size(width, height);
699 handle.commit();
700 surface.update_size_with_compositor_logic(width, height);
701 }
702 }
703
704 fn apply_surface_config_change<F>(
705 ctx: &mut EventDispatchContext<'_>,
706 target: &SurfaceTarget,
707 operation: &str,
708 apply: F,
709 ) where
710 F: Fn(&LayerSurfaceHandle<'_>),
711 {
712 log::debug!("Surface command: {} {:?}", operation, target);
713 for surface in Self::resolve_surface_target(ctx, target) {
714 let handle = LayerSurfaceHandle::from_window_state(surface);
715 apply(&handle);
716 handle.commit();
717 }
718 }
719
720 fn apply_full_config(
721 ctx: &mut EventDispatchContext<'_>,
722 target: &SurfaceTarget,
723 config: &SurfaceConfig,
724 ) {
725 log::debug!("Surface command: ApplyConfig {:?}", target);
726
727 if let Err(e) = config.validate() {
728 log::error!("Invalid surface configuration: {}", e);
729 return;
730 }
731
732 for surface in Self::resolve_surface_target(ctx, target) {
733 let handle = LayerSurfaceHandle::from_window_state(surface);
734
735 handle.set_size(config.dimensions.width(), config.dimensions.height());
736 handle.set_anchor_edges(config.anchor);
737 handle.set_exclusive_zone(config.exclusive_zone);
738 handle.set_margins(config.margin);
739 handle.set_layer(config.layer);
740 handle.set_keyboard_interactivity(config.keyboard_interactivity);
741 handle.commit();
742
743 surface.update_size_with_compositor_logic(
744 config.dimensions.width(),
745 config.dimensions.height(),
746 );
747 }
748 }
749
750 fn handle_surface_command(command: SurfaceCommand, ctx: &mut EventDispatchContext<'_>) {
751 match command {
752 SurfaceCommand::Resize {
753 target,
754 width,
755 height,
756 } => {
757 Self::apply_surface_resize(ctx, &target, width, height);
758 }
759 SurfaceCommand::SetAnchor { target, anchor } => {
760 Self::apply_surface_config_change(ctx, &target, "SetAnchor", |handle| {
761 handle.set_anchor_edges(anchor);
762 });
763 }
764 SurfaceCommand::SetExclusiveZone { target, zone } => {
765 Self::apply_surface_config_change(ctx, &target, "SetExclusiveZone", |handle| {
766 handle.set_exclusive_zone(zone);
767 });
768 }
769 SurfaceCommand::SetMargins { target, margins } => {
770 Self::apply_surface_config_change(ctx, &target, "SetMargins", |handle| {
771 handle.set_margins(margins);
772 });
773 }
774 SurfaceCommand::SetLayer { target, layer } => {
775 Self::apply_surface_config_change(ctx, &target, "SetLayer", |handle| {
776 handle.set_layer(layer);
777 });
778 }
779 SurfaceCommand::SetKeyboardInteractivity { target, mode } => {
780 Self::apply_surface_config_change(
781 ctx,
782 &target,
783 "SetKeyboardInteractivity",
784 |handle| {
785 handle.set_keyboard_interactivity(mode);
786 },
787 );
788 }
789 SurfaceCommand::SetOutputPolicy { target, policy } => {
790 log::debug!(
791 "Surface command: SetOutputPolicy {:?} to {:?}",
792 target,
793 policy
794 );
795 log::warn!(
796 "SetOutputPolicy is not yet implemented - requires runtime surface spawning"
797 );
798 }
799 SurfaceCommand::SetScaleFactor { target, factor } => {
800 log::debug!(
801 "Surface command: SetScaleFactor {:?} to {:?}",
802 target,
803 factor
804 );
805 log::warn!(
806 "SetScaleFactor is not yet implemented - requires runtime surface property updates"
807 );
808 }
809 SurfaceCommand::ApplyConfig { target, config } => {
810 Self::apply_full_config(ctx, &target, &config);
811 }
812 }
813
814 if let Err(e) = ctx.render_frame_if_dirty() {
815 log::error!("Failed to render frame after surface command: {}", e);
816 }
817 }
818
819 #[must_use]
821 pub fn control(&self) -> ShellControl {
822 ShellControl::new(self.command_sender.clone())
823 }
824
825 #[must_use]
827 pub fn popups(&self) -> crate::PopupShell {
828 self.control().popups()
829 }
830
831 pub fn create_session_lock(&self, component: impl Into<String>) -> Result<SessionLock> {
832 self.create_session_lock_with_config(SessionLockBuilder::new(component))
833 }
834
835 pub fn create_session_lock_with_config(
836 &self,
837 builder: SessionLockBuilder,
838 ) -> Result<SessionLock> {
839 let component = builder.component_name().to_string();
840 if self.compilation_result.component(&component).is_none() {
841 return Err(Error::Domain(DomainError::ComponentNotFound {
842 name: component,
843 }));
844 }
845
846 if !self.inner.borrow().is_session_lock_available() {
847 return Err(Error::ProtocolNotAvailable {
848 protocol: "ext-session-lock-v1".to_string(),
849 });
850 }
851
852 Ok(builder.build(Rc::downgrade(&self.inner), self.command_sender.clone()))
853 }
854
855 pub fn surface_names(&self) -> Vec<&str> {
857 self.registry.surface_names()
858 }
859
860 pub fn has_surface(&self, name: &str) -> bool {
862 self.registry.contains_name(name)
863 }
864
865 pub fn event_loop_handle(&self) -> EventLoopHandle {
867 EventLoopHandle::new(Rc::downgrade(&self.inner))
868 }
869
870 pub fn run(&mut self) -> Result<()> {
872 log::info!(
873 "Starting Shell event loop with {} windows",
874 self.registry.len()
875 );
876 self.inner.borrow_mut().run()?;
877 Ok(())
878 }
879
880 pub fn spawn_surface(&mut self, definition: SurfaceDefinition) -> Result<Vec<SurfaceHandle>> {
884 let component_definition = self
885 .compilation_result
886 .component(&definition.component)
887 .ok_or_else(|| {
888 Error::Domain(DomainError::ComponentNotFound {
889 name: definition.component.clone(),
890 })
891 })?;
892
893 let handle = SurfaceHandle::new();
894 let wayland_config = WaylandSurfaceConfig::from_domain_config(
895 handle,
896 &definition.component,
897 component_definition,
898 Some(Rc::clone(&self.compilation_result)),
899 definition.config.clone(),
900 );
901
902 let shell_config = ShellSurfaceConfig {
903 name: definition.component.clone(),
904 config: wayland_config,
905 };
906
907 let mut system = self.inner.borrow_mut();
908 let handles = system.spawn_surface(&shell_config)?;
909
910 let surface_handle = SurfaceHandle::new();
911 let entry = SurfaceEntry::new(surface_handle, definition.component.clone(), definition);
912 self.registry.insert(entry)?;
913
914 log::info!(
915 "Spawned surface with handle {:?}, created {} output instances",
916 surface_handle,
917 handles.len()
918 );
919
920 Ok(vec![surface_handle])
921 }
922
923 pub fn despawn_surface(&mut self, handle: SurfaceHandle) -> Result<()> {
925 let entry = self.registry.remove(handle).ok_or_else(|| {
926 Error::Domain(DomainError::SurfaceNotFound {
927 message: format!("Surface handle {:?} not found", handle),
928 })
929 })?;
930
931 let mut system = self.inner.borrow_mut();
932 system.despawn_surface(&entry.name)?;
933
934 log::info!(
935 "Despawned surface '{}' with handle {:?}",
936 entry.name,
937 handle
938 );
939
940 Ok(())
941 }
942
943 pub fn on_output_connected<F>(&mut self, handler: F) -> Result<()>
947 where
948 F: Fn(&OutputInfo) + 'static,
949 {
950 self.output_connected_handlers
951 .borrow_mut()
952 .push(Box::new(handler));
953 Ok(())
954 }
955
956 pub fn on_output_disconnected<F>(&mut self, handler: F) -> Result<()>
958 where
959 F: Fn(OutputHandle) + 'static,
960 {
961 self.output_disconnected_handlers
962 .borrow_mut()
963 .push(Box::new(handler));
964 Ok(())
965 }
966
967 pub fn get_surface_handle(&self, name: &str) -> Option<SurfaceHandle> {
969 self.registry.handle_by_name(name)
970 }
971
972 pub fn get_surface_name(&self, handle: SurfaceHandle) -> Option<&str> {
974 self.registry.name_by_handle(handle)
975 }
976
977 pub fn with_surface<F, R>(&self, name: &str, f: F) -> Result<R>
979 where
980 F: FnOnce(&ComponentInstance) -> R,
981 {
982 if !self.registry.contains_name(name) {
983 return Err(Error::Domain(DomainError::SurfaceNotFound {
984 message: format!("Window '{}' not found", name),
985 }));
986 }
987
988 let system = self.inner.borrow();
989
990 system
991 .app_state()
992 .surfaces_by_name(name)
993 .first()
994 .map(|surface| f(surface.component_instance()))
995 .ok_or_else(|| {
996 Error::Domain(DomainError::SurfaceNotFound {
997 message: format!("No instance found for window '{}'", name),
998 })
999 })
1000 }
1001
1002 pub fn with_all_surfaces<F>(&self, mut f: F)
1004 where
1005 F: FnMut(&str, &ComponentInstance),
1006 {
1007 let system = self.inner.borrow();
1008
1009 for name in self.registry.surface_names() {
1010 for surface in system.app_state().surfaces_by_name(name) {
1011 f(name, surface.component_instance());
1012 }
1013 }
1014 }
1015
1016 pub fn with_output<F, R>(&self, handle: OutputHandle, f: F) -> Result<R>
1018 where
1019 F: FnOnce(&ComponentInstance) -> R,
1020 {
1021 let system = self.inner.borrow();
1022 let window = system
1023 .app_state()
1024 .get_output_by_handle(handle)
1025 .ok_or_else(|| {
1026 Error::Domain(DomainError::OutputNotFound {
1027 message: format!("Output with handle {:?} not found", handle),
1028 })
1029 })?;
1030 Ok(f(window.component_instance()))
1031 }
1032
1033 pub fn with_all_outputs<F>(&self, mut f: F)
1035 where
1036 F: FnMut(OutputHandle, &ComponentInstance),
1037 {
1038 let system = self.inner.borrow();
1039 for (handle, surface) in system.app_state().outputs_with_handles() {
1040 f(handle, surface.component_instance());
1041 }
1042 }
1043
1044 #[must_use]
1046 pub fn compilation_result(&self) -> &Rc<CompilationResult> {
1047 &self.compilation_result
1048 }
1049
1050 pub fn output_registry(&self) -> OutputRegistry {
1052 let system = self.inner.borrow();
1053 system.app_state().output_registry().clone()
1054 }
1055
1056 pub fn get_output_info(&self, handle: OutputHandle) -> Option<OutputInfo> {
1058 let system = self.inner.borrow();
1059 system.app_state().get_output_info(handle).cloned()
1060 }
1061
1062 pub fn all_output_info(&self) -> Vec<OutputInfo> {
1064 let system = self.inner.borrow();
1065 system.app_state().all_output_info().cloned().collect()
1066 }
1067
1068 pub fn select(&self, selector: impl Into<crate::Selector>) -> crate::Selection<'_> {
1070 crate::Selection::new(self, selector.into())
1071 }
1072
1073 fn get_output_handles(&self) -> (Option<OutputHandle>, Option<OutputHandle>) {
1074 let registry = &self.output_registry();
1075 (registry.primary_handle(), registry.active_handle())
1076 }
1077
1078 pub(crate) fn on_internal<F, R>(
1079 &self,
1080 selector: &crate::Selector,
1081 callback_name: &str,
1082 handler: F,
1083 ) where
1084 F: Fn(CallbackContext) -> R + Clone + 'static,
1085 R: IntoValue,
1086 {
1087 let control = self.control();
1088 let handler = Rc::new(handler);
1089 let system = self.inner.borrow();
1090 let (primary, active) = self.get_output_handles();
1091
1092 for (key, surface) in system.app_state().surfaces_with_keys() {
1093 let surface_handle = key.surface_handle;
1094 let output_handle = key.output_handle;
1095
1096 let surface_name = self.registry.by_handle(surface_handle).map_or_else(
1097 || format!("Unknown-{}", surface_handle.id()),
1098 |entry| entry.name.clone(),
1099 );
1100
1101 let surface_info = crate::SurfaceInfo {
1102 name: surface_name.clone(),
1103 output: output_handle,
1104 instance_id: SurfaceInstanceId::new(surface_handle, output_handle),
1105 };
1106
1107 let output_info = system.app_state().get_output_info(output_handle);
1108
1109 if selector.matches(&surface_info, output_info, primary, active) {
1110 let instance_id = SurfaceInstanceId::new(surface_handle, output_handle);
1111
1112 let handler_rc = Rc::clone(&handler);
1113 let control_clone = control.clone();
1114 let surface_name_clone = surface_name.clone();
1115
1116 if let Err(e) =
1117 surface
1118 .component_instance()
1119 .set_callback(callback_name, move |_args| {
1120 let ctx = CallbackContext::new(
1121 instance_id,
1122 surface_name_clone.clone(),
1123 control_clone.clone(),
1124 );
1125 handler_rc(ctx).into_value()
1126 })
1127 {
1128 log::error!(
1129 "Failed to register callback '{}' on surface '{}': {}",
1130 callback_name,
1131 surface_name,
1132 e
1133 );
1134 }
1135 }
1136 }
1137 }
1138
1139 pub(crate) fn on_with_args_internal<F, R>(
1140 &self,
1141 selector: &crate::Selector,
1142 callback_name: &str,
1143 handler: F,
1144 ) where
1145 F: Fn(&[Value], CallbackContext) -> R + Clone + 'static,
1146 R: IntoValue,
1147 {
1148 let control = self.control();
1149 let handler = Rc::new(handler);
1150 let system = self.inner.borrow();
1151 let (primary, active) = self.get_output_handles();
1152
1153 for (key, surface) in system.app_state().surfaces_with_keys() {
1154 let surface_handle = key.surface_handle;
1155 let output_handle = key.output_handle;
1156
1157 let surface_name = self.registry.by_handle(surface_handle).map_or_else(
1158 || format!("Unknown-{}", surface_handle.id()),
1159 |entry| entry.name.clone(),
1160 );
1161
1162 let surface_info = crate::SurfaceInfo {
1163 name: surface_name.clone(),
1164 output: output_handle,
1165 instance_id: SurfaceInstanceId::new(surface_handle, output_handle),
1166 };
1167
1168 let output_info = system.app_state().get_output_info(output_handle);
1169
1170 if selector.matches(&surface_info, output_info, primary, active) {
1171 let instance_id = SurfaceInstanceId::new(surface_handle, output_handle);
1172
1173 let handler_rc = Rc::clone(&handler);
1174 let control_clone = control.clone();
1175 let surface_name_clone = surface_name.clone();
1176
1177 if let Err(e) =
1178 surface
1179 .component_instance()
1180 .set_callback(callback_name, move |args| {
1181 let ctx = CallbackContext::new(
1182 instance_id,
1183 surface_name_clone.clone(),
1184 control_clone.clone(),
1185 );
1186 handler_rc(args, ctx).into_value()
1187 })
1188 {
1189 log::error!(
1190 "Failed to register callback '{}' on surface '{}': {}",
1191 callback_name,
1192 surface_name,
1193 e
1194 );
1195 }
1196 }
1197 }
1198 }
1199
1200 pub(crate) fn with_selected<F>(&self, selector: &crate::Selector, mut f: F)
1201 where
1202 F: FnMut(&str, &ComponentInstance),
1203 {
1204 let system = self.inner.borrow();
1205 let (primary, active) = self.get_output_handles();
1206
1207 for (key, surface) in system.app_state().surfaces_with_keys() {
1208 let surface_name = system
1209 .app_state()
1210 .get_surface_name(key.surface_handle)
1211 .unwrap_or("unknown");
1212 let surface_info = crate::SurfaceInfo {
1213 name: surface_name.to_string(),
1214 output: key.output_handle,
1215 instance_id: crate::SurfaceInstanceId::new(key.surface_handle, key.output_handle),
1216 };
1217
1218 let output_info = system.app_state().get_output_info(key.output_handle);
1219
1220 if selector.matches(&surface_info, output_info, primary, active) {
1221 f(surface_name, surface.component_instance());
1222 }
1223 }
1224 }
1225
1226 pub(crate) fn with_selected_info<F>(&self, selector: &crate::Selector, mut f: F)
1227 where
1228 F: FnMut(&crate::SurfaceInfo, &ComponentInstance),
1229 {
1230 let system = self.inner.borrow();
1231 let (primary, active) = self.get_output_handles();
1232
1233 for (key, surface) in system.app_state().surfaces_with_keys() {
1234 let surface_name = system
1235 .app_state()
1236 .get_surface_name(key.surface_handle)
1237 .unwrap_or("unknown");
1238 let surface_info = crate::SurfaceInfo {
1239 name: surface_name.to_string(),
1240 output: key.output_handle,
1241 instance_id: crate::SurfaceInstanceId::new(key.surface_handle, key.output_handle),
1242 };
1243
1244 let output_info = system.app_state().get_output_info(key.output_handle);
1245
1246 if selector.matches(&surface_info, output_info, primary, active) {
1247 f(&surface_info, surface.component_instance());
1248 }
1249 }
1250 }
1251
1252 pub(crate) fn configure_selected<F>(&self, selector: &crate::Selector, mut f: F)
1253 where
1254 F: FnMut(&ComponentInstance, LayerSurfaceHandle<'_>),
1255 {
1256 let system = self.inner.borrow();
1257 let (primary, active) = self.get_output_handles();
1258
1259 for (key, surface) in system.app_state().surfaces_with_keys() {
1260 let surface_name = system
1261 .app_state()
1262 .get_surface_name(key.surface_handle)
1263 .unwrap_or("unknown");
1264 let surface_info = crate::SurfaceInfo {
1265 name: surface_name.to_string(),
1266 output: key.output_handle,
1267 instance_id: crate::SurfaceInstanceId::new(key.surface_handle, key.output_handle),
1268 };
1269
1270 let output_info = system.app_state().get_output_info(key.output_handle);
1271
1272 if selector.matches(&surface_info, output_info, primary, active) {
1273 let surface_handle = LayerSurfaceHandle::from_window_state(surface);
1274 f(surface.component_instance(), surface_handle);
1275 }
1276 }
1277 }
1278
1279 pub(crate) fn count_selected(&self, selector: &crate::Selector) -> usize {
1280 let system = self.inner.borrow();
1281 let (primary, active) = self.get_output_handles();
1282
1283 system
1284 .app_state()
1285 .surfaces_with_keys()
1286 .filter(|(key, _)| {
1287 let surface_name = system
1288 .app_state()
1289 .get_surface_name(key.surface_handle)
1290 .unwrap_or("unknown");
1291 let surface_info = crate::SurfaceInfo {
1292 name: surface_name.to_string(),
1293 output: key.output_handle,
1294 instance_id: crate::SurfaceInstanceId::new(
1295 key.surface_handle,
1296 key.output_handle,
1297 ),
1298 };
1299
1300 let output_info = system.app_state().get_output_info(key.output_handle);
1301
1302 selector.matches(&surface_info, output_info, primary, active)
1303 })
1304 .count()
1305 }
1306
1307 pub(crate) fn get_selected_info(&self, selector: &crate::Selector) -> Vec<crate::SurfaceInfo> {
1308 let system = self.inner.borrow();
1309 let (primary, active) = self.get_output_handles();
1310
1311 system
1312 .app_state()
1313 .surfaces_with_keys()
1314 .filter_map(|(key, _)| {
1315 let surface_name = system
1316 .app_state()
1317 .get_surface_name(key.surface_handle)
1318 .unwrap_or("unknown");
1319 let surface_info = crate::SurfaceInfo {
1320 name: surface_name.to_string(),
1321 output: key.output_handle,
1322 instance_id: crate::SurfaceInstanceId::new(
1323 key.surface_handle,
1324 key.output_handle,
1325 ),
1326 };
1327
1328 let output_info = system.app_state().get_output_info(key.output_handle);
1329
1330 if selector.matches(&surface_info, output_info, primary, active) {
1331 Some(surface_info)
1332 } else {
1333 None
1334 }
1335 })
1336 .collect()
1337 }
1338
1339 pub fn select_lock(&self, selector: impl Into<crate::Selector>) -> crate::LockSelection<'_> {
1341 crate::LockSelection::new(self, selector.into())
1342 }
1343
1344 fn selector_to_output_filter(selector: &crate::Selector) -> layer_shika_adapters::OutputFilter {
1345 let selector = selector.clone();
1346
1347 Rc::new(
1348 move |component_name: &str,
1349 output_handle: OutputHandle,
1350 output_info: Option<&OutputInfo>,
1351 primary_handle: Option<OutputHandle>,
1352 active_handle: Option<OutputHandle>| {
1353 let surface_info = crate::SurfaceInfo {
1354 name: component_name.to_string(),
1355 output: output_handle,
1356 instance_id: crate::SurfaceInstanceId::new(
1357 crate::SurfaceHandle::from_raw(0),
1358 output_handle,
1359 ),
1360 };
1361
1362 selector.matches(&surface_info, output_info, primary_handle, active_handle)
1363 },
1364 )
1365 }
1366
1367 pub(crate) fn on_lock_internal<F, R>(
1368 &self,
1369 selector: &crate::Selector,
1370 callback_name: &str,
1371 handler: F,
1372 ) where
1373 F: Fn(CallbackContext) -> R + Clone + 'static,
1374 R: IntoValue,
1375 {
1376 let control = self.control();
1377 let handler = Rc::new(handler);
1378 let callback_name = callback_name.to_string();
1379
1380 let callback_handler = Rc::new(move |_args: &[Value]| {
1381 let handler_rc = Rc::clone(&handler);
1382 let control_clone = control.clone();
1383 let instance_id =
1384 SurfaceInstanceId::new(SurfaceHandle::from_raw(0), OutputHandle::from_raw(0));
1385 let ctx = CallbackContext::new(instance_id, String::new(), control_clone);
1386 handler_rc(ctx).into_value()
1387 });
1388
1389 let filter = Self::selector_to_output_filter(selector);
1390 self.inner
1391 .borrow_mut()
1392 .register_session_lock_callback_with_filter(&callback_name, callback_handler, filter);
1393 }
1394
1395 pub(crate) fn on_lock_with_args_internal<F, R>(
1396 &self,
1397 selector: &crate::Selector,
1398 callback_name: &str,
1399 handler: F,
1400 ) where
1401 F: Fn(&[Value], CallbackContext) -> R + Clone + 'static,
1402 R: IntoValue,
1403 {
1404 let control = self.control();
1405 let handler = Rc::new(handler);
1406 let callback_name = callback_name.to_string();
1407
1408 let callback_handler = Rc::new(move |args: &[Value]| {
1409 let handler_rc = Rc::clone(&handler);
1410 let control_clone = control.clone();
1411 let instance_id =
1412 SurfaceInstanceId::new(SurfaceHandle::from_raw(0), OutputHandle::from_raw(0));
1413 let ctx = CallbackContext::new(instance_id, String::new(), control_clone);
1414 handler_rc(args, ctx).into_value()
1415 });
1416
1417 let filter = Self::selector_to_output_filter(selector);
1418 self.inner
1419 .borrow_mut()
1420 .register_session_lock_callback_with_filter(&callback_name, callback_handler, filter);
1421 }
1422
1423 pub(crate) fn register_lock_property_internal(
1424 &self,
1425 selector: &crate::Selector,
1426 property_name: &str,
1427 value: Value,
1428 ) {
1429 use layer_shika_adapters::create_lock_property_operation_with_output_filter;
1430
1431 let filter = Self::selector_to_output_filter(selector);
1432 let property_operation = create_lock_property_operation_with_output_filter(
1433 property_name,
1434 value,
1435 move |component_name, output_handle, output_info, primary, active| {
1436 filter(component_name, output_handle, output_info, primary, active)
1437 },
1438 );
1439 self.inner
1440 .borrow_mut()
1441 .register_session_lock_property_operation(property_operation);
1442 }
1443
1444 pub(crate) fn with_selected_lock<F>(&self, selector: &crate::Selector, mut f: F)
1445 where
1446 F: FnMut(&str, &ComponentInstance),
1447 {
1448 let system = self.inner.borrow();
1449 let (primary, active) = self.get_output_handles();
1450
1451 let Some(component_name) = system.session_lock_component_name() else {
1452 return;
1453 };
1454
1455 system.iter_lock_surfaces(&mut |output_handle, component| {
1456 let surface_info = crate::SurfaceInfo {
1457 name: component_name.clone(),
1458 output: output_handle,
1459 instance_id: crate::SurfaceInstanceId::new(
1460 crate::SurfaceHandle::from_raw(0),
1461 output_handle,
1462 ),
1463 };
1464
1465 let output_info = system.app_state().get_output_info(output_handle);
1466
1467 if selector.matches(&surface_info, output_info, primary, active) {
1468 f(&component_name, component);
1469 }
1470 });
1471 }
1472
1473 pub(crate) fn count_selected_lock(&self, selector: &crate::Selector) -> usize {
1474 let system = self.inner.borrow();
1475 let (primary, active) = self.get_output_handles();
1476
1477 let Some(component_name) = system.session_lock_component_name() else {
1478 return 0;
1479 };
1480
1481 let mut count = 0;
1482 system.iter_lock_surfaces(&mut |output_handle, _component| {
1483 let surface_info = crate::SurfaceInfo {
1484 name: component_name.clone(),
1485 output: output_handle,
1486 instance_id: crate::SurfaceInstanceId::new(
1487 crate::SurfaceHandle::from_raw(0),
1488 output_handle,
1489 ),
1490 };
1491
1492 let output_info = system.app_state().get_output_info(output_handle);
1493
1494 if selector.matches(&surface_info, output_info, primary, active) {
1495 count += 1;
1496 }
1497 });
1498 count
1499 }
1500
1501 pub(crate) fn get_selected_lock_info(
1502 &self,
1503 selector: &crate::Selector,
1504 ) -> Vec<crate::SurfaceInfo> {
1505 let system = self.inner.borrow();
1506 let (primary, active) = self.get_output_handles();
1507
1508 let Some(component_name) = system.session_lock_component_name() else {
1509 return Vec::new();
1510 };
1511
1512 let mut info_vec = Vec::new();
1513 system.iter_lock_surfaces(&mut |output_handle, _component| {
1514 let surface_info = crate::SurfaceInfo {
1515 name: component_name.clone(),
1516 output: output_handle,
1517 instance_id: crate::SurfaceInstanceId::new(
1518 crate::SurfaceHandle::from_raw(0),
1519 output_handle,
1520 ),
1521 };
1522
1523 let output_info = system.app_state().get_output_info(output_handle);
1524
1525 if selector.matches(&surface_info, output_info, primary, active) {
1526 info_vec.push(surface_info);
1527 }
1528 });
1529 info_vec
1530 }
1531}
1532
1533impl ShellRuntime for Shell {
1534 type LoopHandle = EventLoopHandle;
1535 type Context<'a> = ShellEventContext<'a>;
1536
1537 fn event_loop_handle(&self) -> Self::LoopHandle {
1538 EventLoopHandle::new(Rc::downgrade(&self.inner))
1539 }
1540
1541 fn with_component<F>(&self, name: &str, mut f: F)
1542 where
1543 F: FnMut(&ComponentInstance),
1544 {
1545 let system = self.inner.borrow();
1546
1547 if self.registry.contains_name(name) {
1548 for surface in system.app_state().surfaces_by_name(name) {
1549 f(surface.component_instance());
1550 }
1551 }
1552 }
1553
1554 fn with_all_components<F>(&self, mut f: F)
1555 where
1556 F: FnMut(&str, &ComponentInstance),
1557 {
1558 let system = self.inner.borrow();
1559
1560 for name in self.registry.surface_names() {
1561 for surface in system.app_state().surfaces_by_name(name) {
1562 f(name, surface.component_instance());
1563 }
1564 }
1565 }
1566
1567 fn run(&mut self) -> Result<()> {
1568 self.inner.borrow_mut().run()?;
1569 Ok(())
1570 }
1571}
1572
1573pub struct ShellEventContext<'a> {
1577 app_state: &'a mut AppState,
1578}
1579
1580impl<'a> FromAppState<'a> for ShellEventContext<'a> {
1581 fn from_app_state(app_state: &'a mut AppState) -> Self {
1582 Self { app_state }
1583 }
1584}
1585
1586impl ShellEventContext<'_> {
1587 pub fn get_surface_component(&self, name: &str) -> Option<&ComponentInstance> {
1589 self.app_state
1590 .surfaces_by_name(name)
1591 .first()
1592 .map(|s| s.component_instance())
1593 }
1594
1595 pub fn all_surface_components(&self) -> impl Iterator<Item = &ComponentInstance> {
1597 self.app_state
1598 .all_outputs()
1599 .map(SurfaceState::component_instance)
1600 }
1601
1602 pub fn render_frame_if_dirty(&mut self) -> Result<()> {
1604 for surface in self.app_state.all_outputs() {
1605 surface.render_frame_if_dirty()?;
1606 }
1607 Ok(())
1608 }
1609
1610 #[must_use]
1612 pub fn primary_output_handle(&self) -> Option<OutputHandle> {
1613 self.app_state.primary_output_handle()
1614 }
1615
1616 #[must_use]
1618 pub fn active_output_handle(&self) -> Option<OutputHandle> {
1619 self.app_state.active_output_handle()
1620 }
1621
1622 pub fn output_registry(&self) -> &OutputRegistry {
1624 self.app_state.output_registry()
1625 }
1626
1627 pub fn outputs(&self) -> impl Iterator<Item = (OutputHandle, &ComponentInstance)> {
1629 self.app_state
1630 .outputs_with_handles()
1631 .map(|(handle, surface)| (handle, surface.component_instance()))
1632 }
1633
1634 pub fn get_output_component(&self, handle: OutputHandle) -> Option<&ComponentInstance> {
1636 self.app_state
1637 .get_output_by_handle(handle)
1638 .map(SurfaceState::component_instance)
1639 }
1640
1641 pub fn get_output_info(&self, handle: OutputHandle) -> Option<&OutputInfo> {
1643 self.app_state.get_output_info(handle)
1644 }
1645
1646 pub fn all_output_info(&self) -> impl Iterator<Item = &OutputInfo> {
1648 self.app_state.all_output_info()
1649 }
1650
1651 pub fn outputs_with_info(&self) -> impl Iterator<Item = (&OutputInfo, &ComponentInstance)> {
1653 self.app_state
1654 .outputs_with_info()
1655 .map(|(info, surface)| (info, surface.component_instance()))
1656 }
1657
1658 #[must_use]
1660 pub fn compilation_result(&self) -> Option<Rc<CompilationResult>> {
1661 self.app_state
1662 .primary_output()
1663 .and_then(SurfaceState::compilation_result)
1664 }
1665}