On Fri, 18 Sep 2026 19:55:06 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.
>> 
>> ---------
>> - [x] I confirm that I make this contribution in accordance with the 
>> [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai).
>
> Martin Fox has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Fixed some bugs in how window flags are set up.

modules/javafx.graphics/src/main/java/com/sun/glass/ui/Window.java line 807:

> 805:     }
> 806: 
> 807:     public boolean emulateBackdrop() {

`emulateBackdrop` makes it sound like the method emulates a backdrop. Maybe 
something along the lines of `isEmulatedBackdrop` could make the meaning 
clearer.

modules/javafx.graphics/src/main/java/com/sun/glass/ui/mac/MacWindow.java line 
253:

> 251:     }
> 252: 
> 253:     private static Map<String, Integer> backdropStyles = null;

You could initialize the style map directly, which would remove the need to 
call `initBackdropStyles()` in several places:

Suggestion:

    private static Map<String, Integer> backdropStyles = Map.ofEntries(
        Map.entry("macOS.HUD", BackdropID.HUD),
        Map.entry("macOS.Menu", BackdropID.MENU),
        Map.entry("macOS.Popover", BackdropID.POPOVER),
        Map.entry("macOS.Tooltip", BackdropID.TOOLTIP)
    );

modules/javafx.graphics/src/main/java/com/sun/glass/ui/mac/MacWindow.java line 
279:

> 277:     public static List<String> getPlatformBackdropStyleNames() {
> 278:         initBackdropStyles();
> 279:         return Collections.unmodifiableList(new 
> ArrayList<>(backdropStyles.keySet()));

While this works, I believe it technically relies on implementation details. 
The `HashMap` class documentation states that no guarantee regarding the order 
of its mappings is given; in particular, the documentation states that the 
order may change _over time_ (whatever this means).

Callers of `StageBackdropStyle.getPlatformStyleNames()` end up here, and 
they're given a new list for every call. When called and indexed in a loop, 
this could _very hypothetically_ lead to incorrect indexing of the list 
elements.

The cleanest solution is probably to give callers the same list instance every 
time.

modules/javafx.graphics/src/main/java/com/sun/glass/ui/mac/MacWindow.java line 
320:

> 318:     @Override
> 319:     public void setBackdropOption(String name, Object option) {
> 320:         if (name == "TintColor") {

These strings come from application code, so we're not guaranteed to receive 
interned strings here. Use `equals` here and in other places to be on the safe 
side.

modules/javafx.graphics/src/main/java/com/sun/glass/ui/win/WinWindow.java line 
467:

> 465:         var preferences = Platform.getPreferences();
> 466:         var highcontrast = preferences.get("Windows.SPI.HighContrast");
> 467:         if (highcontrast instanceof Boolean hc) {

Suggestion:

        return highcontrast == Boolean.TRUE;

modules/javafx.graphics/src/main/java/com/sun/javafx/stage/PlatformStageBackdropStyle.java
 line 36:

> 34:  */
> 35: public final class PlatformStageBackdropStyle implements 
> StageBackdropStyle {
> 36:     public String name;

Here and in all new files: we usually use an empty line after the opening brace.

modules/javafx.graphics/src/main/java/com/sun/javafx/stage/StageBackdropHelper.java
 line 36:

> 34:  */
> 35: public class StageBackdropHelper {
> 36:     private static final StageBackdropHelper theInstance;

1. You can remove this field, it's not used.
2. The class should be final and have a private constructor, as the simple 
private accessor pattern doesn't permit polymorphic helpers/accessors (that 
would need to be implemented differently).

modules/javafx.graphics/src/main/java/com/sun/javafx/stage/StageBackdropHelper.java
 line 53:

> 51:     public static void setStageBackdropAccessor(final 
> StageBackdropAccessor newAccessor) {
> 52:         if (stageBackdropAccessor != null) {
> 53:             throw new IllegalStateException();

That's not an illegal state (a private-access helper has no state), it's a 
violated invariant. Most private-access helper don't bother checking things 
like this.

modules/javafx.graphics/src/main/java/javafx/stage/StageBackdropStyle.java line 
119:

> 117:      *  backdrop styles
> 118:      */
> 119:     public static List<String> getPlatformStyleNames() {

I'd start with minimal API first, then only add more if there's an established 
use case. So `getPlatformStyleNames` and `getStandardStyles` would be on my 
chopping block, as these are easily reproducible by application developers.

modules/javafx.graphics/src/main/java/javafx/stage/StageBackdropStyle.java line 
140:

> 138: 
> 139:     /**
> 140:      * Creates an optional platform backdrop style for the specified 
> name.

I don't think we need to guarantee `Creates`. `Gets` is sufficient.

modules/javafx.graphics/src/main/java/javafx/stage/StageBackdropStyle.java line 
145:

> 143:      * @return the optional backdrop style
> 144:      */
> 145:     public static Optional<StageBackdropStyle> style(String name) {

Some alternatives for consideration: `ofNamed`, `ofPlatformName`

-------------

PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160566123
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160286795
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160793153
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160479719
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160527931
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160428473
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160376264
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160416354
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160634907
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160722928
PR Review Comment: https://git.openjdk.org/jfx/pull/2048#discussion_r4160660889

Reply via email to