On Wed, 8 Apr 2026 17:58:25 GMT, Martin Fox <[email protected]> wrote:
>> This PR enables translucent window backdrops for JavaFX stages on macOS and >> Windows 11. Since we’re reliant on the operating system for these effects >> (they typically require real-time blurring of the desktop) I needed to flesh >> out a fairly complete prototype to sort out the API. I will start a >> discussion about the API on the mailing list. >> >> There’s a crude manual test for trying out the different backdrop materials. >> >> java @build/run.args -Djavafx.enablePreview=true >> tests/manual/stage/BackdropTest.java >> >> You’ll want to drag the windows around to avoid having them overlap each >> other since they’re all created in the center of the screen. For windows >> without title bars you can click anywhere on the background to drag the >> window except for TRANSPARENT stages on Windows which are a bit tricker to >> get a hold of; try to click on a text label. >> >> If you create an UNDECORATED stage on Windows the backdrop won’t be >> translucent initially. This can be corrected by changing the stage’s color >> scheme. This is an OS bug that I haven’t found a workaround for. >> >> The changes on Windows 11 are minimal since we’re just invoking an OS >> feature by calling DwmSetWindowAttribute. I did need to make two small >> changes to the D3D9 Prism code to ensure that the swap chain and back buffer >> support an alpha channel so JavaFX can composite its content on top of the >> backdrop. This is the same way the old UNIFIED stage style worked before it >> became unreliable (see >> [JDK-8154847](https://bugs.openjdk.org/browse/JDK-8154847)). >> >> On macOS I moved the GlassHostView so it’s now a permanent part of the >> NSWindow. For some time the host view has been a remnant left over from an >> older approach to implementing fullscreen. Now it serves as a common parent >> for the NSVisualEffectView that provides the backdrop and the GlassView3D >> that contains the JavaFX content. Making it the permanent contentView of the >> NSWindow simplifies some code. >> >> To validate the API I did prototype this for Windows 10 (thanks @mstr2!). >> Well, I prototyped this using DirectComposition so it should work on Win10 >> but I can't test Win10 myself. Using DirectComposition is much more involved >> so I shelved that implementation for now but it does inform the API. It’s >> the reason the backdrop needs to be specified before the Java window is >> shown and the platform window created. > > Martin Fox has updated the pull request with a new target base due to a merge > or a rebase. The pull request now contains eight commits: > > - Merge remote-tracking branch 'upstream/master' into osbackdrop > - Backdrops are now objects created by specifying a material. The > list of materials is now open-ended. > - Merge remote-tracking branch 'upstream/master' into osbackdrop > - Merge remote-tracking branch 'upstream/master' into osbackdrop > - Merge remote-tracking branch 'upstream/master' into osbackdrop > - Removed unused import > - Merge remote-tracking branch 'upstream/master' into osbackdrop > - OS supplied translucent window backdrops The proposed API feels very stringly-typed, and I'm not sure if that's a good model. Specifically, I'm looking at future enhancements that expose configuration options which are available on some [platforms](https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/ui/apply-mica-win32) and which we might want to support. I've played around with your code for a bit and came up with a slightly different idea of how we could design an API. Feel free to criticize or dismiss: // Public API: public sealed interface StageBackdrop permits DefaultStageBackdrop, PlatformStageBackdrop { // Default backdrops are available as static constants StageBackdrop WINDOW = DefaultStageBackdrop.WINDOW; StageBackdrop PARTIAL = DefaultStageBackdrop.PARTIAL; /** * {@return the name of the backdrop} */ String name(); // Potential future enhancement: /** * {@return a backdrop with the specified option} * * @throws NullPointerException if {@code key} or {@code value} is {@code null} * @throws IllegalArgumentException if the option is not supported by this backdrop */ StageBackdrop withOption(String key, Object value); /** * {@return all platform backdrops supported on this system} * * For systems where backdrops are not supported this will be an empty list. */ static List<StageBackdrop> getPlatformBackdrops() { return PlatformStageBackdrop.BACKDROPS; } } // Platform-independent implementations: public enum com.sun.javafx.stage.DefaultStageBackdrop implements StageBackdrop { WINDOW, PARTIAL } // Named platform implementations: public record com.sun.javafx.stage.PlatformStageBackdrop(String name) implements StageBackdrop { public static final List<StageBackdrop> BACKDROPS = Toolkit.getToolkit().getBackdropMaterials().stream() .map(name -> (StageBackdrop)new PlatformStageBackdrop(name)) .toList(); } `StageBackdrop.getPlatformBackdrops()` would only return the platform-prefixed named backdrops, not the two platform-independent variants. Users would only interact with `StageBackdrop` objects, not with strings. This also gets rid of the "material" terminology, which I find a bit confusing (I ask the backdrop for a list of materials, and then turn a material back into a backdrop?). The only way to obtain a `StageBackdrop` is to use a static default instance, choose one of the platform-provided backdrops, or potentially in the future start with a platform-provided backdrop, and derive a new variant with options from it. Backdrop objects are always immutable. Here's how the API could be used: // Default backdrop stage.initBackdrop(StageBackdrop.WINDOW); // Platform-specific backdrop with default fallback stage.initBackdrop(StageBackdrop.getPlatformBackdrops().stream() .filter(b -> b.name().equals("Windows.Transient")) .findFirst() .orElse(StageBackdrop.WINDOW)); // Configurable backdrop with default fallback stage.initBackdrop(StageBackdrop.getPlatformBackdrops().stream() .filter(b -> b.name().equals("Windows.Mica")) .map(b -> b.withOption("TintColor", Color.RED)) .findFirst() .orElse(StageBackdrop.WINDOW)); ------------- PR Comment: https://git.openjdk.org/jfx/pull/2048#issuecomment-4400561734
