RFR: 8360940: Layout stops updating when using Parent#setNeedsLayout(true) due to incorrect state management [v2]

John Hendrikx jhendrikx at openjdk.org
Wed Oct 1 16:49:06 UTC 2025


On Wed, 1 Oct 2025 16:40:34 GMT, Michael Strauß <mstrauss at openjdk.org> 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


More information about the openjfx-dev mailing list