OK, I've discovered the problem and propose a solution.

BACKGROUND -- How Jmol waits
--------------------------------------

At the beginning of every script and at key points (moveTo, delay, 
refresh, for example) a repaintManager.requestRepaintAndWait() is 
carried out:

class RepaintManager:

  synchronized void requestRepaintAndWait() {
    viewer.awtComponent.repaint();
    try {
      wait();
    } catch (InterruptedException e) {
    }
  }

If I understand this correctly, this is simply a way to trigger the 
repaint event from the OS. The event queue thread runs the app/applet 
paint() event, which starts the rendering. After rendering, the last 
thing Viewer.renderScreenImage() does is call repaintManager.repaintView():

class RepaintManager:

  synchronized void repaintView() {
    repaintPending = false;
    notify(); // to cancel any wait
  }

OK, so the function of that notify() is to restart the thread that is 
waiting in requestRepaintAndWait(). The notify() terminates the wait().

THE PROBLEM - using the wrong thread
------------------------------------------

The problem is this. If you execute

  viewer.scriptWait()

from a user event, then the thread that is running it is the event queue 
thread, because it is that same thread that does all the event handling. 
So it is the event queue thread that is waiting. Ah, but if the event 
queue thread is waiting, the event queue thread cannot produce the 
trigger that will ultimately deliver the notify(), and the ship is sunk.

THE SOLUTION - use a different thread
------------------------------------------

In the Jmol application code that I just committed what I did is to have 
the button action listener NOT execute executeCommand(), which calls 
scriptWait(). Rather, the button action listener just starts a new 
thread of the class ExecutionCommandThread. It is THIS thread then that 
waits. The event queue thread goes on its merry way. Here's my code. 
executeCommmandAsThread() is called by the button action listener.

class ScriptWindow:

  ExecuteCommandThread execThread;

  void executeCommandAsThread(){
    String strCommand = console.getCommandString().trim();
    if (strCommand.length() > 0) {
      execThread = new ExecuteCommandThread(strCommand);
      execThread.start();
    }
  }

  class ExecuteCommandThread extends Thread {

    String strCommand;
    ExecuteCommandThread (String command) {
      strCommand = command;
    }
   
    public void run() {
      try {
        executeCommand(strCommand);
      } catch (Exception ie) {
        Logger.debug("execution command interrupted!"+ie);
      }
    }
  }

There's proabably a more elegant way of doing this, but for now that's 
how it works.

SO: If you want to use scriptWait():

1) first, I recommend instead a new method I've added,

  Object Viewer.scriptWaitStatus(String returnType, String script, 
String statusList)

What this function does is to run the script, and follow whatever status 
information you might be interested in knowing about.
These are the items listed at 
http://www.stolaf.edu/people/hansonr/jmol/docs/?ver=11.0#statusreporting
The returnType parameter is one of "JSON", "String", "readable", or 
"object". What would be interesting to this crowd is "object"
because it returns a Vector of Vectors of Vectors:

         * info = [ statusRecortSet0, statusRecortSet1, 
statusRecortSet2, ...]
         * statusRecordSet = [ statusRecord0, statusRecord1, 
statusRecord2, ...]
         * statusRecord = [int msgPtr, String statusName, int intInfo, 
String msg]   

This allows for parsing of the different record types independently, and 
sorting them overall if desired (on the msgPtr).

2) Just make sure that the thread that is using scriptWait() is NOT the 
event queue thread. Basically, start a new thread with any response to a 
user event. Or set up a running event queue thread that processes the 
commands in order of appearance if they are coming from a user. (This is 
probably what we should do for the applet as well.)

Comments?

Bob


Andreas Prlic wrote:

>>If others can suggest the "right" way to do this, that would be 
>>welcome.
>>How is this sort of thing supposed to be handled?
>>    
>>
>
>hm. this is not easy....
>   - but I would be very interested in getting this fixed and would be 
>willing to help ...
>
>I guess all the Evals should go through a common queue ...
>
>Andreas
>
>-----------------------------------------------------------------------
>
>Andreas Prlic      Wellcome Trust Sanger Institute
>                               Hinxton, Cambridge CB10 1SA, UK
>                        +44 (0) 1223 49 6891
>
>
>-------------------------------------------------------------------------
>Take Surveys. Earn Cash. Influence the Future of IT
>Join SourceForge.net's Techsay panel and you'll get the chance to share your
>opinions on IT & business topics through brief surveys -- and earn cash
>http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
>_______________________________________________
>Jmol-developers mailing list
>[email protected]
>https://lists.sourceforge.net/lists/listinfo/jmol-developers
>  
>


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Jmol-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jmol-developers

Reply via email to