21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.embed.swing;
27
28 import java.awt.AlphaComposite;
29 import java.awt.AWTEvent;
30 import java.awt.Component;
31 import java.awt.Cursor;
32 import java.awt.Dimension;
33 import java.awt.Graphics;
34 import java.awt.Graphics2D;
35 import java.awt.KeyboardFocusManager;
36 import java.awt.Point;
37 import java.awt.Window;
38 import java.awt.Insets;
39 import java.awt.EventQueue;
40 import java.awt.SecondaryLoop;
41 import java.awt.event.AWTEventListener;
42 import java.awt.event.ComponentEvent;
43 import java.awt.event.FocusEvent;
44 import java.awt.event.HierarchyEvent;
45 import java.awt.event.InputEvent;
46 import java.awt.event.InputMethodEvent;
47 import java.awt.event.KeyEvent;
48 import java.awt.event.MouseEvent;
49 import java.awt.event.MouseWheelEvent;
50 import java.awt.event.FocusAdapter;
51 import java.awt.event.FocusListener;
52 import java.awt.im.InputMethodRequests;
53 import java.awt.image.BufferedImage;
54 import java.awt.image.DataBufferInt;
55 import java.awt.datatransfer.Clipboard;
56 import java.nio.IntBuffer;
57 import java.security.AccessController;
58 import java.security.PrivilegedAction;
59 import java.util.concurrent.CountDownLatch;
60
61 import javafx.application.Platform;
62 import javafx.scene.Scene;
63
64 import javax.swing.JComponent;
65 import javax.swing.SwingUtilities;
66
67 import com.sun.javafx.application.PlatformImpl;
68 import com.sun.javafx.cursor.CursorFrame;
69 import com.sun.javafx.embed.AbstractEvents;
70 import com.sun.javafx.embed.EmbeddedSceneInterface;
71 import com.sun.javafx.embed.EmbeddedStageInterface;
72 import com.sun.javafx.embed.HostInterface;
73 import com.sun.javafx.stage.EmbeddedWindow;
74 import com.sun.javafx.tk.Toolkit;
75 import com.sun.javafx.PlatformUtil;
76 import java.awt.event.InvocationEvent;
77
78 import java.lang.reflect.Method;
79 import java.util.concurrent.atomic.AtomicInteger;
80 import sun.awt.AppContext;
81 import sun.awt.SunToolkit;
82 import sun.java2d.SunGraphics2D;
83 import sun.java2d.SurfaceData;
84 import com.sun.javafx.logging.PlatformLogger;
85 import com.sun.javafx.logging.PlatformLogger.Level;
86
87 /**
88 * {@code JFXPanel} is a component to embed JavaFX content into
89 * Swing applications. The content to be displayed is specified
90 * with the {@link #setScene} method that accepts an instance of
91 * JavaFX {@code Scene}. After the scene is assigned, it gets
92 * repainted automatically. All the input and focus events are
93 * forwarded to the scene transparently to the developer.
94 * <p>
95 * There are some restrictions related to {@code JFXPanel}. As a
96 * Swing component, it should only be accessed from the event
97 * dispatch thread, except the {@link #setScene} method, which can
98 * be called either on the event dispatch thread or on the JavaFX
99 * application thread.
100 * <p>
101 * Here is a typical pattern how {@code JFXPanel} can used:
102 * <pre>
103 * public class Test {
104 *
105 * private static void initAndShowGUI() {
106 * // This method is invoked on Swing thread
168 private volatile int pPreferredHeight = -1;
169
170 // Cached copy of this component's location on screen to avoid
171 // calling getLocationOnScreen() under the tree lock on FX thread
172 private volatile int screenX = 0;
173 private volatile int screenY = 0;
174
175 // Accessed on EDT only
176 private BufferedImage pixelsIm;
177
178 private volatile float opacity = 1.0f;
179
180 // Indicates how many times setFxEnabled(false) has been called.
181 // A value of 0 means the component is enabled.
182 private AtomicInteger disableCount = new AtomicInteger(0);
183
184 private boolean isCapturingMouse = false;
185
186 private static boolean fxInitialized;
187
188 private synchronized void registerFinishListener() {
189 if (instanceCount.getAndIncrement() > 0) {
190 // Already registered
191 return;
192 }
193 // Need to install a finish listener to catch calls to Platform.exit
194 finishListener = new PlatformImpl.FinishListener() {
195 @Override public void idle(boolean implicitExit) {
196 }
197 @Override public void exitCalled() {
198 }
199 };
200 PlatformImpl.addListener(finishListener);
201 }
202
203 private synchronized void deregisterFinishListener() {
204 if (instanceCount.decrementAndGet() > 0) {
205 // Other JFXPanels still alive
206 return;
207 }
433
434 /**
435 * Overrides the {@link java.awt.Component#processMouseEvent(MouseEvent)}
436 * method to dispatch the mouse event to the JavaFX scene attached to this
437 * {@code JFXPanel}.
438 *
439 * @param e the mouse event to dispatch to the JavaFX scene
440 */
441 @Override
442 protected void processMouseEvent(MouseEvent e) {
443 if ((e.getID() == MouseEvent.MOUSE_PRESSED) &&
444 (e.getButton() == MouseEvent.BUTTON1)) {
445 if (!hasFocus()) {
446 requestFocus();
447 // this focus request event goes to eventqueue and will be
448 // asynchronously handled so MOUSE_PRESSED event will not be
449 // honoured by FX immediately due to lack of focus in fx
450 // component. Fire the same MOUSE_PRESSED event after
451 // requestFocus() so that 2nd mouse press will be honoured
452 // since now fx have focus
453 AppContext context = SunToolkit.targetToAppContext(this);
454 if (context != null) {
455 SunToolkit.postEvent(context, e);
456 }
457 }
458 }
459
460 sendMouseEventToFX(e);
461 super.processMouseEvent(e);
462 }
463
464 /**
465 * Overrides the {@link java.awt.Component#processMouseMotionEvent(MouseEvent)}
466 * method to dispatch the mouse motion event to the JavaFX scene attached to
467 * this {@code JFXPanel}.
468 *
469 * @param e the mouse motion event to dispatch to the JavaFX scene
470 */
471 @Override
472 protected void processMouseMotionEvent(MouseEvent e) {
473 sendMouseEventToFX(e);
474 super.processMouseMotionEvent(e);
475 }
476
553 }
554 super.processComponentEvent(e);
555 }
556
557 // called on EDT only
558 private void updateComponentSize() {
559 int oldWidth = pWidth;
560 int oldHeight = pHeight;
561 // It's quite possible to get negative values here, this is not
562 // what JavaFX embedded scenes/stages are ready to
563 pWidth = Math.max(0, getWidth());
564 pHeight = Math.max(0, getHeight());
565 if (getBorder() != null) {
566 Insets i = getBorder().getBorderInsets(this);
567 pWidth -= (i.left + i.right);
568 pHeight -= (i.top + i.bottom);
569 }
570 double newScaleFactorX = scaleFactorX;
571 double newScaleFactorY = scaleFactorY;
572 Graphics g = getGraphics();
573 if (g instanceof SunGraphics2D) {
574 SurfaceData sd = ((SunGraphics2D) g).surfaceData;
575 newScaleFactorX = sd.getDefaultScaleX();
576 newScaleFactorY = sd.getDefaultScaleY();
577 }
578 if (oldWidth != pWidth || oldHeight != pHeight ||
579 newScaleFactorX != scaleFactorX || newScaleFactorY != scaleFactorY)
580 {
581 createResizePixelBuffer(newScaleFactorX, newScaleFactorY);
582 if (scenePeer != null) {
583 scenePeer.setPixelScaleFactors((float) newScaleFactorX,
584 (float) newScaleFactorY);
585 }
586 scaleFactorX = newScaleFactorX;
587 scaleFactorY = newScaleFactorY;
588 sendResizeEventToFX();
589 }
590 }
591
592 // This methods should only be called on EDT
593 private boolean updateScreenLocation() {
594 synchronized (getTreeLock()) {
595 if (isShowing()) {
596 Point p = getLocationOnScreen();
597 screenX = p.x;
748 if (!scenePeer.getPixels(buf, pWidth, pHeight)) {
749 // In this case we just render what we have so far in the buffer.
750 }
751
752 Graphics gg = null;
753 try {
754 gg = g.create();
755 if ((opacity < 1.0f) && (gg instanceof Graphics2D)) {
756 Graphics2D g2d = (Graphics2D)gg;
757 AlphaComposite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
758 g2d.setComposite(c);
759 }
760 if (getBorder() != null) {
761 Insets i = getBorder().getBorderInsets(this);
762 gg.translate(i.left, i.top);
763 }
764 gg.drawImage(pixelsIm, 0, 0, pWidth, pHeight, null);
765
766 double newScaleFactorX = scaleFactorX;
767 double newScaleFactorY = scaleFactorY;
768 if (g instanceof SunGraphics2D) {
769 SurfaceData sd = ((SunGraphics2D)g).surfaceData;
770 newScaleFactorX = sd.getDefaultScaleX();
771 newScaleFactorY = sd.getDefaultScaleY();
772 }
773 if (scaleFactorX != newScaleFactorX || scaleFactorY != newScaleFactorY) {
774 createResizePixelBuffer(newScaleFactorX, newScaleFactorY);
775 // The scene will request repaint.
776 scenePeer.setPixelScaleFactors((float) newScaleFactorX,
777 (float) newScaleFactorY);
778 scaleFactorX = newScaleFactorX;
779 scaleFactorY = newScaleFactorY;
780 }
781 } catch (Throwable th) {
782 th.printStackTrace();
783 } finally {
784 if (gg != null) {
785 gg.dispose();
786 }
787 }
788 }
789
790 /**
791 * Returns the preferred size of this {@code JFXPanel}, either
792 * previously set with {@link #setPreferredSize(Dimension)} or
811 if (!enabled) {
812 if (disableCount.incrementAndGet() == 1) {
813 if (dnd != null) {
814 dnd.removeNotify();
815 }
816 }
817 } else {
818 if (disableCount.get() == 0) {
819 //should report a warning about an extra enable call ?
820 return;
821 }
822 if (disableCount.decrementAndGet() == 0) {
823 if (dnd != null) {
824 dnd.addNotify();
825 }
826 }
827 }
828 }
829
830 private transient AWTEventListener ungrabListener = event -> {
831 if (event instanceof sun.awt.UngrabEvent) {
832 SwingFXUtils.runOnFxThread(() -> {
833 if (JFXPanel.this.stagePeer != null &&
834 getScene() != null &&
835 getScene().getFocusOwner() != null &&
836 getScene().getFocusOwner().isFocused()) {
837 JFXPanel.this.stagePeer.focusUngrab();
838 }
839 });
840 }
841 if (event instanceof MouseEvent) {
842 // Synthesize FOCUS_UNGRAB if user clicks the AWT top-level window
843 // that contains the JFXPanel.
844 if (event.getID() == MouseEvent.MOUSE_PRESSED && event.getSource() instanceof Component) {
845 final Window jfxPanelWindow = SwingUtilities.getWindowAncestor(JFXPanel.this);
846 final Component source = (Component)event.getSource();
847 final Window eventWindow = source instanceof Window ? (Window)source : SwingUtilities.getWindowAncestor(source);
848
849 if (jfxPanelWindow == eventWindow) {
850 SwingFXUtils.runOnFxThread(() -> {
851 if (JFXPanel.this.stagePeer != null) {
860 }
861 });
862 }
863 }
864 }
865 };
866
867 /**
868 * Notifies this component that it now has a parent component. When this
869 * method is invoked, the chain of parent components is set up with
870 * KeyboardAction event listeners.
871 */
872 @Override
873 public void addNotify() {
874 super.addNotify();
875
876 registerFinishListener();
877
878 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
879 JFXPanel.this.getToolkit().addAWTEventListener(ungrabListener,
880 SunToolkit.GRAB_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
881 return null;
882 });
883 updateComponentSize(); // see RT-23603
884 SwingFXUtils.runOnFxThread(() -> {
885 if ((stage != null) && !stage.isShowing()) {
886 stage.show();
887 sendMoveEventToFX();
888 }
889 });
890 }
891
892 @Override
893 public InputMethodRequests getInputMethodRequests() {
894 EmbeddedSceneInterface scene = scenePeer;
895 if (scene == null) {
896 return null;
897 }
898 return new InputMethodSupport.InputMethodRequestsAdapter(scene.getInputMethodRequests());
899 }
900
911 });
912
913 pixelsIm = null;
914 pWidth = 0;
915 pHeight = 0;
916
917 super.removeNotify();
918
919 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
920 JFXPanel.this.getToolkit().removeAWTEventListener(ungrabListener);
921 return null;
922 });
923
924 /* see CR 4867453 */
925 getInputContext().removeNotify(this);
926
927 deregisterFinishListener();
928 }
929
930 private void invokeOnClientEDT(Runnable r) {
931 AppContext context = SunToolkit.targetToAppContext(this);
932 if (context == null) {
933 if (log.isLoggable(Level.FINE)) log.fine("null AppContext encountered!");
934 return;
935 }
936 SunToolkit.postEvent(context, new InvocationEvent(this, r));
937 }
938
939 private class HostContainer implements HostInterface {
940
941 @Override
942 public void setEmbeddedStage(EmbeddedStageInterface embeddedStage) {
943 stagePeer = embeddedStage;
944 if (stagePeer == null) {
945 return;
946 }
947 if (pWidth > 0 && pHeight > 0) {
948 stagePeer.setSize(pWidth, pHeight);
949 }
950 invokeOnClientEDT(() -> {
951 if (stagePeer != null && JFXPanel.this.isFocusOwner()) {
952 stagePeer.setFocused(true, AbstractEvents.FOCUSEVENT_ACTIVATED);
953 }
954 });
955 sendMoveEventToFX();
956 }
1037 return cachedPlatformCursor;
1038 }
1039
1040 // platform cursor not cached yet
1041 final Cursor platformCursor =
1042 SwingCursors.embedCursorToCursor(cursorFrame);
1043 cursorFrame.setPlatforCursor(Cursor.class, platformCursor);
1044
1045 return platformCursor;
1046 }
1047
1048 @Override
1049 public boolean grabFocus() {
1050 // On X11 grab is limited to a single XDisplay connection,
1051 // so we can't delegate it to another GUI toolkit.
1052 if (PlatformUtil.isLinux()) return true;
1053
1054 invokeOnClientEDT(() -> {
1055 Window window = SwingUtilities.getWindowAncestor(JFXPanel.this);
1056 if (window != null) {
1057 if (JFXPanel.this.getToolkit() instanceof SunToolkit) {
1058 ((SunToolkit)JFXPanel.this.getToolkit()).grab(window);
1059 }
1060 }
1061 });
1062
1063 return true; // Oh, well...
1064 }
1065
1066 @Override
1067 public void ungrabFocus() {
1068 // On X11 grab is limited to a single XDisplay connection,
1069 // so we can't delegate it to another GUI toolkit.
1070 if (PlatformUtil.isLinux()) return;
1071
1072 invokeOnClientEDT(() -> {
1073 Window window = SwingUtilities.getWindowAncestor(JFXPanel.this);
1074 if (window != null) {
1075 if (JFXPanel.this.getToolkit() instanceof SunToolkit) {
1076 ((SunToolkit)JFXPanel.this.getToolkit()).ungrab(window);
1077 }
1078 }
1079 });
1080 }
1081 }
1082 }
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.embed.swing;
27
28 import java.awt.AlphaComposite;
29 import java.awt.AWTEvent;
30 import java.awt.Component;
31 import java.awt.Cursor;
32 import java.awt.Dimension;
33 import java.awt.Graphics;
34 import java.awt.Graphics2D;
35 import java.awt.KeyboardFocusManager;
36 import java.awt.Point;
37 import java.awt.Window;
38 import java.awt.Insets;
39 import java.awt.EventQueue;
40 import java.awt.SecondaryLoop;
41 import java.awt.GraphicsEnvironment;
42 import java.awt.event.AWTEventListener;
43 import java.awt.event.ComponentEvent;
44 import java.awt.event.FocusEvent;
45 import java.awt.event.HierarchyEvent;
46 import java.awt.event.InputEvent;
47 import java.awt.event.InputMethodEvent;
48 import java.awt.event.KeyEvent;
49 import java.awt.event.MouseEvent;
50 import java.awt.event.MouseWheelEvent;
51 import java.awt.event.FocusAdapter;
52 import java.awt.event.FocusListener;
53 import java.awt.im.InputMethodRequests;
54 import java.awt.image.BufferedImage;
55 import java.awt.image.DataBufferInt;
56 import java.awt.datatransfer.Clipboard;
57 import java.nio.IntBuffer;
58 import java.security.AccessController;
59 import java.security.PrivilegedAction;
60 import java.util.concurrent.CountDownLatch;
61
62 import javafx.application.Platform;
63 import javafx.scene.Scene;
64
65 import javax.swing.JComponent;
66 import javax.swing.SwingUtilities;
67
68 import com.sun.javafx.application.PlatformImpl;
69 import com.sun.javafx.cursor.CursorFrame;
70 import com.sun.javafx.embed.AbstractEvents;
71 import com.sun.javafx.embed.EmbeddedSceneInterface;
72 import com.sun.javafx.embed.EmbeddedStageInterface;
73 import com.sun.javafx.embed.HostInterface;
74 import com.sun.javafx.stage.EmbeddedWindow;
75 import com.sun.javafx.tk.Toolkit;
76 import com.sun.javafx.PlatformUtil;
77 import java.awt.event.InvocationEvent;
78
79 import java.lang.reflect.Method;
80 import java.util.concurrent.atomic.AtomicInteger;
81
82 import com.sun.javafx.logging.PlatformLogger;
83 import com.sun.javafx.logging.PlatformLogger.Level;
84
85 import com.sun.javafx.embed.swing.InteropFactory;
86 import com.sun.javafx.embed.swing.SwingDnD;
87 import com.sun.javafx.embed.swing.SwingEvents;
88 import com.sun.javafx.embed.swing.SwingCursors;
89 import com.sun.javafx.embed.swing.JFXPanelInterop;
90
91 /**
92 * {@code JFXPanel} is a component to embed JavaFX content into
93 * Swing applications. The content to be displayed is specified
94 * with the {@link #setScene} method that accepts an instance of
95 * JavaFX {@code Scene}. After the scene is assigned, it gets
96 * repainted automatically. All the input and focus events are
97 * forwarded to the scene transparently to the developer.
98 * <p>
99 * There are some restrictions related to {@code JFXPanel}. As a
100 * Swing component, it should only be accessed from the event
101 * dispatch thread, except the {@link #setScene} method, which can
102 * be called either on the event dispatch thread or on the JavaFX
103 * application thread.
104 * <p>
105 * Here is a typical pattern how {@code JFXPanel} can used:
106 * <pre>
107 * public class Test {
108 *
109 * private static void initAndShowGUI() {
110 * // This method is invoked on Swing thread
172 private volatile int pPreferredHeight = -1;
173
174 // Cached copy of this component's location on screen to avoid
175 // calling getLocationOnScreen() under the tree lock on FX thread
176 private volatile int screenX = 0;
177 private volatile int screenY = 0;
178
179 // Accessed on EDT only
180 private BufferedImage pixelsIm;
181
182 private volatile float opacity = 1.0f;
183
184 // Indicates how many times setFxEnabled(false) has been called.
185 // A value of 0 means the component is enabled.
186 private AtomicInteger disableCount = new AtomicInteger(0);
187
188 private boolean isCapturingMouse = false;
189
190 private static boolean fxInitialized;
191
192 private static JFXPanelInterop jfxPaneliop;
193
194 static {
195 InteropFactory instance = null;
196 try {
197 instance = InteropFactory.getInstance();
198 } catch (Exception e) {
199 throw new ExceptionInInitializerError(e);
200 }
201 jfxPaneliop = instance.createJFXPanelImpl();
202 }
203
204 private synchronized void registerFinishListener() {
205 if (instanceCount.getAndIncrement() > 0) {
206 // Already registered
207 return;
208 }
209 // Need to install a finish listener to catch calls to Platform.exit
210 finishListener = new PlatformImpl.FinishListener() {
211 @Override public void idle(boolean implicitExit) {
212 }
213 @Override public void exitCalled() {
214 }
215 };
216 PlatformImpl.addListener(finishListener);
217 }
218
219 private synchronized void deregisterFinishListener() {
220 if (instanceCount.decrementAndGet() > 0) {
221 // Other JFXPanels still alive
222 return;
223 }
449
450 /**
451 * Overrides the {@link java.awt.Component#processMouseEvent(MouseEvent)}
452 * method to dispatch the mouse event to the JavaFX scene attached to this
453 * {@code JFXPanel}.
454 *
455 * @param e the mouse event to dispatch to the JavaFX scene
456 */
457 @Override
458 protected void processMouseEvent(MouseEvent e) {
459 if ((e.getID() == MouseEvent.MOUSE_PRESSED) &&
460 (e.getButton() == MouseEvent.BUTTON1)) {
461 if (!hasFocus()) {
462 requestFocus();
463 // this focus request event goes to eventqueue and will be
464 // asynchronously handled so MOUSE_PRESSED event will not be
465 // honoured by FX immediately due to lack of focus in fx
466 // component. Fire the same MOUSE_PRESSED event after
467 // requestFocus() so that 2nd mouse press will be honoured
468 // since now fx have focus
469 jfxPaneliop.postEvent(this, e);
470 }
471 }
472
473 sendMouseEventToFX(e);
474 super.processMouseEvent(e);
475 }
476
477 /**
478 * Overrides the {@link java.awt.Component#processMouseMotionEvent(MouseEvent)}
479 * method to dispatch the mouse motion event to the JavaFX scene attached to
480 * this {@code JFXPanel}.
481 *
482 * @param e the mouse motion event to dispatch to the JavaFX scene
483 */
484 @Override
485 protected void processMouseMotionEvent(MouseEvent e) {
486 sendMouseEventToFX(e);
487 super.processMouseMotionEvent(e);
488 }
489
566 }
567 super.processComponentEvent(e);
568 }
569
570 // called on EDT only
571 private void updateComponentSize() {
572 int oldWidth = pWidth;
573 int oldHeight = pHeight;
574 // It's quite possible to get negative values here, this is not
575 // what JavaFX embedded scenes/stages are ready to
576 pWidth = Math.max(0, getWidth());
577 pHeight = Math.max(0, getHeight());
578 if (getBorder() != null) {
579 Insets i = getBorder().getBorderInsets(this);
580 pWidth -= (i.left + i.right);
581 pHeight -= (i.top + i.bottom);
582 }
583 double newScaleFactorX = scaleFactorX;
584 double newScaleFactorY = scaleFactorY;
585 Graphics g = getGraphics();
586 newScaleFactorX = GraphicsEnvironment.getLocalGraphicsEnvironment().
587 getDefaultScreenDevice().getDefaultConfiguration().
588 getDefaultTransform().getScaleX();
589 newScaleFactorY = GraphicsEnvironment.getLocalGraphicsEnvironment().
590 getDefaultScreenDevice().getDefaultConfiguration().
591 getDefaultTransform().getScaleY();
592 if (oldWidth != pWidth || oldHeight != pHeight ||
593 newScaleFactorX != scaleFactorX || newScaleFactorY != scaleFactorY)
594 {
595 createResizePixelBuffer(newScaleFactorX, newScaleFactorY);
596 if (scenePeer != null) {
597 scenePeer.setPixelScaleFactors((float) newScaleFactorX,
598 (float) newScaleFactorY);
599 }
600 scaleFactorX = newScaleFactorX;
601 scaleFactorY = newScaleFactorY;
602 sendResizeEventToFX();
603 }
604 }
605
606 // This methods should only be called on EDT
607 private boolean updateScreenLocation() {
608 synchronized (getTreeLock()) {
609 if (isShowing()) {
610 Point p = getLocationOnScreen();
611 screenX = p.x;
762 if (!scenePeer.getPixels(buf, pWidth, pHeight)) {
763 // In this case we just render what we have so far in the buffer.
764 }
765
766 Graphics gg = null;
767 try {
768 gg = g.create();
769 if ((opacity < 1.0f) && (gg instanceof Graphics2D)) {
770 Graphics2D g2d = (Graphics2D)gg;
771 AlphaComposite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
772 g2d.setComposite(c);
773 }
774 if (getBorder() != null) {
775 Insets i = getBorder().getBorderInsets(this);
776 gg.translate(i.left, i.top);
777 }
778 gg.drawImage(pixelsIm, 0, 0, pWidth, pHeight, null);
779
780 double newScaleFactorX = scaleFactorX;
781 double newScaleFactorY = scaleFactorY;
782 newScaleFactorX = GraphicsEnvironment.getLocalGraphicsEnvironment().
783 getDefaultScreenDevice().getDefaultConfiguration().
784 getDefaultTransform().getScaleX();
785 newScaleFactorY = GraphicsEnvironment.getLocalGraphicsEnvironment().
786 getDefaultScreenDevice().getDefaultConfiguration().
787 getDefaultTransform().getScaleY();
788 if (scaleFactorX != newScaleFactorX || scaleFactorY != newScaleFactorY) {
789 createResizePixelBuffer(newScaleFactorX, newScaleFactorY);
790 // The scene will request repaint.
791 scenePeer.setPixelScaleFactors((float) newScaleFactorX,
792 (float) newScaleFactorY);
793 scaleFactorX = newScaleFactorX;
794 scaleFactorY = newScaleFactorY;
795 }
796 } catch (Throwable th) {
797 th.printStackTrace();
798 } finally {
799 if (gg != null) {
800 gg.dispose();
801 }
802 }
803 }
804
805 /**
806 * Returns the preferred size of this {@code JFXPanel}, either
807 * previously set with {@link #setPreferredSize(Dimension)} or
826 if (!enabled) {
827 if (disableCount.incrementAndGet() == 1) {
828 if (dnd != null) {
829 dnd.removeNotify();
830 }
831 }
832 } else {
833 if (disableCount.get() == 0) {
834 //should report a warning about an extra enable call ?
835 return;
836 }
837 if (disableCount.decrementAndGet() == 0) {
838 if (dnd != null) {
839 dnd.addNotify();
840 }
841 }
842 }
843 }
844
845 private transient AWTEventListener ungrabListener = event -> {
846 if (jfxPaneliop.isUngrabEvent(event)) {
847 SwingFXUtils.runOnFxThread(() -> {
848 if (JFXPanel.this.stagePeer != null &&
849 getScene() != null &&
850 getScene().getFocusOwner() != null &&
851 getScene().getFocusOwner().isFocused()) {
852 JFXPanel.this.stagePeer.focusUngrab();
853 }
854 });
855 }
856 if (event instanceof MouseEvent) {
857 // Synthesize FOCUS_UNGRAB if user clicks the AWT top-level window
858 // that contains the JFXPanel.
859 if (event.getID() == MouseEvent.MOUSE_PRESSED && event.getSource() instanceof Component) {
860 final Window jfxPanelWindow = SwingUtilities.getWindowAncestor(JFXPanel.this);
861 final Component source = (Component)event.getSource();
862 final Window eventWindow = source instanceof Window ? (Window)source : SwingUtilities.getWindowAncestor(source);
863
864 if (jfxPanelWindow == eventWindow) {
865 SwingFXUtils.runOnFxThread(() -> {
866 if (JFXPanel.this.stagePeer != null) {
875 }
876 });
877 }
878 }
879 }
880 };
881
882 /**
883 * Notifies this component that it now has a parent component. When this
884 * method is invoked, the chain of parent components is set up with
885 * KeyboardAction event listeners.
886 */
887 @Override
888 public void addNotify() {
889 super.addNotify();
890
891 registerFinishListener();
892
893 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
894 JFXPanel.this.getToolkit().addAWTEventListener(ungrabListener,
895 jfxPaneliop.setMask());
896 return null;
897 });
898 updateComponentSize(); // see RT-23603
899 SwingFXUtils.runOnFxThread(() -> {
900 if ((stage != null) && !stage.isShowing()) {
901 stage.show();
902 sendMoveEventToFX();
903 }
904 });
905 }
906
907 @Override
908 public InputMethodRequests getInputMethodRequests() {
909 EmbeddedSceneInterface scene = scenePeer;
910 if (scene == null) {
911 return null;
912 }
913 return new InputMethodSupport.InputMethodRequestsAdapter(scene.getInputMethodRequests());
914 }
915
926 });
927
928 pixelsIm = null;
929 pWidth = 0;
930 pHeight = 0;
931
932 super.removeNotify();
933
934 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
935 JFXPanel.this.getToolkit().removeAWTEventListener(ungrabListener);
936 return null;
937 });
938
939 /* see CR 4867453 */
940 getInputContext().removeNotify(this);
941
942 deregisterFinishListener();
943 }
944
945 private void invokeOnClientEDT(Runnable r) {
946 jfxPaneliop.postEvent(this, new InvocationEvent(this, r));
947 }
948
949 private class HostContainer implements HostInterface {
950
951 @Override
952 public void setEmbeddedStage(EmbeddedStageInterface embeddedStage) {
953 stagePeer = embeddedStage;
954 if (stagePeer == null) {
955 return;
956 }
957 if (pWidth > 0 && pHeight > 0) {
958 stagePeer.setSize(pWidth, pHeight);
959 }
960 invokeOnClientEDT(() -> {
961 if (stagePeer != null && JFXPanel.this.isFocusOwner()) {
962 stagePeer.setFocused(true, AbstractEvents.FOCUSEVENT_ACTIVATED);
963 }
964 });
965 sendMoveEventToFX();
966 }
1047 return cachedPlatformCursor;
1048 }
1049
1050 // platform cursor not cached yet
1051 final Cursor platformCursor =
1052 SwingCursors.embedCursorToCursor(cursorFrame);
1053 cursorFrame.setPlatforCursor(Cursor.class, platformCursor);
1054
1055 return platformCursor;
1056 }
1057
1058 @Override
1059 public boolean grabFocus() {
1060 // On X11 grab is limited to a single XDisplay connection,
1061 // so we can't delegate it to another GUI toolkit.
1062 if (PlatformUtil.isLinux()) return true;
1063
1064 invokeOnClientEDT(() -> {
1065 Window window = SwingUtilities.getWindowAncestor(JFXPanel.this);
1066 if (window != null) {
1067 jfxPaneliop.grab(JFXPanel.this.getToolkit(), window);
1068 }
1069 });
1070
1071 return true; // Oh, well...
1072 }
1073
1074 @Override
1075 public void ungrabFocus() {
1076 // On X11 grab is limited to a single XDisplay connection,
1077 // so we can't delegate it to another GUI toolkit.
1078 if (PlatformUtil.isLinux()) return;
1079
1080 invokeOnClientEDT(() -> {
1081 Window window = SwingUtilities.getWindowAncestor(JFXPanel.this);
1082 if (window != null) {
1083 jfxPaneliop.ungrab(JFXPanel.this.getToolkit(), window);
1084 }
1085 });
1086 }
1087 }
1088 }
|