diff --git a/src/org/openstreetmap/josm/Main.java b/src/org/openstreetmap/josm/Main.java
index 2a14c05..fd0a939 100644
--- a/src/org/openstreetmap/josm/Main.java
+++ b/src/org/openstreetmap/josm/Main.java
@@ -529,10 +529,12 @@ public abstract class Main {
 
     public static interface InitStatusListener {
 
-        void updateStatus(String event);
+        Object updateStatus(String event);
+        void finish(Object status);
     }
 
     public static void setInitStatusListener(InitStatusListener listener) {
+        CheckParameterUtil.ensureParameterNotNull(listener);
         initListener = listener;
     }
 
@@ -543,17 +545,22 @@ public abstract class Main {
         main = this;
         isOpenjdk = System.getProperty("java.vm.name").toUpperCase().indexOf("OPENJDK") != -1;
 
-        if (initListener != null) {
-            initListener.updateStatus(tr("Executing platform startup hook"));
-        }
-        platform.startupHook();
+        new InitializationTask(tr("Executing platform startup hook")) {
+            @Override
+            public void initialize() {
+                platform.startupHook();
+            }
+        }.call();
 
-        if (initListener != null) {
-            initListener.updateStatus(tr("Building main menu"));
-        }
-        contentPanePrivate.add(panel, BorderLayout.CENTER);
-        panel.add(gettingStarted, BorderLayout.CENTER);
-        menu = new MainMenu();
+        new InitializationTask(tr("Building main menu")) {
+
+            @Override
+            public void initialize() {
+                contentPanePrivate.add(panel, BorderLayout.CENTER);
+                panel.add(gettingStarted, BorderLayout.CENTER);
+                menu = new MainMenu();
+            }
+        }.call();
 
         undoRedo.addCommandQueueListener(redoUndoListener);
 
@@ -569,7 +576,7 @@ public abstract class Main {
         tasks.add(new InitializationTask(tr("Initializing OSM API")) {
 
             @Override
-            public void initialize() throws Exception {
+            public void initialize() {
                 // We try to establish an API connection early, so that any API
                 // capabilities are already known to the editor instance. However
                 // if it goes wrong that's not critical at this stage.
@@ -584,7 +591,7 @@ public abstract class Main {
         tasks.add(new InitializationTask(tr("Initializing validator")) {
 
             @Override
-            public void initialize() throws Exception {
+            public void initialize() {
                 validator = new OsmValidator();
                 MapView.addLayerChangeListener(validator);
             }
@@ -593,7 +600,7 @@ public abstract class Main {
         tasks.add(new InitializationTask(tr("Initializing presets")) {
 
             @Override
-            public void initialize() throws Exception {
+            public void initialize() {
                 TaggingPresets.initialize();
             }
         });
@@ -601,7 +608,7 @@ public abstract class Main {
         tasks.add(new InitializationTask(tr("Initializing map styles")) {
 
             @Override
-            public void initialize() throws Exception {
+            public void initialize() {
                 MapPaintPreference.initialize();
             }
         });
@@ -609,7 +616,7 @@ public abstract class Main {
         tasks.add(new InitializationTask(tr("Loading imagery preferences")) {
 
             @Override
-            public void initialize() throws Exception {
+            public void initialize() {
                 ImageryPreference.initialize();
             }
         });
@@ -668,14 +675,15 @@ public abstract class Main {
             }
         });
 
-        if (initListener != null) {
-            initListener.updateStatus(tr("Updating user interface"));
-        }
+        new InitializationTask(tr("Updating user interface")) {
 
-        toolbar.refreshToolbarControl();
-
-        toolbar.control.updateUI();
-        contentPanePrivate.updateUI();
+            @Override
+            public void initialize() {
+                toolbar.refreshToolbarControl();
+                toolbar.control.updateUI();
+                contentPanePrivate.updateUI();
+            }
+        }.call();
     }
 
     private abstract class InitializationTask implements Callable<Void> {
@@ -686,18 +694,17 @@ public abstract class Main {
             this.name = name;
         }
 
-        public abstract void initialize() throws Exception;
+        public abstract void initialize();
 
         @Override
-        public Void call() throws Exception {
+        public Void call() {
+            Object status = null;
             if (initListener != null) {
-                initListener.updateStatus(name);
+                status = initListener.updateStatus(name);
             }
-            final long startTime = System.currentTimeMillis();
             initialize();
-            if (isDebugEnabled()) {
-                final long elapsedTime = System.currentTimeMillis() - startTime;
-                Main.debug(tr("{0} completed in {1}", name, Utils.getDurationString(elapsedTime)));
+            if (initListener != null) {
+                initListener.finish(status);
             }
             return null;
         }
diff --git a/src/org/openstreetmap/josm/gui/MainApplication.java b/src/org/openstreetmap/josm/gui/MainApplication.java
index 8568f7e..bb0518c 100644
--- a/src/org/openstreetmap/josm/gui/MainApplication.java
+++ b/src/org/openstreetmap/josm/gui/MainApplication.java
@@ -50,7 +50,6 @@ import org.openstreetmap.josm.data.Version;
 import org.openstreetmap.josm.gui.download.DownloadDialog;
 import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder;
 import org.openstreetmap.josm.gui.preferences.server.ProxyPreference;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.DefaultProxySelector;
 import org.openstreetmap.josm.io.MessageNotifier;
@@ -411,14 +410,22 @@ public class MainApplication extends Main {
         OAuthAccessTokenHolder.getInstance().init(Main.pref, CredentialsManager.getInstance());
 
         final SplashScreen splash = new SplashScreen();
-        final ProgressMonitor monitor = splash.getProgressMonitor();
+        final SplashScreen.SplashProgressMonitor monitor = splash.getProgressMonitor();
         monitor.beginTask(tr("Initializing"));
         splash.setVisible(Main.pref.getBoolean("draw.splashscreen", true));
         Main.setInitStatusListener(new InitStatusListener() {
 
             @Override
-            public void updateStatus(String event) {
-                monitor.indeterminateSubTask(event);
+            public Object updateStatus(String event) {
+                monitor.beginTask(event);
+                return event;
+            }
+
+            @Override
+            public void finish(Object status) {
+                if (status instanceof String) {
+                    monitor.finishTask((String) status);
+                }
             }
         });
 
diff --git a/src/org/openstreetmap/josm/gui/SplashScreen.java b/src/org/openstreetmap/josm/gui/SplashScreen.java
index 1336867..c786ff2 100644
--- a/src/org/openstreetmap/josm/gui/SplashScreen.java
+++ b/src/org/openstreetmap/josm/gui/SplashScreen.java
@@ -4,15 +4,18 @@ package org.openstreetmap.josm.gui;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.Color;
-import java.awt.Dimension;
+import java.awt.Component;
+import java.awt.Graphics;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.Image;
 import java.awt.Insets;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.util.Arrays;
-import java.util.LinkedList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
 
 import javax.swing.ImageIcon;
 import javax.swing.JFrame;
@@ -24,10 +27,10 @@ import javax.swing.border.Border;
 import javax.swing.border.EmptyBorder;
 import javax.swing.border.EtchedBorder;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Version;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.gui.progress.ProgressRenderer;
-import org.openstreetmap.josm.gui.progress.SwingRenderingProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressTaskId;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Utils;
@@ -39,7 +42,8 @@ import org.openstreetmap.josm.tools.WindowGeometry;
  */
 public class SplashScreen extends JFrame {
 
-    private final SwingRenderingProgressMonitor progressMonitor;
+    private final SplashProgressMonitor progressMonitor;
+    public final SplashScreenProgressRenderer progressRenderer;
 
     /**
      * Constructs a new {@code SplashScreen}.
@@ -89,11 +93,11 @@ public class SplashScreen extends JFrame {
         innerContentPane.add(separator, gbc);
 
         // Add a status message
-        SplashScreenProgressRenderer progressRenderer = new SplashScreenProgressRenderer();
+        progressRenderer = new SplashScreenProgressRenderer();
         gbc.gridy = 3;
         gbc.insets = new Insets(0, 0, 10, 0);
         innerContentPane.add(progressRenderer, gbc);
-        progressMonitor = new SwingRenderingProgressMonitor(progressRenderer);
+        progressMonitor = new SplashProgressMonitor(null);
 
         pack();
 
@@ -108,17 +112,191 @@ public class SplashScreen extends JFrame {
         });
     }
 
+    void updateProgress() {
+        progressRenderer.setTasks("<html><style>ul {margin-top: 0; margin-bottom: 0; padding: 0;} li {margin: 0; padding: 0;}</style>"
+                + progressMonitor.toString());
+    }
+
+    private static class MeasurableTask {
+        private final String name;
+        private final long start;
+        private String duration = "";
+
+        public MeasurableTask(String name) {
+            this.name = name;
+            this.start = System.currentTimeMillis();
+        }
+
+        public void finish() {
+            duration = tr(" ({0})", Utils.getDurationString(System.currentTimeMillis() - start));
+        }
+
+        @Override
+        public String toString() {
+            return name + "<i style='color: #666666;'>" + duration + "</i>";
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            MeasurableTask that = (MeasurableTask) o;
+            return Objects.equals(name, that.name);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(name);
+        }
+    }
+
+    class SplashProgressMonitor implements ProgressMonitor {
+
+        private final String name;
+        private final Map<Object, Object> tasks = Collections.synchronizedMap(new LinkedHashMap<Object, Object>() {
+            @Override
+            public Object put(Object key, Object value) {
+                final Object r = super.put(key, value);
+                updateProgress();
+                return r;
+            }
+        });
+        private SplashProgressMonitor latestSubtask;
+
+        public SplashProgressMonitor(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String toString() {
+            return Utils.firstNonNull(name, "") + (tasks.isEmpty() ? "" : Utils.joinAsHtmlUnorderedList(tasks.values()));
+        }
+
+        @Override
+        public void beginTask(String title) {
+            if (title != null) {
+                final MeasurableTask task = new MeasurableTask(title);
+                tasks.put(task, task);
+            }
+        }
+
+        @Override
+        public void beginTask(String title, int ticks) {
+            this.beginTask(title);
+        }
+
+        @Override
+        public void setCustomText(String text) {
+            this.beginTask(text);
+        }
+
+        @Override
+        public void setExtraText(String text) {
+            this.beginTask(text);
+        }
+
+        @Override
+        public void indeterminateSubTask(String title) {
+            this.subTask(title);
+        }
+
+        @Override
+        public void subTask(String title) {
+            latestSubtask = new SplashProgressMonitor(title);
+            tasks.put(latestSubtask, latestSubtask);
+        }
+
+        @Override
+        public ProgressMonitor createSubTaskMonitor(int ticks, boolean internal) {
+            return latestSubtask;
+        }
+
+        @Override
+        @Deprecated
+        public void finishTask() {
+        }
+
+        public void finishTask(String title) {
+            final Object task = tasks.get(new MeasurableTask(title));
+            if (task instanceof MeasurableTask) {
+                ((MeasurableTask) task).finish();
+                Main.debug(tr("{0} completed in {1}", title, ((MeasurableTask) task).duration));
+                updateProgress();
+            }
+        }
+
+        @Override
+        public void invalidate() {
+        }
+
+        @Override
+        public void setTicksCount(int ticks) {
+        }
+
+        @Override
+        public int getTicksCount() {
+            return 0;
+        }
+
+        @Override
+        public void setTicks(int ticks) {
+        }
+
+        @Override
+        public int getTicks() {
+            return 0;
+        }
+
+        @Override
+        public void worked(int ticks) {
+        }
+
+        @Override
+        public boolean isCanceled() {
+            return false;
+        }
+
+        @Override
+        public void cancel() {
+        }
+
+        @Override
+        public void addCancelListener(CancelListener listener) {
+        }
+
+        @Override
+        public void removeCancelListener(CancelListener listener) {
+        }
+
+        @Override
+        public void appendLogMessage(String message) {
+        }
+
+        @Override
+        public void setProgressTaskId(ProgressTaskId taskId) {
+        }
+
+        @Override
+        public ProgressTaskId getProgressTaskId() {
+            return null;
+        }
+
+        @Override
+        public Component getWindowParent() {
+            return Main.parent;
+        }
+    }
+
     /**
      * Returns the progress monitor.
      * @return The progress monitor
      */
-    public ProgressMonitor getProgressMonitor() {
+    public SplashProgressMonitor getProgressMonitor() {
         return progressMonitor;
     }
 
-    private static class SplashScreenProgressRenderer extends JPanel implements ProgressRenderer {
+    private static class SplashScreenProgressRenderer extends JPanel {
         private JLabel lblTaskTitle;
-        private JLabel lblCustomText;
         private JProgressBar progressBar;
 
         protected void build() {
@@ -132,29 +310,10 @@ public class SplashScreen extends JFrame {
             gc.insets = new Insets(5,0,0,0);
             add(lblTaskTitle = new JLabel(" "), gc);
 
-            gc.gridx = 0;
             gc.gridy = 1;
-            gc.fill = GridBagConstraints.HORIZONTAL;
-            gc.weightx = 1.0;
-            gc.weighty = 0.0;
-            gc.insets = new Insets(5,0,0,0);
-            add(lblCustomText = new JLabel(" ") {
-                @Override
-                public Dimension getPreferredSize() {
-                    Dimension d = super.getPreferredSize();
-                    if(d.width < 600) d.width = 600;
-                    d.height *= MAX_NUMBER_OF_MESSAGES;
-                    return d;
-                }
-            }, gc);
-
-            gc.gridx = 0;
-            gc.gridy = 2;
-            gc.fill = GridBagConstraints.HORIZONTAL;
-            gc.weightx = 1.0;
-            gc.weighty = 0.0;
-            gc.insets = new Insets(5,0,0,0);
+            gc.insets = new Insets(15,0,0,0);
             add(progressBar = new JProgressBar(JProgressBar.HORIZONTAL), gc);
+            progressBar.setIndeterminate(true);
         }
 
         public SplashScreenProgressRenderer() {
@@ -162,66 +321,16 @@ public class SplashScreen extends JFrame {
         }
 
         @Override
-        public void setCustomText(String message) {
-            if(message.isEmpty())
-                message = " "; // prevent killing of additional line
-            lblCustomText.setText(message);
-            repaint();
-        }
-
-        @Override
-        public void setIndeterminate(boolean indeterminate) {
-            progressBar.setIndeterminate(indeterminate);
-            repaint();
-        }
-
-        @Override
-        public void setMaximum(int maximum) {
-            progressBar.setMaximum(maximum);
-            repaint();
-        }
-
-        private static final int MAX_NUMBER_OF_MESSAGES = 3;
-        private LinkedList<String> messages = new LinkedList<>(Arrays.asList("", "", "")); //update when changing MAX_NUMBER_OF_MESSAGES
-        private long time = System.currentTimeMillis();
-
-        /**
-         * Stores and displays the {@code MAX_NUMBER_OF_MESSAGES} most recent
-         * task titles together with their execution time.
-         */
-        @Override
-        public void setTaskTitle(String taskTitle) {
-
-            while (messages.size() >= MAX_NUMBER_OF_MESSAGES) {
-                messages.removeFirst();
-            }
-            long now = System.currentTimeMillis();
-            String prevMessageTitle = messages.getLast();
-            // now should always be >= time but if can be inferior sometimes, see #10287
-            if (!prevMessageTitle.isEmpty() && now >= time) {
-                messages.removeLast();
-                messages.add(tr("{0} ({1})", prevMessageTitle, Utils.getDurationString(now - time)));
+        public void paint(Graphics g) {
+            try {
+                super.paint(g);
+            } catch (NullPointerException ignore) {
+                // NullPointerException at javax.swing.text.html.StyleSheet$ListPainter.paint
             }
-            time = now;
-            if (!taskTitle.isEmpty()) {
-                messages.add(taskTitle);
-            }
-            StringBuilder html = new StringBuilder();
-            int i = 0;
-            for (String m : messages) {
-                html.append("<p class=\"entry").append(++i).append("\">").append(m).append("</p>");
-            }
-
-            lblTaskTitle.setText("<html><style>"
-                    + ".entry1{color:#CCCCCC;}"
-                    + ".entry2{color:#999999;}"
-                    + ".entry3{color:#000000;}</style>" + html + "</html>");  //update when changing MAX_NUMBER_OF_MESSAGES
-            repaint();
         }
 
-        @Override
-        public void setValue(int value) {
-            progressBar.setValue(value);
+        public void setTasks(String tasks) {
+            lblTaskTitle.setText(tasks);
             repaint();
         }
     }
