Index: /trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 3116)
@@ -172,5 +172,5 @@
             oldHighlights.add(mouseOnExistingNode);
             if(drawTargetHighlight) {
-                mouseOnExistingNode.highlighted = true;
+                mouseOnExistingNode.setHighlighted(true);
             }
             return;
@@ -189,5 +189,5 @@
         if (!drawTargetHighlight) return;
         for (Way w : mouseOnExistingWays) {
-            w.highlighted = true;
+            w.setHighlighted(true);
         }
     }
@@ -198,5 +198,5 @@
     private void removeHighlighting() {
         for(OsmPrimitive prim : oldHighlights) {
-            prim.highlighted = false;
+            prim.setHighlighted(false);
         }
         oldHighlights = new HashSet<OsmPrimitive>();
Index: /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3116)
@@ -58,4 +58,15 @@
     // Number of open calls to beginUpdate
     private int updateCount;
+
+    private int highlightUpdateCount;
+
+    /**
+     * This method can be used to detect changes in highlight state of primitives. If highlighting was changed
+     * then the method will return different number.
+     * @return
+     */
+    public int getHighlightUpdateCount() {
+        return highlightUpdateCount;
+    }
 
     /**
@@ -314,5 +325,5 @@
      * Replies an unmodifiable collection of primitives currently selected
      * in this dataset
-     * 
+     *
      * @return unmodifiable collection of primitives
      */
@@ -897,4 +908,8 @@
     }
 
+    void fireHighlightingChanged(OsmPrimitive primitive) {
+        highlightUpdateCount++;
+    }
+
     public void clenupDeletedPrimitives() {
         if (cleanupDeleted(nodes.iterator())
Index: /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 3116)
@@ -229,5 +229,5 @@
      * If allowNegativeId is not set, then id will have to be 0 (in that case new unique id will be generated) or
      * positive number.
-     * 
+     *
      * If id is not > 0 version is ignored and set to 0.
      *
@@ -475,5 +475,5 @@
      * show which ways/nodes will connect
      */
-    public volatile boolean highlighted = false;
+    private volatile boolean highlighted = false;
 
     private int timestamp;
@@ -1288,3 +1288,16 @@
         return dataSet != null && dataSet.isSelected(this);
     }
+
+    public void setHighlighted(boolean highlighted) {
+        if (this.highlighted != highlighted) {
+            this.highlighted = highlighted;
+            if (dataSet != null) {
+                dataSet.fireHighlightingChanged(this);
+            }
+        }
+    }
+
+    public boolean isHighlighted() {
+        return highlighted;
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/SimplePaintVisitor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/SimplePaintVisitor.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/SimplePaintVisitor.java	(revision 3116)
@@ -227,5 +227,5 @@
         if (inactive || n.isDisabled()) {
             drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
-        } else if (n.highlighted) {
+        } else if (n.isHighlighted()) {
             drawNode(n, highlightColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
         } else if (ds.isSelected(n)) {
@@ -304,5 +304,5 @@
         if (inactive || w.isDisabled()) {
             wayColor = inactiveColor;
-        } else if(w.highlighted) {
+        } else if(w.isHighlighted()) {
             wayColor = highlightColor;
         } else if(ds.isSelected(w)) {
Index: /trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 3116)
@@ -159,5 +159,5 @@
      * A list of all layers currently loaded.
      */
-    private ArrayList<Layer> layers = new ArrayList<Layer>();
+    private final List<Layer> layers = new ArrayList<Layer>();
     /**
      * The play head marker: there is only one of these so it isn't in any specific layer
@@ -180,4 +180,6 @@
 
     private BufferedImage offscreenBuffer;
+    // Layers that wasn't changed since last paint
+    private final List<Layer> nonChangedLayers = new ArrayList<Layer>();
 
     public MapView() {
@@ -458,21 +460,60 @@
             return; // no data loaded yet.
 
-        // re-create offscreen-buffer if we've been resized, otherwise
-        // just re-use it.
-        if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth()
-                || offscreenBuffer.getHeight() != getHeight()) {
-            offscreenBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
-        }
-
-        Graphics2D tempG = offscreenBuffer.createGraphics();
-        tempG.setClip(g.getClip());
-        tempG.setColor(PaintColors.BACKGROUND.get());
-        tempG.fillRect(0, 0, getWidth(), getHeight());
-
+        List<Layer> visibleLayers = getVisibleLayersInZOrder();
+
+        int nonChangedLayersCount = 0;
+        for (Layer l: visibleLayers) {
+            if (l.isChanged()) {
+                break;
+            } else {
+                nonChangedLayersCount++;
+            }
+        }
+
+        boolean canUseBuffer = nonChangedLayers.size() <= nonChangedLayersCount;
+        if (canUseBuffer) {
+            for (int i=0; i<nonChangedLayers.size(); i++) {
+                if (visibleLayers.get(i) != nonChangedLayers.get(i)) {
+                    canUseBuffer = false;
+                    break;
+                }
+            }
+        }
+
+        Graphics2D tempG = (Graphics2D) g;
         Bounds box = getLatLonBounds(g.getClipBounds());
 
-        for (Layer l: getVisibleLayersInZOrder()) {
-            l.paint(tempG, this, box);
-        }
+        if (!canUseBuffer || offscreenBuffer == null) {
+            if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth() || offscreenBuffer.getHeight() != getHeight()) {
+                offscreenBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
+            }
+            Graphics2D g2 = offscreenBuffer.createGraphics();
+            g2.setColor(PaintColors.BACKGROUND.get());
+            g2.fillRect(0, 0, getWidth(), getHeight());
+
+            for (int i=0; i<nonChangedLayersCount; i++) {
+                visibleLayers.get(i).paint(g2, this, box);
+            }
+        } else {
+            // Maybe there were more unchanged layers then last time - draw them to buffer
+            if (nonChangedLayers.size() != nonChangedLayersCount) {
+                Graphics2D g2 = offscreenBuffer.createGraphics();
+                for (int i=nonChangedLayers.size(); i<nonChangedLayersCount; i++) {
+                    visibleLayers.get(i).paint(g2, this, box);
+                }
+            }
+        }
+
+        nonChangedLayers.clear();
+        for (int i=0; i<nonChangedLayersCount; i++) {
+            nonChangedLayers.add(visibleLayers.get(i));
+        }
+
+        tempG.drawImage(offscreenBuffer, 0, 0, null);
+
+        for (int i=nonChangedLayersCount; i<visibleLayers.size(); i++) {
+            visibleLayers.get(i).paint(tempG, this, box);
+        }
+
         for (MapViewPaintable mvp : temporaryLayers) {
             mvp.paint(tempG, this, box);
@@ -515,6 +556,6 @@
         }
 
-        int w = offscreenBuffer.getWidth();
-        int h = offscreenBuffer.getHeight();
+        int w = getWidth();
+        int h = getHeight();
 
         // Work around OpenJDK having problems when drawing out of bounds
@@ -530,5 +571,4 @@
         }
 
-        g.drawImage(offscreenBuffer, 0, 0, null);
         super.paint(g);
     }
Index: /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 3116)
@@ -679,3 +679,14 @@
         return n.substring(n.lastIndexOf('.')+1);
     }
+
+    /**
+     * Return a ID which is unique as long as viewport dimensions are the same
+     */
+    public int getViewID() {
+        String x = center.east() + "_" + center.north() + "_" + scale + "_" +
+        getWidth() + "_" + getHeight() + "_" + getProjection().toString();
+        java.util.zip.CRC32 id = new java.util.zip.CRC32();
+        id.update(x.getBytes());
+        return (int)id.getValue();
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 3116)
@@ -229,4 +229,13 @@
 
     /**
+     *
+     *
+     * @return True if layer was changed since last paint
+     */
+    public boolean isChanged() {
+        return true;
+    }
+
+    /**
      * The action to save a layer
      *
Index: /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 3116)
@@ -44,4 +44,5 @@
 import org.openstreetmap.josm.command.PurgePrimitivesCommand;
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.conflict.Conflict;
 import org.openstreetmap.josm.data.conflict.ConflictCollection;
@@ -59,4 +60,7 @@
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
+import org.openstreetmap.josm.data.osm.event.DataSetListenerAdapter;
+import org.openstreetmap.josm.data.osm.event.DataSetListenerAdapter.Listener;
 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
@@ -79,5 +83,5 @@
  * @author imi
  */
-public class OsmDataLayer extends Layer {
+public class OsmDataLayer extends Layer implements Listener, SelectionChangedListener {
     static public final String REQUIRES_SAVE_TO_DISK_PROP = OsmDataLayer.class.getName() + ".requiresSaveToDisk";
     static public final String REQUIRES_UPLOAD_TO_SERVER_PROP = OsmDataLayer.class.getName() + ".requiresUploadToServer";
@@ -85,4 +89,7 @@
     private boolean requiresSaveToFile = false;
     private boolean requiresUploadToServer = false;
+    private boolean isChanged = true;
+    private int highlightUpdateCount;
+    private int viewId;
 
     protected void setRequiresSaveToFile(boolean newValue) {
@@ -199,4 +206,6 @@
         this.setAssociatedFile(associatedFile);
         conflicts = new ConflictCollection();
+        data.addDataSetListener(new DataSetListenerAdapter(this));
+        DataSet.selListeners.add(this);
     }
 
@@ -215,4 +224,8 @@
      */
     @Override public void paint(final Graphics2D g, final MapView mv, Bounds box) {
+        isChanged = false;
+        highlightUpdateCount = data.getHighlightUpdateCount();
+        viewId = Main.map.mapView.getViewID();
+
         boolean active = mv.getActiveLayer() == this;
         boolean inactive = !active && Main.pref.getBoolean("draw.data.inactive_color", true);
@@ -711,4 +724,9 @@
     }
 
+    @Override
+    public boolean isChanged() {
+        return isChanged || highlightUpdateCount != data.getHighlightUpdateCount() || viewId != Main.map.mapView.getViewID();
+    }
+
     /**
      * Initializes the layer after a successful save of OSM data to a file
@@ -752,3 +770,11 @@
 
     }
+
+    public void processDatasetEvent(AbstractDatasetChangedEvent event) {
+        isChanged = true;
+    }
+
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        isChanged = true;
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 3116)
@@ -177,5 +177,5 @@
         }
 
-        if(w.highlighted) {
+        if(w.isHighlighted()) {
             myColor = paintSettings.getHighlightColor();
         } else if (selected) {
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/SimpleNodeElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/SimpleNodeElemStyle.java	(revision 3115)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/SimpleNodeElemStyle.java	(revision 3116)
@@ -21,5 +21,5 @@
         Node n = (Node)primitive;
         String name = painter.isShowNames()?painter.getNodeName(n):null;
-        if (n.highlighted) {
+        if (n.isHighlighted()) {
             painter.drawNode(n, settings.getHighlightColor(), settings.getSelectedNodeSize(), settings.isFillSelectedNode(), name);
         } else if (selected) {
