X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTTerminalWindow.java;h=320c67a087364aac66e4e7c5be6215de7d30224d;hb=d91ac0f5500f66bc9fa2691883e2e3ed3fe84ad7;hp=6d06fc88530f4d698c99d6dc8c5244949e0df1cc;hpb=9588c7134280341ab6e92e37d1c1d00b3756cee5;p=fanfix.git diff --git a/src/jexer/TTerminalWindow.java b/src/jexer/TTerminalWindow.java index 6d06fc8..320c67a 100644 --- a/src/jexer/TTerminalWindow.java +++ b/src/jexer/TTerminalWindow.java @@ -123,6 +123,37 @@ public class TTerminalWindow extends TScrollableWindow */ private boolean haveTimer = false; + /** + * The last seen scrollback lines. + */ + private List scrollback; + + /** + * The last seen display lines. + */ + private List display; + + /** + * If true, the display has changed and needs updating. + */ + private volatile boolean dirty = true; + + /** + * Time that the display was last updated. + */ + private long lastUpdateTime = 0; + + /** + * If true, hide the mouse after typing a keystroke. + */ + private boolean hideMouseWhenTyping = true; + + /** + * If true, the mouse should not be displayed because a keystroke was + * typed. + */ + private boolean typingHidMouse = false; + // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- // ------------------------------------------------------------------------ @@ -306,102 +337,123 @@ public class TTerminalWindow extends TScrollableWindow */ @Override public void draw() { - // Synchronize against the emulator so we don't stomp on its reader - // thread. - synchronized (emulator) { - - // Update the scroll bars - reflowData(); - - // Draw the box using my superclass - super.draw(); - - List scrollback = emulator.getScrollbackBuffer(); - List display = emulator.getDisplayBuffer(); + int width = getDisplayWidth(); + boolean syncEmulator = false; + if ((System.currentTimeMillis() - lastUpdateTime >= 25) + && (dirty == true) + ) { + // Too much time has passed, draw it all. + syncEmulator = true; + } else if (emulator.isReading() && (dirty == false)) { + // Wait until the emulator has brought more data in. + syncEmulator = false; + } else if (!emulator.isReading() && (dirty == true)) { + // The emulator won't receive more data, update the display. + syncEmulator = true; + } - // Put together the visible rows - int visibleHeight = getHeight() - 2; - int visibleBottom = scrollback.size() + display.size() - + getVerticalValue(); - assert (visibleBottom >= 0); + if ((syncEmulator == true) + || (scrollback == null) + || (display == null) + ) { + // We want to minimize the amount of time we have the emulator + // locked. Grab a copy of its display. + synchronized (emulator) { + // Update the scroll bars + reflowData(); - List preceedingBlankLines = new ArrayList(); - int visibleTop = visibleBottom - visibleHeight; - if (visibleTop < 0) { - for (int i = visibleTop; i < 0; i++) { - preceedingBlankLines.add(emulator.getBlankDisplayLine()); + if ((scrollback == null) || emulator.isReading()) { + scrollback = copyBuffer(emulator.getScrollbackBuffer()); + display = copyBuffer(emulator.getDisplayBuffer()); } - visibleTop = 0; + width = emulator.getWidth(); } - assert (visibleTop >= 0); + dirty = false; + } - List displayLines = new ArrayList(); - displayLines.addAll(scrollback); - displayLines.addAll(display); + // Draw the box using my superclass + super.draw(); - List visibleLines = new ArrayList(); - visibleLines.addAll(preceedingBlankLines); - visibleLines.addAll(displayLines.subList(visibleTop, - visibleBottom)); + // Put together the visible rows + int visibleHeight = getHeight() - 2; + int visibleBottom = scrollback.size() + display.size() + + getVerticalValue(); + assert (visibleBottom >= 0); - visibleHeight -= visibleLines.size(); - assert (visibleHeight >= 0); + List preceedingBlankLines = new ArrayList(); + int visibleTop = visibleBottom - visibleHeight; + if (visibleTop < 0) { + for (int i = visibleTop; i < 0; i++) { + preceedingBlankLines.add(emulator.getBlankDisplayLine()); + } + visibleTop = 0; + } + assert (visibleTop >= 0); + + List displayLines = new ArrayList(); + displayLines.addAll(scrollback); + displayLines.addAll(display); + + List visibleLines = new ArrayList(); + visibleLines.addAll(preceedingBlankLines); + visibleLines.addAll(displayLines.subList(visibleTop, + visibleBottom)); + + visibleHeight -= visibleLines.size(); + assert (visibleHeight >= 0); + + // Now draw the emulator screen + int row = 1; + for (DisplayLine line: visibleLines) { + int widthMax = width; + if (line.isDoubleWidth()) { + widthMax /= 2; + } + if (widthMax > getWidth() - 2) { + widthMax = getWidth() - 2; + } + for (int i = 0; i < widthMax; i++) { + Cell ch = line.charAt(i); - // Now draw the emulator screen - int row = 1; - for (DisplayLine line: visibleLines) { - int widthMax = emulator.getWidth(); - if (line.isDoubleWidth()) { - widthMax /= 2; - } - if (widthMax > getWidth() - 2) { - widthMax = getWidth() - 2; + if (ch.isImage()) { + putCharXY(i + 1, row, ch); + continue; } - for (int i = 0; i < widthMax; i++) { - Cell ch = line.charAt(i); - if (ch.isImage()) { - putCharXY(i + 1, row, ch); - continue; - } - - Cell newCell = new Cell(); - newCell.setTo(ch); - boolean reverse = line.isReverseColor() ^ ch.isReverse(); - newCell.setReverse(false); - if (reverse) { - if (ch.getForeColorRGB() < 0) { - newCell.setBackColor(ch.getForeColor()); - newCell.setBackColorRGB(-1); - } else { - newCell.setBackColorRGB(ch.getForeColorRGB()); - } - if (ch.getBackColorRGB() < 0) { - newCell.setForeColor(ch.getBackColor()); - newCell.setForeColorRGB(-1); - } else { - newCell.setForeColorRGB(ch.getBackColorRGB()); - } + Cell newCell = new Cell(ch); + boolean reverse = line.isReverseColor() ^ ch.isReverse(); + newCell.setReverse(false); + if (reverse) { + if (ch.getForeColorRGB() < 0) { + newCell.setBackColor(ch.getForeColor()); + newCell.setBackColorRGB(-1); + } else { + newCell.setBackColorRGB(ch.getForeColorRGB()); } - if (line.isDoubleWidth()) { - putDoubleWidthCharXY(line, (i * 2) + 1, row, newCell); + if (ch.getBackColorRGB() < 0) { + newCell.setForeColor(ch.getBackColor()); + newCell.setForeColorRGB(-1); } else { - putCharXY(i + 1, row, newCell); + newCell.setForeColorRGB(ch.getBackColorRGB()); } } - row++; - if (row == getHeight() - 1) { - // Don't overwrite the box edge - break; + if (line.isDoubleWidth()) { + putDoubleWidthCharXY(line, (i * 2) + 1, row, newCell); + } else { + putCharXY(i + 1, row, newCell); } } - CellAttributes background = new CellAttributes(); - // Fill in the blank lines on bottom - for (int i = 0; i < visibleHeight; i++) { - hLineXY(1, i + row, getWidth() - 2, ' ', background); + row++; + if (row == getHeight() - 1) { + // Don't overwrite the box edge + break; } - - } // synchronized (emulator) + } + CellAttributes background = new CellAttributes(); + // Fill in the blank lines on bottom + for (int i = 0; i < visibleHeight; i++) { + hLineXY(1, i + row, getWidth() - 2, ' ', background); + } } @@ -480,6 +532,9 @@ public class TTerminalWindow extends TScrollableWindow */ @Override public void onKeypress(final TKeypressEvent keypress) { + if (hideMouseWhenTyping) { + typingHidMouse = true; + } // Scrollback up/down if (keypress.equals(kbShiftPgUp) @@ -497,25 +552,21 @@ public class TTerminalWindow extends TScrollableWindow return; } - // Synchronize against the emulator so we don't stomp on its reader - // thread. - synchronized (emulator) { - if (emulator.isReading()) { - // Get out of scrollback - setVerticalValue(0); - emulator.keypress(keypress.getKey()); + if (emulator.isReading()) { + // Get out of scrollback + setVerticalValue(0); + emulator.addUserEvent(keypress); - // UGLY HACK TIME! cmd.exe needs CRLF, not just CR, so if - // this is kBEnter then also send kbCtrlJ. - if (System.getProperty("os.name").startsWith("Windows")) { - if (keypress.equals(kbEnter)) { - emulator.keypress(kbCtrlJ); - } + // UGLY HACK TIME! cmd.exe needs CRLF, not just CR, so if + // this is kBEnter then also send kbCtrlJ. + if (System.getProperty("os.name").startsWith("Windows")) { + if (keypress.equals(kbEnter)) { + emulator.addUserEvent(new TKeypressEvent(kbCtrlJ)); } - - readEmulatorState(); - return; } + + readEmulatorState(); + return; } // Process is closed, honor "normal" TUI keystrokes @@ -535,6 +586,10 @@ public class TTerminalWindow extends TScrollableWindow return; } + if (hideMouseWhenTyping) { + typingHidMouse = false; + } + // If the emulator is tracking mouse buttons, it needs to see wheel // events. if (emulator.getMouseProtocol() == ECMA48.MouseProtocol.OFF) { @@ -548,13 +603,11 @@ public class TTerminalWindow extends TScrollableWindow } } if (mouseOnEmulator(mouse)) { - synchronized (emulator) { - mouse.setX(mouse.getX() - 1); - mouse.setY(mouse.getY() - 1); - emulator.mouse(mouse); - readEmulatorState(); - return; - } + mouse.setX(mouse.getX() - 1); + mouse.setY(mouse.getY() - 1); + emulator.addUserEvent(mouse); + readEmulatorState(); + return; } // Emulator didn't consume it, pass it on @@ -574,14 +627,16 @@ public class TTerminalWindow extends TScrollableWindow return; } + if (hideMouseWhenTyping) { + typingHidMouse = false; + } + if (mouseOnEmulator(mouse)) { - synchronized (emulator) { - mouse.setX(mouse.getX() - 1); - mouse.setY(mouse.getY() - 1); - emulator.mouse(mouse); - readEmulatorState(); - return; - } + mouse.setX(mouse.getX() - 1); + mouse.setY(mouse.getY() - 1); + emulator.addUserEvent(mouse); + readEmulatorState(); + return; } // Emulator didn't consume it, pass it on @@ -601,14 +656,16 @@ public class TTerminalWindow extends TScrollableWindow return; } + if (hideMouseWhenTyping) { + typingHidMouse = false; + } + if (mouseOnEmulator(mouse)) { - synchronized (emulator) { - mouse.setX(mouse.getX() - 1); - mouse.setY(mouse.getY() - 1); - emulator.mouse(mouse); - readEmulatorState(); - return; - } + mouse.setX(mouse.getX() - 1); + mouse.setY(mouse.getY() - 1); + emulator.addUserEvent(mouse); + readEmulatorState(); + return; } // Emulator didn't consume it, pass it on @@ -619,6 +676,18 @@ public class TTerminalWindow extends TScrollableWindow // TTerminalWindow -------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Returns true if this window does not want the application-wide mouse + * cursor drawn over it. + * + * @return true if this window does not want the application-wide mouse + * cursor drawn over it + */ + @Override + public boolean hasHiddenMouse() { + return (super.hasHiddenMouse() || typingHidMouse); + } + /** * Claim the keystrokes the emulator will need. */ @@ -754,6 +823,13 @@ public class TTerminalWindow extends TScrollableWindow // Pass the correct text cell width/height to the emulator emulator.setTextWidth(getScreen().getTextWidth()); emulator.setTextHeight(getScreen().getTextHeight()); + + // Hide mouse when typing option + if (System.getProperty("jexer.TTerminal.hideMouseWhenTyping", + "true").equals("false")) { + + hideMouseWhenTyping = false; + } } /** @@ -789,37 +865,6 @@ public class TTerminalWindow extends TScrollableWindow } } - /** - * Called by emulator when fresh data has come in. - */ - public void displayChanged() { - getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT)); - } - - /** - * Function to call to obtain the display width. - * - * @return the number of columns in the display - */ - public int getDisplayWidth() { - if (ptypipe) { - return getWidth() - 2; - } - return 80; - } - - /** - * Function to call to obtain the display height. - * - * @return the number of rows in the display - */ - public int getDisplayHeight() { - if (ptypipe) { - return getHeight() - 2; - } - return 24; - } - /** * Hook for subclasses to be notified of the shell termination. */ @@ -906,10 +951,8 @@ public class TTerminalWindow extends TScrollableWindow */ private boolean mouseOnEmulator(final TMouseEvent mouse) { - synchronized (emulator) { - if (!emulator.isReading()) { - return false; - } + if (!emulator.isReading()) { + return false; } if ((mouse.getAbsoluteX() >= getAbsoluteX() + 1) @@ -922,6 +965,20 @@ public class TTerminalWindow extends TScrollableWindow return false; } + /** + * Copy a display buffer. + * + * @param buffer the buffer to copy + * @return a deep copy of the buffer's data + */ + private List copyBuffer(final List buffer) { + ArrayList result = new ArrayList(buffer.size()); + for (DisplayLine line: buffer) { + result.add(new DisplayLine(line)); + } + return result; + } + /** * Draw glyphs for a double-width or double-height VT100 cell to two * screen cells. @@ -971,8 +1028,7 @@ public class TTerminalWindow extends TScrollableWindow BufferedImage image; if (line.getDoubleHeight() == 1) { // Double-height top half: don't draw the underline. - Cell newCell = new Cell(); - newCell.setTo(cell); + Cell newCell = new Cell(cell); newCell.setUnderline(false); image = doubleFont.getImage(newCell, textWidth * 2, textHeight * 2, cursorBlinkVisible); @@ -983,10 +1039,8 @@ public class TTerminalWindow extends TScrollableWindow // Now that we have the double-wide glyph drawn, copy the right // pieces of it to the cells. - Cell left = new Cell(); - Cell right = new Cell(); - left.setTo(cell); - right.setTo(cell); + Cell left = new Cell(cell); + Cell right = new Cell(cell); right.setChar(' '); BufferedImage leftImage = null; BufferedImage rightImage = null; @@ -1059,4 +1113,40 @@ public class TTerminalWindow extends TScrollableWindow } } + // ------------------------------------------------------------------------ + // DisplayListener -------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Called by emulator when fresh data has come in. + */ + public void displayChanged() { + dirty = true; + getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT)); + } + + /** + * Function to call to obtain the display width. + * + * @return the number of columns in the display + */ + public int getDisplayWidth() { + if (ptypipe) { + return getWidth() - 2; + } + return 80; + } + + /** + * Function to call to obtain the display height. + * + * @return the number of rows in the display + */ + public int getDisplayHeight() { + if (ptypipe) { + return getHeight() - 2; + } + return 24; + } + }