Kernel: Move cursor handling from TTY -> TerminalDriver

This commit is contained in:
Bananymous 2025-04-18 02:43:41 +03:00
parent c0942d78cb
commit 40d1d20cd6
5 changed files with 110 additions and 44 deletions

View File

@ -11,29 +11,38 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> create(BAN::RefPtr<FramebufferDevice>); static BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> create(BAN::RefPtr<FramebufferDevice>);
virtual uint32_t width() const override { return m_framebuffer_device->width() / m_font.width(); } uint32_t width() const override { return m_framebuffer_device->width() / m_font.width(); }
virtual uint32_t height() const override { return m_framebuffer_device->height() / m_font.height(); } uint32_t height() const override { return m_framebuffer_device->height() / m_font.height(); }
virtual void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override; void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override;
virtual bool scroll(Color) override; bool scroll(Color) override;
virtual void clear(Color) override; void clear(Color) override;
virtual void set_cursor_position(uint32_t, uint32_t) override; void set_cursor_shown(bool) override;
void set_cursor_position(uint32_t, uint32_t) override;
virtual bool has_font() const override { return true; } bool has_font() const override { return true; }
virtual void set_font(LibFont::Font&& font) override { m_font = BAN::move(font); }; BAN::ErrorOr<void> set_font(LibFont::Font&& font) override;
virtual const LibFont::Font& font() const override { return m_font; }; const LibFont::Font& font() const override { return m_font; };
private: private:
FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device) FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device)
: m_framebuffer_device(framebuffer_device) : m_framebuffer_device(framebuffer_device)
{ } { }
void read_cursor();
void show_cursor(bool use_data);
private: private:
BAN::RefPtr<FramebufferDevice> m_framebuffer_device; BAN::RefPtr<FramebufferDevice> m_framebuffer_device;
LibFont::Font m_font; LibFont::Font m_font;
static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE;
uint32_t m_cursor_x { 0 };
uint32_t m_cursor_y { 0 };
bool m_cursor_shown { true };
BAN::Vector<uint32_t> m_cursor_data;
static constexpr Color m_cursor_color = TerminalColor::BRIGHT_WHITE;
}; };
} }

View File

@ -34,6 +34,7 @@ namespace Kernel
virtual bool scroll(Color) { return false; } virtual bool scroll(Color) { return false; }
virtual void clear(Color) = 0; virtual void clear(Color) = 0;
virtual void set_cursor_shown(bool) = 0;
virtual void set_cursor_position(uint32_t, uint32_t) = 0; virtual void set_cursor_position(uint32_t, uint32_t) = 0;
virtual bool has_font() const { return false; } virtual bool has_font() const { return false; }

View File

@ -34,7 +34,6 @@ namespace Kernel
void putcodepoint(uint32_t codepoint); void putcodepoint(uint32_t codepoint);
void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y); void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y);
void render_from_buffer(uint32_t x, uint32_t y); void render_from_buffer(uint32_t x, uint32_t y);
void set_cursor_position(uint32_t x, uint32_t y);
private: private:
enum class State enum class State
@ -82,7 +81,6 @@ namespace Kernel
uint32_t m_row { 0 }; uint32_t m_row { 0 };
uint32_t m_column { 0 }; uint32_t m_column { 0 };
Cell* m_buffer { nullptr }; Cell* m_buffer { nullptr };
bool m_show_cursor { true };
BAN::RefPtr<TerminalDriver> m_terminal_driver; BAN::RefPtr<TerminalDriver> m_terminal_driver;
}; };

View File

@ -5,15 +5,14 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> FramebufferTerminalDriver::create(BAN::RefPtr<FramebufferDevice> framebuffer_device) BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> FramebufferTerminalDriver::create(BAN::RefPtr<FramebufferDevice> framebuffer_device)
{ {
auto font = TRY(LibFont::Font::prefs());; auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device);
if (driver_ptr == nullptr)
auto* driver = new FramebufferTerminalDriver(framebuffer_device);
if (driver == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
driver->m_font = BAN::move(font); auto driver = BAN::RefPtr<FramebufferTerminalDriver>::adopt(driver_ptr);
TRY(driver->set_font(BAN::move(TRY(LibFont::Font::prefs()))));
driver->set_cursor_position(0, 0); driver->set_cursor_position(0, 0);
driver->clear(TerminalColor::BLACK); driver->clear(TerminalColor::BLACK);
return BAN::RefPtr<FramebufferTerminalDriver>::adopt(driver); return driver;
} }
void FramebufferTerminalDriver::putchar_at(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg) void FramebufferTerminalDriver::putchar_at(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg)
@ -34,6 +33,12 @@ namespace Kernel
} }
m_framebuffer_device->sync_pixels_rectangle(x, y, m_font.width(), m_font.height()); m_framebuffer_device->sync_pixels_rectangle(x, y, m_font.width(), m_font.height());
if (x == m_cursor_x && y == m_cursor_y)
{
read_cursor();
show_cursor(false);
}
} }
bool FramebufferTerminalDriver::scroll(Color color) bool FramebufferTerminalDriver::scroll(Color color)
@ -45,24 +50,96 @@ namespace Kernel
void FramebufferTerminalDriver::clear(Color color) void FramebufferTerminalDriver::clear(Color color)
{ {
for (auto& pixel : m_cursor_data)
pixel = color.rgb;
for (uint32_t y = 0; y < m_framebuffer_device->height(); y++) for (uint32_t y = 0; y < m_framebuffer_device->height(); y++)
for (uint32_t x = 0; x < m_framebuffer_device->width(); x++) for (uint32_t x = 0; x < m_framebuffer_device->width(); x++)
m_framebuffer_device->set_pixel(x, y, color.rgb); m_framebuffer_device->set_pixel(x, y, color.rgb);
m_framebuffer_device->sync_pixels_full(); m_framebuffer_device->sync_pixels_full();
} }
void FramebufferTerminalDriver::set_cursor_position(uint32_t x, uint32_t y) void FramebufferTerminalDriver::read_cursor()
{ {
const uint32_t cursor_h = m_font.height() / 8; const uint32_t cursor_h = m_font.height() / 8;
const uint32_t cursor_top = m_font.height() * 13 / 16; const uint32_t cursor_top = m_font.height() * 13 / 16;
x *= m_font.width(); const uint32_t x = m_cursor_x * m_font.width();
y *= m_font.height(); const uint32_t y = m_cursor_y * m_font.height();
for (uint32_t dy = 0; dy < cursor_h; dy++) for (uint32_t dy = 0; dy < cursor_h; dy++)
for (uint32_t dx = 0; dx < m_font.width(); dx++) for (uint32_t dx = 0; dx < m_font.width(); dx++)
m_framebuffer_device->set_pixel(x + dx, y + cursor_top + dy, s_cursor_color.rgb); m_cursor_data[dy * m_font.width() + dx] = m_framebuffer_device->get_pixel(x + dx, y + cursor_top + dy);
m_framebuffer_device->sync_pixels_rectangle(x, y + cursor_top, m_font.width(), cursor_h); }
void FramebufferTerminalDriver::show_cursor(bool use_data)
{
const auto get_color =
[this, use_data](uint32_t x, uint32_t y) -> uint32_t
{
if (!use_data)
return m_cursor_color.rgb;
return m_cursor_data[y * m_font.width() + x];
};
const uint32_t cursor_h = m_font.height() / 8;
const uint32_t cursor_w = m_font.width();
const uint32_t cursor_top = m_font.height() * 13 / 16;
const uint32_t x = m_cursor_x * m_font.width();
const uint32_t y = m_cursor_y * m_font.height();
for (uint32_t dy = 0; dy < cursor_h; dy++)
for (uint32_t dx = 0; dx < cursor_w; dx++)
m_framebuffer_device->set_pixel(x + dx, y + cursor_top + dy, get_color(dx, dy));
m_framebuffer_device->sync_pixels_rectangle(x, y + cursor_top, cursor_w, cursor_h);
}
void FramebufferTerminalDriver::set_cursor_shown(bool shown)
{
if (m_cursor_shown == shown)
return;
m_cursor_shown = shown;
if (m_cursor_shown)
{
read_cursor();
show_cursor(false);
}
else
{
show_cursor(true);
}
}
void FramebufferTerminalDriver::set_cursor_position(uint32_t x, uint32_t y)
{
if (!m_cursor_shown)
{
m_cursor_x = x;
m_cursor_y = y;
return;
}
show_cursor(true);
m_cursor_x = x;
m_cursor_y = y;
read_cursor();
show_cursor(false);
}
BAN::ErrorOr<void> FramebufferTerminalDriver::set_font(LibFont::Font&& font)
{
const uint32_t cursor_h = font.height() / 8;
const uint32_t cursor_w = font.width();
TRY(m_cursor_data.resize(cursor_h * cursor_w));
for (auto& val : m_cursor_data)
val = TerminalColor::BLACK.rgb;
m_font = BAN::move(font);
m_cursor_x = BAN::Math::clamp<uint32_t>(m_cursor_x, 0, width() - 1);
m_cursor_y = BAN::Math::clamp<uint32_t>(m_cursor_y, 0, height() - 1);
return {};
} }
} }

View File

@ -92,19 +92,6 @@ namespace Kernel
return {}; return {};
} }
void VirtualTTY::set_cursor_position(uint32_t x, uint32_t y)
{
ASSERT(m_write_lock.current_processor_has_lock());
static uint32_t last_x = -1;
static uint32_t last_y = -1;
if (last_x != uint32_t(-1) && last_y != uint32_t(-1))
render_from_buffer(last_x, last_y);
if (m_show_cursor)
m_terminal_driver->set_cursor_position(x, y);
last_x = x;
last_y = y;
}
void VirtualTTY::reset_ansi() void VirtualTTY::reset_ansi()
{ {
ASSERT(m_write_lock.current_processor_has_lock()); ASSERT(m_write_lock.current_processor_has_lock());
@ -370,7 +357,7 @@ namespace Kernel
case 'l': case 'l':
if (m_ansi_state.question && m_ansi_state.nums[0] == 25) if (m_ansi_state.question && m_ansi_state.nums[0] == 25)
{ {
m_show_cursor = (ch == 'h'); m_terminal_driver->set_cursor_shown(ch == 'h');
return reset_ansi(); return reset_ansi();
} }
reset_ansi(); reset_ansi();
@ -511,7 +498,6 @@ namespace Kernel
return; return;
case State::WaitingAnsiCSI: case State::WaitingAnsiCSI:
handle_ansi_csi(ch); handle_ansi_csi(ch);
set_cursor_position(m_column, m_row);
return; return;
case State::WaitingUTF8: case State::WaitingUTF8:
if ((ch & 0xC0) != 0x80) if ((ch & 0xC0) != 0x80)
@ -531,14 +517,9 @@ namespace Kernel
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
bool old_show_cursor = m_show_cursor;
m_show_cursor = false;
set_cursor_position(m_column, m_row);
putcodepoint(codepoint); putcodepoint(codepoint);
m_show_cursor = old_show_cursor; m_terminal_driver->set_cursor_position(m_column, m_row);
set_cursor_position(m_column, m_row);
} }
} }