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

Blinking main undecorated window during resize on some graphics cards

    Details

    • Subcomponent:
    • CPU:
      x86_64
    • OS:
      windows_7

      Description

      ADDITIONAL SYSTEM INFORMATION :
      SOFTWARE:
      InteliJ 2019.2.4
      Maven 3.6.2
      Java: 11.0.6
      JavaFX: checked on 13,14 and 15-ea+2
      My App: Main window have BorderPane-> TOP:AnchorPane with Button, Center: SplitPane, Bottom: AnchorPane with Label - but I think that amount of components are more important

      HARDWARE:
      CPU: i5-4690K
      Internal GPU: Intel HD 4600 - driver ver. 10.18.14.5117 - 2019-11-25



      A DESCRIPTION OF THE PROBLEM :
      My main (undecorated) window blinks during resizing for milisecond. It happens every time when resizing but in random moments. Saying blink I mean that whole window is getting black for this milisecond. Actual size of the window during resizing makes no difference, its about changing size no matter how much.

      I've implemented few ways to resize my window like this one, but it still blinks:
      https://gist.github.com/Simonwep/642587d0e307de6da6347ba56f396231

      I think this problem is connected with my graphic card (Intel HD 4600) or incompatible driver, because when I've run application on external grpahic card (GTX 1060Ti) problem disappeard.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create new JavaFX Application
      2. Create fxml file
      3. Use class to resize undecorated window : https://gist.github.com/Simonwep/642587d0e307de6da6347ba56f396231
      4. Run app and click border
      5. Resizing (try to experiment fast and also slow mouse moves should finally call blink). Direction of resizing has no matter.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Resizing should be smooth without blinking
      ACTUAL -
      Resizing is smooth but window blinks sometime

      ---------- BEGIN SOURCE ----------
      public class AppStart extends Application {

          FXMLLoader fxmlLoader;
          private Parent rootNode;

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

          @Override
          public void init() throws Exception {
              fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/main.fxml"));
              rootNode = fxmlLoader.load();
          }

          @Override
          public void start(Stage mainStage) {
              Scene scene = new Scene(rootNode);
              mainStage.setScene(scene);
              mainStage.setTitle("Hello World Application");
              mainStage.initStyle(StageStyle.UNDECORATED);
              new FXResizeHelper(mainStage, 10, 10);
              mainStage.show();
          }
      }




      //Class for handle resizing undecorated window - source: https://gist.github.com/Simonwep/642587d0e307de6da6347ba56f396231
      public class FXResizeHelper {

          private final HashMap<Cursor, EventHandler<MouseEvent>> LISTENER = new HashMap<>();
          private final Stage STAGE;
          private final Scene SCENE;
          private final int TR;
          private final int TM;
          private final double SCREEN_WIDTH, SCREEN_HEIGHT;

          private double mPresSceneX, mPresSceneY;
          private double mPresScreeX, mPresScreeY;
          private double mPresStageW, mPresStageH;

          private boolean mIsMaximized = false;
          private double mWidthStore, mHeightStore, mXStore, mYStore;

          public FXResizeHelper(Stage stage, int dt, int rt) {
              this.TR = rt;
              this.TM = dt + rt;
              this.STAGE = stage;
              this.SCENE = stage.getScene();

              this.SCREEN_HEIGHT = Screen.getPrimary().getVisualBounds().getHeight();
              this.SCREEN_WIDTH = Screen.getPrimary().getVisualBounds().getWidth();

              createListener();
              launch();
          }
          
          private void createListener() {
              LISTENER.put(Cursor.NW_RESIZE, event -> {

                  double newWidth = mPresStageW - (event.getScreenX() - mPresScreeX);
                  double newHeight = mPresStageH - (event.getScreenY() - mPresScreeY);
                  if (newHeight > STAGE.getMinHeight()) {
                      STAGE.setY(event.getScreenY() - mPresSceneY);
                      STAGE.setHeight(newHeight);
                  }
                  if (newWidth > STAGE.getMinWidth()) {
                      STAGE.setX(event.getScreenX() - mPresSceneX);
                      STAGE.setWidth(newWidth);
                  }
              });

              LISTENER.put(Cursor.NE_RESIZE, event -> {

                  double newWidth = mPresStageW - (event.getScreenX() - mPresScreeX);
                  double newHeight = mPresStageH + (event.getScreenY() - mPresScreeY);
                  if (newHeight > STAGE.getMinHeight()) STAGE.setHeight(newHeight);
                  if (newWidth > STAGE.getMinWidth()) {
                      STAGE.setX(event.getScreenX() - mPresSceneX);
                      STAGE.setWidth(newWidth);
                  }
              });

              LISTENER.put(Cursor.SW_RESIZE, event -> {

                  double newWidth = mPresStageW + (event.getScreenX() - mPresScreeX);
                  double newHeight = mPresStageH - (event.getScreenY() - mPresScreeY);
                  if (newHeight > STAGE.getMinHeight()) {
                      STAGE.setHeight(newHeight);
                      STAGE.setY(event.getScreenY() - mPresSceneY);
                  }
                  if (newWidth > STAGE.getMinWidth()) STAGE.setWidth(newWidth);
              });

              LISTENER.put(Cursor.SE_RESIZE, event -> {
                  double newWidth = mPresStageW + (event.getScreenX() - mPresScreeX);
                  double newHeight = mPresStageH + (event.getScreenY() - mPresScreeY);
                  if (newHeight > STAGE.getMinHeight()) STAGE.setHeight(newHeight);
                  if (newWidth > STAGE.getMinWidth()) STAGE.setWidth(newWidth);
              });

              LISTENER.put(Cursor.E_RESIZE, event -> {
                  double newWidth = mPresStageW - (event.getScreenX() - mPresScreeX);
                  if (newWidth > STAGE.getMinWidth()) {
                      STAGE.setX(event.getScreenX() - mPresSceneX);
                      STAGE.setWidth(newWidth);
                  }
              });

              LISTENER.put(Cursor.W_RESIZE, event -> {
                  double newWidth = mPresStageW + (event.getScreenX() - mPresScreeX);
                  if (newWidth > STAGE.getMinWidth()) STAGE.setWidth(newWidth);
              });

              LISTENER.put(Cursor.N_RESIZE, event -> {
                  double newHeight = mPresStageH - (event.getScreenY() - mPresScreeY);
                  if (newHeight > STAGE.getMinHeight()) {
                      STAGE.setY(event.getScreenY() - mPresSceneY);
                      STAGE.setHeight(newHeight);
                  }
              });

              LISTENER.put(Cursor.S_RESIZE, event -> {
                  double newHeight = mPresStageH + (event.getScreenY() - mPresScreeY);
                  if (newHeight > STAGE.getMinHeight()) STAGE.setHeight(newHeight);
              });

              LISTENER.put(Cursor.OPEN_HAND, event -> {
                  STAGE.setX(event.getScreenX() - mPresSceneX);
                  STAGE.setY(event.getScreenY() - mPresSceneY);
              });
          }

          private void launch() {

              SCENE.setOnMousePressed(event -> {
                  mPresSceneX = event.getSceneX();
                  mPresSceneY = event.getSceneY();

                  mPresScreeX = event.getScreenX();
                  mPresScreeY = event.getScreenY();

                  mPresStageW = STAGE.getWidth();
                  mPresStageH = STAGE.getHeight();
              });

              SCENE.setOnMouseMoved(event -> {
                  double sx = event.getSceneX();
                  double sy = event.getSceneY();

                  boolean l_trigger = sx > 0 && sx < TR;
                  boolean r_trigger = sx < SCENE.getWidth() && sx > SCENE.getWidth() - TR;
                  boolean u_trigger = sy < SCENE.getHeight() && sy > SCENE.getHeight() - TR;
                  boolean d_trigger = sy > 0 && sy < TR;

                  if (l_trigger && d_trigger) fireAction(Cursor.NW_RESIZE);
                  else if (l_trigger && u_trigger) fireAction(Cursor.NE_RESIZE);
                  else if (r_trigger && d_trigger) fireAction(Cursor.SW_RESIZE);
                  else if (r_trigger && u_trigger) fireAction(Cursor.SE_RESIZE);
                  else if (l_trigger) fireAction(Cursor.E_RESIZE);
                  else if (r_trigger) fireAction(Cursor.W_RESIZE);
                  else if (d_trigger) fireAction(Cursor.N_RESIZE);
                  else if (sy < TM && !u_trigger) fireAction(Cursor.OPEN_HAND);
                  else if (u_trigger) fireAction(Cursor.S_RESIZE);
                  else fireAction(Cursor.DEFAULT);
              });
          }

          private void fireAction(Cursor c) {
              SCENE.setCursor(c);
              if (c != Cursor.DEFAULT) SCENE.setOnMouseDragged(LISTENER.get(c));
              else SCENE.setOnMouseDragged(null);
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      After connect external graphic card problem dissapears - test for GTX 1060Ti

      FREQUENCY : always


        Attachments

        1. AppStart.java
          1 kB
        2. FXResizeHelper.java
          6 kB
        3. resources.rar
          1 kB

          Activity

            People

            • Assignee:
              kcr Kevin Rushforth
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated: