Screenshare stays on the call bar in Firefox/Safari via the in-frame prompt (#43) #244

Merged
jared merged 2 commits from screenshare-prompt into lotus 2026-09-27 13:54:11 -04:00
Owner

Follow-up to #43. On Firefox, Safari and the Linux desktop app, the screenshare button goes back on the call bar, and the confirmation moves into the call frame. Requires element-call lotus-screenshare-prompt (lotus.22).

Changes

  • CallControl:

    • reads screensharePrompt and screensharePromptOpen from controls_state
    • screenshareNeedsPrompt is true when the fork has the card and this engine can't delegate
    • promptScreenshare() sends io.lotus.prompt_screenshare
    • the room's call policy is also pushed in prompt mode, so the card never opens where sharing is forbidden.
  • useScreenshareMode returns one of three modes:

    • hidden: the older fork's corner button, so ours hides, as today
    • prompt: our click asks for the in-frame card
    • direct: our confirm, then the delegated set_screenshare.

    The call bar and the status bar both use it through one handleScreenshareToggle.

  • Picture-in-picture: the "Return to call" overlay covers the whole frame, so the card's Share button couldn't be clicked. While the fork reports the card open, the overlay lets clicks through. Found in testing and fixed here.

Before merging

  • Bump @lotusguild/element-call-embedded to 0.25.0-lotus.22 once the element-call PR is merged and tagged.

card above the call bar
compact card in picture-in-picture

What changes for users

  • Firefox, Safari and the Linux desktop app: the screenshare button is back on the call bar and the status bar, where the camera and speaker buttons are. It replaces the lone button in the call's bottom-right corner.
    • Clicking it shows "Share your screen?" inside the call, just above the bar. Share starts the share; Cancel or Escape closes the card.
    • That's the same two clicks as the "Share your screen?" confirm Chrome already had.
    • The card has to be inside the call: these browsers only start a share after a click in the call frame itself. That's the reason the corner button existed.
  • Picture-in-picture: starting a share from the status bar while you're in another room shows a compact version of the card inside the small call window.
  • Chrome, Edge and the Windows app: unchanged.
  • Stopping a share: works from the bar everywhere, and needs no card.

Test evidence

Local Synapse + LiveKit. "No delegation" means Chromium with navigator.userAgentData removed, which takes exactly the Firefox/Safari code path (no Capability Delegation).

Scenario Result
No delegation, same-origin and cross-origin (call page on :5174, like prod) Bar button present, no corner button. Click → card in frame, Share focused, host confirm not shown. Cancel → no share. Share → LiveKit shows VIDEO/SCREEN_SHARE + AUDIO/SCREEN_SHARE_AUDIO. Bar Stop → tracks gone.
Chromium, same-origin and cross-origin Unchanged: host confirm → share → bar stop.
Picture-in-picture (278×156 window) Compact card, 210×83, fully inside the window, description hidden. Share starts the share. "Return to call" works again afterwards.
Room policy forbids screensharing Bar button hidden. A forced prompt_screenshare request is refused (no card). Restoring the policy brings the button back.
Regression, cross-origin with production headers Join/isolation, PTT/deafen in the frame, layout/reactions/settings, speaking indicator, foreign-frame spoof blocked, soundboard, avatars, muted-speech warning: all pass.

Also: element-call lotus tests 116 (8 new for the card), cinny unit tests 1,268, Playwright e2e 20/20, tsc/eslint/oxlint/knip clean.

Not automated: real Firefox. Playwright's headless Firefox 155 stalls at "Heating up" when setting up the encryption store, before any call code runs, in both dev and production builds. So the Firefox-specific part (a click in the frame counts as activation for getDisplayMedia) is covered by the no-delegation run and by the HTML spec, not by a real Firefox run. Please try it in your Firefox after step 2. Rollback is quick.

Rollout

  1. Merge element-call lotus-screenshare-prompt → tag v0.25.0-lotus.22 → CI publishes. No effect on its own.
  2. In cinny screenshare-prompt, bump the pin to 0.25.0-lotus.22, then merge (deploys).

Order and compatibility:

  • This cinny code with the current fork (lotus.21): the fork still reports its corner button, so the host keeps hiding its own. It behaves exactly like today, so merging cinny early is harmless.
  • The new fork with the current host: never happens, because the fork only reaches production through cinny's pin.

Rollback: set the pin back to 0.25.0-lotus.21 and redeploy. You get the corner button again.

Review checklist

  • Chromium flow is unchanged (host confirm → delegated set_screenshare).
  • hidden mode with lotus.21 matches today's production exactly.
  • The PiP overlay only lets clicks through while the card is open. Verified: "Return to call" works again right after.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA

Follow-up to **#43**. On Firefox, Safari and the Linux desktop app, the screenshare button goes back on the call bar, and the confirmation moves into the call frame. Requires element-call `lotus-screenshare-prompt` (lotus.22). ## Changes - **`CallControl`:** - reads `screensharePrompt` and `screensharePromptOpen` from `controls_state` - `screenshareNeedsPrompt` is true when the fork has the card and this engine can't delegate - `promptScreenshare()` sends `io.lotus.prompt_screenshare` - the room's call policy is also pushed in prompt mode, so the card never opens where sharing is forbidden. - **`useScreenshareMode`** returns one of three modes: - `hidden`: the older fork's corner button, so ours hides, as today - `prompt`: our click asks for the in-frame card - `direct`: our confirm, then the delegated `set_screenshare`. The call bar and the status bar both use it through one `handleScreenshareToggle`. - **Picture-in-picture:** the "Return to call" overlay covers the whole frame, so the card's Share button couldn't be clicked. While the fork reports the card open, the overlay lets clicks through. Found in testing and fixed here. ## Before merging - [ ] Bump `@lotusguild/element-call-embedded` to `0.25.0-lotus.22` once the element-call PR is merged and tagged. ![card above the call bar](https://code.lotusguild.org/attachments/4fbb241e-583a-4fc9-8b55-accf44ee4f17) ![compact card in picture-in-picture](https://code.lotusguild.org/attachments/fe5d585e-187a-49c2-86d0-ceef97524e26) ## What changes for users - **Firefox, Safari and the Linux desktop app:** the screenshare button is back **on the call bar and the status bar**, where the camera and speaker buttons are. It replaces the lone button in the call's bottom-right corner. - Clicking it shows **"Share your screen?"** inside the call, just above the bar. **Share** starts the share; **Cancel** or **Escape** closes the card. - That's the same two clicks as the "Share your screen?" confirm Chrome already had. - The card has to be *inside* the call: these browsers only start a share after a click in the call frame itself. That's the reason the corner button existed. - **Picture-in-picture:** starting a share from the status bar while you're in another room shows a compact version of the card inside the small call window. - **Chrome, Edge and the Windows app:** unchanged. - **Stopping a share:** works from the bar everywhere, and needs no card. ## Test evidence Local Synapse + LiveKit. "No delegation" means Chromium with `navigator.userAgentData` removed, which takes exactly the Firefox/Safari code path (no Capability Delegation). | Scenario | Result | |---|---| | No delegation, same-origin and cross-origin (call page on `:5174`, like prod) | Bar button present, no corner button. Click → card in frame, **Share focused**, host confirm not shown. Cancel → no share. Share → LiveKit shows `VIDEO/SCREEN_SHARE` + `AUDIO/SCREEN_SHARE_AUDIO`. Bar Stop → tracks gone. | | Chromium, same-origin and cross-origin | Unchanged: host confirm → share → bar stop. | | Picture-in-picture (278×156 window) | Compact card, 210×83, fully inside the window, description hidden. Share starts the share. "Return to call" works again afterwards. | | Room policy forbids screensharing | Bar button hidden. A forced `prompt_screenshare` request is refused (no card). Restoring the policy brings the button back. | | Regression, cross-origin with production headers | Join/isolation, PTT/deafen in the frame, layout/reactions/settings, speaking indicator, foreign-frame spoof blocked, soundboard, avatars, muted-speech warning: all pass. | Also: element-call lotus tests 116 (8 new for the card), cinny unit tests 1,268, Playwright e2e 20/20, tsc/eslint/oxlint/knip clean. **Not automated: real Firefox.** Playwright's headless Firefox 155 stalls at "Heating up" when setting up the encryption store, before any call code runs, in both dev and production builds. So the Firefox-specific part (a click in the frame counts as activation for `getDisplayMedia`) is covered by the no-delegation run and by the HTML spec, not by a real Firefox run. **Please try it in your Firefox after step 2.** Rollback is quick. ## Rollout 1. Merge **element-call** `lotus-screenshare-prompt` → tag `v0.25.0-lotus.22` → CI publishes. No effect on its own. 2. In **cinny** `screenshare-prompt`, bump the pin to `0.25.0-lotus.22`, then merge (deploys). **Order and compatibility:** - **This cinny code with the current fork (lotus.21):** the fork still reports its corner button, so the host keeps hiding its own. It behaves exactly like today, so merging cinny early is harmless. - **The new fork with the current host:** never happens, because the fork only reaches production through cinny's pin. **Rollback:** set the pin back to `0.25.0-lotus.21` and redeploy. You get the corner button again. ## Review checklist - [ ] Chromium flow is unchanged (host confirm → delegated `set_screenshare`). - [ ] `hidden` mode with lotus.21 matches today's production exactly. - [ ] The PiP overlay only lets clicks through while the card is open. Verified: "Return to call" works again right after. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
jared added 1 commit 2026-09-27 13:01:05 -04:00
feat(call): screenshare stays on the call bar in Firefox/Safari via the in-frame prompt (#43)
CI / Build & Quality Checks (pull_request) Successful in 4m18s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 11s
CI / Playwright smoke (e2e) (pull_request) Successful in 11m27s
8520de232d
With a fork that reports `screensharePrompt` (element-call lotus-screenshare-
prompt), the call bar and status bar keep their screenshare button on every
engine. Where the click can't be delegated, starting asks the fork to show
"Share your screen?" inside the call frame (io.lotus.prompt_screenshare)
instead of our own confirm; its Share click starts the share. Stopping works
from the bar as before (no click needed in the frame). Chromium is unchanged.

- useScreenshareMode: hidden (older fork's corner button) | prompt | direct.
- The room's call policy is also pushed to the fork in prompt mode, so the
  prompt never opens where sharing is forbidden.
- Picture-in-picture: the "Return to call" overlay covers the frame; while
  the fork reports the prompt open it lets clicks through to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
jared added 1 commit 2026-09-27 13:32:48 -04:00
chore(call): pin element-call-embedded 0.25.0-lotus.22 (#43)
CI / Build & Quality Checks (pull_request) Successful in 4m14s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 9s
CI / Playwright smoke (e2e) (pull_request) Successful in 16m39s
b929cbf74b
lotus.22 draws the "Share your screen?" prompt inside the call frame on
request and drops the corner button. Verified against the published
package: no-delegation (Firefox path) cross- and same-origin — bar button,
in-frame prompt, Cancel, Share → screenshare tracks, bar Stop; Chromium
unchanged; picture-in-picture prompt fits and Share works; room policy
hides the button and refuses the prompt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
jared merged commit e2b23397bd into lotus 2026-09-27 13:54:11 -04:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#244