On Mon, 15 Dec 2025 18:53:59 GMT, Andy Goryachev <[email protected]> wrote:

>> When a Window is created with a certain X/Y coordinate to place it on a 
>> specific screen, and is subsequently shown for the first time, one of the 
>> first things it does is size the window according to the size of the Scene.  
>> It does this based on the render scale of the *primary* screen as it has not 
>> moved the peer yet to the correct screen.  After the scene has been sized, 
>> it is moved to the correct screen, triggering a change of render scale, but 
>> not a resizing of the Window (as this is only done once).
>> 
>> The result of this is that due to slight difference in render scale, the 
>> size calculated for the scene may be a few pixels off.  As the scene's 
>> preferred size is used for this calculation, even a few pixels too small can 
>> result in Labels being shown with ellipsis on the intended target screen 
>> with a different render scale.
>> 
>> When observing the render scale X or Y property, one can observe a change 
>> from 1.0 (the default value) to 2.0 (the primary screen's render scale) to 
>> another value (depending on the target screen).  However, the Window 
>> involved (being positioned by the user using setX()/setY() before it is 
>> shown) was never shown on the primary screen, yet the size calculation 
>> assumed it was.
>> 
>> To solve this problem, the peer should be moved to the correct screen 
>> **before** asking the Scene for its preferred size to use as the initial 
>> Window size.  Doing so (by adding an additional `applyBounds` call) also 
>> results in the render scale properties to only change once (or not at all) 
>> from their default value to the target screen's value (or not at all if the 
>> target screen is 1.0 scale).
>
> This fix introduces another issue in the monkey tester, breaking the layout 
> (see the screenshot below).  The failure can be seen when the MT window 
> appears on the primary (scale=2) as well as on the secondary (scale=1) 
> monitor, running macOS 26.1.  
> 
> The layout gets fixed when the user resizes the window.
> 
> Interestingly, moving the window to another screen with a different scale 
> **does not** fixes the issue.
> 
> <img width="1380" height="623" alt="Screenshot 2025-12-15 at 10 47 46" 
> src="https://github.com/user-attachments/assets/0af65495-7e28-428d-9001-a94c68917833";
>  />
> 
> More observations:
> - it does fixes the menu bar issue mentioned in 
> https://github.com/openjdk/jfx/pull/1945#pullrequestreview-3385140013
> - also tested in combination with #1945 , the layout issue is present in the 
> combined version

@andy-goryachev-oracle  Well, this is going a bit beyond what I'm trying to 
fix.  I don't see any of the issues you're showing, not with test programs, nor 
with MonkeyTester.  In fact, I saw several positive things after applying this 
fix (Windows are no longer sized with unused empty space when immediately shown 
on a different monitor).

As this again seems to be Mac specific, I have very limited means to "fix" this 
further, so perhaps you could have a look yourself.  I've added some debug 
output that will be helpful (you can share it here).  Look specifically at what 
`setBounds` is called with.

MonkeyTester is setting X/Y/width/height of its Window explicitly when it has 
some settings stored from a previous run.  This means it generally follows a 
slightly different code path when the window is shown, since all the "explicit" 
flags for x, y, width and height will be true.  Still, that doesn't explain how 
you get some unused empty space.

Here's an example of the output on my system, where MonkeyTester is shown on 
the 1.0 monitor on the right side of a 1.5 monitor:


Window/invalidationListener: shown changed to: true
Window/invalidationListener: screen=javafx.stage.Screen@21e4df3b 
bounds:Rectangle2D [minX=0.0, minY=0.0, maxX=2560.0, maxY=1440.0, width=2560.0, 
height=1440.0] visualBounds:Rectangle2D [minX=0.0, minY=0.0, maxX=2560.0, 
maxY=1400.0, width=2560.0, height=1400.0] dpi:93.0 outputScale:(1.5,1.5)
Window/peer: setBounds(2698.0, 61.0, true, true, winW:1463.0, 708.0, 
clientW:-1.0, -1.0, 0.0, 0.0, rsx:0.0, rsy:0.0)
Window/invalidationListener: after applying bounds 
screen=javafx.stage.Screen@55e0e86c bounds:Rectangle2D [minX=2560.0, 
minY=-194.0, maxX=4480.0, maxY=1006.0, width=1920.0, height=1200.0] 
visualBounds:Rectangle2D [minX=2560.0, minY=-194.0, maxX=4480.0, maxY=1006.0, 
width=1920.0, height=1200.0] dpi:94.0 outputScale:(1.0,1.0)
Window/invalidationListener: output scale used before sizing scene: 1.0
Window/invalidationListener: size from scene: 517.0x2646.0
Window/peer: setBounds(2698.0, 61.0, true, true, winW:1471.0, 727.0, 
clientW:-1.0, -1.0, 0.0, 0.0, rsx:1.0, rsy:1.0)
Window/invalidationListener: exit invalidation listener

What you see above here is that initially the window screen is still the 
primary screen (at minXY=0,0); after `applyBounds` this changes to the correct 
screen.  The scene size code is then called with the correct values (render 
scale 1.0).  The scene size is however a bit weird; it is very wide, probably 
because there are many controls in your Scene that have a wide preferred width. 
 It's possible this is somehow the cause of that empty space -- still, on my 
system, those values are unused as MonkeyTester sets its own width/height, 
which you can see in the final `setBounds` call -- effectively, the scene 
sizing is ignored, and it should re-layout with the final size.

Come to think of it, the scene size call is basically superfluous; if 
width/height is explicit, we could skip that completely.

Anyway, let me know what you find.  I'm not seeing any issues with the above 
outputs, but perhaps something odd pops up on your system that may point us in 
the right direction.

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

PR Comment: https://git.openjdk.org/jfx/pull/2007#issuecomment-3659265912

Reply via email to