Skip to content

Commit f183966

Browse files
author
Federico Fissore
committed
Added GTKLookAndFeelFixer, courtesy Klaus Reimer
https://www.ailis.de/~k/archives/67-Workaround-for-borderless-Java-Swing-menus-on-Linux.html It makes menu separators visible on linux with the GTK look and feel
1 parent 36079ef commit f183966

File tree

2 files changed

+155
-12
lines changed

2 files changed

+155
-12
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
* This file is part of Arduino.
3+
*
4+
* Arduino is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
*
18+
* As a special exception, you may use this file as part of a free software
19+
* library without restriction. Specifically, if other files instantiate
20+
* templates or use macros or inline functions from this file, or you compile
21+
* this file and link it with other files to produce an executable, this
22+
* file does not by itself cause the resulting executable to be covered by
23+
* the GNU General Public License. This exception does not however
24+
* invalidate any other reasons why the executable file might be covered by
25+
* the GNU General Public License.
26+
*
27+
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
28+
*/
29+
30+
package processing.app.linux;
31+
32+
import javax.swing.*;
33+
import java.lang.reflect.Field;
34+
import java.lang.reflect.Method;
35+
36+
public class GTKLookAndFeelFixer {
37+
38+
/*
39+
* All functions of this class courtesy of Klaus Reimer
40+
* https://www.ailis.de/~k/archives/67-Workaround-for-borderless-Java-Swing-menus-on-Linux.html
41+
*/
42+
43+
/*
44+
* This is free and unencumbered software released into the public domain.
45+
*
46+
* Anyone is free to copy, modify, publish, use, compile, sell, or
47+
* distribute this software, either in source code form or as a compiled
48+
* binary, for any purpose, commercial or non-commercial, and by any
49+
* means.
50+
*
51+
* In jurisdictions that recognize copyright laws, the author or authors
52+
* of this software dedicate any and all copyright interest in the
53+
* software to the public domain. We make this dedication for the benefit
54+
* of the public at large and to the detriment of our heirs and
55+
* successors. We intend this dedication to be an overt act of
56+
* relinquishment in perpetuity of all present and future rights to this
57+
* software under copyright law.
58+
*
59+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
60+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
61+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
62+
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
63+
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
64+
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
65+
* OTHER DEALINGS IN THE SOFTWARE.
66+
*
67+
* For more information, please refer to <http://unlicense.org/>
68+
*/
69+
70+
/**
71+
* Swing menus are looking pretty bad on Linux when the GTK LaF is used (See
72+
* bug #6925412). It will most likely never be fixed anytime soon so this
73+
* method provides a workaround for it. It uses reflection to change the GTK
74+
* style objects of Swing so popup menu borders have a minimum thickness of
75+
* 1 and menu separators have a minimum vertical thickness of 1.
76+
*/
77+
public static void installGtkPopupBugWorkaround() {
78+
// Get current look-and-feel implementation class
79+
LookAndFeel laf = UIManager.getLookAndFeel();
80+
Class<?> lafClass = laf.getClass();
81+
82+
// Do nothing when not using the problematic LaF
83+
if (!lafClass.getName().equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel")) {
84+
return;
85+
}
86+
87+
// We do reflection from here on. Failure is silently ignored. The
88+
// workaround is simply not installed when something goes wrong here
89+
try {
90+
// Access the GTK style factory
91+
Field field = lafClass.getDeclaredField("styleFactory");
92+
boolean accessible = field.isAccessible();
93+
field.setAccessible(true);
94+
Object styleFactory = field.get(laf);
95+
field.setAccessible(accessible);
96+
97+
// Fix the horizontal and vertical thickness of popup menu style
98+
Object style = getGtkStyle(styleFactory, new JPopupMenu(), "POPUP_MENU");
99+
fixGtkThickness(style, "yThickness");
100+
fixGtkThickness(style, "xThickness");
101+
102+
// Fix the vertical thickness of the popup menu separator style
103+
style = getGtkStyle(styleFactory, new JSeparator(), "POPUP_MENU_SEPARATOR");
104+
fixGtkThickness(style, "yThickness");
105+
} catch (Exception e) {
106+
// Silently ignored. Workaround can't be applied.
107+
}
108+
}
109+
110+
/**
111+
* Called internally by installGtkPopupBugWorkaround to fix the thickness
112+
* of a GTK style field by setting it to a minimum value of 1.
113+
*
114+
* @param style The GTK style object.
115+
* @param fieldName The field name.
116+
* @throws Exception When reflection fails.
117+
*/
118+
private static void fixGtkThickness(Object style, String fieldName) throws Exception {
119+
Field field = style.getClass().getDeclaredField(fieldName);
120+
boolean accessible = field.isAccessible();
121+
field.setAccessible(true);
122+
field.setInt(style, Math.max(1, field.getInt(style)));
123+
field.setAccessible(accessible);
124+
}
125+
126+
/**
127+
* Called internally by installGtkPopupBugWorkaround. Returns a specific
128+
* GTK style object.
129+
*
130+
* @param styleFactory The GTK style factory.
131+
* @param component The target component of the style.
132+
* @param regionName The name of the target region of the style.
133+
* @return The GTK style.
134+
* @throws Exception When reflection fails.
135+
*/
136+
private static Object getGtkStyle(Object styleFactory, JComponent component, String regionName) throws Exception {
137+
// Create the region object
138+
Class<?> regionClass = Class.forName("javax.swing.plaf.synth.Region");
139+
Field field = regionClass.getField(regionName);
140+
Object region = field.get(regionClass);
141+
142+
// Get and return the style
143+
Class<?> styleFactoryClass = styleFactory.getClass();
144+
Method method = styleFactoryClass.getMethod("getStyle", JComponent.class, regionClass);
145+
boolean accessible = method.isAccessible();
146+
method.setAccessible(true);
147+
Object style = method.invoke(styleFactory, component, region);
148+
method.setAccessible(accessible);
149+
return style;
150+
}
151+
}

arduino-core/src/processing/app/linux/Platform.java

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
import processing.app.legacy.PConstants;
3030
import processing.app.tools.CollectStdOutExecutor;
3131

32-
import java.io.*;
32+
import java.io.ByteArrayOutputStream;
33+
import java.io.File;
34+
import java.io.IOException;
3335
import java.util.Map;
3436

3537

@@ -42,17 +44,7 @@ public class Platform extends processing.app.Platform {
4244
// TODO Need to be smarter here since KDE people ain't gonna like that GTK.
4345
// It may even throw a weird exception at 'em for their trouble.
4446
public void setLookAndFeel() throws Exception {
45-
// Linux is by default even uglier than metal (Motif?).
46-
// Actually, i'm using native menus, so they're even uglier
47-
// and Motif-looking (Lesstif?). Ick. Need to fix this.
48-
//String lfname = UIManager.getCrossPlatformLookAndFeelClassName();
49-
//UIManager.setLookAndFeel(lfname);
50-
51-
// For 0120, trying out the gtk+ look and feel as the default.
52-
// This is available in Java 1.4.2 and later, and it can't possibly
53-
// be any worse than Metal. (Ocean might also work, but that's for
54-
// Java 1.5, and we aren't going there yet)
55-
//UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
47+
GTKLookAndFeelFixer.installGtkPopupBugWorkaround();
5648
}
5749

5850

0 commit comments

Comments
 (0)