From e8491b34b86b4eadec3f3c67dc55fda0881894bb Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sat, 28 Jun 2025 16:26:13 +0300 Subject: [PATCH] Kernel/LibC: Rework TIOC{G,S}WINSZ more linux like Userspace can freely set terminal size, kernel just updates it when for example new font is loaded. Also SIGWINCH is now sent by kernel instead of userspace. --- .../include/kernel/Terminal/PseudoTerminal.h | 7 --- kernel/include/kernel/Terminal/Serial.h | 3 -- kernel/include/kernel/Terminal/TTY.h | 8 +-- .../include/kernel/Terminal/TerminalDriver.h | 1 + kernel/include/kernel/Terminal/VirtualTTY.h | 3 -- kernel/kernel/Terminal/PseudoTerminal.cpp | 16 ------ kernel/kernel/Terminal/Serial.cpp | 14 ++---- kernel/kernel/Terminal/TTY.cpp | 17 ++++++- kernel/kernel/Terminal/VirtualTTY.cpp | 49 ++++++++++--------- userspace/libraries/LibC/include/sys/ioctl.h | 2 + userspace/programs/Terminal/Terminal.cpp | 17 +++---- userspace/programs/less/main.cpp | 2 +- 12 files changed, 62 insertions(+), 77 deletions(-) diff --git a/kernel/include/kernel/Terminal/PseudoTerminal.h b/kernel/include/kernel/Terminal/PseudoTerminal.h index 2a241cb21f..c3566308b2 100644 --- a/kernel/include/kernel/Terminal/PseudoTerminal.h +++ b/kernel/include/kernel/Terminal/PseudoTerminal.h @@ -59,9 +59,6 @@ namespace Kernel public: BAN::StringView name() const override { return m_name; } - uint32_t height() const override { return m_height; } - uint32_t width() const override { return m_width; } - void clear() override; protected: @@ -72,8 +69,6 @@ namespace Kernel bool can_write_impl() const override; bool has_hungup_impl() const override { return !m_master.valid(); } - BAN::ErrorOr ioctl_impl(int, void*) override; - private: PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t, uid_t, gid_t); ~PseudoTerminalSlave(); @@ -83,8 +78,6 @@ namespace Kernel const uint32_t m_number; BAN::WeakPtr m_master; - uint32_t m_width { 0 }; - uint32_t m_height { 0 }; friend class PseudoTerminalMaster; friend class BAN::RefPtr; diff --git a/kernel/include/kernel/Terminal/Serial.h b/kernel/include/kernel/Terminal/Serial.h index 4a4b2f5c88..fa9f1d5959 100644 --- a/kernel/include/kernel/Terminal/Serial.h +++ b/kernel/include/kernel/Terminal/Serial.h @@ -42,9 +42,6 @@ namespace Kernel public: static BAN::ErrorOr> create(Serial); - uint32_t width() const override; - uint32_t height() const override; - void clear() override { putchar_impl('\e'); putchar_impl('['); putchar_impl('2'); putchar_impl('J'); } void update() override; diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index 3ff636955b..2ddebe5d4b 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -8,6 +8,7 @@ #include #include +#include namespace Kernel { @@ -53,9 +54,6 @@ namespace Kernel virtual bool is_tty() const override { return true; } - virtual uint32_t height() const = 0; - virtual uint32_t width() const = 0; - virtual dev_t rdev() const final override { return m_rdev; } virtual void clear() = 0; @@ -80,6 +78,8 @@ namespace Kernel virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) final override; virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) final override; + void update_winsize(unsigned short cols, unsigned short rows); + private: bool putchar(uint8_t ch); void do_backspace(); @@ -109,6 +109,8 @@ namespace Kernel }; Buffer m_output; + winsize m_winsize {}; + protected: RecursiveSpinLock m_write_lock; ThreadBlocker m_write_blocker; diff --git a/kernel/include/kernel/Terminal/TerminalDriver.h b/kernel/include/kernel/Terminal/TerminalDriver.h index 6eb964dfdb..81bd82c72e 100644 --- a/kernel/include/kernel/Terminal/TerminalDriver.h +++ b/kernel/include/kernel/Terminal/TerminalDriver.h @@ -35,6 +35,7 @@ namespace Kernel : m_palette(palette) {} virtual ~TerminalDriver() {} + virtual uint32_t width() const = 0; virtual uint32_t height() const = 0; diff --git a/kernel/include/kernel/Terminal/VirtualTTY.h b/kernel/include/kernel/Terminal/VirtualTTY.h index 9fbdf92730..fd9970b644 100644 --- a/kernel/include/kernel/Terminal/VirtualTTY.h +++ b/kernel/include/kernel/Terminal/VirtualTTY.h @@ -19,9 +19,6 @@ namespace Kernel BAN::ErrorOr set_font(LibFont::Font&&) override; - uint32_t height() const override { return m_height; } - uint32_t width() const override { return m_width; } - void clear() override; protected: diff --git a/kernel/kernel/Terminal/PseudoTerminal.cpp b/kernel/kernel/Terminal/PseudoTerminal.cpp index 0dd737d15a..43f30fe10d 100644 --- a/kernel/kernel/Terminal/PseudoTerminal.cpp +++ b/kernel/kernel/Terminal/PseudoTerminal.cpp @@ -204,20 +204,4 @@ namespace Kernel return master->m_buffer_size < master->m_buffer->size(); } - BAN::ErrorOr PseudoTerminalSlave::ioctl_impl(int request, void* argument) - { - switch (request) - { - case TIOCSWINSZ: - { - const auto* winsize = static_cast(argument); - m_width = winsize->ws_col; - m_height = winsize->ws_row; - return 0; - } - } - - return TTY::ioctl_impl(request, argument); - } - } diff --git a/kernel/kernel/Terminal/Serial.cpp b/kernel/kernel/Terminal/Serial.cpp index 467fd990df..01c92dede8 100644 --- a/kernel/kernel/Terminal/Serial.cpp +++ b/kernel/kernel/Terminal/Serial.cpp @@ -181,7 +181,9 @@ namespace Kernel }, 0600, 0, 0) , m_name(MUST(BAN::String::formatted("ttyS{}", s_next_tty_number++))) , m_serial(serial) - {} + { + update_winsize(m_serial.width(), m_serial.height()); + } BAN::ErrorOr> SerialTTY::create(Serial serial) { @@ -254,16 +256,6 @@ namespace Kernel handle_input_byte(*ptr++); } - uint32_t SerialTTY::width() const - { - return m_serial.width(); - } - - uint32_t SerialTTY::height() const - { - return m_serial.height(); - } - bool SerialTTY::putchar_impl(uint8_t ch) { m_serial.putchar(ch); diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index ea08808978..345da62a3e 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -184,6 +184,13 @@ namespace Kernel return {}; } + void TTY::update_winsize(unsigned short cols, unsigned short rows) + { + m_winsize.ws_col = cols; + m_winsize.ws_row = rows; + (void)Process::kill(-m_foreground_pgrp, SIGWINCH); + } + BAN::ErrorOr TTY::ioctl_impl(int request, void* argument) { switch (request) @@ -198,8 +205,14 @@ namespace Kernel case TIOCGWINSZ: { auto* winsize = static_cast(argument); - winsize->ws_col = width(); - winsize->ws_row = height(); + *winsize = m_winsize; + return 0; + } + case TIOCSWINSZ: + { + const auto* winsize = static_cast(argument); + m_winsize = *winsize; + (void)Process::kill(-m_foreground_pgrp, SIGWINCH); return 0; } } diff --git a/kernel/kernel/Terminal/VirtualTTY.cpp b/kernel/kernel/Terminal/VirtualTTY.cpp index ebb11fafa4..c2e5d37c44 100644 --- a/kernel/kernel/Terminal/VirtualTTY.cpp +++ b/kernel/kernel/Terminal/VirtualTTY.cpp @@ -53,6 +53,7 @@ namespace Kernel { m_width = m_terminal_driver->width(); m_height = m_terminal_driver->height(); + update_winsize(m_width, m_height); m_buffer = new Cell[m_width * m_height]; ASSERT(m_buffer); @@ -71,34 +72,38 @@ namespace Kernel if (!m_terminal_driver->has_font()) return BAN::Error::from_errno(EINVAL); - SpinLockGuard _(m_write_lock); - - TRY(m_terminal_driver->set_font(BAN::move(font))); - - uint32_t new_width = m_terminal_driver->width(); - uint32_t new_height = m_terminal_driver->height(); - - if (m_width != new_width || m_height != new_height) { - Cell* new_buffer = new Cell[new_width * new_height]; - ASSERT(new_buffer); + SpinLockGuard _(m_write_lock); - for (uint32_t i = 0; i < new_width * m_height; i++) - new_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' }; + TRY(m_terminal_driver->set_font(BAN::move(font))); - for (uint32_t y = 0; y < BAN::Math::min(m_height, new_height); y++) - for (uint32_t x = 0; x < BAN::Math::min(m_width, new_width); x++) - new_buffer[y * new_width + x] = m_buffer[y * m_width + x]; + uint32_t new_width = m_terminal_driver->width(); + uint32_t new_height = m_terminal_driver->height(); - delete[] m_buffer; - m_buffer = new_buffer; - m_width = new_width; - m_height = new_height; + if (m_width != new_width || m_height != new_height) + { + Cell* new_buffer = new Cell[new_width * new_height]; + ASSERT(new_buffer); + + for (uint32_t i = 0; i < new_width * m_height; i++) + new_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' }; + + for (uint32_t y = 0; y < BAN::Math::min(m_height, new_height); y++) + for (uint32_t x = 0; x < BAN::Math::min(m_width, new_width); x++) + new_buffer[y * new_width + x] = m_buffer[y * m_width + x]; + + delete[] m_buffer; + m_buffer = new_buffer; + m_width = new_width; + m_height = new_height; + } + + for (uint32_t y = 0; y < m_height; y++) + for (uint32_t x = 0; x < m_width; x++) + render_from_buffer(x, y); } - for (uint32_t y = 0; y < m_height; y++) - for (uint32_t x = 0; x < m_width; x++) - render_from_buffer(x, y); + update_winsize(m_width, m_height); return {}; } diff --git a/userspace/libraries/LibC/include/sys/ioctl.h b/userspace/libraries/LibC/include/sys/ioctl.h index a4d909900a..74ea0ed01b 100644 --- a/userspace/libraries/LibC/include/sys/ioctl.h +++ b/userspace/libraries/LibC/include/sys/ioctl.h @@ -41,6 +41,8 @@ struct winsize { unsigned short ws_row; unsigned short ws_col; + unsigned short ws_xpixel; /* unused by kernel */ + unsigned short ws_ypixel; /* unused by kernel */ }; #define TIOCGWINSZ 50 #define TIOCSWINSZ 51 diff --git a/userspace/programs/Terminal/Terminal.cpp b/userspace/programs/Terminal/Terminal.cpp index dd7285be7d..f2bb868547 100644 --- a/userspace/programs/Terminal/Terminal.cpp +++ b/userspace/programs/Terminal/Terminal.cpp @@ -128,9 +128,12 @@ void Terminal::run() m_window->set_min_size(m_font.width() * 8, m_font.height() * 2); { - winsize winsize; - winsize.ws_col = cols(); - winsize.ws_row = rows(); + winsize winsize { + .ws_row = static_cast(rows()), + .ws_col = static_cast(cols()), + .ws_xpixel = static_cast(m_window->width()), + .ws_ypixel = static_cast(m_window->height()), + }; if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1) perror("ioctl"); } @@ -170,6 +173,8 @@ void Terminal::run() const winsize winsize { .ws_row = static_cast(rows()), .ws_col = static_cast(cols()), + .ws_xpixel = static_cast(m_window->width()), + .ws_ypixel = static_cast(m_window->height()), }; if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1) { @@ -183,12 +188,6 @@ void Terminal::run() perror("tcgetpgrp"); return; } - - if (kill(-fgpgrp, SIGWINCH) == -1) - { - perror("kill"); - return; - } }); const int max_fd = BAN::Math::max(m_shell_info.pts_master, m_window->server_fd()); diff --git a/userspace/programs/less/main.cpp b/userspace/programs/less/main.cpp index 3e672e43ac..2fae45a136 100644 --- a/userspace/programs/less/main.cpp +++ b/userspace/programs/less/main.cpp @@ -328,7 +328,7 @@ int main(int argc, char** argv) tcsetattr(kb_fd, TCSANOW, &termios); } - winsize ws { .ws_row = 0, .ws_col = 0 }; + winsize ws {}; if (isatty(STDOUT_FILENO)) { if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0)