Class FlatPopupFactory
- java.lang.Object
-
- javax.swing.PopupFactory
-
- com.formdev.flatlaf.ui.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.
-
Field Summary
Fields Modifier and Type Field Description private java.lang.invoke.MethodHandle
java8getPopupMethod
private java.lang.invoke.MethodHandle
java9getPopupMethod
(package private) static java.lang.String
KEY_POPUP_USES_NATIVE_BORDER
private java.util.ArrayList<FlatPopupFactory.NonFlashingPopup>
stillShownHeavyWeightPopups
-
Constructor Summary
Constructors Constructor Description FlatPopupFactory()
-
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 propertyclientKey
ofowner
client propertyclientKey
ofcontents
UI propertyuiKey
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()
-
-
-
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
-
stillShownHeavyWeightPopups
private final java.util.ArrayList<FlatPopupFactory.NonFlashingPopup> stillShownHeavyWeightPopups
-
-
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 classjavax.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:- client property
clientKey
ofowner
- client property
clientKey
ofcontents
- UI property
uiKey
- client property
-
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
-
-