Skip to main content

cranpose_app_shell/
surface.rs

1//! Root surfaces: what the shell keeps per window.
2//!
3//! The composition is one tree. Each window the app shows is a root in that
4//! tree: the composition root for the primary window, a node carrying
5//! `Modifier::window_root` for every other. A [`RootSurface`] is the shell's
6//! bookkeeping for one such root: the renderer that draws it, the viewport it
7//! draws into, the pointer that hovers it, the gesture it tracks, the
8//! snapshots a test or a platform reads for it, and the dirt that says whether
9//! it owes the display a frame. A [`SurfaceMut`] borrows one surface together
10//! with the app, which is how a platform delivers a window's events and reads
11//! a window's frame.
12
13use std::{cell::RefCell, fmt::Debug, rc::Rc};
14
15use cranpose_core::{NodeId, collections::map::HashSet};
16use cranpose_foundation::{PointerButtons, PointerSource, RotaryScrollEvent};
17use cranpose_render_common::Renderer;
18use cranpose_ui::{
19    LayoutTree, PlatformTextInputHandler, SemanticsTree, pointer_icon_session::PointerIconState,
20};
21use cranpose_ui_graphics::{Point, PointerIcon, Size};
22use web_time::Instant;
23
24use crate::{
25    AppShell, DevOverlayControl, FramePacingMode, FrameRatePreference, FrameSchedule,
26    FrameScheduler, FrameUpdateResult, PlatformFrameDriver, ShellApp,
27    hit_path_tracker::{HitPathTracker, PointerId},
28};
29
30/// Names a root surface of the app: the primary window, or a window root
31/// declared with [`Modifier::window_root`](cranpose_ui::Modifier::window_root)
32/// by the id given there.
33#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
34pub enum RootId {
35    /// The composition root, drawn in the app's first window.
36    Primary,
37    /// The node carrying `Modifier::window_root` with this id.
38    Window(u64),
39}
40
41/// The shell's bookkeeping for one root.
42///
43/// The primary surface draws the composition root. A window surface draws the
44/// window root node registered under its id, and draws nothing while that
45/// node is not in the tree. Everything here is what an OS owns per window:
46/// the framebuffer, the viewport, the pointer, the cursor image, the soft
47/// keyboard, the frame the window is asked for.
48pub struct RootSurface<R: Renderer> {
49    pub(crate) id: RootId,
50    pub(crate) root: Option<NodeId>,
51    pub(crate) renderer: R,
52    pub(crate) cursor: (f32, f32),
53    pub(crate) viewport: (f32, f32),
54    pub(crate) buffer_size: (u32, u32),
55    pub(crate) layout_tree: Option<LayoutTree>,
56    pub(crate) semantics_tree: Option<SemanticsTree>,
57    /// A layout pass ran since `semantics_tree` was brought up to date, so
58    /// its bounds may be out of date though no node marked its semantics.
59    semantics_moved: bool,
60    pub(crate) modal_focus: Vec<(NodeId, Option<NodeId>)>,
61    pub(crate) frame_rate_preference: FrameRatePreference,
62    pub(crate) scene_dirty: bool,
63    pub(crate) scoped_layout_scene_nodes: Vec<NodeId>,
64    pub(crate) retained_visual_nodes: HashSet<NodeId>,
65    pub(crate) is_dirty: bool,
66    pub(crate) buttons_pressed: PointerButtons,
67    pub(crate) pointer_source: PointerSource,
68    pub(crate) hit_path_tracker: HitPathTracker,
69    pub(crate) hovered_nodes: Vec<NodeId>,
70    pub(crate) on_rotary_scroll: Option<Rc<dyn Fn(RotaryScrollEvent) -> bool>>,
71    pub(crate) dev_overlay_controls: Vec<DevOverlayControl>,
72    pub(crate) inspector: crate::inspector::DeveloperInspector,
73    pub(crate) dev_overlay_text: String,
74    pub(crate) dev_overlay_last_refresh: Option<Instant>,
75    pub(crate) dev_overlay_viewport: Option<Size>,
76    pub(crate) frame_scheduler: FrameScheduler,
77    pub(crate) pointer_icon: PointerIconState,
78    pub(crate) last_update: FrameUpdateResult,
79    pub(crate) frame_owed: bool,
80    pub(crate) screen_origin: Option<Point>,
81}
82
83impl<R: Renderer> RootSurface<R> {
84    pub(crate) fn new(
85        id: RootId,
86        renderer: R,
87        buffer_size: (u32, u32),
88        viewport: (f32, f32),
89    ) -> Self {
90        Self {
91            id,
92            root: None,
93            renderer,
94            cursor: (0.0, 0.0),
95            viewport,
96            buffer_size,
97            layout_tree: None,
98            semantics_tree: None,
99            semantics_moved: false,
100            modal_focus: Vec::new(),
101            frame_rate_preference: FrameRatePreference::default(),
102            scene_dirty: true,
103            scoped_layout_scene_nodes: Vec::new(),
104            retained_visual_nodes: HashSet::default(),
105            is_dirty: true,
106            buttons_pressed: PointerButtons::NONE,
107            pointer_source: PointerSource::Unknown,
108            hit_path_tracker: HitPathTracker::new(),
109            hovered_nodes: Vec::new(),
110            on_rotary_scroll: None,
111            dev_overlay_controls: Vec::new(),
112            inspector: crate::inspector::DeveloperInspector::default(),
113            dev_overlay_text: String::new(),
114            dev_overlay_last_refresh: None,
115            dev_overlay_viewport: None,
116            frame_scheduler: FrameScheduler::default(),
117            pointer_icon: PointerIconState::new(),
118            last_update: FrameUpdateResult::default(),
119            frame_owed: false,
120            screen_origin: None,
121        }
122    }
123
124    pub(crate) fn root_node(&self, app: &ShellApp) -> Option<NodeId> {
125        match self.id {
126            RootId::Primary => app.composition.root(),
127            RootId::Window(_) => self.root,
128        }
129    }
130
131    pub(crate) fn owns_nodes_under(&self, window_root: Option<NodeId>) -> bool {
132        match self.id {
133            RootId::Primary => window_root.is_none(),
134            RootId::Window(_) => self.root.is_some() && self.root == window_root,
135        }
136    }
137
138    pub(crate) fn viewport_size(&self) -> Size {
139        Size {
140            width: self.viewport.0,
141            height: self.viewport.1,
142        }
143    }
144
145    pub(crate) fn screen_point_inside(&self, screen: Point) -> Option<Point> {
146        let origin = self.screen_origin?;
147        let local = Point {
148            x: screen.x - origin.x,
149            y: screen.y - origin.y,
150        };
151        (local.x >= 0.0
152            && local.y >= 0.0
153            && local.x <= self.viewport.0
154            && local.y <= self.viewport.1)
155            .then_some(local)
156    }
157
158    pub(crate) fn set_root(&mut self, root: Option<NodeId>) {
159        if self.root == root {
160            return;
161        }
162        self.root = root;
163        self.forget_snapshots();
164        self.invalidate_scene_root(root);
165        self.retained_visual_nodes.clear();
166        self.hit_path_tracker.clear();
167        self.hovered_nodes.clear();
168        self.buttons_pressed = PointerButtons::NONE;
169        self.is_dirty = true;
170    }
171
172    pub(crate) fn invalidate_scene_root(&mut self, root: Option<NodeId>) {
173        self.scoped_layout_scene_nodes.clear();
174        self.scoped_layout_scene_nodes.extend(root);
175        self.scene_dirty = true;
176    }
177
178    /// Drops the layout snapshot and marks the semantics tree for an update,
179    /// which keeps what did not change.
180    pub(crate) fn forget_snapshots(&mut self) {
181        self.layout_tree = None;
182        self.semantics_moved = true;
183    }
184
185    pub(crate) fn has_active_pointer_gesture(&self) -> bool {
186        self.buttons_pressed != PointerButtons::NONE
187            && self.hit_path_tracker.has_path(PointerId::PRIMARY)
188    }
189
190    pub(crate) fn renderer_warmup_due(&self, app: &ShellApp) -> bool {
191        self.renderer.needs_frame_warmup() && !app.runtime.runtime_handle().has_frame_callbacks()
192    }
193
194    pub(crate) fn needs_redraw_in_context(&self, app: &ShellApp) -> bool {
195        app.has_stale_work_in_context()
196            || app.composition.should_recompose()
197            || self.is_dirty
198            || self.scene_dirty
199            || self.renderer_warmup_due(app)
200    }
201
202    pub(crate) fn compute_frame_schedule(
203        &self,
204        app: &ShellApp,
205        surfaces_dirty: bool,
206    ) -> FrameSchedule {
207        let app_context = Rc::clone(&app.app_context);
208        let (needs_update, needs_frame) = app_context.enter(|| {
209            let needs_frame = self.is_dirty
210                || self.scene_dirty
211                || app.wants_frame_in_context()
212                || self.has_active_pointer_gesture()
213                || self.renderer_warmup_due(app);
214            (app.needs_ui_update_in_context(surfaces_dirty), needs_frame)
215        });
216        FrameSchedule {
217            needs_update,
218            needs_frame,
219            next_deadline: app.next_event_time(),
220        }
221    }
222
223    pub(crate) fn invalidate_dev_overlay_text(&mut self) {
224        self.dev_overlay_text.clear();
225        self.dev_overlay_last_refresh = None;
226        self.dev_overlay_viewport = None;
227    }
228
229    pub(crate) fn dev_overlay_control_center(&self, mode: FramePacingMode) -> Option<(f32, f32)> {
230        self.dev_overlay_controls
231            .iter()
232            .find(|control| control.mode == mode)
233            .map(|control| {
234                (
235                    control.bounds.x + control.bounds.width * 0.5,
236                    control.bounds.y + control.bounds.height * 0.5,
237                )
238            })
239    }
240
241    pub(crate) fn layout_tree_in_context(&mut self, app: &mut ShellApp) -> Option<&LayoutTree> {
242        if self.layout_tree.is_none() {
243            let root = self.root_node(app)?;
244            let mut applier = app.composition.applier_mut();
245            match cranpose_ui::build_layout_tree_from_applier(&mut applier, root) {
246                Ok(layout_tree) => {
247                    self.layout_tree = layout_tree;
248                }
249                Err(err) => {
250                    log::debug!("failed to build layout snapshot: {err}");
251                    return None;
252                }
253            }
254        }
255        self.layout_tree.as_ref()
256    }
257
258    /// The node an open modal takes this surface over with, the root its
259    /// semantics tree would have, found without building the tree.
260    pub(crate) fn top_modal(&self, app: &mut ShellApp) -> Option<NodeId> {
261        let root = self.root_node(app)?;
262        let mut applier = app.composition.applier_mut();
263        cranpose_ui::top_modal_from_applier(&mut applier, root).unwrap_or_else(|err| {
264            log::debug!("failed to find the top modal under root #{root}: {err}");
265            None
266        })
267    }
268
269    pub(crate) fn semantics_tree_in_context(
270        &mut self,
271        app: &mut ShellApp,
272    ) -> Option<&SemanticsTree> {
273        if !app.semantics_enabled && !self.inspector.state.open {
274            return None;
275        }
276        self.semantics_tree_for_input(app)
277    }
278
279    pub(crate) fn semantics_tree_for_input(
280        &mut self,
281        app: &mut ShellApp,
282    ) -> Option<&SemanticsTree> {
283        app.flush_semantics_invalidations();
284        let root = self.root_node(app)?;
285        let semantics_dirty = {
286            let mut applier = app.composition.applier_mut();
287            cranpose_ui::tree_needs_semantics(&mut *applier, root).unwrap_or_else(|err| {
288                log::debug!("failed to check semantics dirty status for root #{root}: {err}");
289                true
290            })
291        };
292        if self.semantics_tree.is_none() || self.semantics_moved || semantics_dirty {
293            let mut applier = app.composition.applier_mut();
294            match cranpose_ui::update_semantics_tree_from_applier(
295                &mut applier,
296                root,
297                &mut self.semantics_tree,
298            ) {
299                Ok(()) => {
300                    #[cfg(debug_assertions)]
301                    crate::semantics_check::assert_matches_rebuild(
302                        &mut applier,
303                        root,
304                        self.semantics_tree.as_ref(),
305                    );
306                    self.semantics_moved = false;
307                    app.semantics_snapshot_revision =
308                        app.semantics_snapshot_revision.wrapping_add(1);
309                }
310                Err(err) => {
311                    log::debug!("failed to build semantics snapshot: {err}");
312                    return None;
313                }
314            }
315        }
316        self.semantics_tree.as_ref()
317    }
318}
319
320#[derive(Default)]
321pub(crate) struct TextInputRoutes {
322    active: Option<RootId>,
323    shown: Option<RootId>,
324    handlers: Vec<(RootId, Rc<dyn PlatformTextInputHandler>)>,
325}
326
327impl TextInputRoutes {
328    pub(crate) fn active(&self) -> RootId {
329        self.active.unwrap_or(RootId::Primary)
330    }
331
332    pub(crate) fn set_active(&mut self, root: RootId) {
333        self.active = Some(root);
334    }
335
336    pub(crate) fn set_handler(&mut self, root: RootId, handler: Rc<dyn PlatformTextInputHandler>) {
337        self.remove(root);
338        self.handlers.push((root, handler));
339    }
340
341    pub(crate) fn remove(&mut self, root: RootId) {
342        self.handlers.retain(|(id, _)| *id != root);
343        if self.shown == Some(root) {
344            self.shown = None;
345        }
346    }
347
348    fn handler(&self, root: RootId) -> Option<Rc<dyn PlatformTextInputHandler>> {
349        self.handlers
350            .iter()
351            .find(|(id, _)| *id == root)
352            .map(|(_, handler)| Rc::clone(handler))
353    }
354
355    fn take_show_target(&mut self) -> Option<Rc<dyn PlatformTextInputHandler>> {
356        let active = self.active();
357        let handler = self.handler(active);
358        if handler.is_some() {
359            self.shown = Some(active);
360        }
361        handler
362    }
363
364    fn take_hide_target(&mut self) -> Option<Rc<dyn PlatformTextInputHandler>> {
365        let target = self.shown.take().unwrap_or_else(|| self.active());
366        self.handler(target)
367    }
368}
369
370pub(crate) struct TextInputRouter {
371    pub(crate) routes: Rc<RefCell<TextInputRoutes>>,
372}
373
374impl PlatformTextInputHandler for TextInputRouter {
375    fn show_keyboard(&self) {
376        let handler = self.routes.borrow_mut().take_show_target();
377        if let Some(handler) = handler {
378            handler.show_keyboard();
379        }
380    }
381
382    fn hide_keyboard(&self) {
383        let handler = self.routes.borrow_mut().take_hide_target();
384        if let Some(handler) = handler {
385            handler.hide_keyboard();
386        }
387    }
388}
389
390pub(crate) fn partition_nodes_by_surface<R: Renderer>(
391    app: &mut ShellApp,
392    surfaces: &[RootSurface<R>],
393    nodes: Vec<NodeId>,
394) -> Vec<Vec<NodeId>> {
395    let mut buckets: Vec<Vec<NodeId>> = surfaces.iter().map(|_| Vec::new()).collect();
396    let Some(primary_root) = app.composition.root() else {
397        return buckets;
398    };
399    let mut applier = app.composition.applier_mut();
400    let attached: Vec<NodeId> = applier
401        .scene_nodes_attached_to(nodes, primary_root)
402        .into_iter()
403        .flatten()
404        .collect();
405    let owners = cranpose_ui::nearest_window_roots(&mut applier, &attached);
406    for (node, owner) in attached.into_iter().zip(owners) {
407        if let Some(index) = surfaces
408            .iter()
409            .position(|surface| surface.owns_nodes_under(owner))
410        {
411            buckets[index].push(node);
412        }
413    }
414    buckets
415}
416
417/// One surface borrowed together with its shell: the handle a platform
418/// delivers a window's events through and reads a window's frame from.
419///
420/// [`AppShell::surface`] hands one out per root. Every method of [`AppShell`]
421/// that names no root acts on the primary surface through the same code, so
422/// a single-window platform never sees this type.
423pub struct SurfaceMut<'a, R: Renderer> {
424    pub(crate) shell: &'a mut AppShell<R>,
425    pub(crate) index: usize,
426}
427
428impl<'a, R> SurfaceMut<'a, R>
429where
430    R: Renderer,
431    R::Error: Debug,
432{
433    pub(crate) fn new(shell: &'a mut AppShell<R>, index: usize) -> Self {
434        Self { shell, index }
435    }
436
437    /// The whole app, for what a window's event needs beyond its surface:
438    /// the clipboard, the dev options, a debug report.
439    pub fn shell(&mut self) -> &mut AppShell<R> {
440        self.shell
441    }
442
443    pub(crate) fn shell_app(&mut self) -> &mut ShellApp {
444        &mut self.shell.app
445    }
446
447    pub(crate) fn shell_app_ref(&self) -> &ShellApp {
448        &self.shell.app
449    }
450
451    pub(crate) fn surface(&self) -> &RootSurface<R> {
452        &self.shell.surfaces[self.index]
453    }
454
455    pub(crate) fn surface_mut(&mut self) -> &mut RootSurface<R> {
456        &mut self.shell.surfaces[self.index]
457    }
458
459    pub(crate) fn parts(&mut self) -> (&mut ShellApp, &mut RootSurface<R>) {
460        let shell = &mut *self.shell;
461        (&mut shell.app, &mut shell.surfaces[self.index])
462    }
463
464    /// Which root this surface draws.
465    pub fn id(&self) -> RootId {
466        self.surface().id
467    }
468
469    /// The node this surface draws from, when it has one.
470    pub fn root(&self) -> Option<NodeId> {
471        let surface = self.surface();
472        surface.root_node(self.shell_app_ref())
473    }
474
475    /// The renderer that draws this surface.
476    pub fn renderer(&mut self) -> &mut R {
477        &mut self.surface_mut().renderer
478    }
479
480    /// Runs a presentation operation with this surface's app context active.
481    /// Software text rasterization uses the context's font measurement services.
482    pub fn with_renderer<T>(&mut self, block: impl FnOnce(&mut R) -> T) -> T {
483        let (app, surface) = self.parts();
484        app.app_context.enter(|| block(&mut surface.renderer))
485    }
486
487    /// The scene this surface last built.
488    pub fn scene(&self) -> &R::Scene {
489        self.surface().renderer.scene()
490    }
491
492    /// Sets the logical size this surface lays out and draws into.
493    ///
494    /// The primary surface's viewport is the composition root's constraints.
495    /// A window surface's viewport is what its renderer draws into; the
496    /// window root lays out to the size its descriptor reports, which the
497    /// platform keeps equal to this. The next update lays out and renders;
498    /// [`AppShell::set_viewport`] additionally runs that frame at once.
499    pub fn set_viewport(&mut self, width: f32, height: f32) {
500        self.surface_mut().viewport = (width, height);
501        match self.id() {
502            RootId::Primary => self.shell_app().request_forced_layout_pass(),
503            RootId::Window(_) => {
504                if let Some(root) = self.root() {
505                    let app_context = Rc::clone(&self.shell_app_ref().app_context);
506                    app_context.enter(|| cranpose_ui::schedule_measure_repass(root));
507                }
508                self.shell_app().request_layout_pass();
509            }
510        }
511        let root = self.root();
512        self.surface_mut().invalidate_scene_root(root);
513        self.mark_dirty();
514    }
515
516    /// Tells the shell where the window drawing this surface sits on the
517    /// screen, in logical pixels, so pointer events can carry a
518    /// [`screen_position`](cranpose_foundation::PointerEvent::screen_position).
519    /// A platform sets it when the window moves and before it delivers a
520    /// pointer sample; `None` says the platform does not know.
521    pub fn set_screen_origin(&mut self, origin: Option<Point>) {
522        self.surface_mut().screen_origin = origin;
523    }
524
525    /// Where the window drawing this surface sits on the screen, as the
526    /// platform last said.
527    pub fn screen_origin(&self) -> Option<Point> {
528        self.surface().screen_origin
529    }
530
531    /// The logical size this surface draws into.
532    pub fn viewport_size(&self) -> (f32, f32) {
533        self.surface().viewport
534    }
535
536    /// Sets the physical size of this surface's framebuffer.
537    pub fn set_buffer_size(&mut self, width: u32, height: u32) {
538        self.surface_mut().buffer_size = (width, height);
539    }
540
541    /// The physical size of this surface's framebuffer.
542    pub fn buffer_size(&self) -> (u32, u32) {
543        self.surface().buffer_size
544    }
545
546    /// Marks this surface as needing a redraw.
547    pub fn mark_dirty(&mut self) {
548        self.surface_mut().is_dirty = true;
549    }
550
551    /// Whether this surface owes the display a frame: stale pixels, or a
552    /// renderer that has not warmed its swapchain yet. See
553    /// [`AppShell::needs_redraw`].
554    pub fn needs_redraw(&self) -> bool {
555        let app_context = Rc::clone(&self.shell_app_ref().app_context);
556        app_context.enter(|| self.surface().needs_redraw_in_context(self.shell_app_ref()))
557    }
558
559    /// Whether a primary-button gesture that started on this surface is
560    /// still in progress.
561    pub fn has_active_pointer_gesture(&self) -> bool {
562        self.surface().has_active_pointer_gesture()
563    }
564
565    /// What the update and frame produced for this surface the last time
566    /// the app updated.
567    pub fn last_update_result(&self) -> FrameUpdateResult {
568        self.surface().last_update
569    }
570
571    /// Whether an update since the platform last presented this surface
572    /// changed its pixels. An update runs for the whole app, so the update a
573    /// platform ran for one window may have drawn another; this is how the
574    /// other window learns it has a frame to show.
575    pub fn frame_owed(&self) -> bool {
576        self.surface().frame_owed
577    }
578
579    /// [`Self::frame_owed`], cleared: the platform is about to present.
580    pub fn take_frame_owed(&mut self) -> bool {
581        std::mem::take(&mut self.surface_mut().frame_owed)
582    }
583
584    fn compute_frame_schedule(&self) -> FrameSchedule {
585        self.surface()
586            .compute_frame_schedule(self.shell_app_ref(), self.shell.any_surface_dirty())
587    }
588
589    /// The frame this surface asks its platform for, recorded for
590    /// [`Self::frame_scheduler_snapshot`].
591    pub fn frame_schedule(&self) -> FrameSchedule {
592        let schedule = self.compute_frame_schedule();
593        self.surface().frame_scheduler.record(schedule);
594        schedule
595    }
596
597    /// Computes this surface's frame schedule and applies it to `driver`.
598    pub fn schedule_platform_frame<D>(&self, driver: &D) -> FrameSchedule
599    where
600        D: PlatformFrameDriver + ?Sized,
601    {
602        let schedule = self.compute_frame_schedule();
603        self.surface().frame_scheduler.schedule(schedule, driver);
604        schedule
605    }
606
607    /// The schedule this surface last recorded.
608    pub fn frame_scheduler_snapshot(&self) -> FrameSchedule {
609        self.surface().frame_scheduler.snapshot()
610    }
611
612    /// Sets how the platform should vote the display's frame rate for the
613    /// window showing this surface. See [`AppShell::set_frame_rate_preference`].
614    pub fn set_frame_rate_preference(&mut self, preference: FrameRatePreference) {
615        self.surface_mut().frame_rate_preference = preference;
616    }
617
618    /// This surface's display frame-rate preference.
619    pub fn frame_rate_preference(&self) -> FrameRatePreference {
620        self.surface().frame_rate_preference
621    }
622
623    /// Where this surface's dev overlay draws the control for `mode`, in
624    /// logical pixels. See [`AppShell::dev_overlay_control_center`].
625    pub fn dev_overlay_control_center(&self, mode: FramePacingMode) -> Option<(f32, f32)> {
626        self.surface().dev_overlay_control_center(mode)
627    }
628
629    pub(crate) fn dev_overlay_press(&mut self, x: f32, y: f32) -> bool {
630        if !self.shell_app_ref().dev_options.frame_pacing_controls {
631            return false;
632        }
633        let Some(mode) = self
634            .surface()
635            .dev_overlay_controls
636            .iter()
637            .find(|control| control.bounds.contains(x, y))
638            .map(|control| control.mode)
639        else {
640            return false;
641        };
642        self.shell().set_frame_pacing_mode(mode);
643        true
644    }
645
646    /// Runs `block` with this surface's layout snapshot, built on demand.
647    pub fn with_layout_tree<T>(&mut self, block: impl FnOnce(Option<&LayoutTree>) -> T) -> T {
648        let (app, surface) = self.parts();
649        let app_context = Rc::clone(&app.app_context);
650        app_context.enter(|| block(surface.layout_tree_in_context(app)))
651    }
652
653    /// Runs `block` with this surface's semantics snapshot, built on demand;
654    /// `None` while semantics are disabled.
655    pub fn with_semantics_tree<T>(&mut self, block: impl FnOnce(Option<&SemanticsTree>) -> T) -> T {
656        let (app, surface) = self.parts();
657        let app_context = Rc::clone(&app.app_context);
658        app_context.enter(|| block(surface.semantics_tree_in_context(app)))
659    }
660
661    /// The pointer icon the platform has not applied to this surface's
662    /// window yet. See [`AppShell::take_pointer_icon_change`].
663    pub fn take_pointer_icon_change(&self) -> Option<PointerIcon> {
664        self.surface().pointer_icon.take_change()
665    }
666
667    /// Offers this surface's pointer icon to the platform again. See
668    /// [`AppShell::refresh_pointer_icon`].
669    pub fn refresh_pointer_icon(&self) {
670        self.surface().pointer_icon.refresh();
671    }
672
673    /// Installs the platform text input for the window showing this
674    /// surface. Keyboard requests reach the handler of the surface the
675    /// platform last called active, and a hide reaches the handler that
676    /// showed. See [`AppShell::set_platform_text_input`].
677    pub fn set_platform_text_input(&mut self, handler: Rc<dyn PlatformTextInputHandler>) {
678        let id = self.id();
679        let app = self.shell_app();
680        app.text_input_routes.borrow_mut().set_handler(id, handler);
681        app.install_text_input_router();
682    }
683
684    /// Makes this the surface the platform considers focused: the one the
685    /// soft keyboard belongs to. Pointer presses do this on their own.
686    pub fn activate(&mut self) {
687        let id = self.id();
688        self.shell_app()
689            .text_input_routes
690            .borrow_mut()
691            .set_active(id);
692    }
693}