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

Update : WINDOW_MODAL dialog does not popup when restoring iconified owner window, which causes application freeze

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 8u73, 9
    • javafx

      FULL PRODUCT VERSION :
      java version "1.8.0_66"
      Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
      Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [version 10.0.10586]

      A DESCRIPTION OF THE PROBLEM :
      When you create a WINDOW_MODAL dialog while it's owner-window is minimized, and you then restore the owner window (click on task bar icon), the owner window pops up, but the dialog remains invisible :

      Now I know what happens : it's actually rendered off-screen, as the reported coordinates of minimized owner window are something like x = -32765, y = -32765

      I have designed a fix using a listener on owner windows's x property and another on its iconified property to recenter the dialog when its deiconified based on its actual coordinates

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create a scene containing at least two focusable controls (such as a TextFields for instance)
      2. Set it as root for a new stage (Application's primaryStage for instance)
      3.a. Add a handler for WindowEvent.ON_CLOSE_REQUEST on that stage
      3.b. In this handler, make an Alert, set it's modality to WINDOW_MODAL and its owner as the stage, call its showAndWait() method
      4. Launch application, minimize the main window, right-click its taskbar icon, and select "Close Window"
      5. Restore the main window by clicking its icon on task bar : its frozen. You can't get focus into the TextField, can't minimize, maximize or close it
      6. Press ESCAPE: window unfrozen (the alert has been closed)

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The dialog should pop up in front of the owner window when it's restored, so you could read and close it and get back control over your application
      ACTUAL -
      The dialog is invisible, and the owner window is frozen: you can't get focus into the TextField, can't minimize, maximize or close it

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package application;

      import javafx.application.Application;
      import javafx.geometry.Pos;
      import javafx.scene.Scene;
      import javafx.scene.control.Alert;
      import javafx.scene.control.Alert.AlertType;
      import javafx.scene.control.ButtonType;
      import javafx.scene.control.TextField;
      import javafx.scene.layout.BorderPane;
      import javafx.scene.layout.VBox;
      import javafx.stage.Modality;
      import javafx.stage.Stage;
      import javafx.stage.WindowEvent;


      public class Main extends Application {
      @Override
      public void start(Stage primaryStage) {
      try {
      BorderPane root = new BorderPane();
      TextField tf1 = new TextField();
      tf1.setPrefColumnCount(10);
      TextField tf2 = new TextField();
      tf2.setPrefColumnCount(10);
      VBox vb = new VBox(4, tf1, tf2);
      vb.setFillWidth(false);
      vb.setAlignment(Pos.CENTER);
      root.setCenter(vb);
      Scene scene = new Scene(root,400,400);
      scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
      primaryStage.setScene(scene);

      primaryStage.addEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, (event) -> {
      Alert alert = new Alert(AlertType.INFORMATION, "Close window ?", ButtonType.YES, ButtonType.NO);
      alert.initModality(Modality.WINDOW_MODAL);
      alert.initOwner(primaryStage);
      alert.showAndWait().ifPresent((result) -> {
      if (result == ButtonType.NO)
      event.consume();
      });
      });

      primaryStage.show();
      } catch(Exception e) {
      e.printStackTrace();
      }
      }

      public static void main(String[] args) {
      launch(args);
      }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      public T safeShowAndWait(Dialog<T> dialog) {
      Stage nfstage = null;
      if (dialog.getOwner() instanceof Stage)
      nfstage = (Stage) dialog.getOwner();
      Stage ostage = nfstage;
      ChangeListener<? super Boolean> listener = (observable, oldValue, newValue) -> {
      System.err.println(observable + ": " + oldValue + " -> " + newValue);
      if (dialog == null || dialog.getDialogPane() == null || dialog.getDialogPane().getScene() == null)
      return;
      if (!newValue) { // Owner window is being de-iconified
      Window w = dialog.getDialogPane().getScene().getWindow();
      if (w instanceof Stage && dialog.getOwner() instanceof Stage) {
      Stage stage = (Stage) dialog.getOwner();
      Stage wStage = (Stage) w;
      //Get all screens displaying part of the dialog
      List<Screen> scrs = Screen.getScreensForRectangle(wStage.getX(), wStage.getY(), wStage.getWidth(), wStage.getHeight());
      if (scrs.size() == 0) { //No screen found : dialog is off-screen
      //Center dialog on owner window
      double x = stage.getX() + (stage.getWidth() - wStage.getWidth()) / 2.0;
      double y = stage.getY() + (stage.getHeight() - wStage.getHeight()) / 2.0;
      //Apply coordinates
      wStage.setX(x);
      wStage.setY(y);
      }
      }
      }
      };
      ChangeListener<? super Number> xListener = (observable, oldValue, newValue) -> {
      //Detect de-iconification when window is maximized using value of stage.xProperty();
      if (oldValue == null || newValue == null)
      return;
      if (ostage.isMaximized()) {
      if (newValue.doubleValue() <= -32000 && oldValue.doubleValue() > -32000)
      Platform.runLater(() -> ostage.setIconified(true));
      else if (newValue.doubleValue() > -32000 && oldValue.doubleValue() <= -32000)
      Platform.runLater(() -> ostage.setIconified(false));
      }
      };

      try {
      if (ostage != null) {
      ostage.iconifiedProperty().addListener(listener);
      ostage.xProperty().addListener(xListener);
      }

      Optional<T> bType = dialog.showAndWait();

      if (bType.isPresent())
      return bType.get();
      return null;

      } finally {
      if (ostage != null) {
      ostage.iconifiedProperty().removeListener(listener);
      ostage.xProperty().removeListener(xListener);
      }
      }
      }

            ddhill David Hill (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: