1use std::{cell::RefCell, fmt::Debug, rc::Rc};
14
15use cranpose_core::{MemoryApplier, NodeId, collections::map::HashSet};
16use cranpose_foundation::{PointerButtons, PointerSource, RotaryScrollEvent};
17use cranpose_render_common::Renderer;
18use cranpose_ui::{
19 LayoutNode, LayoutTree, MovedSceneNode, PlatformTextInputHandler, SemanticsTree,
20 pointer_icon_session::PointerIconState,
21};
22use cranpose_ui_graphics::{Point, PointerIcon, Size};
23use web_time::Instant;
24
25use crate::{
26 AppShell, DevOverlayControl, FramePacingMode, FrameRatePreference, FrameSchedule,
27 FrameScheduler, FrameUpdateResult, PlatformFrameDriver, ShellApp, SurfaceRoutingScratch,
28 hit_path_tracker::{HitPathTracker, PointerId},
29};
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
35pub enum RootId {
36 Primary,
38 Window(u64),
40}
41
42pub struct RootSurface<R: Renderer> {
50 pub(crate) id: RootId,
51 pub(crate) root: Option<NodeId>,
52 pub(crate) renderer: R,
53 pub(crate) cursor: (f32, f32),
54 pub(crate) viewport: (f32, f32),
55 pub(crate) buffer_size: (u32, u32),
56 pub(crate) layout_tree: Option<LayoutTree>,
57 pub(crate) semantics_tree: Option<SemanticsTree>,
58 semantics_moved: bool,
61 pub(crate) modal_focus: Vec<(NodeId, Option<NodeId>)>,
62 pub(crate) frame_rate_preference: FrameRatePreference,
63 pub(crate) scene_dirty: bool,
64 pub(crate) scoped_layout_scene_nodes: Vec<NodeId>,
65 pub(crate) scoped_moved_scene_nodes: Vec<NodeId>,
67 pub(crate) scoped_draw_nodes: Vec<NodeId>,
68 pub(crate) scoped_layer_property_nodes: Vec<NodeId>,
69 pub(crate) structural_scene_nodes: Vec<NodeId>,
70 pub(crate) partial_scene_nodes: Vec<NodeId>,
71 pub(crate) redraw_walk: Vec<NodeId>,
74 pub(crate) retained_visual_nodes: HashSet<NodeId>,
75 pub(crate) is_dirty: bool,
76 pub(crate) buttons_pressed: PointerButtons,
77 pub(crate) pointer_source: PointerSource,
78 pub(crate) hit_path_tracker: HitPathTracker,
79 pub(crate) hovered_nodes: Vec<NodeId>,
80 pub(crate) on_rotary_scroll: Option<Rc<dyn Fn(RotaryScrollEvent) -> bool>>,
81 pub(crate) dev_overlay_controls: Vec<DevOverlayControl>,
82 pub(crate) inspector: crate::inspector::DeveloperInspector,
83 pub(crate) dev_overlay_text: String,
84 pub(crate) dev_overlay_last_refresh: Option<Instant>,
85 pub(crate) dev_overlay_viewport: Option<Size>,
86 pub(crate) frame_scheduler: FrameScheduler,
87 pub(crate) pointer_icon: PointerIconState,
88 pub(crate) last_update: FrameUpdateResult,
89 pub(crate) frame_owed: bool,
90 pub(crate) screen_origin: Option<Point>,
91}
92
93impl<R: Renderer> RootSurface<R> {
94 pub(crate) fn new(
95 id: RootId,
96 renderer: R,
97 buffer_size: (u32, u32),
98 viewport: (f32, f32),
99 ) -> Self {
100 Self {
101 id,
102 root: None,
103 renderer,
104 cursor: (0.0, 0.0),
105 viewport,
106 buffer_size,
107 layout_tree: None,
108 semantics_tree: None,
109 semantics_moved: false,
110 modal_focus: Vec::new(),
111 frame_rate_preference: FrameRatePreference::default(),
112 scene_dirty: true,
113 scoped_layout_scene_nodes: Vec::new(),
114 scoped_moved_scene_nodes: Vec::new(),
115 scoped_draw_nodes: Vec::new(),
116 scoped_layer_property_nodes: Vec::new(),
117 structural_scene_nodes: Vec::new(),
118 partial_scene_nodes: Vec::new(),
119 redraw_walk: Vec::new(),
120 retained_visual_nodes: HashSet::default(),
121 is_dirty: true,
122 buttons_pressed: PointerButtons::NONE,
123 pointer_source: PointerSource::Unknown,
124 hit_path_tracker: HitPathTracker::new(),
125 hovered_nodes: Vec::new(),
126 on_rotary_scroll: None,
127 dev_overlay_controls: Vec::new(),
128 inspector: crate::inspector::DeveloperInspector::default(),
129 dev_overlay_text: String::new(),
130 dev_overlay_last_refresh: None,
131 dev_overlay_viewport: None,
132 frame_scheduler: FrameScheduler::default(),
133 pointer_icon: PointerIconState::new(),
134 last_update: FrameUpdateResult::default(),
135 frame_owed: false,
136 screen_origin: None,
137 }
138 }
139
140 pub(crate) fn root_node(&self, app: &ShellApp) -> Option<NodeId> {
141 match self.id {
142 RootId::Primary => app.composition.root(),
143 RootId::Window(_) => self.root,
144 }
145 }
146
147 pub(crate) fn owns_nodes_under(&self, window_root: Option<NodeId>) -> bool {
148 match self.id {
149 RootId::Primary => window_root.is_none(),
150 RootId::Window(_) => self.root.is_some() && self.root == window_root,
151 }
152 }
153
154 pub(crate) fn viewport_size(&self) -> Size {
155 Size {
156 width: self.viewport.0,
157 height: self.viewport.1,
158 }
159 }
160
161 pub(crate) fn screen_point_inside(&self, screen: Point) -> Option<Point> {
162 let origin = self.screen_origin?;
163 let local = Point {
164 x: screen.x - origin.x,
165 y: screen.y - origin.y,
166 };
167 (local.x >= 0.0
168 && local.y >= 0.0
169 && local.x <= self.viewport.0
170 && local.y <= self.viewport.1)
171 .then_some(local)
172 }
173
174 pub(crate) fn set_root(&mut self, root: Option<NodeId>) {
175 if self.root == root {
176 return;
177 }
178 self.root = root;
179 self.forget_snapshots();
180 self.invalidate_scene_root(root);
181 self.retained_visual_nodes.clear();
182 self.hit_path_tracker.clear();
183 self.hovered_nodes.clear();
184 self.buttons_pressed = PointerButtons::NONE;
185 self.is_dirty = true;
186 }
187
188 pub(crate) fn invalidate_scene_root(&mut self, root: Option<NodeId>) {
189 self.scoped_layout_scene_nodes.clear();
190 self.scoped_layout_scene_nodes.extend(root);
191 self.scoped_moved_scene_nodes.clear();
192 self.scoped_draw_nodes.clear();
193 self.scoped_layer_property_nodes.clear();
194 self.structural_scene_nodes.clear();
195 self.partial_scene_nodes.clear();
196 self.scene_dirty = true;
197 }
198
199 pub(crate) fn forget_snapshots(&mut self) {
202 self.layout_tree = None;
203 self.semantics_moved = true;
204 }
205
206 pub(crate) fn has_active_pointer_gesture(&self) -> bool {
207 self.buttons_pressed != PointerButtons::NONE
208 && self.hit_path_tracker.has_path(PointerId::PRIMARY)
209 }
210
211 pub(crate) fn renderer_warmup_due(&self, app: &ShellApp) -> bool {
212 self.renderer.needs_frame_warmup() && !app.composition.runtime().has_frame_callbacks()
213 }
214
215 pub(crate) fn needs_redraw_in_context(&self, app: &ShellApp) -> bool {
216 app.has_stale_work_in_context()
217 || app.composition.should_recompose()
218 || self.is_dirty
219 || self.scene_dirty
220 || self.renderer_warmup_due(app)
221 }
222
223 pub(crate) fn compute_frame_schedule(
224 &self,
225 app: &ShellApp,
226 surfaces_dirty: bool,
227 ) -> FrameSchedule {
228 let (needs_update, needs_frame) = app.app_context.enter(|| {
229 let needs_frame = self.is_dirty
230 || self.scene_dirty
231 || app.wants_frame_in_context()
232 || self.has_active_pointer_gesture()
233 || self.renderer_warmup_due(app);
234 (app.needs_ui_update_in_context(surfaces_dirty), needs_frame)
235 });
236 FrameSchedule {
237 needs_update,
238 needs_frame,
239 next_deadline: app.next_event_time(),
240 }
241 }
242
243 pub(crate) fn invalidate_dev_overlay_text(&mut self) {
244 self.dev_overlay_text.clear();
245 self.dev_overlay_last_refresh = None;
246 self.dev_overlay_viewport = None;
247 }
248
249 pub(crate) fn dev_overlay_control_center(&self, mode: FramePacingMode) -> Option<(f32, f32)> {
250 self.dev_overlay_controls
251 .iter()
252 .find(|control| control.mode == mode)
253 .map(|control| {
254 (
255 control.bounds.x + control.bounds.width * 0.5,
256 control.bounds.y + control.bounds.height * 0.5,
257 )
258 })
259 }
260
261 pub(crate) fn layout_tree_in_context(&mut self, app: &mut ShellApp) -> Option<&LayoutTree> {
262 if self.layout_tree.is_none() {
263 let root = self.root_node(app)?;
264 let mut applier = app.composition.applier_mut();
265 match cranpose_ui::build_layout_tree_from_applier(&mut applier, root) {
266 Ok(layout_tree) => {
267 self.layout_tree = layout_tree;
268 }
269 Err(err) => {
270 log::debug!("failed to build layout snapshot: {err}");
271 return None;
272 }
273 }
274 }
275 self.layout_tree.as_ref()
276 }
277
278 pub(crate) fn top_modal(&self, app: &mut ShellApp) -> Option<NodeId> {
281 let root = self.root_node(app)?;
282 let mut applier = app.composition.applier_mut();
283 cranpose_ui::top_modal_from_applier(&mut applier, root).unwrap_or_else(|err| {
284 log::debug!("failed to find the top modal under root #{root}: {err}");
285 None
286 })
287 }
288
289 pub(crate) fn semantics_tree_in_context(
290 &mut self,
291 app: &mut ShellApp,
292 ) -> Option<&SemanticsTree> {
293 if !app.semantics_enabled && !self.inspector.state.open {
294 return None;
295 }
296 self.semantics_tree_for_input(app)
297 }
298
299 pub(crate) fn semantics_tree_for_input(
300 &mut self,
301 app: &mut ShellApp,
302 ) -> Option<&SemanticsTree> {
303 app.flush_semantics_invalidations();
304 let root = self.root_node(app)?;
305 let semantics_dirty = {
306 let mut applier = app.composition.applier_mut();
307 cranpose_ui::tree_needs_semantics(&mut *applier, root).unwrap_or_else(|err| {
308 log::debug!("failed to check semantics dirty status for root #{root}: {err}");
309 true
310 })
311 };
312 if self.semantics_tree.is_none() || self.semantics_moved || semantics_dirty {
313 let mut applier = app.composition.applier_mut();
314 match cranpose_ui::update_semantics_tree_from_applier(
315 &mut applier,
316 root,
317 &mut self.semantics_tree,
318 ) {
319 Ok(()) => {
320 #[cfg(debug_assertions)]
321 crate::semantics_check::assert_matches_rebuild(
322 &mut applier,
323 root,
324 self.semantics_tree.as_ref(),
325 );
326 self.semantics_moved = false;
327 app.semantics_snapshot_revision =
328 app.semantics_snapshot_revision.wrapping_add(1);
329 }
330 Err(err) => {
331 log::debug!("failed to build semantics snapshot: {err}");
332 return None;
333 }
334 }
335 }
336 self.semantics_tree.as_ref()
337 }
338}
339
340#[derive(Default)]
341pub(crate) struct TextInputRoutes {
342 active: Option<RootId>,
343 shown: Option<RootId>,
344 handlers: Vec<(RootId, Rc<dyn PlatformTextInputHandler>)>,
345}
346
347impl TextInputRoutes {
348 pub(crate) fn active(&self) -> RootId {
349 self.active.unwrap_or(RootId::Primary)
350 }
351
352 pub(crate) fn set_active(&mut self, root: RootId) {
353 self.active = Some(root);
354 }
355
356 pub(crate) fn set_handler(&mut self, root: RootId, handler: Rc<dyn PlatformTextInputHandler>) {
357 self.remove(root);
358 self.handlers.push((root, handler));
359 }
360
361 pub(crate) fn remove(&mut self, root: RootId) {
362 self.handlers.retain(|(id, _)| *id != root);
363 if self.shown == Some(root) {
364 self.shown = None;
365 }
366 }
367
368 fn handler(&self, root: RootId) -> Option<Rc<dyn PlatformTextInputHandler>> {
369 self.handlers
370 .iter()
371 .find(|(id, _)| *id == root)
372 .map(|(_, handler)| Rc::clone(handler))
373 }
374
375 fn take_show_target(&mut self) -> Option<Rc<dyn PlatformTextInputHandler>> {
376 let active = self.active();
377 let handler = self.handler(active);
378 if handler.is_some() {
379 self.shown = Some(active);
380 }
381 handler
382 }
383
384 fn take_hide_target(&mut self) -> Option<Rc<dyn PlatformTextInputHandler>> {
385 let target = self.shown.take().unwrap_or_else(|| self.active());
386 self.handler(target)
387 }
388}
389
390pub(crate) struct TextInputRouter {
391 pub(crate) routes: Rc<RefCell<TextInputRoutes>>,
392}
393
394impl PlatformTextInputHandler for TextInputRouter {
395 fn show_keyboard(&self) {
396 let handler = self.routes.borrow_mut().take_show_target();
397 if let Some(handler) = handler {
398 handler.show_keyboard();
399 }
400 }
401
402 fn hide_keyboard(&self) {
403 let handler = self.routes.borrow_mut().take_hide_target();
404 if let Some(handler) = handler {
405 handler.hide_keyboard();
406 }
407 }
408}
409
410#[derive(Clone, Copy)]
411pub(crate) enum SurfaceDirtyLane {
412 Layout,
413 Moved,
414 Draw,
415 LayerProperties,
416 Structural,
417}
418
419fn append_surface_dirty_node(
420 surface: &mut RootSurface<impl Renderer>,
421 surface_index: usize,
422 node: NodeId,
423 lane: SurfaceDirtyLane,
424 seen: &mut HashSet<(usize, NodeId)>,
425) {
426 match lane {
430 SurfaceDirtyLane::Layout => {
431 surface.scene_dirty = true;
432 surface.scoped_layout_scene_nodes.push(node);
433 }
434 SurfaceDirtyLane::Moved => {
435 surface.scene_dirty = true;
436 surface.scoped_moved_scene_nodes.push(node);
437 }
438 SurfaceDirtyLane::Draw => surface.scoped_draw_nodes.push(node),
439 SurfaceDirtyLane::LayerProperties => surface.scoped_layer_property_nodes.push(node),
440 SurfaceDirtyLane::Structural => {
441 if seen.insert((surface_index, node)) {
442 surface.structural_scene_nodes.push(node);
443 }
444 }
445 }
446}
447
448pub(crate) fn route_nodes_by_surface<R: Renderer>(
449 app: &mut ShellApp,
450 surfaces: &mut [RootSurface<R>],
451 nodes: impl IntoIterator<Item = NodeId>,
452 lane: SurfaceDirtyLane,
453 scratch: &mut SurfaceRoutingScratch,
454) {
455 let Some(primary_root) = app.composition.root() else {
456 scratch.attached.clear();
457 scratch.owners.clear();
458 return;
459 };
460 let mut applier = app.composition.applier_mut();
461 applier.scene_nodes_attached_to_into(
462 nodes,
463 primary_root,
464 &mut scratch.attached,
465 &mut scratch.attachment,
466 );
467 if scratch.attached.is_empty() {
468 scratch.owners.clear();
469 return;
470 }
471 scratch.seen.clear();
472 if app.app_context.window_roots().is_empty() {
473 scratch.owners.clear();
474 if let Some(index) = surfaces
475 .iter()
476 .position(|surface| surface.id == RootId::Primary)
477 {
478 let surface = &mut surfaces[index];
479 for node in scratch.attached.iter().flatten().copied() {
480 append_surface_dirty_node(surface, index, node, lane, &mut scratch.seen);
481 }
482 }
483 return;
484 }
485 cranpose_ui::nearest_window_roots_into(
486 &mut applier,
487 scratch.attached.iter().flatten().copied(),
488 &mut scratch.owners,
489 &mut scratch.window_roots,
490 );
491 for (node, owner) in scratch.attached.iter().flatten().zip(&scratch.owners) {
492 let node = *node;
493 if let Some(index) = surfaces
494 .iter()
495 .position(|surface| surface.owns_nodes_under(*owner))
496 {
497 let surface = &mut surfaces[index];
498 append_surface_dirty_node(surface, index, node, lane, &mut scratch.seen);
499 }
500 }
501}
502
503pub(crate) fn route_geometry_scene_nodes<R: Renderer>(
509 app: &mut ShellApp,
510 surfaces: &mut [RootSurface<R>],
511 laid_out: impl IntoIterator<Item = NodeId>,
512 moved: &[MovedSceneNode],
513 scratch: &mut SurfaceRoutingScratch,
514) {
515 if moved.is_empty() {
516 route_nodes_by_surface(app, surfaces, laid_out, SurfaceDirtyLane::Layout, scratch);
517 return;
518 }
519 scratch.laid_out_starts.clear();
520 scratch.laid_out_starts.extend(
521 surfaces
522 .iter()
523 .map(|surface| surface.scoped_layout_scene_nodes.len()),
524 );
525 route_nodes_by_surface(app, surfaces, laid_out, SurfaceDirtyLane::Layout, scratch);
526 let mut routed = std::mem::take(&mut scratch.moved);
527 routed.clear();
528 {
529 let applier = app.composition.applier_mut();
530 scratch.laid_out.reset(&applier);
531 for (surface, &start) in surfaces.iter().zip(&scratch.laid_out_starts) {
532 for &node in &surface.scoped_layout_scene_nodes[start..] {
533 scratch.laid_out.set(&applier, node, 1);
534 }
535 }
536 let marks = &scratch.laid_out;
537 let window_roots = !app.app_context.window_roots().is_empty();
538 let mut last_placer = None;
541 for &moved in moved {
542 let placed_again = moved.placer.is_some_and(|placer| match last_placer {
543 Some((last, laid_out)) if last == placer => laid_out,
544 _ => {
545 let laid_out = marks.get(&applier, placer) != 0;
546 last_placer = Some((placer, laid_out));
547 laid_out
548 }
549 });
550 if !placed_again || window_roots && is_window_root(&applier, moved.node) {
551 routed.push(moved.node);
552 }
553 }
554 }
555 route_nodes_by_surface(
556 app,
557 surfaces,
558 routed.iter().copied(),
559 SurfaceDirtyLane::Moved,
560 scratch,
561 );
562 scratch.moved = routed;
563}
564
565fn is_window_root(applier: &MemoryApplier, node: NodeId) -> bool {
567 applier.get_ref(node).is_ok_and(|node| {
568 let node: &dyn std::any::Any = node;
569 node.downcast_ref::<LayoutNode>()
570 .is_some_and(LayoutNode::is_window_root)
571 })
572}
573
574pub struct SurfaceMut<'a, R: Renderer> {
581 pub(crate) shell: &'a mut AppShell<R>,
582 pub(crate) index: usize,
583}
584
585impl<'a, R> SurfaceMut<'a, R>
586where
587 R: Renderer,
588 R::Error: Debug,
589{
590 pub(crate) fn new(shell: &'a mut AppShell<R>, index: usize) -> Self {
591 Self { shell, index }
592 }
593
594 pub fn shell(&mut self) -> &mut AppShell<R> {
597 self.shell
598 }
599
600 pub(crate) fn shell_app(&mut self) -> &mut ShellApp {
601 &mut self.shell.app
602 }
603
604 pub(crate) fn shell_app_ref(&self) -> &ShellApp {
605 &self.shell.app
606 }
607
608 pub(crate) fn surface(&self) -> &RootSurface<R> {
609 &self.shell.surfaces[self.index]
610 }
611
612 pub(crate) fn surface_mut(&mut self) -> &mut RootSurface<R> {
613 &mut self.shell.surfaces[self.index]
614 }
615
616 pub(crate) fn parts(&mut self) -> (&mut ShellApp, &mut RootSurface<R>) {
617 let shell = &mut *self.shell;
618 (&mut shell.app, &mut shell.surfaces[self.index])
619 }
620
621 pub fn id(&self) -> RootId {
623 self.surface().id
624 }
625
626 pub fn root(&self) -> Option<NodeId> {
628 let surface = self.surface();
629 surface.root_node(self.shell_app_ref())
630 }
631
632 pub fn renderer(&mut self) -> &mut R {
634 &mut self.surface_mut().renderer
635 }
636
637 pub fn with_renderer<T>(&mut self, block: impl FnOnce(&mut R) -> T) -> T {
640 let (app, surface) = self.parts();
641 app.app_context.enter(|| block(&mut surface.renderer))
642 }
643
644 pub fn scene(&self) -> &R::Scene {
646 self.surface().renderer.scene()
647 }
648
649 pub fn set_viewport(&mut self, width: f32, height: f32) {
657 self.surface_mut().viewport = (width, height);
658 match self.id() {
659 RootId::Primary => self.shell_app().request_forced_layout_pass(),
660 RootId::Window(_) => {
661 if let Some(root) = self.root() {
662 self.shell_app_ref()
663 .app_context
664 .enter(|| cranpose_ui::schedule_measure_repass(root));
665 }
666 self.shell_app().request_layout_pass();
667 }
668 }
669 let root = self.root();
670 self.surface_mut().invalidate_scene_root(root);
671 self.mark_dirty();
672 }
673
674 pub fn set_screen_origin(&mut self, origin: Option<Point>) {
680 self.surface_mut().screen_origin = origin;
681 }
682
683 pub fn screen_origin(&self) -> Option<Point> {
686 self.surface().screen_origin
687 }
688
689 pub fn viewport_size(&self) -> (f32, f32) {
691 self.surface().viewport
692 }
693
694 pub fn set_buffer_size(&mut self, width: u32, height: u32) {
696 self.surface_mut().buffer_size = (width, height);
697 }
698
699 pub fn buffer_size(&self) -> (u32, u32) {
701 self.surface().buffer_size
702 }
703
704 pub fn mark_dirty(&mut self) {
706 self.surface_mut().is_dirty = true;
707 }
708
709 pub fn needs_redraw(&self) -> bool {
713 self.shell_app_ref()
714 .app_context
715 .enter(|| self.surface().needs_redraw_in_context(self.shell_app_ref()))
716 }
717
718 pub fn has_active_pointer_gesture(&self) -> bool {
721 self.surface().has_active_pointer_gesture()
722 }
723
724 pub fn last_update_result(&self) -> FrameUpdateResult {
727 self.surface().last_update
728 }
729
730 pub fn frame_owed(&self) -> bool {
735 self.surface().frame_owed
736 }
737
738 pub fn take_frame_owed(&mut self) -> bool {
740 std::mem::take(&mut self.surface_mut().frame_owed)
741 }
742
743 fn compute_frame_schedule(&self) -> FrameSchedule {
744 self.surface()
745 .compute_frame_schedule(self.shell_app_ref(), self.shell.any_surface_dirty())
746 }
747
748 pub fn frame_schedule(&self) -> FrameSchedule {
751 let schedule = self.compute_frame_schedule();
752 self.surface().frame_scheduler.record(schedule);
753 schedule
754 }
755
756 pub fn schedule_platform_frame<D>(&self, driver: &D) -> FrameSchedule
758 where
759 D: PlatformFrameDriver + ?Sized,
760 {
761 let schedule = self.compute_frame_schedule();
762 self.surface().frame_scheduler.schedule(schedule, driver);
763 schedule
764 }
765
766 pub fn frame_scheduler_snapshot(&self) -> FrameSchedule {
768 self.surface().frame_scheduler.snapshot()
769 }
770
771 pub fn set_frame_rate_preference(&mut self, preference: FrameRatePreference) {
774 self.surface_mut().frame_rate_preference = preference;
775 }
776
777 pub fn frame_rate_preference(&self) -> FrameRatePreference {
779 self.surface().frame_rate_preference
780 }
781
782 pub fn dev_overlay_control_center(&self, mode: FramePacingMode) -> Option<(f32, f32)> {
785 self.surface().dev_overlay_control_center(mode)
786 }
787
788 pub(crate) fn dev_overlay_press(&mut self, x: f32, y: f32) -> bool {
789 if !self.shell_app_ref().dev_options.frame_pacing_controls {
790 return false;
791 }
792 let Some(mode) = self
793 .surface()
794 .dev_overlay_controls
795 .iter()
796 .find(|control| control.bounds.contains(x, y))
797 .map(|control| control.mode)
798 else {
799 return false;
800 };
801 self.shell().set_frame_pacing_mode(mode);
802 true
803 }
804
805 pub fn with_layout_tree<T>(&mut self, block: impl FnOnce(Option<&LayoutTree>) -> T) -> T {
807 let (app, surface) = self.parts();
808 let _app_context = app.app_context.enter_scope();
809 block(surface.layout_tree_in_context(app))
810 }
811
812 pub fn with_semantics_tree<T>(&mut self, block: impl FnOnce(Option<&SemanticsTree>) -> T) -> T {
815 let (app, surface) = self.parts();
816 let _app_context = app.app_context.enter_scope();
817 block(surface.semantics_tree_in_context(app))
818 }
819
820 pub fn take_pointer_icon_change(&self) -> Option<PointerIcon> {
823 self.surface().pointer_icon.take_change()
824 }
825
826 pub fn refresh_pointer_icon(&self) {
829 self.surface().pointer_icon.refresh();
830 }
831
832 pub fn set_platform_text_input(&mut self, handler: Rc<dyn PlatformTextInputHandler>) {
837 let id = self.id();
838 let app = self.shell_app();
839 app.text_input_routes.borrow_mut().set_handler(id, handler);
840 app.install_text_input_router();
841 }
842
843 pub fn activate(&mut self) {
846 let id = self.id();
847 self.shell_app()
848 .text_input_routes
849 .borrow_mut()
850 .set_active(id);
851 }
852}