- /**
- * Copy out variables from the emulator that TTerminal has to expose on
- * screen.
- */
- private void readEmulatorState() {
- // Synchronize against the emulator so we don't stomp on its reader
- // thread.
- synchronized (emulator) {
- setHiddenMouse(emulator.hasHiddenMousePointer());
-
- setCursorX(emulator.getCursorX() + 1);
- setCursorY(emulator.getCursorY() + 1
- + (getHeight() - 2 - emulator.getHeight())
- - getVerticalValue());
- setCursorVisible(emulator.isCursorVisible());
- if (getCursorX() > getWidth() - 2) {
- setCursorVisible(false);
- }
- if ((getCursorY() > getHeight() - 2) || (getCursorY() < 0)) {
- setCursorVisible(false);
- }
- if (emulator.getScreenTitle().length() > 0) {
- // Only update the title if the shell is still alive
- if (shell != null) {
- setTitle(emulator.getScreenTitle());
- }
- }
-
- // Check to see if the shell has died.
- if (!emulator.isReading() && (shell != null)) {
- try {
- int rc = shell.exitValue();
- // The emulator exited on its own, all is fine
- setTitle(MessageFormat.format(i18n.
- getString("windowTitleCompleted"), getTitle(), rc));
- shell = null;
- emulator.close();
- 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
- // this in a future tick.
- }
- } else if (emulator.isReading() && (shell != null)) {
- // The shell might be dead, let's check
- try {
- int rc = shell.exitValue();
- // If we got here, the shell died.
- setTitle(MessageFormat.format(i18n.
- getString("windowTitleCompleted"), getTitle(), rc));
- shell = null;
- emulator.close();
- clearShortcutKeypresses();
- statusBar.setText(MessageFormat.format(i18n.
- getString("statusBarCompleted"), rc));
- onShellExit();
- } catch (IllegalThreadStateException e) {
- // The shell is still running, do nothing.
- }
- }
-
- } // synchronized (emulator)
- }
-
- /**
- * Check if a mouse press/release/motion event coordinate is over the
- * emulator.
- *
- * @param mouse a mouse-based event
- * @return whether or not the mouse is on the emulator
- */
- private boolean mouseOnEmulator(final TMouseEvent mouse) {
-
- synchronized (emulator) {
- if (!emulator.isReading()) {
- return false;
- }
- }
-
- if ((mouse.getAbsoluteX() >= getAbsoluteX() + 1)
- && (mouse.getAbsoluteX() < getAbsoluteX() + getWidth() - 1)
- && (mouse.getAbsoluteY() >= getAbsoluteY() + 1)
- && (mouse.getAbsoluteY() < getAbsoluteY() + getHeight() - 1)
- ) {
- return true;
- }
- return false;
- }
-
- /**
- * Draw glyphs for a double-width or double-height VT100 cell to two
- * screen cells.
- *
- * @param line the line this VT100 cell is in
- * @param x the X position to draw the left half to
- * @param y the Y position to draw to
- * @param cell the cell to draw
- */
- private void putDoubleWidthCharXY(final DisplayLine line, final int x,
- final int y, final Cell cell) {
-
- int textWidth = getScreen().getTextWidth();
- int textHeight = getScreen().getTextHeight();
- boolean cursorBlinkVisible = true;
-
- if (getScreen() instanceof SwingTerminal) {
- SwingTerminal terminal = (SwingTerminal) getScreen();
- cursorBlinkVisible = terminal.getCursorBlinkVisible();
- } else if (getScreen() instanceof ECMA48Terminal) {
- ECMA48Terminal terminal = (ECMA48Terminal) getScreen();
-
- if (!terminal.hasSixel()) {
- // The backend does not have sixel support, draw this as text
- // and bail out.
- putCharXY(x, y, cell);
- putCharXY(x + 1, y, ' ', cell);
- return;
- }
- cursorBlinkVisible = blinkState;
- } else {
- // We don't know how to dray glyphs to this screen, draw them as
- // text and bail out.
- putCharXY(x, y, cell);
- putCharXY(x + 1, y, ' ', cell);
- return;
- }
-
- if ((textWidth != lastTextWidth) || (textHeight != lastTextHeight)) {
- // Screen size has changed, reset all fonts.
- setupFonts(textHeight);
- lastTextWidth = textWidth;
- lastTextHeight = textHeight;
- }
- assert (doubleFont != null);
-
- BufferedImage image = null;
- if (cell.isBlink() && !cursorBlinkVisible) {
- image = glyphCacheBlink.get(cell);
- } else {
- image = glyphCache.get(cell);
- }
- if (image == null) {
- // Generate glyph and draw it to an image.
- image = new BufferedImage(textWidth * 2, textHeight * 2,
- BufferedImage.TYPE_INT_ARGB);
- Graphics2D gr2 = image.createGraphics();
- gr2.setFont(doubleFont);
-
- // Draw the background rectangle, then the foreground character.
- if (getScreen() instanceof ECMA48Terminal) {
- // BUG: the background color is coming in the same as the
- // foreground color. For now, don't draw it.
- } else {
- gr2.setColor(SwingTerminal.attrToBackgroundColor(cell));
- gr2.fillRect(0, 0, image.getWidth(), image.getHeight());
- }
- if (!cell.isBlink()
- || (cell.isBlink() && cursorBlinkVisible)
- ) {
- gr2.setColor(SwingTerminal.attrToForegroundColor(cell));
- char [] chars = new char[1];
- chars[0] = cell.getChar();
- gr2.drawChars(chars, 0, 1, doubleTextAdjustX,
- (textHeight * 2) - doubleMaxDescent + doubleTextAdjustY);
-
- if (cell.isUnderline() && (line.getDoubleHeight() != 1)) {
- gr2.fillRect(0, textHeight - 2, textWidth, 2);
- }
- }
- gr2.dispose();
-
- // Now save this generated image, using a new key that will not
- // be mutated by invertCell().
- Cell key = new Cell();
- key.setTo(cell);
- if (cell.isBlink() && !cursorBlinkVisible) {
- glyphCacheBlink.put(key, image);
- } else {
- glyphCache.put(key, image);
- }
- }
-
- // Now that we have the double-wide glyph drawn, copy the right
- // pieces of it to the cells.
- Cell left = new Cell();
- Cell right = new Cell();
- left.setTo(cell);
- right.setTo(cell);
- right.setChar(' ');
- BufferedImage leftImage = null;
- BufferedImage rightImage = null;
- switch (line.getDoubleHeight()) {
- case 1:
- // Top half double height
- leftImage = image.getSubimage(0, 0, textWidth, textHeight);
- rightImage = image.getSubimage(textWidth, 0, textWidth, textHeight);
- break;
- case 2:
- // Bottom half double height
- leftImage = image.getSubimage(0, textHeight, textWidth, textHeight);
- rightImage = image.getSubimage(textWidth, textHeight,
- textWidth, textHeight);
- break;
- default:
- // Either single height double-width, or error fallback
- BufferedImage wideImage = new BufferedImage(textWidth * 2,
- textHeight, BufferedImage.TYPE_INT_ARGB);
- Graphics2D grWide = wideImage.createGraphics();
- grWide.drawImage(image, 0, 0, wideImage.getWidth(),
- wideImage.getHeight(), null);
- grWide.dispose();
- leftImage = wideImage.getSubimage(0, 0, textWidth, textHeight);
- rightImage = wideImage.getSubimage(textWidth, 0, textWidth,
- textHeight);
- break;
- }
- left.setImage(leftImage);
- right.setImage(rightImage);
- putCharXY(x, y, left);
- putCharXY(x + 1, y, right);
- }
-
- /**
- * Set up the single and double-width fonts.
- *
- * @param fontSize the size of font to request for the single-width font.
- * The double-width font will be 2x this value.
- */
- private void setupFonts(final int fontSize) {
- try {
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- InputStream in = loader.getResourceAsStream(SwingTerminal.FONTFILE);
- Font terminusRoot = Font.createFont(Font.TRUETYPE_FONT, in);
- Font terminusDouble = terminusRoot.deriveFont(Font.PLAIN,
- fontSize * 2);
- doubleFont = terminusDouble;
- } catch (java.awt.FontFormatException e) {
- new TExceptionDialog(getApplication(), e);
- doubleFont = new Font(Font.MONOSPACED, Font.PLAIN, fontSize * 2);
- } catch (java.io.IOException e) {
- new TExceptionDialog(getApplication(), e);
- doubleFont = new Font(Font.MONOSPACED, Font.PLAIN, fontSize * 2);
- }
-
- // Get font descent.
- BufferedImage image = new BufferedImage(fontSize * 10, fontSize * 10,
- BufferedImage.TYPE_INT_ARGB);
- Graphics2D gr = image.createGraphics();
- gr.setFont(doubleFont);
- FontMetrics fm = gr.getFontMetrics();
- doubleMaxDescent = fm.getMaxDescent();
-
- gr.dispose();
-
- // (Re)create the glyph caches.
- glyphCache = new HashMap<Cell, BufferedImage>();
- glyphCacheBlink = new HashMap<Cell, BufferedImage>();
-
- // Special case: the ECMA48 backend needs to have a timer to drive
- // its blink state.
- if (getScreen() instanceof jexer.backend.ECMA48Terminal) {
- // Blink every 500 millis.
- long millis = 500;
- getApplication().addTimer(millis, true,
- new TAction() {
- public void DO() {
- blinkState = !blinkState;
- getApplication().doRepaint();
- }
- }
- );
- }
-
- }
-