Index: trunk/src/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyAction.java	(revision 10024)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyAction.java	(revision 10031)
@@ -39,6 +39,6 @@
 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;
@@ -51,5 +51,5 @@
  * @author Alexander Kachkaev &lt;alexander@kachkaev.ru&gt;, 2011
  */
-public class ImproveWayAccuracyAction extends MapMode implements MapViewPaintable,
+public class ImproveWayAccuracyAction extends MapMode implements
         SelectionChangedListener, ModifierListener {
 
@@ -90,4 +90,11 @@
 
     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);;
+        }
+    };
 
     /**
@@ -136,5 +143,5 @@
         Main.map.mapView.addMouseListener(this);
         Main.map.mapView.addMouseMotionListener(this);
-        Main.map.mapView.addTemporaryLayer(this);
+        Main.map.mapView.addTemporaryLayer(temporaryLayer);
         DataSet.addSelectionListener(this);
 
@@ -161,9 +168,9 @@
         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();
     }
 
@@ -213,6 +220,8 @@
      * 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) {
@@ -357,5 +366,5 @@
         updateCursor();
         updateStatusLine();
-        Main.map.mapView.repaint();
+        temporaryLayer.invalidate();
     }
 
@@ -386,5 +395,5 @@
         updateCursor();
         updateStatusLine();
-        Main.map.mapView.repaint();
+        temporaryLayer.invalidate();
     }
 
@@ -512,5 +521,5 @@
         updateCursor();
         updateStatusLine();
-        Main.map.mapView.repaint();
+        temporaryLayer.invalidate();
     }
 
@@ -524,5 +533,5 @@
             mousePos = null;
         }
-        Main.map.mapView.repaint();
+        temporaryLayer.invalidate();
     }
 
@@ -598,5 +607,5 @@
         targetWay = null;
 
-        mv.repaint();
+        temporaryLayer.invalidate();
         updateStatusLine();
     }
@@ -623,5 +632,5 @@
         this.candidateSegment = null;
 
-        mv.repaint();
+        temporaryLayer.invalidate();
         updateStatusLine();
     }
Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 10024)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 10031)
@@ -55,4 +55,5 @@
 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;
@@ -60,4 +61,6 @@
 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;
@@ -125,4 +128,47 @@
     }
 
+    /**
+     * 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;
 
@@ -269,4 +315,9 @@
 
     /**
+     * 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
@@ -382,4 +433,5 @@
 
             layer.addPropertyChangeListener(this);
+            invalidatedListener.addTo(layer);
             Main.addProjectionChangeListener(layer);
             AudioPlayer.reset();
@@ -506,4 +558,5 @@
             Main.removeProjectionChangeListener(layer);
             layer.removePropertyChangeListener(this);
+            invalidatedListener.removeFrom(layer);
             layer.destroy();
             AudioPlayer.reset();
@@ -1035,5 +1088,9 @@
     public boolean addTemporaryLayer(MapViewPaintable mvp) {
         synchronized (temporaryLayers) {
-            return temporaryLayers.add(mvp);
+            boolean added = temporaryLayers.add(mvp);
+            if (added) {
+                invalidatedListener.addTo(mvp);
+            }
+            return added;
         }
     }
@@ -1046,5 +1103,9 @@
     public boolean removeTemporaryLayer(MapViewPaintable mvp) {
         synchronized (temporaryLayers) {
-            return temporaryLayers.remove(mvp);
+            boolean removed = temporaryLayers.remove(mvp);
+            if (removed) {
+                invalidatedListener.removeFrom(mvp);
+            }
+            return removed;
         }
     }
@@ -1206,3 +1267,11 @@
         super.repaint(tm, x, y, width, height);
     }
+
+    @Override
+    public void repaint() {
+        if (Main.isTraceEnabled()) {
+            invalidatedListener.traceRandomRepaint();
+        }
+        super.repaint();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/SelectionManager.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 10024)
+++ trunk/src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 10031)
@@ -23,5 +23,5 @@
 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;
 
@@ -89,5 +89,5 @@
      * @author Michael Zangl
      */
-    private class SelectionHintLayer implements MapViewPaintable {
+    private class SelectionHintLayer extends AbstractMapViewPaintable {
         @Override
         public void paint(Graphics2D g, MapView mv, Bounds bbox) {
@@ -368,8 +368,6 @@
     }
 
-    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();
     }
 
@@ -383,5 +381,4 @@
      */
     public Collection<OsmPrimitive> getSelectedObjects(boolean alt) {
-
         Collection<OsmPrimitive> selection = new LinkedList<>();
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/AbstractMapViewPaintable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/AbstractMapViewPaintable.java	(revision 10031)
+++ trunk/src/org/openstreetmap/josm/gui/layer/AbstractMapViewPaintable.java	(revision 10031)
@@ -0,0 +1,43 @@
+// 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
+ * @since 10031
+ */
+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));
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 10024)
+++ trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 10031)
@@ -48,5 +48,5 @@
  * @author imi
  */
-public abstract class Layer implements Destroyable, MapViewPaintable, ProjectionChangeListener {
+public abstract class Layer extends AbstractMapViewPaintable implements Destroyable, ProjectionChangeListener {
 
     /**
Index: trunk/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java	(revision 10024)
+++ trunk/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java	(revision 10031)
@@ -7,5 +7,57 @@
 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);
+    }
 
     /**
Index: trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 10024)
+++ trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 10031)
@@ -917,5 +917,5 @@
     @Override
     public void processDatasetEvent(AbstractDatasetChangedEvent event) {
-        isChanged = true;
+        invalidate();
         setRequiresSaveToFile(true);
         setRequiresUploadToServer(true);
@@ -924,5 +924,11 @@
     @Override
     public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        invalidate();
+    }
+
+    @Override
+    public void invalidate() {
         isChanged = true;
+        super.invalidate();
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 10024)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 10031)
@@ -970,5 +970,5 @@
     public void updateBufferAndRepaint() {
         updateOffscreenBuffer = true;
-        Main.map.mapView.repaint();
+        invalidate();
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 10024)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 10031)
@@ -158,5 +158,5 @@
                 mousePressed  = true;
                 if (isVisible()) {
-                    Main.map.mapView.repaint();
+                    invalidate();
                 }
             }
@@ -176,5 +176,5 @@
                     }
                 }
-                Main.map.mapView.repaint();
+                invalidate();
             }
         });
