From 03142590ff42579505476729ed1e189a2aa35ce4 Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Thu, 26 Sep 2024 16:49:38 +0200 Subject: [PATCH] Added: Terminal CSI reporting of window and cell pixel size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the following CSI escape sequences from https://invisible-island.net/xterm/ctlseqs/ctlseqs.html: > CSI Ps ; Ps ; Ps t > [..] > Ps = 1 4 ⇒ Report xterm text area size in pixels. > Result is CSI 4 ; height ; width t > [..] > Ps = 1 6 ⇒ Report xterm character cell size in pixels. > Result is CSI 6 ; height ; width t Extracted from changes in https://github.com/termux/termux-app/pull/2973 by @MatanZ and adopted to play well with the just merged #3098 (.ws_xpixel and .ws_ypixel values in winsize). --- .../com/termux/terminal/TerminalEmulator.java | 18 +++++++++++++---- .../com/termux/terminal/TerminalSession.java | 14 ++++++------- .../ControlSequenceIntroducerTest.java | 20 +++++++++++++++++++ .../java/com/termux/terminal/HistoryTest.java | 4 ++-- .../java/com/termux/terminal/ResizeTest.java | 6 +++--- .../com/termux/terminal/TerminalTest.java | 2 +- .../com/termux/terminal/TerminalTestCase.java | 9 ++++++--- 7 files changed, 53 insertions(+), 20 deletions(-) diff --git a/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java b/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java index 14fb84865a..993e0c6895 100644 --- a/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java +++ b/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java @@ -136,6 +136,9 @@ public final class TerminalEmulator { /** The number of character rows and columns in the terminal screen. */ public int mRows, mColumns; + /** Size of a terminal cell in pixels. */ + private int mCellWidthPixels, mCellHeightPixels; + /** The number of terminal transcript rows that can be scrolled back to. */ public static final int TERMINAL_TRANSCRIPT_ROWS_MIN = 100; public static final int TERMINAL_TRANSCRIPT_ROWS_MAX = 50000; @@ -314,13 +317,15 @@ static int mapDecSetBitToInternalBit(int decsetBit) { } } - public TerminalEmulator(TerminalOutput session, int columns, int rows, Integer transcriptRows, TerminalSessionClient client) { + public TerminalEmulator(TerminalOutput session, int columns, int rows, int cellWidthPixels, int cellHeightPixels, Integer transcriptRows, TerminalSessionClient client) { mSession = session; mScreen = mMainBuffer = new TerminalBuffer(columns, getTerminalTranscriptRows(transcriptRows), rows); mAltBuffer = new TerminalBuffer(columns, rows, rows); mClient = client; mRows = rows; mColumns = columns; + mCellWidthPixels = cellWidthPixels; + mCellHeightPixels = cellHeightPixels; mTabStop = new boolean[mColumns]; reset(); } @@ -370,7 +375,10 @@ public void sendMouseEvent(int mouseButton, int column, int row, boolean pressed } } - public void resize(int columns, int rows) { + public void resize(int columns, int rows, int cellWidthPixels, int cellHeightPixels) { + this.mCellWidthPixels = cellWidthPixels; + this.mCellHeightPixels = cellHeightPixels; + if (mRows == rows && mColumns == columns) { return; } else if (columns < 2 || rows < 2) { @@ -1748,8 +1756,10 @@ private void doCsi(int b) { mSession.write("\033[3;0;0t"); break; case 14: // Report xterm window in pixels. Result is CSI 4 ; height ; width t - // We just report characters time 12 here. - mSession.write(String.format(Locale.US, "\033[4;%d;%dt", mRows * 12, mColumns * 12)); + mSession.write(String.format(Locale.US, "\033[4;%d;%dt", mRows * mCellHeightPixels, mColumns * mCellWidthPixels)); + break; + case 16: // Report xterm character cell size in pixels. Result is CSI 6 ; height ; width t + mSession.write(String.format(Locale.US, "\033[6;%d;%dt", mCellHeightPixels, mCellWidthPixels)); break; case 18: // Report the size of the text area in characters. Result is CSI 8 ; height ; width t mSession.write(String.format(Locale.US, "\033[8;%d;%dt", mRows, mColumns)); diff --git a/terminal-emulator/src/main/java/com/termux/terminal/TerminalSession.java b/terminal-emulator/src/main/java/com/termux/terminal/TerminalSession.java index 33f1b355b4..b068be203b 100644 --- a/terminal-emulator/src/main/java/com/termux/terminal/TerminalSession.java +++ b/terminal-emulator/src/main/java/com/termux/terminal/TerminalSession.java @@ -100,12 +100,12 @@ public void updateTerminalSessionClient(TerminalSessionClient client) { } /** Inform the attached pty of the new size and reflow or initialize the emulator. */ - public void updateSize(int columns, int rows, int fontWidth, int fontHeight) { + public void updateSize(int columns, int rows, int cellWidthPixels, int cellHeightPixels) { if (mEmulator == null) { - initializeEmulator(columns, rows, fontWidth, fontHeight); + initializeEmulator(columns, rows, cellWidthPixels, cellHeightPixels); } else { - JNI.setPtyWindowSize(mTerminalFileDescriptor, rows, columns, fontWidth, fontHeight); - mEmulator.resize(columns, rows); + JNI.setPtyWindowSize(mTerminalFileDescriptor, rows, columns, cellWidthPixels, cellHeightPixels); + mEmulator.resize(columns, rows, cellWidthPixels, cellHeightPixels); } } @@ -120,11 +120,11 @@ public String getTitle() { * @param columns The number of columns in the terminal window. * @param rows The number of rows in the terminal window. */ - public void initializeEmulator(int columns, int rows, int cellWidth, int cellHeight) { - mEmulator = new TerminalEmulator(this, columns, rows, mTranscriptRows, mClient); + public void initializeEmulator(int columns, int rows, int cellWidthPixels, int cellHeightPixels) { + mEmulator = new TerminalEmulator(this, columns, rows, cellWidthPixels, cellHeightPixels, mTranscriptRows, mClient); int[] processId = new int[1]; - mTerminalFileDescriptor = JNI.createSubprocess(mShellPath, mCwd, mArgs, mEnv, processId, rows, columns, cellWidth, cellHeight); + mTerminalFileDescriptor = JNI.createSubprocess(mShellPath, mCwd, mArgs, mEnv, processId, rows, columns, cellWidthPixels, cellHeightPixels); mShellPid = processId[0]; mClient.setTerminalShellPid(this, mShellPid); diff --git a/terminal-emulator/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java b/terminal-emulator/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java index 5a12edd749..c356baa891 100644 --- a/terminal-emulator/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java +++ b/terminal-emulator/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java @@ -62,4 +62,24 @@ public void testCsi3J() { assertEquals("y\nz", mTerminal.getScreen().getTranscriptText()); } + public void testReportPixelSize() { + int columns = 3; + int rows = 3; + withTerminalSized(columns, rows); + int cellWidth = TerminalTest.INITIAL_CELL_WIDTH_PIXELS; + int cellHeight = TerminalTest.INITIAL_CELL_HEIGHT_PIXELS; + assertEnteringStringGivesResponse("\033[14t", "\033[4;" + (rows*cellHeight) + ";" + (columns*cellWidth) + "t"); + assertEnteringStringGivesResponse("\033[16t", "\033[6;" + cellHeight + ";" + cellWidth + "t"); + columns = 23; + rows = 33; + resize(columns, rows); + assertEnteringStringGivesResponse("\033[14t", "\033[4;" + (rows*cellHeight) + ";" + (columns*cellWidth) + "t"); + assertEnteringStringGivesResponse("\033[16t", "\033[6;" + cellHeight + ";" + cellWidth + "t"); + cellWidth = 8; + cellHeight = 18; + mTerminal.resize(columns, rows, cellWidth, cellHeight); + assertEnteringStringGivesResponse("\033[14t", "\033[4;" + (rows*cellHeight) + ";" + (columns*cellWidth) + "t"); + assertEnteringStringGivesResponse("\033[16t", "\033[6;" + cellHeight + ";" + cellWidth + "t"); + } + } diff --git a/terminal-emulator/src/test/java/com/termux/terminal/HistoryTest.java b/terminal-emulator/src/test/java/com/termux/terminal/HistoryTest.java index a252e1a8cb..17f8111205 100644 --- a/terminal-emulator/src/test/java/com/termux/terminal/HistoryTest.java +++ b/terminal-emulator/src/test/java/com/termux/terminal/HistoryTest.java @@ -11,10 +11,10 @@ public void testHistory() { assertLinesAre("777", "888", "999"); assertHistoryStartsWith("666", "555"); - mTerminal.resize(cols, 2); + resize(cols, 2); assertHistoryStartsWith("777", "666", "555"); - mTerminal.resize(cols, 3); + resize(cols, 3); assertHistoryStartsWith("666", "555"); } diff --git a/terminal-emulator/src/test/java/com/termux/terminal/ResizeTest.java b/terminal-emulator/src/test/java/com/termux/terminal/ResizeTest.java index fa4a702473..6c32d663b4 100644 --- a/terminal-emulator/src/test/java/com/termux/terminal/ResizeTest.java +++ b/terminal-emulator/src/test/java/com/termux/terminal/ResizeTest.java @@ -72,11 +72,11 @@ public void testResizeAfterHistoryWraparound() { enterString("\r\n"); } assertLinesAre("998 ", "999 ", " "); - mTerminal.resize(cols, 2); + resize(cols, 2); assertLinesAre("999 ", " "); - mTerminal.resize(cols, 5); + resize(cols, 5); assertLinesAre("996 ", "997 ", "998 ", "999 ", " "); - mTerminal.resize(cols, rows); + resize(cols, rows); assertLinesAre("998 ", "999 ", " "); } diff --git a/terminal-emulator/src/test/java/com/termux/terminal/TerminalTest.java b/terminal-emulator/src/test/java/com/termux/terminal/TerminalTest.java index e3efa81d3f..739529a841 100644 --- a/terminal-emulator/src/test/java/com/termux/terminal/TerminalTest.java +++ b/terminal-emulator/src/test/java/com/termux/terminal/TerminalTest.java @@ -82,7 +82,7 @@ public void testReportTerminalSize() throws Exception { assertEnteringStringGivesResponse("\033[18t", "\033[8;5;5t"); for (int width = 3; width < 12; width++) { for (int height = 3; height < 12; height++) { - mTerminal.resize(width, height); + resize(width, height); assertEnteringStringGivesResponse("\033[18t", "\033[8;" + height + ";" + width + "t"); } } diff --git a/terminal-emulator/src/test/java/com/termux/terminal/TerminalTestCase.java b/terminal-emulator/src/test/java/com/termux/terminal/TerminalTestCase.java index 1d0b0271bb..4490207932 100644 --- a/terminal-emulator/src/test/java/com/termux/terminal/TerminalTestCase.java +++ b/terminal-emulator/src/test/java/com/termux/terminal/TerminalTestCase.java @@ -13,7 +13,10 @@ public abstract class TerminalTestCase extends TestCase { - public static class MockTerminalOutput extends TerminalOutput { + public static final int INITIAL_CELL_WIDTH_PIXELS = 13; + public static final int INITIAL_CELL_HEIGHT_PIXELS = 15; + + public static class MockTerminalOutput extends TerminalOutput { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); public final List titleChanges = new ArrayList<>(); public final List clipboardPuts = new ArrayList<>(); @@ -108,7 +111,7 @@ protected void setUp() throws Exception { protected TerminalTestCase withTerminalSized(int columns, int rows) { // The tests aren't currently using the client, so a null client will suffice, a dummy client should be implemented if needed - mTerminal = new TerminalEmulator(mOutput, columns, rows, rows * 2, null); + mTerminal = new TerminalEmulator(mOutput, columns, rows, INITIAL_CELL_WIDTH_PIXELS, INITIAL_CELL_HEIGHT_PIXELS, rows * 2, null); return this; } @@ -201,7 +204,7 @@ public TerminalTestCase assertLinesAre(String... lines) { } public TerminalTestCase resize(int cols, int rows) { - mTerminal.resize(cols, rows); + mTerminal.resize(cols, rows, INITIAL_CELL_WIDTH_PIXELS, INITIAL_CELL_HEIGHT_PIXELS); assertInvariants(); return this; }