From beefe74ec56b438ec0a3a8d0b3b7726df23d471e Mon Sep 17 00:00:00 2001 From: elfmz Date: Sun, 1 Oct 2023 11:08:59 +0300 Subject: [PATCH] Far2lTTY: new input notification about terminal size (fix #1856) --- WinPort/FarTTY.h | 11 ++++++ WinPort/src/Backend/TTY/TTYBackend.cpp | 46 +++++++++++++++----------- WinPort/src/Backend/TTY/TTYBackend.h | 2 +- WinPort/src/Backend/TTY/TTYOutput.cpp | 6 +++- far2l/src/vt/VTFar2lExtensios.cpp | 18 ++++++++++ far2l/src/vt/VTFar2lExtensios.h | 1 + far2l/src/vt/vtshell.cpp | 8 ++++- 7 files changed, 70 insertions(+), 22 deletions(-) diff --git a/WinPort/FarTTY.h b/WinPort/FarTTY.h index ba72ba1e4..638f7bc76 100644 --- a/WinPort/FarTTY.h +++ b/WinPort/FarTTY.h @@ -233,6 +233,12 @@ All integer values are in little-endian format. */ #define FARTTY_FEAT_COMPACT_INPUT 0x00000001 +/** Client may specify this wanted extra feature if it supports in-band terminal size events. + If server supports this feature it may send such events, however client should be ready to + handle usual SIGWINCH signals as well. +*/ +#define FARTTY_FEAT_TERMINAL_SIZE 0x00000002 + /** Server reports this on responce of FARTTY_INTERRACT_CLIP_OPEN if it supports clipboard data ID. Clipboard data ID allows client-side caching of clipboard data to avoid known data transfers. */ @@ -291,3 +297,8 @@ all arguments are defined by FARTTY_INPUT_* notification ID - see below (stack t #define FARTTY_INPUT_KEYDOWN_COMPACT 'C' #define FARTTY_INPUT_KEYUP_COMPACT 'c' +/** Server sends this to inform about recent terminal size. + uint16_t (terminal width) + uint16_t (terminal height) +*/ +#define FARTTY_INPUT_TERMINAL_SIZE 'S' diff --git a/WinPort/src/Backend/TTY/TTYBackend.cpp b/WinPort/src/Backend/TTY/TTYBackend.cpp index 625deb7af..b4e2f6360 100644 --- a/WinPort/src/Backend/TTY/TTYBackend.cpp +++ b/WinPort/src/Backend/TTY/TTYBackend.cpp @@ -28,6 +28,7 @@ #include "FarTTY.h" #include "../FSClipboardBackend.h" +static uint16_t g_far2l_term_width = 80, g_far2l_term_height = 25; static volatile long s_terminal_size_change_id = 0; static TTYBackend * g_vtb = nullptr; @@ -100,9 +101,8 @@ TTYBackend::TTYBackend(const char *full_exe_path, int std_in, int std_out, bool } struct winsize w{}; - if (GetWinSize(w)) { - g_winport_con_out->SetSize(w.ws_col, w.ws_row); - } + GetWinSize(w); + g_winport_con_out->SetSize(w.ws_col, w.ws_row); g_winport_con_out->GetSize(_cur_width, _cur_height); g_vtb = this; } @@ -128,18 +128,17 @@ TTYBackend::~TTYBackend() DetachNotifyPipe(); } -bool TTYBackend::GetWinSize(struct winsize &w) +void TTYBackend::GetWinSize(struct winsize &w) { int r = ioctl(_stdout, TIOCGWINSZ, &w); if (UNLIKELY(r != 0)) { r = ioctl(_stdin, TIOCGWINSZ, &w); if (UNLIKELY(r != 0)) { - perror("GetWinSize"); - return false; + perror("TIOCGWINSZ"); + w.ws_row = g_far2l_term_height; + w.ws_col = g_far2l_term_width; } } - - return true; } void TTYBackend::DetachNotifyPipe() @@ -461,9 +460,7 @@ void TTYBackend::DispatchPalette(TTYOutput &tty_out) void TTYBackend::DispatchTermResized(TTYOutput &tty_out) { struct winsize w{}; - if (!GetWinSize(w)) { - return; - } + GetWinSize(w); if (_cur_width != w.ws_col || _cur_height != w.ws_row) { g_winport_con_out->SetSize(w.ws_col, w.ws_row); @@ -908,6 +905,14 @@ bool TTYBackend::OnConsoleIsActive() return false;//true; } +void TTYBackend_OnTerminalDamaged(bool flush_input_queue) +{ + __sync_add_and_fetch ( &s_terminal_size_change_id, 1); + if (g_vtb) { + g_vtb->KickAss(flush_input_queue); + } +} + static void OnFar2lKey(bool down, StackSerializer &stk_ser) { try { @@ -927,6 +932,13 @@ static void OnFar2lKey(bool down, StackSerializer &stk_ser) } } +static void OnFar2lTerminalSize(StackSerializer &stk_ser) +{ + stk_ser.PopNum(g_far2l_term_height); + stk_ser.PopNum(g_far2l_term_width); + TTYBackend_OnTerminalDamaged(false); +} + static void OnFar2lKeyCompact(bool down, StackSerializer &stk_ser) { try { @@ -1026,6 +1038,10 @@ void TTYBackend::OnFar2lEvent(StackSerializer &stk_ser) OnFar2lKeyCompact(code == FARTTY_INPUT_KEYDOWN_COMPACT, stk_ser); break; + case FARTTY_INPUT_TERMINAL_SIZE: + OnFar2lTerminalSize(stk_ser); + break; + default: fprintf(stderr, "Far2lEvent unknown code=0x%x!\n", (unsigned int)(unsigned char)code); } @@ -1149,14 +1165,6 @@ bool TTYBackend::OnConsoleBackgroundMode(bool TryEnterBackgroundMode) } -void TTYBackend_OnTerminalDamaged(bool flush_input_queue) -{ - __sync_add_and_fetch ( &s_terminal_size_change_id, 1); - if (g_vtb) { - g_vtb->KickAss(flush_input_queue); - } -} - static void OnSigWinch(int) { TTYBackend_OnTerminalDamaged(false); diff --git a/WinPort/src/Backend/TTY/TTYBackend.h b/WinPort/src/Backend/TTY/TTYBackend.h index 25720253e..b9035ed80 100644 --- a/WinPort/src/Backend/TTY/TTYBackend.h +++ b/WinPort/src/Backend/TTY/TTYBackend.h @@ -99,7 +99,7 @@ class TTYBackend : IConsoleOutputBackend, ITTYInputSpecialSequenceHandler, IFar2 ClipboardBackendSetter _clipboard_backend_setter; - bool GetWinSize(struct winsize &w); + void GetWinSize(struct winsize &w); void ChooseSimpleClipboardBackend(); void DispatchTermResized(TTYOutput &tty_out); void DispatchOutput(TTYOutput &tty_out); diff --git a/WinPort/src/Backend/TTY/TTYOutput.cpp b/WinPort/src/Backend/TTY/TTYOutput.cpp index 2e1a15bb6..7357d49d0 100644 --- a/WinPort/src/Backend/TTY/TTYOutput.cpp +++ b/WinPort/src/Backend/TTY/TTYOutput.cpp @@ -177,8 +177,12 @@ TTYOutput::TTYOutput(int out, bool far2l_tty, bool norgb) ChangeMouse(true); if (far2l_tty) { + uint64_t wanted_feats = FARTTY_FEAT_COMPACT_INPUT; + if (!isatty(_out)) { + wanted_feats|= FARTTY_FEAT_TERMINAL_SIZE; + } StackSerializer stk_ser; - stk_ser.PushNum((uint64_t)(FARTTY_FEAT_COMPACT_INPUT)); + stk_ser.PushNum(wanted_feats); stk_ser.PushNum(FARTTY_INTERRACT_CHOOSE_EXTRA_FEATURES); stk_ser.PushNum((uint8_t)0); // zero ID means not expecting reply SendFar2lInterract(stk_ser); diff --git a/far2l/src/vt/VTFar2lExtensios.cpp b/far2l/src/vt/VTFar2lExtensios.cpp index d8ab791ad..3a3e237f1 100644 --- a/far2l/src/vt/VTFar2lExtensios.cpp +++ b/far2l/src/vt/VTFar2lExtensios.cpp @@ -146,6 +146,21 @@ void VTFar2lExtensios::AllowClipboardRead(bool prolong) /// +void VTFar2lExtensios::OnTerminalResized() +{ + if ( (_xfeatures & FARTTY_FEAT_TERMINAL_SIZE) != 0) { + CONSOLE_SCREEN_BUFFER_INFO csbi = { }; + if (WINPORT(GetConsoleScreenBufferInfo)( NULL, &csbi ) + && csbi.dwSize.X && csbi.dwSize.Y) { + StackSerializer stk_ser; + stk_ser.PushNum((uint16_t)csbi.dwSize.X); + stk_ser.PushNum((uint16_t)csbi.dwSize.Y); + stk_ser.PushNum(FARTTY_INPUT_TERMINAL_SIZE); + WriteInputEvent(stk_ser); + } + } +} + bool VTFar2lExtensios::OnInputMouse(const MOUSE_EVENT_RECORD &MouseEvent) { if (MouseEvent.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) { @@ -554,6 +569,9 @@ void VTFar2lExtensios::OnInterract(StackSerializer &stk_ser) _xfeatures = 0; stk_ser.PopNum(_xfeatures); stk_ser.Clear(); + if (_xfeatures & FARTTY_FEAT_TERMINAL_SIZE) { + OnTerminalResized(); + } break; case FARTTY_INTERRACT_CONSOLE_ADHOC_QEDIT: diff --git a/far2l/src/vt/VTFar2lExtensios.h b/far2l/src/vt/VTFar2lExtensios.h index bef273c3b..1db2862db 100644 --- a/far2l/src/vt/VTFar2lExtensios.h +++ b/far2l/src/vt/VTFar2lExtensios.h @@ -48,6 +48,7 @@ class VTFar2lExtensios VTFar2lExtensios(IVTShell *vt_shell, const std::string &host_id); ~VTFar2lExtensios(); + void OnTerminalResized(); bool OnInputMouse(const MOUSE_EVENT_RECORD &MouseEvent); bool OnInputKey(const KEY_EVENT_RECORD &KeyEvent); void OnInterract(StackSerializer &stk_ser); diff --git a/far2l/src/vt/vtshell.cpp b/far2l/src/vt/vtshell.cpp index 1784d1ec7..9c4c77d8d 100644 --- a/far2l/src/vt/vtshell.cpp +++ b/far2l/src/vt/vtshell.cpp @@ -222,7 +222,7 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell void UpdateTerminalSize(int fd_term) { CONSOLE_SCREEN_BUFFER_INFO csbi = { }; - if (WINPORT(GetConsoleScreenBufferInfo)( NULL, &csbi ) + if (WINPORT(GetConsoleScreenBufferInfo)( NULL, &csbi ) && csbi.dwSize.X && csbi.dwSize.Y) { fprintf(stderr, "UpdateTerminalSize: %u x %u\n", csbi.dwSize.X, csbi.dwSize.Y); struct winsize ws = {(unsigned short)csbi.dwSize.Y, @@ -346,6 +346,8 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell { if (!_slavename.empty()) UpdateTerminalSize(_fd_out); + if (_far2l_exts) + _far2l_exts->OnTerminalResized(); } virtual void OnInputResized(const INPUT_RECORD &ir) //called from worker thread @@ -496,6 +498,8 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell if (!_slavename.empty()) UpdateTerminalSize(_fd_out); + if (_far2l_exts) + _far2l_exts->OnTerminalResized(); } virtual void OnKeypadChange(unsigned char keypad) @@ -843,6 +847,8 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell if (!_slavename.empty()) UpdateTerminalSize(_fd_out); + if (_far2l_exts) + _far2l_exts->OnTerminalResized(); std::string cmd_str; if (!_slavename.empty()) {