Index: /trunk/src/org/openstreetmap/josm/gui/MainApplication.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 12694)
+++ /trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 12695)
@@ -38,4 +38,5 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.logging.Level;
@@ -60,4 +61,5 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.OpenFileAction;
+import org.openstreetmap.josm.actions.OpenFileAction.OpenFileTask;
 import org.openstreetmap.josm.actions.PreferencesAction;
 import org.openstreetmap.josm.actions.RestartAction;
@@ -103,4 +105,5 @@
 import org.openstreetmap.josm.io.OsmApiInitializationException;
 import org.openstreetmap.josm.io.OsmTransferCanceledException;
+import org.openstreetmap.josm.io.OsmTransferException;
 import org.openstreetmap.josm.io.auth.CredentialsManager;
 import org.openstreetmap.josm.io.auth.DefaultAuthenticator;
@@ -117,4 +120,5 @@
 import org.openstreetmap.josm.tools.OsmUrlToBounds;
 import org.openstreetmap.josm.tools.OverpassTurboQueryWizard;
+import org.openstreetmap.josm.tools.PlatformHook.NativeOsCallback;
 import org.openstreetmap.josm.tools.PlatformHookWindows;
 import org.openstreetmap.josm.tools.RightAndLefthandTraffic;
@@ -124,4 +128,5 @@
 import org.openstreetmap.josm.tools.bugreport.BugReport;
 import org.openstreetmap.josm.tools.bugreport.BugReportExceptionHandler;
+import org.xml.sax.SAXException;
 
 /**
@@ -725,4 +730,5 @@
         // initialize the platform hook, and
         Main.determinePlatformHook();
+        Main.platform.setNativeOsCallback(new DefaultNativeOsCallback());
         // call the really early hook before we do anything else
         Main.platform.preStartupHook();
@@ -1188,3 +1194,40 @@
         }
     }
+
+    private static class DefaultNativeOsCallback implements NativeOsCallback {
+        @Override
+        public void openFiles(List<File> files) {
+            Executors.newSingleThreadExecutor(Utils.newThreadFactory("openFiles-%d", Thread.NORM_PRIORITY)).submit(
+                    new OpenFileTask(files, null) {
+                @Override
+                protected void realRun() throws SAXException, IOException, OsmTransferException {
+                    // Wait for JOSM startup is advanced enough to load a file
+                    while (Main.parent == null || !Main.parent.isVisible()) {
+                        try {
+                            Thread.sleep(25);
+                        } catch (InterruptedException e) {
+                            Logging.warn(e);
+                            Thread.currentThread().interrupt();
+                        }
+                    }
+                    super.realRun();
+                }
+            });
+        }
+
+        @Override
+        public boolean handleQuitRequest() {
+            return MainApplication.exitJosm(false, 0, null);
+        }
+
+        @Override
+        public void handleAbout() {
+            MainApplication.getMenu().about.actionPerformed(null);
+        }
+
+        @Override
+        public void handlePreferences() {
+            MainApplication.getMenu().preferences.actionPerformed(null);
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/tools/PlatformHook.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 12694)
+++ /trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 12695)
@@ -272,3 +272,42 @@
         }
     }
+
+    /**
+     * Called when interfacing with native OS functions. Currently only used with macOS.
+     * The callback must perform all GUI-related tasks associated to an OS request.
+     * The non-GUI, platform-specific tasks, are usually performed by the {@code PlatformHook}.
+     * @since 12695
+     */
+    interface NativeOsCallback {
+        /**
+         * macOS: Called when JOSM is asked to open a list of files.
+         * @param files list of files to open
+         */
+        void openFiles(List<File> files);
+
+        /**
+         * macOS: Invoked when JOSM is asked to quit.
+         * @return {@code true} if JOSM has been closed, {@code false} if the user has cancelled the operation.
+         */
+        boolean handleQuitRequest();
+
+        /**
+         * macOS: Called when JOSM is asked to show it's about dialog.
+         */
+        void handleAbout();
+
+        /**
+         * macOS: Called when JOSM is asked to show it's preferences UI.
+         */
+        void handlePreferences();
+    }
+
+    /**
+     * Registers the native OS callback. Currently only needed for macOS.
+     * @param callback the native OS callback
+     * @since 12695
+     */
+    default void setNativeOsCallback(NativeOsCallback callback) {
+        // To be implemented if needed
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java	(revision 12694)
+++ /trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java	(revision 12695)
@@ -17,13 +17,9 @@
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.Executors;
+import java.util.Objects;
 
 import javax.swing.UIManager;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.OpenFileAction.OpenFileTask;
-import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.io.OsmTransferException;
-import org.xml.sax.SAXException;
 
 /**
@@ -36,4 +32,6 @@
 
     private String oSBuildNumber;
+
+    private NativeOsCallback osCallback;
 
     @Override
@@ -138,4 +136,9 @@
     }
 
+    @Override
+    public void setNativeOsCallback(NativeOsCallback callback) {
+        osCallback = Objects.requireNonNull(callback);
+    }
+
     @SuppressWarnings("unchecked")
     @Override
@@ -150,20 +153,5 @@
                     Object oFiles = args[0].getClass().getMethod("getFiles").invoke(args[0]);
                     if (oFiles instanceof List) {
-                        Executors.newSingleThreadExecutor(Utils.newThreadFactory("openFiles-%d", Thread.NORM_PRIORITY)).submit(
-                                new OpenFileTask((List<File>) oFiles, null) {
-                            @Override
-                            protected void realRun() throws SAXException, IOException, OsmTransferException {
-                                // Wait for JOSM startup is advanced enough to load a file
-                                while (Main.parent == null || !Main.parent.isVisible()) {
-                                    try {
-                                        Thread.sleep(25);
-                                    } catch (InterruptedException e) {
-                                        Logging.warn(e);
-                                        Thread.currentThread().interrupt();
-                                    }
-                                }
-                                super.realRun();
-                            }
-                        });
+                        osCallback.openFiles((List<File>) oFiles);
                     }
                 } catch (ReflectiveOperationException | SecurityException | IllegalArgumentException ex) {
@@ -173,5 +161,5 @@
             break;
         case "handleQuitRequestWith":
-            boolean closed = MainApplication.exitJosm(false, 0, null);
+            boolean closed = osCallback.handleQuitRequest();
             if (args[1] != null) {
                 try {
@@ -185,8 +173,8 @@
             break;
         case "handleAbout":
-            MainApplication.getMenu().about.actionPerformed(null);
+            osCallback.handleAbout();
             break;
         case "handlePreferences":
-            MainApplication.getMenu().preferences.actionPerformed(null);
+            osCallback.handlePreferences();
             break;
         default:
