< prev index next >

modules/javafx.swt/src/main/java/javafx/embed/swt/FXCanvas.java

Print this page
rev 10032 : 8143596: Ensure FXCanvas properly forwards SWT gesture events to its embedded scene.
Summary: Ensured SWT magnify, rotate, pan, and swipe events are properly forwarded to the embedded scene.
Reviewed-by: XXXX


  30 import com.sun.javafx.cursor.CursorFrame;
  31 import com.sun.javafx.cursor.CursorType;
  32 import com.sun.javafx.embed.AbstractEvents;
  33 import com.sun.javafx.embed.EmbeddedSceneDSInterface;
  34 import com.sun.javafx.embed.EmbeddedSceneDTInterface;
  35 import com.sun.javafx.embed.EmbeddedSceneInterface;
  36 import com.sun.javafx.embed.EmbeddedStageInterface;
  37 import com.sun.javafx.embed.HostInterface;
  38 import com.sun.javafx.stage.EmbeddedWindow;
  39 
  40 import java.lang.reflect.Field;
  41 import java.lang.reflect.Method;
  42 import java.nio.ByteBuffer;
  43 import java.nio.IntBuffer;
  44 import java.security.AccessController;
  45 import java.security.PrivilegedAction;
  46 import java.util.ArrayList;
  47 import java.util.Arrays;
  48 import java.util.HashSet;
  49 import java.util.Set;

  50 import java.util.concurrent.CountDownLatch;
  51 
  52 import javafx.application.Platform;
  53 import javafx.beans.NamedArg;
  54 import javafx.scene.Scene;
  55 import javafx.scene.input.TransferMode;
  56 import javafx.stage.Window;
  57 import javafx.util.FXPermission;
  58 
  59 import org.eclipse.swt.SWT;
  60 import org.eclipse.swt.dnd.DND;
  61 import org.eclipse.swt.dnd.DragSource;
  62 import org.eclipse.swt.dnd.DragSourceListener;
  63 import org.eclipse.swt.dnd.DropTarget;
  64 import org.eclipse.swt.dnd.DropTargetEvent;
  65 import org.eclipse.swt.dnd.DropTargetListener;
  66 import org.eclipse.swt.dnd.FileTransfer;
  67 import org.eclipse.swt.dnd.HTMLTransfer;
  68 import org.eclipse.swt.dnd.ImageTransfer;
  69 import org.eclipse.swt.dnd.RTFTransfer;
  70 import org.eclipse.swt.dnd.TextTransfer;
  71 import org.eclipse.swt.dnd.Transfer;
  72 import org.eclipse.swt.dnd.TransferData;
  73 import org.eclipse.swt.dnd.URLTransfer;
  74 import org.eclipse.swt.events.ControlEvent;
  75 import org.eclipse.swt.events.ControlListener;
  76 import org.eclipse.swt.events.DisposeEvent;
  77 import org.eclipse.swt.events.DisposeListener;
  78 import org.eclipse.swt.events.FocusEvent;
  79 import org.eclipse.swt.events.FocusListener;

  80 import org.eclipse.swt.events.KeyEvent;
  81 import org.eclipse.swt.events.KeyListener;
  82 import org.eclipse.swt.events.MenuDetectEvent;
  83 import org.eclipse.swt.events.MouseEvent;
  84 import org.eclipse.swt.events.MouseListener;
  85 import org.eclipse.swt.events.MouseTrackListener;
  86 import org.eclipse.swt.events.PaintEvent;
  87 import org.eclipse.swt.graphics.Image;
  88 import org.eclipse.swt.graphics.ImageData;
  89 import org.eclipse.swt.graphics.PaletteData;
  90 import org.eclipse.swt.graphics.Point;
  91 import org.eclipse.swt.graphics.RGB;
  92 import org.eclipse.swt.graphics.Rectangle;
  93 import org.eclipse.swt.widgets.Canvas;
  94 import org.eclipse.swt.widgets.Composite;
  95 import org.eclipse.swt.widgets.Control;
  96 import org.eclipse.swt.widgets.Display;
  97 import org.eclipse.swt.widgets.Event;
  98 import org.eclipse.swt.widgets.Listener;
  99 import org.eclipse.swt.widgets.Shell;


 447             public void mouseUp(MouseEvent me) {
 448                 // FX only supports 3 buttons so don't send the event for other buttons
 449                 if (me.button > 3) return;
 450                 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_RELEASED);
 451             }
 452         });
 453 
 454         addMouseMoveListener(me -> {
 455             if ((me.stateMask & SWT.BUTTON_MASK) != 0) {
 456                 // FX only supports 3 buttons so don't send the event for other buttons
 457                 if ((me.stateMask & (SWT.BUTTON1 | SWT.BUTTON2 | SWT.BUTTON3)) != 0) {
 458                     FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED);
 459                 } else {
 460                     FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);
 461                 }
 462             } else {
 463                 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);
 464             }
 465         });
 466 


 467         addListener(SWT.MouseVerticalWheel, e -> {
 468             FXCanvas.this.sendScrollEventToFX(e, AbstractEvents.MOUSEEVENT_VERTICAL_WHEEL);



 469         });
 470         addListener(SWT.MouseHorizontalWheel, e -> {
 471             FXCanvas.this.sendScrollEventToFX(e, AbstractEvents.MOUSEEVENT_HORIZONTAL_WHEEL);



 472         });
 473 
 474         addMouseTrackListener(new MouseTrackListener() {
 475             @Override
 476             public void mouseEnter(MouseEvent me) {
 477                 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_ENTERED);
 478             }
 479             @Override
 480             public void mouseExit(MouseEvent me) {
 481                 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_EXITED);
 482             }
 483             @Override
 484             public void mouseHover(MouseEvent me) {
 485                 // No mouse hovering in FX
 486             }
 487         });
 488 
 489         addControlListener(new ControlListener() {
 490             @Override
 491             public void controlMoved(ControlEvent ce) {


 503                 FXCanvas.this.sendFocusEventToFX(fe, true);
 504             }
 505             @Override
 506             public void focusLost(FocusEvent fe) {
 507                 FXCanvas.this.sendFocusEventToFX(fe, false);
 508             }
 509         });
 510 
 511         addKeyListener(new KeyListener() {
 512             @Override
 513             public void keyPressed(KeyEvent e) {
 514                 FXCanvas.this.sendKeyEventToFX(e, SWT.KeyDown);
 515 
 516             }
 517             @Override
 518             public void keyReleased(KeyEvent e) {
 519                 FXCanvas.this.sendKeyEventToFX(e, SWT.KeyUp);
 520             }
 521         });
 522 




 523         addMenuDetectListener(e -> {
 524             Runnable r = () -> {
 525                 if (isDisposed()) return;
 526                 FXCanvas.this.sendMenuEventToFX(e);
 527             };
 528             // In SWT, MenuDetect comes before the equivalent mouse event
 529             // On Mac, the order is MenuDetect, MouseDown, MouseUp.  FX
 530             // does not expect this order and when it gets the MouseDown,
 531             // it closes the menu.  The fix is to defer the MenuDetect
 532             // notification until after the MouseDown is sent to FX.
 533             if ("cocoa".equals(SWT.getPlatform())) {
 534                 getDisplay().asyncExec(r);
 535             } else {
 536                 r.run();
 537             }
 538         });
 539     }
 540 
 541     private void widgetDisposed(DisposeEvent de) {
 542         setDropTarget(null);


 663                     } else if ((me.stateMask & SWT.BUTTON3) != 0) {
 664                         button = 3;
 665                     }
 666                 }
 667                 break;
 668 
 669             default:
 670                 break;
 671         }
 672 
 673         scenePeer.mouseEvent(
 674                 embedMouseType,
 675                 SWTEvents.mouseButtonToEmbedMouseButton(button, me.stateMask),
 676                 primaryBtnDown, middleBtnDown, secondaryBtnDown,
 677                 me.x, me.y,
 678                 los.x, los.y,
 679                 shift, control, alt, meta,
 680                 false);  // RT-32990: popup trigger not implemented
 681     }
 682 
 683     private void sendScrollEventToFX(Event event, int type){


 684         if (scenePeer == null) {
 685             return;
 686         }
 687         Point los = toDisplay(event.x, event.y);
































 688         scenePeer.scrollEvent(type,
 689                 (type == AbstractEvents.MOUSEEVENT_HORIZONTAL_WHEEL) ? -SWTEvents.getWheelRotation(event) : 0,
 690                 (type == AbstractEvents.MOUSEEVENT_VERTICAL_WHEEL) ? -SWTEvents.getWheelRotation(event) : 0,
 691                 event.x, event.y,

 692                 los.x, los.y,
 693                 (event.stateMask & SWT.SHIFT) != 0,
 694                 (event.stateMask & SWT.CONTROL) != 0,
 695                 (event.stateMask & SWT.ALT) != 0,
 696                 (event.stateMask & SWT.COMMAND) != 0);

 697     }
 698 
 699     private void sendKeyEventToFX(final KeyEvent e, int type) {
 700         if (scenePeer == null /*|| !isFxEnabled()*/) {
 701             return;
 702         }
 703         int stateMask = e.stateMask;
 704         if (type == SWT.KeyDown) {
 705             if (e.keyCode == SWT.SHIFT) stateMask |= SWT.SHIFT;
 706             if (e.keyCode == SWT.CONTROL) stateMask |= SWT.CONTROL;
 707             if (e.keyCode == SWT.ALT) stateMask |= SWT.ALT;
 708             if (e.keyCode == SWT.COMMAND) stateMask |= SWT.COMMAND;
 709         } else {
 710             if (e.keyCode == SWT.SHIFT) stateMask &= ~SWT.SHIFT;
 711             if (e.keyCode == SWT.CONTROL) stateMask &= ~SWT.CONTROL;
 712             if (e.keyCode == SWT.ALT) stateMask &= ~SWT.ALT;
 713             if (e.keyCode == SWT.COMMAND) stateMask &= ~SWT.COMMAND;
 714         }
 715         int keyCode = SWTEvents.keyCodeToEmbedKeyCode(e.keyCode);
 716         scenePeer.keyEvent(
 717                 SWTEvents.keyIDToEmbedKeyType(type),
 718                 keyCode, new char[0],
 719                 SWTEvents.keyModifiersToEmbedKeyModifiers(stateMask));
 720         if (e.character != '\0' && type == SWT.KeyDown) {
 721             char[] chars = new char[] { e.character };
 722             scenePeer.keyEvent(
 723                     AbstractEvents.KEYEVENT_TYPED,
 724                     e.keyCode, chars,
 725                     SWTEvents.keyModifiersToEmbedKeyModifiers(stateMask));
 726         }
 727     }
 728 

























































































































































































 729     private void sendMenuEventToFX(MenuDetectEvent me) {
 730         if (scenePeer == null /*|| !isFxEnabled()*/) {
 731             return;
 732         }
 733         Point pt = toControl(me.x, me.y);
 734         scenePeer.menuEvent(pt.x, pt.y, me.x, me.y, false);
 735     }
 736 
 737     private void sendResizeEventToFX() {
 738 
 739         // force the panel to draw right away (avoid black rectangle)
 740         redraw();
 741         update();
 742 
 743         pWidth = getClientArea().width;
 744         pHeight = getClientArea().height;
 745 
 746         resizePixelBuffer(lastScaleFactor);
 747 
 748         if (scenePeer == null) {




  30 import com.sun.javafx.cursor.CursorFrame;
  31 import com.sun.javafx.cursor.CursorType;
  32 import com.sun.javafx.embed.AbstractEvents;
  33 import com.sun.javafx.embed.EmbeddedSceneDSInterface;
  34 import com.sun.javafx.embed.EmbeddedSceneDTInterface;
  35 import com.sun.javafx.embed.EmbeddedSceneInterface;
  36 import com.sun.javafx.embed.EmbeddedStageInterface;
  37 import com.sun.javafx.embed.HostInterface;
  38 import com.sun.javafx.stage.EmbeddedWindow;
  39 
  40 import java.lang.reflect.Field;
  41 import java.lang.reflect.Method;
  42 import java.nio.ByteBuffer;
  43 import java.nio.IntBuffer;
  44 import java.security.AccessController;
  45 import java.security.PrivilegedAction;
  46 import java.util.ArrayList;
  47 import java.util.Arrays;
  48 import java.util.HashSet;
  49 import java.util.Set;
  50 import java.util.Stack;
  51 import java.util.concurrent.CountDownLatch;
  52 
  53 import javafx.application.Platform;
  54 import javafx.beans.NamedArg;
  55 import javafx.scene.Scene;
  56 import javafx.scene.input.TransferMode;
  57 import javafx.stage.Window;
  58 import javafx.util.FXPermission;
  59 
  60 import org.eclipse.swt.SWT;
  61 import org.eclipse.swt.dnd.DND;
  62 import org.eclipse.swt.dnd.DragSource;
  63 import org.eclipse.swt.dnd.DragSourceListener;
  64 import org.eclipse.swt.dnd.DropTarget;
  65 import org.eclipse.swt.dnd.DropTargetEvent;
  66 import org.eclipse.swt.dnd.DropTargetListener;
  67 import org.eclipse.swt.dnd.FileTransfer;
  68 import org.eclipse.swt.dnd.HTMLTransfer;
  69 import org.eclipse.swt.dnd.ImageTransfer;
  70 import org.eclipse.swt.dnd.RTFTransfer;
  71 import org.eclipse.swt.dnd.TextTransfer;
  72 import org.eclipse.swt.dnd.Transfer;
  73 import org.eclipse.swt.dnd.TransferData;
  74 import org.eclipse.swt.dnd.URLTransfer;
  75 import org.eclipse.swt.events.ControlEvent;
  76 import org.eclipse.swt.events.ControlListener;
  77 import org.eclipse.swt.events.DisposeEvent;
  78 import org.eclipse.swt.events.DisposeListener;
  79 import org.eclipse.swt.events.FocusEvent;
  80 import org.eclipse.swt.events.FocusListener;
  81 import org.eclipse.swt.events.GestureEvent;
  82 import org.eclipse.swt.events.KeyEvent;
  83 import org.eclipse.swt.events.KeyListener;
  84 import org.eclipse.swt.events.MenuDetectEvent;
  85 import org.eclipse.swt.events.MouseEvent;
  86 import org.eclipse.swt.events.MouseListener;
  87 import org.eclipse.swt.events.MouseTrackListener;
  88 import org.eclipse.swt.events.PaintEvent;
  89 import org.eclipse.swt.graphics.Image;
  90 import org.eclipse.swt.graphics.ImageData;
  91 import org.eclipse.swt.graphics.PaletteData;
  92 import org.eclipse.swt.graphics.Point;
  93 import org.eclipse.swt.graphics.RGB;
  94 import org.eclipse.swt.graphics.Rectangle;
  95 import org.eclipse.swt.widgets.Canvas;
  96 import org.eclipse.swt.widgets.Composite;
  97 import org.eclipse.swt.widgets.Control;
  98 import org.eclipse.swt.widgets.Display;
  99 import org.eclipse.swt.widgets.Event;
 100 import org.eclipse.swt.widgets.Listener;
 101 import org.eclipse.swt.widgets.Shell;


 449             public void mouseUp(MouseEvent me) {
 450                 // FX only supports 3 buttons so don't send the event for other buttons
 451                 if (me.button > 3) return;
 452                 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_RELEASED);
 453             }
 454         });
 455 
 456         addMouseMoveListener(me -> {
 457             if ((me.stateMask & SWT.BUTTON_MASK) != 0) {
 458                 // FX only supports 3 buttons so don't send the event for other buttons
 459                 if ((me.stateMask & (SWT.BUTTON1 | SWT.BUTTON2 | SWT.BUTTON3)) != 0) {
 460                     FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED);
 461                 } else {
 462                     FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);
 463                 }
 464             } else {
 465                 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED);
 466             }
 467         });
 468 
 469         // SWT emulates mouse events from PAN gesture events.
 470         // We need to suppress them while a gesture is active or inertia events are still processed.
 471         addListener(SWT.MouseVerticalWheel, e -> {
 472             if (!gestureActive && (!panGestureInertiaActive || lastGestureEvent == null || e.time != lastGestureEvent.time)) {
 473                 FXCanvas.this.sendScrollEventToFX(AbstractEvents.MOUSEEVENT_VERTICAL_WHEEL,
 474                         0, SWTEvents.getWheelRotation(e), e.x, e.y, e.stateMask, false);
 475             }
 476         });
 477         addListener(SWT.MouseHorizontalWheel, e -> {
 478             if (!gestureActive && (!panGestureInertiaActive || lastGestureEvent == null || e.time != lastGestureEvent.time)) {
 479                 FXCanvas.this.sendScrollEventToFX(AbstractEvents.MOUSEEVENT_HORIZONTAL_WHEEL,
 480                         SWTEvents.getWheelRotation(e), 0, e.x, e.y, e.stateMask, false);
 481             }
 482         });
 483 
 484         addMouseTrackListener(new MouseTrackListener() {
 485             @Override
 486             public void mouseEnter(MouseEvent me) {
 487                 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_ENTERED);
 488             }
 489             @Override
 490             public void mouseExit(MouseEvent me) {
 491                 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_EXITED);
 492             }
 493             @Override
 494             public void mouseHover(MouseEvent me) {
 495                 // No mouse hovering in FX
 496             }
 497         });
 498 
 499         addControlListener(new ControlListener() {
 500             @Override
 501             public void controlMoved(ControlEvent ce) {


 513                 FXCanvas.this.sendFocusEventToFX(fe, true);
 514             }
 515             @Override
 516             public void focusLost(FocusEvent fe) {
 517                 FXCanvas.this.sendFocusEventToFX(fe, false);
 518             }
 519         });
 520 
 521         addKeyListener(new KeyListener() {
 522             @Override
 523             public void keyPressed(KeyEvent e) {
 524                 FXCanvas.this.sendKeyEventToFX(e, SWT.KeyDown);
 525 
 526             }
 527             @Override
 528             public void keyReleased(KeyEvent e) {
 529                 FXCanvas.this.sendKeyEventToFX(e, SWT.KeyUp);
 530             }
 531         });
 532 
 533         addGestureListener(ge -> {
 534             FXCanvas.this.sendGestureEventToFX(ge);
 535         });
 536 
 537         addMenuDetectListener(e -> {
 538             Runnable r = () -> {
 539                 if (isDisposed()) return;
 540                 FXCanvas.this.sendMenuEventToFX(e);
 541             };
 542             // In SWT, MenuDetect comes before the equivalent mouse event
 543             // On Mac, the order is MenuDetect, MouseDown, MouseUp.  FX
 544             // does not expect this order and when it gets the MouseDown,
 545             // it closes the menu.  The fix is to defer the MenuDetect
 546             // notification until after the MouseDown is sent to FX.
 547             if ("cocoa".equals(SWT.getPlatform())) {
 548                 getDisplay().asyncExec(r);
 549             } else {
 550                 r.run();
 551             }
 552         });
 553     }
 554 
 555     private void widgetDisposed(DisposeEvent de) {
 556         setDropTarget(null);


 677                     } else if ((me.stateMask & SWT.BUTTON3) != 0) {
 678                         button = 3;
 679                     }
 680                 }
 681                 break;
 682 
 683             default:
 684                 break;
 685         }
 686 
 687         scenePeer.mouseEvent(
 688                 embedMouseType,
 689                 SWTEvents.mouseButtonToEmbedMouseButton(button, me.stateMask),
 690                 primaryBtnDown, middleBtnDown, secondaryBtnDown,
 691                 me.x, me.y,
 692                 los.x, los.y,
 693                 shift, control, alt, meta,
 694                 false);  // RT-32990: popup trigger not implemented
 695     }
 696 
 697     double totalScrollX = 0;
 698     double totalScrollY = 0;
 699     private void sendScrollEventToFX(int type, double scrollX, double scrollY, int x, int y, int stateMask, boolean inertia) {
 700         if (scenePeer == null) {
 701             return;
 702         }
 703 
 704         double multiplier = 5.0;
 705         if (type == AbstractEvents.MOUSEEVENT_HORIZONTAL_WHEEL  || type == AbstractEvents.MOUSEEVENT_VERTICAL_WHEEL) {
 706             // granularity for mouse wheel scroll events is more coarse-grained than for pan gesture events
 707             multiplier = 40.0;
 708 
 709             // mouse wheel scroll events do not belong to a gesture,
 710             // so total scroll is not accumulated
 711             totalScrollX = scrollX;
 712             totalScrollY = scrollY;
 713         } else {
 714             // up to and including SWT 4.5, direction was inverted for pan gestures on the Mac
 715             // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=481331)
 716             if ("cocoa".equals(SWT.getPlatform()) && SWT.getVersion() < 4600) {
 717                 multiplier  *= -1.0;
 718             }
 719 
 720             if (type == AbstractEvents.SCROLLEVENT_STARTED) {
 721                 totalScrollX = 0;
 722                 totalScrollY = 0;
 723             } else if (inertia) {
 724                 // inertia events do not belong to the gesture,
 725                 // thus total scroll is not accumulated
 726                 totalScrollX = scrollX;
 727                 totalScrollY = scrollY;
 728             } else {
 729                 // accumulate total scroll as long as the gesture occurs
 730                 totalScrollX += scrollX;
 731                 totalScrollY += scrollY;
 732             }
 733         }
 734 
 735         Point los = toDisplay(x, y);
 736         scenePeer.scrollEvent(type,
 737                 scrollX, scrollY,
 738                 totalScrollX, totalScrollY,
 739                 multiplier, multiplier,
 740                 x, y,
 741                 los.x, los.y,
 742                 (stateMask & SWT.SHIFT) != 0,
 743                 (stateMask & SWT.CONTROL) != 0,
 744                 (stateMask & SWT.ALT) != 0,
 745                 (stateMask & SWT.COMMAND) != 0,
 746                 inertia);
 747     }
 748 
 749     private void sendKeyEventToFX(final KeyEvent e, int type) {
 750         if (scenePeer == null /*|| !isFxEnabled()*/) {
 751             return;
 752         }
 753         int stateMask = e.stateMask;
 754         if (type == SWT.KeyDown) {
 755             if (e.keyCode == SWT.SHIFT) stateMask |= SWT.SHIFT;
 756             if (e.keyCode == SWT.CONTROL) stateMask |= SWT.CONTROL;
 757             if (e.keyCode == SWT.ALT) stateMask |= SWT.ALT;
 758             if (e.keyCode == SWT.COMMAND) stateMask |= SWT.COMMAND;
 759         } else {
 760             if (e.keyCode == SWT.SHIFT) stateMask &= ~SWT.SHIFT;
 761             if (e.keyCode == SWT.CONTROL) stateMask &= ~SWT.CONTROL;
 762             if (e.keyCode == SWT.ALT) stateMask &= ~SWT.ALT;
 763             if (e.keyCode == SWT.COMMAND) stateMask &= ~SWT.COMMAND;
 764         }
 765         int keyCode = SWTEvents.keyCodeToEmbedKeyCode(e.keyCode);
 766         scenePeer.keyEvent(
 767                 SWTEvents.keyIDToEmbedKeyType(type),
 768                 keyCode, new char[0],
 769                 SWTEvents.keyModifiersToEmbedKeyModifiers(stateMask));
 770         if (e.character != '\0' && type == SWT.KeyDown) {
 771             char[] chars = new char[] { e.character };
 772             scenePeer.keyEvent(
 773                     AbstractEvents.KEYEVENT_TYPED,
 774                     e.keyCode, chars,
 775                     SWTEvents.keyModifiersToEmbedKeyModifiers(stateMask));
 776         }
 777     }
 778 
 779     // true in between begin and end events of a (compound) gesture (not including inertia events)
 780     private boolean gestureActive = false;
 781     // true while inertia events of a pan gesture might be processed
 782     private boolean panGestureInertiaActive = false;
 783     // the last gesture event that was received (may also be an inertia event)
 784     private GestureEvent lastGestureEvent;
 785     // used to keep track of which (atomic) gestures are enclosed
 786     private Stack<Integer> nestedGestures = new Stack<>();
 787     // data used to compute inertia values for pan gesture events (as SWT does not provide these)
 788     private long inertiaTime = 0;
 789     private double inertiaXScroll = 0.0;
 790     private double inertiaYScroll = 0.0;
 791     private void sendGestureEventToFX(GestureEvent gestureEvent) {
 792         if (scenePeer == null) {
 793             return;
 794         }
 795 
 796         // An SWT gesture may be compound, comprising several MAGNIFY, PAN, and ROTATE events, which are enclosed by a
 797         // generic BEGIN and END event (while SWIPE events occur without being enclosed).
 798         // In JavaFX, such a compound gesture is represented through (possibly nested) atomic gestures, which all
 799         // (again excluding swipe) have their specific START and FINISH events.
 800         // While a complex SWT gesture is active, we therefore have to generate START events for atomic gestures as
 801         // needed, finishing them all when the compound SWT gesture ends (in the reverse order they were started),
 802         // after which we still process inertia events (that only seem to occur for PAN). SWIPE events may simply be
 803         // forwarded.
 804         switch (gestureEvent.detail) {
 805             case SWT.GESTURE_BEGIN:
 806                 // a (complex) gesture has started
 807                 gestureActive = true;
 808                 // we are within an active gesture, so no inertia processing now
 809                 panGestureInertiaActive = false;
 810                 break;
 811             case SWT.GESTURE_MAGNIFY:
 812                 // emulate the start of an atomic gesture
 813                 if (gestureActive && !nestedGestures.contains(SWT.GESTURE_MAGNIFY)) {
 814                     sendZoomEventToFX(AbstractEvents.ZOOMEVENT_STARTED, gestureEvent);
 815                     nestedGestures.push(SWT.GESTURE_MAGNIFY);
 816                 }
 817                 sendZoomEventToFX(AbstractEvents.ZOOMEVENT_ZOOM, gestureEvent);
 818                 break;
 819             case SWT.GESTURE_PAN:
 820                 // emulate the start of an atomic gesture
 821                 if (gestureActive && !nestedGestures.contains(SWT.GESTURE_PAN)) {
 822                     sendScrollEventToFX(AbstractEvents.SCROLLEVENT_STARTED, gestureEvent.xDirection, gestureEvent.yDirection,
 823                             gestureEvent.x, gestureEvent.y, gestureEvent.stateMask, false);
 824                     nestedGestures.push(SWT.GESTURE_PAN);
 825                 }
 826 
 827                 // SWT does not flag inertia events and does not allow to distinguish emulated PAN gesture events
 828                 // (resulting from mouse wheel interaction) from native ones (resulting from touch device interaction);
 829                 // as it will always send both, mouse wheel as well as PAN gesture events when using the touch device or
 830                 // the mouse wheel, we can identify native PAN gesture inertia events only based on their temporal relationship
 831                 // to the preceding gesture event.
 832                 if(panGestureInertiaActive && gestureEvent.time > lastGestureEvent.time + 250) {
 833                     panGestureInertiaActive = false;
 834                 }
 835 
 836                 if(gestureActive || panGestureInertiaActive) {
 837                     double xDirection = gestureEvent.xDirection;
 838                     double yDirection = gestureEvent.yDirection;
 839 
 840                     if (panGestureInertiaActive) {
 841                         // calculate inertia values for scrollX and scrollY, as SWT (at least on MacOSX) provides zero values
 842                         if (xDirection == 0 && yDirection == 0) {
 843                             double delta = Math.max(0.0, Math.min(1.0, (gestureEvent.time - inertiaTime) / 1500.0));
 844                             xDirection = (1.0 - delta) * inertiaXScroll;
 845                             yDirection = (1.0 - delta) * inertiaYScroll;
 846                         }
 847                     }
 848 
 849                     sendScrollEventToFX(AbstractEvents.SCROLLEVENT_SCROLL, xDirection, yDirection,
 850                             gestureEvent.x, gestureEvent.y, gestureEvent.stateMask, panGestureInertiaActive);
 851                 }
 852                 break;
 853             case SWT.GESTURE_ROTATE:
 854                 // emulate the start of an atomic gesture
 855                 if(gestureActive && !nestedGestures.contains(SWT.GESTURE_ROTATE)) {
 856                     sendRotateEventToFX(AbstractEvents.ROTATEEVENT_STARTED, gestureEvent);
 857                     nestedGestures.push(SWT.GESTURE_ROTATE);
 858                 }
 859                 sendRotateEventToFX(AbstractEvents.ROTATEEVENT_ROTATE, gestureEvent);
 860                 break;
 861             case SWT.GESTURE_SWIPE:
 862                 sendSwipeEventToFX(gestureEvent);
 863                 break;
 864             case SWT.GESTURE_END:
 865                 // finish atomic gesture(s) in reverse order of their start; SWIPE may be ignored,
 866                 // as JavaFX (like SWT) does not recognize it as a gesture
 867                 while (!nestedGestures.isEmpty()) {
 868                     switch (nestedGestures.pop()) {
 869                         case SWT.GESTURE_MAGNIFY:
 870                             sendZoomEventToFX(AbstractEvents.ZOOMEVENT_FINISHED, gestureEvent);
 871                             break;
 872                         case SWT.GESTURE_PAN:
 873                             sendScrollEventToFX(AbstractEvents.SCROLLEVENT_FINISHED, gestureEvent.xDirection, gestureEvent.yDirection,
 874                                     gestureEvent.x, gestureEvent.y, gestureEvent.stateMask, false);
 875                             // use the scroll values of the preceding scroll event to compute values for inertia events
 876                             inertiaXScroll = lastGestureEvent.xDirection;
 877                             inertiaYScroll = lastGestureEvent.yDirection;
 878                             inertiaTime = gestureEvent.time;
 879                             // from now on, inertia events may occur
 880                             panGestureInertiaActive = true;
 881                             break;
 882                         case SWT.GESTURE_ROTATE:
 883                             sendRotateEventToFX(AbstractEvents.ROTATEEVENT_FINISHED, gestureEvent);
 884                             break;
 885                     }
 886                 }
 887                 // compound SWT gesture has ended
 888                 gestureActive = false;
 889                 break;
 890             default:
 891                 throw new IllegalStateException("Unsupported gesture event type: " + gestureEvent);
 892         }
 893         // keep track of currently received gesture event; this is needed to identify inertia events
 894         lastGestureEvent = gestureEvent;
 895     }
 896 
 897     // used to compute zoom deltas, which are not provided by SWT
 898     private double lastTotalZoom = 0.0;
 899     private void sendZoomEventToFX(int type, GestureEvent gestureEvent) {
 900         Point los = toDisplay(gestureEvent.x, gestureEvent.y);
 901 
 902         double totalZoom = gestureEvent.magnification;
 903         if (type == AbstractEvents.ZOOMEVENT_STARTED) {
 904             // ensure first event does not provide any zoom yet
 905             totalZoom = lastTotalZoom = 1.0;
 906         } else if (type == AbstractEvents.ZOOMEVENT_FINISHED) {
 907             // SWT uses 0.0 for final event, while JavaFX still provides a (total) zoom value
 908             totalZoom = lastTotalZoom;
 909         }
 910         double zoom = type == AbstractEvents.ZOOMEVENT_FINISHED ? 1.0 : totalZoom / lastTotalZoom;
 911         lastTotalZoom = totalZoom;
 912 
 913         scenePeer.zoomEvent(type, zoom, totalZoom,
 914                 gestureEvent.x, gestureEvent.y, los.x, los.y,
 915                 (gestureEvent.stateMask & SWT.SHIFT) != 0,
 916                 (gestureEvent.stateMask & SWT.CONTROL) != 0,
 917                 (gestureEvent.stateMask & SWT.ALT) != 0,
 918                 (gestureEvent.stateMask & SWT.COMMAND) != 0,
 919                 !gestureActive);
 920     }
 921 
 922     private double lastTotalAngle = 0.0;
 923     private void sendRotateEventToFX(int type, GestureEvent gestureEvent) {
 924         Point los = toDisplay(gestureEvent.x, gestureEvent.y);
 925 
 926         double totalAngle = gestureEvent.rotation;
 927         if (type == AbstractEvents.ROTATEEVENT_STARTED) {
 928             totalAngle = lastTotalAngle = 0.0;
 929         } else if (type == AbstractEvents.ROTATEEVENT_FINISHED) {
 930             // SWT uses 0.0 for final event, while JavaFX still provides a (total) rotation value
 931             totalAngle = lastTotalAngle;
 932         }
 933         double angle = type == AbstractEvents.ROTATEEVENT_FINISHED ? 0.0 : totalAngle - lastTotalAngle;
 934         lastTotalAngle = totalAngle;
 935 
 936         scenePeer.rotateEvent(type, angle, totalAngle,
 937                 gestureEvent.x, gestureEvent.y, los.x, los.y,
 938                 (gestureEvent.stateMask & SWT.SHIFT) != 0,
 939                 (gestureEvent.stateMask & SWT.CONTROL) != 0,
 940                 (gestureEvent.stateMask & SWT.ALT) != 0,
 941                 (gestureEvent.stateMask & SWT.COMMAND) != 0,
 942                 !gestureActive);
 943     }
 944 
 945     private void sendSwipeEventToFX(GestureEvent gestureEvent) {
 946         Point los = toDisplay(gestureEvent.x, gestureEvent.y);
 947         int type = -1;
 948         if(gestureEvent.yDirection > 0) {
 949             type = AbstractEvents.SWIPEEVENT_DOWN;
 950         } else if(gestureEvent.yDirection < 0) {
 951             type = AbstractEvents.SWIPEEVENT_UP;
 952         } else if(gestureEvent.xDirection > 0) {
 953             type = AbstractEvents.SWIPEEVENT_RIGHT;
 954         } else if(gestureEvent.xDirection < 0) {
 955             type = AbstractEvents.SWIPEEVENT_LEFT;
 956         }
 957         scenePeer.swipeEvent(type, gestureEvent.x, gestureEvent.y, los.x, los.y,
 958                 (gestureEvent.stateMask & SWT.SHIFT) != 0,
 959                 (gestureEvent.stateMask & SWT.CONTROL) != 0,
 960                 (gestureEvent.stateMask & SWT.ALT) != 0,
 961                 (gestureEvent.stateMask & SWT.COMMAND) != 0);
 962     }
 963 
 964     private void sendMenuEventToFX(MenuDetectEvent me) {
 965         if (scenePeer == null /*|| !isFxEnabled()*/) {
 966             return;
 967         }
 968         Point pt = toControl(me.x, me.y);
 969         scenePeer.menuEvent(pt.x, pt.y, me.x, me.y, false);
 970     }
 971 
 972     private void sendResizeEventToFX() {
 973 
 974         // force the panel to draw right away (avoid black rectangle)
 975         redraw();
 976         update();
 977 
 978         pWidth = getClientArea().width;
 979         pHeight = getClientArea().height;
 980 
 981         resizePixelBuffer(lastScaleFactor);
 982 
 983         if (scenePeer == null) {


< prev index next >