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

[FXCanvas, JFXPanel] NPE in Browser while pressing back/forward buttons from mouse

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 8u20
    • 8u20
    • javafx
    • Fedora 20 x64, Windows 7 x64 with 32bit java
      Oracle java7u51, java8u5, mouse with 5 buttons

      I have 5-buttons mouse, by default in Linux and Windows additional buttons actions in browser is back and forward. It works fine in Firefox but in JavaFx WebView I got NPE.

      Code example:

      import org.eclipse.swt.SWT;
      import org.eclipse.swt.layout.FillLayout;
      import org.eclipse.swt.widgets.Composite;
      import org.eclipse.swt.widgets.Display;
      import org.eclipse.swt.widgets.Shell;

      import javafx.embed.swt.FXCanvas;
      import javafx.scene.Scene;
      import javafx.scene.web.WebEngine;
      import javafx.scene.web.WebView;

      public class SampleApp extends FXCanvas {
      public SampleApp(Composite parent) {
      super(parent, SWT.NONE);
      WebView browser = new WebView();
      this.setScene(new Scene(browser));
      WebEngine webEngine = browser.getEngine();
      webEngine.load("http://www.oracle.com");
      }

      public static void main(String[] args) {
      Display display = new Display();
      Shell shell = new Shell(display);
      shell.setLayout(new FillLayout());

      SampleApp app = new SampleApp(shell);
      shell.open();
      while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
      display.sleep();
      }
      display.dispose();
      }
      }

      Stacktrace(two NPEs per one click):
      Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
      at javafx.scene.Scene$ClickCounter.access$7400(Scene.java:3321)
      at javafx.scene.Scene$ClickGenerator.preProcess(Scene.java:3417)
      at javafx.scene.Scene$ClickGenerator.access$8100(Scene.java:3387)
      at javafx.scene.Scene$MouseHandler.process(Scene.java:3724)
      at javafx.scene.Scene$MouseHandler.access$1800(Scene.java:3471)
      at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1695)
      at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2486)
      at com.sun.javafx.tk.quantum.EmbeddedScene$2$1.run(EmbeddedScene.java:260)
      at com.sun.javafx.tk.quantum.EmbeddedScene$2$1.run(EmbeddedScene.java:246)
      at java.security.AccessController.doPrivileged(Native Method)
      at com.sun.javafx.tk.quantum.EmbeddedScene$2.run(EmbeddedScene.java:246)
      at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
      at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
      at java.security.AccessController.doPrivileged(Native Method)
      at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
      at org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native Method)
      at org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:2473)
      at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3414)
      at org.jboss.tools.vpe.browsersim.browser.javafx.SampleApp.main(SampleApp.java:35)
      Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
      at javafx.scene.Scene$ClickCounter.access$7700(Scene.java:3321)
      at javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3452)
      at javafx.scene.Scene$ClickGenerator.access$8300(Scene.java:3387)
      at javafx.scene.Scene$MouseHandler.process(Scene.java:3755)
      at javafx.scene.Scene$MouseHandler.access$1800(Scene.java:3471)
      at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1695)
      at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2486)
      at com.sun.javafx.tk.quantum.EmbeddedScene$2$1.run(EmbeddedScene.java:260)
      at com.sun.javafx.tk.quantum.EmbeddedScene$2$1.run(EmbeddedScene.java:246)
      at java.security.AccessController.doPrivileged(Native Method)
      at com.sun.javafx.tk.quantum.EmbeddedScene$2.run(EmbeddedScene.java:246)
      at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
      at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
      at java.security.AccessController.doPrivileged(Native Method)
      at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
      at org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native Method)
      at org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:2473)
      at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3414)
      at org.jboss.tools.vpe.browsersim.browser.javafx.SampleApp.main(SampleApp.java:35)

          [JDK-8092920] [FXCanvas, JFXPanel] NPE in Browser while pressing back/forward buttons from mouse

          Tested-with: MouseTest_RT37436.java (the attachment), SampleApp.java (in the comment of this JIRA)
          Unit Tests: none

          Steve Northover (Inactive) added a comment - Tested-with: MouseTest_RT37436.java (the attachment), SampleApp.java (in the comment of this JIRA) Unit Tests: none

          Changeset: d10817fc3844
          Author: snorthov
          Date: 2014-06-10 14:06 -0400
          URL: http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/d10817fc3844

          Steve Northover (Inactive) added a comment - Changeset: d10817fc3844 Author: snorthov Date: 2014-06-10 14:06 -0400 URL: http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/d10817fc3844

          The fix looks fine now.

          +1

          Anthony Petrov (Inactive) added a comment - The fix looks fine now. +1

          I'm okay with the last patch, personally i would let the "case MouseEvent.MOUSE_DRAGGED:' fall thru.

          Felipe Heidrich (Inactive) added a comment - I'm okay with the last patch, personally i would let the "case MouseEvent.MOUSE_DRAGGED:' fall thru.

          Steve Northover (Inactive) added a comment - - edited
          diff --git a/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java b/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java
          --- a/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java
          +++ b/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java
          @@ -319,6 +319,15 @@
                   if (scenePeer == null || !isFxEnabled()) {
                       return;
                   }
          +
          + // FX only supports 3 buttons so don't send the event for other buttons
          + switch (e.getID()) {
          + case MouseEvent.MOUSE_DRAGGED:
          + case MouseEvent.MOUSE_PRESSED:
          + case MouseEvent.MOUSE_RELEASED:
          + if (e.getButton() > 3) return;
          + break;
          + }
           
                   int extModifiers = e.getModifiersEx();
                   // Fix for RT-15457: we should report no mouse button upon mouse release, so
          diff --git a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java
          --- a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java
          +++ b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java
          @@ -398,17 +398,26 @@
                       }
                       @Override
                       public void mouseDown(MouseEvent me) {
          + // FX only supports 3 buttons so don't send the event for other buttons
          + if (me.button > 3) return;
                           FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_PRESSED);
                       }
                       @Override
                       public void mouseUp(MouseEvent me) {
          + // FX only supports 3 buttons so don't send the event for other buttons
          + if (me.button > 3) return;
                           FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_RELEASED);
                       }
                   });
           
                   addMouseMoveListener(me -> {
                       if ((me.stateMask & SWT.BUTTON_MASK) != 0) {
          - FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED);
          + // FX only supports 3 buttons so don't send the event for other buttons
          + if ((me.stateMask & (SWT.BUTTON1 | SWT.BUTTON2 | SWT.BUTTON3)) != 0) {
          + FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED);
          + } else {
          + FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);
          + }
                       } else {
                           FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);
                       }

          Steve Northover (Inactive) added a comment - - edited diff --git a/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java b/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java --- a/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java +++ b/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java @@ -319,6 +319,15 @@          if (scenePeer == null || !isFxEnabled()) {              return;          } + + // FX only supports 3 buttons so don't send the event for other buttons + switch (e.getID()) { + case MouseEvent.MOUSE_DRAGGED: + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + if (e.getButton() > 3) return; + break; + }            int extModifiers = e.getModifiersEx();          // Fix for RT-15457 : we should report no mouse button upon mouse release, so diff --git a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java --- a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java +++ b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java @@ -398,17 +398,26 @@              }              @Override              public void mouseDown(MouseEvent me) { + // FX only supports 3 buttons so don't send the event for other buttons + if (me.button > 3) return;                  FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_PRESSED);              }              @Override              public void mouseUp(MouseEvent me) { + // FX only supports 3 buttons so don't send the event for other buttons + if (me.button > 3) return;                  FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_RELEASED);              }          });            addMouseMoveListener(me -> {              if ((me.stateMask & SWT.BUTTON_MASK) != 0) { - FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED); + // FX only supports 3 buttons so don't send the event for other buttons + if ((me.stateMask & (SWT.BUTTON1 | SWT.BUTTON2 | SWT.BUTTON3)) != 0) { + FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED); + } else { + FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED); + }              } else {                  FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);              }

          The extra code is obviously bogus. I was working quickly and trying to do something else and missed this stupidity. Sorry about that and thanks! I would not have pushed the code with the extra crap in it.

          I'm not sure about just running away when button is greater than three. It is likely ok to say that any event with a button count greater than three should be thrown away, however the code is explicit.

          I will attach the new code that should allow mouse move for both, however, if you run the test code. Mouse dragged for 4 and 5 never comes in from AWT/Swing. (I will attach an AWT/Swing only example).

          Steve Northover (Inactive) added a comment - The extra code is obviously bogus. I was working quickly and trying to do something else and missed this stupidity. Sorry about that and thanks! I would not have pushed the code with the extra crap in it. I'm not sure about just running away when button is greater than three. It is likely ok to say that any event with a button count greater than three should be thrown away, however the code is explicit. I will attach the new code that should allow mouse move for both, however, if you run the test code. Mouse dragged for 4 and 5 never comes in from AWT/Swing. (I will attach an AWT/Swing only example).

          FXCanvas.java is fine. As for JFXPanel.java, since you moved the filtering code inside of sendMouseEventToFX(), why do you still need the copies of the code in processMouseEvent() and processMouseMotionEvent() ?

          For JFXPanel.java, what about just "if (e.getButton() > 3) return;" right at the start of sendMouseEventToFX() ? Would that work ?

          The one problem with the fix above (and with the fix you proposed as well) is the case of MOUSE_DRAGGED of buttons 4 and 5. For swt.FXCanvas you chose to translate those to mouse moved events, in swing.JFXPanel you chose to ignore them. Is that right ?

          Felipe Heidrich (Inactive) added a comment - FXCanvas.java is fine. As for JFXPanel.java, since you moved the filtering code inside of sendMouseEventToFX(), why do you still need the copies of the code in processMouseEvent() and processMouseMotionEvent() ? For JFXPanel.java, what about just "if (e.getButton() > 3) return;" right at the start of sendMouseEventToFX() ? Would that work ? The one problem with the fix above (and with the fix you proposed as well) is the case of MOUSE_DRAGGED of buttons 4 and 5. For swt.FXCanvas you chose to translate those to mouse moved events, in swing.JFXPanel you chose to ignore them. Is that right ?

          Much better code. I was unaware the ENTER / EXIT came through the previous place. In fact, they don't seem to be delivered for me in the test code that is attached to this JIRA (before or after the patch).

          Steve Northover (Inactive) added a comment - Much better code. I was unaware the ENTER / EXIT came through the previous place. In fact, they don't seem to be delivered for me in the test code that is attached to this JIRA (before or after the patch).

          diff --git a/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java b/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java
          --- a/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java
          +++ b/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java
          @@ -319,6 +319,17 @@
                   if (scenePeer == null || !isFxEnabled()) {
                       return;
                   }
          +
          + // FX only supports 3 buttons so don't send the event for other buttons
          + switch (e.getID()) {
          + case MouseEvent.MOUSE_DRAGGED:
          + if (e.getButton() > 3) return;
          + break;
          + case MouseEvent.MOUSE_PRESSED:
          + case MouseEvent.MOUSE_RELEASED:
          + if (e.getButton() > 3) return;
          + break;
          + }
           
                   int extModifiers = e.getModifiersEx();
                   // Fix for RT-15457: we should report no mouse button upon mouse release, so
          @@ -374,7 +385,20 @@
                       }
                   }
           
          - sendMouseEventToFX(e);
          + // FX only supports 3 buttons so don't send the event for other buttons
          + switch (e.getID()) {
          + case MouseEvent.MOUSE_PRESSED:
          + case MouseEvent.MOUSE_RELEASED:
          + if (e.getButton() == MouseEvent.BUTTON1
          + || e.getButton() == MouseEvent.BUTTON2
          + || e.getButton() == MouseEvent.BUTTON3) {
          + sendMouseEventToFX(e);
          + }
          + break;
          + default:
          + sendMouseEventToFX(e);
          + break;
          + }
                   super.processMouseEvent(e);
               }
           
          @@ -387,7 +411,16 @@
                */
               @Override
               protected void processMouseMotionEvent(MouseEvent e) {
          - sendMouseEventToFX(e);
          + // FX only supports 3 buttons so don't send the event for other buttons
          + if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
          + if (e.getButton() == MouseEvent.BUTTON1
          + || e.getButton() == MouseEvent.BUTTON2
          + || e.getButton() == MouseEvent.BUTTON3) {
          + sendMouseEventToFX(e);
          + }
          + } else {
          + sendMouseEventToFX(e);
          + }
                   super.processMouseMotionEvent(e);
               }
           
          diff --git a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java
          --- a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java
          +++ b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java
          @@ -398,17 +398,26 @@
                       }
                       @Override
                       public void mouseDown(MouseEvent me) {
          + // FX only supports 3 buttons so don't send the event for other buttons
          + if (me.button > 3) return;
                           FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_PRESSED);
                       }
                       @Override
                       public void mouseUp(MouseEvent me) {
          + // FX only supports 3 buttons so don't send the event for other buttons
          + if (me.button > 3) return;
                           FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_RELEASED);
                       }
                   });
           
                   addMouseMoveListener(me -> {
                       if ((me.stateMask & SWT.BUTTON_MASK) != 0) {
          - FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED);
          + // FX only supports 3 buttons so don't send the event for other buttons
          + if ((me.stateMask & (SWT.BUTTON1 | SWT.BUTTON2 | SWT.BUTTON3)) != 0) {
          + FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED);
          + } else {
          + FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);
          + }
                       } else {
                           FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);
                       }

          Steve Northover (Inactive) added a comment - diff --git a/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java b/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java --- a/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java +++ b/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java @@ -319,6 +319,17 @@          if (scenePeer == null || !isFxEnabled()) {              return;          } + + // FX only supports 3 buttons so don't send the event for other buttons + switch (e.getID()) { + case MouseEvent.MOUSE_DRAGGED: + if (e.getButton() > 3) return; + break; + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + if (e.getButton() > 3) return; + break; + }            int extModifiers = e.getModifiersEx();          // Fix for RT-15457 : we should report no mouse button upon mouse release, so @@ -374,7 +385,20 @@              }          }   - sendMouseEventToFX(e); + // FX only supports 3 buttons so don't send the event for other buttons + switch (e.getID()) { + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + if (e.getButton() == MouseEvent.BUTTON1 + || e.getButton() == MouseEvent.BUTTON2 + || e.getButton() == MouseEvent.BUTTON3) { + sendMouseEventToFX(e); + } + break; + default: + sendMouseEventToFX(e); + break; + }          super.processMouseEvent(e);      }   @@ -387,7 +411,16 @@       */      @Override      protected void processMouseMotionEvent(MouseEvent e) { - sendMouseEventToFX(e); + // FX only supports 3 buttons so don't send the event for other buttons + if (e.getID() == MouseEvent.MOUSE_DRAGGED) { + if (e.getButton() == MouseEvent.BUTTON1 + || e.getButton() == MouseEvent.BUTTON2 + || e.getButton() == MouseEvent.BUTTON3) { + sendMouseEventToFX(e); + } + } else { + sendMouseEventToFX(e); + }          super.processMouseMotionEvent(e);      }   diff --git a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java --- a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java +++ b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java @@ -398,17 +398,26 @@              }              @Override              public void mouseDown(MouseEvent me) { + // FX only supports 3 buttons so don't send the event for other buttons + if (me.button > 3) return;                  FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_PRESSED);              }              @Override              public void mouseUp(MouseEvent me) { + // FX only supports 3 buttons so don't send the event for other buttons + if (me.button > 3) return;                  FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_RELEASED);              }          });            addMouseMoveListener(me -> {              if ((me.stateMask & SWT.BUTTON_MASK) != 0) { - FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED); + // FX only supports 3 buttons so don't send the event for other buttons + if ((me.stateMask & (SWT.BUTTON1 | SWT.BUTTON2 | SWT.BUTTON3)) != 0) { + FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED); + } else { + FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED); + }              } else {                  FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);              }

          1) ENTERED/EXITED events surely don't have this problem. However, this code from your patch:

          - sendMouseEventToFX(e);
          + // FX only supports 3 buttons so don't send the event for other buttons
          + switch (e.getID()) {
          + case MouseEvent.MOUSE_PRESSED:
          + case MouseEvent.MOUSE_RELEASED:
          + if (e.getButton() == MouseEvent.BUTTON1
          + || e.getButton() == MouseEvent.BUTTON2
          + || e.getButton() == MouseEvent.BUTTON3) {
          + sendMouseEventToFX(e);
          + }
          + }

          simply strips these events. It only passed PRESSED and RELEASED mouse events to sendMouseEventToFX().


          2)
          Not sure there's need to attach anything. The pattern for skipping events is all there, in the sendMouseEventToFX() method itself. E.g.:

                  if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
                      if (!isCapturingMouse) {
                          return;
                      }

          etc. Just add a similar code, like:

                  switch (ID) {
                      case PRESSED/RELEASED:
                           if (button > 3) return;
                   }

          What problem do you see with this approach?

          Anthony Petrov (Inactive) added a comment - 1) ENTERED/EXITED events surely don't have this problem. However, this code from your patch: - sendMouseEventToFX(e); + // FX only supports 3 buttons so don't send the event for other buttons + switch (e.getID()) { + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + if (e.getButton() == MouseEvent.BUTTON1 + || e.getButton() == MouseEvent.BUTTON2 + || e.getButton() == MouseEvent.BUTTON3) { + sendMouseEventToFX(e); + } + } simply strips these events. It only passed PRESSED and RELEASED mouse events to sendMouseEventToFX(). 2) Not sure there's need to attach anything. The pattern for skipping events is all there, in the sendMouseEventToFX() method itself. E.g.:         if (e.getID() == MouseEvent.MOUSE_DRAGGED) {             if (!isCapturingMouse) {                 return;             } etc. Just add a similar code, like:         switch (ID) {             case PRESSED/RELEASED:                  if (button > 3) return;          } What problem do you see with this approach?

            snorthov Steve Northover (Inactive)
            kmarmalyujfx Konstantin Marmalyukov (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: