Struct PresenceCtx
pub struct PresenceCtx {
pub here: HashMap<PresenceKey, Vec<UserId>>,
pub pointers: HashMap<PresenceKey, Vec<(UserId, (f32, f32))>>,
pub selections: HashMap<PresenceKey, Vec<(UserId, SelectionRange)>>,
pub carets: HashMap<PresenceKey, Vec<(UserId, usize)>>,
pub remote_cursors: Vec<RemoteCursor>,
pub color_overrides: HashMap<UserId, (u8, u8, u8)>,
pub names: HashMap<UserId, String>,
pub viewport: Cell<Option<Rect>>,
/* private fields */
}Fields§
§here: HashMap<PresenceKey, Vec<UserId>>§pointers: HashMap<PresenceKey, Vec<(UserId, (f32, f32))>>§selections: HashMap<PresenceKey, Vec<(UserId, SelectionRange)>>§carets: HashMap<PresenceKey, Vec<(UserId, usize)>>§remote_cursors: Vec<RemoteCursor>§color_overrides: HashMap<UserId, (u8, u8, u8)>Seeded by the shell from Collaborator::cursor_color; falls
through to user_color via PresenceCtx::color_for when unset.
names: HashMap<UserId, String>Friendly display names per user, seeded from the collab roster
(CollabEvent::Context). A peer with no entry falls back to its raw
id via PresenceCtx::display_name, so a caret chip is never blank.
viewport: Cell<Option<Rect>>Draw-time visibility window in scene-space pixels, for spatial culling.
Cell so containers (Scrollable) can scope-push a tighter inner
viewport without needing &mut PresenceCtx everywhere.
Implementations§
§impl PresenceCtx
impl PresenceCtx
pub fn apply_interaction(
&mut self,
interaction: SemanticInteraction,
) -> Result<bool, InteractionViolation>
pub fn apply_interaction( &mut self, interaction: SemanticInteraction, ) -> Result<bool, InteractionViolation>
Apply one broker-normalized interaction update.
Returns Ok(true) only when visible state advanced. Replays, older
sequences, identity/target substitution within an invocation, and any
update after a terminal edge are ignored. Validation errors remain
explicit so a trust-boundary caller can log the malformed frame.
§Errors
Returns the interaction contract’s validation error when the incoming update is malformed or exceeds its wire bounds.
pub fn observe_interaction(
&mut self,
interaction: SemanticInteraction,
) -> Result<bool, InteractionViolation>
pub fn observe_interaction( &mut self, interaction: SemanticInteraction, ) -> Result<bool, InteractionViolation>
Observe semantic work without claiming its resource belongs to this
rendering surface. The shell People roster uses this after the room
broker has authenticated and routed the event; app canvases continue
to use apply_remote_presence, whose resource-key check prevents an
interaction from painting in unrelated applications.
§Errors
Returns the interaction contract’s validation error when the incoming update is malformed or exceeds its wire bounds.
pub fn prune_interactions(&mut self, now: Instant) -> bool
pub fn prune_interactions(&mut self, now: Instant) -> bool
Remove interactions whose visible dwell has ended. Returns whether a repaint is warranted.
pub fn interactions_for_resource(
&self,
resource_id: &str,
now: Instant,
) -> Vec<&SemanticInteraction>
pub fn interactions_for_resource( &self, resource_id: &str, now: Instant, ) -> Vec<&SemanticInteraction>
Current, non-expired interactions for a resource. App-native renderers use this to project text ranges, cells, objects, rows, and timelines.
pub fn visible_interactions(&self, now: Instant) -> Vec<SemanticInteraction>
pub fn visible_interactions(&self, now: Instant) -> Vec<SemanticInteraction>
All currently visible interactions in deterministic display order. The host uses this read-only view to resolve generic semantic-control anchors against the current accessibility tree before falling back to the activity rail.
pub fn agent_marker_interactions(
&self,
now: Instant,
) -> Vec<SemanticInteraction>
pub fn agent_marker_interactions( &self, now: Instant, ) -> Vec<SemanticInteraction>
The newest visible invocation for each agent. A host may resolve these against its current action loci and paint at most one moving marker per agent; people and older agent invocations retain the ordinary outline.
pub fn visible_interactions_excluding(
&self,
now: Instant,
resolved: &[InvocationId],
) -> Vec<SemanticInteraction>
pub fn visible_interactions_excluding( &self, now: Instant, resolved: &[InvocationId], ) -> Vec<SemanticInteraction>
Visible activity excluding invocations already projected onto exact action loci. This keeps a resolved marker/outline from also appearing as a generic fallback card.
pub fn visible_interactions_for_app(
&self,
app_id: &str,
now: Instant,
) -> Vec<SemanticInteraction>
pub fn visible_interactions_for_app( &self, app_id: &str, now: Instant, ) -> Vec<SemanticInteraction>
Visible semantic work whose authenticated action catalogue names this application as its owner. Missing ownership is intentionally excluded: a compositor must never guess which foreign window may display it.
pub fn has_visible_interactions(&self, now: Instant) -> bool
pub fn has_visible_interactions(&self, now: Instant) -> bool
Whether another frame is needed to retire an active dwell.
pub fn interaction_animation_demand(&self, now: Instant, theme: &Theme) -> bool
pub fn interaction_animation_demand(&self, now: Instant, theme: &Theme) -> bool
Whether an exact marker painted on a previous frame still needs a smooth frame. Long active-action dwell never keeps the renderer awake.
pub fn interaction_next_wake_deadline(&self, now: Instant) -> Option<Instant>
pub fn interaction_next_wake_deadline(&self, now: Instant) -> Option<Instant>
Earliest discrete wake at which visible semantic activity expires.
Motion is intentionally omitted: Self::interaction_animation_demand
drives those short frame sequences.
pub fn draw_agent_action_marker(
&mut self,
paint: &mut PaintCtx<'_>,
interaction: &SemanticInteraction,
locus: Rect,
viewport: Rect,
surface: &str,
now: Instant,
) -> Option<AgentActionMarker>
pub fn draw_agent_action_marker( &mut self, paint: &mut PaintCtx<'_>, interaction: &SemanticInteraction, locus: Rect, viewport: Rect, surface: &str, now: Instant, ) -> Option<AgentActionMarker>
Paint a cursor-shaped collaboration marker moving toward one exact, current action locus. This is visual narration only: it does not write pointer, focus, caret, selection, hover, or input state.
Returns None for people, expired/stale invocations, invalid geometry,
or an older invocation when the same agent has newer visible work.
pub fn interaction_announcement(
&self,
interaction: &SemanticInteraction,
) -> Option<String>
pub fn interaction_announcement( &self, interaction: &SemanticInteraction, ) -> Option<String>
Concise live-region copy for a semantic action phase. Locating is
intentionally silent: it is often immediately followed by Applying,
and narrating both turns a fast action into accessibility chatter.
pub fn interaction_status_label(
&self,
interaction: &SemanticInteraction,
) -> String
pub fn interaction_status_label( &self, interaction: &SemanticInteraction, ) -> String
An exact-locus label keeps the lifecycle visible when the generic rail is suppressed. Failure must not look like a successful pointer action.
pub fn interaction_card_layout(
&self,
viewport: Rect,
now: Instant,
) -> Vec<InteractionCardPlacement>
pub fn interaction_card_layout( &self, viewport: Rect, now: Instant, ) -> Vec<InteractionCardPlacement>
Lay out the generic app-level fallback without overlap. At most three rows are shown; excess activity is summarized on the last row.
pub fn interaction_card_layout_excluding(
&self,
viewport: Rect,
now: Instant,
resolved: &[InvocationId],
) -> Vec<InteractionCardPlacement>
pub fn interaction_card_layout_excluding( &self, viewport: Rect, now: Instant, resolved: &[InvocationId], ) -> Vec<InteractionCardPlacement>
Lay out fallback cards without duplicating invocations whose exact action locus the host has resolved for this frame.
pub fn draw_interactions_excluding(
&self,
scene: &mut Scene,
transform: Affine,
viewport: Rect,
text_renderer: &mut TextRenderer,
theme: &Theme,
now: Instant,
resolved: &[InvocationId],
)
pub fn draw_interactions_excluding( &self, scene: &mut Scene, transform: Affine, viewport: Rect, text_renderer: &mut TextRenderer, theme: &Theme, now: Instant, resolved: &[InvocationId], )
Draw generic activity only for work not already projected onto an exact locus in this frame.
pub fn draw_interactions_for_app(
&self,
scene: &mut Scene,
transform: Affine,
viewport: Rect,
text_renderer: &mut TextRenderer,
theme: &Theme,
now: Instant,
app_id: &str,
)
pub fn draw_interactions_for_app( &self, scene: &mut Scene, transform: Affine, viewport: Rect, text_renderer: &mut TextRenderer, theme: &Theme, now: Instant, app_id: &str, )
Draw the generic rail only for semantic work explicitly owned by one application. Compositors use this for foreign surfaces: an external client gets collaboration by default, while activity from a different app can never be painted over its pixels.
§impl PresenceCtx
impl PresenceCtx
pub fn widget_presence(&self, now: Instant) -> WidgetPresence
pub fn widget_presence(&self, now: Instant) -> WidgetPresence
What widgets may paint from at now; see WidgetPresence.
§impl PresenceCtx
impl PresenceCtx
pub fn draw_peer_caret(
&self,
scene: &mut Scene,
theme: &Theme,
transform: Affine,
user: &UserId,
rect: Rect,
)
pub fn draw_peer_caret( &self, scene: &mut Scene, theme: &Theme, transform: Affine, user: &UserId, rect: Rect, )
Paint a peer’s caret in their colour. rect is the widget’s own
caret geometry (TextInput::caret_rect / RichTextLine::caret_rect),
so a peer caret is pixel-identical to the local one.
pub fn draw_peer_selection( &self, scene: &mut Scene, theme: &Theme, transform: Affine, user: &UserId, rect: Rect, )
Draw an authorship “marker”: translucent underlay in the author’s colour behind the runs they wrote, at lower alpha than a selection.
Not presence-fed — authorship must survive both peers closing the
doc, so it’s an Automerge mark (local_author /
RichTextLine::author_runs). Silently a no-op if
set_local_author was never called — looks exactly like a network
fault. Set by apps/notes/apps/chat; tilo-doc has no per-run author
field yet.
pub fn draw_peer_pointer(
&self,
scene: &mut Scene,
theme: &Theme,
transform: Affine,
user: &UserId,
pos: (f32, f32),
)
pub fn draw_peer_pointer( &self, scene: &mut Scene, theme: &Theme, transform: Affine, user: &UserId, pos: (f32, f32), )
kurbo::Affine composition below is plain f64 matrix math with no
panic path; arithmetic_side_effects flags the * operator
overload anyway.
pub fn draw_peer_mist(
&self,
scene: &mut Scene,
theme: &Theme,
user: &UserId,
rect: Rect,
)
pub fn draw_peer_mist( &self, scene: &mut Scene, theme: &Theme, user: &UserId, rect: Rect, )
Draw a soft “indicative mist” glow over rect in the peer’s colour —
wayfinding to where a peer currently is. Two translucent fills
approximate a radial glow without an actual gradient.
pub fn draw_peer_caret_labeled(
&self,
scene: &mut Scene,
theme: &Theme,
text_renderer: &mut TextRenderer,
transform: Affine,
user: &UserId,
name: &str,
caret_rect: Rect,
)
pub fn draw_peer_caret_labeled( &self, scene: &mut Scene, theme: &Theme, text_renderer: &mut TextRenderer, transform: Affine, user: &UserId, name: &str, caret_rect: Rect, )
Draw a peer’s caret with a name chip above the tip — mirrors the pointer’s pill (same size/shadow) so caret and pointer read as one person.
pub fn draw_peer_outline(
&self,
scene: &mut Scene,
theme: &Theme,
transform: Affine,
user: &UserId,
rect: Rect,
radius: f64,
)
pub fn draw_peer_outline( &self, scene: &mut Scene, theme: &Theme, transform: Affine, user: &UserId, rect: Rect, radius: f64, )
Outline rect in the peer’s colour — “this peer has this object
selected”. The counterpart to Self::draw_peer_selection for
content that is an object rather than a run of text: a clip on a
timeline, a file in a grid, a shape on a canvas.
A wash plus a ring rather than either alone. The wash on its own is too easily read as the app’s own hover state; the ring on its own disappears against a busy fill — and a peer’s selection is the one thing that has to stay legible over whatever the object is showing. Both are the peer’s colour, the same colour their pointer and caret carry, so the three read as one person.
rect is in the caller’s local coordinates and transform maps it
into scene space, so the outline is drawn from the very geometry the
object itself was drawn from — never a re-derived approximation.
pub fn draw_peer_outline_labeled(
&self,
ctx: &mut PaintCtx<'_>,
user: &UserId,
name: &str,
rect: Rect,
radius: f64,
)
pub fn draw_peer_outline_labeled( &self, ctx: &mut PaintCtx<'_>, user: &UserId, name: &str, rect: Rect, radius: f64, )
Self::draw_peer_outline with the peer’s name chipped above the
object’s top-left corner, so a selection says who without needing
a hover or a roster lookup. Mirrors
Self::draw_peer_caret_labeled — one chip design for every “this
is where that person is” affordance.
pub fn draw_peer_outline_labeled_within(
&self,
ctx: &mut PaintCtx<'_>,
user: &UserId,
name: &str,
rect: Rect,
radius: f64,
bounds: Rect,
)
pub fn draw_peer_outline_labeled_within( &self, ctx: &mut PaintCtx<'_>, user: &UserId, name: &str, rect: Rect, radius: f64, bounds: Rect, )
Self::draw_peer_outline_labeled for a surface that clips its own
contents.
A name chip normally hangs above the thing it names. On the top row of
a clipped area there is nothing above to hang it in, so the chip is cut
in half by the clip — which is how a collaborator ends up labelled with
the bottom two pixels of their name. When bounds leaves no room above,
the chip drops inside the object’s top edge instead.
Inside, it goes to the right, because an object that carries a
label of its own puts it top-left: a chip there turns a clip named
Logo_Bug.png into one named Ada_Bug.png. On an object too narrow to
hold both, the chip stays within the object rather than escaping it —
covering a name is recoverable, pointing at the wrong clip is not.
pub fn draw_peer_typing(
&self,
scene: &mut Scene,
theme: &Theme,
user: &UserId,
spans: &[(Rect, f32)],
)
pub fn draw_peer_typing( &self, scene: &mut Scene, theme: &Theme, user: &UserId, spans: &[(Rect, f32)], )
Draw a peer’s fading “just typed” highlighter behind the glyph runs
they inserted. spans pairs each rect with its fade alpha.
§Must be painted BEFORE the text, not after
Painted over glyphs this drags ink and paper toward the same pigment:
measured, a fresh mark over text leaves 2.4:1 (unmarked ~15:1, below
WCAG AA); beneath the glyphs the same band leaves 7.5:1. Composite
strength is identical either way, so getting the order right is
free. Held by text_stays_legible_under_a_marker_in_both_palettes.
pub fn draw_peer_focus( &self, scene: &mut Scene, theme: &Theme, user: &UserId, rect: Rect, )
§impl PresenceCtx
impl PresenceCtx
pub fn should_cull(&self, rect: Rect) -> bool
pub fn should_cull(&self, rect: Rect) -> bool
True when the supplied rect falls entirely outside the active
viewport, so a widget can skip its draw. Off-viewport widgets MUST
NOT clear their dirty flag, or mark_drawn (which only visits
widgets whose draw ran) leaves them stuck dirty when scrolled back in.
pub fn push_viewport(&self, vp: Rect) -> Option<Rect>
pub fn push_viewport(&self, vp: Rect) -> Option<Rect>
Replace the active viewport, returning the previous value so the caller can restore it.
pub fn pop_viewport(&self, prev: Option<Rect>)
pub fn with_permissions<R>(
&self,
permissions: PermissionContext,
draw: impl FnOnce() -> R,
) -> R
pub fn with_permissions<R>( &self, permissions: PermissionContext, draw: impl FnOnce() -> R, ) -> R
Draw with permissions as the authority gated widgets check, then
restore the outer one.
pub fn permits(&self, scope: &PermissionScope) -> bool
pub fn permits(&self, scope: &PermissionScope) -> bool
Whether the authority of the subtree being drawn covers scope.
Outside any Self::with_permissions everything is allowed.
pub fn permission_context(&self) -> Option<PermissionContext>
pub fn permission_context(&self) -> Option<PermissionContext>
The authority of the subtree being drawn, if anyone scoped one.
§impl PresenceCtx
impl PresenceCtx
pub fn empty() -> PresenceCtx
pub fn set_own_identity<I, S>(&mut self, ids: I)
pub fn set_own_identity<I, S>(&mut self, ids: I)
Declare the identities a frame this session published comes back stamped with, so its own presence is never painted as somebody else’s.
Discriminator is the participant, not the process or app: two windows
of one app are one person, but an agent editing the same document
joins under its own identity and stays a peer. Blank entries are
dropped — an unset forwarded env var produces "", and taking it
literally would make every unnamed participant “me”.
pub fn add_own_identity(&mut self, id: impl AsRef<str>) -> bool
pub fn add_own_identity(&mut self, id: impl AsRef<str>) -> bool
Add one more spelling of “me” without disturbing the others —
Self::set_own_identity replaces its whole set instead. Returns
whether anything was new. Blank is ignored, as in set_own_identity.
pub fn set_surface_id(&mut self, surface: impl Into<String>)
pub fn set_surface_id(&mut self, surface: impl Into<String>)
Set from crate::local_surface_id — the same value the publishing
side scopes its pointer with, so the two spellings cannot drift.
pub fn pointer_owner_for(&self, key: &PresenceKey) -> PointerOwner
pub fn pointer_owner_for(&self, key: &PresenceKey) -> PointerOwner
A pointer is in exactly one space, so a frame fanned to every app in a room still has at most one willing to draw it.
pub fn set_self_participant(&mut self, id: UserId, name: impl Into<String>)
pub fn set_self_participant(&mut self, id: UserId, name: impl Into<String>)
Fed only from the is_self row of CollabEvent::Context — a
machine cannot mint this for itself. Blank id is dropped, as in
set_own_identity.
pub fn self_id(&self) -> Option<&UserId>
pub fn self_id(&self) -> Option<&UserId>
Which participant in the room this session is, if the room has said.
pub fn self_name(&self) -> Option<&str>
pub fn self_name(&self) -> Option<&str>
What the room calls this session’s own participant. None for a
participant the room knows only as an address.
pub fn is_own_identity(&self, user_id: &str) -> bool
pub fn is_own_identity(&self, user_id: &str) -> bool
Whether user_id is this session’s own participant. Checks
self_participant before the declared list (which
Self::set_own_identity replaces wholesale), and also matches the
room’s name for this session — a locally-sent frame is stamped
Xaver, the announced row is quinten; safe because a remote id is
always peer@<handle>, never a bare name.
pub fn register_presence(&mut self, key: &PresenceKey, user: UserId)
pub fn remove_presence(&mut self, key: &PresenceKey, user: &UserId)
pub fn set_tab_focus(&mut self, target: &PresenceKey, user: UserId)
pub fn set_tab_focus(&mut self, target: &PresenceKey, user: UserId)
Re-attribute user to exactly one PresenceKey::Tab at a time, so a
peer switching tabs moves their dot rather than leaving a trail. No-op
(falls back to register_presence) if target isn’t a Tab key.
pub fn set_pointer(&mut self, key: &PresenceKey, user: UserId, pos: (f32, f32))
pub fn set_pointer_at(
&mut self,
key: &PresenceKey,
user: UserId,
pos: (f32, f32),
now: Instant,
)
pub fn set_pointer_at( &mut self, key: &PresenceKey, user: UserId, pos: (f32, f32), now: Instant, )
Self::set_pointer with the clock supplied, so retirement can be
exercised without sleeping. Records the peer as present as well as
pointing — deliberately a separate record, since the pointer expires
but being here does not. Single-location like set_caret/
set_selection: a person has one pointer, so this moves it rather
than adding a new entry under a different scope.
A move heard at a later instant than the last is a new sample, and
the pointer glides to it (Self::pointer_position_at). A move
stamped with the same instant is that sample re-placed — the tile
it is anchored to moved — so it is carried there with no glide of its
own, any glide already in flight riding along.
pub fn pointer_position_at(
&self,
key: &PresenceKey,
user: &UserId,
now: Instant,
) -> Option<(f32, f32)>
pub fn pointer_position_at( &self, key: &PresenceKey, user: &UserId, now: Instant, ) -> Option<(f32, f32)>
Where to paint user’s pointer at key at now: on its way from
where it was shown to where it was last heard, eased over the gap
between its last two samples (at most POINTER_EASE_MAX), so a
~30 Hz stream of samples moves smoothly on a faster display instead
of stepping. None when there is no such pointer. Painters of peer
pointers read this rather than Self::pointer_for’s raw position,
except under reduced motion, where the raw position is the answer.
pub fn pointers_easing(&self, now: Instant) -> bool
pub fn pointers_easing(&self, now: Instant) -> bool
Whether any pointer is still gliding at now (see
Self::pointer_position_at) — a reason to paint the next frame too.
pub fn prune_pointers(&mut self, now: Instant, horizon: Duration) -> bool
pub fn prune_pointers(&mut self, now: Instant, horizon: Duration) -> bool
Retire every pointer nobody has restated within horizon. Returns
whether anything was retired — a reason to repaint. horizon must
comfortably exceed the ~1s restate interval, so this notices a peer
gone quiet rather than blinking one whose keepalive was briefly
delayed. Only the pointer goes — the peer stays in Self::here,
since going quiet about pointing is not leaving — and with it the
peer’s Self::remote_cursors record of that pointer, as
Self::clear_pointer does, so a peer that vanished leaves nothing
for a window to keep repainting.
pub fn pointer_opacity(
&self,
key: &PresenceKey,
user: &UserId,
now: Instant,
horizon: Duration,
fade: Duration,
) -> f32
pub fn pointer_opacity( &self, key: &PresenceKey, user: &UserId, now: Instant, horizon: Duration, fade: Duration, ) -> f32
How opaque to paint user’s pointer at key: fully until the last
fade before it goes quiet for horizon, then falling to zero as
Self::prune_pointers is about to retire it. A zero fade (reduced
motion) keeps it opaque until it is retired.
pub fn pointers_fading(
&self,
now: Instant,
horizon: Duration,
fade: Duration,
) -> bool
pub fn pointers_fading( &self, now: Instant, horizon: Duration, fade: Duration, ) -> bool
Whether any pointer is fading out at now (see
Self::pointer_opacity) — a reason to paint the next frame too.
pub fn set_caret(&mut self, key: &PresenceKey, user: UserId, pos: usize)
pub fn set_selection( &mut self, key: &PresenceKey, user: UserId, range: SelectionRange, )
pub fn peers_on(&self, key: &PresenceKey) -> &[UserId]
pub fn pointer_for( &self, key: &PresenceKey, user: &UserId, ) -> Option<(f32, f32)>
pub fn selection_for( &self, key: &PresenceKey, user: &UserId, ) -> Option<SelectionRange>
pub fn caret_for(&self, key: &PresenceKey, user: &UserId) -> Option<usize>
pub fn set_color_override(&mut self, user: UserId, hex: &str)
pub fn set_color_override(&mut self, user: UserId, hex: &str)
Seed or replace this user’s colour override (see parse_hex_color
for the accepted formats). Malformed input silently clears the
override, falling back to user_color.
pub fn set_presence_hue(&mut self, user: UserId, hue: PresenceHue)
pub fn set_presence_hue(&mut self, user: UserId, hue: PresenceHue)
Paint user in the presence colour they wear — their choice, or the
one their stable identity derives, as their own machine said it — in
place of the colour their id derives here. Recolours a cursor already
on screen.
pub fn color_for(&self, user: &UserId) -> (u8, u8, u8)
pub fn set_display_name(&mut self, user: UserId, name: impl Into<String>)
pub fn set_display_name(&mut self, user: UserId, name: impl Into<String>)
Seeded from the collab roster. Overwrites any prior name.
pub fn set_participant_kind(
&mut self,
user: impl AsRef<UserId>,
kind: impl Into<ParticipantKind>,
)
pub fn set_participant_kind( &mut self, user: impl AsRef<UserId>, kind: impl Into<ParticipantKind>, )
Seed the authenticated participant kind announced by the room. Both the legacy boolean and the typed enum map to the same authenticated kind, so changing names never changes a participant’s principal kind.
pub fn participant_kind(&self, user: &UserId) -> ParticipantKind
pub fn is_agent(&self, user: &UserId) -> bool
pub fn is_agent(&self, user: &UserId) -> bool
Whether user is software acting for someone (an agent, a Shortcut,
an app) rather than a person: drawn with the agent mark.
pub fn set_acting_for(
&mut self,
user: impl AsRef<UserId>,
person: Option<UserId>,
)
pub fn set_acting_for( &mut self, user: impl AsRef<UserId>, person: Option<UserId>, )
Record whom user acts for, as the broker admitted it; None when
it acts for nobody in particular.
pub fn acting_for(&self, user: &UserId) -> Option<&UserId>
pub fn acting_for(&self, user: &UserId) -> Option<&UserId>
The person user acts for, if it is an agent, a Shortcut or an app
acting for one.
pub fn display_name(&self, user: &UserId) -> String
pub fn display_name(&self, user: &UserId) -> String
The friendly name to show for user, falling back to the raw id
when the roster hasn’t announced one. Never blank. Software acting
for a person is named with that person (“Claude, for Ada”), else
with its kind (“Claude · Agent”).
pub fn user(&self, user: &UserId) -> PresenceUser
pub fn note_remote_text_edit(&mut self, now: Instant)
pub fn note_remote_text_edit(&mut self, now: Instant)
Called by the App after it diffs the document, not on every delta
— a metadata-only delta isn’t an edit.
pub fn record_peer_typing(
&mut self,
user: UserId,
key: PresenceKey,
range: SelectionRange,
now: Instant,
)
pub fn record_peer_typing( &mut self, user: UserId, key: PresenceKey, range: SelectionRange, now: Instant, )
Adjacent/overlapping marks from the same peer under the same key coalesce into one growing span with a refreshed birth instant, so a keystroke burst reads as one moving highlighter, not a stack of tints.
pub fn active_typing(
&self,
user: &UserId,
key: &PresenceKey,
now: Instant,
) -> Vec<(SelectionRange, f32)>
pub fn active_typing( &self, user: &UserId, key: &PresenceKey, now: Instant, ) -> Vec<(SelectionRange, f32)>
The peer’s still-visible typing spans under key at time now,
each paired with a fade alpha in 0.0..=1.0 (1.0 = just typed,
tapering linearly to 0 at TYPING_FADE). This is a read only:
call Self::prune_typing separately to reclaim expired entries.
pub fn typing_marks_for_key(
&self,
key: &PresenceKey,
now: Instant,
) -> Vec<(UserId, SelectionRange, f32)>
pub fn typing_marks_for_key( &self, key: &PresenceKey, now: Instant, ) -> Vec<(UserId, SelectionRange, f32)>
Every peer’s typing spans under key at now, as (user, range, alpha).
pub fn has_active_typing(&self, now: Instant) -> bool
pub fn has_active_typing(&self, now: Instant) -> bool
The App polls this to keep requesting animation frames while a highlighter is still decaying.
pub fn prune_typing(&mut self, now: Instant)
pub fn prune_typing(&mut self, now: Instant)
Call once a frame.
pub fn set_peer_view(&mut self, user: UserId, view: ViewSubset)
pub fn set_peer_view(&mut self, user: UserId, view: ViewSubset)
Never merged, only replaced, so a peer’s entry is always exactly what they last published.
pub fn peer_view(&self, user: &UserId) -> Option<&ViewSubset>
pub fn peer_view(&self, user: &UserId) -> Option<&ViewSubset>
What attach/follow binds the local viewport to.
pub fn peer_pointer(&self, user_id: &str) -> Option<[f32; 2]>
pub fn peer_pointer(&self, user_id: &str) -> Option<[f32; 2]>
The target a “follow” action scrolls toward — reads the same
remote_cursors overlay the pointer is drawn from, so following a
peer lands exactly where their cursor shows.
pub fn following_in(&self, key: &PresenceKey) -> Vec<(&UserId, &UserId)>
pub fn following_in(&self, key: &PresenceKey) -> Vec<(&UserId, &UserId)>
Every live (follower, target) relationship announced in key.
This is deliberately a render-only projection of transient presence.
pub fn hit_test_offscreen_mist(
&self,
viewport: Rect,
point: Point,
) -> Option<String>
pub fn hit_test_offscreen_mist( &self, viewport: Rect, point: Point, ) -> Option<String>
Returns the id of the peer whose off-screen mist band (the strips
draw_remote_presence paints) contains point, so clicking a
peer’s mist selects them to follow.
pub fn upsert_remote_cursor(
&mut self,
user_id: String,
position: [f32; 2],
display_name: Option<&str>,
)
pub fn upsert_remote_cursor( &mut self, user_id: String, position: [f32; 2], display_name: Option<&str>, )
Upsert a remote peer’s cursor into remote_cursors. Label defaults to
user_id when display_name is None.
pub fn upsert_remote_cursor_faded(
&mut self,
user_id: String,
position: [f32; 2],
display_name: Option<&str>,
alpha: f32,
)
pub fn upsert_remote_cursor_faded( &mut self, user_id: String, position: [f32; 2], display_name: Option<&str>, alpha: f32, )
Self::upsert_remote_cursor with an explicit opacity, so a caller
that ages cursors out can fade one rather than popping it. Clamped to 0.0..=1.0.
pub fn upsert_remote_cursor_owned(
&mut self,
user_id: String,
position: [f32; 2],
display_name: Option<&str>,
alpha: f32,
owner: PointerOwner,
)
pub fn upsert_remote_cursor_owned( &mut self, user_id: String, position: [f32; 2], display_name: Option<&str>, alpha: f32, owner: PointerOwner, )
Self::upsert_remote_cursor_faded naming which layer paints the
result — see PointerOwner. An upsert re-states the owner, so a
peer whose pointer changes transport changes hands too.
pub fn remove_remote_cursor(&mut self, user_id: &str)
pub fn set_remote_caret( &mut self, user_id: String, key: PresenceKey, pos: usize, )
pub fn set_remote_selection( &mut self, user_id: String, key: PresenceKey, start: usize, end: usize, )
pub fn register_peer_at(&mut self, user_id: String, key: PresenceKey)
pub fn apply_remote_presence(
&mut self,
user_id: String,
key: PresenceKey,
payload: PresencePayload,
) -> RemotePresenceEffect
pub fn apply_remote_presence( &mut self, user_id: String, key: PresenceKey, payload: PresencePayload, ) -> RemotePresenceEffect
Fold one inbound presence frame into this context — the whole decode
of a RemotePresenceUpdate. Lives on PresenceCtx rather than App
because the compositor also subscribes to the identical stream, and
two decoders would drift. The returned RemotePresenceEffect names
what a bare presence store can’t do for itself.
pub fn apply_remote_presence_at(
&mut self,
user_id: String,
key: PresenceKey,
payload: PresencePayload,
now: Instant,
) -> RemotePresenceEffect
pub fn apply_remote_presence_at( &mut self, user_id: String, key: PresenceKey, payload: PresencePayload, now: Instant, ) -> RemotePresenceEffect
Self::apply_remote_presence with the instant the frame was heard
supplied. A compositor re-placing a pointer it heard earlier (its tile
moved) passes the original instant, so the move is carried rather
than read as the peer moving again (Self::set_pointer_at); tests
pass a clock they control.
pub fn clear_pointer(&mut self, user_id: &str) -> bool
pub fn clear_pointer(&mut self, user_id: &str) -> bool
Drop every trace of user_id, on an actual disconnect (not Left,
which is just the pointer leaving the viewport — see the arm above).
Stop drawing user_id’s pointer, wherever it was, without touching
anything else about them: they are still here, just not pointing at
anything this device can show. Returns whether a pointer went.
pub fn unregister_peer(&mut self, user_id: &str)
pub fn status_for(&self, user: &UserId, now: SystemTime) -> Option<&LiveStatus>
pub fn status_for(&self, user: &UserId, now: SystemTime) -> Option<&LiveStatus>
Current status for a room participant. Inferred statuses apply their normal expiry even if a peer vanished without a clean disconnect.
Trait Implementations§
§impl Clone for PresenceCtx
impl Clone for PresenceCtx
§fn clone(&self) -> PresenceCtx
fn clone(&self) -> PresenceCtx
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more§impl Debug for PresenceCtx
impl Debug for PresenceCtx
§impl Default for PresenceCtx
impl Default for PresenceCtx
§fn default() -> PresenceCtx
fn default() -> PresenceCtx
Auto Trait Implementations§
impl !Freeze for PresenceCtx
impl !RefUnwindSafe for PresenceCtx
impl Send for PresenceCtx
impl !Sync for PresenceCtx
impl Unpin for PresenceCtx
impl UnsafeUnpin for PresenceCtx
impl !UnwindSafe for PresenceCtx
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more