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 2a241cb2..c3566308 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 4a4b2f5c..fa9f1d59 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 3ff63695..2ddebe5d 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 6eb964df..81bd82c7 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 9fbdf927..fd9970b6 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 0dd737d1..43f30fe1 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 467fd990..01c92ded 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 ea088089..345da62a 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 ebb11faf..c2e5d37c 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 a4d90990..74ea0ed0 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 dd7285be..f2bb8685 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 3e672e43..2fae45a1 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)