diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java index 0f22fa8e79..34e188ba43 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java @@ -1344,7 +1344,7 @@ class StructureEditorModel extends CompEditorModel { String title = "Specify the Structure's Name"; InputDialog nameStructureDialog = new InputDialog(title, new String[] { "New Structure's Name: " }, - new String[] { defaultName }, true, listener); + new String[] { defaultName }, listener); provider.getPlugin().getTool().showDialog(nameStructureDialog); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TagListPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TagListPanel.java index 4662340d24..0a08a6bb8c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TagListPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TagListPanel.java @@ -138,7 +138,7 @@ public abstract class TagListPanel extends JPanel { String comment = rowObject.getComment(); String[] labels = new String[] { "Name:", "Comment:" }; String[] init = new String[] { tagName, comment }; - InputDialog dialog = new InputDialog("Edit Tag", labels, init, true, d -> { + InputDialog dialog = new InputDialog("Edit Tag", labels, init, d -> { String[] results = d.getValues(); if (results == null || results.length != 2) { return false; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/script/AskDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/script/AskDialog.java index 8d8ac4885b..b62df1ec5d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/script/AskDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/script/AskDialog.java @@ -28,7 +28,6 @@ import docking.widgets.label.GDLabel; import generic.util.WindowUtilities; import ghidra.framework.preferences.Preferences; import ghidra.util.NumericUtilities; -import ghidra.util.SystemUtilities; public class AskDialog extends DialogComponentProvider { public final static int STRING = 0; @@ -97,12 +96,13 @@ public class AskDialog extends DialogComponentProvider { panel.add(comboField, BorderLayout.CENTER); } + setTransient(true); addWorkPanel(panel); addOKButton(); addCancelButton(); setDefaultButton(okButton); setRememberSize(false); - SystemUtilities.runSwingNow(() -> DockingWindowManager.showDialog(parent, AskDialog.this)); + DockingWindowManager.showDialog(parent, AskDialog.this); } private void saveCurrentDimensions() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/script/SelectLanguageDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/script/SelectLanguageDialog.java index c6df23a359..6e8ba4e7ec 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/script/SelectLanguageDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/script/SelectLanguageDialog.java @@ -33,6 +33,7 @@ public class SelectLanguageDialog extends DialogComponentProvider { languagePanel = new NewLanguagePanel(); + setTransient(true); addWorkPanel(languagePanel); addOKButton(); addCancelButton(); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/RenameTask.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/RenameTask.java index c87a2f63c5..32f746b593 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/RenameTask.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/RenameTask.java @@ -85,7 +85,7 @@ public abstract class RenameTask { String label = "Rename " + oldName + ":"; InputDialog renameVarDialog = new InputDialog( getTransactionName(), - new String[]{ label }, new String[]{ oldName }, true, listener ); + new String[]{ label }, new String[]{ oldName }, listener ); tool.showDialog(renameVarDialog); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java index 7755e4cd2a..65e5792860 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java @@ -1766,41 +1766,45 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder This method seeks to accomplish 2 goals: 1) find a suitable component over which to center, and 2) ensure that the chosen component is in the parent hierarchy - + */ - Component bestComponent = centeredOnComponent; - if (SwingUtilities.isDescendingFrom(parent, bestComponent)) { - return bestComponent; + if (SwingUtilities.isDescendingFrom(parent, centeredOnComponent)) { + return centeredOnComponent; } - // by default, prefer to center over the active window - KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - Window activeWindow = kfm.getActiveWindow(); - bestComponent = activeWindow; - if (SwingUtilities.isDescendingFrom(parent, bestComponent)) { - return bestComponent; + // + // By default, prefer to center over the active window + // + Window activeWindow = getActiveNonTransientWindow(); + if (SwingUtilities.isDescendingFrom(parent, activeWindow)) { + // + // Have an active, visible, non-transient window, which may be another dialog. + // We prefer this to be the parent. + // + return activeWindow; } + // // The chosen component is not in the parent's hierarchy. See if there exists a // non-transient parent window for that component. - Window newWindow = getParentWindow(parent); + // + Window newWindow = getParentWindow(centeredOnComponent); if (newWindow != null) { // the component is safe to use; the caller of this method will validate the component // we return, updating the parent as needed - return bestComponent; + return centeredOnComponent; } // We were unable to find a suitable parent for the 'best' component. Just return the // parent as the thing over which to center. return parent; - } private static Window getParentWindow(Component parent) { /* Note: Which window should be the parent of the dialog when the user does not specify? - + Some use cases; a dialog is shown from: 1) A toolbar action 2) A component provider's code @@ -1808,7 +1812,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder 4) A background thread 5) The help window 6) A modal password dialog appears over the splash screen - + It seems like the parent should be the active window for 1-2. Case 3 should probably use the window of the dialog provider. Case 4 should probably use the main tool frame, since the user may be @@ -1816,12 +1820,12 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder active window, we can default to the tool's frame. Case 5 should use the help window. Case 6 should use the splash screen as the parent. - + We have not yet solidified how we should parent. This documentation is meant to move us towards clarity as we find Use Cases that don't make sense. (Once we finalize our understanding, we should update the javadoc to list exactly where the given Dialog Component will be shown.) - + Use Case A -The user presses an action on a toolbar from a window on screen 1, while the main tool frame is on screen 2. We want the popup window to appear on screen @@ -1833,11 +1837,16 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder -modal - Java handles this correctly, allowing the new dialog to be used -non-modal - Java prevents the non-modal from being editing if not parented correctly - - - For now, the easiest mental model to use is to always prefer the active window so - that a dialog will appear in the user's view. If we find a case where this is + D -The user runs a script that shows an input dialog before the non-modal script + dialog is shown. If the non-modal dialog is parented to the modal input dialog, + then the script progress dialog appears on top (which we do not want) and the + progress dialog goes away when the input dialog is closed. + + + For now, the easiest mental model to use is to always prefer the active non-transient + window so that a dialog will appear in the user's view. If we find a case where this is not desired, then document it here. + */ // diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/OptionDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/OptionDialog.java index 397a895715..ac2861af58 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/OptionDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/OptionDialog.java @@ -174,6 +174,7 @@ public class OptionDialog extends DialogComponentProvider { protected OptionDialog(String title, String message, String option1, String option2, int messageType, Icon icon, boolean addCancel) { super(title, true, false, true, false); + setTransient(true); buildMainPanel(message, messageType, icon, null); buildButtons(toList(option1, option2), addCancel, null); } @@ -194,6 +195,7 @@ public class OptionDialog extends DialogComponentProvider { protected OptionDialog(String title, String message, String option1, String option2, int messageType, Icon icon, boolean addCancel, String defaultButtonName) { super(title, true, false, true, false); + setTransient(true); buildMainPanel(message, messageType, icon, null); buildButtons(toList(option1, option2), addCancel, defaultButtonName); } @@ -233,6 +235,7 @@ public class OptionDialog extends DialogComponentProvider { protected OptionDialog(String title, String message, String option1, String option2, String option3, int messageType, Icon icon, boolean addCancel) { super(title, true, false, true, false); + setTransient(true); buildMainPanel(message, messageType, icon, null); buildButtons(toList(option1, option2, option3), addCancel, null); } @@ -240,6 +243,7 @@ public class OptionDialog extends DialogComponentProvider { OptionDialog(String title, String message, int messageType, Icon icon, boolean addCancelButton, DialogRememberOption savedDialogChoice, List options, String defaultOption) { super(title, true, false, true, false); + setTransient(true); buildMainPanel(message, messageType, icon, savedDialogChoice); buildButtons(options, addCancelButton, defaultOption); } @@ -256,6 +260,7 @@ public class OptionDialog extends DialogComponentProvider { private void buildMainPanel(String message, int messageType, Icon icon, DialogRememberOption rememberOptionChoice) { + JPanel panel = new JPanel(new BorderLayout()); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/AbstractNumberInputDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/AbstractNumberInputDialog.java index 3255482526..87ecf40a3c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/AbstractNumberInputDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/AbstractNumberInputDialog.java @@ -75,6 +75,7 @@ public abstract class AbstractNumberInputDialog extends DialogComponentProvider } this.max = max; + setTransient(true); addWorkPanel(buildMainPanel(prompt, showAsHex)); addOKButton(); addCancelButton(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/InputDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/InputDialog.java index fe7a15e21d..e8f4f1d6f3 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/InputDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/InputDialog.java @@ -53,7 +53,7 @@ public class InputDialog extends DialogComponentProvider { * @param label value to use for the label of the text field */ public InputDialog(String dialogTitle, String label) { - this(dialogTitle, new String[] { label }, new String[] { DEFAULT_VALUE }, true, null); + this(dialogTitle, new String[] { label }, new String[] { DEFAULT_VALUE }, null); } /** @@ -68,7 +68,7 @@ public class InputDialog extends DialogComponentProvider { * @param initialValue initial value to use for the text field */ public InputDialog(String dialogTitle, String label, String initialValue) { - this(dialogTitle, new String[] { label }, new String[] { initialValue }, true, null); + this(dialogTitle, new String[] { label }, new String[] { initialValue }, null); } /** @@ -85,7 +85,7 @@ public class InputDialog extends DialogComponentProvider { */ public InputDialog(String dialogTitle, String label, String initialValue, InputDialogListener listener) { - this(dialogTitle, new String[] { label }, new String[] { initialValue }, true, listener); + this(dialogTitle, new String[] { label }, new String[] { initialValue }, listener); } /** @@ -101,7 +101,7 @@ public class InputDialog extends DialogComponentProvider { * @param isModal whether or not the dialog is to be modal */ public InputDialog(String dialogTitle, String label, String initialValue, boolean isModal) { - this(dialogTitle, new String[] { label }, new String[] { initialValue }, isModal, null); + this(dialogTitle, new String[] { label }, new String[] { initialValue }, null); } /** @@ -116,7 +116,7 @@ public class InputDialog extends DialogComponentProvider { * @param initialValues initial values to use for the text fields */ public InputDialog(String dialogTitle, String[] labels, String[] initialValues) { - this(dialogTitle, labels, initialValues, true, null); + this(dialogTitle, labels, initialValues, null); } /** @@ -129,12 +129,11 @@ public class InputDialog extends DialogComponentProvider { * @param dialogTitle used as the name of the dialog's title bar * @param labels values to use for the labels of the text fields * @param initialValues initial values to use for the text fields - * @param isModal whether or not the dialog is to be modal * @param listener listener that is called when the OK button is hit */ - public InputDialog(String dialogTitle, String[] labels, String[] initialValues, boolean isModal, + public InputDialog(String dialogTitle, String[] labels, String[] initialValues, InputDialogListener listener) { - super(dialogTitle, isModal, (listener != null) /* status */, true /* buttons */, + super(dialogTitle, true, (listener != null) /* status */, true /* buttons */, false /* no tasks */); this.listener = listener; @@ -152,8 +151,9 @@ public class InputDialog extends DialogComponentProvider { // put the rest of the dialog together inputLabels = labels; this.initialValues = initialValues; - this.addOKButton(); - this.addCancelButton(); + setTransient(true); + addOKButton(); + addCancelButton(); buildMainPanel(); if (initialValues != null && initialValues[0] != null && initialValues[0].length() > 0) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/InputWithChoicesDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/InputWithChoicesDialog.java index 51ae9d7cda..6d24a935b3 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/InputWithChoicesDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/InputWithChoicesDialog.java @@ -55,10 +55,11 @@ public class InputWithChoicesDialog extends DialogComponentProvider { super(dialogTitle, true, false, true, false); - this.addOKButton(); - this.addCancelButton(); - this.setRememberSize(false); - this.setRememberLocation(false); + setTransient(true); + addOKButton(); + addCancelButton(); + setRememberSize(false); + setRememberLocation(false); buildMainPanel(label, optionValues, initialValue, messageIcon); setFocusComponent(combo); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineInputDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineInputDialog.java index 7fa9916ec3..da402f4c5d 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineInputDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineInputDialog.java @@ -43,6 +43,7 @@ public class MultiLineInputDialog extends DialogComponentProvider { setFocusComponent(inputTextArea); + setTransient(true); addOKButton(); addCancelButton(); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineMessageDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineMessageDialog.java index 248e69a6f3..2c2af26f0d 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineMessageDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineMessageDialog.java @@ -148,6 +148,7 @@ public class MultiLineMessageDialog extends DialogComponentProvider { workPanel.add(iconLabel, BorderLayout.WEST); } + setTransient(true); addWorkPanel(workPanel); addOKButton(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ObjectChooserDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ObjectChooserDialog.java index db2d4b7408..f88a89a9c5 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ObjectChooserDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ObjectChooserDialog.java @@ -36,6 +36,8 @@ public class ObjectChooserDialog extends DialogComponentProvider { this.objectClass = objectClass; this.choosableObjects = choosableObjects; this.methodsForColumns = methodsForColumns; + + setTransient(true); addWorkPanel(buildWorkPanel()); addOKButton(); addCancelButton(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ReadTextDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ReadTextDialog.java index aae35a149e..3f15479912 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ReadTextDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ReadTextDialog.java @@ -55,8 +55,9 @@ public class ReadTextDialog extends DialogComponentProvider { } private void init(JPanel workPanelToInit) { - this.addWorkPanel(workPanelToInit); - this.addOKButton(); + setTransient(true); + addWorkPanel(workPanelToInit); + addOKButton(); setRememberLocation(false); setRememberSize(false); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/SettingsDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/SettingsDialog.java index 94e907ebf9..a86fb22987 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/SettingsDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/SettingsDialog.java @@ -52,6 +52,8 @@ public class SettingsDialog extends DialogComponentProvider { if (help != null) { setHelpLocation(help); } + + setTransient(true); addWorkPanel(buildWorkPanel()); addDismissButton(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java index 6023e76576..9e8f54eaea 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java @@ -234,6 +234,7 @@ public class GhidraFileChooser extends DialogComponentProvider super(TITLE, true, true, true, false); this.parent = parent; + setTransient(true); init(model); loadRecentList(); loadOptions();