Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Java for OS X 2013-004 affect (break) Swing applications?

It seems like Java for OS X 2013-004 (Java 1.6.0_51) breaks some Swing applications: https://discussions.apple.com/message/22279872?tstart=0#22279872?tstart=0 http://www.mathworks.com/matlabcentral/answers/79489

My app loads, but it doesn't repaint normally. Clicking on buttons and other operations actually seem to work, but the display only gets updated if the frame is resized - really bizarre.

Does anyone have any idea what the problem could be?

Edit: Seems like Apple fixed it: http://lists.apple.com/archives/java-dev/2013/Jun/msg00055.html

like image 742
Peter Tseng Avatar asked Mar 24 '23 12:03

Peter Tseng


1 Answers

Update 2013-06-21: this answer contains some workarounds and alternatives that may be useful, but @sidney-markowitz-biomatters' answer contains the correct code fix - the LAF needs to be set from the event thread!

The recent problems seem to be related to the updates breaking the Aqua Look and Feel (LAF), which is the default for Swing apps on Mac OS X.

If you need the Aqua LAF then there are not too many options. You might need to wait for the next Java update from Apple (I'm assuming they will fix this with priority, given it's their own LAF). You could also try using the Java Application Bundler (i.e. bundle the Oracle JRE and avoid using the system's JRE).

If you can get by with a different LAF then your app should work as normal. It did for PaperCut, at least (the 003 update caused some window focus problems, the 004 update caused mayhem).

Some options:

  • Using the Java version-specific cross platform LAF from Java code (e.g. Nimbus or Metal):

    UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName())
    
  • Setting a specific LAF from Java code:

    UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel")
    
  • Overriding the default LAF from terminal:

    java -Dswing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel MyApp
    

In our case we were explicitly calling UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) in our code and wanted a workaround that didn't involve a code change (i.e. a hotfix), so we needed to override the default system LAF as follows.

  • Overriding the system LAF from terminal:

    java -Dswing.systemlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel ...
    
  • Overriding the system LAF from an Info.plist file (if you have bundled as a Mac application, also works for the other VM options) (e.g. at My.app/Contents/Info.plist).

    You want to add -Dswing.systemlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel to the end of the <string> value for the VMOptions <key>. The options are space separated, just like from the terminal. E.g. if you already have a useScreenMenuBar option:

    <key>VMOptions</key>
    <string>-Dcom.apple.macos.useScreenMenuBar=true -Dswing.systemlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel</string>
    


Edit: @trashgod asked for a reproducible example. I'm not sure what the full scope of the problems with the 004 update are, but here's a simple reproduction:

Update 2013-06-21 - the wrong way, reproducing the error:

public class AquaLafTest {
    public static void main(String[] args) throws Exception {
        javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
        javax.swing.JOptionPane.showMessageDialog(null, "msg");
    }
}
  1. Run with the Apple JRE that comes with the 004 update (e.g. at /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home). Observe that the message is not visible, the dialog icon is not visible and the button is not visibly clickable.

  2. Run with an older Apple JRE or another JRE. Observe that the dialog displays as expected.

Update 2013-06-21 - the right way, on the event thread, works correctly:

public class AquaLafTest {
    public static void main(String[] args) throws Exception {
        javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                try {
                    javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
                    javax.swing.JOptionPane.showMessageDialog(null, "msg");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
like image 178
Tom Clift Avatar answered Apr 05 '23 16:04

Tom Clift