From 315cc27a5ae09854e19d458fb4819d4f9c74d56c Mon Sep 17 00:00:00 2001 From: Blue Date: Wed, 26 Nov 2025 19:33:17 +0000 Subject: [PATCH] User/oneblue/initial tty size (#13786) * Save state * Pass in the terminal size when creating a WSLA process --- src/shared/inc/lxinitshared.h | 4 +--- src/windows/common/WSLAProcessLauncher.cpp | 8 ++++++++ src/windows/common/WSLAProcessLauncher.h | 3 +++ src/windows/common/WslClient.cpp | 12 +++++++++--- src/windows/wslaservice/exe/WSLAVirtualMachine.cpp | 9 +++++---- src/windows/wslaservice/exe/WSLAVirtualMachine.h | 3 ++- src/windows/wslaservice/inc/wslaservice.idl | 2 ++ 7 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/shared/inc/lxinitshared.h b/src/shared/inc/lxinitshared.h index ca7d204..f0499d0 100644 --- a/src/shared/inc/lxinitshared.h +++ b/src/shared/inc/lxinitshared.h @@ -1666,10 +1666,8 @@ struct WSLA_TTY_RELAY int32_t TtyInput; int32_t TtyOutput; int32_t TtyControl; - uint32_t Rows; - uint32_t Columns; - PRETTY_PRINT(FIELD(Header), FIELD(TtyMaster), FIELD(TtyInput), FIELD(TtyOutput), FIELD(TtyControl), FIELD(Rows), FIELD(Columns)); + PRETTY_PRINT(FIELD(Header), FIELD(TtyMaster), FIELD(TtyInput), FIELD(TtyOutput), FIELD(TtyControl)); }; struct WSLA_ACCEPT diff --git a/src/windows/common/WSLAProcessLauncher.cpp b/src/windows/common/WSLAProcessLauncher.cpp index 6e2b4cd..3a2e47a 100644 --- a/src/windows/common/WSLAProcessLauncher.cpp +++ b/src/windows/common/WSLAProcessLauncher.cpp @@ -48,6 +48,12 @@ void WSLAProcessLauncher::AddFd(WSLA_PROCESS_FD Fd) m_fds.push_back(Fd); } +void WSLAProcessLauncher::SetTtySize(ULONG Rows, ULONG Columns) +{ + m_rows = Rows; + m_columns = Columns; +} + std::tuple, std::vector> WSLAProcessLauncher::CreateProcessOptions() { std::vector commandLine; @@ -64,6 +70,8 @@ std::tuple, std::vector(m_fds.size()); options.Environment = environment.data(); options.EnvironmentCount = static_cast(environment.size()); + options.TtyColumns = m_columns; + options.TtyRows = m_rows; return std::make_tuple(options, std::move(commandLine), std::move(environment)); } diff --git a/src/windows/common/WSLAProcessLauncher.h b/src/windows/common/WSLAProcessLauncher.h index 97fd2ac..1b26ec0 100644 --- a/src/windows/common/WSLAProcessLauncher.h +++ b/src/windows/common/WSLAProcessLauncher.h @@ -82,6 +82,7 @@ public: ProcessFlags Flags = ProcessFlags::Stdout | ProcessFlags::Stderr); void AddFd(WSLA_PROCESS_FD Fd); + void SetTtySize(ULONG Rows, ULONG Columns); // TODO: Add overloads for IWSLAContainer once implemented. ClientRunningWSLAProcess Launch(IWSLASession& Session); @@ -95,6 +96,8 @@ protected: std::string m_executable; std::vector m_arguments; std::vector m_environment; + DWORD m_rows = 0; + DWORD m_columns = 0; }; } // namespace wsl::windows::common \ No newline at end of file diff --git a/src/windows/common/WslClient.cpp b/src/windows/common/WslClient.cpp index 6b40f92..bd3f9e4 100644 --- a/src/windows/common/WslClient.cpp +++ b/src/windows/common/WslClient.cpp @@ -1606,17 +1606,23 @@ int WslaShell(_In_ std::wstring_view commandLine) THROW_HR_IF(E_FAIL, initProcess.WaitAndCaptureOutput().Code != 0); } + // Get the terminal size. + HANDLE Stdout = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE Stdin = GetStdHandle(STD_INPUT_HANDLE); + + CONSOLE_SCREEN_BUFFER_INFOEX Info{}; + Info.cbSize = sizeof(Info); + THROW_IF_WIN32_BOOL_FALSE(::GetConsoleScreenBufferInfoEx(Stdout, &Info)); + wsl::windows::common::WSLAProcessLauncher launcher{shell, {shell}, {"TERM=xterm-256color"}, ProcessFlags::None}; launcher.AddFd(WSLA_PROCESS_FD{.Fd = 0, .Type = WSLAFdTypeTerminalInput}); launcher.AddFd(WSLA_PROCESS_FD{.Fd = 1, .Type = WSLAFdTypeTerminalOutput}); launcher.AddFd(WSLA_PROCESS_FD{.Fd = 2, .Type = WSLAFdTypeTerminalControl}); + launcher.SetTtySize(Info.srWindow.Bottom - Info.srWindow.Top + 1, Info.srWindow.Right - Info.srWindow.Left + 1); auto process = launcher.Launch(*session); // Configure console for interactive usage. - - HANDLE Stdout = GetStdHandle(STD_OUTPUT_HANDLE); - HANDLE Stdin = GetStdHandle(STD_INPUT_HANDLE); { DWORD OutputMode{}; THROW_LAST_ERROR_IF(!::GetConsoleMode(Stdout, &OutputMode)); diff --git a/src/windows/wslaservice/exe/WSLAVirtualMachine.cpp b/src/windows/wslaservice/exe/WSLAVirtualMachine.cpp index e6a5f73..0c8265c 100644 --- a/src/windows/wslaservice/exe/WSLAVirtualMachine.cpp +++ b/src/windows/wslaservice/exe/WSLAVirtualMachine.cpp @@ -727,7 +727,8 @@ std::tuple WSLAVirtualMachine::For return Fork(m_initChannel, Type); } -std::tuple WSLAVirtualMachine::Fork(wsl::shared::SocketChannel& Channel, enum WSLA_FORK::ForkType Type) +std::tuple WSLAVirtualMachine::Fork( + wsl::shared::SocketChannel& Channel, enum WSLA_FORK::ForkType Type, ULONG TtyRows, ULONG TtyColumns) { uint32_t port{}; int32_t pid{}; @@ -737,8 +738,8 @@ std::tuple WSLAVirtualMachine::For WSLA_FORK message; message.ForkType = Type; - message.TtyColumns = 80; - message.TtyRows = 80; + message.TtyColumns = static_cast(TtyColumns); + message.TtyRows = static_cast(TtyRows); const auto& response = Channel.Transaction(message); port = response.Port; pid = response.Pid; @@ -857,7 +858,7 @@ Microsoft::WRL::ComPtr WSLAVirtualMachine::CreateLinuxProcess(_In_ // If this is an interactive tty, we need a relay process if (interactiveTty) { - auto [grandChildPid, ptyMaster, grandChildChannel] = Fork(childChannel, WSLA_FORK::Pty); + auto [grandChildPid, ptyMaster, grandChildChannel] = Fork(childChannel, WSLA_FORK::Pty, Options.TtyRows, Options.TtyColumns); WSLA_TTY_RELAY relayMessage{}; relayMessage.TtyMaster = ptyMaster; relayMessage.TtyInput = ttyInput->Fd; diff --git a/src/windows/wslaservice/exe/WSLAVirtualMachine.h b/src/windows/wslaservice/exe/WSLAVirtualMachine.h index 9019aa7..a2ed053 100644 --- a/src/windows/wslaservice/exe/WSLAVirtualMachine.h +++ b/src/windows/wslaservice/exe/WSLAVirtualMachine.h @@ -82,7 +82,8 @@ private: void OnCrash(_In_ const HCS_EVENT* Event); std::tuple Fork(enum WSLA_FORK::ForkType Type); - std::tuple Fork(wsl::shared::SocketChannel& Channel, enum WSLA_FORK::ForkType Type); + std::tuple Fork( + wsl::shared::SocketChannel& Channel, enum WSLA_FORK::ForkType Type, ULONG TtyRows = 0, ULONG TtyColumns = 0); int32_t ExpectClosedChannelOrError(wsl::shared::SocketChannel& Channel); ConnectedSocket ConnectSocket(wsl::shared::SocketChannel& Channel, int32_t Fd); diff --git a/src/windows/wslaservice/inc/wslaservice.idl b/src/windows/wslaservice/inc/wslaservice.idl index 72df736..33c0553 100644 --- a/src/windows/wslaservice/inc/wslaservice.idl +++ b/src/windows/wslaservice/inc/wslaservice.idl @@ -112,6 +112,8 @@ struct WSLA_PROCESS_OPTIONS ULONG EnvironmentCount; [unique, size_is(FdsCount)] WSLA_PROCESS_FD *Fds; int FdsCount; + ULONG TtyRows; // Only needed when tty fd's are passed. + ULONG TtyColumns; }; struct WSLA_VOLUME