Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8350048: Enforce threading restrictions for show and hide methods in Window, Control, and Skin #1717

Conversation

andy-goryachev-oracle
Copy link
Contributor

@andy-goryachev-oracle andy-goryachev-oracle commented Feb 19, 2025

  • enforced fx application thread
  • clarify doc where an IllegalStateException can get thrown, such as hide() and show()
  • clarified ComboBoxBase::show
  • added a headful test TestThreadingRestrictions

Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change requires CSR request JDK-8350962 to be approved
  • Change must be properly reviewed (2 reviews required, with at least 2 Reviewers)

Issues

  • JDK-8350048: Enforce threading restrictions for show and hide methods in Window, Control, and Skin (Bug - P3)
  • JDK-8350962: Enforce threading restrictions for show and hide methods in Window, Control, and Skin (CSR)

Reviewers

Reviewing

Using git

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

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

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 1717

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

Using diff file

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

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Feb 19, 2025

👋 Welcome back angorya! 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 Feb 19, 2025

@andy-goryachev-oracle This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8350048: Enforce threading restrictions for show and hide methods in Window, Control, and Skin

Reviewed-by: kcr, mstrauss

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been no new commits pushed to the master branch. If another commit should be pushed before you perform the /integrate command, your PR will be automatically rebased. If you prefer to avoid any potential automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@kevinrushforth
Copy link
Member

/reviewers 2 reviewers
/csr

@openjdk
Copy link

openjdk bot commented Feb 19, 2025

@kevinrushforth
The total number of required reviews for this PR (including the jcheck configuration and the last /reviewers command) is now set to 2 (with at least 2 Reviewers).

@openjdk openjdk bot added the csr Need approved CSR to integrate pull request label Feb 19, 2025
@openjdk
Copy link

openjdk bot commented Feb 19, 2025

@kevinrushforth has indicated that a compatibility and specification (CSR) request is needed for this pull request.

@andy-goryachev-oracle please create a CSR request for issue JDK-8350048 with the correct fix version. This pull request cannot be integrated until the CSR request is approved.

@mlbridge
Copy link

mlbridge bot commented Feb 20, 2025

Webrevs

@kevinrushforth
Copy link
Member

Reviewers: @kevinrushforth @arapte

Copy link
Member

@kevinrushforth kevinrushforth left a comment

Choose a reason for hiding this comment

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

The API doc changes look good, although I noted a couple additional changes that are needed.

The API docs for Dialog::hide should also be documented to throw ISE (since it calls close() directly the implementation is fine)

The API docs for Stage::close should also be documented to throw ISE (since it calls hide() directly the implementation is fine)

For ComboBoxBase, were you going to get rid of the word "aspect" in the opening sentence "... display the popup aspect of the user interface."? I think that's a little awkward even with that word removed. Maybe it could just be: "... display the popup associated with this control."

As for the implementation, There are a few places where the skin will call hide(), and I can't tell by just looking at the code that they are all guaranteed to be on the FX app thread.

For example, I recommend checking the following:

  • MenuBarSkin line 799
  • ComboBoxListViewSkin line 199

There may be others.

*
* This test ensures that the threading restrictions are in place where required.
*/
@TestMethodOrder(MethodOrderer.MethodName.class)
Copy link
Member

Choose a reason for hiding this comment

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

This is unnecessary (and not a usual practice).


test(TPopupWindow::new, (p) -> p.show(stage));
test(TPopupWindow::new, (p) -> p.show(stage, 0, 0));
test(TPopupWindow::new, (p) -> p.show(contentPane, 0, 0));
Copy link
Member

Choose a reason for hiding this comment

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

It's probably worth adding a test for hide when it isn't showing (like you've done for other objects).

Util.runAndWait(() -> {
p.show();
});
p.hide(); // do we need to fail early here, or only when showing?
Copy link
Member

Choose a reason for hiding this comment

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

We should fail early (although this comment seems misplaced, since it is the case where it is showing).

}

@Test
@Timeout(value = 1, unit = TimeUnit.DAYS)
Copy link
Member

Choose a reason for hiding this comment

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

Um, 1 DAY???

Seriously, though: Remove the timeout (it isn't needed or wanted).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

checked in by mistake

Comment on lines 486 to 491
public void show() {
if (!isDisabled()) setShowing(true);
Toolkit.getToolkit().checkFxUserThread();
if (!isDisabled()) {
setShowing(true);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Would it be a good idea to move the check Toolkit.getToolkit().checkFxUserThread(); to a new method show() in Parent class Control? And may be similarly to Parent classes of other classes.

Copy link
Member

Choose a reason for hiding this comment

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

No, we don't want to add a new public show method to Control since it is only a very few controls that have the concept of showing a popup.

@andy-goryachev-oracle
Copy link
Contributor Author

For example, I recommend checking the following:
MenuBarSkin line 799
ComboBoxListViewSkin line 199

I think it should be sufficient to mention the exception in the actual methods where the check is done, such as hide() and show().

@kevinrushforth
Copy link
Member

For example, I recommend checking the following:
MenuBarSkin line 799
ComboBoxListViewSkin line 199

I think it should be sufficient to mention the exception in the actual methods where the check is done, such as hide() and show().

I'm not talking about docs here. What I meant that if the code in question is ever executed on a background thread such that hide is called, this will now cause an exception at runtime. I don't know whether it is possible, but it isn't immediately obvious that this can't happen on a background thread -- at least not for the two cases I mentioned. In fact, I'm pretty sure that at least the second case (ComboBoxListViewSkin line 199) is possible.

        lh.addInvalidationListener(comboBox.sceneProperty(), (o) -> {
            if (((ObservableValue)o).getValue() == null) {
                comboBox.hide();
            }
        });

I suspect that the following sequence of operations, all on a background thread, will trigger the exception:

  1. Create a ComboBox
  2. Create a Skin
  3. Add the combobox to a Scene (the scene must not be showing, of course)

A solution might be to check whether the combobox is showing before hiding it.

        lh.addInvalidationListener(comboBox.sceneProperty(), (o) -> {
            if (((ObservableValue)o).getValue() == null) {
                if (comboBox.isShowing()) {
                    comboBox.hide();
                }
            }
        });

And, if the code in MenuBarSkin is a problem, then something like this might be in order:

            if (menuButton.isShowing()) {
                menuButton.hide();
            }

Similarly, I think this listener in MenuBarSkin::rebuildUI (starting on line 913) might need a check before calling menuButton.hide():

            menuButton.menuListener = (observable, oldValue, newValue) -> {
                if (menu.isShowing()) {
                    menuButton.show();
                    menuModeStart(container.getChildren().indexOf(menuButton));
                } else {
                    menuButton.hide();     // <--  check if (menuButton.isShowing()) before calling
                }
            };

@kevinrushforth
Copy link
Member

The updated docs look good. Go ahead and create the CSR.

@andy-goryachev-oracle
Copy link
Contributor Author

@andy-goryachev-oracle
Copy link
Contributor Author

MenuBarSkin line 799
ComboBoxListViewSkin line 199

ComboBoxListViewSkin - thanks for the suggestion!

MenuBarSkin - is a bit more complex case because of the interaction with the system menu Toolkit.getToolkit().getSystemMenu().isSupported() which needs to be called from the FX application thread.

We probably should disallow creating MenuBars in background thread (similar to Window, WebView, and HtmlEditor) in the constructor. What do you think?

@andy-goryachev-oracle
Copy link
Contributor Author

Created https://bugs.openjdk.org/browse/JDK-8350976 for the MenuBarSkin.

Copy link
Member

@kevinrushforth kevinrushforth left a comment

Choose a reason for hiding this comment

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

All looks good now.

Have you done a headful test run?

@openjdk openjdk bot removed the csr Need approved CSR to integrate pull request label Mar 4, 2025
@andy-goryachev-oracle
Copy link
Contributor Author

Have you done a headful test run?

combined branch (this PR + #1697 + #1727) is green on all platforms except for a single unrelated failure on linux:

RegionBackgroundFillUITest > testScenario1() FAILED

@@ -1183,6 +1183,8 @@ public void toBack() {
/**
* Closes this {@code Stage}.
* This call is equivalent to {@code hide()}.
* @throws IllegalStateException if this method is called on a thread
* other than the JavaFX Application Thread.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor: add a blank line before @throws. I also think it's easier to read docs when multi-line text for a javadoc tag is indented, either by four spaces or lined up with the beginning of the first line of text (i.e. with the beginning of IllegalStateException).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good idea, even though it does not affect generated javadoc.
will do next time, to avoid re-setting the approvals ;-)

Copy link
Collaborator

Choose a reason for hiding this comment

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

will do next time, to avoid re-setting the approvals ;-)

I'll re-approve if you decide to do the changes anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it is not required, and the code is inconsistent (Stage:472) ... but ok.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you do it for the other changed docs also?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The general policy is to avoid unrelated changes and expanding the scope.

A proper way to address that would be to create a JBS and do a wholesale bulk edit, not sure if it's worth it though.

Copy link
Collaborator

Choose a reason for hiding this comment

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

You've added the same javadoc tag in 20 different places. All I'm asking is that you do the change that you did in this particular place in all of the other places too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I misunderstood, sorry. Done.

@openjdk openjdk bot added the ready Ready to be integrated label Mar 7, 2025
@openjdk openjdk bot removed the ready Ready to be integrated label Mar 7, 2025
@openjdk openjdk bot added the ready Ready to be integrated label Mar 10, 2025
@andy-goryachev-oracle
Copy link
Contributor Author

/integrate

@openjdk
Copy link

openjdk bot commented Mar 10, 2025

Going to push as commit b5f76ad.

@openjdk openjdk bot added the integrated Pull request has been integrated label Mar 10, 2025
@openjdk openjdk bot closed this Mar 10, 2025
@openjdk openjdk bot removed ready Ready to be integrated rfr Ready for review labels Mar 10, 2025
@openjdk
Copy link

openjdk bot commented Mar 10, 2025

@andy-goryachev-oracle Pushed as commit b5f76ad.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@andy-goryachev-oracle andy-goryachev-oracle deleted the 8350048.enforce branch March 10, 2025 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integrated Pull request has been integrated
Development

Successfully merging this pull request may close these issues.

4 participants