NationalSecurityAgency / ghidra

Ghidra is a software reverse engineering (SRE) framework
https://www.nsa.gov/ghidra
Apache License 2.0
51.41k stars 5.86k forks source link

Enable/allow antialiased text in Motif look & feel #3795

Open M-a-r-k opened 2 years ago

M-a-r-k commented 2 years ago

The Motif look and feel is one of the better choices for the Use Inverted Colors option, but it doesn't support antialiased text. Apparently that's by design.

That might not be too bad, but as I understand it Java/Swing doesn't support bitmap fonts. It makes using the Motif look & feel on a non-high-DPI screen not great. On Windows the only really legible mono-spaced scalable font (when rendered without antialiasing at small sizes) is Courier New.

This is an enhancement request to support/allow font antialiasing in the Motif look & feel. This thread on the Oracle site gives some hints on how that might be possible: Anti-Aliasing Text in Motif Look and Feel

M-a-r-k commented 2 years ago

I managed to get anti-aliased text with the Motif look & feel! Here's how. It's a bit quick-and-dirty; there must be a nicer way to achieve this. But it works.

You need to add this line to Ghidra/RuntimeScripts/Common/support/launch.properties:

VMARGS=--add-exports java.desktop/sun.swing=ALL-UNNAMED

You could also add one of these if you want a different antialiasing method to the Windows default:

# Grayscale
VMARGS=-Dawt.useSystemAAFontSettings=gasp
# LCD (HRGB)
VMARGS=-Dawt.useSystemAAFontSettings=lcd

Add a line to Ghidra/Framework/Docking/build.gradle:

ext.addExports([
    'java.desktop/sun.awt=ALL-UNNAMED',
    'java.desktop/sun.awt.image=ALL-UNNAMED',
    'java.desktop/sun.swing=ALL-UNNAMED'        // <-- Add this line
])

In Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/DockingWindowsLookAndFeelUtils.java:

import sun.swing.SwingUtilities2;
...
/**
 * Fixes issues in the currently running look and feel.
 */
private static void fixupLookAndFeelIssues() {
    LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
    UIDefaults defaults = UIManager.getDefaults();
    switch (lookAndFeel.getName()) {
        case NIMBUS_LOOK_AND_FEEL:
            // fix scroll bar grabber disappearing.  See https://bugs.openjdk.java.net/browse/JDK-8134828
            // This fix looks like it should not cause harm even if the bug is fixed on the jdk side.
            defaults.put("ScrollBar.minimumThumbSize", new Dimension(30, 30));

            // (see NimbusDefaults for key values that can be changed here)
            break;
        default:
            SwingUtilities2.putAATextInfo(true, defaults);
            break;
    }
}

That could/should be adjusted to only call SwingUtilities2.putAATextInfo() for the Motif theme. But probably all other look & feels do that themselves anyway.

By the way, it looks like the Nimbus scroll bar issue was fixed in 2015 so that could probably be removed from Ghidra source.

Ghidra_Motif_aa
M-a-r-k commented 2 years ago

I noticed something strange after building with the changes described above.

Size of build/dist zip created by gradle buildGhidra from unmodified source: 344,520,116 bytes Making the above changes and doing gradle buildGhidra again gave a build/dist zip file size of 312,684,129 bytes!

ryanmkurtz commented 2 years ago

What happens if you build unmodified source, and then without making any changes, do another gradle buildGhidra?

M-a-r-k commented 2 years ago

This is strange. Maybe there's some quirk with the build process, independent from this issue? It doesn't add all needed files in the build/dist zip archive in some cases? But the with-changes build did always have a lower .zip file size (~312MB vs ~344MB).

Building unmodified source, deleting the build/dist zip, and building again resulted in a new build/dist zip size of <20MB!

I tried these steps: (In a new directory, unzip ghidra-master.zip as downloaded from github on 2021-12-24.)

gradle -I gradle/support/fetchDependencies.gradle init gradle buildGhidra (build/dist zip size: 344,521,098 bytes) (delete the build/dist zip archive) gradle buildGhidra (new build/dist zip size: 19,617,513 bytes!)

gradle clean gradle buildGhidra (build/dist zip size: 344,519,002 bytes)

gradle clean (make code changes described above to allow antialiased text) gradle buildGhidra (build/dist zip size: 312,683,847 bytes)

(delete the build/dist zip archive) gradle buildGhidra (build/dist zip size: 19,617,514 bytes!) (Leave that too-small zip file, don't delete it.) gradle buildGhidra (build/dist zip size: 312,683,879) (delete the build/dist zip) gradle buildGhidra (build/dist zip size: 19,617,514 bytes!) (Leave that too-small zip file, don't delete it.) gradle buildGhidra (build/dist zip size: 312,683,878)

gradle clean gradle buildGhidra (build/dist zip size: 312,683,948)

(Now start with a new directory, unzip ghidra-master.zip to it and make above code changes before anything else.) gradle -I gradle/support/fetchDependencies.gradle init gradle buildGhidra (build/dist zip size: 312,684,032) gradle buildGhidra (build/dist zip size: 19,617,529) gradle buildGhidra (build/dist zip size: 312,684,061) gradle buildGhidra (build/dist zip size: 19,617,534) gradle buildGhidra (build/dist zip size: 312,684,060)

The built .zip size alternates between completely broken (~19MB) and probably-OK on successive invocations of gradle buildGhidra.

By the way, I'm using Gradle 7.3.3, Visual Studio 2022, JDK zulu18.0.65-ea-jdk18.0.0-ea.28-win_x64

ryanmkurtz commented 2 years ago

I'm able to reproduce this. I've seen this happen before with gradle prepDev deleting files every other run, so this is probably related. I'll investigate. Would you mind making a new ticket for this, since it's unrelated to antialiased text?

M-a-r-k commented 2 years ago

Sure, I'll do that tomorrow.

M-a-r-k commented 1 year ago

Playing around with github I created a pull request which should hopefully make the changes I outlined above.

M-a-r-k commented 1 year ago

A possible "legal" way to achieve this may be given in this StackOverflow post. It does look like way more work though...

dragonmacher commented 1 year ago

That post seems to imply setting it on a per-component basis, which does not scale.

In reading this ticket from the beginning, is it safe to assume that if we had a dark theme, you would no longer need to use Motif? If so, then a better solution should be forthcoming.

M-a-r-k commented 1 year ago

I like the old-school look so would probably stick with Motif (with the change to allow antialiased text), or the Steel variant of the Metal look & feel. :)