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.
This commit is contained in:
Bananymous 2025-06-28 16:26:13 +03:00
parent 521457eb92
commit e8491b34b8
12 changed files with 62 additions and 77 deletions

View File

@ -59,9 +59,6 @@ namespace Kernel
public: public:
BAN::StringView name() const override { return m_name; } 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; void clear() override;
protected: protected:
@ -72,8 +69,6 @@ namespace Kernel
bool can_write_impl() const override; bool can_write_impl() const override;
bool has_hungup_impl() const override { return !m_master.valid(); } bool has_hungup_impl() const override { return !m_master.valid(); }
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
private: private:
PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t, uid_t, gid_t); PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t, uid_t, gid_t);
~PseudoTerminalSlave(); ~PseudoTerminalSlave();
@ -83,8 +78,6 @@ namespace Kernel
const uint32_t m_number; const uint32_t m_number;
BAN::WeakPtr<PseudoTerminalMaster> m_master; BAN::WeakPtr<PseudoTerminalMaster> m_master;
uint32_t m_width { 0 };
uint32_t m_height { 0 };
friend class PseudoTerminalMaster; friend class PseudoTerminalMaster;
friend class BAN::RefPtr<PseudoTerminalSlave>; friend class BAN::RefPtr<PseudoTerminalSlave>;

View File

@ -42,9 +42,6 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::RefPtr<SerialTTY>> create(Serial); static BAN::ErrorOr<BAN::RefPtr<SerialTTY>> 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 clear() override { putchar_impl('\e'); putchar_impl('['); putchar_impl('2'); putchar_impl('J'); }
void update() override; void update() override;

View File

@ -8,6 +8,7 @@
#include <LibInput/KeyEvent.h> #include <LibInput/KeyEvent.h>
#include <termios.h> #include <termios.h>
#include <sys/ioctl.h>
namespace Kernel namespace Kernel
{ {
@ -53,9 +54,6 @@ namespace Kernel
virtual bool is_tty() const override { return true; } 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 dev_t rdev() const final override { return m_rdev; }
virtual void clear() = 0; virtual void clear() = 0;
@ -80,6 +78,8 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) final override; virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) final override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) final override; virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) final override;
void update_winsize(unsigned short cols, unsigned short rows);
private: private:
bool putchar(uint8_t ch); bool putchar(uint8_t ch);
void do_backspace(); void do_backspace();
@ -109,6 +109,8 @@ namespace Kernel
}; };
Buffer m_output; Buffer m_output;
winsize m_winsize {};
protected: protected:
RecursiveSpinLock m_write_lock; RecursiveSpinLock m_write_lock;
ThreadBlocker m_write_blocker; ThreadBlocker m_write_blocker;

View File

@ -35,6 +35,7 @@ namespace Kernel
: m_palette(palette) : m_palette(palette)
{} {}
virtual ~TerminalDriver() {} virtual ~TerminalDriver() {}
virtual uint32_t width() const = 0; virtual uint32_t width() const = 0;
virtual uint32_t height() const = 0; virtual uint32_t height() const = 0;

View File

@ -19,9 +19,6 @@ namespace Kernel
BAN::ErrorOr<void> set_font(LibFont::Font&&) override; BAN::ErrorOr<void> set_font(LibFont::Font&&) override;
uint32_t height() const override { return m_height; }
uint32_t width() const override { return m_width; }
void clear() override; void clear() override;
protected: protected:

View File

@ -204,20 +204,4 @@ namespace Kernel
return master->m_buffer_size < master->m_buffer->size(); return master->m_buffer_size < master->m_buffer->size();
} }
BAN::ErrorOr<long> PseudoTerminalSlave::ioctl_impl(int request, void* argument)
{
switch (request)
{
case TIOCSWINSZ:
{
const auto* winsize = static_cast<struct winsize*>(argument);
m_width = winsize->ws_col;
m_height = winsize->ws_row;
return 0;
}
}
return TTY::ioctl_impl(request, argument);
}
} }

View File

@ -181,7 +181,9 @@ namespace Kernel
}, 0600, 0, 0) }, 0600, 0, 0)
, m_name(MUST(BAN::String::formatted("ttyS{}", s_next_tty_number++))) , m_name(MUST(BAN::String::formatted("ttyS{}", s_next_tty_number++)))
, m_serial(serial) , m_serial(serial)
{} {
update_winsize(m_serial.width(), m_serial.height());
}
BAN::ErrorOr<BAN::RefPtr<SerialTTY>> SerialTTY::create(Serial serial) BAN::ErrorOr<BAN::RefPtr<SerialTTY>> SerialTTY::create(Serial serial)
{ {
@ -254,16 +256,6 @@ namespace Kernel
handle_input_byte(*ptr++); 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) bool SerialTTY::putchar_impl(uint8_t ch)
{ {
m_serial.putchar(ch); m_serial.putchar(ch);

View File

@ -184,6 +184,13 @@ namespace Kernel
return {}; 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<long> TTY::ioctl_impl(int request, void* argument) BAN::ErrorOr<long> TTY::ioctl_impl(int request, void* argument)
{ {
switch (request) switch (request)
@ -198,8 +205,14 @@ namespace Kernel
case TIOCGWINSZ: case TIOCGWINSZ:
{ {
auto* winsize = static_cast<struct winsize*>(argument); auto* winsize = static_cast<struct winsize*>(argument);
winsize->ws_col = width(); *winsize = m_winsize;
winsize->ws_row = height(); return 0;
}
case TIOCSWINSZ:
{
const auto* winsize = static_cast<const struct winsize*>(argument);
m_winsize = *winsize;
(void)Process::kill(-m_foreground_pgrp, SIGWINCH);
return 0; return 0;
} }
} }

View File

@ -53,6 +53,7 @@ namespace Kernel
{ {
m_width = m_terminal_driver->width(); m_width = m_terminal_driver->width();
m_height = m_terminal_driver->height(); m_height = m_terminal_driver->height();
update_winsize(m_width, m_height);
m_buffer = new Cell[m_width * m_height]; m_buffer = new Cell[m_width * m_height];
ASSERT(m_buffer); ASSERT(m_buffer);
@ -71,34 +72,38 @@ namespace Kernel
if (!m_terminal_driver->has_font()) if (!m_terminal_driver->has_font())
return BAN::Error::from_errno(EINVAL); 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]; SpinLockGuard _(m_write_lock);
ASSERT(new_buffer);
for (uint32_t i = 0; i < new_width * m_height; i++) TRY(m_terminal_driver->set_font(BAN::move(font)));
new_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
for (uint32_t y = 0; y < BAN::Math::min<uint32_t>(m_height, new_height); y++) uint32_t new_width = m_terminal_driver->width();
for (uint32_t x = 0; x < BAN::Math::min<uint32_t>(m_width, new_width); x++) uint32_t new_height = m_terminal_driver->height();
new_buffer[y * new_width + x] = m_buffer[y * m_width + x];
delete[] m_buffer; if (m_width != new_width || m_height != new_height)
m_buffer = new_buffer; {
m_width = new_width; Cell* new_buffer = new Cell[new_width * new_height];
m_height = 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<uint32_t>(m_height, new_height); y++)
for (uint32_t x = 0; x < BAN::Math::min<uint32_t>(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++) update_winsize(m_width, m_height);
for (uint32_t x = 0; x < m_width; x++)
render_from_buffer(x, y);
return {}; return {};
} }

View File

@ -41,6 +41,8 @@ struct winsize
{ {
unsigned short ws_row; unsigned short ws_row;
unsigned short ws_col; unsigned short ws_col;
unsigned short ws_xpixel; /* unused by kernel */
unsigned short ws_ypixel; /* unused by kernel */
}; };
#define TIOCGWINSZ 50 #define TIOCGWINSZ 50
#define TIOCSWINSZ 51 #define TIOCSWINSZ 51

View File

@ -128,9 +128,12 @@ void Terminal::run()
m_window->set_min_size(m_font.width() * 8, m_font.height() * 2); m_window->set_min_size(m_font.width() * 8, m_font.height() * 2);
{ {
winsize winsize; winsize winsize {
winsize.ws_col = cols(); .ws_row = static_cast<unsigned short>(rows()),
winsize.ws_row = rows(); .ws_col = static_cast<unsigned short>(cols()),
.ws_xpixel = static_cast<unsigned short>(m_window->width()),
.ws_ypixel = static_cast<unsigned short>(m_window->height()),
};
if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1) if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1)
perror("ioctl"); perror("ioctl");
} }
@ -170,6 +173,8 @@ void Terminal::run()
const winsize winsize { const winsize winsize {
.ws_row = static_cast<unsigned short>(rows()), .ws_row = static_cast<unsigned short>(rows()),
.ws_col = static_cast<unsigned short>(cols()), .ws_col = static_cast<unsigned short>(cols()),
.ws_xpixel = static_cast<unsigned short>(m_window->width()),
.ws_ypixel = static_cast<unsigned short>(m_window->height()),
}; };
if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1) if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1)
{ {
@ -183,12 +188,6 @@ void Terminal::run()
perror("tcgetpgrp"); perror("tcgetpgrp");
return; 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()); const int max_fd = BAN::Math::max(m_shell_info.pts_master, m_window->server_fd());

View File

@ -328,7 +328,7 @@ int main(int argc, char** argv)
tcsetattr(kb_fd, TCSANOW, &termios); tcsetattr(kb_fd, TCSANOW, &termios);
} }
winsize ws { .ws_row = 0, .ws_col = 0 }; winsize ws {};
if (isatty(STDOUT_FILENO)) if (isatty(STDOUT_FILENO))
{ {
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0) if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0)