Max + SWT: Threading issue
Having a hard time getting Max to work with JavaSWT. Does anyone have any experience with this? Both Max and SWT are forced to share the same UI thread. SWT goes to sleep when waiting for events, which hangs Max.
Error:
***WARNING: Display must be created on main thread due to Cocoa restrictions.
Exception in thread "AWT-EventQueue-0" org.eclipse.swt.SWTException: Invalid thread access
I've done a bunch of searches on these errors and haven't found a solution specific to using SWT with Max.
OSX 10.6.7
SWT 3.6
Max 5.1.8
I've encountered this in another situation (Forth/OpenGL), but I'm sure someone here has direct experience with Java and a better answer.
Parts of Cocoa aren't thread safe, and so the Cocoa UI has to run in the main thread. So something about what you're coding has got a run loop (I think) going in another thread.
Linux, for example, doesn't care at all about this, so if you've ported code that worked there, maybe that's the issue.
A fix for this can be really difficult. Especially if it's inside SWT and not in your code.
HTH, Charles
I have spent quite a bit of time trying to understand the scenario, and I believe it is the SWT dispatch loop doesn't work along side with Max dispatch loop. For any cocoa interaction code must execute in the main thread. So either the SWT dispatch code is running or the max dispatching code. What we see is if we don't have the following template code, our SWT application doesn't receive any events (it appears non-responsive). The following is the common example of SWT dispatching code.
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
Using the above code in the main java thread (APP-KIT) causes us to exclusively remain in java, and never return this thread back to MAXMSP. What we see is the SWT window is fully responsive, and works perfectly, but our Max requests are not handled. I suspect they are queuing up within MaxMSP. We aren't returning control of the main thread to Max, so no one is working on those events.
It took a while, but we figured out a very HACKY workaround. We put the above code into a thread that MaxSystem.deferLow(), and if there isn't any SWT work, we re-queue ourselves deferLow() and continue into MaxMSP. At the sametime, we have a 'Waker' thread, that forces us to come out of display.sleep() every 50ms, to ensure we do not sleep forever. So we are sharing the event handling with SWT and MaxMSP.
PROBLEM IS: it makes the ui somewhat unresponsive. Some mouse events are lost. 95% of keystrokes targeted to MaxMSP are ignored. So this hack doesn't really work.
I am hoping there is a MaxMSP expert who can help us out. Here is the sample code and patch we wrote to understand and "workaround" the problem
The basic example works like this:
- Create an SWT Display object.
- Create a new Thread, and execute it.
- In the execution loop, put the thread to sleep for a very short period of time (ex; 50 ms). When it wakes, send a wake command to the Display, which is most likely put to sleep by a Dispatcher.
- meanwhile, place a Dispatcher object on the Max thread using deferLow and pass in the Display. The Dispatcher, on execute(), checks to see if there is anything in the queue for the Display thread. If there isn't, it puts Display to sleep. When it awakens, it checks to see if there is anything in the queue for the Display thread. If there isn't, it puts itself on the queue.
Try searching for "swing" in the forum. Most of the good threads are 3 or more years old.
Also, there may be some interesting information on the JMSL site:
HTH, Charles