Skip to content

Commit d8f9189

Browse files
committed
address open dialog delay issue
1 parent 0818336 commit d8f9189

File tree

1 file changed

+72
-40
lines changed

1 file changed

+72
-40
lines changed

hdfview/src/main/java/hdf/view/HDFView.java

Lines changed: 72 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)