Skip to content

feat(desktop-gpui): picker controls in Cap Glass - #3456

Draft
richiemcilroy wants to merge 23 commits into
feat/gpui-cap-glassfrom
feat/gpui-picker-glass
Draft

richiemcilroy wants to merge 23 commits into
feat/gpui-cap-glassfrom
feat/gpui-picker-glass

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Stacked on #3442 (Cap Glass). Last in the picker stack: #3441, #3450, #3452, #3454, #3442, this.

What changes

The picker's panels and floating controls are drawn in Cap Glass instead of an 82% opaque grey fill:

  • the start cluster card and the device card: Regular glass, 16 px corners
  • the area toolbar: Regular glass
  • the close and countdown buttons: round Clear glass
  • the window size chip and the Focus pill: Clear glass capsules
  • the Focus switch: a new ui::GlassSwitch, shaped like the system switch as measured from Apple's own controls in the reference captures (scripts/glass-reference). It has a 54 x 24 track, a 34 x 22 capsule knob inset a point, and the accent colour when on. While pressed, the knob swells into a Clear glass lens over the track, and it slides between ends over 220 ms. The teleprompter keeps ui::Toggle.

Glass over a transparent window

The overlay is a transparent window. Glass reads what is already in the window, which for the overlay is only its own dimming. So each overlay captures the desktop beneath it and paints that capture under its panes before anything else it draws. The dimming and highlights then land on the capture exactly as they land on the real desktop. Outside the panes the capture is pixel-identical to what is on screen until the desktop changes.

  • Leaving the overlay out. For the length of one capture, the overlay is marked hidden from screen capture: NSWindowSharingNone on macOS, WDA_EXCLUDEFROMCAPTURE on Windows. Neither changes what is on screen. If the window server reports that it kept the window in the capture (a Windows remote session does), no capture is used.
  • Capturing. macOS reads CGDisplayCreateImage straight into gpui's BGRA layout with one copy per row. Windows uses the shared screenshot path.
  • Painting only where it's needed. ui::glass::Backdrop paints the capture only where panes sample: their bounds plus the blur's three-sigma reach and the rim lensing, plus 24 pt of slack. Pane positions come from layout, so the layer uses the previous frame's positions. A pane that moves outside them asks for one more frame. Each region is one sprite cropped to its own size (paint_image_fitted).
  • When captures happen.
    • Only when the overlay draws and the last capture is more than 3 s old, so a picker left alone takes none.
    • While a dragged area moves its panels, the old capture holds, and a new one is taken 400 ms after they stop.
    • After a resize or Focus moves a window, the capture is retaken 350 ms later.
    • An overlay that stops showing controls (the cursor moved to another display) drops its capture and frees the texture.
  • The trade-off. Outside each pane, within the blur's reach plus the slack, the capture stands in for the desktop. Something changing there (a video under the toolbar) shows frozen until the next capture. Everywhere but inside a drawn area that strip is under the overlay's dimming.
  • Fallback. Linux can't leave a window out of a capture short of unmapping it. There, and until the first capture lands, the panes sit on the previous panel fill.

Measured

The picker smoke measures process CPU, as a percentage of one core, in one process on one machine:

  1. 3 s with the area picker left alone;
  2. 6 s sliding the drawn area back and forth every 8 ms, with the capture;
  3. the same 6 s with captures turned off.
OS Idle Drag, with capture Drag, without One capture
macOS (CI VM) 0.3% 9.90% 9.81% 52 ms
Windows (CI, WARP software renderer) 2.1% 306% 307% 92 ms
Linux X11 (CI, lavapipe) 8.7% 184% 188% n/a (fallback)

Testing

  • Picker smoke. It saves each mode's backdrop next to its screenshot (<mode>-backdrop.png). On macOS and Windows it fails if a mode has no backdrop, or if the backdrop's mean per-channel difference from the screenshot is 6 levels or less. The overlay dims and tints the whole display, so a capture that held the overlay would match the screenshot. Measured differences:
    • macOS: 60, 30 and 17 levels;
    • Windows: 116, 116 and 57 levels.
  • Unit tests.
    • overlay_backdrop for the capture-to-overlay shape check.
    • glass_switch for the knob's slide.
    • Existing target_overlay and window_arrange tests pass.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; the remaining smoke-check display mismatch is non-blocking.

Findings

  1. P2 Smoke check mixes displays ▶
Fix with agent prompt
### Issue 1
apps/desktop-gpui/src/picker_probe.rs:301-305
`probe_backdrop` takes the first available overlay capture, but `screenshot` always captures the primary display. When the cursor is on a secondary display, that overlay supplies the backdrop. Different display sizes then fail the check even when capture exclusion works; equal sizes compare unrelated desktops. This can give developers a false failure or a misleading pass.

Capture the comparison screenshot from the same display as the chosen backdrop.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The picker now draws its panels and floating controls in Cap Glass.

  • Picker panes show glass over a capture of the desktop beneath the overlay.
  • Picker cards and floating controls use Regular and Clear glass.
  • Picker smoke runs save backdrop images and report capture and CPU readings.

Reviews (4) · Last reviewed commit: "Merge feat/gpui-cap-glass into feat/gpui..." · Reviewed by Greptile

RetriggerView in GreptileConfidence Score: 4/5

Fix the Windows compile error before merging.

Findings

  1. P1 Windows build fails ▶
  2. P2 Smoke check mixes displays ▶
  3. P2 Switch jumps on reversal ▶
Fix with agent prompt
### Issue 1
apps/desktop-gpui/src/platform/windows.rs:157-158
In `window_capture_hidden`, Rust treats the unparenthesized `unsafe { ... }` as a statement, then parses `&& current` as a borrow rather than a boolean conjunction. This produces type errors and prevents the Windows app from building. Wrap the unsafe expression in parentheses before `&&`.

```suggestion
    (unsafe { GetWindowDisplayAffinity(native.hwnd(), &mut current) != 0 })
        && current == WDA_EXCLUDEFROMCAPTURE
```

### Issue 2
apps/desktop-gpui/src/picker_probe.rs:301-305
`probe_backdrop` takes the first available overlay capture, but `screenshot` always captures the primary display. When the cursor is on a secondary display, that overlay supplies the backdrop. Different display sizes then fail the check even when capture exclusion works; equal sizes compare unrelated desktops. This can give developers a false failure or a misleading pass.

Capture the comparison screenshot from the same display as the chosen backdrop.

### Issue 3
apps/desktop-gpui/src/ui/glass_switch.rs:79-84
Clicking Focus again before its 220 ms slide finishes makes the knob jump. Each change resets `changed_at`, but the next slide starts at the opposite end rather than the knob's current position. The selected value still updates correctly, but the animation visibly jumps before sliding back.

Save the knob's current position and start the next slide there.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The picker now draws its panels and floating controls in Cap Glass.

  • Picker glass panes show a capture of the desktop beneath them.
  • Picker panels and floating controls use Regular and Clear glass.
  • The Focus control uses an animated glass switch.

Reviews (6) · Last reviewed commit: "fix(desktop-gpui): leave the camera out ..." · Reviewed by Greptile

@vercel

vercel Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cap-status Ready Ready Preview Oct 27, 2026 7:05pm UTC

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

Comment thread apps/desktop-gpui/src/ui/glass.rs
Comment thread apps/desktop-gpui/src/picker_probe.rs Outdated
Comment thread apps/desktop-gpui/src/ui/glass.rs Outdated
@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

Comment on lines +301 to +305
.find_map(|(_, overlay)| {
overlay
.update(cx, |view, _, _| view.backdrop_image())
.ok()
.flatten()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Smoke check mixes displays

probe_backdrop takes the first available overlay capture, but screenshot always captures the primary display. When the cursor is on a secondary display, that overlay supplies the backdrop. Different display sizes then fail the check even when capture exclusion works; equal sizes compare unrelated desktops. This can give developers a false failure or a misleading pass.

Capture the comparison screenshot from the same display as the chosen backdrop.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/picker_probe.rs
Line: 301-305

Comment:
**Smoke check mixes displays**

`probe_backdrop` takes the first available overlay capture, but `screenshot` always captures the primary display. When the cursor is on a secondary display, that overlay supplies the backdrop. Different display sizes then fail the check even when capture exclusion works; equal sizes compare unrelated desktops. This can give developers a false failure or a misleading pass.

Capture the comparison screenshot from the same display as the chosen backdrop.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

Comment on lines +79 to +84
let (pressed, progress) = state.update(cx, |state, _| {
if state.drawn.is_some_and(|drawn| drawn != checked) {
state.changed_at = Some(now);
}
state.drawn = Some(checked);
(state.pressed, travel(state.changed_at, now))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Switch jumps on reversal

Clicking Focus again before its 220 ms slide finishes makes the knob jump. Each change resets changed_at, but the next slide starts at the opposite end rather than the knob's current position. The selected value still updates correctly, but the animation visibly jumps before sliding back.

Save the knob's current position and start the next slide there.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/ui/glass_switch.rs
Line: 79-84

Comment:
**Switch jumps on reversal**

Clicking Focus again before its 220 ms slide finishes makes the knob jump. Each change resets `changed_at`, but the next slide starts at the opposite end rather than the knob's current position. The selected value still updates correctly, but the animation visibly jumps before sliding back.

Save the knob's current position and start the next slide there.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

This branch was successfully deployed

2 active deployments
Preview – cap-web — f6da4ea1 Deployed Oct 27, 2026 by vercel[bot]
Preview – cap-status — f6da4ea1 Deployed Oct 27, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant