mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-25 00:01:50 +08: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.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.highlights.middle.mouse = color.bg.highlight
|
||||
@@ -46,8 +49,11 @@ icon.decompiler.action.display.lock = lock.gif
|
||||
font.decompiler = font.monospaced
|
||||
font.decompiler.pcode.dfg = font.graphdisplay.default
|
||||
|
||||
|
||||
font.decompiler.message = font.graph.component.message
|
||||
|
||||
[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
|
||||
|
||||
+8
-2
@@ -51,8 +51,7 @@ public class DecompilerController {
|
||||
private int cacheSize;
|
||||
|
||||
public DecompilerController(ServiceProvider serviceProvider, DecompilerCallbackHandler handler,
|
||||
DecompileOptions options,
|
||||
DecompilerClipboardProvider clipboard) {
|
||||
DecompileOptions options, DecompilerClipboardProvider clipboard) {
|
||||
this.serviceProvider = serviceProvider;
|
||||
this.cacheSize = options.getCacheSize();
|
||||
this.callbackHandler = handler;
|
||||
@@ -370,6 +369,13 @@ public class DecompilerController {
|
||||
decompilerCache.invalidateAll();
|
||||
}
|
||||
|
||||
public void clearCacheForCurrentFunction() {
|
||||
Function function = getFunction();
|
||||
if (function != null) {
|
||||
decompilerCache.invalidate(function);
|
||||
}
|
||||
}
|
||||
|
||||
public void programClosed(Program closedProgram) {
|
||||
for (Function function : decompilerCache.asMap().keySet()) {
|
||||
Program functionProgram = function.getProgram();
|
||||
|
||||
+20
-6
@@ -1393,16 +1393,30 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
|
||||
* decompiler content panel and the line numbers panel}
|
||||
*/
|
||||
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
|
||||
// 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
|
||||
// it is offset by the line number panel's width. We are also assuming there are no borders
|
||||
// internal to the DecompilerPanel. If that changes, we would also need to factor in the
|
||||
// insets.
|
||||
// of the line numbers panel can be found by looking at the x position of the scroll view,
|
||||
// as it is offset by the line number panel's width.
|
||||
Rectangle bounds = scroller.getBounds();
|
||||
Dimension scrollerSize = scroller.getViewExtentSize();
|
||||
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() {
|
||||
|
||||
+41
-18
@@ -86,6 +86,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||
|
||||
private ToggleDockingAction displayUnreachableCodeToggle;
|
||||
private ToggleDockingAction respectReadOnlyFlags;
|
||||
private ToggleDockingAction toggleLockAction;
|
||||
|
||||
private final DecompilePlugin plugin;
|
||||
private ClipboardService clipboardService;
|
||||
@@ -146,7 +147,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||
new DecompilerController(getTool(), this, decompilerOptions, clipboardProvider);
|
||||
DecompilerPanel decompilerPanel = controller.getDecompilerPanel();
|
||||
|
||||
// TODO move the hl controller into the panel
|
||||
// FUTURE move the hl controller into the panel
|
||||
highlightController = new LocationClangHighlightController();
|
||||
decompilerPanel.setHighlightController(highlightController);
|
||||
decorationPanel = new DecoratorPanel(decompilerPanel, isConnected) {
|
||||
@@ -155,7 +156,6 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||
super.paint(g);
|
||||
overlayPainter.paintOverlay(g, decompilerPanel.getViewContentBounds());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if (!isConnected) {
|
||||
@@ -326,6 +326,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||
ToolOptions opt = tool.getOptions(DecompilePlugin.OPTIONS_TITLE);
|
||||
|
||||
@@ -350,11 +351,15 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||
|
||||
if (currentLocation != null) {
|
||||
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());
|
||||
}
|
||||
else {
|
||||
controller.refreshDisplay(program, currentLocation, null);
|
||||
setOverlayMessage("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,6 +384,11 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||
decorationPanel.repaint();
|
||||
}
|
||||
|
||||
private void clearOverlayMessage() {
|
||||
overlayPainter.setMessage("");
|
||||
decorationPanel.repaint();
|
||||
}
|
||||
|
||||
private void refreshToggleButtons() {
|
||||
displayUnreachableCodeToggle.setSelected(!decompilerOptions.isEliminateUnreachable());
|
||||
respectReadOnlyFlags.setSelected(!decompilerOptions.isRespectReadOnly());
|
||||
@@ -533,7 +543,6 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||
*/
|
||||
void refresh() {
|
||||
controller.refreshDisplay(program, currentLocation, null);
|
||||
setOverlayMessage("");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -616,6 +625,8 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||
updateTitle();
|
||||
contextChanged();
|
||||
controller.setSelection(currentSelection);
|
||||
|
||||
clearOverlayMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -764,22 +775,34 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||
// invoke later to give the window manage a chance to create the new window
|
||||
// (its done in an invoke later)
|
||||
Swing.runLater(() -> {
|
||||
initializeClone(newProvider);
|
||||
});
|
||||
}
|
||||
|
||||
ViewerPosition myViewPosition = controller.getDecompilerPanel().getViewerPosition();
|
||||
newProvider.doSetProgram(program);
|
||||
private void initializeClone(DecompilerProvider newProvider) {
|
||||
ViewerPosition myViewPosition = controller.getDecompilerPanel().getViewerPosition();
|
||||
newProvider.doSetProgram(program);
|
||||
|
||||
// initialize the new provider's cache and then set the location
|
||||
DecompileData myDecompileData = controller.getDecompileData();
|
||||
newProvider.controller.addToCache(myDecompileData);
|
||||
newProvider.setLocation(currentLocation, myViewPosition);
|
||||
// initialize the new provider's cache and then set the location
|
||||
DecompileData myDecompileData = controller.getDecompileData();
|
||||
newProvider.controller.addToCache(myDecompileData);
|
||||
newProvider.setLocation(currentLocation, myViewPosition);
|
||||
|
||||
// transfer any state after the new decompiler is initialized
|
||||
DecompilerPanel myPanel = getDecompilerPanel();
|
||||
DecompilerPanel newPanel = newProvider.getDecompilerPanel();
|
||||
newProvider.doWhenNotBusy(() -> {
|
||||
newPanel.setViewerPosition(myViewPosition);
|
||||
newPanel.cloneHighlights(myPanel);
|
||||
});
|
||||
// update the lock action and overlay message for the new provider
|
||||
if (lockDisplay) {
|
||||
newProvider.toggleLockAction.setSelected(true);
|
||||
newProvider.lockDisplay = true;
|
||||
if (overlayPainter.isActive()) {
|
||||
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) {
|
||||
String owner = plugin.getName();
|
||||
|
||||
new ToggleActionBuilder("Lock Display", owner)
|
||||
toggleLockAction = new ToggleActionBuilder("Lock Display", owner)
|
||||
.toolBarIcon(LOCK_DISPLAY_ICON)
|
||||
.description("Lock display for auto-updates, only update on manual refresh")
|
||||
.helpLocation(new HelpLocation(HelpTopics.DECOMPILER, "LockDisplay"))
|
||||
|
||||
+17
-10
@@ -20,7 +20,7 @@ import java.awt.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import generic.theme.GColor;
|
||||
import generic.theme.GThemeDefaults.Colors.Palette;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import generic.theme.Gui;
|
||||
|
||||
/**
|
||||
@@ -28,9 +28,13 @@ import generic.theme.Gui;
|
||||
* needs to be refreshed manually.
|
||||
*/
|
||||
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 String FONT_ID = "font.graph.component.message";
|
||||
private final Color gradientColor = new GColor("color.bg.visualgraph.message");
|
||||
|
||||
private String message;
|
||||
|
||||
void setMessage(String message) {
|
||||
@@ -47,32 +51,35 @@ class OverlayMessagePainter {
|
||||
}
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// this composite softens the text and color of the message
|
||||
Composite originalComposite = g2.getComposite();
|
||||
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SrcOver.getRule(), .60f));
|
||||
|
||||
// set up font
|
||||
Font font = Gui.getFont(FONT_ID);
|
||||
Font font = Gui.getFont(FONT_MESSAGE_ID);
|
||||
g.setFont(font);
|
||||
Rectangle textBounds = font.getStringBounds(message, g2.getFontRenderContext()).getBounds();
|
||||
|
||||
int gx = bounds.x;
|
||||
int gh = textBounds.height * 3;
|
||||
int gy = bounds.height - gh;
|
||||
paintGradient(g2, 0, gy, bounds.width, gh);
|
||||
int gy = (bounds.y + bounds.height) - gh;
|
||||
int gw = bounds.width;
|
||||
paintGradient(g2, gx, gy, gw, gh);
|
||||
|
||||
// paint message
|
||||
g2.setPaint(Palette.BLACK);
|
||||
g2.setPaint(COLOR_FG_MESSAGE);
|
||||
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.setComposite(originalComposite);
|
||||
}
|
||||
|
||||
private void paintGradient(Graphics2D g2, int x, int y, int w, int h) {
|
||||
Color[] colors = new Color[] { Color.WHITE, gradientColor };
|
||||
float[] fractions = new float[] { 0.0f, .95f };
|
||||
Color[] colors = new Color[] { Colors.BACKGROUND, COLOR_BG_GRADIENT };
|
||||
float[] fractions = new float[] { 0.0f, .85f };
|
||||
LinearGradientPaint gradiantPaint =
|
||||
new LinearGradientPaint(new Point(x, y), new Point(x, y + h), fractions, colors);
|
||||
g2.setPaint(gradiantPaint);
|
||||
|
||||
+8
-5
@@ -115,12 +115,15 @@ public class IndexedScrollPane extends JPanel implements IndexScrollListener {
|
||||
|
||||
}
|
||||
|
||||
public Dimension getViewSize() {
|
||||
return new Dimension(comp.getPreferredSize().width, indexMapper.getViewHeight());
|
||||
public Dimension getViewExtentSize() {
|
||||
Dimension size = viewport.getExtentSize();
|
||||
int w = size.width;
|
||||
int h = size.height;
|
||||
return new Dimension(w, h);
|
||||
}
|
||||
|
||||
public Dimension getViewExtentSize() {
|
||||
return viewport.getExtentSize();
|
||||
public Insets getViewInsets() {
|
||||
return scrollPane.getInsets();
|
||||
}
|
||||
|
||||
public void viewportStateChanged() {
|
||||
@@ -311,7 +314,7 @@ public class IndexedScrollPane extends JPanel implements IndexScrollListener {
|
||||
public void setColumnHeaderComp(JComponent 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
|
||||
// horizontal position to 0 and back to where it was, resynchronizes the header with the
|
||||
// view.
|
||||
|
||||
Reference in New Issue
Block a user