mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
Fixed Decompiler message area not going away when changing functions
This commit is contained in:
@@ -14,6 +14,9 @@ color.fg.decompiler.global = color.palette.darkcyan
|
|||||||
color.fg.decompiler.special = color.palette.crimson
|
color.fg.decompiler.special = color.palette.crimson
|
||||||
color.fg.decompiler.external.function = color.palette.fuchsia
|
color.fg.decompiler.external.function = color.palette.fuchsia
|
||||||
|
|
||||||
|
color.fg.decompiler.message = color.palette.black
|
||||||
|
color.bg.decompiler.message = color.bg.visualgraph.message
|
||||||
|
|
||||||
color.bg.decompiler.current.variable = color.palette.highlight.transparent.yellow
|
color.bg.decompiler.current.variable = color.palette.highlight.transparent.yellow
|
||||||
|
|
||||||
color.bg.decompiler.highlights.middle.mouse = color.bg.highlight
|
color.bg.decompiler.highlights.middle.mouse = color.bg.highlight
|
||||||
@@ -46,8 +49,11 @@ icon.decompiler.action.display.lock = lock.gif
|
|||||||
font.decompiler = font.monospaced
|
font.decompiler = font.monospaced
|
||||||
font.decompiler.pcode.dfg = font.graphdisplay.default
|
font.decompiler.pcode.dfg = font.graphdisplay.default
|
||||||
|
|
||||||
|
font.decompiler.message = font.graph.component.message
|
||||||
|
|
||||||
[Dark Defaults]
|
[Dark Defaults]
|
||||||
|
|
||||||
|
# the message text needs to be dark in dark mode
|
||||||
|
color.fg.decompiler.message = rgb(0, 0, 0)
|
||||||
|
|
||||||
color.bg.decompiler.highlights.find = color.palette.cornflowerblue
|
color.bg.decompiler.highlights.find = color.palette.cornflowerblue
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ public class DecompilerController {
|
|||||||
private int cacheSize;
|
private int cacheSize;
|
||||||
|
|
||||||
public DecompilerController(ServiceProvider serviceProvider, DecompilerCallbackHandler handler,
|
public DecompilerController(ServiceProvider serviceProvider, DecompilerCallbackHandler handler,
|
||||||
DecompileOptions options,
|
DecompileOptions options, DecompilerClipboardProvider clipboard) {
|
||||||
DecompilerClipboardProvider clipboard) {
|
|
||||||
this.serviceProvider = serviceProvider;
|
this.serviceProvider = serviceProvider;
|
||||||
this.cacheSize = options.getCacheSize();
|
this.cacheSize = options.getCacheSize();
|
||||||
this.callbackHandler = handler;
|
this.callbackHandler = handler;
|
||||||
@@ -370,6 +369,13 @@ public class DecompilerController {
|
|||||||
decompilerCache.invalidateAll();
|
decompilerCache.invalidateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearCacheForCurrentFunction() {
|
||||||
|
Function function = getFunction();
|
||||||
|
if (function != null) {
|
||||||
|
decompilerCache.invalidate(function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void programClosed(Program closedProgram) {
|
public void programClosed(Program closedProgram) {
|
||||||
for (Function function : decompilerCache.asMap().keySet()) {
|
for (Function function : decompilerCache.asMap().keySet()) {
|
||||||
Program functionProgram = function.getProgram();
|
Program functionProgram = function.getProgram();
|
||||||
|
|||||||
@@ -1393,16 +1393,30 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
|
|||||||
* decompiler content panel and the line numbers panel}
|
* decompiler content panel and the line numbers panel}
|
||||||
*/
|
*/
|
||||||
public Rectangle getViewContentBounds() {
|
public Rectangle getViewContentBounds() {
|
||||||
|
|
||||||
|
Insets viewInsets = scroller.getViewInsets();
|
||||||
|
int x = 0; // don't use insets here, since we want the full size including the line # panel
|
||||||
|
int y = viewInsets.top;
|
||||||
|
|
||||||
|
// This compensates for the optional parent border. We have guilty knowledge that our parent
|
||||||
|
// will have a non-empty border when in a snapshot
|
||||||
|
JComponent decorationPanel = (JComponent) getParent();
|
||||||
|
Insets parentInsets = decorationPanel.getInsets();
|
||||||
|
x += parentInsets.left;
|
||||||
|
y += parentInsets.top;
|
||||||
|
|
||||||
// The bounds we want includes both the extent size of the main decompiler view + the
|
// The bounds we want includes both the extent size of the main decompiler view + the
|
||||||
// area that displays the line numbers which is not inside the IndexedScrollPane. The width
|
// area that displays the line numbers which is not inside the IndexedScrollPane. The width
|
||||||
// of the line numbers panel can be found by looking at the x position of the scroller as
|
// of the line numbers panel can be found by looking at the x position of the scroll view,
|
||||||
// it is offset by the line number panel's width. We are also assuming there are no borders
|
// as it is offset by the line number panel's width.
|
||||||
// internal to the DecompilerPanel. If that changes, we would also need to factor in the
|
|
||||||
// insets.
|
|
||||||
Rectangle bounds = scroller.getBounds();
|
Rectangle bounds = scroller.getBounds();
|
||||||
Dimension scrollerSize = scroller.getViewExtentSize();
|
|
||||||
int lineNumberWidth = bounds.x;
|
int lineNumberWidth = bounds.x;
|
||||||
return new Rectangle(0, 0, scrollerSize.width + lineNumberWidth, scrollerSize.height);
|
int gap = viewInsets.left;
|
||||||
|
Dimension extent = scroller.getViewExtentSize();
|
||||||
|
int width = lineNumberWidth + gap + extent.width;
|
||||||
|
int height = extent.height;
|
||||||
|
|
||||||
|
return new Rectangle(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildPanels() {
|
private void buildPanels() {
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
|
|
||||||
private ToggleDockingAction displayUnreachableCodeToggle;
|
private ToggleDockingAction displayUnreachableCodeToggle;
|
||||||
private ToggleDockingAction respectReadOnlyFlags;
|
private ToggleDockingAction respectReadOnlyFlags;
|
||||||
|
private ToggleDockingAction toggleLockAction;
|
||||||
|
|
||||||
private final DecompilePlugin plugin;
|
private final DecompilePlugin plugin;
|
||||||
private ClipboardService clipboardService;
|
private ClipboardService clipboardService;
|
||||||
@@ -146,7 +147,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
new DecompilerController(getTool(), this, decompilerOptions, clipboardProvider);
|
new DecompilerController(getTool(), this, decompilerOptions, clipboardProvider);
|
||||||
DecompilerPanel decompilerPanel = controller.getDecompilerPanel();
|
DecompilerPanel decompilerPanel = controller.getDecompilerPanel();
|
||||||
|
|
||||||
// TODO move the hl controller into the panel
|
// FUTURE move the hl controller into the panel
|
||||||
highlightController = new LocationClangHighlightController();
|
highlightController = new LocationClangHighlightController();
|
||||||
decompilerPanel.setHighlightController(highlightController);
|
decompilerPanel.setHighlightController(highlightController);
|
||||||
decorationPanel = new DecoratorPanel(decompilerPanel, isConnected) {
|
decorationPanel = new DecoratorPanel(decompilerPanel, isConnected) {
|
||||||
@@ -155,7 +156,6 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
super.paint(g);
|
super.paint(g);
|
||||||
overlayPainter.paintOverlay(g, decompilerPanel.getViewContentBounds());
|
overlayPainter.paintOverlay(g, decompilerPanel.getViewContentBounds());
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
@@ -326,6 +326,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
if (!isVisible()) {
|
if (!isVisible()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||||
ToolOptions opt = tool.getOptions(DecompilePlugin.OPTIONS_TITLE);
|
ToolOptions opt = tool.getOptions(DecompilePlugin.OPTIONS_TITLE);
|
||||||
|
|
||||||
@@ -350,11 +351,15 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
|
|
||||||
if (currentLocation != null) {
|
if (currentLocation != null) {
|
||||||
if (lockDisplay) {
|
if (lockDisplay) {
|
||||||
|
// Clear the cached results so the next time we come back to this function, it will
|
||||||
|
// get re-decompiled. If we don't do this, then we would need the ability to mark
|
||||||
|
// the cached results as needing update, so future loads of that cached function
|
||||||
|
// will trigger the refresh message.
|
||||||
|
controller.clearCacheForCurrentFunction();
|
||||||
setOverlayMessage(getOverlayRefreshMessage());
|
setOverlayMessage(getOverlayRefreshMessage());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
controller.refreshDisplay(program, currentLocation, null);
|
controller.refreshDisplay(program, currentLocation, null);
|
||||||
setOverlayMessage("");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,6 +384,11 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
decorationPanel.repaint();
|
decorationPanel.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearOverlayMessage() {
|
||||||
|
overlayPainter.setMessage("");
|
||||||
|
decorationPanel.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
private void refreshToggleButtons() {
|
private void refreshToggleButtons() {
|
||||||
displayUnreachableCodeToggle.setSelected(!decompilerOptions.isEliminateUnreachable());
|
displayUnreachableCodeToggle.setSelected(!decompilerOptions.isEliminateUnreachable());
|
||||||
respectReadOnlyFlags.setSelected(!decompilerOptions.isRespectReadOnly());
|
respectReadOnlyFlags.setSelected(!decompilerOptions.isRespectReadOnly());
|
||||||
@@ -533,7 +543,6 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
*/
|
*/
|
||||||
void refresh() {
|
void refresh() {
|
||||||
controller.refreshDisplay(program, currentLocation, null);
|
controller.refreshDisplay(program, currentLocation, null);
|
||||||
setOverlayMessage("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -616,6 +625,8 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
updateTitle();
|
updateTitle();
|
||||||
contextChanged();
|
contextChanged();
|
||||||
controller.setSelection(currentSelection);
|
controller.setSelection(currentSelection);
|
||||||
|
|
||||||
|
clearOverlayMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -764,22 +775,34 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
// invoke later to give the window manage a chance to create the new window
|
// invoke later to give the window manage a chance to create the new window
|
||||||
// (its done in an invoke later)
|
// (its done in an invoke later)
|
||||||
Swing.runLater(() -> {
|
Swing.runLater(() -> {
|
||||||
|
initializeClone(newProvider);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ViewerPosition myViewPosition = controller.getDecompilerPanel().getViewerPosition();
|
private void initializeClone(DecompilerProvider newProvider) {
|
||||||
newProvider.doSetProgram(program);
|
ViewerPosition myViewPosition = controller.getDecompilerPanel().getViewerPosition();
|
||||||
|
newProvider.doSetProgram(program);
|
||||||
|
|
||||||
// initialize the new provider's cache and then set the location
|
// initialize the new provider's cache and then set the location
|
||||||
DecompileData myDecompileData = controller.getDecompileData();
|
DecompileData myDecompileData = controller.getDecompileData();
|
||||||
newProvider.controller.addToCache(myDecompileData);
|
newProvider.controller.addToCache(myDecompileData);
|
||||||
newProvider.setLocation(currentLocation, myViewPosition);
|
newProvider.setLocation(currentLocation, myViewPosition);
|
||||||
|
|
||||||
// transfer any state after the new decompiler is initialized
|
// update the lock action and overlay message for the new provider
|
||||||
DecompilerPanel myPanel = getDecompilerPanel();
|
if (lockDisplay) {
|
||||||
DecompilerPanel newPanel = newProvider.getDecompilerPanel();
|
newProvider.toggleLockAction.setSelected(true);
|
||||||
newProvider.doWhenNotBusy(() -> {
|
newProvider.lockDisplay = true;
|
||||||
newPanel.setViewerPosition(myViewPosition);
|
if (overlayPainter.isActive()) {
|
||||||
newPanel.cloneHighlights(myPanel);
|
newProvider.setOverlayMessage(getOverlayRefreshMessage());
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// transfer any state after the new decompiler is initialized
|
||||||
|
DecompilerPanel myPanel = getDecompilerPanel();
|
||||||
|
DecompilerPanel newPanel = newProvider.getDecompilerPanel();
|
||||||
|
newProvider.doWhenNotBusy(() -> {
|
||||||
|
newPanel.setViewerPosition(myViewPosition);
|
||||||
|
newPanel.cloneHighlights(myPanel);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -835,7 +858,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
private void createActions(boolean isConnected) {
|
private void createActions(boolean isConnected) {
|
||||||
String owner = plugin.getName();
|
String owner = plugin.getName();
|
||||||
|
|
||||||
new ToggleActionBuilder("Lock Display", owner)
|
toggleLockAction = new ToggleActionBuilder("Lock Display", owner)
|
||||||
.toolBarIcon(LOCK_DISPLAY_ICON)
|
.toolBarIcon(LOCK_DISPLAY_ICON)
|
||||||
.description("Lock display for auto-updates, only update on manual refresh")
|
.description("Lock display for auto-updates, only update on manual refresh")
|
||||||
.helpLocation(new HelpLocation(HelpTopics.DECOMPILER, "LockDisplay"))
|
.helpLocation(new HelpLocation(HelpTopics.DECOMPILER, "LockDisplay"))
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import java.awt.*;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import generic.theme.GColor;
|
import generic.theme.GColor;
|
||||||
import generic.theme.GThemeDefaults.Colors.Palette;
|
import generic.theme.GThemeDefaults.Colors;
|
||||||
import generic.theme.Gui;
|
import generic.theme.Gui;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,9 +28,13 @@ import generic.theme.Gui;
|
|||||||
* needs to be refreshed manually.
|
* needs to be refreshed manually.
|
||||||
*/
|
*/
|
||||||
class OverlayMessagePainter {
|
class OverlayMessagePainter {
|
||||||
|
|
||||||
|
private static final String FONT_MESSAGE_ID = "font.decompiler.message";
|
||||||
|
private static final Color COLOR_BG_GRADIENT = new GColor("color.bg.decompiler.message");
|
||||||
|
private static final Color COLOR_FG_MESSAGE = new GColor("color.fg.decompiler.message");
|
||||||
|
|
||||||
private static final int MARGIN = 10;
|
private static final int MARGIN = 10;
|
||||||
private static final String FONT_ID = "font.graph.component.message";
|
|
||||||
private final Color gradientColor = new GColor("color.bg.visualgraph.message");
|
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
void setMessage(String message) {
|
void setMessage(String message) {
|
||||||
@@ -47,32 +51,35 @@ class OverlayMessagePainter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Graphics2D g2 = (Graphics2D) g;
|
Graphics2D g2 = (Graphics2D) g;
|
||||||
|
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
// this composite softens the text and color of the message
|
// this composite softens the text and color of the message
|
||||||
Composite originalComposite = g2.getComposite();
|
Composite originalComposite = g2.getComposite();
|
||||||
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SrcOver.getRule(), .60f));
|
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SrcOver.getRule(), .60f));
|
||||||
|
|
||||||
// set up font
|
// set up font
|
||||||
Font font = Gui.getFont(FONT_ID);
|
Font font = Gui.getFont(FONT_MESSAGE_ID);
|
||||||
g.setFont(font);
|
g.setFont(font);
|
||||||
Rectangle textBounds = font.getStringBounds(message, g2.getFontRenderContext()).getBounds();
|
Rectangle textBounds = font.getStringBounds(message, g2.getFontRenderContext()).getBounds();
|
||||||
|
|
||||||
|
int gx = bounds.x;
|
||||||
int gh = textBounds.height * 3;
|
int gh = textBounds.height * 3;
|
||||||
int gy = bounds.height - gh;
|
int gy = (bounds.y + bounds.height) - gh;
|
||||||
paintGradient(g2, 0, gy, bounds.width, gh);
|
int gw = bounds.width;
|
||||||
|
paintGradient(g2, gx, gy, gw, gh);
|
||||||
|
|
||||||
// paint message
|
// paint message
|
||||||
g2.setPaint(Palette.BLACK);
|
g2.setPaint(COLOR_FG_MESSAGE);
|
||||||
int textX = bounds.width - textBounds.width - MARGIN;
|
int textX = bounds.width - textBounds.width - MARGIN;
|
||||||
int textY = bounds.height - textBounds.height / 2; //text at bottom; account for baseline
|
int textY = bounds.height - textBounds.height / 2; // text at bottom; account for baseline
|
||||||
g2.drawString(message, textX, textY);
|
g2.drawString(message, textX, textY);
|
||||||
|
|
||||||
g2.setComposite(originalComposite);
|
g2.setComposite(originalComposite);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void paintGradient(Graphics2D g2, int x, int y, int w, int h) {
|
private void paintGradient(Graphics2D g2, int x, int y, int w, int h) {
|
||||||
Color[] colors = new Color[] { Color.WHITE, gradientColor };
|
Color[] colors = new Color[] { Colors.BACKGROUND, COLOR_BG_GRADIENT };
|
||||||
float[] fractions = new float[] { 0.0f, .95f };
|
float[] fractions = new float[] { 0.0f, .85f };
|
||||||
LinearGradientPaint gradiantPaint =
|
LinearGradientPaint gradiantPaint =
|
||||||
new LinearGradientPaint(new Point(x, y), new Point(x, y + h), fractions, colors);
|
new LinearGradientPaint(new Point(x, y), new Point(x, y + h), fractions, colors);
|
||||||
g2.setPaint(gradiantPaint);
|
g2.setPaint(gradiantPaint);
|
||||||
|
|||||||
@@ -115,12 +115,15 @@ public class IndexedScrollPane extends JPanel implements IndexScrollListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dimension getViewSize() {
|
public Dimension getViewExtentSize() {
|
||||||
return new Dimension(comp.getPreferredSize().width, indexMapper.getViewHeight());
|
Dimension size = viewport.getExtentSize();
|
||||||
|
int w = size.width;
|
||||||
|
int h = size.height;
|
||||||
|
return new Dimension(w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dimension getViewExtentSize() {
|
public Insets getViewInsets() {
|
||||||
return viewport.getExtentSize();
|
return scrollPane.getInsets();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void viewportStateChanged() {
|
public void viewportStateChanged() {
|
||||||
@@ -311,7 +314,7 @@ public class IndexedScrollPane extends JPanel implements IndexScrollListener {
|
|||||||
public void setColumnHeaderComp(JComponent comp) {
|
public void setColumnHeaderComp(JComponent comp) {
|
||||||
scrollPane.setColumnHeaderView(comp);
|
scrollPane.setColumnHeaderView(comp);
|
||||||
|
|
||||||
// SWING WORK AROUND - setting the header panel on a scrollpane that is horizontally
|
// SWING WORK AROUND - setting the header panel on a scroll pane that is horizontally
|
||||||
// scrolled does not initially scroll the header to match the main view. Setting the
|
// scrolled does not initially scroll the header to match the main view. Setting the
|
||||||
// horizontal position to 0 and back to where it was, resynchronizes the header with the
|
// horizontal position to 0 and back to where it was, resynchronizes the header with the
|
||||||
// view.
|
// view.
|
||||||
|
|||||||
Reference in New Issue
Block a user