GP-3958 - Update how un-maximized window bounds are tracked

This commit is contained in:
dragonmacher 2023-10-23 17:14:57 -04:00
parent fc9e495c6c
commit 3de35623bd

View file

@ -28,6 +28,7 @@ import org.jdom.Element;
import generic.util.WindowUtilities;
import ghidra.framework.OperatingSystem;
import ghidra.framework.Platform;
import ghidra.util.Swing;
import ghidra.util.bean.GGlassPane;
import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet;
@ -427,16 +428,13 @@ class RootNode extends WindowNode {
Element saveToXML() {
Element root = new Element(ROOT_NODE_ELEMENT_NAME);
JFrame frame = windowWrapper.getParentFrame();
// Save un-maximized/un-iconified bounds rather than e.g. whole screen if maximized
int state = frame.getExtendedState(); // Remember current state
frame.setExtendedState(JFrame.NORMAL); // Un-maximize & un-iconify
Rectangle r = frame.getBounds(); // The un-maximized & un-iconified bounds
frame.setExtendedState(state); // Revert to original state
Rectangle r = getSaveableBounds();
root.setAttribute("X_POS", "" + r.x);
root.setAttribute("Y_POS", "" + r.y);
root.setAttribute("WIDTH", "" + r.width);
root.setAttribute("HEIGHT", "" + r.height);
root.setAttribute("EX_STATE", "" + state);
root.setAttribute("EX_STATE", "" + frame.getExtendedState());
if (child != null) {
root.addContent(child.saveToXML());
}
@ -448,6 +446,18 @@ class RootNode extends WindowNode {
return root;
}
private Rectangle getSaveableBounds() {
Rectangle bounds = windowWrapper.getLastBounds();
if (bounds != null) {
return bounds;
}
// This implies the user has never maximized the window; just use the window bounds.
JFrame frame = windowWrapper.getParentFrame();
return frame.getBounds();
}
/**
* Restores the component hierarchy from the given XML JDOM element.
* <p>
@ -478,7 +488,15 @@ class RootNode extends WindowNode {
Rectangle bounds = new Rectangle(x, y, width, height);
WindowUtilities.ensureOnScreen(frame, bounds);
frame.setBounds(bounds);
frame.setExtendedState(extendedState);
windowWrapper.setLastBounds(bounds);
Swing.runLater(() -> {
// On some systems setting the bounds will interfere with setting the extended state.
// Run this later to ensure the extended state is applied after setting the bounds.
// Executing in this order allows the bounds we set above to be used when the user
// transitions out of the maximized state.
frame.setExtendedState(extendedState);
});
List<ComponentPlaceholder> restoredPlaceholders = new ArrayList<>();
Iterator<?> elementIterator = rootNodeElement.getChildren().iterator();
@ -611,29 +629,64 @@ class RootNode extends WindowNode {
//==================================================================================================
/** Interface to wrap JDialog and JFrame so that they can be used by one handle */
private interface SwingWindowWrapper {
boolean isVisible();
private abstract class SwingWindowWrapper {
boolean isModal();
/**
* The last known non-maximized window bounds
*/
private Rectangle lastBounds;
void validate();
abstract boolean isVisible();
Container getContentPane();
abstract boolean isModal();
void setJMenuBar(JMenuBar menuBar);
abstract void validate();
void dispose();
abstract Container getContentPane();
Window getWindow();
abstract void setJMenuBar(JMenuBar menuBar);
JFrame getParentFrame();
abstract void dispose();
void setTitle(String title);
abstract Window getWindow();
String getTitle();
abstract JFrame getParentFrame();
abstract void setTitle(String title);
abstract String getTitle();
/**
* Stores the given bounds if they are not the maximized bounds
* @param bounds the bounds
*/
public void setLastBounds(Rectangle bounds) {
Rectangle screenBounds = WindowUtilities.getScreenBounds(getWindow());
if (screenBounds == null) {
return;
}
Rectangle boundsSize = new Rectangle(bounds.getSize());
Rectangle screenSize = new Rectangle(screenBounds.getSize());
if (boundsSize.contains(screenSize)) {
// This can happen when the bounds being set are the full screen bounds. We only
// wish to save the non-maximized bounds.
return;
}
this.lastBounds = bounds;
}
/**
* Returns the last non-maximized frame bounds
* @return the bounds
*/
public Rectangle getLastBounds() {
return lastBounds;
}
}
private class JDialogWindowWrapper implements SwingWindowWrapper {
private class JDialogWindowWrapper extends SwingWindowWrapper {
private final JDialog wrappedDialog;
private final SwingWindowWrapper parentFrame;
@ -663,9 +716,16 @@ class RootNode extends WindowNode {
public void windowActivated(WindowEvent e) {
winMgr.setActive(wrappedDialog, true);
}
@Override
public void windowStateChanged(WindowEvent e) {
// this is called when transitioning in and out of the full-screen state
setLastBounds(wrappedDialog.getBounds());
}
};
dialog.addWindowListener(windowListener);
dialog.addWindowStateListener(windowListener);
}
@Override
@ -686,6 +746,11 @@ class RootNode extends WindowNode {
return wrappedDialog;
}
@Override
public JFrame getParentFrame() {
return parentFrame.getParentFrame();
}
@Override
public boolean isVisible() {
return wrappedDialog.isVisible();
@ -701,11 +766,6 @@ class RootNode extends WindowNode {
wrappedDialog.validate();
}
@Override
public JFrame getParentFrame() {
return parentFrame.getParentFrame();
}
@Override
public void setTitle(String title) {
wrappedDialog.setTitle(title);
@ -722,7 +782,7 @@ class RootNode extends WindowNode {
}
}
private class JFrameWindowWrapper implements SwingWindowWrapper {
private class JFrameWindowWrapper extends SwingWindowWrapper {
private final JFrame wrappedFrame;
private WindowAdapter windowListener;
@ -763,8 +823,16 @@ class RootNode extends WindowNode {
public void windowDeiconified(WindowEvent e) {
winMgr.deIconify();
}
@Override
public void windowStateChanged(WindowEvent e) {
// this is called when transitioning in and out of the full-screen state
setLastBounds(wrappedFrame.getBounds());
}
};
wrappedFrame.addWindowListener(windowListener);
wrappedFrame.addWindowStateListener(windowListener);
wrappedFrame.setSize(800, 400);
}
@ -786,6 +854,11 @@ class RootNode extends WindowNode {
return wrappedFrame;
}
@Override
public JFrame getParentFrame() {
return wrappedFrame;
}
@Override
public boolean isVisible() {
return wrappedFrame.isVisible();
@ -801,11 +874,6 @@ class RootNode extends WindowNode {
wrappedFrame.validate();
}
@Override
public JFrame getParentFrame() {
return wrappedFrame;
}
@Override
public void setTitle(String title) {
wrappedFrame.setTitle(title);
@ -820,7 +888,6 @@ class RootNode extends WindowNode {
public boolean isModal() {
return false;
}
}
public void addDockingWindowListener(DockingWindowListener listener) {