summaryrefslogtreecommitdiff
path: root/Kernel/TTY
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/TTY')
-rw-r--r--Kernel/TTY/ConsoleManagement.cpp72
-rw-r--r--Kernel/TTY/ConsoleManagement.h41
-rw-r--r--Kernel/TTY/VirtualConsole.cpp382
-rw-r--r--Kernel/TTY/VirtualConsole.h96
4 files changed, 419 insertions, 172 deletions
diff --git a/Kernel/TTY/ConsoleManagement.cpp b/Kernel/TTY/ConsoleManagement.cpp
new file mode 100644
index 0000000000..c9753578f7
--- /dev/null
+++ b/Kernel/TTY/ConsoleManagement.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Singleton.h>
+#include <Kernel/Debug.h>
+#include <Kernel/Graphics/GraphicsManagement.h>
+#include <Kernel/TTY/ConsoleManagement.h>
+
+namespace Kernel {
+
+static AK::Singleton<ConsoleManagement> s_the;
+
+bool ConsoleManagement::is_initialized()
+{
+ if (!s_the.is_initialized())
+ return false;
+ if (s_the->m_consoles.is_empty())
+ return false;
+ if (s_the->m_active_console.is_null())
+ return false;
+ return true;
+}
+
+ConsoleManagement& ConsoleManagement::the()
+{
+ return *s_the;
+}
+
+UNMAP_AFTER_INIT ConsoleManagement::ConsoleManagement()
+{
+}
+
+UNMAP_AFTER_INIT void ConsoleManagement::initialize()
+{
+ for (size_t index = 0; index < 4; index++) {
+ m_consoles.append(VirtualConsole::create(index));
+ }
+ // Note: By default the active console is the first one.
+ m_active_console = m_consoles[0];
+ ScopedSpinLock lock(m_lock);
+ m_active_console->set_active(true);
+}
+
+void ConsoleManagement::switch_to(unsigned index)
+{
+ ScopedSpinLock lock(m_lock);
+ VERIFY(m_active_console);
+ VERIFY(index < m_consoles.size());
+ if (m_active_console->index() == index)
+ return;
+
+ bool was_graphical = m_active_console->is_graphical();
+ m_active_console->set_active(false);
+ m_active_console = m_consoles[index];
+ dbgln_if(VIRTUAL_CONSOLE_DEBUG, "Console: Switch to {}", index);
+
+ // Before setting current console to be "active", switch between graphical mode to "textual" mode
+ // if needed. This will ensure we clear the screen and also that WindowServer won't print anything
+ // in between.
+ if (m_active_console->is_graphical() && !was_graphical) {
+ GraphicsManagement::the().activate_graphical_mode();
+ }
+ if (!m_active_console->is_graphical() && was_graphical) {
+ GraphicsManagement::the().deactivate_graphical_mode();
+ }
+ m_active_console->set_active(true);
+}
+
+}
diff --git a/Kernel/TTY/ConsoleManagement.h b/Kernel/TTY/ConsoleManagement.h
new file mode 100644
index 0000000000..8cca80e860
--- /dev/null
+++ b/Kernel/TTY/ConsoleManagement.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/NonnullRefPtr.h>
+#include <AK/NonnullRefPtrVector.h>
+#include <AK/Types.h>
+#include <Kernel/TTY/VirtualConsole.h>
+
+namespace Kernel {
+
+class ConsoleManagement {
+ AK_MAKE_ETERNAL;
+ friend class VirtualConsole;
+
+public:
+ ConsoleManagement();
+
+ static bool is_initialized();
+ static ConsoleManagement& the();
+
+ void switch_to(unsigned);
+ void initialize();
+
+ NonnullRefPtr<VirtualConsole> first_tty() const { return m_consoles[0]; }
+ NonnullRefPtr<VirtualConsole> debug_tty() const { return m_consoles[1]; }
+
+ RecursiveSpinLock& tty_write_lock() { return m_tty_write_lock; }
+
+private:
+ NonnullRefPtrVector<VirtualConsole> m_consoles;
+ RefPtr<VirtualConsole> m_active_console;
+ SpinLock<u8> m_lock;
+ RecursiveSpinLock m_tty_write_lock;
+};
+
+};
diff --git a/Kernel/TTY/VirtualConsole.cpp b/Kernel/TTY/VirtualConsole.cpp
index 5ac13edee4..f08284a339 100644
--- a/Kernel/TTY/VirtualConsole.cpp
+++ b/Kernel/TTY/VirtualConsole.cpp
@@ -1,128 +1,147 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "VirtualConsole.h"
+#include <AK/StdLibExtras.h>
#include <AK/String.h>
#include <Kernel/Arch/x86/CPU.h>
+#include <Kernel/Debug.h>
#include <Kernel/Devices/HID/HIDManagement.h>
+#include <Kernel/Graphics/GraphicsManagement.h>
#include <Kernel/Heap/kmalloc.h>
#include <Kernel/IO.h>
#include <Kernel/StdLib.h>
+#include <Kernel/TTY/ConsoleManagement.h>
namespace Kernel {
-static u8* s_vga_buffer;
-static VirtualConsole* s_consoles[s_max_virtual_consoles];
-static int s_active_console;
-static RecursiveSpinLock s_lock;
-
-void VirtualConsole::flush_vga_cursor()
+ConsoleImpl::ConsoleImpl(VirtualConsole& client)
+ : Terminal(client)
{
- u16 value = m_current_vga_start_address + (m_terminal.cursor_row() * columns() + m_terminal.cursor_column());
- IO::out8(0x3d4, 0x0e);
- IO::out8(0x3d5, MSB(value));
- IO::out8(0x3d4, 0x0f);
- IO::out8(0x3d5, LSB(value));
}
-UNMAP_AFTER_INIT void VirtualConsole::initialize()
+void ConsoleImpl::invalidate_cursor()
{
- s_vga_buffer = (u8*)0xc00b8000;
- s_active_console = -1;
}
-
-void VirtualConsole::set_graphical(bool graphical)
+void ConsoleImpl::clear()
+{
+ m_client.clear();
+}
+void ConsoleImpl::clear_including_history()
{
- if (graphical)
- set_vga_start_row(0);
-
- m_graphical = graphical;
}
-UNMAP_AFTER_INIT VirtualConsole::VirtualConsole(const unsigned index)
- : TTY(4, index)
- , m_index(index)
- , m_terminal(*this)
+void ConsoleImpl::set_size(u16 determined_columns, u16 determined_rows)
{
- VERIFY(index < s_max_virtual_consoles);
+ VERIFY(determined_columns);
+ VERIFY(determined_rows);
- m_tty_name = String::formatted("/dev/tty{}", m_index);
- m_terminal.set_size(80, 25);
+ if (determined_columns == columns() && determined_rows == rows())
+ return;
- s_consoles[index] = this;
-}
+ m_columns = determined_columns;
+ m_rows = determined_rows;
-UNMAP_AFTER_INIT VirtualConsole::~VirtualConsole()
+ m_cursor_row = min<size_t>((int)m_cursor_row, rows() - 1);
+ m_cursor_column = min<size_t>((int)m_cursor_column, columns() - 1);
+ m_saved_cursor_row = min<size_t>((int)m_saved_cursor_row, rows() - 1);
+ m_saved_cursor_column = min<size_t>((int)m_saved_cursor_column, columns() - 1);
+
+ m_horizontal_tabs.resize(determined_columns);
+ for (unsigned i = 0; i < determined_columns; ++i)
+ m_horizontal_tabs[i] = (i % 8) == 0;
+ // Rightmost column is always last tab on line.
+ m_horizontal_tabs[determined_columns - 1] = 1;
+ m_client.terminal_did_resize(m_columns, m_rows);
+}
+void ConsoleImpl::scroll_up()
{
- VERIFY_NOT_REACHED();
+ // NOTE: We have to invalidate the cursor first.
+ m_client.invalidate_cursor(m_cursor_row);
+ m_client.scroll_up();
}
-
-void VirtualConsole::switch_to(unsigned index)
+void ConsoleImpl::scroll_down()
{
- if ((int)index == s_active_console)
- return;
- VERIFY(index < s_max_virtual_consoles);
- VERIFY(s_consoles[index]);
-
- ScopedSpinLock lock(s_lock);
- if (s_active_console != -1) {
- auto* active_console = s_consoles[s_active_console];
- // We won't know how to switch away from a graphical console until we
- // can set the video mode on our own. Just stop anyone from trying for
- // now.
- if (active_console->is_graphical()) {
- dbgln("Cannot switch away from graphical console yet :(");
- return;
- }
- active_console->set_active(false);
+}
+void ConsoleImpl::newline()
+{
+ u16 new_row = m_cursor_row;
+ u16 max_row = rows() - 1;
+ if (new_row == max_row) {
+ // NOTE: We have to invalidate the cursor first.
+ m_client.invalidate_cursor(new_row);
+ m_client.scroll_up();
+ } else {
+ ++new_row;
}
- dbgln("VC: Switch to {} ({})", index, s_consoles[index]);
- s_active_console = index;
- s_consoles[s_active_console]->set_active(true);
+ set_cursor(new_row, 0);
+}
+void ConsoleImpl::put_character_at(unsigned row, unsigned column, u32 ch)
+{
+ m_client.put_character_at(row, column, ch, m_current_attribute);
+ m_last_code_point = ch;
+}
+void ConsoleImpl::set_window_title(const String&)
+{
+}
+void ConsoleImpl::ICH(Parameters)
+{
+ // FIXME: Implement this
+}
+void ConsoleImpl::IL(Parameters)
+{
+ // FIXME: Implement this
+}
+void ConsoleImpl::DCH(Parameters)
+{
+ // FIXME: Implement this
+}
+void ConsoleImpl::DL(Parameters)
+{
+ // FIXME: Implement this
}
-void VirtualConsole::set_active(bool active)
+void VirtualConsole::set_graphical(bool graphical)
{
- if (active == m_active)
- return;
+ m_graphical = graphical;
+}
- ScopedSpinLock lock(s_lock);
+UNMAP_AFTER_INIT NonnullRefPtr<VirtualConsole> VirtualConsole::create(size_t index)
+{
+ return adopt_ref(*new VirtualConsole(index));
+}
- m_active = active;
+UNMAP_AFTER_INIT VirtualConsole::VirtualConsole(const unsigned index)
+ : TTY(4, index)
+ , m_index(index)
+ , m_console_impl(*this)
+{
+ m_tty_name = String::formatted("/dev/tty{}", m_index);
+ VERIFY(GraphicsManagement::the().console());
+ set_size(GraphicsManagement::the().console()->max_column(), GraphicsManagement::the().console()->max_row());
+ m_console_impl.set_size(GraphicsManagement::the().console()->max_column(), GraphicsManagement::the().console()->max_row());
- if (active) {
- set_vga_start_row(0);
- HIDManagement::the().set_client(this);
+ // Allocate twice of the max row * max column * sizeof(Cell) to ensure we can some sort of history mechanism...
+ auto size = GraphicsManagement::the().console()->max_column() * GraphicsManagement::the().console()->max_row() * sizeof(Cell) * 2;
+ m_cells = MM.allocate_kernel_region(page_round_up(size), "Virtual Console Cells", Region::Access::Read | Region::Access::Write, AllocationStrategy::AllocateNow);
- m_terminal.m_need_full_flush = true;
- flush_dirty_lines();
- } else {
- HIDManagement::the().set_client(nullptr);
+ // Add the lines, so we also ensure they will be flushed now
+ for (size_t row = 0; row < rows(); row++) {
+ m_lines.append({ true });
}
+ clear();
+ VERIFY(m_cells);
}
-enum class VGAColor : u8 {
- Black = 0,
- Blue,
- Green,
- Cyan,
- Red,
- Magenta,
- Brown,
- LightGray,
- DarkGray,
- BrightBlue,
- BrightGreen,
- BrightCyan,
- BrightRed,
- BrightMagenta,
- Yellow,
- White,
-};
+UNMAP_AFTER_INIT VirtualConsole::~VirtualConsole()
+{
+ VERIFY_NOT_REACHED();
+}
enum class ANSIColor : u8 {
Black = 0,
@@ -144,60 +163,53 @@ enum class ANSIColor : u8 {
__Count,
};
-static inline VGAColor ansi_color_to_vga(ANSIColor color)
+static inline Graphics::Console::Color ansi_color_to_standard_vga_color(ANSIColor color)
{
switch (color) {
case ANSIColor::Black:
- return VGAColor::Black;
+ return Graphics::Console::Color::Black;
case ANSIColor::Red:
- return VGAColor::Red;
+ return Graphics::Console::Color::Red;
case ANSIColor::Brown:
- return VGAColor::Brown;
+ return Graphics::Console::Color::Brown;
case ANSIColor::Blue:
- return VGAColor::Blue;
+ return Graphics::Console::Color::Blue;
case ANSIColor::Magenta:
- return VGAColor::Magenta;
+ return Graphics::Console::Color::Magenta;
case ANSIColor::Green:
- return VGAColor::Green;
+ return Graphics::Console::Color::Green;
case ANSIColor::Cyan:
- return VGAColor::Cyan;
+ return Graphics::Console::Color::Cyan;
case ANSIColor::LightGray:
- return VGAColor::LightGray;
+ return Graphics::Console::Color::LightGray;
case ANSIColor::DarkGray:
- return VGAColor::DarkGray;
+ return Graphics::Console::Color::DarkGray;
case ANSIColor::BrightRed:
- return VGAColor::BrightRed;
+ return Graphics::Console::Color::BrightRed;
case ANSIColor::BrightGreen:
- return VGAColor::BrightGreen;
+ return Graphics::Console::Color::BrightGreen;
case ANSIColor::Yellow:
- return VGAColor::Yellow;
+ return Graphics::Console::Color::Yellow;
case ANSIColor::BrightBlue:
- return VGAColor::BrightBlue;
+ return Graphics::Console::Color::BrightBlue;
case ANSIColor::BrightMagenta:
- return VGAColor::BrightMagenta;
+ return Graphics::Console::Color::BrightMagenta;
case ANSIColor::BrightCyan:
- return VGAColor::BrightCyan;
+ return Graphics::Console::Color::BrightCyan;
case ANSIColor::White:
- return VGAColor::White;
+ return Graphics::Console::Color::White;
default:
VERIFY_NOT_REACHED();
}
}
-static inline u8 xterm_color_to_vga(u32 color)
+static inline Graphics::Console::Color xterm_to_standard_color(u32 color)
{
for (u8 i = 0; i < (u8)ANSIColor::__Count; i++) {
if (xterm_colors[i] == color)
- return (u8)ansi_color_to_vga((ANSIColor)i);
+ return (Graphics::Console::Color)ansi_color_to_standard_vga_color((ANSIColor)i);
}
- return (u8)VGAColor::LightGray;
-}
-
-void VirtualConsole::clear_vga_row(u16 row)
-{
- u16* linemem = (u16*)&m_current_vga_window[row * 160];
- for (u16 i = 0; i < columns(); ++i)
- linemem[i] = 0x0720;
+ return Graphics::Console::Color::LightGray;
}
void VirtualConsole::on_key_pressed(KeyEvent event)
@@ -209,26 +221,18 @@ void VirtualConsole::on_key_pressed(KeyEvent event)
if (!event.is_press())
return;
- if (event.key == KeyCode::Key_PageUp && event.flags == Mod_Shift) {
- // TODO: scroll up
- return;
- }
- if (event.key == KeyCode::Key_PageDown && event.flags == Mod_Shift) {
- // TODO: scroll down
- return;
- }
-
Processor::deferred_call_queue([this, event]() {
- m_terminal.handle_key_press(event.key, event.code_point, event.flags);
+ m_console_impl.handle_key_press(event.key, event.code_point, event.flags);
});
}
ssize_t VirtualConsole::on_tty_write(const UserOrKernelBuffer& data, ssize_t size)
{
- ScopedSpinLock lock(s_lock);
+ ScopedSpinLock global_lock(ConsoleManagement::the().tty_write_lock());
+ ScopedSpinLock lock(m_lock);
auto result = data.read_buffered<512>((size_t)size, [&](u8 const* buffer, size_t buffer_bytes) {
for (size_t i = 0; i < buffer_bytes; ++i)
- m_terminal.on_input(buffer[i]);
+ m_console_impl.on_input(buffer[i]);
return buffer_bytes;
});
if (m_active)
@@ -238,52 +242,51 @@ ssize_t VirtualConsole::on_tty_write(const UserOrKernelBuffer& data, ssize_t siz
return (ssize_t)result.value();
}
-void VirtualConsole::set_vga_start_row(u16 row)
-{
- m_vga_start_row = row;
- m_current_vga_start_address = row * columns();
- m_current_vga_window = s_vga_buffer + row * 160;
- IO::out8(0x3d4, 0x0c);
- IO::out8(0x3d5, MSB(m_current_vga_start_address));
- IO::out8(0x3d4, 0x0d);
- IO::out8(0x3d5, LSB(m_current_vga_start_address));
-}
-
-static inline u8 attribute_to_vga(const VT::Attribute& attribute)
+void VirtualConsole::set_active(bool active)
{
- u8 vga_attr = 0x07;
-
- if (attribute.flags & VT::Attribute::Bold)
- vga_attr |= 0x08;
+ VERIFY(ConsoleManagement::the().m_lock.is_locked());
+ VERIFY(m_active != active);
+ m_active = active;
- // Background color
- vga_attr &= ~0x70;
- vga_attr |= xterm_color_to_vga(attribute.effective_background_color()) << 8;
+ if (active) {
+ HIDManagement::the().set_client(this);
- // Foreground color
- vga_attr &= ~0x7;
- vga_attr |= xterm_color_to_vga(attribute.effective_foreground_color());
+ m_console_impl.m_need_full_flush = true;
+ flush_dirty_lines();
+ } else {
+ HIDManagement::the().set_client(nullptr);
+ }
+}
- return vga_attr;
+void VirtualConsole::emit_char(char ch)
+{
+ echo(ch);
}
void VirtualConsole::flush_dirty_lines()
{
- for (u16 visual_row = 0; visual_row < m_terminal.rows(); ++visual_row) {
- auto& line = m_terminal.visible_line(visual_row);
- if (!line.is_dirty() && !m_terminal.m_need_full_flush)
+ VERIFY(GraphicsManagement::is_initialized());
+ VERIFY(GraphicsManagement::the().console());
+ for (u16 visual_row = 0; visual_row < rows(); ++visual_row) {
+ auto& line = m_lines[visual_row];
+ if (!line.dirty && !m_console_impl.m_need_full_flush)
continue;
- for (size_t column = 0; column < line.length(); ++column) {
- u32 code_point = line.code_point(column);
- auto attribute = line.attribute_at(column);
- u16 vga_index = (visual_row * 160) + (column * 2);
- m_current_vga_window[vga_index] = code_point < 128 ? code_point : '?';
- m_current_vga_window[vga_index + 1] = attribute_to_vga(attribute);
+ for (size_t column = 0; column < columns(); ++column) {
+ auto& cell = cell_at(column, visual_row);
+
+ auto foreground_color = xterm_to_standard_color(cell.attribute.effective_foreground_color());
+ if (cell.attribute.flags & VT::Attribute::Flags::Bold)
+ foreground_color = (Graphics::Console::Color)((u8)foreground_color | 0x08);
+ GraphicsManagement::the().console()->write(column,
+ visual_row,
+ ((u8)cell.ch < 128 ? cell.ch : '?'),
+ xterm_to_standard_color(cell.attribute.effective_background_color()),
+ foreground_color);
}
- line.set_dirty(false);
+ line.dirty = false;
}
- flush_vga_cursor();
- m_terminal.m_need_full_flush = false;
+ GraphicsManagement::the().console()->set_cursor(m_console_impl.cursor_column(), m_console_impl.cursor_row());
+ m_console_impl.m_need_full_flush = false;
}
void VirtualConsole::beep()
@@ -304,9 +307,8 @@ void VirtualConsole::set_window_progress(int, int)
void VirtualConsole::terminal_did_resize(u16 columns, u16 rows)
{
- VERIFY(columns == 80);
- VERIFY(rows == 25);
- set_size(columns, rows);
+ // FIXME: Allocate more Region(s) or deallocate them if needed...
+ dbgln("VC {}: Resized to {} x {}", index(), columns, rows);
}
void VirtualConsole::terminal_history_changed()
@@ -333,4 +335,66 @@ void VirtualConsole::echo(u8 ch)
}
}
+VirtualConsole::Cell& VirtualConsole::cell_at(size_t x, size_t y)
+{
+ auto* ptr = (VirtualConsole::Cell*)(m_cells->vaddr().as_ptr());
+ ptr += (y * columns()) + x;
+ return *ptr;
+}
+
+void VirtualConsole::clear()
+{
+ auto* cell = (Cell*)m_cells->vaddr().as_ptr();
+ for (size_t y = 0; y < rows(); y++) {
+ m_lines[y].dirty = true;
+ for (size_t x = 0; x < columns(); x++) {
+ cell[x].clear();
+ }
+ cell += columns();
+ }
+ m_console_impl.set_cursor(0, 0);
+}
+
+void VirtualConsole::scroll_up()
+{
+ memmove(m_cells->vaddr().as_ptr(), m_cells->vaddr().offset(columns() * sizeof(Cell)).as_ptr(), ((rows() - 1) * columns() * sizeof(Cell)));
+ clear_line(rows() - 1);
+ m_console_impl.m_need_full_flush = true;
+}
+
+void VirtualConsole::newline()
+{
+}
+
+void VirtualConsole::clear_line(size_t y_index)
+{
+ m_lines[y_index].dirty = true;
+ for (size_t x = 0; x < columns(); x++) {
+ auto& cell = cell_at(x, y_index);
+ cell.clear();
+ }
+}
+
+void VirtualConsole::put_character_at(unsigned row, unsigned column, u32 code_point, const VT::Attribute& attribute)
+{
+ VERIFY(row < rows());
+ VERIFY(column < columns());
+ auto& line = m_lines[row];
+ auto& cell = cell_at(column, row);
+ cell.attribute.foreground_color = attribute.foreground_color;
+ cell.attribute.background_color = attribute.background_color;
+ cell.attribute.flags = attribute.flags;
+ if (code_point > 128)
+ cell.ch = ' ';
+ else
+ cell.ch = code_point;
+ cell.attribute.flags |= VT::Attribute::Flags::Touched;
+ line.dirty = true;
+}
+
+void VirtualConsole::invalidate_cursor(size_t row)
+{
+ m_lines[row].dirty = true;
+}
+
}
diff --git a/Kernel/TTY/VirtualConsole.h b/Kernel/TTY/VirtualConsole.h
index 10b04771f8..3ad2c0f703 100644
--- a/Kernel/TTY/VirtualConsole.h
+++ b/Kernel/TTY/VirtualConsole.h
@@ -1,35 +1,91 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
+#include <AK/Noncopyable.h>
+#include <AK/NonnullOwnPtrVector.h>
+#include <AK/String.h>
+#include <AK/Vector.h>
+#include <Kernel/API/KeyCode.h>
#include <Kernel/ConsoleDevice.h>
#include <Kernel/Devices/HID/HIDManagement.h>
+#include <Kernel/Graphics/Console/Console.h>
#include <Kernel/TTY/TTY.h>
+#include <LibVT/Attribute.h>
+#include <LibVT/Position.h>
#include <LibVT/Terminal.h>
namespace Kernel {
-static constexpr unsigned s_max_virtual_consoles = 6;
+class ConsoleManagement;
+class VirtualConsole;
+// FIXME: This implementation has no knowledge about keeping terminal history...
+class ConsoleImpl final : public VT::Terminal {
+public:
+ explicit ConsoleImpl(VirtualConsole&);
+
+ virtual void set_size(u16 columns, u16 rows) override;
+
+private:
+ virtual void invalidate_cursor() override;
+ virtual void clear() override;
+ virtual void clear_including_history() override;
+
+ virtual void scroll_up() override;
+ virtual void scroll_down() override;
+ virtual void newline() override;
+ virtual void put_character_at(unsigned row, unsigned column, u32 ch) override;
+ virtual void set_window_title(const String&) override;
+
+ virtual void ICH(Parameters) override;
+
+ virtual void IL(Parameters) override;
+ virtual void DCH(Parameters) override;
+ virtual void DL(Parameters) override;
+};
class VirtualConsole final : public TTY
, public KeyboardClient
, public VT::TerminalClient {
AK_MAKE_ETERNAL
+ friend class ConsoleManagement;
+ friend class ConsoleImpl;
+ friend class VT::Terminal;
+
public:
- VirtualConsole(const unsigned index);
+ struct Line {
+ bool dirty;
+ };
+
+ struct Cell {
+ void clear()
+ {
+ ch = ' ';
+ attribute.reset();
+ }
+ char ch;
+ VT::Attribute attribute;
+ };
+
+public:
+ static NonnullRefPtr<VirtualConsole> create(size_t index);
+
virtual ~VirtualConsole() override;
- static void switch_to(unsigned);
- static void initialize();
+ size_t index() const { return m_index; }
bool is_graphical() { return m_graphical; }
void set_graphical(bool graphical);
+ void emit_char(char);
+
private:
+ VirtualConsole(const unsigned index);
// ^KeyboardClient
virtual void on_key_pressed(KeyEvent) override;
@@ -53,23 +109,37 @@ private:
virtual String device_name() const override;
void set_active(bool);
-
- void flush_vga_cursor();
void flush_dirty_lines();
unsigned m_index;
bool m_active { false };
bool m_graphical { false };
- void clear_vga_row(u16 row);
- void set_vga_start_row(u16 row);
- u16 m_vga_start_row { 0 };
- u16 m_current_vga_start_address { 0 };
- u8* m_current_vga_window { nullptr };
+ String m_tty_name;
+ RecursiveSpinLock m_lock;
- VT::Terminal m_terminal;
+private:
+ void invalidate_cursor(size_t row);
- String m_tty_name;
+ void clear();
+
+ void inject_string(const StringView&);
+
+ Cell& cell_at(size_t column, size_t row);
+
+ typedef Vector<unsigned, 4> ParamVector;
+
+ void on_code_point(u32);
+
+ void scroll_down();
+ void scroll_up();
+ void newline();
+ void clear_line(size_t index);
+ void put_character_at(unsigned row, unsigned column, u32 ch, const VT::Attribute&);
+
+ OwnPtr<Region> m_cells;
+ Vector<VirtualConsole::Line> m_lines;
+ ConsoleImpl m_console_impl;
};
}