/*
* $Id$
*/
package charva.awt;
import java.util.LinkedList;
import java.util.Arrays;
import javax.naming.NameNotFoundException;
import org.jnode.driver.console.ConsoleManager;
import org.jnode.driver.console.TextConsole;
import org.jnode.driver.console.ConsoleListener;
import org.jnode.driver.console.ConsoleEvent;
import org.jnode.driver.input.KeyboardAdapter;
import org.jnode.driver.input.KeyboardEvent;
import org.jnode.driver.input.KeyboardListener;
import org.jnode.driver.input.PointerEvent;
import org.jnode.driver.input.PointerListener;
import org.jnode.naming.InitialNaming;
import org.jnode.shell.ShellManager;
import charva.awt.event.KeyEvent;
import charva.awt.event.MouseEvent;
/**
* @author vali
* @author Levente S\u00e1ntha
*/
public class Toolkit extends AbstractToolkit implements KeyboardListener,
PointerListener, ConsoleListener {
private static Toolkit instance = null;
private int[] colorpairs = new int[256];
// This is a mixed queue of Integer and MouseEvent instances
private LinkedList<Object> keyQueue = new LinkedList<Object>();
private final TextConsole console;
//private final int iniCurX;
//private final int iniCurY;
private int curX;
private int curY;
private int leftClip;
private int rightClip;
private int topClip;
private int bottomClip;
private boolean registered;
private ConsoleManager conMan;
// mouse state
private int prevMouseX = 0;
private int prevMouseY = 0;
boolean leftWasPressed = false;
boolean middleWasPressed = false;
boolean rightWasPressed = false;
// end of mouse state
private final boolean useBuffer = false;
protected Toolkit() {
throw new RuntimeException("Illegal use of constructor");
}
public Toolkit(TextConsole console, ConsoleManager conMan) {
this._evtQueue = EventQueue.getInstance();
/*
* If the terminal is capable of handling colors, initialize the color
* capability and the first color-pair (the default foreground and
* background colors are white-on-black, but can be modified by setting
* the static variables _defaultForeground and _defaultBackground.
*/
if (this.hasColors() && Toolkit.isColorEnabled) {
startColors();
_colorPairs.add(new ColorPair(_defaultForeground,
_defaultBackground));
}
this.conMan = conMan;
//if (!useBuffer) {
this.console = console;
// } else {
// BufferScreen bs = new BufferScreen(console.getWidth(), console
// .getHeight());
// try {
// buffer = new RawTextConsole(conMan, console.getConsoleName()
// + "_buffer", bs);
// } catch (ConsoleException e) {
// e.printStackTrace();
// }
// buffer.setCursorVisible(false);
// }
//this.console = console;
initConsole(console);
register();
}
/**
* This static method instantiates a Toolkit object if it does not already
* exist; and returns a reference to the instantiated Toolkit.
*/
// public static void pause() {
// try {
// Thread.sleep( 500 );
// }
// catch( InterruptedException e ) {
// e.printStackTrace();
// }
// }
public void unregister() {
if (registered) {
conMan.unregisterConsole(console);
registered = false;
}
}
public void register() {
if (registered) {
return;
}
registered = true;
conMan.registerConsole(console);
//System.out.println("Registering charva Toolkit with consoleManager.");
// pause();
conMan.focus(console);
console.clear();
}
public static void setDefaultToolkit(Toolkit tk) {
instance = tk;
}
public static synchronized Toolkit getDefaultToolkit() {
if (instance == null) {
instance = createInstance();
}
return instance;
}
private static Toolkit createInstance() {
try {
final ShellManager sm = InitialNaming.lookup(ShellManager.NAME);
final ConsoleManager conMgr = sm.getCurrentShell().getConsole().getManager();
final TextConsole console = (TextConsole) conMgr.createConsole(
"charva",
ConsoleManager.CreateOptions.TEXT |
ConsoleManager.CreateOptions.STACKED |
ConsoleManager.CreateOptions.NO_LINE_EDITTING);
console.addKeyboardListener(new KeyboardAdapter() {
public void keyPressed(KeyboardEvent event) {
if (event.isControlDown() && event.getKeyChar() == 'z') {
System.err.println("got ctrl-z, unregistering Toolkit.");
//maybe this will help to debug the finite-sized text
// area bug.
getDefaultToolkit().unregister();
event.consume();
}
}
});
return new Toolkit(console, conMgr);
} catch (NameNotFoundException e) {
throw new RuntimeException(e);
}
}
private void initConsole(TextConsole cons) {
// cons.setCursorVisible(false); //This may have to be commented out if charva items lose their cursor.
cons.setCursorVisible( true );//Keep this so TextComponents have a cursor.
cons.addKeyboardListener(this);
cons.addPointerListener(this);
curX = /* iniCurX = */console.getCursorX();
curY = /* iniCurY = */console.getCursorY();
resetClipRect();
}
public synchronized void waitTillFinished() {
while (isKeyboardReaderRunning()) {
try {
instance.wait();
} catch (InterruptedException ie) {
//ignore
}
}
close();
}
public void consoleClosed(ConsoleEvent event) {
synchronized(Toolkit.class){
instance = null;
}
}
public void close() {
unregister();
synchronized(Toolkit.class){
instance = null;
}
//this could kill threads, etc. But let's save 'em for if this instance
// comes up again.
// System.err.println( "In close(), calling clear" );
// pause();
// clear();
// System.err.println( "Stopping SyncQueue" );
// pause();
// SyncQueue.getInstance().stop();
// System.err.println( "Stopping KeyboardReader" );
// pause();
// setKeyboardReaderRunning( false );
// System.err.println( "Skipping KeyQueue.Notify all" );
// pause();
//// keyQueue.notifyAll();
// System.err.println( "Closing console: " + console.getConsoleName() +
// ": " + console.getClass().getName() );
// pause();
//
// System.err.println( "Unregistering" );
// unregister();
// System.err.println( "Returning from close()" );
// pause();
}
public void clear() {
console.clear();
}
public void setCursor(int x_, int y_) {
curX = x_;
curY = y_;
console.setCursor(x_, y_);
}
public void addChar(int chr, int attrib, int colorpair_) {
putCharWithClip(chr, attrib, colorpair_);
}
public void addVerticalLine(int length, int attrib, int colorpair) {
int x = curX;
for (int ln = curY + length, i = curY; i < ln; i++) {
setCursor(x, i);
putCharWithClip(ACS_VLINE, attrib, colorpair);
}
}
public void setCursorVisible(boolean visible) {
console.setCursorVisible(visible);
}
public void addString(String str_, int attrib_, int colorpair_) {
if (str_ == null) {
return;
}
putCharsWithClip(str_.toCharArray(), attrib_, colorpair_);
}
public void drawBoxNative(int left_, int top_, int right_, int bottom_,
int colorpair_) {
setCharWithClip(left_, top_, ACS_ULCORNER, colorpair_);
setCharsWithClip(left_ + 1, top_, ACS_HLINE, colorpair_, right_ - left_ - 1);
setCharWithClip(left_, bottom_, ACS_LLCORNER, colorpair_);
setCharsWithClip(left_ + 1, bottom_, ACS_HLINE, colorpair_, right_ - left_ - 1);
setCharWithClip(right_, top_, ACS_URCORNER, colorpair_);
for (int j = top_ + 1; j < bottom_; j++) {
setCharWithClip(left_, j, ACS_VLINE, colorpair_);
}
setCharWithClip(right_, bottom_, ACS_LRCORNER, colorpair_);
for (int j = top_ + 1; j < bottom_; j++) {
setCharWithClip(right_, j, ACS_VLINE, colorpair_);
}
}
public void blankBoxNative(int left_, int top_, int right_, int bottom_,
int colorpair_) {
int width = right_ - left_;
for (int j = top_; j < bottom_; j++) {
setCharsWithClip(left_, j, ' ', colorpair_, width);
}
}
public void setClipRectNative(int left_, int top_, int right_, int bottom_) {
leftClip = left_;
rightClip = right_;
topClip = top_;
bottomClip = bottom_;
}
public void resetClipRect() {
leftClip = 0;
rightClip = console.getWidth();
topClip = 0;
bottomClip = console.getHeight();
}
public void beep() {
// SpeakerUtils.beep();
}
public int getScreenRows() {
return console.getHeight();
}
public int getScreenColumns() {
return console.getWidth();
}
public boolean hasColors() {
return true;
}
public int getMaxColorPairs() {
return 256;
}
public void startColors() {
}
public void sync() {
if (useBuffer) {
//buffer.copyTo(console);
}
}
public void initColorPair(int index, int fgnd_, int bgnd_)
throws TerminfoCapabilityException {
colorpairs[index] = ((0xF & bgnd_) << 4) | (0xF & fgnd_);
}
public String getTtyName() {
return console.getConsoleName();
}
protected Object readKey() {
synchronized (keyQueue) {
while (keyQueue.isEmpty() && isKeyboardReaderRunning()) {
try {
keyQueue.wait();
} catch (InterruptedException ie) {
}
}
if (isKeyboardReaderRunning()) {
return keyQueue.removeFirst();
} else {
return null;
}
}
}
protected int getx() {
return console.getCursorX();
}
protected int gety() {
return console.getCursorY();
}
public void keyPressed(KeyboardEvent event) {
synchronized (keyQueue) {
int key_code = event.getKeyCode();
int key_char = event.getKeyChar();
int key;
switch (key_code) {
case java.awt.event.KeyEvent.VK_LEFT:
key = KeyEvent.VK_LEFT;
break;
case java.awt.event.KeyEvent.VK_RIGHT:
key = KeyEvent.VK_RIGHT;
break;
case java.awt.event.KeyEvent.VK_UP:
key = KeyEvent.VK_UP;
break;
case java.awt.event.KeyEvent.VK_DOWN:
key = KeyEvent.VK_DOWN;
break;
case java.awt.event.KeyEvent.VK_PAGE_DOWN:
key = KeyEvent.VK_PAGE_DOWN;
break;
case java.awt.event.KeyEvent.VK_PAGE_UP:
key = KeyEvent.VK_PAGE_UP;
break;
case java.awt.event.KeyEvent.VK_HOME:
key = KeyEvent.VK_HOME;
break;
case java.awt.event.KeyEvent.VK_END:
key = KeyEvent.VK_END;
break;
case java.awt.event.KeyEvent.VK_BACK_SPACE:
key = KeyEvent.VK_BACK_SPACE;
break;
case java.awt.event.KeyEvent.VK_INSERT:
key = KeyEvent.VK_INSERT;
break;
case java.awt.event.KeyEvent.VK_DELETE:
key = KeyEvent.VK_DELETE;
break;
case java.awt.event.KeyEvent.VK_ENTER:
key = KeyEvent.VK_ENTER;
break;
case java.awt.event.KeyEvent.VK_ESCAPE:
key = KeyEvent.VK_ESCAPE;
break;
case java.awt.event.KeyEvent.VK_F1:
case java.awt.event.KeyEvent.VK_F2:
case java.awt.event.KeyEvent.VK_F3:
case java.awt.event.KeyEvent.VK_F4:
case java.awt.event.KeyEvent.VK_F5:
case java.awt.event.KeyEvent.VK_F6:
case java.awt.event.KeyEvent.VK_F7:
case java.awt.event.KeyEvent.VK_F8:
case java.awt.event.KeyEvent.VK_F9:
case java.awt.event.KeyEvent.VK_F10:
case java.awt.event.KeyEvent.VK_F11:
case java.awt.event.KeyEvent.VK_F12:
case java.awt.event.KeyEvent.VK_F13:
case java.awt.event.KeyEvent.VK_F14:
case java.awt.event.KeyEvent.VK_F15:
case java.awt.event.KeyEvent.VK_F16:
case java.awt.event.KeyEvent.VK_F17:
case java.awt.event.KeyEvent.VK_F18:
case java.awt.event.KeyEvent.VK_F19:
case java.awt.event.KeyEvent.VK_F20:
key = KeyEvent.VK_F1 + key_code - java.awt.event.KeyEvent.VK_F1;
break;
default:
key = key_char;
}
keyQueue.add(new Integer(key));
keyQueue.notifyAll();
event.consume();
}
}
public void keyReleased(KeyboardEvent event) {
}
private void setCharWithClip(int x, int y, int ch, int cp) {
if (x >= leftClip && x <= rightClip && y >= topClip && y <= bottomClip) {
if (console != null) {
console.setChar(x, y, (char) ch, colorpairs[cp]);
}
}
}
private void setCharsWithClip(int x, int y, int ch, int cp, int nbCopy) {
if (x >= leftClip && x <= rightClip && y >= topClip && y <= bottomClip) {
if (console != null) {
char c = (char) ch;
int color = colorpairs[cp];
int xmax = Math.min(x + nbCopy, rightClip + 1);
int ln = xmax - x;
if(ln > 0){
char[] chars = new char[ln];
Arrays.fill(chars, c);
console.setChar(x, y, chars, color);
}
}
}
}
private void putCharWithClip(int ch, int att, int cp) {
if (curY >= topClip && curY <= bottomClip && curX >= leftClip
&& curX <= rightClip) {
console.putChar((char) ch, computeColor(att, cp));
curX++;
}
}
private void putCharsWithClip(char[] chars, int att, int cp) {
if (curY >= topClip && curY <= bottomClip && curX >= leftClip
&& curX <= rightClip) {
int xmax = Math.min(curX + chars.length, rightClip + 1);
int cx = console.getCursorX();
int cy = console.getCursorY();
int length = xmax - curX;
if(length > 0){
console.setChar(cx, cy, chars, 0, length, computeColor(att, cp));
console.setCursor(cx + length, cy);
curX += length;
}
}
}
private int computeColor(int att, int cp) {
int c = colorpairs[cp];
if ((att & A_REVERSE) != 0) {
c = ((c << 4) & 0xF0) | ((c >> 4) & 0xF);
}
if ((att & A_UNDERLINE) != 0) {
c = c | 8;
}
if ((att & A_BOLD) != 0) {
c = c | 8;
}
int bu = A_BOLD | A_UNDERLINE;
if ((att & bu) == bu) {
c = c ^ 0xFF;
}
return c;
}
/**
*
*/
public void pointerStateChanged(PointerEvent event) {
synchronized (keyQueue) {
int x = prevMouseX;
int y = prevMouseY;
// compute the new mouse position
if (event.isRelative()) {
//System.err.println("relative x="+event.getX()+"
// y="+event.getY());
x += event.getX();
y += event.getY();
} else if (event.isAbsolute()) {
//System.err.println("absolute x="+event.getX()+"
// y="+event.getY());
x = event.getX();
y = event.getY();
}
//System.err.println("x="+event.getX()+" y="+event.getY());
int button = -1;
int modifiers = 0;
if (leftWasPressed && !event.isLeftButtonPressed()) {
button = MouseEvent.BUTTON1;
modifiers = MouseEvent.MOUSE_RELEASED;
} else if (!leftWasPressed && event.isLeftButtonPressed()) {
button = MouseEvent.BUTTON1;
modifiers = MouseEvent.MOUSE_PRESSED;
} else if (middleWasPressed && !event.isMiddleButtonPressed()) {
button = MouseEvent.BUTTON2;
modifiers = MouseEvent.MOUSE_RELEASED;
} else if (!middleWasPressed && event.isMiddleButtonPressed()) {
button = MouseEvent.BUTTON2;
modifiers = MouseEvent.MOUSE_PRESSED;
} else if (rightWasPressed && !event.isRightButtonPressed()) {
button = MouseEvent.BUTTON3;
modifiers = MouseEvent.MOUSE_RELEASED;
} else if (!rightWasPressed && event.isRightButtonPressed()) {
button = MouseEvent.BUTTON3;
modifiers = MouseEvent.MOUSE_PRESSED;
}
// save the current mouse state
leftWasPressed = event.isLeftButtonPressed();
middleWasPressed = event.isMiddleButtonPressed();
rightWasPressed = event.isRightButtonPressed();
prevMouseX = x;
prevMouseY = y;
Component component = getComponentAt(x, y);
if (component != null) {
MouseEvent me = new MouseEvent(component, modifiers, x, y, 0,
button);
keyQueue.add(me);
keyQueue.notifyAll();
}
}
}
//NOT USED
// public void redrawWin() {
// }
// public String getStringCapability(String capname_)
// throws TerminfoCapabilityException {
// return null;
// }
// public int getNumericCapability(String capname_)
// throws TerminfoCapabilityException {
// return 0;
// }
//NOT USED
// public boolean getBooleanCapability(String capname_)
// throws TerminfoCapabilityException {
// return false;
// }
//NOT USED
// public void putp(String str_) {
// }
//NOT USED
// public void print(String str_) throws TerminfoCapabilityException {
// }
//NOT USED
// public void addHorizontalLine(int length_, int attrib_, int colorpair) {
// }
}