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) {
|