RFR: 8155030: The Menu Mnemonics are always displayed for GTK LAF [v9]
Alexey Ivanov
aivanov at openjdk.org
Thu Jun 27 17:31:56 UTC 2024
On Thu, 27 Jun 2024 10:06:49 GMT, Abhishek Kumar <abhiscxk at openjdk.org> wrote:
>> In GTK LAF, the menu mnemonics are always displayed which is different from the native behavior. In native application **(tested with gedit for normal buttons and tested with libreoffice for menu**), the menu mnemonics toggle on press of `ALT` key. Menu mnemonics are hidden initially and then toggles between show/hide on `ALT` press.
>> Proposed fix is to handle the `ALT` key press for GTK LAF and mimic the native behavior. Fix is similar to the `ALT` key processing in Windows LAF. Automated test case is added to verify the fix and tested in Ubuntu and Oracle linux.
>>
>> CI testing is green and link attached in JBS.
>
> Abhishek Kumar has updated the pull request incrementally with two additional commits since the last revision:
>
> - Mnemonic handler class
> - Mnemonic handler added and previous implementation revert back
I think we're moving in the right direction.
My idea was to extract the common functionality as the methods `setMnemonicHidden`, `isMnemonicHidden` and `repaintMnemonicsInWindow`, `repaintMnemonicsInContainer` into a helper class.
`AltProcessor`… Your version for GTK and the version in Aqua look the same to me. I think it makes sense to create a common `AltProcessor` class which would be used by GTK and Aqua.
The Windows version is different, so it'll stay this way… It doesn't look worth trying to fit that version into a shared class.
src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java line 1461:
> 1459:
> 1460: KeyboardFocusManager.getCurrentKeyboardFocusManager().
> 1461: addKeyEventPostProcessor(MnemonicHandler.altProcessor);
Suggestion:
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventPostProcessor(MnemonicHandler.altProcessor);
Better wrap the line before the dot operator — this conveys that it's a continuation of a call sequence rather than a wrapped parameter to a method.
src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java line 1469:
> 1467: /**
> 1468: * Called by UIManager when this look and feel is uninstalled.
> 1469: */
Does it repeat the javadoc of the super class? Likely it does, use `{@inheritDoc}` instead.
src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java line 1470:
> 1468: * Called by UIManager when this look and feel is uninstalled.
> 1469: */
> 1470: @Override
You may want to add the `@Override` annotation to `initialize` method too… for consistency.
src/java.desktop/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java line 672:
> 670: int mnemIndex = lh.getMenuItem().getDisplayedMnemonicIndex();
> 671: // Check to see if the Mnemonic should be rendered in GTK.
> 672: if (mnemIndex >= 0 && MnemonicHandler.isMnemonicHidden()) {
Is 0 a valid mnemonic? Probably not.
src/java.desktop/share/classes/sun/swing/MnemonicHandler.java line 40:
> 38: import javax.swing.UIManager;
> 39:
> 40: public class MnemonicHandler {
Suggestion:
public final class MnemonicHandler {
It's an utility class that should not be extended. In addition to that, it should have a private constructor to prevent instantiating the class.
src/java.desktop/share/classes/sun/swing/MnemonicHandler.java line 41:
> 39:
> 40: public class MnemonicHandler {
> 41: public static final AltProcessor altProcessor = new AltProcessor();
I'd like to see `AltProcessor` here but it's different for Windows. Thus, `AltProcessor` should be local to `*RootUI` as it is now.
If `AltProcessor` in GTK and Aqua are similar or the same, it makes sense to extract them into a common helper class.
src/java.desktop/share/classes/sun/swing/MnemonicHandler.java line 43:
> 41: public static final AltProcessor altProcessor = new AltProcessor();
> 42:
> 43: protected static boolean isMnemonicHidden;
Suggestion:
private static boolean isMnemonicHidden;
It's accessed via `isMnemonicHidden` and `setMnemonicHidden`; since the class cannot be extended, it should not have protected members.
src/java.desktop/share/classes/sun/swing/MnemonicHandler.java line 103:
> 101: * Repaints all the components with the mnemonics in the given window and all its owned windows.
> 102: */
> 103: static void repaintMnemonicsInWindow(final Window w) {
Suggestion:
public static void repaintMnemonicsInWindow(final Window w) {
This method would be called from `AltProcessor` class in the three different L&Fs, it should be `public`.
src/java.desktop/share/classes/sun/swing/MnemonicHandler.java line 120:
> 118: * Recursively searches for all the subcomponents.
> 119: */
> 120: static void repaintMnemonicsInContainer(final Container cont) {
If `repaintMnemonicsInContainer` is never called directly but only from `repaintMnemonicsInWindow` above, the method should be `private`.
src/java.desktop/share/classes/sun/swing/MnemonicHandler.java line 131:
> 129: c.repaint();
> 130: continue;
> 131: } else if (c instanceof Container) {
`continue` is redundant if you chain `if` block with `else if`.
If you remove `continue` from the first `if` block, it becomes empty, which isn't good. I suggest moving the first block into its own `if` statement:
if (c == null || !c.isVisible()) {
continue;
}
if (/* other conditions */) {
You can use pattern matching to avoid explicit cast. Are we planning to backporting this change to JDK 11? If not, I'd go for pattern matching:
if (c instanceof AbstractButton b && b.getMnemonic() != '\0') {
c.repaint();
}
Likely, the condition can be simplified further: the button and the label cases have the same body, and thus the two conditions can be combined into one condition.
-------------
Changes requested by aivanov (Reviewer).
PR Review: https://git.openjdk.org/jdk/pull/18992#pullrequestreview-2145923809
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657452729
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657450301
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657450931
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657448791
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657454306
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657457592
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657459171
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657461663
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657462542
PR Review Comment: https://git.openjdk.org/jdk/pull/18992#discussion_r1657470679
More information about the client-libs-dev
mailing list