On Wed, 1 Oct 2025 16:40:34 GMT, Michael Strauß <[email protected]> wrote:

>> Or maybe even make it more generic: detect when (a small number of) 
>> additional layout passes are needed and do them right away instead of 
>> waiting for another pulse?
>
> That's exactly what this old PR does.

> When a situation like this happens in reality, we might see a momentary 
> flicker due to the layout spanning several pulses, correct?

Well, if layout runs (due to a significant change), you'll see components be 
re-arranged, and if a 2nd pulse is needed, you would probably not notice as 
things were moved around a lot anyway.  But on top of that, there is a good 
chance the 2nd pass is just recalculating everything without actually changing 
anything because it is often triggered without a good reason.  For example:

Take an HBox for example.  During layoutChildren, it will position its 
children.  If this involves moving a child to the right or left because an 
earlier child has shrunk/grown then layout X is changed and triggers the logic 
in Node (without good reason I might add).  This is in part because HBox does 
not update or set the "current layout child" at all (none of the containers do 
this, except Parent's layoutChildren which is almost always overridden).  So 
this code below in Node will trigger and force another layout pass:

                    if (p != null && !p.isCurrentLayoutChild(Node.this)) {
                        if (isManaged()) {
                            // Force its parent to fix the layout since it is a 
managed child.
                            p.requestLayout(true);
                        } else {
                            // Parent size changed, parent's parent might need 
to re-layout
                            p.clearSizeCache();
                            p.requestParentLayout();
                        }
                    }
                    
All the ingredients match:
- LayoutX was modified on a child
- Its parent is not `null` (it's the HBox)
- It is not the current layout child (HBox doesn't update this before modifying 
a position on a child)
- The child in question is managed (all children in an HBox generally are)

End result: schedule another layout pass

Now, if in the 2nd pass none of the X (or Y) positions change again, then this 
2nd pass will end up doing nothing.  Quite wasteful.

> The platform itself can't really do anything, except for the application code 
> to call the layout() explicitly to avoid flicker, right?

Calling `layout` won't do much when the flags are bad, as layout basically 
operates based on those flags.  So if you call layout at the root, and the 
flags say that it is `CLEAN` then it stops right there.  

However there are many things that will "fix" the situation; this can be a 
nearby Node that changes size for some reason, or say the user resizing the 
Window.  Generally, you will almost never notice as often something triggers 
layout again, fixing the flags, but if say a custom control is careful about 
when to redo calculations (because they're even more expensive than usual) and 
uses tricks like `setNeedsLayout(true)` then a part of the UI may not get 
updated as you'd expect as the flags got into a bad state.  

Also see the long note on top of this PR.... the way the flags are managed, and 
the way that Parent allows `requestLayout` to be overridden by children (really 
bad design there), it is still possible to mess up the flags.  All this PR does 
is remove one of the ways (I'd remove the other way as well, but it would mean 
making `requestLayout` final).

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

PR Review Comment: https://git.openjdk.org/jfx/pull/1879#discussion_r2395215058

Reply via email to