On Mon, 20 Jan 2025 19:56:18 GMT, Alexey Ivanov <aiva...@openjdk.org> wrote:
> What if the window that loses focus is not the parent of the popup hierarchy? > Or is it guaranteed that all the children of the popup window receive the > focus lost event? I can't imagine such a case, but even if it is, it will all be handled correctly once we pass the input back to the XWayland server. At the moment the popup menu is open, we have grabbed the input inside the Xserver, so any click outside the menu should result in ungrabbing and hiding all menus. But XWayland is a special case, where we can't track mouse clicks outside of it in native apps and DE, so we have to implement this workaround by manually ungrabbing the input, so that our code can at least handle the lost window focus as a reason to dismiss the popup menu. There are a few cases where this workaround does not work, e.g. when we click on or non-focusable native windows/panels (Dock, top panel in Gnome, etc.), or show a pop-up menu on our non-focusable window: import java.awt.EventQueue; import java.awt.Frame; import java.awt.MenuItem; import java.awt.PopupMenu; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; public class AwtPopup { public static void main(String[] args) throws Exception{ EventQueue.invokeAndWait(() -> { final Frame f= new Frame("PopupMenu Example"); final PopupMenu popupmenu = new PopupMenu("Menu"); popupmenu.add(new MenuItem("Item")); f.add(popupmenu); f.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { popupmenu.show(f , e.getX(), e.getY()); } }); f.setSize(200,200); f.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { f.dispose(); } }); f.setLocationRelativeTo(null); // Menu is not hidden when we click on the native focusable window // but it is hidden when we click on any X11 application f.setFocusableWindowState(false); f.setVisible(true); }); } } It is not an ideal workaround, but it is good enough to exist. > Shouldn't the line below > > https://github.com/openjdk/jdk/blob/b60a33269247c1039fa0ec6cd99476c9f8976852/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java#L563 > be changed to call dismissPopupOnFocusLostIfNeededCleanUp to remove the > listener from the popup and its children? Not really, because a few lines after we ungrab the input, so all the popup menu will be dismissed, performing cleanups in their `hide()` and `setVisible()` methods. https://github.com/openjdk/jdk/blob/f54e0bf267280c270b0e181289498b28aaf36ee6/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java#L442-L444 https://github.com/openjdk/jdk/blob/f54e0bf267280c270b0e181289498b28aaf36ee6/src/java.desktop/share/classes/javax/swing/JPopupMenu.java#L824-L826 ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/22729#discussion_r1923549477