Rename AWT to Swing

This commit is contained in:
Kevin Lamonte 2015-03-21 19:14:34 -04:00
parent 091d8a06c7
commit a4406f4ed7
9 changed files with 188 additions and 117 deletions

View file

@ -1,7 +1,8 @@
Jexer - Java Text User Interface library Jexer - Java Text User Interface library
======================================== ========================================
WARNING: THIS IS ALPHA CODE! WARNING: THIS IS ALPHA CODE! PLEASE CONSIDER FILING BUGS AS YOU
ENCOUNTER THEM.
This library is intended to implement a text-based windowing system This library is intended to implement a text-based windowing system
loosely reminiscient of Borland's [Turbo loosely reminiscient of Borland's [Turbo
@ -16,16 +17,20 @@ Two backends are available:
(tested on Linux + xterm). I/O is handled through terminal escape (tested on Linux + xterm). I/O is handled through terminal escape
sequences generated by the library itself: ncurses is not required sequences generated by the library itself: ncurses is not required
or linked to. xterm mouse tracking using UTF8 coordinates is or linked to. xterm mouse tracking using UTF8 coordinates is
supported. This is the default backend on non-Windows platforms. supported. For the demo application, this is the default backend on
non-Windows platforms.
* Java AWT UI. This backend can be selected by setting * Java Swing UI. This backend can be selected by setting
jexer.AWT=true. This is the default backend on Windows platforms. jexer.Swing=true. The default window size for Swing is 132x40,
AWT is experimental, please consider filing bugs when you encounter which is set in jexer.session.SwingSession. For the demo
them. The default window size for AWT is 132x40, which is set in application, this is the default backend on Windows platforms.
jexer.session.AWTSession.
A demo application showing the existing UI controls is available via The demo application showing the existing UI controls is available via
'java -jar jexer.jar' or 'java -Djexer.AWT=true -jar jexer.jar' . 'java -jar jexer.jar' or 'java -Djexer.Swing=true -jar jexer.jar' .
Additional backends can be created by subclassing
jexer.backend.Backend and passing it into the TApplication
constructor.
@ -55,7 +60,7 @@ Usage
----- -----
Usage patterns are still being worked on, but in general the goal will Usage patterns are still being worked on, but in general the goal will
be to build applications somewhat as follows: be to build applications as follows:
```Java ```Java
import jexer.*; import jexer.*;
@ -63,7 +68,7 @@ import jexer.*;
public class MyApplication extends TApplication { public class MyApplication extends TApplication {
public MyApplication() { public MyApplication() {
super(); super(BackendType.SWING); // Could also use BackendType.XTERM
// Create standard menus for File and Window // Create standard menus for File and Window
addFileMenu(); addFileMenu();
@ -72,7 +77,7 @@ public class MyApplication extends TApplication {
public static void main(String [] args) { public static void main(String [] args) {
MyApplication app = new MyApplication(); MyApplication app = new MyApplication();
app.run(); (new Thread(app)).start();
} }
} }
``` ```
@ -100,6 +105,10 @@ ambiguous. This section describes such issues.
- See jexer.tterminal.ECMA48 for more specifics of terminal - See jexer.tterminal.ECMA48 for more specifics of terminal
emulation limitations. emulation limitations.
- TTerminalWindow uses cmd.exe on Windows. Output will not be seen
until enter is pressed, due to cmd.exe's use of line-oriented
input (see the ENABLE_LINE_INPUT flag for GetConsoleMode() and
SetConsoleMode()).
@ -108,15 +117,14 @@ Roadmap
Many tasks remain before calling this version 1.0: Many tasks remain before calling this version 1.0:
0.0.2: 0.0.2: STABILIZE EXISTING
- Making TMenu keyboard accelerators active/inactive - TTerminalWindow
- AWT: - Expose shell commands as properties
- Swing:
- Blinking cursor - Blinking cursor
- Block cursor - Block cursor
- ECMA48Backend running on socket - ECMA48Backend running on socket
- TTreeView
- TDirectoryList
- TFileOpen - TFileOpen
- Decide on naming convention: getText, getValue, getLabel: one or all - Decide on naming convention: getText, getValue, getLabel: one or all
of them? of them?
@ -125,36 +133,42 @@ Many tasks remain before calling this version 1.0:
- getCh() --> getChar() - getCh() --> getChar()
- getAlt/getCtrl/getShift --> isAltDown / isCtrlDown / isShiftDown - getAlt/getCtrl/getShift --> isAltDown / isCtrlDown / isShiftDown
- Other boolean getters --> isSomething - Other boolean getters --> isSomething
- Document any properties used
- Expose use of 'stty'
0.0.3: 0.0.3: FINISH PORTING
- TTreeView
- Also add keyboard navigation
- TDirectoryList
- Also add keyboard navigation
0.0.4: NEW STUFF
- Making TMenu keyboard accelerators active/inactive
- TStatusBar - TStatusBar
- TEditor - TEditor
0.0.4:
- Bugs
- TSubMenu keyboard mnemonic not working
- TDirectoryList cannot be navigated only with keyboard
- TTreeView cannot be navigated only with keyboard
- RangeViolation after dragging scrollbar up/down
0.1.0:
- TWindow - TWindow
- "Smart placement" for new windows - "Smart placement" for new windows
0.0.5: BUG HUNT
- TSubMenu keyboard mnemonic not working
0.1.0: BETA RELEASE
- TSpinner
- TComboBox
- TListBox
- TCalendar
- TColorPicker
Wishlist features (2.0): Wishlist features (2.0):
- TTerminal - TTerminal
- Handle resize events (pass to child process) - Handle resize events (pass to child process)
- Screen - Screen
- Allow complex characters in putCharXY() and detect them in putStrXY(). - Allow complex characters in putCharXY() and detect them in putStrXY().
- TComboBox
- TListBox
- TSpinner
- TCalendar widget
- TColorPicker widget
- Drag and drop - Drag and drop
- TEditor - TEditor
- TField - TField

View file

@ -35,9 +35,11 @@
<property name="build.dir" value="build"/> <property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/> <property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/> <property name="jar.dir" value="${build.dir}/jar"/>
<property name="apidocs.dir" value="docs/api"/>
<target name="clean"> <target name="clean">
<delete dir="${build.dir}"/> <delete dir="${build.dir}"/>
<delete dir="${apidocs.dir}"/>
</target> </target>
<target name="compile"> <target name="compile">
@ -62,7 +64,7 @@
<target name="run" depends="jar"> <target name="run" depends="jar">
<java jar="${jar.dir}/${ant.project.name}.jar" fork="true"> <java jar="${jar.dir}/${ant.project.name}.jar" fork="true">
<arg value="-Djexer.AWT=true"/> <arg value="-Djexer.Swing=true"/>
</java> </java>
</target> </target>
@ -74,7 +76,7 @@
<target name="docs" depends="jar"> <target name="docs" depends="jar">
<javadoc <javadoc
destdir="docs/api" destdir="${apidocs.dir}"
author="true" author="true"
version="true" version="true"
use="true" use="true"

View file

@ -51,7 +51,7 @@ import jexer.event.TMenuEvent;
import jexer.event.TMouseEvent; import jexer.event.TMouseEvent;
import jexer.event.TResizeEvent; import jexer.event.TResizeEvent;
import jexer.backend.Backend; import jexer.backend.Backend;
import jexer.backend.AWTBackend; import jexer.backend.SwingBackend;
import jexer.backend.ECMA48Backend; import jexer.backend.ECMA48Backend;
import jexer.io.Screen; import jexer.io.Screen;
import jexer.menu.TMenu; import jexer.menu.TMenu;
@ -61,7 +61,7 @@ import static jexer.TCommand.*;
/** /**
* TApplication sets up a full Text User Interface application. * TApplication sets up a full Text User Interface application.
*/ */
public class TApplication { public class TApplication implements Runnable {
/** /**
* If true, emit thread stuff to System.err. * If true, emit thread stuff to System.err.
@ -73,6 +73,26 @@ public class TApplication {
*/ */
private static final boolean debugEvents = false; private static final boolean debugEvents = false;
/**
* Two backend types are available.
*/
public static enum BackendType {
/**
* A Swing JFrame.
*/
SWING,
/**
* An ECMA48 / ANSI X3.64 / XTERM style terminal.
*/
ECMA48,
/**
* Synonym for ECMA48
*/
XTERM
}
/** /**
* WidgetEventHandler is the main event consumer loop. There are at most * WidgetEventHandler is the main event consumer loop. There are at most
* two such threads in existence: the primary for normal case and a * two such threads in existence: the primary for normal case and a
@ -461,6 +481,29 @@ public class TApplication {
/** /**
* Public constructor. * Public constructor.
* *
* @param backendType BackendType.XTERM, BackendType.ECMA48 or
* BackendType.SWING
* @throws UnsupportedEncodingException if an exception is thrown when
* creating the InputStreamReader
*/
public TApplication(final BackendType backendType)
throws UnsupportedEncodingException {
switch (backendType) {
case SWING:
backend = new SwingBackend(this);
break;
case XTERM:
// Fall through...
case ECMA48:
backend = new ECMA48Backend(this, null, null);
}
TApplicationImpl();
}
/**
* Public constructor. The backend type will be BackendType.ECMA48.
*
* @param input an InputStream connected to the remote user, or null for * @param input an InputStream connected to the remote user, or null for
* System.in. If System.in is used, then on non-Windows systems it will * System.in. If System.in is used, then on non-Windows systems it will
* be put in raw mode; shutdown() will (blindly!) put System.in in cooked * be put in raw mode; shutdown() will (blindly!) put System.in in cooked
@ -474,26 +517,25 @@ public class TApplication {
public TApplication(final InputStream input, public TApplication(final InputStream input,
final OutputStream output) throws UnsupportedEncodingException { final OutputStream output) throws UnsupportedEncodingException {
// AWT is the default backend on Windows unless explicitly overridden backend = new ECMA48Backend(this, input, output);
// by jexer.AWT. TApplicationImpl();
boolean useAWT = false; }
if (System.getProperty("os.name").startsWith("Windows")) {
useAWT = true;
}
if (System.getProperty("jexer.AWT") != null) {
if (System.getProperty("jexer.AWT", "false").equals("true")) {
useAWT = true;
} else {
useAWT = false;
}
}
/**
* Public constructor. This hook enables use with new non-Jexer
* backends.
*
* @param backend a Backend that is already ready to go.
*/
public TApplication(final Backend backend) {
this.backend = backend;
TApplicationImpl();
}
if (useAWT) { /**
backend = new AWTBackend(this); * Finish construction once the backend is set.
} else { */
backend = new ECMA48Backend(this, input, output); private void TApplicationImpl() {
}
theme = new ColorTheme(); theme = new ColorTheme();
desktopBottom = getScreen().getHeight() - 1; desktopBottom = getScreen().getHeight() - 1;
fillEventQueue = new ArrayList<TInputEvent>(); fillEventQueue = new ArrayList<TInputEvent>();
@ -638,7 +680,7 @@ public class TApplication {
/** /**
* Run this application until it exits. * Run this application until it exits.
*/ */
public final void run() { public void run() {
while (!quit) { while (!quit) {
// Timeout is in milliseconds, so default timeout after 1 second // Timeout is in milliseconds, so default timeout after 1 second
// of inactivity. // of inactivity.

View file

@ -33,19 +33,19 @@ package jexer.backend;
import java.util.List; import java.util.List;
import jexer.event.TInputEvent; import jexer.event.TInputEvent;
import jexer.io.AWTScreen; import jexer.io.SwingScreen;
import jexer.io.AWTTerminal; import jexer.io.SwingTerminal;
/** /**
* This class uses standard AWT calls to handle screen, keyboard, and mouse * This class uses standard Swing calls to handle screen, keyboard, and mouse
* I/O. * I/O.
*/ */
public final class AWTBackend extends Backend { public final class SwingBackend extends Backend {
/** /**
* Input events are processed by this Terminal. * Input events are processed by this Terminal.
*/ */
private AWTTerminal terminal; private SwingTerminal terminal;
/** /**
* Public constructor. * Public constructor.
@ -53,13 +53,13 @@ public final class AWTBackend extends Backend {
* @param listener the object this backend needs to wake up when new * @param listener the object this backend needs to wake up when new
* input comes in * input comes in
*/ */
public AWTBackend(final Object listener) { public SwingBackend(final Object listener) {
// Create a screen // Create a screen
AWTScreen screen = new AWTScreen(); SwingScreen screen = new SwingScreen();
this.screen = screen; this.screen = screen;
// Create the AWT event listeners // Create the Swing event listeners
terminal = new AWTTerminal(listener, screen); terminal = new SwingTerminal(listener, screen);
// Hang onto the session info // Hang onto the session info
this.sessionInfo = terminal.getSessionInfo(); this.sessionInfo = terminal.getSessionInfo();

View file

@ -446,10 +446,11 @@ class DemoApplication extends TApplication {
/** /**
* Public constructor. * Public constructor.
* *
* @param backendType one of the TApplication.BackendType values
* @throws Exception if TApplication can't instantiate the Backend. * @throws Exception if TApplication can't instantiate the Backend.
*/ */
public DemoApplication() throws Exception { public DemoApplication(BackendType backendType) throws Exception {
super(null, null); super(backendType);
new DemoMainWindow(this); new DemoMainWindow(this);
// Add the menus // Add the menus
@ -494,8 +495,21 @@ public class Demo1 {
*/ */
public static void main(final String [] args) { public static void main(final String [] args) {
try { try {
DemoApplication app = new DemoApplication(); // Swing is the default backend on Windows unless explicitly
app.run(); // overridden by jexer.Swing.
TApplication.BackendType backendType = TApplication.BackendType.XTERM;
if (System.getProperty("os.name").startsWith("Windows")) {
backendType = TApplication.BackendType.SWING;
}
if (System.getProperty("jexer.Swing") != null) {
if (System.getProperty("jexer.Swing", "false").equals("true")) {
backendType = TApplication.BackendType.SWING;
} else {
backendType = TApplication.BackendType.XTERM;
}
}
DemoApplication app = new DemoApplication(backendType);
(new Thread(app)).start();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View file

@ -32,7 +32,7 @@ package jexer.io;
import jexer.bits.Cell; import jexer.bits.Cell;
import jexer.bits.CellAttributes; import jexer.bits.CellAttributes;
import jexer.session.AWTSessionInfo; import jexer.session.SwingSessionInfo;
import java.awt.Color; import java.awt.Color;
import java.awt.Cursor; import java.awt.Cursor;
@ -50,9 +50,9 @@ import javax.swing.JFrame;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
/** /**
* This Screen implementation draws to a Java AWT Frame. * This Screen implementation draws to a Java Swing JFrame.
*/ */
public final class AWTScreen extends Screen { public final class SwingScreen extends Screen {
private static Color MYBLACK; private static Color MYBLACK;
private static Color MYRED; private static Color MYRED;
@ -75,7 +75,7 @@ public final class AWTScreen extends Screen {
private static boolean dosColors = false; private static boolean dosColors = false;
/** /**
* Setup AWT colors to match DOS color palette. * Setup Swing colors to match DOS color palette.
*/ */
private static void setDOSColors() { private static void setDOSColors() {
if (dosColors) { if (dosColors) {
@ -102,9 +102,9 @@ public final class AWTScreen extends Screen {
} }
/** /**
* AWTFrame is our top-level hook into the AWT system. * SwingFrame is our top-level hook into the Swing system.
*/ */
class AWTFrame extends JFrame { class SwingFrame extends JFrame {
/** /**
* Serializable version. * Serializable version.
@ -119,7 +119,7 @@ public final class AWTScreen extends Screen {
/** /**
* The TUI Screen data. * The TUI Screen data.
*/ */
AWTScreen screen; SwingScreen screen;
/** /**
* Width of a character cell. * Width of a character cell.
@ -147,10 +147,10 @@ public final class AWTScreen extends Screen {
private int left = 30; private int left = 30;
/** /**
* Convert a CellAttributes foreground color to an AWT Color. * Convert a CellAttributes foreground color to an Swing Color.
* *
* @param attr the text attributes * @param attr the text attributes
* @return the AWT Color * @return the Swing Color
*/ */
private Color attrToForegroundColor(final CellAttributes attr) { private Color attrToForegroundColor(final CellAttributes attr) {
/* /*
@ -200,10 +200,10 @@ public final class AWTScreen extends Screen {
} }
/** /**
* Convert a CellAttributes background color to an AWT Color. * Convert a CellAttributes background color to an Swing Color.
* *
* @param attr the text attributes * @param attr the text attributes
* @return the AWT Color * @return the Swing Color
*/ */
private Color attrToBackgroundColor(final CellAttributes attr) { private Color attrToBackgroundColor(final CellAttributes attr) {
/* /*
@ -237,7 +237,7 @@ public final class AWTScreen extends Screen {
* *
* @param screen the Screen that Backend talks to * @param screen the Screen that Backend talks to
*/ */
public AWTFrame(final AWTScreen screen) { public SwingFrame(final SwingScreen screen) {
this.screen = screen; this.screen = screen;
setDOSColors(); setDOSColors();
@ -310,7 +310,7 @@ public final class AWTScreen extends Screen {
/** /**
* Update redraws the whole screen. * Update redraws the whole screen.
* *
* @param gr the AWT Graphics context * @param gr the Swing Graphics context
*/ */
@Override @Override
public void update(final Graphics gr) { public void update(final Graphics gr) {
@ -322,7 +322,7 @@ public final class AWTScreen extends Screen {
/** /**
* Paint redraws the whole screen. * Paint redraws the whole screen.
* *
* @param gr the AWT Graphics context * @param gr the Swing Graphics context
*/ */
@Override @Override
public void paint(final Graphics gr) { public void paint(final Graphics gr) {
@ -420,31 +420,31 @@ public final class AWTScreen extends Screen {
} // synchronized (screen) } // synchronized (screen)
} }
} // class AWTFrame } // class SwingFrame
/** /**
* The raw AWT Frame. Note package private access. * The raw Swing JFrame. Note package private access.
*/ */
AWTFrame frame; SwingFrame frame;
/** /**
* Public constructor. * Public constructor.
*/ */
public AWTScreen() { public SwingScreen() {
try { try {
SwingUtilities.invokeAndWait(new Runnable() { SwingUtilities.invokeAndWait(new Runnable() {
public void run() { public void run() {
AWTScreen.this.frame = new AWTFrame(AWTScreen.this); SwingScreen.this.frame = new SwingFrame(SwingScreen.this);
AWTScreen.this.sessionInfo = SwingScreen.this.sessionInfo =
new AWTSessionInfo(AWTScreen.this.frame, new SwingSessionInfo(SwingScreen.this.frame,
frame.textWidth, frame.textWidth,
frame.textHeight); frame.textHeight);
AWTScreen.this.setDimensions(sessionInfo.getWindowWidth(), SwingScreen.this.setDimensions(sessionInfo.getWindowWidth(),
sessionInfo.getWindowHeight()); sessionInfo.getWindowHeight());
AWTScreen.this.frame.resizeToScreen(); SwingScreen.this.frame.resizeToScreen();
AWTScreen.this.frame.setVisible(true); SwingScreen.this.frame.setVisible(true);
} }
} ); } );
} catch (Exception e) { } catch (Exception e) {
@ -455,14 +455,14 @@ public final class AWTScreen extends Screen {
/** /**
* The sessionInfo. * The sessionInfo.
*/ */
private AWTSessionInfo sessionInfo; private SwingSessionInfo sessionInfo;
/** /**
* Create the AWTSessionInfo. Note package private access. * Create the SwingSessionInfo. Note package private access.
* *
* @return the sessionInfo * @return the sessionInfo
*/ */
AWTSessionInfo getSessionInfo() { SwingSessionInfo getSessionInfo() {
return sessionInfo; return sessionInfo;
} }

View file

@ -51,26 +51,26 @@ import jexer.event.TKeypressEvent;
import jexer.event.TMouseEvent; import jexer.event.TMouseEvent;
import jexer.event.TResizeEvent; import jexer.event.TResizeEvent;
import jexer.session.SessionInfo; import jexer.session.SessionInfo;
import jexer.session.AWTSessionInfo; import jexer.session.SwingSessionInfo;
import static jexer.TCommand.*; import static jexer.TCommand.*;
import static jexer.TKeypress.*; import static jexer.TKeypress.*;
/** /**
* This class reads keystrokes and mouse events from an AWT Frame. * This class reads keystrokes and mouse events from an Swing JFrame.
*/ */
public final class AWTTerminal implements ComponentListener, KeyListener, public final class SwingTerminal implements ComponentListener, KeyListener,
MouseListener, MouseMotionListener, MouseListener, MouseMotionListener,
MouseWheelListener, WindowListener { MouseWheelListener, WindowListener {
/** /**
* The backend Screen. * The backend Screen.
*/ */
private AWTScreen screen; private SwingScreen screen;
/** /**
* The session information. * The session information.
*/ */
private AWTSessionInfo sessionInfo; private SwingSessionInfo sessionInfo;
/** /**
* Getter for sessionInfo. * Getter for sessionInfo.
@ -132,9 +132,9 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
* *
* @param listener the object this backend needs to wake up when new * @param listener the object this backend needs to wake up when new
* input comes in * input comes in
* @param screen the top-level AWT frame * @param screen the top-level Swing frame
*/ */
public AWTTerminal(final Object listener, final AWTScreen screen) { public SwingTerminal(final Object listener, final SwingScreen screen) {
this.listener = listener; this.listener = listener;
this.screen = screen; this.screen = screen;
mouse1 = false; mouse1 = false;
@ -176,7 +176,7 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
} }
/** /**
* Pass AWT keystrokes into the event queue. * Pass Swing keystrokes into the event queue.
* *
* @param key keystroke received * @param key keystroke received
*/ */
@ -186,7 +186,7 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
} }
/** /**
* Pass AWT keystrokes into the event queue. * Pass Swing keystrokes into the event queue.
* *
* @param key keystroke received * @param key keystroke received
*/ */
@ -196,7 +196,7 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
} }
/** /**
* Pass AWT keystrokes into the event queue. * Pass Swing keystrokes into the event queue.
* *
* @param key keystroke received * @param key keystroke received
*/ */
@ -217,7 +217,7 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
shift = key.isShiftDown(); shift = key.isShiftDown();
/* /*
System.err.printf("AWT Key: %s\n", key); System.err.printf("Swing Key: %s\n", key);
System.err.printf(" isKey: %s\n", isKey); System.err.printf(" isKey: %s\n", isKey);
System.err.printf(" alt: %s\n", alt); System.err.printf(" alt: %s\n", alt);
System.err.printf(" ctrl: %s\n", ctrl); System.err.printf(" ctrl: %s\n", ctrl);

View file

@ -34,14 +34,14 @@ import java.awt.Frame;
import java.awt.Insets; import java.awt.Insets;
/** /**
* AWTSessionInfo provides a session implementation with a callback into an * SwingSessionInfo provides a session implementation with a callback into an
* AWT Frame to support queryWindowSize(). The username is blank, language * Swing Frame to support queryWindowSize(). The username is blank, language
* is "en_US", with a 132x40 text window. * is "en_US", with a 132x40 text window.
*/ */
public final class AWTSessionInfo implements SessionInfo { public final class SwingSessionInfo implements SessionInfo {
/** /**
* The AWT Frame. * The Swing Frame.
*/ */
private Frame frame; private Frame frame;
@ -132,11 +132,11 @@ public final class AWTSessionInfo implements SessionInfo {
/** /**
* Public constructor. * Public constructor.
* *
* @param frame the AWT Frame * @param frame the Swing Frame
* @param textWidth the width of a cell in pixels * @param textWidth the width of a cell in pixels
* @param textHeight the height of a cell in pixels * @param textHeight the height of a cell in pixels
*/ */
public AWTSessionInfo(final Frame frame, final int textWidth, public SwingSessionInfo(final Frame frame, final int textWidth,
final int textHeight) { final int textHeight) {
this.frame = frame; this.frame = frame;

View file

@ -38,9 +38,8 @@ import java.util.StringTokenizer;
/** /**
* TTYSessionInfo queries environment variables and the tty window size for * TTYSessionInfo queries environment variables and the tty window size for
* the session information. The username is taken from * the session information. The username is taken from user.name, language
* getpwuid(geteuid()).pw_name, language is taken from LANG, and text window * is taken from user.language, and text window size from 'stty size'.
* size from ioctl(TIOCGWINSIZ).
*/ */
public final class TTYSessionInfo implements SessionInfo { public final class TTYSessionInfo implements SessionInfo {