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

GTK: On newer linux distros StageStyle.TRANSPARENT stages don't receive all the mouse events they should

XMLWordPrintable

      I have narrowed down a pretty major bug with any newer linux distro and a Stage created with StageStyle.TRANSPARENT. When this StageStyle is used the mouse events over the stage feel like they are passing through the stage even when it contains opaque controls. This is most obvious in menus which I believe are implemented with transparent stages so that they can have a nice drop shadow. I have also seen it on my own dialog implementations that use a transparent stage to avoid window decoration but also render a nice drop shadow.

      To observe this bug you need to use one of the newer linux distros (mentioned below) and run the supplied test class. Once the stage is visible try clicking on the "Show transparent dialog..." button. Then observe that the hover effect on the "Close" button in the new dialog is inconsistent when the mouse is moved overtop of it. You will also notice in the console that the button receives MOUSE_EXIT events even though the mouse is still over the button. You can also try using the "Test" menu to see the bug happening with a regular menu. The hover selection on the menu items will flicker as the mouse is moved overtop of them.

      Occasionally in my testing it felt like the "Close" button on the transparent stage didn't receive ANY mouse events so there may also be a race condition occurring in this bug. Closing the application and restarting it would eventually show the Close button getting some very inconsistent mouse events.

      Linux distros that exhibit the bug (tested with Live CD isos):

      Fedora 18 and Fedora 19
      Ubuntu 13.04 and the final beta of Ubuntu 13.10

      Linux distros that don't exhibit the bug (tested with Live CD isos):

      Fedora 17
      Ubuntu 12.10

      *********************************** test case *********************************************
      import javafx.application.Application;
      import javafx.event.ActionEvent;
      import javafx.event.EventHandler;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.control.Menu;
      import javafx.scene.control.MenuBar;
      import javafx.scene.control.MenuItem;
      import javafx.scene.input.MouseEvent;
      import javafx.scene.layout.Priority;
      import javafx.scene.layout.Region;
      import javafx.scene.layout.StackPane;
      import javafx.scene.layout.VBox;
      import javafx.scene.paint.Color;
      import javafx.stage.Modality;
      import javafx.stage.Stage;
      import javafx.stage.StageStyle;
      import javafx.stage.Window;

      public class TransparentStageTest extends Application {
         
         @Override public void start(final Stage primaryStage) throws Exception {

            primaryStage.centerOnScreen();
            primaryStage.setHeight(200);
            primaryStage.setWidth(550);
            
            EventHandler<ActionEvent> dialog1Handler = new EventHandler<ActionEvent>(){
               @Override public void handle(ActionEvent event) {
                  showDialog(primaryStage, true);
               }
            };
            EventHandler<ActionEvent> dialog2Handler = new EventHandler<ActionEvent>(){
               @Override public void handle(ActionEvent event) {
                  showDialog(primaryStage, false);
               }
            };
            
            Button dialogButton1 = new Button("Show transparent dialog...");
            Button dialogButton2 = new Button("Show opaque dialog...");
            dialogButton1.setOnAction(dialog1Handler);
            dialogButton2.setOnAction(dialog2Handler);
            
            VBox vbox = new VBox(20, dialogButton1, dialogButton2);
            vbox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
            final StackPane mainPane = new StackPane( vbox );
            
            MenuItem testItem1 = new MenuItem("Show transparent dialog...");
            testItem1.setOnAction(dialog1Handler);
            MenuItem testItem2 = new MenuItem("Show opaque dialog...");
            testItem2.setOnAction(dialog2Handler);
            Menu testMenu = new Menu("Test");
            testMenu.getItems().addAll(testItem1, testItem2);
            MenuBar menuBar = new MenuBar();
            menuBar.getMenus().add(testMenu);
            
            VBox.setVgrow(mainPane, Priority.ALWAYS);
            primaryStage.setScene(new Scene(new VBox(menuBar, mainPane)));
            
            primaryStage.show();

         }
         
         private void showDialog( Window owner, boolean transparentStyle ) {
            final Stage testStage = new Stage(
                  transparentStyle ? StageStyle.TRANSPARENT : StageStyle.UNDECORATED);
            testStage.initModality(Modality.WINDOW_MODAL);
            testStage.initOwner(owner);
            testStage.setWidth(150);
            testStage.setHeight(150);
            
            Button closeButton = new Button("Close");
            closeButton.setDefaultButton(true);
            closeButton.setCancelButton(true);
            closeButton.setOnAction(new EventHandler<ActionEvent>() {
               @Override public void handle(ActionEvent event) {
                  testStage.hide();
               }
            });
            
            closeButton.setOnMouseExited(new EventHandler<MouseEvent>() {
               @Override public void handle(MouseEvent event) {
                  System.out.println(event);
               }
            });
            
            StackPane pane = new StackPane(closeButton);
            pane.setStyle("-fx-border-width: 1px; "
                  + "-fx-border-color: -fx-box-border;"
                  + "-fx-background-insets: 7 12 15 12, 8 13 16 13, 9 14 17 14;"
                  + "-fx-border-insets: 7 12 15 12;"
                  + "-fx-effect: dropshadow(three-pass-box, "
                  + "rgba(0.0, 0.0, 0.0, 0.3), 15.0, 0.2, 3.0, 6.0);");
            testStage.setScene(new Scene(pane, Color.TRANSPARENT));
            testStage.showAndWait();

         }

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

      }

            azvegint Alexander Zvegintsev
            csmithjfx Charles Smith (Inactive)
            Votes:
            2 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: