From 40d1d20cd60a6a86ea413950b1c6ab5147261a53 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Fri, 18 Apr 2025 02:43:41 +0300 Subject: [PATCH] Kernel: Move cursor handling from TTY -> TerminalDriver --- .../kernel/Terminal/FramebufferTerminal.h | 29 ++++-- .../include/kernel/Terminal/TerminalDriver.h | 1 + kernel/include/kernel/Terminal/VirtualTTY.h | 2 - .../kernel/Terminal/FramebufferTerminal.cpp | 99 ++++++++++++++++--- kernel/kernel/Terminal/VirtualTTY.cpp | 23 +---- 5 files changed, 110 insertions(+), 44 deletions(-) diff --git a/kernel/include/kernel/Terminal/FramebufferTerminal.h b/kernel/include/kernel/Terminal/FramebufferTerminal.h index 02bf9e76..30120028 100644 --- a/kernel/include/kernel/Terminal/FramebufferTerminal.h +++ b/kernel/include/kernel/Terminal/FramebufferTerminal.h @@ -11,29 +11,38 @@ namespace Kernel public: static BAN::ErrorOr> create(BAN::RefPtr); - virtual 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 width() const override { return m_framebuffer_device->width() / m_font.width(); } + 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; - virtual bool scroll(Color) override; - virtual void clear(Color) override; + void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override; + bool scroll(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); }; - virtual const LibFont::Font& font() const override { return m_font; }; + BAN::ErrorOr set_font(LibFont::Font&& font) override; + const LibFont::Font& font() const override { return m_font; }; private: FramebufferTerminalDriver(BAN::RefPtr framebuffer_device) : m_framebuffer_device(framebuffer_device) { } + void read_cursor(); + void show_cursor(bool use_data); + private: BAN::RefPtr m_framebuffer_device; 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 m_cursor_data; + static constexpr Color m_cursor_color = TerminalColor::BRIGHT_WHITE; }; } diff --git a/kernel/include/kernel/Terminal/TerminalDriver.h b/kernel/include/kernel/Terminal/TerminalDriver.h index a5a7d0c8..3a5fb0bf 100644 --- a/kernel/include/kernel/Terminal/TerminalDriver.h +++ b/kernel/include/kernel/Terminal/TerminalDriver.h @@ -34,6 +34,7 @@ namespace Kernel virtual bool scroll(Color) { return false; } virtual void clear(Color) = 0; + virtual void set_cursor_shown(bool) = 0; virtual void set_cursor_position(uint32_t, uint32_t) = 0; virtual bool has_font() const { return false; } diff --git a/kernel/include/kernel/Terminal/VirtualTTY.h b/kernel/include/kernel/Terminal/VirtualTTY.h index 867c3d04..0f0c4392 100644 --- a/kernel/include/kernel/Terminal/VirtualTTY.h +++ b/kernel/include/kernel/Terminal/VirtualTTY.h @@ -34,7 +34,6 @@ namespace Kernel void putcodepoint(uint32_t codepoint); void putchar_at(uint32_t codepoint, 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: enum class State @@ -82,7 +81,6 @@ namespace Kernel uint32_t m_row { 0 }; uint32_t m_column { 0 }; Cell* m_buffer { nullptr }; - bool m_show_cursor { true }; BAN::RefPtr m_terminal_driver; }; diff --git a/kernel/kernel/Terminal/FramebufferTerminal.cpp b/kernel/kernel/Terminal/FramebufferTerminal.cpp index 38ed6550..9fb4668c 100644 --- a/kernel/kernel/Terminal/FramebufferTerminal.cpp +++ b/kernel/kernel/Terminal/FramebufferTerminal.cpp @@ -5,15 +5,14 @@ namespace Kernel BAN::ErrorOr> FramebufferTerminalDriver::create(BAN::RefPtr framebuffer_device) { - auto font = TRY(LibFont::Font::prefs());; - - auto* driver = new FramebufferTerminalDriver(framebuffer_device); - if (driver == nullptr) + auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device); + if (driver_ptr == nullptr) return BAN::Error::from_errno(ENOMEM); - driver->m_font = BAN::move(font); + auto driver = BAN::RefPtr::adopt(driver_ptr); + TRY(driver->set_font(BAN::move(TRY(LibFont::Font::prefs())))); driver->set_cursor_position(0, 0); driver->clear(TerminalColor::BLACK); - return BAN::RefPtr::adopt(driver); + return driver; } 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()); + + if (x == m_cursor_x && y == m_cursor_y) + { + read_cursor(); + show_cursor(false); + } } bool FramebufferTerminalDriver::scroll(Color color) @@ -45,24 +50,96 @@ namespace Kernel 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 x = 0; x < m_framebuffer_device->width(); x++) m_framebuffer_device->set_pixel(x, y, color.rgb); 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_top = m_font.height() * 13 / 16; - x *= m_font.width(); - y *= m_font.height(); + 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 < m_font.width(); dx++) - m_framebuffer_device->set_pixel(x + dx, y + cursor_top + dy, s_cursor_color.rgb); - m_framebuffer_device->sync_pixels_rectangle(x, y + cursor_top, m_font.width(), cursor_h); + m_cursor_data[dy * m_font.width() + dx] = m_framebuffer_device->get_pixel(x + dx, y + cursor_top + dy); + } + + 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 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(m_cursor_x, 0, width() - 1); + m_cursor_y = BAN::Math::clamp(m_cursor_y, 0, height() - 1); + return {}; } } diff --git a/kernel/kernel/Terminal/VirtualTTY.cpp b/kernel/kernel/Terminal/VirtualTTY.cpp index 0bfab80e..8eab46b8 100644 --- a/kernel/kernel/Terminal/VirtualTTY.cpp +++ b/kernel/kernel/Terminal/VirtualTTY.cpp @@ -92,19 +92,6 @@ namespace Kernel 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() { ASSERT(m_write_lock.current_processor_has_lock()); @@ -370,7 +357,7 @@ namespace Kernel case 'l': 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(); } reset_ansi(); @@ -511,7 +498,6 @@ namespace Kernel return; case State::WaitingAnsiCSI: handle_ansi_csi(ch); - set_cursor_position(m_column, m_row); return; case State::WaitingUTF8: if ((ch & 0xC0) != 0x80) @@ -531,14 +517,9 @@ namespace Kernel ASSERT_NOT_REACHED(); } - bool old_show_cursor = m_show_cursor; - m_show_cursor = false; - set_cursor_position(m_column, m_row); - putcodepoint(codepoint); - m_show_cursor = old_show_cursor; - set_cursor_position(m_column, m_row); + m_terminal_driver->set_cursor_position(m_column, m_row); } }