Skip to content

Conversation

@mstr2
Copy link
Collaborator

@mstr2 mstr2 commented Nov 25, 2025

This enhancement allows Stage to be placed on the screen similar to a popup window, where a user-specified positioning anchor defines a point on the stage that should coincide with a given location on the screen. For this purpose, the following new methods are added to Stage:

public class Stage {
    public void relocate(double anchorX, double anchorY, AnchorPoint);
    public void relocate(double anchorX, double anchorY, AnchorPoint, AnchorPolicy, Insets screenPadding);
}

AnchorPoint

AnchorPoint is a point that is either specified in absolute coordinates, or relative to the stage:

var anchor1 = AnchorPoint.proportional(0.5, 0.5); // center of the stage
var anchor2 = AnchorPoint.absolute(100, 100); // absolute coordinates within stage

For example, a stage that sits flush with the bottom-right corner of the screen can be shown as follows:

var bounds = Screen.getPrimary().getBounds();
var anchor = AnchorPoint.proportional(1, 1); // or use the AnchorPoint.BOTTOM_RIGHT constant
stage.relocate(bounds.getMaxX(), bounds.getMaxY(), anchor);
stage.show();

AnchorPolicy

AnchorPolicy controls how the anchor may be adjusted when the preferred placement doesn't fit within the screen bounds:

public enum AnchorPolicy {
    FIXED,
    FLIP_HORIZONTAL,
    FLIP_VERTICAL,
    AUTO
}
  • FIXED: always use the provided anchor; only adjust the resulting position to fit within the screen.
  • FLIP_HORIZONTAL: if the preferred placement violates horizontal constraints, try a horizontally flipped anchor (e.g. top-left to top-right) before falling back to the original anchor.
  • FLIP_VERTICAL: likewise for vertical constraints.
  • AUTO: automatically choose the most suitable flip:
    if only horizontal constraints are violated, acts like FLIP_HORIZONTAL;
    if only vertical constraints are violated, acts like FLIP_VERTICAL;
    if both are violated, try a diagonally flipped anchor (both axes) and pick the placement that requires the least adjustment.

This is useful for popup-like behavior where you have a preferred "opening direction", but want the window to flip to the opposite side of the reference point when there isn’t enough space (e.g. "prefer below, but open above if below doesn’t fit").

PopupWindow support

The new PopupWindow.anchorPolicy property adds the same "flip the anchor when it would go off-screen" capability for popups. This complements the existing PopupWindow.anchorLocation / PopupWindow.autoFix behavior: applications can keep using PopupWindow.anchorLocation to express the preferred anchor, while PopupWindow.anchorPolicy controls how the popup may flip that anchor as a fallback when the preferred placement wouldn't fit within screen bounds.

Edge constraints

screenPadding specifies per-edge padding relative to the screen, expressed as an Insets:

  • An inset value >= 0 enables a constraint for that edge and specifies the minimum distance in pixels that the stage must keep from that screen edge.
  • An inset value < 0 disables the constraint for that edge.

Enabled constraints effectively shrink the usable screen area by the given insets.


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8372530: Easier placement of windows with positioning anchor (Enhancement - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1986/head:pull/1986
$ git checkout pull/1986

Update a local copy of the PR:
$ git checkout pull/1986
$ git pull https://git.openjdk.org/jfx.git pull/1986/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 1986

View PR using the GUI difftool:
$ git pr show -t 1986

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1986.diff

@bridgekeeper
Copy link

bridgekeeper bot commented Nov 25, 2025

👋 Welcome back mstrauss! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Nov 25, 2025

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

*
* @since 26
*/
public static final class Anchor {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be a record too

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it could, but I don't like the boolean parameter that it would expose. Boolean parameters are usually not a good idea, as they lead to "boolean blindness" at the call site. I've moved this entire class to javafx.geometry, as it might be useful for other code in the future, and I don't want to proliferate two nested versions of an anchor point (one in Stage, the other in PopupWindow).

0, 0);
}

// Give subclasses a chance to adjust the window bounds
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to this Enhancement, but I wonder if the centerOnScreen line before could also be rewritten using this system (at one point). Now, it looks like he might be centering the Window, and then fix the bounds to something else, wasting some time.

* @throws NullPointerException if {@code anchor} is {@code null}
* @since 26
*/
public final void show(double anchorX, double anchorY, AnchorPoint anchor) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make more sense to move these new methods to Window, so they can also work for the Popup and its hierarchy ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PopupWindow works differently, it has a anchorLocation property which is a bit limited. We also couldn't move PopupWindow.AnchorLocation anywhere else (as this would be a breaking change), which would make the signature of the show() method very awkward: On Stage.show(x, y, PopupWindow.AnchorLocation) you'd have a parameter that is declared on an unrelated class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is unfortunate.
Can we do anything to make the positioning of Popups and its hierarchy easier? Maybe add another show() with a ClampPolicy argument?

Use case: I want to open a PopupWindow below the owner node, but: if the popup cannot be placed there because the whole thing is too close to the bottom of the screen, I want the popup to be above the node, and not on top of it as it works currently.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've redesigned the feature a bit, and found that we can indeed make this compatible with PopupWindow. You now have the option to specify PopupWindow.anchorPolicy, which defaults to the current behavior, but can also be specified to work as you describe (using AnchorPolicy.AUTO).

*
* @since 26
*/
public enum ClampPolicy {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe call it RelocationPolicy?

@Maran23
Copy link
Member

Maran23 commented Nov 27, 2025

I will test and review this. Especially test with the scenarios where I used the workaround described in the mailing list.
And give feedback accordingly (API and Functionality-wise).
Will probably take a bit, as there are some other things (like Direct3D12) on my list.

@mstr2 mstr2 changed the title 8372530: Easier placement of stages with positioning anchor 8372530: Easier placement of windows with positioning anchor Nov 27, 2025

@Override
public void centerOnScreen() {
relocationRequest = null; // cancel previous relocation request
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand, with the new anchor system, a center on screen can easily be achieved as well? I wonder if we could also deprecate this method instead. But not sure if I understand it correctly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the anchor is always a point on the window being shown, not on the screen. All anchor APIs require you to specify an explicit screen location, and the window is then moved so that the anchor coincides with that screen location. So to emulate centerOnScreen(), you'd have to manually get the screen bounds, and then calculate the center.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants