Index: trunk/src/org/openstreetmap/josm/data/SelectionChangedListener.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/SelectionChangedListener.java	(revision 12097)
+++ trunk/src/org/openstreetmap/josm/data/SelectionChangedListener.java	(revision 12098)
@@ -4,5 +4,7 @@
 import java.util.Collection;
 
+import org.openstreetmap.josm.data.osm.DataSelectionListener;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
 
 /**
@@ -14,4 +16,7 @@
  * Swing event queue and packed together. So only one selection changed event
  * is issued within a one message dispatch routine.
+ *
+ * @see DataSelectionListener For a more advanced listener class.
+ * @see SelectionEventManager For managing your selection events.
  *
  * @author imi
Index: trunk/src/org/openstreetmap/josm/data/osm/event/SelectionEventManager.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/event/SelectionEventManager.java	(revision 12097)
+++ trunk/src/org/openstreetmap/josm/data/osm/event/SelectionEventManager.java	(revision 12098)
@@ -2,10 +2,8 @@
 package org.openstreetmap.josm.data.osm.event;
 
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
-import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.stream.Stream;
@@ -17,5 +15,4 @@
 import org.openstreetmap.josm.data.osm.DataSelectionListener;
 import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
 import org.openstreetmap.josm.gui.layer.MainLayerManager;
@@ -45,9 +42,18 @@
     }
 
-    private static class ListenerInfo {
+    private abstract static class AbstractListenerInfo {
+        abstract void fire(SelectionChangeEvent event);
+    }
+
+    private static class ListenerInfo extends AbstractListenerInfo {
         private final SelectionChangedListener listener;
 
         ListenerInfo(SelectionChangedListener listener) {
             this.listener = listener;
+        }
+
+        @Override
+        void fire(SelectionChangeEvent event) {
+            listener.selectionChanged(event.getSelection());
         }
 
@@ -66,7 +72,32 @@
     }
 
-    private Collection<? extends OsmPrimitive> selection;
-    private final CopyOnWriteArrayList<ListenerInfo> inEDTListeners = new CopyOnWriteArrayList<>();
-    private final CopyOnWriteArrayList<ListenerInfo> normalListeners = new CopyOnWriteArrayList<>();
+    private static class DataListenerInfo extends AbstractListenerInfo {
+        private final DataSelectionListener listener;
+
+        DataListenerInfo(DataSelectionListener listener) {
+            this.listener = listener;
+        }
+
+        @Override
+        void fire(SelectionChangeEvent event) {
+            listener.selectionChanged(event);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(listener);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            DataListenerInfo that = (DataListenerInfo) o;
+            return Objects.equals(listener, that.listener);
+        }
+    }
+
+    private final CopyOnWriteArrayList<AbstractListenerInfo> inEDTListeners = new CopyOnWriteArrayList<>();
+    private final CopyOnWriteArrayList<AbstractListenerInfo> immedatelyListeners = new CopyOnWriteArrayList<>();
 
     /**
@@ -82,4 +113,6 @@
     /**
      * Registers a new {@code SelectionChangedListener}.
+     *
+     * It is preferred to add a DataSelectionListener - that listener will receive more information about the event.
      * @param listener listener to add
      * @param fireMode Set this to IN_EDT_CONSOLIDATED if you want the event to be fired in the EDT thread.
@@ -92,6 +125,25 @@
             inEDTListeners.addIfAbsent(new ListenerInfo(listener));
         } else {
-            normalListeners.addIfAbsent(new ListenerInfo(listener));
-        }
+            immedatelyListeners.addIfAbsent(new ListenerInfo(listener));
+        }
+    }
+
+    /**
+     * Adds a selection listener that gets notified for selections immediately.
+     * @param listener The listener to add.
+     * @since 12098
+     */
+    public void addSelectionListener(DataSelectionListener listener) {
+        immedatelyListeners.addIfAbsent(new DataListenerInfo(listener));
+    }
+
+    /**
+     * Adds a selection listener that gets notified for selections later in the EDT thread.
+     * Events are sent in the right order but may be delayed.
+     * @param listener The listener to add.
+     * @since 12098
+     */
+    public void addSelectionListenerForEdt(DataSelectionListener listener) {
+        inEDTListeners.addIfAbsent(new DataListenerInfo(listener));
     }
 
@@ -101,7 +153,19 @@
      */
     public void removeSelectionListener(SelectionChangedListener listener) {
-        ListenerInfo searchListener = new ListenerInfo(listener);
+        remove(new ListenerInfo(listener));
+    }
+
+    /**
+     * Unregisters a {@code DataSelectionListener}.
+     * @param listener listener to remove
+     * @since 12098
+     */
+    public void removeSelectionListener(DataSelectionListener listener) {
+        remove(new DataListenerInfo(listener));
+    }
+
+    private void remove(AbstractListenerInfo searchListener) {
         inEDTListeners.remove(searchListener);
-        normalListeners.remove(searchListener);
+        immedatelyListeners.remove(searchListener);
     }
 
@@ -130,22 +194,14 @@
 
     @Override
-    public void selectionChanged(SelectionChangeEvent e) {
-        Set<OsmPrimitive> newSelection = e.getSelection();
-        fireEvents(normalListeners, newSelection);
-        selection = newSelection;
-        SwingUtilities.invokeLater(edtRunnable);
-    }
-
-    private static void fireEvents(List<ListenerInfo> listeners, Collection<? extends OsmPrimitive> newSelection) {
-        for (ListenerInfo listener: listeners) {
-            listener.listener.selectionChanged(newSelection);
-        }
-    }
-
-    private final Runnable edtRunnable = () -> {
-        if (selection != null) {
-            fireEvents(inEDTListeners, selection);
-        }
-    };
+    public void selectionChanged(SelectionChangeEvent event) {
+        fireEvent(immedatelyListeners, event);
+        SwingUtilities.invokeLater(() -> fireEvent(inEDTListeners, event));
+    }
+
+    private static void fireEvent(List<AbstractListenerInfo> listeners, SelectionChangeEvent event) {
+        for (AbstractListenerInfo listener: listeners) {
+            listener.fire(event);
+        }
+    }
 
     /**
@@ -155,5 +211,5 @@
     public void resetState() {
         inEDTListeners.clear();
-        normalListeners.clear();
+        immedatelyListeners.clear();
         Main.getLayerManager().addAndFireActiveLayerChangeListener(this);
     }
