2

I've run up on a really frustrating problem involving OS X and Java Swing GUIs; specifically I'm having a problem with Cocoa Compatibility mode.

I work at a robotics lab, and a great deal of our software is run through an in-house simulation suite. The code for this simulation suite is nearly 10 years old and was created by one of our head researchers while he was in college. The simulation runs in a Swing GUI. The simulations all run fine on Linux and Windows computers, but they don't run on OS X.

To be clear, the code I am writing is not GUI code. I'm not a "GUI Guy". The code he wrote however long ago provides an API for quickly creating simulations to model robots based on standard mechanical systems of joints and links, and these simulations appear with a GUI to facilitate operations such as starting, stopping, recording, playing back, tracking variables, creating plots, etc. So I'm not invoking any Swing code directly; this is all "bog standard" (to our situation) stuff that every single one of our simulations uses. And every single one crashes on OS X while running just fine under Windows and Linux.

I've poked around the internet, and while I haven't been able to find a solution to my issue, the root of the problem seems to be that Cocoa Compatibility Mode expects the programmer to adhere to strict threading guidelines for graphical interfaces. The one example that seems to pop up the most is that if you don't thread your GUI using SwingUtilities.invokeLater() then your code will be unstable. The guy who wrote the code acknowledges that he did not adhere to the best possible threading practices when he originally created the API.

Cocoa Compatibility Mode also seems to enforce some sort of timeout for some kind of Swing operation, not quite sure what it is, but I'm on a 2011 MacBook Pro with a 2.3 GHz quad core i7, 8 gigs of RAM, an SSD, and a 1 gig Radeon 6750M. I'd like to think I'm not running up on a time-out of some sort.

We develop in Eclipse, and launch our sims from Eclipse as well (we have no need to turn them in to executables of any form). When a simulation is launched, the GUI appears and is fully populated. However, it cannot be interacted with. Even the "traffic lights" never activate, so the only way to kill the GUI is by using the terminate button in Eclipse.

Here is a screenshot of what the console looks like. I'm not at Cocoa developer so the errors themselves don't mean too much to me, but I know that the NS prefix means that the errors are coming from Cocoa and I understand that what appears to be happening is that some sort of thread manager (Grand Central Dispatch maybe?) is attempting to act on null lock objects and at some point or another there's an issue with a thread pool.

From what I've gathered there is no way to currently disable Cocoa Compatibility Mode (it seems there used to be by using an Apple specific java system property, but that property no longer appears on the list of valid System Properties provided on the Apple Developer web site). I also tried using the -XstartOnFirstThread argument to no avail. While we are primarily Linux and Windows driven in our lab, our organization is large and a different group wants to start using some of the simulations we've created for their projects and this division is a primarily Mac using division (I'm also an OS X user myself and so I'd like to continue working off of my MBP).

Can anyone out there tell me if there is a way to disable Cocoa compatibility mode or at the very least if my suspicions are correct re: what's causing the errors? We're not a bureaucracy and our boss knows that the code has errors so if my hunch is correct then performing a gut and a rewrite isn't out of the question like it would be at a large corporation. The simulations have no stability issues on other OSes as I have already stated, and a lot of the stability issues stemming from the restrictions of OS X seem to be related to providing an enjoyable user experience, which we don't really care about because this isn't a user-facing product. It isn't a product at all.

I'm not looking for comments or answers that talk to me about UX/UIX, non-blocking UI's, or best practices in threading/UI design. These are all things that I'm familiar with, and these are all things that my boss is more than familiar with as well. I just want someone to either help me eliminate the restrictions that OS X is arbitrarily placing on our Java code, or someone who can point me in the right direction so that we can get our current code in line with the OS's restrictions.

I'm using the most up-to-date JVM/JDK available for OS X, the most up-to-date OS X dev tools, and the most up-to-date version of Snow Leopard.

EDIT: Here's a Gist that is self-contained and compiles. It is completely unresponsive, like above, and while it doesn't have all the null lock errors, it does have the autorelease errors and doesn't work on OS X.

Doug Stephen
  • 7,181
  • 1
  • 38
  • 46
  • Does your application use [`com.apple.eawt.CocoaComponent`](http://developer.apple.com/library/mac/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/CocoaComponent.html) as well as Swing? – trashgod Jun 22 '11 at 22:12
  • An [sscce](http://sscce.org/) that reproduces the problem might help clarify things. – trashgod Jun 22 '11 at 22:13
  • @trashgod no we don't use CocoaComponents, this code was not made for OS X, and was created well over 10 years ago. I'd imagine that if it did use those things it probably wouldn't run on Windows or Linux like it does now. – Doug Stephen Jun 22 '11 at 22:16
  • Also, it would make absolutely no sense to post a code snippet, as that would basically involve posting the entire massive API since all of the Swing code is in the API. I'm not going to put our lab's entire codebase up on SO. – Doug Stephen Jun 22 '11 at 22:17
  • I agree completely, a snippet would be useless; an [sscce](http://sscce.org/) might help, but reliably incorrect threading is usually obvious. I write lots of cross-platform Swing on Mac OS, and I've had to chase these things down in legacy code more than once. Mac OS may expose the problem, but that's coincidental. I empathize, but I don't see how to answer this question in its present form. – trashgod Jun 22 '11 at 22:27
  • I know it's not an easy problem to figure out in its current form. When I say snippet I really mean self-contained example, but the same applies. As I said in the question, I'm not actually writing any Swing code. Swing is being invoked by a large API, and the GUI has a great deal of elements to it, so there really is not small self contained example to post. Effectively, when I create a simulation object, an entire GUI with a Java3D sim environment is created on my behalf. The code has worked perfectly for 10-15 years, it's just generating the null lock errors from above on OS X. – Doug Stephen Jun 22 '11 at 22:31
  • @trashgod I've added an extremely small GUI example as a GitHub Gist up above. It's a JFrame with a slider, Text Field, and Label, all of which do absolutely nothing. ALL of the code was created using the version of WindowBuilder that just started packaging itself with Eclipse 3.7 Indigo. I don't get the null lock errors, but I do get the same unresponsive behavior and the same AutoRelease errors. – Doug Stephen Jun 23 '11 at 22:46

2 Answers2

2

I was facing the same problems (on the same macbook configuration) and found a bug description here.

First, I installed openjdk 7 on OSX:

I altered my project build path in eclipse to point to the newly installed jdk.1.7.0u (on my Mac: /Library/Java/JavaVirtualMachines/1.7.0u.jdk/Contents/Home/) and had no UI freezing anymore.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
Math
  • 36
  • 3
  • I'm going to toy around with this, but a lot of our internal libraries rely on code that is considered legacy by the OpenJDK groups and was not implemented in OpenJDK (ex: com.sun.image.codec.jpeg) so we aren't supposed to use OpenJDK implementations on our development machines. Because all of our code has to build against Real Time Java for the robots, this isn't an issue since the RT Java spec builds against 1.5 system libraries and we can still get 1.5 and 1.6 Sun/Oracle JDK's for Linux. I'll see what I can do with this though. Thanks for the tip. – Doug Stephen Feb 02 '12 at 17:48
  • This definitely makes Swing/AWT work under Lion. Still gotta resolve the dependency on Sun code in our stuff at the lab, but thanks for the suggestion. – Doug Stephen Feb 05 '12 at 20:06
1

Apart from a missing trailing brace, your example and the variation below operate as expected on Mac OS 10.5.8 using Java 1.6.0_24. In particular, mouse, keyboard and focus all appear normal. Note that JFrame forwards add() and setLayout() (among others) to the content pane. I'm just not used to replacing the content pane.

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class FrameExample2 extends JFrame {

    private JPanel panel = new JPanel();
    private JTextField xAccelTextField = new JTextField(10);
    private JSlider xAccelSlider = new JSlider();

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    FrameExample2 frame = new FrameExample2();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace(System.out);
                }
            }
        });
    }

    public FrameExample2() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        panel.setLayout(new GridLayout(0, 1));
        panel.setBorder(BorderFactory.createLineBorder(Color.gray, 8));
        panel.add(new JLabel("Linear Acceleration along X", JLabel.CENTER));
        panel.add(xAccelSlider);
        xAccelTextField.setEditable(false);
        xAccelTextField.setText("0");
        panel.add(xAccelTextField);
        xAccelTextField.setColumns(10);
        this.add(panel);
        this.pack();
        this.setLocationRelativeTo(null);
        xAccelSlider.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                xAccelTextField.setText(
                    String.valueOf(xAccelSlider.getValue()));
            }
        });
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • The fact that it works on Leopard makes me think that the issue is with the 64-bit JVM. I'll try using -d32 and see if it runs. – Doug Stephen Jun 24 '11 at 01:12
  • Sorry to report negative findings. You might look for adventitious JARs, as mentioned [here](http://stackoverflow.com/questions/3432051/problems-with-java-installation-xerces-on-mac/3432254#3432254). – trashgod Jun 24 '11 at 01:14
  • 32 bit JVM didn't help. Sigh. Thanks for the help though. – Doug Stephen Jun 24 '11 at 01:22
  • Yeah, I'm at a loss. Obviously Swing works on OS X, or Eclipse itself wouldn't launch. And this is a problem that a lot of people seem to have from searching around SO. But nobody has an answer for it. I'm thinking that it's something really silly like a missing native library. – Doug Stephen Jun 24 '11 at 01:26
  • Runs fine from both NetBeans and Eclipse. Note Eclipse uses SWT, not Swing. – trashgod Jun 24 '11 at 01:35
  • Is eclipse not built with SWT? – dominic Mar 14 '16 at 00:35