Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8350962

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

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • jfx25
    • javafx
    • None
    • behavioral
    • minimal
    • Hide
      There is no impact for applications that always access FX objects from the FX application thread. Applications that call one of the affected methods on the wrong thread will already see unpredictable failures today: an exception might get thrown in some scenarios (but not all) where methods are being called in a background thread, and intermittent failures in others. After this change the methods will consistently fail fast if called on the wrong thread.
      Show
      There is no impact for applications that always access FX objects from the FX application thread. Applications that call one of the affected methods on the wrong thread will already see unpredictable failures today: an exception might get thrown in some scenarios (but not all) where methods are being called in a background thread, and intermittent failures in others. After this change the methods will consistently fail fast if called on the wrong thread.
    • Java API
    • JDK

      Summary

      Adds a check for FX application thread to show(), hide() (and related methods like showAndWait(), setShowing(), close(), etc.) of Window, Control, and Skin. These methods will throw an IllegalStageException if called on a thread other than the FX app thread.

      Problem

      Most JavaFX objects, such as Node and Scene, can be constructed and modified on any thread unless and until that object is attached to a visible Window. Showing or hiding a Window is an operation that must always be done on the JavaFX application thread as documented in the Window and Stage classes.

      Currently, calling these methods in a background thread will lead to exceptions in some cases (but not all) and intermittent failures in others. See JDK-8349004 and JDK-8349096 for an example.

      Solution

      The solution is to check for the FX application thread and throw an IllegalStageException if called from any other thread.

      Basically, what we are doing is to propagate the already-documented restriction on showing and hiding windows, extending it to popup windows and controls that can show popup windows.

      Specification

      javafx.controls/src/main/java/javafx/scene/control/ChoiceBox.java

           /**
            * Opens the list of choices.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public void show() {
      
           /**
            * Closes the list of choices.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public void hide() {

      javafx.controls/src/main/java/javafx/scene/control/ComboBoxBase.java

           /**
      -     * Requests that the ComboBox display the popup aspect of the user interface.
      +     * Requests that the ComboBox display the popup associated with this control.
            * As mentioned in the {@link ComboBoxBase} class javadoc, what is actually
            * shown when this method is called is undefined, but commonly it is some
            * form of popup or dialog window.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public void show() {
      
           /**
            * Closes the popup / dialog that was shown when {@link #show()} was called.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public void hide() {

      javafx.controls/src/main/java/javafx/scene/control/ContextMenu.java

            * <p>
            * This function is useful for finely tuning the position of a menu,
            * relative to the parent node to ensure close alignment.
      +     *
            * @param anchor the anchor node
            * @param side the side
            * @param dx the dx value for the x-axis
            * @param dy the dy value for the y-axis
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
          public void show(Node anchor, Side side, double dx, double dy) {
      
            * given its size requirements, the necessary adjustments are made to bring
            * the {@code ContextMenu} back on screen. This also means that the
            * {@code ContextMenu} will not span multiple monitors.
      +     *
            * @param anchor the anchor node
            * @param screenX the x position of the anchor in screen coordinates
            * @param screenY the y position of the anchor in screen coordinates
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           @Override
           public void show(Node anchor, double screenX, double screenY) {
      
            * <p>
            * If this {@code ContextMenu} is not showing, then nothing happens.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
      -    @Override public void hide() {

      javafx.controls/src/main/java/javafx/scene/control/Dialog.java

           /**
            * Closes this {@code Dialog}.
            * This call is equivalent to {@link #hide}.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public final void close() {
      
           /**
            * Hides this {@code Dialog}.
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public final void hide() {

      javafx.controls/src/main/java/javafx/scene/control/Menu.java

           /**
            * If the Menu is not disabled and the {@link ContextMenu} is not already showing,
            * then this will cause the {@link ContextMenu} to be shown.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public void show() {
      
            * Hides the {@link ContextMenu} if it was previously showing, and any showing
            * submenus. If this menu is not showing, then invoking this function
            * has no effect.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public void hide() {

      javafx.controls/src/main/java/javafx/scene/control/MenuButton.java

           /**
            * Shows the {@link ContextMenu}, assuming this MenuButton is not disabled.
            *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            * @see #isDisabled()
            * @see #isShowing()
            */
           public void show() {
      
           /**
            * Hides the {@link ContextMenu}.
            *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            * @see #isShowing()
            */
           public void hide() {

      javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxBaseSkin.java

           /**
            * This method will be called when the ComboBox popup should be displayed.
            * It is up to specific skin implementations to determine how this is handled.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public abstract void show();
      
           /**
            * This method will be called when the ComboBox popup should be hidden.
            * It is up to specific skin implementations to determine how this is handled.
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
           public abstract void hide();

      javafx.graphics/src/main/java/javafx/stage/PopupWindow.java

            * @throws NullPointerException if owner is null
            * @throws IllegalArgumentException if the specified owner window would
            *      create cycle in the window hierarchy
      +     * @throws IllegalStateException if this method is called on a thread
      +     *      other than the JavaFX Application Thread.
            */
           public void show(Window owner) {
      
            * @throws IllegalArgumentException if the specified owner node is not
            *      associated with a Window or when the window would create cycle
            *      in the window hierarchy
      +     * @throws IllegalStateException if this method is called on a thread
      +     *      other than the JavaFX Application Thread.
            */
           public void show(Node ownerNode, double anchorX, double anchorY) {
      
            * @throws NullPointerException if ownerWindow is null
            * @throws IllegalArgumentException if the specified owner window would
            *      create cycle in the window hierarchy
      +     * @throws IllegalStateException if this method is called on a thread
      +     *      other than the JavaFX Application Thread.
            */
           public void show(Window ownerWindow, double anchorX, double anchorY) {
      
           /**
            * Hide this Popup and all its children
      +     *
      +     * @throws IllegalStateException if this method is called on a thread
      +     * other than the JavaFX Application Thread.
            */
          @Override
          public void hide() {

      javafx.graphics/src/main/java/javafx/stage/Stage.java

           /**
            * 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.
            */
           public void close() {

            angorya Andy Goryachev
            kcr Kevin Rushforth
            Kevin Rushforth
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: