Kernel: Don't wrap cursor immediatly at cols()

This prevents unwanted scrolling when writing to bottom right cell
This commit is contained in:
Bananymous 2025-04-23 19:09:16 +03:00
parent cc7c1ad30d
commit dabc3c6cc4
4 changed files with 40 additions and 25 deletions

View File

@ -38,6 +38,7 @@ 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 scroll_if_needed();
private:
enum class State

View File

@ -104,6 +104,11 @@ namespace Kernel
void FramebufferTerminalDriver::show_cursor(bool use_data)
{
// NOTE: cursor is allowed to be on width as scrolling only
// happens after character gets printed to next line
if (m_cursor_x == width())
return;
if (!use_data)
read_cursor();

View File

@ -140,6 +140,10 @@ namespace Kernel
void TextModeTerminalDriver::set_cursor_position(uint32_t x, uint32_t y)
{
// NOTE: cursor is allowed to be on width as scrolling only
// happens after character gets printed to next line
if (x == m_width)
return;
const uint16_t pos = y * m_width + x;
IO::outb(0x3D4, 0x0F);
IO::outb(0x3D5, pos & 0xFF);

View File

@ -385,6 +385,29 @@ namespace Kernel
m_terminal_driver->putchar_at(codepoint, x, y, cell.foreground, cell.background);
}
void VirtualTTY::scroll_if_needed()
{
while (m_row >= m_height)
{
memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell));
// Clear last line in buffer
for (uint32_t x = 0; x < m_width; x++)
m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
if (!m_terminal_driver->scroll(m_background))
{
// No fast scrolling, render the whole buffer to the screen
for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++)
render_from_buffer(x, y);
}
m_column = 0;
m_row--;
}
}
void VirtualTTY::putcodepoint(uint32_t codepoint)
{
ASSERT(m_write_lock.current_processor_has_lock());
@ -416,37 +439,19 @@ namespace Kernel
m_state = State::WaitingAnsiEscape;
break;
default:
if (m_column >= m_width)
{
m_column = 0;
m_row++;
}
scroll_if_needed();
putchar_at(codepoint, m_column, m_row);
m_last_graphic_char = codepoint;
m_column++;
break;
}
if (m_column >= m_width)
{
m_column = 0;
m_row++;
}
while (m_row >= m_height)
{
memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell));
// Clear last line in buffer
for (uint32_t x = 0; x < m_width; x++)
m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
if (!m_terminal_driver->scroll(m_background))
{
// No fast scrolling, render the whole buffer to the screen
for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++)
render_from_buffer(x, y);
}
m_column = 0;
m_row--;
}
scroll_if_needed();
}
void VirtualTTY::putchar_impl(uint8_t ch)