Class FlatPopupFactory

java.lang.Object
javax.swing.PopupFactory
com.formdev.flatlaf.ui.FlatPopupFactory

public class FlatPopupFactory extends 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.
  • Field Details

  • Constructor Details

    • FlatPopupFactory

      public FlatPopupFactory()
  • Method Details

    • getPopup

      public Popup getPopup(Component owner, Component contents, int x, int y) throws IllegalArgumentException
      Overrides:
      getPopup in class PopupFactory
      Throws:
      IllegalArgumentException
    • getPopupForScreenOfOwner

      private Popup getPopupForScreenOfOwner(Component owner, Component contents, int x, int y, boolean forceHeavyWeight) throws 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:
      IllegalArgumentException
    • getHeavyWeightPopup

      private Popup getHeavyWeightPopup(Component owner, Component contents, int x, int y) throws 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:
      IllegalArgumentException
    • isOptionEnabled

      private static boolean isOptionEnabled(Component owner, Component contents, String clientKey, String uiKey)
    • getOption

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

      private Point fixToolTipLocation(Component owner, 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(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(Window popupWindow, Component owner, Component contents)
    • resetWindows11Border

      private static void resetWindows11Border(Window popupWindow)
    • getBorderCornerRadius

      private static int getBorderCornerRadius(Component owner, Component contents)
    • getRoundedBorderWidth

      private static float getRoundedBorderWidth(Component owner, Component contents)
    • overlapsHeavyWeightComponent

      private static boolean overlapsHeavyWeightComponent(Component owner, Component contents, int x, int y)
    • overlapsHeavyWeightComponent

      private static boolean overlapsHeavyWeightComponent(Component parent, Rectangle r)
    • fixLinuxWaylandJava21focusIssue

      private static void fixLinuxWaylandJava21focusIssue(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(Popup popup, 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