diff --git a/src/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyAction.java b/src/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyAction.java
index 87599f2..e5ca19e 100644
--- a/src/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyAction.java
+++ b/src/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyAction.java
@@ -38,8 +38,8 @@ import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.layer.AbstractMapViewPaintable;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.MapViewPaintable;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.gui.util.ModifierListener;
@@ -50,7 +50,7 @@ import org.openstreetmap.josm.tools.Shortcut;
 /**
  * @author Alexander Kachkaev &lt;alexander@kachkaev.ru&gt;, 2011
  */
-public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintable,
+public class ImproveWayAccuracyAction extends MapMode implements
         SelectionChangedListener, ModifierListener {
 
     enum State {
@@ -90,6 +90,13 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
 
     protected String oldModeHelpText;
 
+    private final AbstractMapViewPaintable temporaryLayer = new AbstractMapViewPaintable() {
+        @Override
+        public void paint(Graphics2D g, MapView mv, Bounds bbox) {
+            ImproveWayAccuracyAction.this.paint(g, mv, bbox);;
+        }
+    };
+
     /**
      * Constructs a new {@code ImproveWayAccuracyAction}.
      * @param mapFrame Map frame
@@ -135,7 +142,7 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
 
         Main.map.mapView.addMouseListener(this);
         Main.map.mapView.addMouseMotionListener(this);
-        Main.map.mapView.addTemporaryLayer(this);
+        Main.map.mapView.addTemporaryLayer(temporaryLayer);
         DataSet.addSelectionListener(this);
 
         Main.map.keyDetector.addModifierListener(this);
@@ -160,11 +167,11 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
 
         Main.map.mapView.removeMouseListener(this);
         Main.map.mapView.removeMouseMotionListener(this);
-        Main.map.mapView.removeTemporaryLayer(this);
+        Main.map.mapView.removeTemporaryLayer(temporaryLayer);
         DataSet.removeSelectionListener(this);
 
         Main.map.keyDetector.removeModifierListener(this);
-        Main.map.mapView.repaint();
+        temporaryLayer.invalidate();
     }
 
     @Override
@@ -212,8 +219,10 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
     /**
      * Redraws temporary layer. Highlights targetWay in select mode. Draws
      * preview lines in improve mode and highlights the candidateNode
+     * @param g The graphics
+     * @param mv The map view
+     * @param bbox The bounding box
      */
-    @Override
     public void paint(Graphics2D g, MapView mv, Bounds bbox) {
         if (mousePos == null) {
             return;
@@ -356,7 +365,7 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
         updateCursorDependentObjectsIfNeeded();
         updateCursor();
         updateStatusLine();
-        Main.map.mapView.repaint();
+        temporaryLayer.invalidate();
     }
 
     @Override
@@ -385,7 +394,7 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
         updateCursorDependentObjectsIfNeeded();
         updateCursor();
         updateStatusLine();
-        Main.map.mapView.repaint();
+        temporaryLayer.invalidate();
     }
 
     @Override
@@ -511,7 +520,7 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
         mousePos = null;
         updateCursor();
         updateStatusLine();
-        Main.map.mapView.repaint();
+        temporaryLayer.invalidate();
     }
 
     @Override
@@ -523,7 +532,7 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
         if (!dragging) {
             mousePos = null;
         }
-        Main.map.mapView.repaint();
+        temporaryLayer.invalidate();
     }
 
     // -------------------------------------------------------------------------
@@ -597,7 +606,7 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
 
         targetWay = null;
 
-        mv.repaint();
+        temporaryLayer.invalidate();
         updateStatusLine();
     }
 
@@ -622,7 +631,7 @@ public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintabl
         this.candidateNode = null;
         this.candidateSegment = null;
 
-        mv.repaint();
+        temporaryLayer.invalidate();
         updateStatusLine();
     }
 
diff --git a/src/org/openstreetmap/josm/gui/MapView.java b/src/org/openstreetmap/josm/gui/MapView.java
index f509eac..002941a 100644
--- a/src/org/openstreetmap/josm/gui/MapView.java
+++ b/src/org/openstreetmap/josm/gui/MapView.java
@@ -54,11 +54,14 @@ import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
 import org.openstreetmap.josm.data.osm.visitor.paint.Rendering;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
+import org.openstreetmap.josm.gui.layer.AbstractMapViewPaintable;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.ImageryLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.LayerPositionStrategy;
 import org.openstreetmap.josm.gui.layer.MapViewPaintable;
+import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationEvent;
+import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationListener;
 import org.openstreetmap.josm.gui.layer.NativeScaleLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
@@ -124,6 +127,49 @@ implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
         void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer);
     }
 
+    /**
+     * An invalidation listener that simply calls repaint() for now.
+     * @author Michael Zangl
+     */
+    private class LayerInvalidatedListener implements PaintableInvalidationListener {
+        private boolean ignoreRepaint;
+        @Override
+        public void paintablInvalidated(PaintableInvalidationEvent event) {
+            ignoreRepaint = true;
+            repaint();
+        }
+
+        /**
+         * Temporary until all {@link MapViewPaintable}s support this.
+         * @param p The paintable.
+         */
+        public void addTo(MapViewPaintable p) {
+            if (p instanceof AbstractMapViewPaintable) {
+                ((AbstractMapViewPaintable) p).addInvalidationListener(this);
+            }
+        }
+        /**
+         * Temporary until all {@link MapViewPaintable}s support this.
+         * @param p The paintable.
+         */
+        public void removeFrom(MapViewPaintable p) {
+            if (p instanceof AbstractMapViewPaintable) {
+                ((AbstractMapViewPaintable) p).removeInvalidationListener(this);
+            }
+        }
+
+        /**
+         * Attempts to trace repaints that did not originate from this listener. Good to find missed {@link MapView#repaint()}s in code.
+         */
+        protected synchronized void traceRandomRepaint() {
+            if (!ignoreRepaint) {
+                System.err.println("Repaint:");
+                Thread.dumpStack();
+            }
+            ignoreRepaint = false;
+        }
+    }
+
     public boolean viewportFollowing;
 
     /**
@@ -268,6 +314,11 @@ implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
     private transient MapMover mapMover;
 
     /**
+     * The listener that listens to invalidations of all layers.
+     */
+    private final LayerInvalidatedListener invalidatedListener = new LayerInvalidatedListener();
+
+    /**
      * Constructs a new {@code MapView}.
      * @param contentPane The content pane used to register shortcuts in its
      * {@link InputMap} and {@link ActionMap}
@@ -381,6 +432,7 @@ implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
             }
 
             layer.addPropertyChangeListener(this);
+            invalidatedListener.addTo(layer);
             Main.addProjectionChangeListener(layer);
             AudioPlayer.reset();
         }
@@ -505,6 +557,7 @@ implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
             layers.remove(layer);
             Main.removeProjectionChangeListener(layer);
             layer.removePropertyChangeListener(this);
+            invalidatedListener.removeFrom(layer);
             layer.destroy();
             AudioPlayer.reset();
         }
@@ -1034,7 +1087,11 @@ implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
      */
     public boolean addTemporaryLayer(MapViewPaintable mvp) {
         synchronized (temporaryLayers) {
-            return temporaryLayers.add(mvp);
+            boolean added = temporaryLayers.add(mvp);
+            if (added) {
+                invalidatedListener.addTo(mvp);
+            }
+            return added;
         }
     }
 
@@ -1045,7 +1102,11 @@ implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
      */
     public boolean removeTemporaryLayer(MapViewPaintable mvp) {
         synchronized (temporaryLayers) {
-            return temporaryLayers.remove(mvp);
+            boolean removed = temporaryLayers.remove(mvp);
+            if (removed) {
+                invalidatedListener.removeFrom(mvp);
+            }
+            return removed;
         }
     }
 
@@ -1205,4 +1266,12 @@ implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
         }
         super.repaint(tm, x, y, width, height);
     }
+
+    @Override
+    public void repaint() {
+        if (Main.isTraceEnabled()) {
+            invalidatedListener.traceRandomRepaint();
+        }
+        super.repaint();
+    }
 }
diff --git a/src/org/openstreetmap/josm/gui/SelectionManager.java b/src/org/openstreetmap/josm/gui/SelectionManager.java
index c0d87e4..eacb9ba 100644
--- a/src/org/openstreetmap/josm/gui/SelectionManager.java
+++ b/src/org/openstreetmap/josm/gui/SelectionManager.java
@@ -22,7 +22,7 @@ import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
-import org.openstreetmap.josm.gui.layer.MapViewPaintable;
+import org.openstreetmap.josm.gui.layer.AbstractMapViewPaintable;
 import org.openstreetmap.josm.tools.Utils;
 
 /**
@@ -88,7 +88,7 @@ public class SelectionManager implements MouseListener, MouseMotionListener, Pro
      *
      * @author Michael Zangl
      */
-    private class SelectionHintLayer implements MapViewPaintable {
+    private class SelectionHintLayer extends AbstractMapViewPaintable {
         @Override
         public void paint(Graphics2D g, MapView mv, Bounds bbox) {
             if (mousePos == null || mousePosStart == null || mousePos == mousePosStart)
@@ -367,10 +367,8 @@ public class SelectionManager implements MouseListener, MouseMotionListener, Pro
         }
     }
 
-    private static void selectionAreaChanged() {
-        // Trigger a redraw of the map view.
-        // A nicer way would be to provide change events for the temporary layer.
-        Main.map.mapView.repaint();
+    private void selectionAreaChanged() {
+        selectionHintLayer.invalidate();
     }
 
     /**
@@ -382,7 +380,6 @@ public class SelectionManager implements MouseListener, MouseMotionListener, Pro
      * @return The collection of selected objects.
      */
     public Collection<OsmPrimitive> getSelectedObjects(boolean alt) {
-
         Collection<OsmPrimitive> selection = new LinkedList<>();
 
         // whether user only clicked, not dragged.
diff --git a/src/org/openstreetmap/josm/gui/layer/AbstractMapViewPaintable.java b/src/org/openstreetmap/josm/gui/layer/AbstractMapViewPaintable.java
new file mode 100644
index 0000000..761a7df
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/layer/AbstractMapViewPaintable.java
@@ -0,0 +1,42 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * This class implements the invalidation listener mechanism suggested by {@link MapViewPaintable}.
+ *
+ * @author Michael Zangl
+ */
+public abstract class AbstractMapViewPaintable implements MapViewPaintable {
+
+    /**
+     * A list of invalidation listeners to call when this layer is invalidated.
+     */
+    private final CopyOnWriteArrayList<PaintableInvalidationListener> invalidationListeners = new CopyOnWriteArrayList<>();
+
+    /**
+     * Adds a new paintable invalidation listener.
+     * @param l The listener to add.
+     */
+    public void addInvalidationListener(PaintableInvalidationListener l) {
+        invalidationListeners.add(l);
+    }
+
+    /**
+     * Removes an added paintable invalidation listener.
+     * @param l The listener to remove.
+     */
+    public void removeInvalidationListener(PaintableInvalidationListener l) {
+        invalidationListeners.remove(l);
+    }
+
+    /**
+     * This needs to be called whenever the content of this view was invalidated.
+     */
+    public void invalidate() {
+        for (PaintableInvalidationListener l : invalidationListeners) {
+            l.paintablInvalidated(new PaintableInvalidationEvent(this));
+        }
+    }
+}
diff --git a/src/org/openstreetmap/josm/gui/layer/Layer.java b/src/org/openstreetmap/josm/gui/layer/Layer.java
index 8a4acfa..88cddc5 100644
--- a/src/org/openstreetmap/josm/gui/layer/Layer.java
+++ b/src/org/openstreetmap/josm/gui/layer/Layer.java
@@ -47,7 +47,7 @@ import org.openstreetmap.josm.tools.Utils;
  *
  * @author imi
  */
-public abstract class Layer implements Destroyable, MapViewPaintable, ProjectionChangeListener {
+public abstract class Layer extends AbstractMapViewPaintable implements Destroyable, ProjectionChangeListener {
 
     /**
      * Action related to a single layer.
diff --git a/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java b/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java
index fa0fc7b..9eab095 100644
--- a/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java
+++ b/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java
@@ -6,9 +6,61 @@ import java.awt.Graphics2D;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.gui.MapView;
 
+/**
+ * This is a component that can be painted on the map view.
+ * <p>
+ * You might want to extend {@link AbstractMapViewPaintable} to ease implementation of this.
+ * <p>
+ * That class allows you to listen to paintable change events. Those methods may be moved here some time in the future.
+ */
 public interface MapViewPaintable {
 
     /**
+     * This event is fired whenever the paintable got invalidated and needs repainting some time in the future.
+     * <p>
+     * Note: We might add an area in the future.
+     *
+     * @author Michael Zangl
+     */
+    class PaintableInvalidationEvent {
+        private final MapViewPaintable paintable;
+
+        /**
+         * Creates a new {@link PaintableInvalidationEvent}
+         * @param paintable The paintable that is invalidated.
+         */
+        public PaintableInvalidationEvent(MapViewPaintable paintable) {
+            super();
+            this.paintable = paintable;
+        }
+
+        /**
+         * Gets the layer that was invalidated.
+         * @return The layer.
+         */
+        public MapViewPaintable getLayer() {
+            return paintable;
+        }
+
+        @Override
+        public String toString() {
+            return "LayerInvalidationEvent [layer=" + paintable + "]";
+        }
+    }
+
+    /**
+     * This is a listener that listens to {@link PaintableInvalidationEvent}s
+     * @author Michael Zangl
+     */
+    interface PaintableInvalidationListener {
+        /**
+         * Called whenever a {@link PaintableInvalidationEvent} is fired. This might be called from any thread.
+         * @param event The event
+         */
+        void paintablInvalidated(PaintableInvalidationEvent event);
+    }
+
+    /**
      * Paint the dataset using the engine set.
      * @param g Graphics
      * @param mv The object that can translate GeoPoints to screen coordinates.
diff --git a/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java b/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
index 55d352b..f33cfd7 100644
--- a/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
+++ b/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
@@ -916,14 +916,20 @@ public class OsmDataLayer extends AbstractModifiableLayer implements Listener, S
 
     @Override
     public void processDatasetEvent(AbstractDatasetChangedEvent event) {
-        isChanged = true;
+        invalidate();
         setRequiresSaveToFile(true);
         setRequiresUploadToServer(true);
     }
 
     @Override
     public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        invalidate();
+    }
+
+    @Override
+    public void invalidate() {
         isChanged = true;
+        super.invalidate();
     }
 
     @Override
diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java b/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
index 39dfe55..4286aab 100644
--- a/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
+++ b/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
@@ -969,7 +969,7 @@ public class GeoImageLayer extends AbstractModifiableLayer implements PropertyCh
 
     public void updateBufferAndRepaint() {
         updateOffscreenBuffer = true;
-        Main.map.mapView.repaint();
+        invalidate();
     }
 
     /**
diff --git a/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java b/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
index 543835d..f687a40 100644
--- a/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
+++ b/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
@@ -157,7 +157,7 @@ public class MarkerLayer extends Layer implements JumpToMarkerLayer {
                     return;
                 mousePressed  = true;
                 if (isVisible()) {
-                    Main.map.mapView.repaint();
+                    invalidate();
                 }
             }
 
@@ -175,7 +175,7 @@ public class MarkerLayer extends Layer implements JumpToMarkerLayer {
                         }
                     }
                 }
-                Main.map.mapView.repaint();
+                invalidate();
             }
         });
     }
