private boolean haveTimer = false;
/**
- * The last seen scrollback lines.
- */
- private List<DisplayLine> scrollback;
-
- /**
- * The last seen display lines.
+ * The last seen visible display.
*/
private List<DisplayLine> display;
}
// ------------------------------------------------------------------------
- // TScrollableWidget ------------------------------------------------------
+ // Event handlers ---------------------------------------------------------
// ------------------------------------------------------------------------
- /**
- * Draw the display buffer.
- */
- @Override
- public void draw() {
- 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;
- }
-
- 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();
-
- if (!isDrawable()) {
- // We lost the connection, onShellExit() called an action
- // that ultimately removed this widget from the UI
- // hierarchy, so no one cares if we update the display.
- // Bail out.
- return;
- }
-
- if ((scrollback == null) || emulator.isReading()) {
- scrollback = copyBuffer(emulator.getScrollbackBuffer());
- display = copyBuffer(emulator.getDisplayBuffer());
- }
- width = emulator.getWidth();
- }
- dirty = false;
- }
-
- // Put together the visible rows
- int visibleHeight = getHeight();
- int visibleBottom = scrollback.size() + display.size()
- + getVerticalValue();
- assert (visibleBottom >= 0);
-
- List<DisplayLine> preceedingBlankLines = new ArrayList<DisplayLine>();
- int visibleTop = visibleBottom - visibleHeight;
- if (visibleTop < 0) {
- for (int i = visibleTop; i < 0; i++) {
- preceedingBlankLines.add(emulator.getBlankDisplayLine());
- }
- visibleTop = 0;
- }
- assert (visibleTop >= 0);
-
- List<DisplayLine> displayLines = new ArrayList<DisplayLine>();
- displayLines.addAll(scrollback);
- displayLines.addAll(display);
-
- List<DisplayLine> visibleLines = new ArrayList<DisplayLine>();
- visibleLines.addAll(preceedingBlankLines);
- visibleLines.addAll(displayLines.subList(visibleTop,
- visibleBottom));
-
- visibleHeight -= visibleLines.size();
- assert (visibleHeight >= 0);
-
- // Now draw the emulator screen
- int row = 0;
- for (DisplayLine line: visibleLines) {
- int widthMax = width;
- if (line.isDoubleWidth()) {
- widthMax /= 2;
- }
- if (widthMax > getWidth()) {
- widthMax = getWidth();
- }
- for (int i = 0; i < widthMax; i++) {
- Cell ch = line.charAt(i);
-
- if (ch.isImage()) {
- putCharXY(i, row, ch);
- continue;
- }
-
- 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 (ch.getBackColorRGB() < 0) {
- newCell.setForeColor(ch.getBackColor());
- newCell.setForeColorRGB(-1);
- } else {
- newCell.setForeColorRGB(ch.getBackColorRGB());
- }
- }
- if (line.isDoubleWidth()) {
- putDoubleWidthCharXY(line, (i * 2), row, newCell);
- } else {
- putCharXY(i, row, newCell);
- }
- }
- row++;
- if (row == getHeight()) {
- // Don't overwrite the box edge
- break;
- }
- }
- CellAttributes background = new CellAttributes();
- // Fill in the blank lines on bottom
- for (int i = 0; i < visibleHeight; i++) {
- hLineXY(0, i + row, getWidth(), ' ', background);
- }
-
- }
-
- /**
- * Handle widget close.
- */
- @Override
- public void close() {
- emulator.close();
- if (shell != null) {
- terminateShellChildProcess();
- shell.destroy();
- shell = null;
- }
- }
-
/**
* Handle window/screen resize events.
*
// Let TWidget set my size.
super.onResize(resize);
+ if (emulator == null) {
+ return;
+ }
+
// Synchronize against the emulator so we don't stomp on its reader
// thread.
synchronized (emulator) {
} // synchronized (emulator)
}
- /**
- * Resize scrollbars for a new width/height.
- */
- @Override
- public void reflowData() {
-
- // Synchronize against the emulator so we don't stomp on its reader
- // thread.
- synchronized (emulator) {
-
- // Pull cursor information
- readEmulatorState();
-
- // Vertical scrollbar
- setTopValue(getHeight()
- - (emulator.getScrollbackBuffer().size()
- + emulator.getDisplayBuffer().size()));
- setVerticalBigChange(getHeight());
-
- } // synchronized (emulator)
- }
-
/**
* Handle keystrokes.
*
|| keypress.equals(kbAltPgUp)
) {
bigVerticalDecrement();
+ dirty = true;
return;
}
if (keypress.equals(kbShiftPgDn)
|| keypress.equals(kbAltPgDn)
) {
bigVerticalIncrement();
+ dirty = true;
return;
}
- if (emulator.isReading()) {
+ if ((emulator != null) && (emulator.isReading())) {
// Get out of scrollback
setVerticalValue(0);
emulator.addUserEvent(keypress);
typingHidMouse = false;
}
- // If the emulator is tracking mouse buttons, it needs to see wheel
- // events.
- if (emulator.getMouseProtocol() == ECMA48.MouseProtocol.OFF) {
- if (mouse.isMouseWheelUp()) {
- verticalDecrement();
- return;
+ if (emulator != null) {
+ // If the emulator is tracking mouse buttons, it needs to see
+ // wheel events.
+ if (emulator.getMouseProtocol() == ECMA48.MouseProtocol.OFF) {
+ if (mouse.isMouseWheelUp()) {
+ verticalDecrement();
+ dirty = true;
+ return;
+ }
+ if (mouse.isMouseWheelDown()) {
+ verticalIncrement();
+ dirty = true;
+ return;
+ }
}
- if (mouse.isMouseWheelDown()) {
- verticalIncrement();
+ if (mouseOnEmulator(mouse)) {
+ emulator.addUserEvent(mouse);
+ readEmulatorState();
return;
}
}
- if (mouseOnEmulator(mouse)) {
- emulator.addUserEvent(mouse);
- readEmulatorState();
- return;
- }
// Emulator didn't consume it, pass it on
super.onMouseDown(mouse);
typingHidMouse = false;
}
- if (mouseOnEmulator(mouse)) {
+ if ((emulator != null) && (mouseOnEmulator(mouse))) {
emulator.addUserEvent(mouse);
readEmulatorState();
return;
typingHidMouse = false;
}
- if (mouseOnEmulator(mouse)) {
+ if ((emulator != null) && (mouseOnEmulator(mouse))) {
emulator.addUserEvent(mouse);
readEmulatorState();
return;
super.onMouseMotion(mouse);
}
+ // ------------------------------------------------------------------------
+ // TScrollableWidget ------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Draw the display buffer.
+ */
+ @Override
+ public void draw() {
+ if (emulator == null) {
+ return;
+ }
+
+ int width = getDisplayWidth();
+
+ boolean syncEmulator = false;
+ if (System.currentTimeMillis() - lastUpdateTime >= 50) {
+ // 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;
+ }
+
+ if ((syncEmulator == true)
+ || (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();
+
+ if (!isDrawable()) {
+ // We lost the connection, onShellExit() called an action
+ // that ultimately removed this widget from the UI
+ // hierarchy, so no one cares if we update the display.
+ // Bail out.
+ return;
+ }
+
+ if ((display == null) || emulator.isReading()) {
+ display = emulator.getVisibleDisplay(getHeight(),
+ -getVerticalValue());
+ assert (display.size() == getHeight());
+ }
+ width = emulator.getWidth();
+ }
+ dirty = false;
+ }
+
+ // Now draw the emulator screen
+ int row = 0;
+ for (DisplayLine line: display) {
+ int widthMax = width;
+ if (line.isDoubleWidth()) {
+ widthMax /= 2;
+ }
+ if (widthMax > getWidth()) {
+ widthMax = getWidth();
+ }
+ for (int i = 0; i < widthMax; i++) {
+ Cell ch = line.charAt(i);
+
+ if (ch.isImage()) {
+ putCharXY(i, row, ch);
+ continue;
+ }
+
+ 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 (ch.getBackColorRGB() < 0) {
+ newCell.setForeColor(ch.getBackColor());
+ newCell.setForeColorRGB(-1);
+ } else {
+ newCell.setForeColorRGB(ch.getBackColorRGB());
+ }
+ }
+ if (line.isDoubleWidth()) {
+ putDoubleWidthCharXY(line, (i * 2), row, newCell);
+ } else {
+ putCharXY(i, row, newCell);
+ }
+ }
+ row++;
+ }
+ }
+
+ /**
+ * Set current value of the vertical scroll.
+ *
+ * @param value the new scroll value
+ */
+ @Override
+ public void setVerticalValue(final int value) {
+ super.setVerticalValue(value);
+ dirty = true;
+ }
+
+ /**
+ * Perform a small step change up.
+ */
+ @Override
+ public void verticalDecrement() {
+ super.verticalDecrement();
+ dirty = true;
+ }
+
+ /**
+ * Perform a small step change down.
+ */
+ @Override
+ public void verticalIncrement() {
+ super.verticalIncrement();
+ dirty = true;
+ }
+
+ /**
+ * Perform a big step change up.
+ */
+ public void bigVerticalDecrement() {
+ super.bigVerticalDecrement();
+ dirty = true;
+ }
+
+ /**
+ * Perform a big step change down.
+ */
+ public void bigVerticalIncrement() {
+ super.bigVerticalIncrement();
+ dirty = true;
+ }
+
+ /**
+ * Go to the top edge of the vertical scroller.
+ */
+ public void toTop() {
+ super.toTop();
+ dirty = true;
+ }
+
+ /**
+ * Go to the bottom edge of the vertical scroller.
+ */
+ public void toBottom() {
+ super.toBottom();
+ dirty = true;
+ }
+
+ /**
+ * Handle widget close.
+ */
+ @Override
+ public void close() {
+ if (emulator != null) {
+ emulator.close();
+ }
+ if (shell != null) {
+ terminateShellChildProcess();
+ shell.destroy();
+ shell = null;
+ }
+ }
+
+ /**
+ * Resize scrollbars for a new width/height.
+ */
+ @Override
+ public void reflowData() {
+ if (emulator == null) {
+ return;
+ }
+
+ // Synchronize against the emulator so we don't stomp on its reader
+ // thread.
+ synchronized (emulator) {
+
+ // Pull cursor information
+ readEmulatorState();
+
+ // Vertical scrollbar
+ setTopValue(getHeight()
+ - (emulator.getScrollbackBuffer().size()
+ + emulator.getDisplayBuffer().size()));
+ setVerticalBigChange(getHeight());
+
+ } // synchronized (emulator)
+ }
+
// ------------------------------------------------------------------------
// TTerminalWidget --------------------------------------------------------
// ------------------------------------------------------------------------
* cursor drawn over it
*/
public boolean hasHiddenMouse() {
+ if (emulator == null) {
+ return false;
+ }
return (emulator.hasHiddenMousePointer() || typingHidMouse);
}
* side
*/
public boolean isReading() {
+ if (emulator == null) {
+ return false;
+ }
return emulator.isReading();
}
* screen.
*/
private void readEmulatorState() {
+ if (emulator == null) {
+ return;
+ }
+
// Synchronize against the emulator so we don't stomp on its reader
// thread.
synchronized (emulator) {
* @return whether or not the mouse is on the emulator
*/
private boolean mouseOnEmulator(final TMouseEvent mouse) {
+ if (emulator == null) {
+ return false;
+ }
if (!emulator.isReading()) {
return false;
return false;
}
- /**
- * Copy a display buffer.
- *
- * @param buffer the buffer to copy
- * @return a deep copy of the buffer's data
- */
- private List<DisplayLine> copyBuffer(final List<DisplayLine> buffer) {
- ArrayList<DisplayLine> result = new ArrayList<DisplayLine>(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.
* Called by emulator when fresh data has come in.
*/
public void displayChanged() {
- dirty = true;
+ if (emulator != null) {
+ // Force sync here: EMCA48.run() thread might be setting
+ // dirty=true while TTerminalWdiget.draw() is setting
+ // dirty=false. If these writes start interleaving, the display
+ // stops getting updated.
+ synchronized (emulator) {
+ dirty = true;
+ }
+ } else {
+ dirty = true;
+ }
getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT));
}