Subject: [PATCH] Fix #16485: Ensure windows lose always-on-top status when JOSM loses focus
---
Index: core/src/org/openstreetmap/josm/gui/util/WindowOnTopListener.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/org/openstreetmap/josm/gui/util/WindowOnTopListener.java b/core/src/org/openstreetmap/josm/gui/util/WindowOnTopListener.java
new file mode 100644
--- /dev/null	(date 1703083978225)
+++ b/core/src/org/openstreetmap/josm/gui/util/WindowOnTopListener.java	(date 1703083978225)
@@ -0,0 +1,71 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.util;
+
+import java.awt.Dialog;
+import java.awt.Window;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowFocusListener;
+
+import javax.swing.event.AncestorEvent;
+import javax.swing.event.AncestorListener;
+
+/**
+ * A listener for windows that block other inputs, to ensure they are always on top
+ * @since xxx
+ */
+public class WindowOnTopListener implements AncestorListener, WindowFocusListener {
+
+    /**
+     * {@code true} indicates that the window was always on top prior to the change
+     */
+    private boolean wasAlwaysOnTop;
+    @Override
+    public void windowGainedFocus(WindowEvent e) {
+        final Window window = e.getWindow();
+        if (window != null && window.isAlwaysOnTop() != wasAlwaysOnTop) {
+            window.setAlwaysOnTop(wasAlwaysOnTop);
+        }
+    }
+
+    @Override
+    public void windowLostFocus(WindowEvent e) {
+        final Window window = e.getWindow();
+        if (window != null) {
+            wasAlwaysOnTop = window.isAlwaysOnTop();
+        }
+    }
+
+    @Override
+    public void ancestorAdded(AncestorEvent event) {
+        if (event.getAncestor() instanceof Dialog) {
+            Dialog dialog = (Dialog) event.getAncestor();
+            wasAlwaysOnTop = dialog.isAlwaysOnTop();
+            if (dialog.isVisible() && dialog.isModal()) {
+                dialog.setAlwaysOnTop(true);
+            }
+        }
+        if (event.getAncestor() instanceof Window) {
+            Window window = (Window) event.getAncestor();
+            window.addWindowFocusListener(this);
+        }
+    }
+
+    @Override
+    public void ancestorRemoved(AncestorEvent event) {
+        if (event.getAncestor() instanceof Dialog) {
+            Dialog dialog = (Dialog) event.getAncestor();
+            if (dialog.isVisible() && dialog.isModal()) {
+                dialog.setAlwaysOnTop(wasAlwaysOnTop);
+            }
+        }
+        if (event.getAncestor() instanceof Window) {
+            Window window = (Window) event.getAncestor();
+            window.removeWindowFocusListener(this);
+        }
+    }
+
+    @Override
+    public void ancestorMoved(AncestorEvent event) {
+        // Do nothing
+    }
+}
Index: core/src/org/openstreetmap/josm/gui/ConditionalOptionPaneUtil.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/org/openstreetmap/josm/gui/ConditionalOptionPaneUtil.java b/core/src/org/openstreetmap/josm/gui/ConditionalOptionPaneUtil.java
--- a/core/src/org/openstreetmap/josm/gui/ConditionalOptionPaneUtil.java	(revision 18917)
+++ b/core/src/org/openstreetmap/josm/gui/ConditionalOptionPaneUtil.java	(date 1703081634671)
@@ -4,7 +4,6 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.Component;
-import java.awt.Dialog;
 import java.awt.GridBagLayout;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -15,9 +14,8 @@
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JRadioButton;
-import javax.swing.event.AncestorEvent;
-import javax.swing.event.AncestorListener;
 
+import org.openstreetmap.josm.gui.util.WindowOnTopListener;
 import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.tools.GBC;
@@ -287,34 +285,7 @@
             }
             add(cbStandard, GBC.eol());
 
-            this.addAncestorListener(new AncestorListener() {
-                boolean wasAlwaysOnTop;
-                @Override
-                public void ancestorAdded(AncestorEvent event) {
-                    if (event.getAncestor() instanceof Dialog) {
-                        Dialog dialog = (Dialog) event.getAncestor();
-                        wasAlwaysOnTop = dialog.isAlwaysOnTop();
-                        if (dialog.isVisible() && dialog.isModal()) {
-                            dialog.setAlwaysOnTop(true);
-                        }
-                    }
-                }
-
-                @Override
-                public void ancestorRemoved(AncestorEvent event) {
-                    if (event.getAncestor() instanceof Dialog) {
-                        Dialog dialog = (Dialog) event.getAncestor();
-                        if (dialog.isVisible() && dialog.isModal()) {
-                            dialog.setAlwaysOnTop(wasAlwaysOnTop);
-                        }
-                    }
-                }
-
-                @Override
-                public void ancestorMoved(AncestorEvent event) {
-                    // Do nothing
-                }
-            });
+            this.addAncestorListener(new WindowOnTopListener());
         }
 
         NotShowAgain getNotShowAgain() {
Index: core/src/org/openstreetmap/josm/gui/ExtendedDialog.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/org/openstreetmap/josm/gui/ExtendedDialog.java b/core/src/org/openstreetmap/josm/gui/ExtendedDialog.java
--- a/core/src/org/openstreetmap/josm/gui/ExtendedDialog.java	(revision 18917)
+++ b/core/src/org/openstreetmap/josm/gui/ExtendedDialog.java	(date 1703081630594)
@@ -35,6 +35,7 @@
 import org.openstreetmap.josm.gui.help.HelpUtil;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.gui.util.WindowGeometry;
+import org.openstreetmap.josm.gui.util.WindowOnTopListener;
 import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
 import org.openstreetmap.josm.io.NetworkManager;
 import org.openstreetmap.josm.io.OnlineResource;
@@ -461,6 +462,7 @@
         }
         if (visible && isModal()) {
             this.setAlwaysOnTop(true);
+            this.addWindowFocusListener(new WindowOnTopListener());
         }
         super.setVisible(visible);
 
Index: core/src/org/openstreetmap/josm/gui/HelpAwareOptionPane.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/org/openstreetmap/josm/gui/HelpAwareOptionPane.java b/core/src/org/openstreetmap/josm/gui/HelpAwareOptionPane.java
--- a/core/src/org/openstreetmap/josm/gui/HelpAwareOptionPane.java	(revision 18917)
+++ b/core/src/org/openstreetmap/josm/gui/HelpAwareOptionPane.java	(date 1703081631037)
@@ -27,6 +27,7 @@
 import org.openstreetmap.josm.gui.help.HelpUtil;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.gui.util.WindowGeometry;
+import org.openstreetmap.josm.gui.util.WindowOnTopListener;
 import org.openstreetmap.josm.gui.widgets.HtmlPanel;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
@@ -352,6 +353,7 @@
         }
         if (dialog.isModal()) {
             dialog.setAlwaysOnTop(true);
+            dialog.addWindowFocusListener(new WindowOnTopListener());
         }
         dialog.setVisible(true);
     }
Index: core/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTestIT.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTestIT.java b/core/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTestIT.java
--- a/core/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTestIT.java	(revision 18917)
+++ b/core/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTestIT.java	(date 1703079616394)
@@ -29,6 +29,7 @@
 import org.openstreetmap.josm.gui.tagging.presets.items.Link;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.annotations.HTTPS;
+import org.openstreetmap.josm.testutils.annotations.Territories;
 import org.openstreetmap.josm.tools.HttpClient;
 import org.openstreetmap.josm.tools.HttpClient.Response;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -39,6 +40,7 @@
  * Integration tests of {@link TaggingPresetPreference} class.
  */
 @HTTPS
+@Territories
 @Timeout(value = 20, unit = TimeUnit.MINUTES)
 class TaggingPresetPreferenceTestIT extends AbstractExtendedSourceEntryTestCase {
     /**
