mirror of
https://gitlab.com/AutumnMeowMeow/jexer
synced 2024-09-19 11:50:19 -06:00
#103 Push screens from ECMA48 to TTerminalWidget
This commit is contained in:
parent
3bb1294e04
commit
ea4d7bdd08
4 changed files with 129 additions and 86 deletions
|
@ -135,12 +135,7 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
/**
|
||||
* If true, the display has changed and needs updating.
|
||||
*/
|
||||
private List<String> dirtyQueue = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Time that the display was last updated.
|
||||
*/
|
||||
private long lastUpdateTime = 0;
|
||||
private List<List<DisplayLine>> dirtyQueue = new ArrayList<List<DisplayLine>>();
|
||||
|
||||
/**
|
||||
* If true, hide the mouse after typing a keystroke.
|
||||
|
@ -642,50 +637,21 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
|
||||
int width = getDisplayWidth();
|
||||
|
||||
boolean syncEmulator = false;
|
||||
// Get the very first display.
|
||||
if (display == null) {
|
||||
width = readEmulatorDisplay();
|
||||
}
|
||||
|
||||
// If the emulator notified of an update, sync.
|
||||
synchronized (dirtyQueue) {
|
||||
if (dirtyQueue.size() > 0) {
|
||||
dirtyQueue.remove(dirtyQueue.size() - 1);
|
||||
syncEmulator = true;
|
||||
// We will be dropping frames to keep up.
|
||||
display = dirtyQueue.remove(dirtyQueue.size() - 1);
|
||||
dirtyQueue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// If it has been longer than 250 milliseconds, sync.
|
||||
long now = System.currentTimeMillis();
|
||||
if ((now - lastUpdateTime) > 250) {
|
||||
syncEmulator = true;
|
||||
}
|
||||
lastUpdateTime = now;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// Now draw the emulator screen
|
||||
// Draw the emulator screen.
|
||||
int row = 0;
|
||||
for (DisplayLine line: display) {
|
||||
int widthMax = width;
|
||||
|
@ -840,14 +806,10 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the dirty flag.
|
||||
* Update the display to account for a change in scrollback.
|
||||
*/
|
||||
public void setDirty() {
|
||||
synchronized (dirtyQueue) {
|
||||
if (dirtyQueue.size() == 0) {
|
||||
dirtyQueue.add("dirty");
|
||||
}
|
||||
}
|
||||
private void setDirty() {
|
||||
readEmulatorDisplay();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -914,6 +876,9 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
*/
|
||||
public boolean hasHiddenMouse() {
|
||||
if (emulator != null) {
|
||||
if (!emulator.isReading()) {
|
||||
typingHidMouse = false;
|
||||
}
|
||||
boolean hiddenMouse = (emulator.hasHiddenMousePointer()
|
||||
|| typingHidMouse);
|
||||
if (hiddenMouse) {
|
||||
|
@ -1429,30 +1394,42 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the scrollback buffer from the emulator.
|
||||
* Get the visible display buffer from the emulator.
|
||||
*
|
||||
* @return the scrollback buffer, all the lines that have scrolled off
|
||||
* screen
|
||||
* @return the width of the display, or -1 if the display was not read
|
||||
*/
|
||||
public final List<DisplayLine> getScrollbackBuffer() {
|
||||
ArrayList<DisplayLine> buffer = new ArrayList<DisplayLine>();
|
||||
for (DisplayLine line: emulator.getScrollbackBuffer()) {
|
||||
buffer.add(new DisplayLine(line));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
private int readEmulatorDisplay() {
|
||||
|
||||
/**
|
||||
* Get the display buffer from the emulator.
|
||||
*
|
||||
* @return the display buffer, the lines that are on the visible screen
|
||||
*/
|
||||
public final List<DisplayLine> getDisplayBuffer() {
|
||||
ArrayList<DisplayLine> buffer = new ArrayList<DisplayLine>();
|
||||
for (DisplayLine line: emulator.getDisplayBuffer()) {
|
||||
buffer.add(new DisplayLine(line));
|
||||
List<DisplayLine> currentDisplay = null;
|
||||
int width = 80;
|
||||
|
||||
// Synchronize against the emulator so we don't stomp on its reader
|
||||
// thread.
|
||||
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 -1;
|
||||
}
|
||||
|
||||
if (emulator.isReading()) {
|
||||
currentDisplay = emulator.getVisibleDisplay(getHeight(),
|
||||
-getVerticalValue());
|
||||
assert (display.size() == getHeight());
|
||||
}
|
||||
width = emulator.getWidth();
|
||||
}
|
||||
return buffer;
|
||||
if (currentDisplay != null) {
|
||||
synchronized (dirtyQueue) {
|
||||
dirtyQueue.add(currentDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1506,6 +1483,18 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
// DisplayListener --------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Called by emulator when fresh data has come in (push).
|
||||
*
|
||||
* @param display the updated display
|
||||
*/
|
||||
public void updateDisplay(final List<DisplayLine> display) {
|
||||
synchronized (dirtyQueue) {
|
||||
dirtyQueue.add(display);
|
||||
}
|
||||
getApplication().doRepaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by emulator when fresh data has come in.
|
||||
*
|
||||
|
@ -1514,22 +1503,30 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
*/
|
||||
public void displayChanged(final boolean cursorOnly) {
|
||||
if (cursorOnly) {
|
||||
TApplication app = getApplication();
|
||||
if (app != null) {
|
||||
app.postEvent(new TMenuEvent(null, TMenu.MID_REPAINT));
|
||||
}
|
||||
getApplication().doRepaint();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean readDisplay = false;
|
||||
synchronized (dirtyQueue) {
|
||||
if (dirtyQueue.size() == 0) {
|
||||
dirtyQueue.add("dirty");
|
||||
TApplication app = getApplication();
|
||||
if (app != null) {
|
||||
app.postEvent(new TMenuEvent(null, TMenu.MID_REPAINT));
|
||||
}
|
||||
if (dirtyQueue.size() > 0) {
|
||||
display = dirtyQueue.remove(0);
|
||||
}
|
||||
}
|
||||
if (readDisplay) {
|
||||
readEmulatorDisplay();
|
||||
}
|
||||
getApplication().doRepaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to call to obtain the number of rows from the bottom to
|
||||
* scroll back when sending updates via updateDisplay().
|
||||
*
|
||||
* @return the number of rows from the bottom to scroll back
|
||||
*/
|
||||
public int getScrollBottom() {
|
||||
return -getVerticalValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -278,7 +278,7 @@ public class TTextPicture extends TScrollableWidget
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Called by emulator when fresh data has come in.
|
||||
* Called by emulator when fresh data has come in (request poll).
|
||||
*
|
||||
* @param cursorOnly if true, the screen has not changed but the cursor
|
||||
* may be on a different location.
|
||||
|
@ -287,6 +287,25 @@ public class TTextPicture extends TScrollableWidget
|
|||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by emulator when fresh data has come in (push).
|
||||
*
|
||||
* @param display the updated display
|
||||
*/
|
||||
public void updateDisplay(final List<DisplayLine> display) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to call to obtain the number of rows from the bottom to
|
||||
* scroll back when sending updates via updateDisplay().
|
||||
*
|
||||
* @return the number of rows from the bottom to scroll back
|
||||
*/
|
||||
public int getScrollBottom() {
|
||||
return -getVerticalValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to call to obtain the display width.
|
||||
*
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
*/
|
||||
package jexer.tterminal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DisplayListener is used to callback into external UI when data has come in
|
||||
* from the remote side.
|
||||
|
@ -35,13 +37,28 @@ package jexer.tterminal;
|
|||
public interface DisplayListener {
|
||||
|
||||
/**
|
||||
* Function to call when the display needs to be updated.
|
||||
* Function to call when the display needs to be updated (request poll).
|
||||
*
|
||||
* @param cursorOnly if true, the screen has not changed but the cursor
|
||||
* may be on a different location.
|
||||
*/
|
||||
public void displayChanged(final boolean cursorOnly);
|
||||
|
||||
/**
|
||||
* Function to call when the display has updated (push).
|
||||
*
|
||||
* @param display the updated display
|
||||
*/
|
||||
public void updateDisplay(final List<DisplayLine> display);
|
||||
|
||||
/**
|
||||
* Function to call to obtain the number of rows from the bottom to
|
||||
* scroll back when sending updates via updateDisplay().
|
||||
*
|
||||
* @return the number of rows from the bottom to scroll back
|
||||
*/
|
||||
public int getScrollBottom();
|
||||
|
||||
/**
|
||||
* Function to call to obtain the display width.
|
||||
*
|
||||
|
|
|
@ -266,6 +266,12 @@ public class ECMA48 implements Runnable {
|
|||
*/
|
||||
private boolean screenIsDirty = true;
|
||||
|
||||
/**
|
||||
* When true, synchronized update has already pushed a screen to the
|
||||
* display, so run() should not do it again.
|
||||
*/
|
||||
private boolean doNotUpdateDisplay = false;
|
||||
|
||||
/**
|
||||
* When true, the reader thread is expected to exit.
|
||||
*/
|
||||
|
@ -860,15 +866,17 @@ public class ECMA48 implements Runnable {
|
|||
}
|
||||
}
|
||||
// Permit my enclosing UI to know that I updated.
|
||||
if (displayListener != null) {
|
||||
if ((displayListener != null) && !doNotUpdateDisplay) {
|
||||
if (screenIsDirty) {
|
||||
displayListener.displayChanged(false);
|
||||
displayListener.updateDisplay(getVisibleDisplay(
|
||||
height, displayListener.getScrollBottom()));
|
||||
screenIsDirty = false;
|
||||
} else {
|
||||
displayListener.displayChanged(true);
|
||||
screenIsDirty = false;
|
||||
}
|
||||
}
|
||||
doNotUpdateDisplay = false;
|
||||
}
|
||||
// System.err.println("end while loop"); System.err.flush();
|
||||
} catch (IOException e) {
|
||||
|
@ -2288,7 +2296,8 @@ public class ECMA48 implements Runnable {
|
|||
printCharacter(keypress.getChar());
|
||||
}
|
||||
if (displayListener != null) {
|
||||
displayListener.displayChanged(false);
|
||||
displayListener.updateDisplay(getVisibleDisplay(
|
||||
height, displayListener.getScrollBottom()));
|
||||
screenIsDirty = false;
|
||||
}
|
||||
}
|
||||
|
@ -3804,7 +3813,8 @@ public class ECMA48 implements Runnable {
|
|||
withinSynchronizedUpdate = false;
|
||||
// Permit my enclosing UI to know that I updated.
|
||||
if (displayListener != null) {
|
||||
displayListener.displayChanged(false);
|
||||
displayListener.updateDisplay(lastVisibleDisplay);
|
||||
doNotUpdateDisplay = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue