minor cleanup
[fanfix.git] / src / jexer / tterminal / ECMA48.java
index 93ae3cd91930ca2f12bea2c38024b2c3408a0b33..ca32d201a2d4dfa0133fe4806ec094731f7bab73 100644 (file)
@@ -871,10 +871,10 @@ public class ECMA48 implements Runnable {
         case XTERM:
             // "I am a VT220" - 7 bit version
             if (!s8c1t) {
-                return "\033[?62;1;6c";
+                return "\033[?62;1;6;9;4c";
             }
             // "I am a VT220" - 8 bit version
-            return "\u009b?62;1;6c";
+            return "\u009b?62;1;6;9;4c";
         default:
             throw new IllegalArgumentException("Invalid device type: " + type);
         }
@@ -1078,6 +1078,64 @@ public class ECMA48 implements Runnable {
         return display;
     }
 
+    /**
+     * Get the visible display + scrollback buffer, offset by a specified
+     * number of rows from the bottom.
+     *
+     * @param visibleHeight the total height of the display to show
+     * @param scrollBottom the number of rows from the bottom to scroll back
+     * @return a copy of the display + scrollback buffers
+     */
+    public final List<DisplayLine> getVisibleDisplay(final int visibleHeight,
+        final int scrollBottom) {
+
+        assert (visibleHeight >= 0);
+        assert (scrollBottom >= 0);
+
+        int visibleBottom = scrollback.size() + display.size() - scrollBottom;
+
+        List<DisplayLine> preceedingBlankLines = new ArrayList<DisplayLine>();
+        int visibleTop = visibleBottom - visibleHeight;
+        if (visibleTop < 0) {
+            for (int i = visibleTop; i < 0; i++) {
+                preceedingBlankLines.add(getBlankDisplayLine());
+            }
+            visibleTop = 0;
+        }
+        assert (visibleTop >= 0);
+
+        List<DisplayLine> displayLines = new ArrayList<DisplayLine>();
+        displayLines.addAll(scrollback);
+        displayLines.addAll(display);
+
+        List<DisplayLine> visibleLines = new ArrayList<DisplayLine>();
+        visibleLines.addAll(preceedingBlankLines);
+        visibleLines.addAll(displayLines.subList(visibleTop, visibleBottom));
+
+        // Fill in the blank lines on bottom
+        int bottomBlankLines = visibleHeight - visibleLines.size();
+        assert (bottomBlankLines >= 0);
+        for (int i = 0; i < bottomBlankLines; i++) {
+            visibleLines.add(getBlankDisplayLine());
+        }
+
+        return copyBuffer(visibleLines);
+    }
+
+    /**
+     * Copy a display buffer.
+     *
+     * @param buffer the buffer to copy
+     * @return a deep copy of the buffer's data
+     */
+    private List<DisplayLine> copyBuffer(final List<DisplayLine> buffer) {
+        ArrayList<DisplayLine> result = new ArrayList<DisplayLine>(buffer.size());
+        for (DisplayLine line: buffer) {
+            result.add(new DisplayLine(line));
+        }
+        return result;
+    }
+
     /**
      * Get the display width.
      *
@@ -1092,7 +1150,7 @@ public class ECMA48 implements Runnable {
      *
      * @param width the new width
      */
-    public final void setWidth(final int width) {
+    public final synchronized void setWidth(final int width) {
         this.width = width;
         rightMargin = width - 1;
         if (currentState.cursorX >= width) {
@@ -1117,7 +1175,7 @@ public class ECMA48 implements Runnable {
      *
      * @param height the new height
      */
-    public final void setHeight(final int height) {
+    public final synchronized void setHeight(final int height) {
         int delta = height - this.height;
         this.height = height;
         scrollRegionBottom += delta;
@@ -2816,6 +2874,7 @@ public class ECMA48 implements Runnable {
      */
     private void setToggle(final boolean value) {
         boolean decPrivateModeFlag = false;
+
         for (int i = 0; i < collectBuffer.length(); i++) {
             if (collectBuffer.charAt(i) == '?') {
                 decPrivateModeFlag = true;
@@ -4665,6 +4724,32 @@ public class ECMA48 implements Runnable {
                         }
                     }
                 }
+
+                if (p[0].equals("10")) {
+                    if (p[1].equals("?")) {
+                        // Respond with foreground color.
+                        java.awt.Color color = jexer.backend.SwingTerminal.attrToForegroundColor(currentState.attr);
+
+                        writeRemote(String.format(
+                            "\033]10;rgb:%04x/%04x/%04x\033\\",
+                                color.getRed() << 8,
+                                color.getGreen() << 8,
+                                color.getBlue() << 8));
+                    }
+                }
+
+                if (p[0].equals("11")) {
+                    if (p[1].equals("?")) {
+                        // Respond with background color.
+                        java.awt.Color color = jexer.backend.SwingTerminal.attrToBackgroundColor(currentState.attr);
+
+                        writeRemote(String.format(
+                            "\033]11;rgb:%04x/%04x/%04x\033\\",
+                                color.getRed() << 8,
+                                color.getGreen() << 8,
+                                color.getBlue() << 8));
+                    }
+                }
             }
 
             // Go to SCAN_GROUND state
@@ -4721,12 +4806,51 @@ public class ECMA48 implements Runnable {
         int i = getCsiParam(0, 0);
 
         if (!xtermPrivateModeFlag) {
-            if (i == 14) {
-                // Report xterm window in pixels as CSI 4 ; height ; width t
+            switch (i) {
+            case 14:
+                // Report xterm text area size in pixels as CSI 4 ; height ;
+                // width t
                 writeRemote(String.format("\033[4;%d;%dt", textHeight * height,
                         textWidth * width));
+                break;
+            case 16:
+                // Report character size in pixels as CSI 6 ; height ; width
+                // t
+                writeRemote(String.format("\033[6;%d;%dt", textHeight,
+                        textWidth));
+                break;
+            case 18:
+                // Report the text are size in characters as CSI 8 ; height ;
+                // width t
+                writeRemote(String.format("\033[8;%d;%dt", height, width));
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+    /**
+     * Respond to xterm sixel query.
+     */
+    private void xtermSixelQuery() {
+        int item = getCsiParam(0, 0);
+        int action = getCsiParam(1, 0);
+        int value = getCsiParam(2, 0);
+
+        switch (item) {
+        case 1:
+            if (action == 1) {
+                // Report number of color registers.
+                writeRemote(String.format("\033[?%d;%d;%dS", item, 0, 1024));
+                return;
             }
+            break;
+        default:
+            break;
         }
+        // We will not support this option.
+        writeRemote(String.format("\033[?%d;%dS", item, action));
     }
 
     /**
@@ -5892,7 +6016,18 @@ public class ECMA48 implements Runnable {
                 case 'S':
                     // Scroll up X lines (default 1)
                     if (type == DeviceType.XTERM) {
-                        su();
+                        boolean xtermPrivateModeFlag = false;
+                        for (int i = 0; i < collectBuffer.length(); i++) {
+                            if (collectBuffer.charAt(i) == '?') {
+                                xtermPrivateModeFlag = true;
+                                break;
+                            }
+                        }
+                        if (xtermPrivateModeFlag) {
+                            xtermSixelQuery();
+                        } else {
+                            su();
+                        }
                     }
                     break;
                 case 'T':
@@ -6166,7 +6301,18 @@ public class ECMA48 implements Runnable {
                 case 'S':
                     // Scroll up X lines (default 1)
                     if (type == DeviceType.XTERM) {
-                        su();
+                        boolean xtermPrivateModeFlag = false;
+                        for (int i = 0; i < collectBuffer.length(); i++) {
+                            if (collectBuffer.charAt(i) == '?') {
+                                xtermPrivateModeFlag = true;
+                                break;
+                            }
+                        }
+                        if (xtermPrivateModeFlag) {
+                            xtermSixelQuery();
+                        } else {
+                            su();
+                        }
                     }
                     break;
                 case 'T':
@@ -6606,17 +6752,20 @@ public class ECMA48 implements Runnable {
             }
 
             // 00-17, 19, 1C-1F, 20-7E   --> put
-            // TODO
             if (ch <= 0x17) {
+                // We ignore all DCS except sixel.
                 return;
             }
             if (ch == 0x19) {
+                // We ignore all DCS except sixel.
                 return;
             }
             if ((ch >= 0x1C) && (ch <= 0x1F)) {
+                // We ignore all DCS except sixel.
                 return;
             }
             if ((ch >= 0x20) && (ch <= 0x7E)) {
+                // We ignore all DCS except sixel.
                 return;
             }