Index: trunk/CONTRIBUTION
===================================================================
--- trunk/CONTRIBUTION	(revision 14577)
+++ trunk/CONTRIBUTION	(revision 14578)
@@ -80,4 +80,7 @@
 - https://github.com/codebling/WindowsShortcuts
 
+The gui/animation Christmas GPL code is from Jiri Vanek (Red Hat):
+- http://icedtea.classpath.org/hg/icedtea-web/rev/87d3081ab573
+
 ------------------------------- PROJECTION DATA -------------------------------
 
Index: trunk/src/org/openstreetmap/josm/gui/GettingStarted.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/GettingStarted.java	(revision 14577)
+++ trunk/src/org/openstreetmap/josm/gui/GettingStarted.java	(revision 14578)
@@ -6,4 +6,5 @@
 import java.awt.BorderLayout;
 import java.awt.EventQueue;
+import java.awt.Graphics;
 import java.io.IOException;
 import java.net.URL;
@@ -15,4 +16,5 @@
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.Timer;
 import javax.swing.border.EmptyBorder;
 import javax.swing.event.HyperlinkEvent;
@@ -21,4 +23,5 @@
 import org.openstreetmap.josm.actions.DownloadPrimitiveAction;
 import org.openstreetmap.josm.data.Version;
+import org.openstreetmap.josm.gui.animation.AnimationExtensionManager;
 import org.openstreetmap.josm.gui.datatransfer.OpenTransferHandler;
 import org.openstreetmap.josm.gui.dialogs.MenuItemSearchDialog;
@@ -46,4 +49,5 @@
     private String content = "";
     private boolean contentInitialized;
+    private final Timer timer = new Timer(50, e -> repaint());
 
     private static final String STYLE = "<style type=\"text/css\">\n"
@@ -142,4 +146,26 @@
 
         setTransferHandler(new OpenTransferHandler());
+    }
+
+    @Override
+    public void addNotify() {
+        timer.start();
+        super.addNotify();
+    }
+
+    @Override
+    public void removeNotify() {
+        timer.stop();
+        super.removeNotify();
+    }
+
+    @Override
+    public void paint(Graphics g) {
+        super.paint(g);
+        if (isShowing()) {
+            AnimationExtensionManager.getExtension().adjustForSize(getWidth(), getHeight());
+            AnimationExtensionManager.getExtension().animate();
+            AnimationExtensionManager.getExtension().paint(g);
+        }
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/animation/AnimationExtension.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/animation/AnimationExtension.java	(revision 14578)
+++ trunk/src/org/openstreetmap/josm/gui/animation/AnimationExtension.java	(revision 14578)
@@ -0,0 +1,31 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.animation;
+
+import java.awt.Graphics;
+
+/**
+ * Graphical animation extension. Copied from Icedtea-Web.
+ * @author Jiri Vanek (Red Hat)
+ * @see <a href="http://icedtea.classpath.org/hg/icedtea-web/rev/87d3081ab573">Initial commit</a>
+ * @since 14578
+ */
+public interface AnimationExtension {
+
+    /**
+     * Adjusts for size.
+     * @param w width
+     * @param h height
+     */
+    void adjustForSize(int w, int h);
+
+    /**
+     * Paints static contents.
+     * @param g graphics object
+     */
+    void paint(Graphics g);
+
+    /**
+     * Performs the optional animation.
+     */
+    void animate();
+}
Index: trunk/src/org/openstreetmap/josm/gui/animation/AnimationExtensionManager.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/animation/AnimationExtensionManager.java	(revision 14578)
+++ trunk/src/org/openstreetmap/josm/gui/animation/AnimationExtensionManager.java	(revision 14578)
@@ -0,0 +1,38 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.animation;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+/**
+ * Animation extension manager. Copied from Icedtea-Web.
+ * @author Jiri Vanek (Red Hat)
+ * @see <a href="http://icedtea.classpath.org/hg/icedtea-web/rev/87d3081ab573">Initial commit</a>
+ * @since 14578
+ */
+public final class AnimationExtensionManager {
+
+    private static AnimationExtension currentExtension;
+
+    private AnimationExtensionManager() {
+        // Hide default constructor for utility classes
+    }
+
+    /**
+     * Returns the current animation extension.
+     * @return the current animation extension
+     */
+    public static AnimationExtension getExtension() {
+        if (currentExtension == null) {
+            currentExtension = isChristmas() ? new ChristmasExtension() : new NoExtension();
+        }
+        return currentExtension;
+    }
+
+    private static boolean isChristmas() {
+        Calendar c = new GregorianCalendar();
+        c.setTime(new Date());
+        return c.get(Calendar.DAY_OF_YEAR) > 350;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/animation/ChristmasExtension.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/animation/ChristmasExtension.java	(revision 14578)
+++ trunk/src/org/openstreetmap/josm/gui/animation/ChristmasExtension.java	(revision 14578)
@@ -0,0 +1,212 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.animation;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Polygon;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Christmas animation extension. Copied from Icedtea-Web.
+ * @author Jiri Vanek (Red Hat)
+ * @see <a href="http://icedtea.classpath.org/hg/icedtea-web/rev/87d3081ab573">Initial commit</a>
+ * @since 14578
+ */
+public class ChristmasExtension implements AnimationExtension {
+
+    ChristmasExtension() {
+        this(0, 0);
+    }
+
+    private static final Random seed = new Random();
+    private static final int averageStarWidth = 10;    // stars will be 5-15
+    private static final int averageFallSpeed = 4;     // 2-6
+    private static final int averageRotationSpeed = 2; // 1-3
+
+    private static final Color WATER_LIVE_COLOR = new Color(80, 131, 160);
+
+    /**
+     * Interpolation is root ratio is r= (currentSize / origSize)
+     * then value to-from is interpolated from to to from according to ratio
+     *
+     * @param origSize original size
+     * @param currentSize current size
+     * @param from starting value
+     * @param to ending value
+     * @return interpolated value
+     */
+    public static double interpol(double origSize, double currentSize, double from, double to) {
+        return (currentSize / origSize) * (to - from) + from;
+    }
+
+    private class Star {
+
+        private int radiusX;
+        private int radiusY;
+        private int maxRadiusX;
+        private int maxRadiusY;
+        private int centerX;
+        private int centerY;
+        private final int fallSpeed;
+        private final boolean orientation;
+        private final int[] originalColor = new int[3];
+        private final int[] color = new int[originalColor.length];
+        private int direction;
+        private final boolean haveEight;
+
+        Star() {
+            createRadiuses();
+            haveEight = seed.nextBoolean();
+            this.centerX = seed.nextInt(w + 1);
+            this.centerY = seed.nextInt(h + 1);
+            this.fallSpeed = averageFallSpeed / 2 + seed.nextInt(averageFallSpeed / 2);
+            this.orientation = seed.nextBoolean();
+            this.direction = -(averageRotationSpeed / 2 + seed.nextInt(averageRotationSpeed / 2));
+            if (seed.nextInt(4) == 0) {
+                originalColor[0] = Color.yellow.getRed();
+                originalColor[1] = Color.yellow.getGreen();
+                originalColor[2] = Color.yellow.getBlue();
+            } else {
+                originalColor[0] = WATER_LIVE_COLOR.getRed();
+                originalColor[1] = WATER_LIVE_COLOR.getGreen();
+                originalColor[2] = WATER_LIVE_COLOR.getBlue();
+            }
+        }
+
+        public void paint(Graphics g) {
+            Color c = g.getColor();
+            g.setColor(new Color(color[0], color[1], color[2]));
+            Polygon p = createPolygon();
+            if (haveEight) {
+                int min1 = Math.min(radiusX, radiusY);
+                int min2 = min1 / 2;
+                g.fillRect(centerX - min2, centerY - min2, min1, min1);
+            }
+            g.fillPolygon(p);
+            g.setColor(c);
+        }
+
+        private void animate() {
+            centerY += fallSpeed;
+            if (orientation) {
+                radiusX += direction;
+                if (radiusX <= -direction) {
+                    direction = -direction;
+                    radiusX = direction;
+                }
+                if (radiusX >= maxRadiusX) {
+                    direction = -direction;
+                    radiusX = maxRadiusX;
+                }
+                interpolateColors(radiusX, maxRadiusX);
+            } else {
+                radiusY += direction;
+                if (radiusY <= -direction) {
+                    direction = -direction;
+                    radiusY = direction;
+                }
+                if (radiusY >= maxRadiusY) {
+                    direction = -direction;
+                    radiusY = maxRadiusY;
+                }
+                interpolateColors(radiusY, maxRadiusY);
+            }
+            if (centerY > h + radiusX * 2 || centerY > h + radiusY * 2) {
+                createRadiuses();
+                this.centerX = seed.nextInt(w + 1);
+                this.centerY = -radiusY * 2;
+            }
+        }
+
+        private int createRadius() {
+            return averageStarWidth / 2 + seed.nextInt(averageStarWidth);
+        }
+
+        private Polygon createPolygon() {
+            int min = Math.min(radiusX, radiusY) / 3;
+            Polygon p = new Polygon();
+            p.addPoint(centerX - radiusX, centerY);
+            p.addPoint(centerX - min, centerY - min);
+            p.addPoint(centerX, centerY - radiusY);
+            p.addPoint(centerX + min, centerY - min);
+            p.addPoint(centerX + radiusX, centerY);
+            p.addPoint(centerX + min, centerY + min);
+            p.addPoint(centerX, centerY + radiusY);
+            p.addPoint(centerX - min, centerY + min);
+            return p;
+        }
+
+        private void interpolateColors(int is, int max) {
+            for (int i = 0; i < originalColor.length; i++) {
+                int fadeMin;
+                if (centerY < 0) {
+                    fadeMin = 0;
+                } else if (centerY > h) {
+                    fadeMin = 255;
+                } else {
+                    fadeMin = (int) interpol(h, centerY, 255, 0); // from white to black
+                }
+                int fadeMax;
+                if (centerY < 0) {
+                    fadeMax = 0;
+                } else if (centerY > h) {
+                    fadeMax = originalColor[i];
+                } else {
+                    fadeMax = (int) interpol(h, centerY, originalColor[i], 0); // from color to black
+                }
+                color[i] = (int) interpol(max, is, fadeMin, fadeMax);
+            }
+        }
+
+        private void createRadiuses() {
+            this.radiusX = createRadius();
+            this.radiusY = radiusX;
+            switch (seed.nextInt(3)) {
+                case 0:
+                    radiusX = radiusX + (2 * radiusX) / 3;
+                    break;
+                case 1:
+                    radiusY = radiusY + (2 * radiusY) / 3;
+                    break;
+                case 2:
+                    //noop
+                    break;
+            }
+            maxRadiusX = radiusX;
+            maxRadiusY = radiusY;
+        }
+    }
+
+    private int w;
+    private int h;
+    private final List<Star> stars = new ArrayList<>(50);
+
+    ChristmasExtension(int w, int h) {
+        adjustForSize(w, h);
+    }
+
+    @Override
+    public void paint(Graphics g) {
+        stars.forEach(s -> s.paint(g));
+    }
+
+    @Override
+    public void animate() {
+        stars.forEach(Star::animate);
+    }
+
+    @Override
+    public final void adjustForSize(int w, int h) {
+        this.w = w;
+        this.h = h;
+        int count = w / (2 * (averageStarWidth + 1));
+        while (stars.size() > count) {
+            stars.remove(stars.size() - 1);
+        }
+        while (stars.size() < count) {
+            stars.add(new Star());
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/animation/NoExtension.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/animation/NoExtension.java	(revision 14578)
+++ trunk/src/org/openstreetmap/josm/gui/animation/NoExtension.java	(revision 14578)
@@ -0,0 +1,28 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.animation;
+
+import java.awt.Graphics;
+
+/**
+ * Animation no-op extension. Copied from Icedtea-Web.
+ * @author Jiri Vanek (Red Hat)
+ * @see <a href="http://icedtea.classpath.org/hg/icedtea-web/rev/87d3081ab573">Initial commit</a>
+ * @since 14578
+ */
+public class NoExtension implements AnimationExtension {
+
+    NoExtension() {
+    }
+
+    @Override
+    public void adjustForSize(int w, int h) {
+    }
+
+    @Override
+    public void animate() {
+    }
+
+    @Override
+    public void paint(Graphics g) {
+    }
+}
