Skip to content

fix(hud): restore the Linux HUD from the tray and keep the vertical bar on screen on Wayland - #1272

Merged
EtienneLescot merged 2 commits into
mainfrom
fix/hud-wayland-geometry
Oct 15, 2026
Merged

EtienneLescot merged 2 commits into
mainfrom
fix/hud-wayland-geometry

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Summary

Two HUD fixes for Linux, found in the manual e2e pass of the installed v2.1.0-rc.1 .deb on Ubuntu 24.04, GNOME Shell 46, native Wayland (Electron 41.2.1, ozone auto → Wayland), 1920×1080 at 100 %, 32 px top bar, Ubuntu dock at the bottom. One commit per defect, independent of each other, so they can be cherry-picked onto release/v2.1.0 separately. A third defect from the same pass is analysed below and deliberately left out.

1. Tray → Open did not bring back a hidden HUD (573ba3ca)

Observed. Hide recording bar minimized the HUD and the app kept running. Tray (AppIndicator) → Open then made GNOME show only an "“openscreen” is ready" notification, and the HUD stayed minimized. Clicking the app's dock icon did restore it.

Root cause (read in Chromium's ui/ozone/platform/wayland/host/wayland_toplevel_window.cc and mutter 46):

  • xdg-shell has set_minimized and no request to undo it. A Wayland client cannot un-minimize itself.
  • showMainWindow() calls restore(), show(), focus(). On Wayland Restore() leaves a minimized window to Show(), and WaylandToplevelWindow::Show() returns at once when the xdg_toplevel still exists. So neither call did anything.
  • focus() → Activate() asks for an xdg-activation token tied to the app's last input serial. That serial is not from the tray click, which happens in gnome-shell. mutter refuses the activation and flags the window as demanding attention, and gnome-shell turns that into the "is ready" notification.

Fix. On Linux, hud-overlay-hide calls hide() instead of minimize(). Chromium destroys the xdg_toplevel, and the show() already in showMainWindow() maps a new one, which the compositor displays. It should also take focus when it is mapped: mutter's intervening_user_event_occurred returns FALSE for a Wayland window with no user time. This fixes every caller of showMainWindow(): tray Open, a second launch (second-instance), and the global shortcut where it can register. On X11 the HUD is already skipTaskbar, so a minimized HUD had no taskbar entry and the tray was its only way back anyway; hide() changes nothing there that a user can see. Windows and macOS keep minimize().

Trade-off (Wayland only). The new toplevel is placed by the compositor, so the HUD does not come back exactly where it was hidden. A Wayland client cannot set its own position, so this cannot be avoided. The dock icon no longer brings the bar back either, because no window is mapped; the tooltip already says "Show it again from the tray icon". While a recording is running the tray menu holds only Stop Recording, on every platform, so the way back mid-take is to launch the app again (the dock or the app grid). That raises second-instance, which shows the HUD.

2. The vertical bar ran off the screen (3e262901)

Observed. The horizontal HUD window measured 910×696 (AT-SPI), with the 528×54 bar at window-relative (191, 622). Switch to vertical bar resized it to 648×1080 (bar 54×499 at (297, 561)), and the compositor kept its top-left at about (150, 186). So the window ran from y 186 to y 1266 on a 1080 px display: Record sat under the dock, and Open Studio, language, Hide and Quit were below the screen edge.

Root cause.

  • Wayland has no protocol that tells a client where the shell's panels are. Chromium leaves the work area at the display bounds: WaylandOutput::UpdateMetrics never fills the work-area insets that WaylandScreen::AddOrUpdateDisplay applies. So screen.availHeight is 1080. The vertical tray asks for more than that (bar + 470 px panel reserve + 120 px hysteresis = 1141), so computeHudWindowSize capped it at the reported 1080. That window cannot fit under the 32 px top bar, because mutter keeps a window's top edge inside the work area on a client-started move. Its bottom controls were out of reach wherever it was dragged: the window top stops at y 32, so the bar's bottom stays at y ≥ 1092.
  • mutter resizes a Wayland client from its top-left corner (meta_window_wayland_finish_move_resize). The position hudResizeBounds computes is ignored, so the bottom-anchored bar moved down by the growth. mutter does move a client-resized window back inside the work area (constrain_fully_onscreen), but only when the window fits there. The HUD is not resizable, so mutter cannot shrink it either (the window kept its 1080 px), and a 1080 px window does not fit.

Fix. computeHudAvailableHeight() (in hudGeometry.ts). On Linux, when the platform reports the whole display height as free, the HUD budgets 128 px less: GNOME's top bar plus a bottom dock at Ubuntu's largest icon size. On a 1080 px display the vertical tray now asks for 952 px. That fits, so:

  • it can always be dragged fully on screen;
  • when the horizontal window was inside the work area before the flip, mutter moves the flipped window back inside it on its own, so the bar ends just above the dock.

The horizontal tray's window is unchanged (696 px either way). X11 publishes the panels, so its availHeight is already smaller than height. Windows (where a full-height work area means an auto-hidden taskbar) and macOS are not touched.

3. Not fixed here: the HUD cannot be dragged into the upper part of the screen

Observed. Dragging up stops the bar at y ≈ 681 (horizontal) or 593 (vertical), because the transparent reserve above the bar is part of the window and mutter keeps the window's top edge below the top bar.

Why there is no change for it. The reserve is where the device-settings panel (up to 470 px), the language menu, notices and toasts open above the bar without resizing the window. On Wayland the client cannot position its window and cannot learn where it is (getPosition() and getCursorScreenPoint() are fictions there). Every in-window layout I looked at trades one defect for another:

  • A reserve below the bar (bar at the window top) lets the bar go anywhere. But menus would open downward, entirely off screen when the bar sits at the bottom, which is the default and most common spot. The gear would look dead there.
  • A tight window that grows when a menu opens moves the bar. mutter resizes from the top-left, and it moves a window back on screen only when the window was fully inside the work area before. The bar would jump on open or close, or the menu would open off screen.

The Linux HUD also keeps its whole window inside the work area by design (HUD_CLAMPS_CONTENT in windows.ts, because Linux has no click-through), so X11 has the same reach limit. Changing that is a design change, not a fix for a frozen release branch. Options for main:

  • render the language menu as a native Menu.popup(), which is an xdg_popup the compositor positions relative to the HUD and keeps on screen;
  • move the device panel out of the HUD's toplevel;
  • or a top-anchored Linux layout with menus opening downward, as a product decision.

Workaround on GNOME today. Super+drag the bar. mutter's own modifier-drag is META_GRAB_OP_WINDOW_FLAG_UNCONSTRAINED and may take the window's top above the top bar, which an xdg_toplevel.move may not (mutter 46 window.c, constraints.c). It holds until the HUD next resizes itself (a layout flip, a notice).

Related issue

Refs the manual e2e pass of v2.1.0-rc.1 on Ubuntu 24.04 / GNOME 46 Wayland (no issue filed).

Type of change

  • Bug fix
  • Feature
  • Enhancement
  • Documentation
  • Refactor / maintenance
  • Performance
  • Security

Release impact

  • Patch
  • Minor
  • Major / breaking change
  • No release note needed

Desktop impact

  • Windows
  • macOS
  • Linux
  • Installer / packaging
  • Not platform-specific

Screenshots / video

None. These changes were written without launching the app: another session was driving the desktop. See the manual steps below.

Testing

Unit tests:

  • electron/windows.hudHide.test.ts (new): Hide recording bar calls hide() on Linux and minimize() on Windows and macOS. process.platform is pinned per case, and the module is re-imported because windows.ts reads the platform at import.
  • src/components/launch/hudGeometry.test.ts: computeHudAvailableHeight on Wayland, X11, Windows and macOS. The reported 54×499 vertical bar was granted 1080 px before and now fits between GNOME's top bar and a dock of 80 px; the bar does not scroll internally and still has room for a full popover. The horizontal tray's window is identical.
  • src/components/launch/LaunchWindow.test.tsx: on a Linux display reporting its whole height free, the HUD asks for at most 1080 − 128 px for the vertical bar. Verified failing without the fix: it asks for 1080.
  • npx vitest --run src/components/launch electron/windows*.test.ts electron/hudWindowBounds.test.ts: 198 passed. npm run test: 4720 passed. The only failures are the 5 electron/mcp/* suites, which cannot import @modelcontextprotocol/sdk because the node_modules this worktree borrowed predates that dependency. That is a local setup gap; CI installs with npm ci.
  • npx tsc --noEmit, npx tsc -p tsconfig.test.json --noEmit: clean apart from the same missing-SDK errors in electron/mcp/*. npm run lint: no new diagnostics.

Manual verification on GNOME Wayland (needs a real session)

Use a build of this branch, on Ubuntu 24.04 / GNOME 46 Wayland with the dock at the bottom, launched from a shell with OPENSCREEN_DISABLE_CONTENT_PROTECTION=1. Check echo $XDG_SESSION_TYPE → wayland.

  1. Tray restore. HUD → Hide recording bar: the bar disappears. Tray → Open: the bar comes back, and no "“openscreen” is ready" notification appears. Expect it where mutter places a new window (often centred), not where it was hidden. Repeat with a second openscreen launch instead of the tray: same result.
  2. Mid-recording hide. Start a recording, hide the bar, launch the app again from the dock or app grid: the bar returns, still recording. Stop from the bar.
  3. Vertical flip. With the horizontal bar fully above the dock, Switch to vertical bar. The whole vertical bar, Hide and Quit included, is on screen above the dock. Measure the window with AT-SPI: it should be 648×952 (it was 648×1080). Switch back: the horizontal bar is fully visible.
  4. Vertical flip from a low bar. Drag the horizontal bar onto the dock so the window overlaps it, then flip. mutter may leave the vertical bar partly below the screen, because its fully-onscreen rule only applies to a window that was inside the work area. Dragging it up must now bring every control on screen (the window top stops at y 32, so the bar's bottom reaches about y 964).
  5. Start in vertical. Quit while vertical and relaunch: the HUD opens with the whole vertical bar on screen.
  6. Popovers. Device settings and the language menu open above the bar and are fully visible in both orientations. In vertical the device panel is now capped at 377 px instead of 470 px and scrolls. The language menu keeps its 320 px.
  7. Regression. On GNOME X11 (or --ozone-platform=x11) the vertical tray's size must not change, since X11 reports the panels. On Windows and macOS Hide recording bar still minimizes.

What only a real session can confirm:

  • the focus and placement mutter gives the re-mapped HUD;
  • that the fully-onscreen shove happens after a flip;
  • that 128 px covers the tester's top bar and dock. With the 32 px top bar, a dock taller than 96 px stops the flipped window fitting, so mutter no longer shoves it back; one taller than 116 px leaves the bar's bottom unreachable again.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • On Linux, hiding the recording bar now hides it instead of minimizing it.
    • Improved HUD sizing on Linux when screen information doesn’t account for desktop panels, helping keep vertical trays within the available display area.
    • Preserved existing work-area sizing on Linux, Windows, and macOS, and horizontal-tray sizing across platforms.

On GNOME Wayland, "Hide recording bar" minimized the HUD and the tray's
Open could not bring it back: GNOME only showed an "openscreen is ready"
notification. xdg-shell has set_minimized and nothing to undo it,
Chromium's Wayland Show() returns early on a toplevel that still exists,
and the activation focus() then requests carries no fresh token, which
mutter turns into that notification.

hide() destroys the toplevel and show() maps a new one, so the tray's
Open, a second launch and the global shortcut all bring the bar back.
Linux only: Windows and macOS keep minimize().
On GNOME Wayland, switching the HUD to the vertical bar left its bottom
controls off screen: the window came out 648x1080 on a 1080p display and
the compositor kept its top-left where the horizontal one had been, so
it ran from y 186 to 1266, the record button under the dock and Open
Studio, language, hide and quit below the screen edge.

Wayland has no protocol for a client to learn where the shell's panels
are, so Chromium's screen.availHeight is the display's full height
there. The vertical tray asks for more than it can have, so it was
granted all 1080px: a window that cannot fit below GNOME's 32px top bar,
whose bottom controls stayed out of reach wherever it was dragged. And
mutter only moves a client-resized window back into the work area when
it fits there.

On Linux, when the platform reported the whole height as free, the HUD
now budgets 128px less (GNOME's top bar plus a bottom dock at Ubuntu's
largest icon size). The vertical window then fits: it can be dragged
fully on screen, and mutter's fully-onscreen constraint puts a flipped
tray back on screen when the window was inside the work area before.
X11, Windows and macOS report their panels and are unchanged, and so is
the horizontal tray.
@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7d23388d-2150-400d-a8b0-8f5f30d474f8
📥 Commits

Reviewing files that changed from the base of the PR and between 1b7ed86 and 3e26290.

📒 Files selected for processing: 6
  • electron/windows.hudHide.test.ts
  • electron/windows.ts
  • src/components/launch/LaunchWindow.test.tsx
  • src/components/launch/LaunchWindow.tsx
  • src/components/launch/hudGeometry.test.ts
  • src/components/launch/hudGeometry.ts

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 0 remain after this review.

📝 Walkthrough

The HUD hide action now hides on Linux and minimizes on Windows and macOS. HUD sizing now calculates available height with a Linux allowance when the reported work area matches or exceeds the display height.

Changes: HUD hide behavior

Layer / File(s) Summary
Platform-specific hide action
electron/windows.ts, electron/windows.hudHide.test.ts
The hide handler calls hide on Linux and minimize on Windows and macOS. Tests cover the platform-specific calls.

HUD available-height calculation

Layer / File(s) Summary
Available-height calculation and sizing
src/components/launch/hudGeometry.ts, src/components/launch/LaunchWindow.tsx, src/components/launch/hudGeometry.test.ts, src/components/launch/LaunchWindow.test.tsx
The geometry helper subtracts 128 pixels on Linux when availHeight is at least height. LaunchWindow uses the computed value and falls back to 1080 when it is not positive or window is unavailable. Tests cover work-area preservation and tray sizing.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Suggested reviewers: my-denia

Merge Risk: ⚪ Minimal · up to 3e262

The change makes the Linux HUD restorable from the tray and keeps the vertical bar on screen. No concrete merge-blocking risk was found. Manual verification on a real Wayland session is still advisable.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 6 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly summarizes the two main Linux HUD fixes: restoring the HUD from the tray and keeping the vertical bar on screen on Wayland.
Description check Passed The description follows the repository template and provides detailed summaries, issue context, change type, release impact, platform impact, testing results, known local dependency failures, and manu…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@EtienneLescot
EtienneLescot merged commit 880bfa0 into main Oct 15, 2026
19 checks passed
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