Struct PresenceCtx
pub struct PresenceCtx {
pub here: HashMap<PresenceKey, Vec<UserId>>,
pub pointers: HashMap<PresenceKey, Vec<(UserId, (f32, f32))>>,
pub chats: CursorChats,
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))>>§chats: CursorChatsWhat people are saying beside their pointers, and their reactions.
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.
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 workspace
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.
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 note_shown(&self, invocation: InvocationId)
pub fn note_shown(&self, invocation: InvocationId)
Say that this frame paints invocation’s exact place: the characters
a write landed in, or the row it names. The activity rail then leaves
the invocation out, so one action is not named twice on one frame.
pub fn interaction_fade(
&self,
invocation: InvocationId,
now: Instant,
) -> Option<f32>
pub fn interaction_fade( &self, invocation: InvocationId, now: Instant, ) -> Option<f32>
How strongly an interaction still shows, from when its current phase
arrived: what the text it wrote fades by. None when it is no longer
shown, or its mark has faded out.
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,
control: Rect,
viewport: Rect,
surface: &str,
now: Instant,
) -> Option<AgentActionMarker>
pub fn draw_agent_action_marker( &mut self, paint: &mut PaintCtx<'_>, interaction: &SemanticInteraction, locus: Rect, control: 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 places_content_marks(&self, now: Instant) -> bool
pub fn places_content_marks(&self, now: Instant) -> bool
Whether widgets paint marks placed from their own content at now
(WidgetPresence::marks_follow_content): a widget’s damage does
not say where those marks were.
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 placed_cursor(&self, placed: PlacedPointer) -> PeerCursor
pub fn placed_cursor(&self, placed: PlacedPointer) -> PeerCursor
placed as the frame draws it: in the colour and under the name
this presence knows the person by, so a pointer always matches their
avatar. Someone presence has no name for yet goes by the one their
own presence gives, else the start of their id, never the whole key.
§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_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_caret_labeled_in(
&self,
scene: &mut Scene,
theme: &Theme,
text_renderer: &mut TextRenderer,
transform: Affine,
user: &UserId,
name: &str,
caret: LabeledCaret,
)
pub fn draw_peer_caret_labeled_in( &self, scene: &mut Scene, theme: &Theme, text_renderer: &mut TextRenderer, transform: Affine, user: &UserId, name: &str, caret: LabeledCaret, )
Self::draw_peer_caret_labeled for text with content above its
first line (a note’s title and dates over its body): a chip that
would rise above LabeledCaret::top hangs below the caret instead,
so a caret on the first line never covers what is above the text.
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 workspace 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 paint_permission_generation(&self) -> u64
pub fn paint_permission_generation(&self) -> u64
What crate::permissions::shared_revision was when the drawing in
progress was lent its authority: a retained drawing from another
generation paints what the permissions no longer allow, or not what
they now do.
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.
Forget the caret name tags painted so far: a host calls it before a frame that draws every window again.
The caret name tags painted since Self::clear_caret_tags, in
scene coordinates.
§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 workspace 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 workspace this session is, if the workspace has said.
pub fn self_name(&self) -> Option<&str>
pub fn self_name(&self) -> Option<&str>
What the workspace calls this session’s own participant. None for a
participant the workspace 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
workspace’s name for this session: a locally-sent frame is stamped Bob, the announced
row ada, and a remote id is always peer@<handle>.
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). None when there is no such pointer; painters read this rather than
Self::pointer_for’s raw position.
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 pointer_name_opacity(
&self,
key: &PresenceKey,
user: &UserId,
now: Instant,
fade: Duration,
) -> f32
pub fn pointer_name_opacity( &self, key: &PresenceKey, user: &UserId, now: Instant, fade: Duration, ) -> f32
How opaque to paint the name beside user’s pointer at key: whole while it moves and
while they are talking (CursorChats::talking), then fading over the last fade of
POINTER_NAME_LINGER once it stands still. A zero fade (reduced motion) keeps it whole
until the linger is up.
pub fn pointer_names_fading(&self, now: Instant, fade: Duration) -> bool
pub fn pointer_names_fading(&self, now: Instant, fade: Duration) -> bool
Whether any pointer’s name is fading at now (see
Self::pointer_name_opacity), or will step aside at the end of its
linger: a reason to paint the next frame too.
pub fn next_pointer_name_fade(
&self,
now: Instant,
fade: Duration,
) -> Option<Instant>
pub fn next_pointer_name_fade( &self, now: Instant, fade: Duration, ) -> Option<Instant>
When the next pointer’s name starts to step aside, for a host that sleeps between frames.
pub fn set_workspace_in_front(&mut self, workspace: Option<String>)
pub fn set_workspace_in_front(&mut self, workspace: Option<String>)
Name the workspace in front: the one
Self::availability_of and Self::call_of answer for.
pub fn availability_in(&self, workspace: &str, user: &UserId) -> Availability
pub fn availability_in(&self, workspace: &str, user: &UserId) -> Availability
How available user says they are in workspace; available until they
said.
pub fn call_in(&self, workspace: &str, user: &UserId) -> Option<&str>
pub fn call_in(&self, workspace: &str, user: &UserId) -> Option<&str>
The voice channel user says they are in, in workspace.
pub fn has_availability_in(&self, workspace: &str, user: &UserId) -> bool
pub fn has_availability_in(&self, workspace: &str, user: &UserId) -> bool
Whether user has said how available they are in workspace.
pub fn availability_of(&self, user: &UserId) -> Availability
pub fn availability_of(&self, user: &UserId) -> Availability
How available user says they are in the workspace in front.
pub fn has_availability(&self, user: &UserId) -> bool
pub fn has_availability(&self, user: &UserId) -> bool
Whether user has said how available they are in the workspace in
front.
pub fn call_of(&self, user: &UserId) -> Option<&str>
pub fn call_of(&self, user: &UserId) -> Option<&str>
The voice channel user is in, in the workspace in front.
pub fn bounce(&mut self, user: UserId, motion: EffectiveMotion, now: Instant)
pub fn bounce(&mut self, user: UserId, motion: EffectiveMotion, now: Instant)
Bounce user’s face once: they just waved at this person.
pub fn face_scale(&self, user: &UserId, now: Instant) -> f64
pub fn face_scale(&self, user: &UserId, now: Instant) -> f64
The scale of user’s face at now (1 at rest).
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_joined_at(&mut self, user: UserId, joined: Option<u64>)
pub fn set_joined_at(&mut self, user: UserId, joined: Option<u64>)
When the workspace admitted user, as its roster records it; None when
it has no time for them. People who share a name are numbered by it,
so a newcomer never takes an earlier member’s number.
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 labels(&self) -> &ParticipantLabels
pub fn labels(&self) -> &ParticipantLabels
The numbers people who share a name are told apart by in this workspace.
Self::display_name already applies them; this is for a caller
that holds names of its own for the same participants.
pub fn roster(&self) -> Vec<PresenceUser>
pub fn roster(&self) -> Vec<PresenceUser>
Everyone the workspace names, this session’s own participant included, as they are shown, in an order every replica shares: who a people list or a mention picker offers.
pub fn self_label(&self) -> Option<String>
pub fn self_label(&self) -> Option<String>
What this session’s own participant is shown as, numbered like
anyone else’s name; None until the workspace has named them.
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 workspace. 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 set_persons(&mut self, pairs: impl IntoIterator<Item = (UserId, UserId)>)
pub fn set_persons(&mut self, pairs: impl IntoIterator<Item = (UserId, UserId)>)
Replace which person each participant here is a device of, as the
workspace’s host paired them: (participant, person). Where presence
already names people, there is nothing to pair.
pub fn person_of(&self, user: &UserId) -> Option<&UserId>
pub fn person_of(&self, user: &UserId) -> Option<&UserId>
The person participant user is a device of, when the workspace’s host
paired them; None where presence names the person itself.
pub fn participant_label(&self, user: &str) -> String
pub fn participant_label(&self, user: &str) -> String
What every surface calls user — chat lines, pills, people lists,
the top bar, mentions: Self::display_name by its id.
pub fn display_name(&self, user: &UserId) -> String
pub fn display_name(&self, user: &UserId) -> String
The friendly name to show for user, this session’s own participant included, falling back
to the raw id when the roster has not announced one. Never blank. People sharing a name
carry their number (“Ada (2)”, ParticipantLabels); software acting for a person is named
with that person (“Claude, for Ada”), else with its kind.
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 typing_next_step(&self, now: Instant) -> Option<Instant>
pub fn typing_next_step(&self, now: Instant) -> Option<Instant>
When the next typing mark steps down its fade (or ends): the host sleeps until then and paints once, instead of pumping frames through the fade.
pub fn has_active_typing(&self, now: Instant) -> bool
pub fn has_active_typing(&self, now: Instant) -> bool
Whether a typing highlight is still on screen at now.
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 composing_at(&self, key: &PresenceKey, now: Instant) -> Vec<UserId>
pub fn composing_at(&self, key: &PresenceKey, now: Instant) -> Vec<UserId>
Fold one inbound presence frame into this context — the whole decode of a
RemotePresenceUpdate. Lives on PresenceCtx rather than App because the compositor
subscribes to the identical stream, and two decoders would drift. The returned
RemotePresenceEffect names what a bare presence store can’t do for itself.
Who is composing a message in key now, the person looking excluded: a channel’s
“Mia is typing”. A composer gone quiet for COMPOSING_LINGER without saying they
stopped drops out, so a crashed window leaves no one typing forever.
pub fn prune_composing(&mut self, now: Instant)
pub fn prune_composing(&mut self, now: Instant)
Drop composers gone quiet for COMPOSING_LINGER: what a frame does before it asks
Self::composing_at, so the answer does not depend on when it was last asked.
pub fn apply_remote_presence( &mut self, user_id: String, key: PresenceKey, payload: PresencePayload, ) -> RemotePresenceEffect
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).
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 workspace 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> 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>, which can then be
downcast into Box<dyn 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>, which 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> DowncastSend for T
impl<T> DowncastSend for T
§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