diff --git a/app/PdeEditorConsole.java b/app/PdeEditorConsole.java index f64ab0ff1..6788e6eb9 100644 --- a/app/PdeEditorConsole.java +++ b/app/PdeEditorConsole.java @@ -17,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -29,8 +29,8 @@ import javax.swing.*; import javax.swing.text.*; -// debugging this class is tricky.. if it's throwing -// exceptions, don't take over System.err, and debug +// debugging this class is tricky.. if it's throwing +// exceptions, don't take over System.err, and debug // while watching just System.out // or just write directly to systemOut or systemErr @@ -99,7 +99,7 @@ public class PdeEditorConsole extends JScrollPane { // add the jtextpane to this scrollpane this.setViewportView(consoleTextPane); - // calculate height of a line of text in pixels + // calculate height of a line of text in pixels // and size window accordingly FontMetrics metrics = this.getFontMetrics(font); int height = metrics.getAscent() + metrics.getDescent(); @@ -124,13 +124,13 @@ public class PdeEditorConsole extends JScrollPane { } } catch (IOException e) { PdeBase.showWarning("Console Error", - "A problem occurred while trying to open the\n" + + "A problem occurred while trying to open the\n" + "files used to store the console output.", e); } - consoleOut = + consoleOut = new PrintStream(new PdeEditorConsoleStream(this, false, stdoutFile)); - consoleErr = + consoleErr = new PrintStream(new PdeEditorConsoleStream(this, true, stderrFile)); if (PdePreferences.getBoolean("console")) { @@ -143,7 +143,7 @@ public class PdeEditorConsole extends JScrollPane { } } - // to fix ugliness.. normally macosx java 1.3 puts an + // to fix ugliness.. normally macosx java 1.3 puts an // ugly white border around this object, so turn it off. if (PdeBase.platform == PdeBase.MACOSX) { setBorder(null); @@ -200,45 +200,64 @@ public class PdeEditorConsole extends JScrollPane { } - synchronized private void appendText(String text, boolean err) { - //if (true) return; + /** + * append a piece of text to the console. + * + * Swing components are NOT thread-safe, and since the PdeMessageSiphon + * instantiates new threads, and in those callbacks, they often print + * output to stdout and stderr, which are wrapped by PdeEditorConsoleStream + * and eventually leads to PdeEditorConsole.appendText(), which directly + * updates the Swing text components, causing deadlock. + * + * A quick hack from Francis Li (who found this to be a problem) + * wraps the contents of appendText() into a Runnable and uses + * SwingUtilities.invokeLater() to ensure that the updates only + * occur on the main event dispatching thread, and that appears + * to have solved the problem. + */ + synchronized private void appendText(String txt, boolean e) { + final String text = txt; + final boolean err = e; + SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + // check how many lines have been used so far + // if too many, shave off a few lines from the beginning + Element element = consoleDoc.getDefaultRootElement(); + int lineCount = element.getElementCount(); + int overage = lineCount - maxLineCount; + if (overage > 0) { + // if 1200 lines, and 1000 lines is max, + // find the position of the end of the 200th line + //systemOut.println("overage is " + overage); + Element lineElement = element.getElement(overage); + if (lineElement == null) return; // do nuthin - try { - // check how many lines have been used so far - // if too many, shave off a few lines from the beginning - Element element = consoleDoc.getDefaultRootElement(); - int lineCount = element.getElementCount(); - int overage = lineCount - maxLineCount; - if (overage > 0) { - // if 1200 lines, and 1000 lines is max, - // find the position of the end of the 200th line - //systemOut.println("overage is " + overage); - Element lineElement = element.getElement(overage); - if (lineElement == null) return; // do nuthin + int endOffset = lineElement.getEndOffset(); + // remove to the end of the 200th line + consoleDoc.remove(0, endOffset); + } - int endOffset = lineElement.getEndOffset(); - // remove to the end of the 200th line - consoleDoc.remove(0, endOffset); - } + // add the text to the end of the console, + consoleDoc.insertString(consoleDoc.getLength(), text, + err ? errStyle : stdStyle); - // add the text to the end of the console, - consoleDoc.insertString(consoleDoc.getLength(), text, - err ? errStyle : stdStyle); + // always move to the end of the text as it's added + consoleTextPane.setCaretPosition(consoleDoc.getLength()); - // always move to the end of the text as it's added - consoleTextPane.setCaretPosition(consoleDoc.getLength()); - - } catch (BadLocationException e) { - // ignore the error otherwise this will cause an infinite loop - // maybe not a good idea in the long run? - } + } catch (BadLocationException e) { + // ignore the error otherwise this will cause an infinite loop + // maybe not a good idea in the long run? + } + } + }); } public void clear() { try { consoleDoc.remove(0, consoleDoc.getLength()); - } catch (BadLocationException e) { + } catch (BadLocationException e) { // ignore the error otherwise this will cause an infinite loop // maybe not a good idea in the long run? } @@ -252,7 +271,7 @@ class PdeEditorConsoleStream extends OutputStream { byte single[] = new byte[1]; OutputStream echo; - public PdeEditorConsoleStream(PdeEditorConsole parent, + public PdeEditorConsoleStream(PdeEditorConsole parent, boolean err, OutputStream echo) { this.parent = parent; this.err = err;