X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTTerminalWidget.java;h=f488320c463ba9e30be64a8c77864762a5418f83;hb=5ca5f8e5310b189232ed337643f3b7b2ce6cd3b1;hp=fb4b68bb68e0648c16a5e8daaed4a8c6132fc386;hpb=dbf8e80aeb64b989342bdad91fae00ce5cbc3d06;p=fanfix.git diff --git a/src/jexer/TTerminalWidget.java b/src/jexer/TTerminalWidget.java index fb4b68b..f488320 100644 --- a/src/jexer/TTerminalWidget.java +++ b/src/jexer/TTerminalWidget.java @@ -49,6 +49,7 @@ import jexer.backend.MultiScreen; import jexer.backend.SwingTerminal; import jexer.bits.Cell; import jexer.bits.CellAttributes; +import jexer.event.TCommandEvent; import jexer.event.TKeypressEvent; import jexer.event.TMenuEvent; import jexer.event.TMouseEvent; @@ -57,13 +58,14 @@ import jexer.menu.TMenu; import jexer.tterminal.DisplayLine; import jexer.tterminal.DisplayListener; import jexer.tterminal.ECMA48; +import static jexer.TCommand.*; import static jexer.TKeypress.*; /** * TTerminalWidget exposes a ECMA-48 / ANSI X3.64 style terminal in a widget. */ public class TTerminalWidget extends TScrollableWidget - implements DisplayListener { + implements DisplayListener, EditMenuUser { /** * Translated strings. @@ -198,7 +200,7 @@ public class TTerminalWidget extends TScrollableWidget * @param x column relative to parent * @param y row relative to parent * @param command the command line to execute - * @param closeAction action to perform when the shell sxits + * @param closeAction action to perform when the shell exits */ public TTerminalWidget(final TWidget parent, final int x, final int y, final String [] command, final TAction closeAction) { @@ -215,7 +217,7 @@ public class TTerminalWidget extends TScrollableWidget * @param width width of widget * @param height height of widget * @param command the command line to execute - * @param closeAction action to perform when the shell sxits + * @param closeAction action to perform when the shell exits */ public TTerminalWidget(final TWidget parent, final int x, final int y, final int width, final int height, final String [] command, @@ -251,12 +253,24 @@ public class TTerminalWidget extends TScrollableWidget fullCommand[5] = stringArrayToString(command); } else { // Default: behave like Linux - fullCommand = new String[5]; - fullCommand[0] = "script"; - fullCommand[1] = "-fqe"; - fullCommand[2] = "/dev/null"; - fullCommand[3] = "-c"; - fullCommand[4] = stringArrayToString(command); + if (System.getProperty("jexer.TTerminal.setsid", + "true").equals("false") + ) { + fullCommand = new String[5]; + fullCommand[0] = "script"; + fullCommand[1] = "-fqe"; + fullCommand[2] = "/dev/null"; + fullCommand[3] = "-c"; + fullCommand[4] = stringArrayToString(command); + } else { + fullCommand = new String[6]; + fullCommand[0] = "setsid"; + fullCommand[1] = "script"; + fullCommand[2] = "-fqe"; + fullCommand[3] = "/dev/null"; + fullCommand[4] = "-c"; + fullCommand[5] = stringArrayToString(command); + } } spawnShell(fullCommand); } @@ -278,7 +292,7 @@ public class TTerminalWidget extends TScrollableWidget * @param parent parent widget * @param x column relative to parent * @param y row relative to parent - * @param closeAction action to perform when the shell sxits + * @param closeAction action to perform when the shell exits */ public TTerminalWidget(final TWidget parent, final int x, final int y, final TAction closeAction) { @@ -294,7 +308,7 @@ public class TTerminalWidget extends TScrollableWidget * @param y row relative to parent * @param width width of widget * @param height height of widget - * @param closeAction action to perform when the shell sxits + * @param closeAction action to perform when the shell exits */ public TTerminalWidget(final TWidget parent, final int x, final int y, final int width, final int height, final TAction closeAction) { @@ -320,6 +334,7 @@ public class TTerminalWidget extends TScrollableWidget // GNU differ on the '-f' vs '-F' flags, we need two different // commands. Lovely. String cmdShellGNU = "script -fqe /dev/null"; + String cmdShellGNUSetsid = "setsid script -fqe /dev/null"; String cmdShellBSD = "script -q -F /dev/null"; // ptypipe is another solution that permits dynamic window resizing. @@ -337,7 +352,13 @@ public class TTerminalWidget extends TScrollableWidget } else if (System.getProperty("os.name").startsWith("Mac")) { spawnShell(cmdShellBSD.split("\\s+")); } else if (System.getProperty("os.name").startsWith("Linux")) { - spawnShell(cmdShellGNU.split("\\s+")); + if (System.getProperty("jexer.TTerminal.setsid", + "true").equals("false") + ) { + spawnShell(cmdShellGNU.split("\\s+")); + } else { + spawnShell(cmdShellGNUSetsid.split("\\s+")); + } } else { // When all else fails, assume GNU. spawnShell(cmdShellGNU.split("\\s+")); @@ -358,6 +379,10 @@ public class TTerminalWidget extends TScrollableWidget // 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) { @@ -418,7 +443,7 @@ public class TTerminalWidget extends TScrollableWidget return; } - if (emulator.isReading()) { + if ((emulator != null) && (emulator.isReading())) { // Get out of scrollback setVerticalValue(0); emulator.addUserEvent(keypress); @@ -453,25 +478,27 @@ public class TTerminalWidget extends TScrollableWidget 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(); - dirty = true; - 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(); - dirty = true; + 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); @@ -488,7 +515,7 @@ public class TTerminalWidget extends TScrollableWidget typingHidMouse = false; } - if (mouseOnEmulator(mouse)) { + if ((emulator != null) && (mouseOnEmulator(mouse))) { emulator.addUserEvent(mouse); readEmulatorState(); return; @@ -509,7 +536,7 @@ public class TTerminalWidget extends TScrollableWidget typingHidMouse = false; } - if (mouseOnEmulator(mouse)) { + if ((emulator != null) && (mouseOnEmulator(mouse))) { emulator.addUserEvent(mouse); readEmulatorState(); return; @@ -519,6 +546,32 @@ public class TTerminalWidget extends TScrollableWidget super.onMouseMotion(mouse); } + /** + * Handle posted command events. + * + * @param command command event + */ + @Override + public void onCommand(final TCommandEvent command) { + if (emulator == null) { + return; + } + + if (command.equals(cmPaste)) { + // Paste text from clipboard. + String text = getClipboard().pasteText(); + if (text != null) { + for (int i = 0; i < text.length(); ) { + int ch = text.codePointAt(i); + emulator.addUserEvent(new TKeypressEvent(false, 0, ch, + false, false, false)); + i += Character.charCount(ch); + } + } + return; + } + } + // ------------------------------------------------------------------------ // TScrollableWidget ------------------------------------------------------ // ------------------------------------------------------------------------ @@ -528,12 +581,14 @@ public class TTerminalWidget extends TScrollableWidget */ @Override public void draw() { + if (emulator == null) { + return; + } + int width = getDisplayWidth(); boolean syncEmulator = false; - if ((System.currentTimeMillis() - lastUpdateTime >= 20) - && (dirty == true) - ) { + if (System.currentTimeMillis() - lastUpdateTime >= 50) { // Too much time has passed, draw it all. syncEmulator = true; } else if (emulator.isReading() && (dirty == false)) { @@ -682,7 +737,9 @@ public class TTerminalWidget extends TScrollableWidget */ @Override public void close() { - emulator.close(); + if (emulator != null) { + emulator.close(); + } if (shell != null) { terminateShellChildProcess(); shell.destroy(); @@ -695,6 +752,9 @@ public class TTerminalWidget extends TScrollableWidget */ @Override public void reflowData() { + if (emulator == null) { + return; + } // Synchronize against the emulator so we don't stomp on its reader // thread. @@ -733,6 +793,9 @@ public class TTerminalWidget extends TScrollableWidget * cursor drawn over it */ public boolean hasHiddenMouse() { + if (emulator == null) { + return false; + } return (emulator.hasHiddenMousePointer() || typingHidMouse); } @@ -743,6 +806,9 @@ public class TTerminalWidget extends TScrollableWidget * side */ public boolean isReading() { + if (emulator == null) { + return false; + } return emulator.isReading(); } @@ -863,10 +929,7 @@ public class TTerminalWidget extends TScrollableWidget } }); } - if (getApplication() != null) { - getApplication().postEvent(new TMenuEvent( - TMenu.MID_REPAINT)); - } + app.doRepaint(); } } @@ -875,6 +938,10 @@ public class TTerminalWidget extends TScrollableWidget * screen. */ private void readEmulatorState() { + if (emulator == null) { + return; + } + // Synchronize against the emulator so we don't stomp on its reader // thread. synchronized (emulator) { @@ -932,6 +999,19 @@ public class TTerminalWidget extends TScrollableWidget } // synchronized (emulator) } + /** + * Wait for a period of time to get output from the launched process. + * + * @param millis millis to wait for, or 0 to wait forever + * @return true if the launched process has emitted something + */ + public boolean waitForOutput(final int millis) { + if (emulator == null) { + return false; + } + return emulator.waitForOutput(millis); + } + /** * Check if a mouse press/release/motion event coordinate is over the * emulator. @@ -940,6 +1020,9 @@ public class TTerminalWidget extends TScrollableWidget * @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; @@ -1097,7 +1180,17 @@ public class TTerminalWidget extends TScrollableWidget * 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)); } @@ -1125,4 +1218,44 @@ public class TTerminalWidget extends TScrollableWidget return 24; } + // ------------------------------------------------------------------------ + // EditMenuUser ----------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Check if the cut menu item should be enabled. + * + * @return true if the cut menu item should be enabled + */ + public boolean isEditMenuCut() { + return false; + } + + /** + * Check if the copy menu item should be enabled. + * + * @return true if the copy menu item should be enabled + */ + public boolean isEditMenuCopy() { + return false; + } + + /** + * Check if the paste menu item should be enabled. + * + * @return true if the paste menu item should be enabled + */ + public boolean isEditMenuPaste() { + return true; + } + + /** + * Check if the clear menu item should be enabled. + * + * @return true if the clear menu item should be enabled + */ + public boolean isEditMenuClear() { + return false; + } + }