@@ -516,7 +516,7 @@ public void widgetDisposed(DisposeEvent e)
516516 log .info ("Main Window created" );
517517
518518 // Start background class warm-up for all platforms
519- startBackgroundClassWarmup ();
519+ startBackgroundClassWarmup (shell );
520520
521521 return shell ;
522522 }
@@ -1075,8 +1075,8 @@ private void setupMacOSMenuHandlers(final Shell shell)
10751075 // Hook up the "About HDFView" menu item
10761076 item .addListener (SWT .Selection , event -> {
10771077 log .debug ("macOS About menu triggered" );
1078- // Use timerExec to allow the OS menu to close before opening the dialog
1079- display .timerExec (10 , () -> {
1078+ // Use timerExec with 100ms delay to allow macOS menu animation to complete
1079+ display .timerExec (100 , () -> {
10801080 if (!shell .isDisposed ()) {
10811081 new AboutDialog (shell ).open ();
10821082 }
@@ -1087,8 +1087,8 @@ else if (id == SWT.ID_PREFERENCES) {
10871087 // Hook up the "Preferences..." menu item
10881088 item .addListener (SWT .Selection , event -> {
10891089 log .debug ("macOS Preferences menu triggered" );
1090- // Use timerExec to allow the OS menu to close before opening the dialog
1091- display .timerExec (10 , () -> {
1090+ // Use timerExec with 100ms delay to allow macOS menu animation to complete
1091+ display .timerExec (100 , () -> {
10921092 if (!shell .isDisposed ()) {
10931093 openUserOptionsDialog (shell );
10941094 }
@@ -1105,33 +1105,53 @@ else if (id == SWT.ID_PREFERENCES) {
11051105 }
11061106
11071107 /**
1108- * Starts a background thread to pre-load User Options dialog classes.
1109- * This prevents UI freezes when the user first opens the preferences dialog.
1110- * The warm-up runs at low priority to avoid impacting application startup.
1108+ * Schedules background pre-creation of the User Options dialog on the UI thread.
1109+ * This eliminates the 2-3 second freeze when the user first clicks Preferences.
1110+ * The dialog is created in the background after startup, then cached for instant reuse.
1111+ *
1112+ * @param shell the main shell (used to access the Display and as parent for dialog)
11111113 */
1112- private void startBackgroundClassWarmup ()
1114+ private void startBackgroundClassWarmup (final Shell shell )
11131115 {
1114- Thread warmUpThread = new Thread (() -> {
1116+ final Display display = shell .getDisplay ();
1117+
1118+ // Schedule dialog creation on the UI thread after a 2-second delay
1119+ // This delay ensures the UI is fully initialized and startup is complete
1120+ display .timerExec (2000 , () -> {
1121+ if (shell .isDisposed ()) {
1122+ return ; // Don't run if the shell was closed during the delay
1123+ }
1124+
11151125 try {
1116- // Force JVM to load and verify these classes now, instead of waiting for the user to
1117- // click.
1118- Class .forName ("org.eclipse.jface.preference.PreferenceManager" );
1119- Class .forName ("org.eclipse.jface.preference.PreferenceDialog" );
1120- Class .forName ("hdf.view.UserOptionsDialog" );
1121- Class .forName ("hdf.view.UserOptionsNode" );
1122- Class .forName ("hdf.view.UserOptionsGeneralPage" );
1123- Class .forName ("hdf.view.UserOptionsHDFPage" );
1124- Class .forName ("hdf.view.UserOptionsViewModulesPage" );
1126+ log .debug ("Pre-creating User Options dialog in background..." );
1127+
1128+ // Pre-create the entire dialog structure (this is what takes 2-3 seconds)
1129+ // The dialog will be cached and reused when the user clicks Preferences
1130+ PreferenceManager mgr = new PreferenceManager ();
1131+
1132+ UserOptionsNode generalNode = new UserOptionsNode ("general" , new UserOptionsGeneralPage ());
1133+ UserOptionsNode hdfNode = new UserOptionsNode ("hdf" , new UserOptionsHDFPage ());
1134+ UserOptionsNode modulesNode = new UserOptionsNode ("modules" , new UserOptionsViewModulesPage ());
1135+
1136+ mgr .addToRoot (generalNode );
1137+ mgr .addToRoot (hdfNode );
1138+ mgr .addToRoot (modulesNode );
1139+
1140+ userOptionDialog = new UserOptionsDialog (shell , mgr , rootDir );
1141+ userOptionDialog .setPreferenceStore (props );
1142+ userOptionDialog .create (); // This creates all the SWT widgets (expensive!)
1143+
1144+ log .info ("User Options dialog pre-created successfully - first open will be instant" );
11251145 }
11261146 catch (Throwable t ) {
1127- // Ignore errors during warm-up; they will be handled normally if they persist
1147+ // If pre-creation fails, the dialog will be created on-demand when user clicks
1148+ log .warn ("Failed to pre-create User Options dialog (will create on-demand): {}" ,
1149+ t .getMessage ());
1150+ userOptionDialog = null ; // Ensure we don't keep a broken reference
11281151 }
11291152 });
1130- warmUpThread .setDaemon (true ); // Ensure this thread doesn't prevent app exit
1131- warmUpThread .setPriority (Thread .MIN_PRIORITY );
1132- warmUpThread .start ();
11331153
1134- log .debug ("Background class warm-up thread started " );
1154+ log .debug ("Background dialog pre-creation scheduled " );
11351155 }
11361156
11371157 /**
@@ -1142,27 +1162,39 @@ private void startBackgroundClassWarmup()
11421162 */
11431163 private void openUserOptionsDialog (Shell parentShell )
11441164 {
1145- // Create the preference manager
1146- PreferenceManager mgr = new PreferenceManager ();
1165+ // Check if we have a pre-created dialog that's still valid
1166+ boolean needsCreation = (userOptionDialog == null ) ||
1167+ (userOptionDialog .getShell () != null &&
1168+ userOptionDialog .getShell ().isDisposed ());
1169+
1170+ if (needsCreation ) {
1171+ log .debug ("Creating User Options dialog (first open or after disposal)..." );
1172+
1173+ // Create the preference manager
1174+ PreferenceManager mgr = new PreferenceManager ();
11471175
1148- // Create the preference nodes with semantic names
1149- UserOptionsNode generalNode = new UserOptionsNode ("general" , new UserOptionsGeneralPage ());
1150- UserOptionsNode hdfNode = new UserOptionsNode ("hdf" , new UserOptionsHDFPage ());
1151- UserOptionsNode modulesNode = new UserOptionsNode ("modules" , new UserOptionsViewModulesPage ());
1176+ // Create the preference nodes with semantic names
1177+ UserOptionsNode generalNode = new UserOptionsNode ("general" , new UserOptionsGeneralPage ());
1178+ UserOptionsNode hdfNode = new UserOptionsNode ("hdf" , new UserOptionsHDFPage ());
1179+ UserOptionsNode modulesNode = new UserOptionsNode ("modules" , new UserOptionsViewModulesPage ());
11521180
1153- // Add the nodes
1154- mgr .addToRoot (generalNode );
1155- mgr .addToRoot (hdfNode );
1156- mgr .addToRoot (modulesNode );
1181+ // Add the nodes
1182+ mgr .addToRoot (generalNode );
1183+ mgr .addToRoot (hdfNode );
1184+ mgr .addToRoot (modulesNode );
11571185
1158- // Create the preferences dialog using the provided parent shell
1159- userOptionDialog = new UserOptionsDialog (parentShell , mgr , rootDir );
1186+ // Create the preferences dialog using the provided parent shell
1187+ userOptionDialog = new UserOptionsDialog (parentShell , mgr , rootDir );
11601188
1161- // Set the preference store
1162- userOptionDialog .setPreferenceStore (props );
1163- userOptionDialog .create ();
1189+ // Set the preference store
1190+ userOptionDialog .setPreferenceStore (props );
1191+ userOptionDialog .create ();
1192+ }
1193+ else {
1194+ log .debug ("Reusing pre-created User Options dialog (instant open)" );
1195+ }
11641196
1165- // Open the dialog
1197+ // Open the dialog (instant if pre-created, or newly created if needed)
11661198 userOptionDialog .open ();
11671199
11681200 // TODO(HDFView) [2025-01]: TECHNICAL DEBT - Fix work directory change detection
0 commit comments