JDK-8298796 : JavaFX SwingNode does not always render initially on Windows
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 10,11,17,19,20,21
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: windows
  • Submitted: 2022-12-14
  • Updated: 2023-10-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
To reproduce, run the attached test program on a Windows platform using a recent JDK + JavaFX. For example, it reproduces using JDK 19 + JavaFX 19 and also reproduces using the latest JDK 20 ea and JavaFX 20 ea.

1. Run the program: "java SimpleSwingNodeTest"

2. BUG: The Swing content in the SwingNode will not initially be displayed. See "SwingNode-Windows-initial.png".

3. Mouse over the black rectangle where the label and button should be

4. BUG: The JButton is now displayed, but the JLabel is not. See SwingNode-Windows-2.png

5. Maximize and then restore the window using the window decoration controls

6. It will now be drawn correctly. See SwingNode-Windows-final.png.

NOTE: This was originally filed as JDK-8193103, which was closed as a duplicate of JDK-8170386, and that bug was later closed as Incomplete.

Note also that on a Hi-DPI Windows system the text in the SwingNode is blurry, so I'll file a separate bug (against javafx.swing rather than client-libs).
Comments
Please also see discussion in https://github.com/openjdk/jdk/pull/15960 it looks like the issue may not be limited to initial state, but also when the layout changes due to user input (in the case of that PR, changing the size of the button). I wonder if there might be a problem in the way the damage region in swing is communicated to FX or something like that.
12-10-2023

mach5 build was failing as it was release build whereas local build was debug build mach5 release build is having issues but debug build is passing for 20+ iterations. Here's the mach5 debug build job in case someone needs to try (can someone please confirm?) https://mach5.us.oracle.com/mdash/buildIds/2023-04-03-0521593.prasanta.sadhukhan.jdk local release build is having issues unlike debug build so it seems to be some timing related issue
03-04-2023

I am using latest jdk build locally.. If you are unable to build latest jdk locally due to paucity of time or whatever reason, I can provide a mach5 build of my repo and you can try the jdk build, it you like to do thatway... It seems mach5 build of my repo is not working...probably VS is the problem..I am using VS2019 locally.. Tried with JIB build (with VS2022) of my repo locally and it works with same command for 30+ iterations.. Not sure why mach5 build of same repo is not working (fails 10 of 10 as if fix doesn't have any effect). Even tried changing mach5 default build platform from Windows2016 server to Windows10 through task definitions file but still fails on mach5 build..
28-03-2023

I tried with USE_JPANEL=true on windows 10 (with default system scalefactor 125%) and I am unable to reproduce the issue even in 30+ consecutive iterations of the test run and I could see JButton rendered immediately.. My command is ./jdk/bin/java @E://ade/javafx//jfx//rt//build//run.args SimpleSwingNodeTest Which platform you see the issue?
27-03-2023

I'm also using Windows 10 with the default 125% scale factor. What version of the JDK were you testing on? I was using JDK 19.0.2.
27-03-2023

OK...It does work for me all the time, which is why I proposed...Any difference in execution(like USE_JPANEL true or false) when it fails or is it like if you draw 10 times under same circumstances, it will fail 1-2 times..(although I have many debug statements that might be circumventing the race condition and make it works all the time)
24-03-2023

It fails slightly more often with USE_JPANEL=true, but it does fail occasionally with USE_JPANEL=false. And yes, running the same command 10 or 15 times in a row will see maybe 1 or 2 failures.
24-03-2023

It doesn't appear that there are any changes in FX for that build that could impact this. I tried your above proposed patch, and while it makes it better, it isn't a solid fix. Even the button still fails to be drawn occasionally (although it is drawn most of the time). It feels like there is some sort of race condition and your fix makes it more likely to avoid it, but we still need a root cause.
23-03-2023

As mentioned above in Jan, SwingNode rendering issue started happening in jdk10b31 and in clientlibs we have JDK-8159062: [hidpi] DnD on Windows while scaling is non-integer Would be nice to know if there is any fix in FX in that build that can be a suspect..
23-03-2023

On the FX side, the following SwingNode fix went into JDK 9 b139: JDK-8162551: SwingNode scaling doesn't work I suspect this might be relevant. If it is, then it might be worth seeing whether you can fix the JLabel case as well. If you aren't able to fix the JLabel case, then it might be OK to fix the rest and address that with a follow-up fix. I do have a question about your proposed fix: Are there any drawbacks you can think of if we unconditionally call activateLwFrame?
23-03-2023

As per my testing, issue with JLabel predates JButton issue and happens in jdk9 too (so the root cause is different) I see it passes in b138 and started to fail in b139 and only client fix is JDK-8165263: Remove code in MetaData that hacks into private fields of Collections implementation classes which I am not sure how will it affect this behaviour so I think we probably can fix JButton (and other non-JLabel) widgets by above patch and create a separate issue for JLabel [~kcr] Please let me know your opinion
23-03-2023

The following patch helps in rendering JButton in SwingNode [modules/javafx.swing/src/main/java/javafx/embed/swing/SwingNode.java] ============ @@ -267,9 +267,6 @@ public class SwingNode extends Node { setEventHandler(KeyEvent.ANY, new SwingKeyEventHandler()); setEventHandler(ScrollEvent.SCROLL, new SwingScrollEventHandler()); - focusedProperty().addListener((observable, oldValue, newValue) -> { - activateLwFrame(newValue); - }); //Workaround for RT-34170 javafx.scene.text.Font.getFamilies(); @@ -390,9 +387,7 @@ public class SwingNode extends Node { SwingNodeHelper.runOnFxThread(() -> { locateLwFrame();// initialize location - if (focusedProperty().get()) { activateLwFrame(true); - } }); } } ======== It seems when we activate the LightweightFrame, it sends java.awt.event.WindowEvent[WINDOW_ACTIVATED] event which will cause java.awt.event.WindowEvent[WINDOW_GAINED_FOCUS] event to be generated and subsequently java.awt.event.FocusEvent[FOCUS_GAINED] event for JButton This will call JLightweightFrame paint() which calls notifyImageUpdated() which calls SwingNodeHelper.repaintDirtyRegion to repaint the dirty region and JButton is rendered but the same doesn't work on JLabel as JLabel cannot get keyboard focus As per https://github.com/openjdk/jdk/blame/master/src/java.desktop/windows/native/libawt/windows/awt_Window.h#L197 SynthesizeWmActivate() is not dependent on widget having focus, it seems to be having an effect if window is visible and not iconed so not sure why focus state was check before calling activateLwFrame, but this check was there from initial port of SwingNode (maybe we dont need it only for windows pltaform currently)
15-03-2023

Creating an artificial PAINT PaintEvent in JLightweightFrame apparently does not help sun.awt.PaintEventDispatcher.getPaintEventDispatcher().createPaintEvent(this,0, 0, d.width, d.height);
01-03-2023

Well, it was backed out in JDK21 actually so jdk19 and jdk20 will have the problematic fix. But I dont think they are related as that bug is about processing multiple PaintEvents whereas this is about missing PAINT event from SwingNode. Also, if that would have affected apps, being in 2D, it would have affected normal swing apps too, which it has not apparently, at least no open bugs on that.. Also, it does not work even if I run with -Dsun.java2d.noddraw=true ie without D3D If I change this implementation https://github.com/openjdk/jdk/blob/master/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java#L363-L373 ie do the PAINT even for UPDATE PaintEvent, it works so basically a native Paint event is missing somehow from SwingNode if (!isLayouting) { paintArea.paint(target,shouldClearRectBeforePaint()); } but it's not evident as to why JDK-8159062 changes making JDK conform to integer-coordinate is causing SwingNode to miss PAINT event
28-02-2023

It's not directly related. JDK-8275715 was fixed in 19, and due to regressions (similar in nature to this bug, but not quite the same), it was backed out in 20 by JDK-8298876. So only JDK 19 has the problematic fix.
27-02-2023

Could this issue be related to JDK-8275715 D3D pipeline processes multiple PaintEvent at initial drawing or JDK-8299436 [REDO] D3D pipeline processes multiple PaintEvent at initial drawing ?
27-02-2023

Event handled by SimpleSwingNode (this issue) ===================== java.awt.event.ComponentEvent[COMPONENT_MOVED (373,150 148x42)] on frame0 java.awt.event.ComponentEvent[COMPONENT_RESIZED (373,150 148x42)] on frame0 java.awt.event.ComponentEvent[COMPONENT_MOVED (373,150 148x42)] on frame0 java.awt.event.ComponentEvent[COMPONENT_RESIZED (373,150 148x42)] on frame0 java.awt.event.PaintEvent[UPDATE,updateRect=java.awt.Rectangle[x=0,y=0,width=148,height=42]] on frame0 nothing is shown. When mouse is moved over swing components, additional events are which makes the widgets visible java.awt.event.MouseEvent[MOUSE_ENTERED,(22,42),absolute(395,192),button=0,clickCount=0] on frame0 java.awt.event.MouseEvent[MOUSE_MOVED,(25,35),absolute(398,186),clickCount=0] on frame0 java.awt.event.MouseEvent[MOUSE_MOVED,(26,30),absolute(399,180),clickCount=0] on frame0 java.awt.event.MouseEvent[MOUSE_MOVED,(2,26),absolute(375,177),clickCount=0] on frame0 java.awt.event.MouseEvent[MOUSE_EXITED,(-10,30),absolute(363,180),button=0,clickCount=0] on frame0 When window is maximised and restored, then additional events which cause the widgets to be visible java.awt.event.ComponentEvent[COMPONENT_MOVED (5,81 148x42)] on frame0 java.awt.event.ComponentEvent[COMPONENT_MOVED (5,81 148x42)] on frame0 java.awt.event.ComponentEvent[COMPONENT_RESIZED (5,81 148x42)] on frame0 java.awt.event.ComponentEvent[COMPONENT_MOVED (5,81 148x42)] on frame0 java.awt.event.ComponentEvent[COMPONENT_MOVED (5,81 148x42)] on frame0 java.awt.event.ComponentEvent[COMPONENT_RESIZED (5,81 148x42)] on frame0 java.awt.event.PaintEvent[PAINT,updateRect=java.awt.Rectangle[x=0,y=0,width=0,height=0]] on frame0 Event handled by BlurrySwingNode (which have widgets visible after momentary blackness) ===================== java.awt.event.ComponentEvent[COMPONENT_RESIZED (338,334 816x152)] on frame0 java.awt.event.ComponentEvent[COMPONENT_MOVED (338,334 816x152)] on frame0 java.awt.event.ComponentEvent[COMPONENT_RESIZED (338,334 816x152)] on frame0 java.awt.event.MouseEvent[MOUSE_ENTERED,(475,78),absolute(813,413),button=0,clickCount=0] on frame0 java.awt.event.MouseEvent[MOUSE_MOVED,(475,78),absolute(813,413),clickCount=0] on frame0 java.awt.event.WindowEvent[WINDOW_ACTIVATED,opposite=null,oldState=0,newState=0] on frame0 sun.awt.TimedWindowEvent[WINDOW_GAINED_FOCUS,opposite=null,oldState=0,newState=0] on frame0 java.awt.event.ComponentEvent[COMPONENT_MOVED (338,334 816x152)] on frame0 java.awt.event.ComponentEvent[COMPONENT_MOVED (338,334 816x152)] on frame0 java.awt.event.ComponentEvent[COMPONENT_RESIZED (338,334 816x152)] on frame0 java.awt.event.FocusEvent[FOCUS_GAINED,permanent,opposite=null,cause=ACTIVATION] on frame0 java.awt.event.PaintEvent[UPDATE,updateRect=java.awt.Rectangle[x=0,y=0,width=816,height=152]] on frame0 java.awt.event.PaintEvent[PAINT,updateRect=java.awt.Rectangle[x=0,y=0,width=0,height=0]] on frame0 java.awt.event.PaintEvent[PAINT,updateRect=java.awt.Rectangle[x=0,y=0,width=0,height=0]] on frame0 so it seems apparently a PaintEvent[PAINT] event is missing for SimpleSwingNode upfront...
27-02-2023

> I'm not sure how using absolute coordinates enters into this I'm also not sure but as I mentioned above, JDK-8159062 changes only non-absolute coordinates (ScaleUpX, ScaleUpY, ScaleDownX, ScaleDownY) which caused the problem to first surface but if I retain only those same methods and make other methods (scaleUpAbsX, ScaleUpAbsY, scaleDownAbsX, scaleDownAbsY) back to pre-JDK-8159062 in latest jdk, it works in latest jdk. It only fails if we change these absolute coordinate methods (scaleUpAbsX, ScaleUpY, ScaleUpAbsY) but it might be a red herring to pursue this line.. Anyways, I found that if we move the frame slightly or move the mouse over the JLabel/JButton then those are displayed as it calls SwingNode.repaintDirtyRegion (which is not called when swing content is first displayed) ============= at javafx.swing/javafx.embed.swing.SwingNode$2.repaintDirtyRegion(SwingNode.java:187) at javafx.swing/com.sun.javafx.embed.swing.SwingNodeHelper.repaintDirtyRegion(SwingNodeHelper.java:108) at javafx.swing/com.sun.javafx.embed.swing.newimpl.SwingNodeInteropN$SwingNodeContent.imageUpdated(SwingNodeInteropN.java:306) at jdk.unsupported.desktop/jdk.swing.interop.LightweightContentWrapper$LightweightContentProxy.imageUpdated(LightweightContentWrapper.jav a:131) at java.desktop/sun.swing.JLightweightFrame.notifyImageUpdated(JLightweightFrame.java:331) at java.desktop/sun.swing.JLightweightFrame$3$1.run(JLightweightFrame.java:358) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714) ============ Maybe a paint event is lost when it is made visible? How to find if FX event is getting lost? Also, since JDK-8159062 deals with coordinate change (guess making jdk integer coordinate aware) I guess it will unlikely be caused because of lost event
23-02-2023

I'm not sure how using absolute coordinates enters into this. Have you tried instrumenting the code on both the JDK and FX side to see whether the values are coming out wrong or whether an event is getting lost?
22-02-2023

From http://hg.openjdk.java.net/jdk10/master/rev/fc3ec7e40a12 commit, If we only make ScaleUpX, ScaleUpY, ScaleDownX, ScaleDownY use value -= 0.5 to calculate ceil(value), it does not fail in latest jdk code with FX In latest JDK code, it seems FX fails only if scaleUpAbsX, ScaleUpY, ScaleUpAbsY together are using this value -= 0.5 to calculate ceil(value) If coordinates are not using this "value -= 0.5" calculation it does not fail so it seems this commit https://github.com/openjdk/jdk/commit/be635258fa0b7c25441ab23ff9ec0f86655dc5ca for JDK-8211999 has enhanced JDK code to use absolute coordinates (as compared to jdk10b31) which is not making it fail if only normal non-absolute coordinates are used (as in http://hg.openjdk.java.net/jdk10/master/rev/fc3ec7e40a12) As of now, I am not sure how to make FX use absolute coordinates to make this work..
21-02-2023

Seems to be a regression of JDK-8159062: [hidpi] DnD on Windows while scaling is non-integer for commit http://hg.openjdk.java.net/jdk10/master/rev/fc3ec7e40a12 specifically this change =================== -int AwtWin32GraphicsDevice::CheckIntLimits(double value) +int AwtWin32GraphicsDevice::ClipRound(double value) { + value -= 0.5; ===================== Since no regression is observed in client awt/swing apps, guess something needs to be done in FX side..
20-01-2023

Seems to be failing from jdk10b31 onwards..
05-01-2023

I can confirm that this is present in JDK 11. It does not happen with JDK 8.
04-01-2023

>and I'm pretty sure was present in JDK 11) [~kcr] Can you please confirm if this was present in jdk11, jdk8 too?
04-01-2023

[~psadhukhan] it is quite likely that this is a client-libs bug, even though it only happens when running JavaFX + SwingNode. I think it makes more sense to keep it in the client-libs component, but either way, you will need a JavaFX setup to debug it.
03-01-2023

I do not have FX setup so running via java does not run the test ------------- Error: Could not find or load main class SimpleSwingNodeTest Caused by: java.lang.NoClassDefFoundError: javafx/application/Application ----------------- Is it possible to provide a simple swing testcase? till that time, I am putting this JBS issue into "javafx" component..
02-01-2023

I do not have FX setup so running via java does not run the test ------------- Error: Could not find or load main class SimpleSwingNodeTest Caused by: java.lang.NoClassDefFoundError: javafx/application/Application ----------------- Is it possible to provide a simple swing testcase? till that time, I am putting this JBS issue into "javafx" component..
02-01-2023

The issue you describe is not directly related, since this bug happens at least as far back as JDK 17 (and I'm pretty sure was present in JDK 11). It could be indirectly related, so if you file a bug for your issue, you might link it to this one.
14-12-2022

I wonder another issue might be related: a Swing program does not repaint its window coming out of Windows sleep. It started to happen with java19, upgraded from possibly java17 (not sure), on Windows 10.
14-12-2022