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