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

Provide public, unsupported JDK API for JavaFX / Swing interop

    Details

    • Type: CSR
    • Status: Closed
    • Priority: P2
    • Resolution: Approved
    • Fix Version/s: 11
    • Component/s: client-libs
    • Labels:
      None
    • Subcomponent:
    • Compatibility Risk:
      minimal
    • Compatibility Risk Description:
      This adds a new module, so there should be no compatibility issues.
    • Interface Kind:
      Java API
    • Scope:
      JDK

      Description

      Summary

      Provide a new module, jdk.unsupported.desktop, which provides API that wraps and exports otherwise inaccessible java.desktop internals, The sole intended client of this is the unbundled OpenJFX, which needs these APIs to support interoperation between Swing and JavaFX components to replace previous use of internal APIs when it was part of Oracle JDK.

      Problem

      A JavaFX UI can embed Swing UI, and vice versa. This embedding also includes support for Drag and Drop between the two API stacks. There is no suitable public API in the java.desktop module to support all the required parts of this, and designing such API is non-trivial, or may be undesirable. Previously, when JavaFX was part of the Oracle JDK, it was able to use internal JDK APIs from the java.desktop module to support this requirement, with java.desktop providing qualified exports to the appropriate javafx modules. Now in JDK 11 that is no longer possible and requiring that JavaFX applications use command line --add-export options to re-enable this support is not desirable.

      Solution

      Provide a new "jdk.unsupported.desktop" module that exports public API that is intended to be used by the javafx.swing module. The concept is the same as jdk.unsupported, in that it is documented as being unsupported and may be removed, either partially or wholly, without notice in a later release, possibly by being superseded by standard SE API, or just removed. Further, since it is only intended to be used by javafx.swing, it need not be in the default module graph. The module-info.java will look like this:

      module jdk.unsupported.desktop { 
          requires transitive java.desktop;
      
          exports jdk.swing.interop;
      } 

      The java.desktop module exports the 6 packages needed for swing interop to jdk.unsupported.desktop (and no other changes to java.desktop).

      jdk.unsupported.desktop module will expose 6 public classes in jdk.swing.interop package to be used by javafx.swing.

      src/jdk.unsupported.desktop/share/classes/jdk/swing/interop/LightweightFrameWrapper.java
      src/jdk.unsupported.desktop/share/classes/jdk/swing/interop/LightweightContentWrapper.java
      src/jdk.unsupported.desktop/share/classes/jdk/swing/interop/SwingInterOpUtils.java
      src/jdk.unsupported.desktop/share/classes/jdk/swing/interop/DragSourceContextWrapper.java
      src/jdk.unsupported.desktop/share/classes/jdk/swing/interop/DropTargetContextWrapper.java.
      and
      src/jdk.unsupported.desktop/share/classes/jdk/swing/interop/DispatcherWrapper.java

      Specification

      /**
        * This class wraps sun.swing.JLightweightFrame and implements
        * APIs to be used by FX swing interop to access and use JLightweightFrame APIs.
        */
      public class LightweightFrameWrapper  {
          public LightweightFrameWrapper() {}
          public void notifyDisplayChanged(final int scaleFactor) {}
          /**
            * {@code overrideNativeWindowHandle()} is package private but
            * part of the interface. It supports providing a foreign native window
            * handle (i.e. an FX window handle) to AWT, and as such is intended to
            * be called via JNI code, not by Java code, so it is not public
            */
          void overrideNativeWindowHandle(long handle, Runnable closeWindow) {}
          public void setHostBounds(int x, int y, int w, int h) {}
          public void dispose() {}
          public void addWindowFocusListener(WindowFocusListener listener) {}
          public void setVisible(boolean visible) {}
          public void setBounds(int x, int y, int w, int h) {}
          public void setContent(final LightweightContentProxy content) {}
          public void emulateActivation(boolean activate) {}
          public MouseEvent createMouseEvent(LightweightFrameWrapper lwFrame, int swingID, long swingWhen, 
                                                                       int swingModifiers, 
                                                                       int relX, int relY, int absX, int absY, 
                                                                       int clickCount, 
                                                                       boolean swingPopupTrigger, int swingButton) {}
          public MouseWheelEvent createMouseWheelEvent(LightweightFrameWrapper lwFrame, int swingModifiers, 
                                                                                            int x, int y, 
                                                                                            int wheelRotation) {}
          public KeyEvent createKeyEvent(LightweightFrameWrapper lwFrame, int swingID, long swingWhen,
                                                               int swingModifiers, 
                                                               int swingKeyCode, char swingChar) {}
          public AWTEvent createUngrabEvent(LightweightFrameWrapper lwFrame) {}
          public Component findComponentAt(LightweightFrameWrapper cont, int x, int y, boolean ignoreEnabled) {}
          public boolean isCompEqual(Component c, LightweightFrameWrapper lwFrame) {}        
      }
      
      /**
        * This class provides a wrapper over inner LightweightContentProxy class
        * which implements jdk internal sun.swing.LightweightContent interface 
        * and provides APIs to be used by FX swing interop to access and use LightweightContent APIs.
        */
      public abstract class LightweightContentWrapper {
          public LightweightContentWrapper() {}
          public abstract void imageBufferReset(int[] data, int x, int y, int width, int height, int linestride);
          public abstract void imageBufferReset(int[] data, int x, int y, int width, int height,
                                       int linestride, double scaleX, double scaleY);
          public abstract JComponent getComponent();
          public abstract void paintLock();
          public abstract void paintUnlock();
          public abstract void imageReshaped(int x, int y, int width, int height);
          public abstract void imageUpdated(int dirtyX, int dirtyY,int dirtyWidth, int dirtyHeight);
          public abstract void focusGrabbed();
          public abstract void focusUngrabbed();
          public abstract void preferredSizeChanged(int width, int height);
          public abstract void maximumSizeChanged(int width, int height);
          public abstract void minimumSizeChanged(int width, int height);
      
          public abstract <T extends DragGestureRecognizer> T createDragGestureRecognizer(
                  Class<T> abstractRecognizerClass,  DragSource ds, Component c, int srcActions,
                  DragGestureListener dgl);
          public abstract DragSourceContextWrapper createDragSourceContext(DragGestureEvent dge)
                                              throws InvalidDnDOperationException;
      
          public abstract void addDropTarget(DropTarget dt);
          public abstract removeDropTarget(DropTarget dt);
      }
      
      /**
        * This class provides static utility methods to be used by FX swing interop 
        * to access and use jdk internal classes like SunToolkit, AppContext, 
        * and UngrabEvent.
        */
      public class SwingInterOpUtils {        
          public static void postEvent(Object target, java.awt.AWTEvent e) {}
          public static void grab(Toolkit toolkit, Window window) {}
          public static void ungrab(Toolkit toolkit, Window window) {}
          public static boolean isUngrabEvent(AWTEvent e) {}    
      }
      
        /**
          * This class provides a wrapper over inner DragSourceContextPeerProxy class
          * which extends jdk internal sun.awt.dnd.SunDragSourceContextPeer class
          * and provides APIs to be used by FX swing interop to access and use 
          * DragSourceContextPeer APIs.
          */
      public abstract class DragSourceContextWrapper {
          public DragSourceContextWrapper(DragGestureEvent e) {}
          public static int convertModifiersToDropAction(int modifiers,int supportedActions) {}
          protected abstract void setNativeCursor(Cursor c, int cType);
          protected abstract void startDrag(Transferable trans, long[] formats,Map<Long, DataFlavor> formatMap);
          public abstract void startSecondaryEventLoop();
          public abstract void quitSecondaryEventLoop();
          public void dragDropFinished(final boolean success,final int operations,final int x, final int y) {}
          public DragSourceContext getDragSourceContext() {}
      }
      
      /**
        * This class provides a wrapper over inner class DropTargetContextPeerProxy
        * which implements jdk internal java.awt.dnd.peer.DropTargetContextPeer interface
        * and provides APIs to be used by FX swing interop to access and use
        * DropTargetContextPeer APIs.
        */
      public abstract class DropTargetContextWrapper {
          public DropTargetContextWrapper() {}
          public void setDropTargetContext(DropTargetContext dtc,
                                                                               DropTargetContextWrapper dtcpw) {}
          public void reset(DropTargetContext dtc) {}
          public abstract void setTargetActions(int actions);
          public abstract int getTargetActions();
          public abstract DropTarget getDropTarget();
          public abstract DataFlavor[] getTransferDataFlavors();
          public abstract Transferable getTransferable() throws InvalidDnDOperationException;
          public abstract boolean isTransferableJVMLocal();
          public abstract void acceptDrag(int dragAction);
          public abstract void rejectDrag();
          public abstract void acceptDrop(int dropAction);
          public abstract void rejectDrop();
          public abstract void dropComplete(boolean success);
      }
      
      /**
        * This class provides a wrapper over inner class DispatcherProxy
        * which implements jdk internal sun.awt.FwDispatcher interface
        * and provides APIs to be used by FX swing interop to access and use
        * FwDispatcher APIs.
        */
      public abstract class DispatcherWrapper {
          public DispatcherWrapper() {}
          public abstract boolean isDispatchThread();
          public abstract void scheduleDispatch(Runnable r);
          public abstract SecondaryLoop createSecondaryLoop();
          public static void setFwDispatcher(EventQueue eventQueue, 
                                                                 DispatcherWrapper dispatcher) {}
      }

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                psadhukhan Prasanta Sadhukhan
                Reporter:
                kcr Kevin Rushforth
                Reviewed By:
                Kevin Rushforth, Philip Race
              • Votes:
                0 Vote for this issue
                Watchers:
                5 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: