Class FlatPopupFactory


  • public class FlatPopupFactory
    extends javax.swing.PopupFactory
    A popup factory that adds drop shadows to popups on Windows. On macOS and Linux, heavy weight popups (without drop shadow) are produced and the operating system automatically adds drop shadows.
    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class Description
      private class  FlatPopupFactory.DropShadowPopup  
      private class  FlatPopupFactory.NonFlashingPopup
      Fixes popup background flashing effect when using dark theme on light platform theme, where the light popup background is shown for a fraction of a second before the dark popup content is shown.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      private static void fixLinuxWaylandJava21focusIssue​(java.awt.Component owner)
      On Linux with Wayland, since Java 21, Swing adds a window focus listener to popup owner/invoker window, which hides the popup as soon as the owner/invoker window looses focus.
      private java.awt.Point fixToolTipLocation​(java.awt.Component owner, java.awt.Component contents, int x, int y)
      Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
      private static int getBorderCornerRadius​(java.awt.Component owner, java.awt.Component contents)  
      private javax.swing.Popup getHeavyWeightPopup​(java.awt.Component owner, java.awt.Component contents, int x, int y)
      There is no API in Java 8 to force creation of heavy weight popups, but it is possible with reflection.
      private static java.lang.Object getOption​(java.awt.Component owner, java.awt.Component contents, java.lang.String clientKey, java.lang.String uiKey)
      Get option from: client property clientKey of owner client property clientKey of contents UI property uiKey
      javax.swing.Popup getPopup​(java.awt.Component owner, java.awt.Component contents, int x, int y)  
      private javax.swing.Popup getPopupForScreenOfOwner​(java.awt.Component owner, java.awt.Component contents, int x, int y, boolean forceHeavyWeight)
      Creates a popup for the screen that the owner component is on.
      private static float getRoundedBorderWidth​(java.awt.Component owner, java.awt.Component contents)  
      private boolean hasTipLocation​(java.awt.Component owner)
      Checks whether the owner component returns a tooltip location in JComponent.getToolTipLocation(MouseEvent).
      private static boolean isOptionEnabled​(java.awt.Component owner, java.awt.Component contents, java.lang.String clientKey, java.lang.String uiKey)  
      private static boolean isWindows11BorderSupported()  
      private static boolean overlapsHeavyWeightComponent​(java.awt.Component owner, java.awt.Component contents, int x, int y)  
      private static boolean overlapsHeavyWeightComponent​(java.awt.Component parent, java.awt.Rectangle r)  
      private static void resetWindows11Border​(java.awt.Window popupWindow)  
      private static FlatPopupFactory.NonFlashingPopup reuseStillShownHeavyWeightPopups​(FlatPopupFactory.NonFlashingPopup reusePopup, java.awt.Component contents, int ownerX, int ownerY)
      Reuse a heavy weight popup window, which is still shown on screen, by updating window location and contents.
      private static void setupRoundedBorder​(java.awt.Window popupWindow, java.awt.Component owner, java.awt.Component contents)  
      private static void showPopupAndFixLocation​(javax.swing.Popup popup, java.awt.Window popupWindow)
      Shows the given popup and, if necessary, fixes the location of a heavy weight popup window.
      private boolean wasInvokedFromToolTipManager()  
      • Methods inherited from class javax.swing.PopupFactory

        getPopup, getSharedInstance, setSharedInstance
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • KEY_POPUP_USES_NATIVE_BORDER

        static final java.lang.String KEY_POPUP_USES_NATIVE_BORDER
        See Also:
        Constant Field Values
      • java8getPopupMethod

        private java.lang.invoke.MethodHandle java8getPopupMethod
      • java9getPopupMethod

        private java.lang.invoke.MethodHandle java9getPopupMethod
    • Constructor Detail

      • FlatPopupFactory

        public FlatPopupFactory()
    • Method Detail

      • getPopup

        public javax.swing.Popup getPopup​(java.awt.Component owner,
                                          java.awt.Component contents,
                                          int x,
                                          int y)
                                   throws java.lang.IllegalArgumentException
        Overrides:
        getPopup in class javax.swing.PopupFactory
        Throws:
        java.lang.IllegalArgumentException
      • getPopupForScreenOfOwner

        private javax.swing.Popup getPopupForScreenOfOwner​(java.awt.Component owner,
                                                           java.awt.Component contents,
                                                           int x,
                                                           int y,
                                                           boolean forceHeavyWeight)
                                                    throws java.lang.IllegalArgumentException
        Creates a popup for the screen that the owner component is on.

        PopupFactory caches heavy weight popup windows and reuses them. On a dual screen setup, if the popup owner has moved from one screen to the other one, then the cached heavy weight popup window may be connected to the wrong screen. If the two screens use different scaling factors, then the popup location and size is scaled when the popup becomes visible, which shows the popup in the wrong location (or on wrong screen). The re-scaling is done in WWindowPeer.setBounds() (Java 9+).

        To fix this, dispose popup windows that are on wrong screen and get new popup.

        This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608

        Throws:
        java.lang.IllegalArgumentException
      • getHeavyWeightPopup

        private javax.swing.Popup getHeavyWeightPopup​(java.awt.Component owner,
                                                      java.awt.Component contents,
                                                      int x,
                                                      int y)
                                               throws java.lang.IllegalArgumentException
        There is no API in Java 8 to force creation of heavy weight popups, but it is possible with reflection. Java 9 provides a new method. When changing FlatLaf system requirements to Java 9+, then this method can be replaced with: return getPopup( owner, contents, x, y, true );
        Throws:
        java.lang.IllegalArgumentException
      • isOptionEnabled

        private static boolean isOptionEnabled​(java.awt.Component owner,
                                               java.awt.Component contents,
                                               java.lang.String clientKey,
                                               java.lang.String uiKey)
      • getOption

        private static java.lang.Object getOption​(java.awt.Component owner,
                                                  java.awt.Component contents,
                                                  java.lang.String clientKey,
                                                  java.lang.String uiKey)
        Get option from:
        1. client property clientKey of owner
        2. client property clientKey of contents
        3. UI property uiKey
      • reuseStillShownHeavyWeightPopups

        private static FlatPopupFactory.NonFlashingPopup reuseStillShownHeavyWeightPopups​(FlatPopupFactory.NonFlashingPopup reusePopup,
                                                                                          java.awt.Component contents,
                                                                                          int ownerX,
                                                                                          int ownerY)
        Reuse a heavy weight popup window, which is still shown on screen, by updating window location and contents. This avoid flicker when popup (e.g. a tooltip) is moving while mouse is moved. E.g. overridden JComponent.getToolTipLocation(MouseEvent). See ToolTipManager.checkForTipChange(MouseEvent).
      • fixToolTipLocation

        private java.awt.Point fixToolTipLocation​(java.awt.Component owner,
                                                  java.awt.Component contents,
                                                  int x,
                                                  int y)
        Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20). In case that the tooltip would be partly outside of the screen, the ToolTipManager changes the location so that the entire tooltip fits on screen. But this can place the tooltip under the mouse location and hide the owner component.

        This method checks whether the current mouse location is within tooltip bounds and corrects the y-location so that the tooltip is placed above the mouse location.

      • wasInvokedFromToolTipManager

        private boolean wasInvokedFromToolTipManager()
      • hasTipLocation

        private boolean hasTipLocation​(java.awt.Component owner)
        Checks whether the owner component returns a tooltip location in JComponent.getToolTipLocation(MouseEvent).
      • isWindows11BorderSupported

        private static boolean isWindows11BorderSupported()
      • setupRoundedBorder

        private static void setupRoundedBorder​(java.awt.Window popupWindow,
                                               java.awt.Component owner,
                                               java.awt.Component contents)
      • resetWindows11Border

        private static void resetWindows11Border​(java.awt.Window popupWindow)
      • getBorderCornerRadius

        private static int getBorderCornerRadius​(java.awt.Component owner,
                                                 java.awt.Component contents)
      • getRoundedBorderWidth

        private static float getRoundedBorderWidth​(java.awt.Component owner,
                                                   java.awt.Component contents)
      • overlapsHeavyWeightComponent

        private static boolean overlapsHeavyWeightComponent​(java.awt.Component owner,
                                                            java.awt.Component contents,
                                                            int x,
                                                            int y)
      • overlapsHeavyWeightComponent

        private static boolean overlapsHeavyWeightComponent​(java.awt.Component parent,
                                                            java.awt.Rectangle r)
      • fixLinuxWaylandJava21focusIssue

        private static void fixLinuxWaylandJava21focusIssue​(java.awt.Component owner)
        On Linux with Wayland, since Java 21, Swing adds a window focus listener to popup owner/invoker window, which hides the popup as soon as the owner/invoker window looses focus. This works fine for light-weight popups. It also works for heavy-weight popups if they do not request focus. Because FlatLaf always uses heavy-weight popups, all popups that request focus are broken since Java 21. This method removes the problematic window focus listener. https://bugs.openjdk.org/browse/JDK-8280993 https://github.com/openjdk/jdk/pull/13830
      • showPopupAndFixLocation

        private static void showPopupAndFixLocation​(javax.swing.Popup popup,
                                                    java.awt.Window popupWindow)
        Shows the given popup and, if necessary, fixes the location of a heavy weight popup window.

        On a dual screen setup, where screens use different scale factors, it may happen that the window location changes when showing a heavy weight popup window. E.g. when opening a dialog on the secondary screen and making combobox popup visible.

        This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608