Skip to content

linux: Draw shadows and rounded corners for frameless windows#4181

Open
aiddya wants to merge 1 commit into
chromiumembedded:masterfrom
aiddya:frameless-window-wayland
Open

linux: Draw shadows and rounded corners for frameless windows#4181
aiddya wants to merge 1 commit into
chromiumembedded:masterfrom
aiddya:frameless-window-wayland

Conversation

@aiddya

@aiddya aiddya commented May 27, 2026

Copy link
Copy Markdown

Introduce CaptionlessFrameViewLinux to draw shadows and rounded corners for frameless windows on Linux. This matches the behavior of frameless windows on macOS and Windows.

CaptionlessFrameViewLinux extends FrameViewLinux to suppress the titlebar and round all four corners. Corner radii propagate from the frame view to the client view, which rounds the hosted web contents. Overlay positioning is offset by the new frame border insets so overlays stay within the client area.

@magreenblatt

Copy link
Copy Markdown
Collaborator

Review Comments

Good approach overall — extending FrameViewLinux and FrameViewLayoutLinux is the right architecture, reusing upstream shadow drawing, resize handling, and layout while only overriding what's needed. A few items:

  1. static_cast to aura::WindowTreeHostPlatform* in the CaptionlessFrameViewLinux constructor is fragile. If the window tree host implementation changes, this crashes silently. Consider dynamic_cast with a null check, or moving this logic to the call site where the concrete type is known (similar to how DesktopWindowTreeHostLinux::CreateFrameView() does it).

  2. remove_standard_frame = true on Linux — this changes the guard from IS_WIN-only to IS_WIN || IS_LINUX and removes the X11 SetUseOSWindowFrame(x11window, false) call. The old comment warned this "will result in window resize artifacts" on Linux. The PR description and test instructions only cover Wayland — worth verifying this doesn't regress X11 frameless windows.

  3. UpdateWebViewRoundedCorners runs on every Layout() call — the recursive traversal looking for WebView instances could be expensive for complex view hierarchies. Also, the flush-detection epsilon (kEpsilon = 1.0f) seems generous; a comment explaining why 1.0f was chosen would help.

  4. Test only asserts on WaylandWindowFramelessClientBounds guards the inset assertions with IsRunningOnWayland(). A smoke test on X11 would help guard against the remove_standard_frame change causing regressions.

  5. Minor: SetPaintToLayer() in UpdateWindowRoundedCorners creates a compositing layer that's never removed when corners become square (e.g., maximized). Low impact but worth noting.

The overlay offset fix via ConvertPointToWidget is correct and clean.

@aiddya

aiddya commented May 28, 2026

Copy link
Copy Markdown
Author
  1. As CaptionlessFrameViewLinux is only used on Linux, GetHost() will always return DesktopWindowTreeHostLinux or a subclass if a consumer customizes it. DesktopWindowTreeHostLinux extends aura::WindowTreeHostPlatform, the static_cast is safe here. If the tree host classes are refactored, that line of code will have to change anyway. Chromium does not allow dynamic_cast, and the call site does not have access to the concrete type. DesktopWindowTreeHostLinux::CreateFrameView() is within the same class, so it doesn't face the same problem.
  2. I have tested this on XWayland and I've confirmed that this works the same way as on Wayland. I'm using translucent widgets now, which should avoid black bars in transparent areas. I've previously made changes to DesktopWindowTreeHostLinux to set opaque regions correctly as a part of FrameViewLinux work. This should resolve any persistent artifacts. As for transient artifacts during resize, that's an inherent X11 problem without any solution.
  3. a. It's important to run UpdateWebViewRoundedCorners on every Layout for correctness, as the web view instances could change. This operation is not very expensive, it's just a walk over all views and computing some rects. Setting the corner radii eventually calls NativeViewHostAura::ApplyRoundedCorners(), which caches the radii. If the values are the same, the operation completes pretty quickly.
    b. The epsilon is 1px to account for rounding errors. Chromium does not snap views to a grid, so with some fractional scaling factors, there could be 1px difference in overlapping views. See Frameless window on Wayland has a white line on top electron/electron#51457 for an example. There's already a 1-line comment about this, but I can elaborate if necessary. I misremembered the details of the issue. The mismatch shows up after converting DIPs to display pixels. I'll remove epsilon here, it's not necessary while calculating with DIPs.
  4. The asserts in WindowFramelessClientBounds are valid only for Wayland and X11 compositors that support transparency. I could include X11 in the test too, but I'll have to bring in some X11 dependencies in tests to check for transparency. Is that okay?
  5. The predominant Chromium pattern is to retain the layer when radii go to 0, as this would avoid the churn to recreate the layer when the window is moved back to "restored" state. See ContentsWebView for example.

Introduce CaptionlessFrameViewLinux to draw shadows and rounded corners
for frameless windows on Linux. This matches the behavior of frameless
windows on macOS and Windows.

CaptionlessFrameViewLinux extends FrameViewLinux to suppress the titlebar
and round all four corners. Corner radii propagate from the frame view to
the client view, which rounds the hosted web contents. Overlay positioning
is offset by the new frame border insets so overlays stay within the
client area.
@aiddya
aiddya force-pushed the frameless-window-wayland branch from 6e06c31 to df67ebe Compare May 31, 2026 16:22
@aiddya

aiddya commented May 31, 2026

Copy link
Copy Markdown
Author

Removed epsilon and expanded tests to X11 with compositing support.

@aiddya

aiddya commented Jun 16, 2026

Copy link
Copy Markdown
Author

@magreenblatt Can you please take another look at this? I want to land this in 7871 if possible.

@magreenblatt

magreenblatt commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Follow-up review

I checked the latest update against the earlier review comments and found two blocking issues:

  1. [P1] Clear rounded corners for maximized and fullscreen windows

    FrameViewLayoutLinux::GetCornerRadii() does not clear its radius for maximized or fullscreen windows—only for tiled windows or when client-frame shadows are unsupported. CaptionlessFrameViewLayoutLinux::GetCornerRadii() expands that radius to all four corners, and Layout() applies it to both the client layer and hosted WebViews. Maximized/fullscreen frameless windows will therefore retain clipped, transparent content corners. Please explicitly use empty radii for those states before updating the client.

  2. [P1] Do not equate an X11 compositor with decoration-inset support

    The production code enables the 10-DIP shadow border only when both CanSetDecorationInsets() and window compositing are supported. IsRunningOnX11WithCompositor() checks only whether _NET_WM_CM_S* has an owner. For example, Chromium deliberately returns false from X11Window::CanSetDecorationInsets() under Xfce even when its compositor is running. The test condition is then true while the fallback frame has a zero top inset and four-DIP side/bottom insets, causing the new assertions to fail. Please query the same effective capability or keep X11 as a smoke test without the 10-DIP assertions.

Status of the earlier comments:

  • The static_cast is unchanged. The current Linux host invariant makes it work, but aura::WindowTreeHostPlatform::GetHostForWindow() would address the maintainability concern without RTTI.
  • X11 frame handling was manually tested under XWayland and moved to remove_standard_frame; broadly addressed.
  • The recursive layout traversal remains with a reasonable caching explanation; the unnecessary epsilon was removed.
  • X11 test coverage was added, but currently has the capability mismatch above.
  • Retaining the client layer is consistent with the referenced Chromium pattern.

The branch is also 28 commits behind current master. GitHub reports it mergeable and the newer commits do not overlap these six modified files, but please rebase.

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.

2 participants