X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTTerminalWindow.java;h=415a1a0a9fd1eb7ece35db9e3914ca9973b5124e;hb=0525b2ed026e0d510fdf23f6d8f4cb4562a17e0b;hp=3dc6a4c19e11322f22d4d20126721cb01f4b7209;hpb=339652cc241d738d461670c3309eaf6fc85c992a;p=fanfix.git diff --git a/src/jexer/TTerminalWindow.java b/src/jexer/TTerminalWindow.java index 3dc6a4c..415a1a0 100644 --- a/src/jexer/TTerminalWindow.java +++ b/src/jexer/TTerminalWindow.java @@ -39,8 +39,10 @@ import java.util.ResourceBundle; import jexer.bits.Cell; import jexer.bits.CellAttributes; import jexer.event.TKeypressEvent; +import jexer.event.TMenuEvent; import jexer.event.TMouseEvent; import jexer.event.TResizeEvent; +import jexer.menu.TMenu; import jexer.tterminal.DisplayLine; import jexer.tterminal.DisplayListener; import jexer.tterminal.ECMA48; @@ -146,18 +148,33 @@ public class TTerminalWindow extends TScrollableWindow } /** - * Public constructor spawns a shell. + * Convert a string array to a whitespace-separated string. * - * @param application TApplication that manages this window - * @param x column relative to parent - * @param y row relative to parent - * @param flags mask of CENTERED, MODAL, or RESIZABLE + * @param array the string array + * @return a single string */ - public TTerminalWindow(final TApplication application, final int x, - final int y, final int flags) { + private String stringArrayToString(final String [] array) { + StringBuilder sb = new StringBuilder(array[0].length()); + for (int i = 0; i < array.length; i++) { + sb.append(array[i]); + if (i < array.length - 1) { + sb.append(' '); + } + } + return sb.toString(); + } - super(application, i18n.getString("windowTitle"), x, y, - 80 + 2, 24 + 2, flags); + /** + * Spawn the shell. + * + * @param command the command line to execute + */ + private void spawnShell(final String [] command) { + + /* + System.err.printf("spawnShell(): '%s'\n", + stringArrayToString(command)); + */ vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2); setBottomValue(0); @@ -166,43 +183,7 @@ public class TTerminalWindow extends TScrollableWindow ECMA48.DeviceType deviceType = ECMA48.DeviceType.XTERM; try { - String [] cmdShellWindows = { - "cmd.exe" - }; - - // You cannot run a login shell in a bare Process interactively, - // due to libc's behavior of buffering when stdin/stdout aren't a - // tty. Use 'script' instead to run a shell in a pty. And - // because BSD and GNU differ on the '-f' vs '-F' flags, we need - // two different commands. Lovely. - String [] cmdShellGNU = { - "script", "-fqe", "/dev/null" - }; - String [] cmdShellBSD = { - "script", "-q", "-F", "/dev/null" - }; - String [] cmdShellPtypipe = { - "ptypipe", "/bin/bash", "--login" - }; - // Spawn a shell and pass its I/O to the other constructor. - - ProcessBuilder pb; - if ((System.getProperty("jexer.TTerminal.ptypipe") != null) - && (System.getProperty("jexer.TTerminal.ptypipe"). - equals("true")) - ) { - pb = new ProcessBuilder(cmdShellPtypipe); - ptypipe = true; - } else if (System.getProperty("os.name").startsWith("Windows")) { - pb = new ProcessBuilder(cmdShellWindows); - } else if (System.getProperty("os.name").startsWith("Mac")) { - pb = new ProcessBuilder(cmdShellBSD); - } else if (System.getProperty("os.name").startsWith("Linux")) { - pb = new ProcessBuilder(cmdShellGNU); - } else { - // When all else fails, assume GNU. - pb = new ProcessBuilder(cmdShellGNU); - } + ProcessBuilder pb = new ProcessBuilder(command); Map env = pb.environment(); env.put("TERM", ECMA48.deviceTypeTerm(deviceType)); env.put("LANG", ECMA48.deviceTypeLang(deviceType, "en")); @@ -229,6 +210,117 @@ public class TTerminalWindow extends TScrollableWindow newStatusBar(i18n.getString("statusBarRunning")); } + /** + * Public constructor spawns a custom command line. + * + * @param application TApplication that manages this window + * @param x column relative to parent + * @param y row relative to parent + * @param commandLine the command line to execute + */ + public TTerminalWindow(final TApplication application, final int x, + final int y, final String commandLine) { + + this(application, x, y, RESIZABLE, commandLine.split("\\s")); + } + + /** + * Public constructor spawns a custom command line. + * + * @param application TApplication that manages this window + * @param x column relative to parent + * @param y row relative to parent + * @param flags mask of CENTERED, MODAL, or RESIZABLE + * @param command the command line to execute + */ + public TTerminalWindow(final TApplication application, final int x, + final int y, final int flags, final String [] command) { + + super(application, i18n.getString("windowTitle"), x, y, + 80 + 2, 24 + 2, flags); + + String [] fullCommand; + + // Spawn a shell and pass its I/O to the other constructor. + if ((System.getProperty("jexer.TTerminal.ptypipe") != null) + && (System.getProperty("jexer.TTerminal.ptypipe"). + equals("true")) + ) { + ptypipe = true; + fullCommand = new String[command.length + 1]; + fullCommand[0] = "ptypipe"; + System.arraycopy(command, 0, fullCommand, 1, command.length); + } else if (System.getProperty("os.name").startsWith("Windows")) { + fullCommand = new String[3]; + fullCommand[0] = "cmd"; + fullCommand[1] = "/c"; + fullCommand[2] = stringArrayToString(command); + } else if (System.getProperty("os.name").startsWith("Mac")) { + fullCommand = new String[6]; + fullCommand[0] = "script"; + fullCommand[1] = "-q"; + fullCommand[2] = "-F"; + fullCommand[3] = "/dev/null"; + fullCommand[4] = "-c"; + 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); + } + spawnShell(fullCommand); + } + + /** + * Public constructor spawns a shell. + * + * @param application TApplication that manages this window + * @param x column relative to parent + * @param y row relative to parent + * @param flags mask of CENTERED, MODAL, or RESIZABLE + */ + public TTerminalWindow(final TApplication application, final int x, + final int y, final int flags) { + + super(application, i18n.getString("windowTitle"), x, y, + 80 + 2, 24 + 2, flags); + + String cmdShellWindows = "cmd.exe"; + + // You cannot run a login shell in a bare Process interactively, due + // to libc's behavior of buffering when stdin/stdout aren't a tty. + // Use 'script' instead to run a shell in a pty. And because BSD and + // GNU differ on the '-f' vs '-F' flags, we need two different + // commands. Lovely. + String cmdShellGNU = "script -fqe /dev/null"; + String cmdShellBSD = "script -q -F /dev/null"; + + // ptypipe is another solution that permits dynamic window resizing. + String cmdShellPtypipe = "ptypipe /bin/bash --login"; + + // Spawn a shell and pass its I/O to the other constructor. + if ((System.getProperty("jexer.TTerminal.ptypipe") != null) + && (System.getProperty("jexer.TTerminal.ptypipe"). + equals("true")) + ) { + ptypipe = true; + spawnShell(cmdShellPtypipe.split("\\s")); + } else if (System.getProperty("os.name").startsWith("Windows")) { + spawnShell(cmdShellWindows.split("\\s")); + } else if (System.getProperty("os.name").startsWith("Mac")) { + spawnShell(cmdShellBSD.split("\\s")); + } else if (System.getProperty("os.name").startsWith("Linux")) { + spawnShell(cmdShellGNU.split("\\s")); + } else { + // When all else fails, assume GNU. + spawnShell(cmdShellGNU.split("\\s")); + } + } + /** * Terminate the child of the 'script' process used on POSIX. This may * or may not work. @@ -325,8 +417,18 @@ public class TTerminalWindow extends TScrollableWindow boolean reverse = line.isReverseColor() ^ ch.isReverse(); newCell.setReverse(false); if (reverse) { - newCell.setBackColor(ch.getForeColor()); - newCell.setForeColor(ch.getBackColor()); + 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()) { getScreen().putCharXY((i * 2) + 1, row, newCell); @@ -356,7 +458,7 @@ public class TTerminalWindow extends TScrollableWindow * Called by emulator when fresh data has come in. */ public void displayChanged() { - doRepaint(); + getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT)); } /** @@ -396,6 +498,13 @@ public class TTerminalWindow extends TScrollableWindow } } + /** + * Hook for subclasses to be notified of the shell termination. + */ + public void onShellExit() { + getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT)); + } + /** * Copy out variables from the emulator that TTerminal has to expose on * screen. @@ -435,6 +544,7 @@ public class TTerminalWindow extends TScrollableWindow clearShortcutKeypresses(); statusBar.setText(MessageFormat.format(i18n. getString("statusBarCompleted"), rc)); + onShellExit(); } catch (IllegalThreadStateException e) { // The emulator thread has exited, but the shell Process // hasn't figured that out yet. Do nothing, we will see @@ -452,6 +562,7 @@ public class TTerminalWindow extends TScrollableWindow clearShortcutKeypresses(); statusBar.setText(MessageFormat.format(i18n. getString("statusBarCompleted"), rc)); + onShellExit(); } catch (IllegalThreadStateException e) { // The shell is still running, do nothing. }