Compare commits
No commits in common. "7c6966a9c45a8a53f37d3c64c3b7333634ea234c" and "bdbde25784e0e08a8b167c9bc8dcfcdd53e17790" have entirely different histories.
7c6966a9c4
...
bdbde25784
|
@ -89,8 +89,6 @@ set(KERNEL_SOURCES
|
|||
kernel/Terminal/FramebufferTerminal.cpp
|
||||
kernel/Terminal/PseudoTerminal.cpp
|
||||
kernel/Terminal/Serial.cpp
|
||||
kernel/Terminal/TerminalDriver.cpp
|
||||
kernel/Terminal/TextModeTerminal.cpp
|
||||
kernel/Terminal/TTY.cpp
|
||||
kernel/Terminal/VirtualTTY.cpp
|
||||
kernel/Thread.cpp
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#define BANAN_BOOTLOADER_MAGIC 0xD3C60CFF
|
||||
#define BANAN_BOOTLOADER_FB_RGB 1
|
||||
#define BANAN_BOOTLOADER_FB_TEXT 2
|
||||
#define BANAN_BOOTLOADER_FB_RGB 1
|
||||
|
||||
struct BananBootFramebufferInfo
|
||||
{
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace Kernel
|
|||
None,
|
||||
Unknown,
|
||||
RGB,
|
||||
Text,
|
||||
};
|
||||
|
||||
paddr_t address;
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace Kernel
|
|||
uint32_t width() const { return m_width; }
|
||||
uint32_t height() const { return m_height; }
|
||||
|
||||
uint32_t get_pixel(uint32_t x, uint32_t y) const;
|
||||
void set_pixel(uint32_t x, uint32_t y, uint32_t rgb);
|
||||
|
||||
// positive rows -> empty pixels on bottom
|
||||
|
|
|
@ -9,40 +9,25 @@ namespace Kernel
|
|||
class FramebufferTerminalDriver final : public TerminalDriver
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> create(BAN::RefPtr<FramebufferDevice>);
|
||||
static FramebufferTerminalDriver* create(BAN::RefPtr<FramebufferDevice>);
|
||||
|
||||
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 uint32_t width() const override { return m_framebuffer_device->width() / font().width(); }
|
||||
virtual uint32_t height() const override { return m_framebuffer_device->height() / font().height(); }
|
||||
|
||||
void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override;
|
||||
bool scroll(Color) override;
|
||||
void clear(Color) override;
|
||||
virtual void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override;
|
||||
virtual bool scroll(Color) override;
|
||||
virtual void clear(Color) override;
|
||||
|
||||
void set_cursor_shown(bool) override;
|
||||
void set_cursor_position(uint32_t, uint32_t) override;
|
||||
|
||||
bool has_font() const override { return true; }
|
||||
|
||||
BAN::ErrorOr<void> set_font(LibFont::Font&& font) override;
|
||||
const LibFont::Font& font() const override { return m_font; };
|
||||
virtual void set_cursor_position(uint32_t, uint32_t) override;
|
||||
|
||||
private:
|
||||
FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device)
|
||||
: m_framebuffer_device(framebuffer_device)
|
||||
{ }
|
||||
|
||||
void read_cursor();
|
||||
void show_cursor(bool use_data);
|
||||
|
||||
private:
|
||||
BAN::RefPtr<FramebufferDevice> m_framebuffer_device;
|
||||
LibFont::Font m_font;
|
||||
|
||||
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;
|
||||
static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Kernel
|
|||
class TTY : public CharacterDevice
|
||||
{
|
||||
public:
|
||||
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); }
|
||||
virtual void set_font(const LibFont::Font&) {};
|
||||
|
||||
void set_foreground_pgrp(pid_t pgrp) { m_foreground_pgrp = pgrp; }
|
||||
pid_t foreground_pgrp() const { return m_foreground_pgrp; }
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/RefPtr.h>
|
||||
|
||||
#include <LibFont/Font.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class TerminalDriver : public BAN::RefCounted<TerminalDriver>
|
||||
class TerminalDriver
|
||||
{
|
||||
public:
|
||||
struct Color
|
||||
|
@ -25,7 +25,7 @@ namespace Kernel
|
|||
};
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<void> initialize_from_boot_info();
|
||||
TerminalDriver() : m_font(MUST(LibFont::Font::prefs())) {}
|
||||
virtual ~TerminalDriver() {}
|
||||
virtual uint32_t width() const = 0;
|
||||
virtual uint32_t height() const = 0;
|
||||
|
@ -34,15 +34,14 @@ 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; }
|
||||
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); }
|
||||
virtual const LibFont::Font& font() const { ASSERT_NOT_REACHED(); }
|
||||
};
|
||||
void set_font(const LibFont::Font& font) { m_font = font; };
|
||||
const LibFont::Font& font() const { return m_font; }
|
||||
|
||||
extern BAN::RefPtr<TerminalDriver> g_terminal_driver;
|
||||
private:
|
||||
LibFont::Font m_font;
|
||||
};
|
||||
|
||||
namespace TerminalColor
|
||||
{
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/Terminal/TerminalDriver.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class TextModeTerminalDriver final : public TerminalDriver
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<TextModeTerminalDriver>> create_from_boot_info();
|
||||
~TextModeTerminalDriver();
|
||||
|
||||
uint32_t width() const override { return m_width; }
|
||||
uint32_t height() const override { return m_height; }
|
||||
|
||||
void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override;
|
||||
void clear(Color) override;
|
||||
|
||||
void set_cursor_shown(bool) override;
|
||||
void set_cursor_position(uint32_t, uint32_t) override;
|
||||
|
||||
private:
|
||||
TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch)
|
||||
: m_paddr(paddr)
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
, m_pitch(pitch)
|
||||
{}
|
||||
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
private:
|
||||
const paddr_t m_paddr;
|
||||
const uint32_t m_width;
|
||||
const uint32_t m_height;
|
||||
const uint32_t m_pitch;
|
||||
vaddr_t m_vaddr { 0 };
|
||||
static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE;
|
||||
};
|
||||
|
||||
}
|
|
@ -12,9 +12,9 @@ namespace Kernel
|
|||
class VirtualTTY : public TTY
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(BAN::RefPtr<TerminalDriver>);
|
||||
static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(TerminalDriver*);
|
||||
|
||||
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) override;
|
||||
virtual void set_font(const LibFont::Font&) override;
|
||||
|
||||
virtual uint32_t height() const override { return m_height; }
|
||||
virtual uint32_t width() const override { return m_width; }
|
||||
|
@ -26,14 +26,14 @@ namespace Kernel
|
|||
virtual void putchar_impl(uint8_t ch) override;
|
||||
|
||||
private:
|
||||
VirtualTTY(BAN::RefPtr<TerminalDriver>);
|
||||
VirtualTTY(TerminalDriver*);
|
||||
|
||||
void reset_ansi();
|
||||
void handle_ansi_csi(uint8_t ch);
|
||||
void handle_ansi_csi_color(uint8_t ch);
|
||||
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
|
||||
|
@ -81,8 +81,9 @@ namespace Kernel
|
|||
uint32_t m_row { 0 };
|
||||
uint32_t m_column { 0 };
|
||||
Cell* m_buffer { nullptr };
|
||||
bool m_show_cursor { true };
|
||||
|
||||
BAN::RefPtr<TerminalDriver> m_terminal_driver;
|
||||
TerminalDriver* m_terminal_driver { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
#define MULTIBOOT2_TAG_OLD_RSDP 14
|
||||
#define MULTIBOOT2_TAG_NEW_RSDP 15
|
||||
|
||||
#define MULTIBOOT2_FRAMEBUFFER_TYPE_RGB 1
|
||||
#define MULTIBOOT2_FRAMEBUFFER_TYPE_TEXT 2
|
||||
#define MULTIBOOT2_FRAMEBUFFER_TYPE_RGB 1
|
||||
|
||||
#define MULTIBOOT2_MAGIC 0x36d76289
|
||||
|
||||
|
|
|
@ -41,8 +41,6 @@ namespace Kernel
|
|||
g_boot_info.framebuffer.bpp = framebuffer_tag.framebuffer_bpp;
|
||||
if (framebuffer_tag.framebuffer_type == MULTIBOOT2_FRAMEBUFFER_TYPE_RGB)
|
||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::RGB;
|
||||
else if (framebuffer_tag.framebuffer_type == MULTIBOOT2_FRAMEBUFFER_TYPE_TEXT)
|
||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::Text;
|
||||
else
|
||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::Unknown;
|
||||
}
|
||||
|
@ -109,8 +107,6 @@ namespace Kernel
|
|||
g_boot_info.framebuffer.bpp = framebuffer.bpp;
|
||||
if (framebuffer.type == BANAN_BOOTLOADER_FB_RGB)
|
||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::RGB;
|
||||
else if (framebuffer.type == BANAN_BOOTLOADER_FB_TEXT)
|
||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::Text;
|
||||
else
|
||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::Unknown;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <ctype.h>
|
||||
|
||||
bool g_disable_debug = false;
|
||||
extern Kernel::TerminalDriver* g_terminal_driver;
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
#include <kernel/Device/FramebufferDevice.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Memory/Heap.h>
|
||||
#include <kernel/Terminal/FramebufferTerminal.h>
|
||||
#include <kernel/Terminal/TerminalDriver.h>
|
||||
|
||||
#include <sys/framebuffer.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
extern Kernel::TerminalDriver* g_terminal_driver;
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
@ -20,7 +22,8 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> FramebufferDevice::create_from_boot_framebuffer()
|
||||
{
|
||||
ASSERT(g_boot_info.framebuffer.type == FramebufferInfo::Type::RGB);
|
||||
if (g_boot_info.framebuffer.type != FramebufferInfo::Type::RGB)
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
if (g_boot_info.framebuffer.bpp != 24 && g_boot_info.framebuffer.bpp != 32)
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
auto* device_ptr = new FramebufferDevice(
|
||||
|
@ -36,7 +39,6 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto device = BAN::RefPtr<FramebufferDevice>::adopt(device_ptr);
|
||||
TRY(device->initialize());
|
||||
DevFileSystem::get().add_device(device);
|
||||
return device;
|
||||
}
|
||||
|
||||
|
@ -125,15 +127,6 @@ namespace Kernel
|
|||
return bytes_to_copy;
|
||||
}
|
||||
|
||||
uint32_t FramebufferDevice::get_pixel(uint32_t x, uint32_t y) const
|
||||
{
|
||||
ASSERT(x < m_width && y < m_height);
|
||||
const auto* video_buffer_u8 = reinterpret_cast<const uint8_t*>(m_video_buffer->vaddr());
|
||||
return (video_buffer_u8[(y * m_width + x) * (BANAN_FB_BPP / 8) + 0] << 0)
|
||||
| (video_buffer_u8[(y * m_width + x) * (BANAN_FB_BPP / 8) + 1] << 8)
|
||||
| (video_buffer_u8[(y * m_width + x) * (BANAN_FB_BPP / 8) + 2] << 16);
|
||||
}
|
||||
|
||||
void FramebufferDevice::set_pixel(uint32_t x, uint32_t y, uint32_t rgb)
|
||||
{
|
||||
if (x >= m_width || y >= m_height)
|
||||
|
@ -322,8 +315,6 @@ namespace Kernel
|
|||
|
||||
const uint32_t fb_width = m_framebuffer->width();
|
||||
|
||||
// If we are here (in FramebufferMemoryRegion), our terminal driver is FramebufferTerminalDriver
|
||||
ASSERT(g_terminal_driver->has_font());
|
||||
const auto& font = g_terminal_driver->font();
|
||||
|
||||
const uint32_t x = first_pixel % fb_width;
|
||||
|
|
|
@ -210,7 +210,7 @@ namespace Kernel
|
|||
return m_open_files[fd].status_flags();
|
||||
case F_SETFL:
|
||||
extra &= O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC;
|
||||
m_open_files[fd].status_flags() &= O_ACCMODE;
|
||||
m_open_files[fd].status_flags() &= ~O_ACCMODE;
|
||||
m_open_files[fd].status_flags() |= extra;
|
||||
return 0;
|
||||
default:
|
||||
|
|
|
@ -445,9 +445,6 @@ namespace Kernel
|
|||
{
|
||||
ASSERT(m_process_lock.is_locked());
|
||||
|
||||
if (path[0] == '\0')
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
|
||||
auto relative_parent = TRY(find_relative_parent(fd, path));
|
||||
|
||||
VirtualFileSystem::File parent;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
extern Kernel::TerminalDriver* g_terminal_driver;
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
|
|
@ -3,13 +3,11 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> FramebufferTerminalDriver::create(BAN::RefPtr<FramebufferDevice> framebuffer_device)
|
||||
FramebufferTerminalDriver* FramebufferTerminalDriver::create(BAN::RefPtr<FramebufferDevice> framebuffer_device)
|
||||
{
|
||||
auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device);
|
||||
if (driver_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto driver = BAN::RefPtr<FramebufferTerminalDriver>::adopt(driver_ptr);
|
||||
TRY(driver->set_font(BAN::move(TRY(LibFont::Font::prefs()))));
|
||||
auto* driver = new FramebufferTerminalDriver(framebuffer_device);
|
||||
if (driver == nullptr)
|
||||
return nullptr;
|
||||
driver->set_cursor_position(0, 0);
|
||||
driver->clear(TerminalColor::BLACK);
|
||||
return driver;
|
||||
|
@ -17,129 +15,51 @@ namespace Kernel
|
|||
|
||||
void FramebufferTerminalDriver::putchar_at(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg)
|
||||
{
|
||||
const uint8_t* glyph = m_font.has_glyph(ch) ? m_font.glyph(ch) : m_font.glyph('?');
|
||||
const uint8_t* glyph = font().has_glyph(ch) ? font().glyph(ch) : font().glyph('?');
|
||||
|
||||
x *= m_font.width();
|
||||
y *= m_font.height();
|
||||
x *= font().width();
|
||||
y *= font().height();
|
||||
|
||||
for (uint32_t dy = 0; dy < m_font.height() && y + dy < m_framebuffer_device->height(); dy++)
|
||||
for (uint32_t dy = 0; dy < font().height() && y + dy < m_framebuffer_device->height(); dy++)
|
||||
{
|
||||
for (uint32_t dx = 0; dx < m_font.width() && x + dx < m_framebuffer_device->width(); dx++)
|
||||
for (uint32_t dx = 0; dx < font().width() && x + dx < m_framebuffer_device->width(); dx++)
|
||||
{
|
||||
const uint8_t bitmask = 1 << (m_font.width() - dx - 1);
|
||||
const auto color = glyph[dy * m_font.pitch()] & bitmask ? fg : bg;
|
||||
const uint8_t bitmask = 1 << (font().width() - dx - 1);
|
||||
const auto color = glyph[dy * font().pitch()] & bitmask ? fg : bg;
|
||||
m_framebuffer_device->set_pixel(x + dx, y + dy, color.rgb);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
m_framebuffer_device->sync_pixels_rectangle(x, y, font().width(), font().height());
|
||||
}
|
||||
|
||||
bool FramebufferTerminalDriver::scroll(Color color)
|
||||
{
|
||||
m_framebuffer_device->scroll(m_font.height(), color.rgb);
|
||||
m_framebuffer_device->scroll(font().height(), color.rgb);
|
||||
m_framebuffer_device->sync_pixels_full();
|
||||
return true;
|
||||
}
|
||||
|
||||
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::read_cursor()
|
||||
{
|
||||
const uint32_t cursor_h = m_font.height() / 8;
|
||||
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 < m_font.width(); dx++)
|
||||
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;
|
||||
}
|
||||
const uint32_t cursor_h = font().height() / 8;
|
||||
const uint32_t cursor_top = font().height() * 13 / 16;
|
||||
|
||||
show_cursor(true);
|
||||
m_cursor_x = x;
|
||||
m_cursor_y = y;
|
||||
read_cursor();
|
||||
show_cursor(false);
|
||||
}
|
||||
x *= font().width();
|
||||
y *= font().height();
|
||||
|
||||
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 {};
|
||||
for (uint32_t dy = 0; dy < cursor_h; dy++)
|
||||
for (uint32_t dx = 0; dx < 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, font().width(), cursor_h);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ namespace Kernel
|
|||
{
|
||||
auto absolute_path = TRY(Process::current().absolute_path_of(BAN::StringView(reinterpret_cast<const char*>(argument))));
|
||||
auto new_font = TRY(LibFont::Font::load(absolute_path));
|
||||
TRY(set_font(BAN::move(new_font)));
|
||||
set_font(new_font);
|
||||
return 0;
|
||||
}
|
||||
case TIOCGWINSZ:
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
#include <kernel/BootInfo.h>
|
||||
#include <kernel/Terminal/FramebufferTerminal.h>
|
||||
#include <kernel/Terminal/TextModeTerminal.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::RefPtr<TerminalDriver> g_terminal_driver;
|
||||
|
||||
BAN::ErrorOr<void> TerminalDriver::initialize_from_boot_info()
|
||||
{
|
||||
switch (g_boot_info.framebuffer.type)
|
||||
{
|
||||
case FramebufferInfo::Type::None:
|
||||
case FramebufferInfo::Type::Unknown:
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
case FramebufferInfo::Type::RGB:
|
||||
g_terminal_driver = TRY(FramebufferTerminalDriver::create(
|
||||
TRY(FramebufferDevice::create_from_boot_framebuffer())
|
||||
));
|
||||
break;
|
||||
case FramebufferInfo::Type::Text:
|
||||
g_terminal_driver = TRY(TextModeTerminalDriver::create_from_boot_info());
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
#include <kernel/BootInfo.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/MMIO.h>
|
||||
#include <kernel/Terminal/TextModeTerminal.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static constexpr TerminalDriver::Color s_palette[] {
|
||||
TerminalColor::BLACK,
|
||||
TerminalColor::BLUE,
|
||||
TerminalColor::GREEN,
|
||||
TerminalColor::CYAN,
|
||||
TerminalColor::RED,
|
||||
TerminalColor::MAGENTA,
|
||||
TerminalColor::YELLOW,
|
||||
TerminalColor::WHITE,
|
||||
TerminalColor::BRIGHT_BLACK,
|
||||
TerminalColor::BRIGHT_BLUE,
|
||||
TerminalColor::BRIGHT_GREEN,
|
||||
TerminalColor::BRIGHT_CYAN,
|
||||
TerminalColor::BRIGHT_RED,
|
||||
TerminalColor::BRIGHT_MAGENTA,
|
||||
TerminalColor::BRIGHT_YELLOW,
|
||||
TerminalColor::BRIGHT_WHITE,
|
||||
};
|
||||
|
||||
static constexpr uint8_t color_to_text_mode_color(TerminalDriver::Color color)
|
||||
{
|
||||
uint32_t min_diff = BAN::numeric_limits<uint32_t>::max();
|
||||
uint8_t closest = 0;
|
||||
|
||||
static_assert(sizeof(s_palette) / sizeof(*s_palette) == 16);
|
||||
for (size_t i = 0; i < 16; i++)
|
||||
{
|
||||
const auto rdiff = color.red() - s_palette[i].red();
|
||||
const auto gdiff = color.green() - s_palette[i].green();
|
||||
const auto bdiff = color.blue() - s_palette[i].blue();
|
||||
const uint32_t diff = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff;
|
||||
if (diff >= min_diff)
|
||||
continue;
|
||||
min_diff = diff;
|
||||
closest = i;
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<TextModeTerminalDriver>> TextModeTerminalDriver::create_from_boot_info()
|
||||
{
|
||||
ASSERT(g_boot_info.framebuffer.type == FramebufferInfo::Type::Text);
|
||||
if (g_boot_info.framebuffer.bpp != 16)
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
auto* driver_ptr = new TextModeTerminalDriver(
|
||||
g_boot_info.framebuffer.address,
|
||||
g_boot_info.framebuffer.width,
|
||||
g_boot_info.framebuffer.height,
|
||||
g_boot_info.framebuffer.pitch
|
||||
);
|
||||
if (driver_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto driver = BAN::RefPtr<TextModeTerminalDriver>::adopt(driver_ptr);
|
||||
TRY(driver->initialize());
|
||||
return driver;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> TextModeTerminalDriver::initialize()
|
||||
{
|
||||
const size_t page_count = range_page_count(m_paddr, m_height * m_pitch);
|
||||
const vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(page_count, KERNEL_OFFSET);
|
||||
if (vaddr == 0)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
PageTable::kernel().map_range_at(
|
||||
m_paddr & PAGE_ADDR_MASK,
|
||||
vaddr,
|
||||
page_count * PAGE_SIZE,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
PageTable::MemoryType::WriteCombining
|
||||
);
|
||||
|
||||
m_vaddr = vaddr + (m_paddr % PAGE_SIZE);
|
||||
|
||||
set_cursor_position(0, 0);
|
||||
clear(TerminalColor::BLACK);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
TextModeTerminalDriver::~TextModeTerminalDriver()
|
||||
{
|
||||
if (m_vaddr == 0)
|
||||
return;
|
||||
const size_t page_count = range_page_count(m_paddr, m_height * m_pitch);
|
||||
PageTable::kernel().unmap_range(m_vaddr & PAGE_ADDR_MASK, page_count * PAGE_SIZE);
|
||||
}
|
||||
|
||||
void TextModeTerminalDriver::putchar_at(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg)
|
||||
{
|
||||
if (x >= m_width || y >= m_height)
|
||||
return;
|
||||
|
||||
if (ch >= 0x100)
|
||||
ch = '?';
|
||||
|
||||
const uint8_t color =
|
||||
(color_to_text_mode_color(bg) << 4) |
|
||||
(color_to_text_mode_color(fg) << 0);
|
||||
MMIO::write16(m_vaddr + y * m_pitch + 2 * x, ch | (color << 8));
|
||||
}
|
||||
|
||||
void TextModeTerminalDriver::clear(Color color)
|
||||
{
|
||||
for (uint32_t y = 0; y < m_height; y++)
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
putchar_at(' ', x, y, TerminalColor::BRIGHT_WHITE, color);
|
||||
}
|
||||
|
||||
void TextModeTerminalDriver::set_cursor_shown(bool shown)
|
||||
{
|
||||
if (shown)
|
||||
{
|
||||
IO::outb(0x3D4, 0x0A);
|
||||
IO::outb(0x3D5, (IO::inb(0x3D5) & 0xC0) | 14);
|
||||
|
||||
IO::outb(0x3D4, 0x0B);
|
||||
IO::outb(0x3D5, (IO::inb(0x3D5) & 0xE0) | 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
IO::outb(0x3D4, 0x0A);
|
||||
IO::outb(0x3D5, 0x20);
|
||||
}
|
||||
}
|
||||
|
||||
void TextModeTerminalDriver::set_cursor_position(uint32_t x, uint32_t y)
|
||||
{
|
||||
const uint16_t pos = y * m_width + x;
|
||||
IO::outb(0x3D4, 0x0F);
|
||||
IO::outb(0x3D5, pos & 0xFF);
|
||||
IO::outb(0x3D4, 0x0E);
|
||||
IO::outb(0x3D5, pos >> 8);
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,7 @@ namespace Kernel
|
|||
|
||||
static BAN::Atomic<uint32_t> s_next_tty_number = 0;
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> VirtualTTY::create(BAN::RefPtr<TerminalDriver> driver)
|
||||
BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> VirtualTTY::create(TerminalDriver* driver)
|
||||
{
|
||||
auto* tty_ptr = new VirtualTTY(driver);
|
||||
ASSERT(tty_ptr);
|
||||
|
@ -35,7 +35,7 @@ namespace Kernel
|
|||
return tty;
|
||||
}
|
||||
|
||||
VirtualTTY::VirtualTTY(BAN::RefPtr<TerminalDriver> driver)
|
||||
VirtualTTY::VirtualTTY(TerminalDriver* driver)
|
||||
: TTY(0600, 0, 0)
|
||||
, m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++)))
|
||||
, m_terminal_driver(driver)
|
||||
|
@ -55,14 +55,11 @@ namespace Kernel
|
|||
m_terminal_driver->clear(m_background);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> VirtualTTY::set_font(LibFont::Font&& font)
|
||||
void VirtualTTY::set_font(const LibFont::Font& font)
|
||||
{
|
||||
if (!m_terminal_driver->has_font())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
SpinLockGuard _(m_write_lock);
|
||||
|
||||
TRY(m_terminal_driver->set_font(BAN::move(font)));
|
||||
m_terminal_driver->set_font(font);
|
||||
|
||||
uint32_t new_width = m_terminal_driver->width();
|
||||
uint32_t new_height = m_terminal_driver->height();
|
||||
|
@ -88,8 +85,19 @@ namespace Kernel
|
|||
for (uint32_t y = 0; y < m_height; y++)
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
render_from_buffer(x, y);
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -321,24 +329,23 @@ namespace Kernel
|
|||
case '@':
|
||||
if (m_ansi_state.nums[0] == -1)
|
||||
m_ansi_state.nums[0] = 1;
|
||||
m_ansi_state.nums[0] = BAN::Math::min<uint32_t>(m_ansi_state.nums[0], m_width - m_column);
|
||||
memmove(
|
||||
&m_buffer[m_row * m_width + m_column],
|
||||
&m_buffer[m_row * m_width + m_column + m_ansi_state.nums[0]],
|
||||
m_width - m_column - m_ansi_state.nums[0]
|
||||
);
|
||||
reset_ansi();
|
||||
for (int i = 0; i < m_ansi_state.nums[0]; i++)
|
||||
putchar_at(' ', m_column + i, m_row);
|
||||
for (uint32_t x = m_column + m_ansi_state.nums[0]; x < m_width; x++)
|
||||
render_from_buffer(x, m_row);
|
||||
return reset_ansi();
|
||||
putchar_impl(' ');
|
||||
return;
|
||||
case 'b':
|
||||
if (m_ansi_state.nums[0] == -1)
|
||||
m_ansi_state.nums[0] = 1;
|
||||
reset_ansi();
|
||||
if (m_last_graphic_char)
|
||||
{
|
||||
char buffer[5] {};
|
||||
BAN::UTF8::from_codepoints(&m_last_graphic_char, 1, buffer);
|
||||
for (int i = 0; i < m_ansi_state.nums[0]; i++)
|
||||
putcodepoint(m_last_graphic_char);
|
||||
return reset_ansi();
|
||||
for (int j = 0; buffer[j]; j++)
|
||||
putchar_impl(buffer[j]);
|
||||
}
|
||||
return;
|
||||
case 'd':
|
||||
if (m_ansi_state.nums[0] == -1)
|
||||
m_ansi_state.nums[0] = 1;
|
||||
|
@ -348,7 +355,7 @@ namespace Kernel
|
|||
if (m_ansi_state.index == 0 || m_ansi_state.nums[0] == -1)
|
||||
{
|
||||
m_ansi_state.question = true;
|
||||
return;
|
||||
return reset_ansi();
|
||||
}
|
||||
reset_ansi();
|
||||
dprintln_if(DEBUG_VTTY, "invalid ANSI CSI ?");
|
||||
|
@ -357,7 +364,7 @@ namespace Kernel
|
|||
case 'l':
|
||||
if (m_ansi_state.question && m_ansi_state.nums[0] == 25)
|
||||
{
|
||||
m_terminal_driver->set_cursor_shown(ch == 'h');
|
||||
m_show_cursor = (ch == 'h');
|
||||
return reset_ansi();
|
||||
}
|
||||
reset_ansi();
|
||||
|
@ -389,10 +396,75 @@ namespace Kernel
|
|||
m_terminal_driver->putchar_at(codepoint, x, y, m_foreground, m_background);
|
||||
}
|
||||
|
||||
void VirtualTTY::putcodepoint(uint32_t codepoint)
|
||||
void VirtualTTY::putchar_impl(uint8_t ch)
|
||||
{
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
|
||||
uint32_t codepoint = ch;
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case State::Normal:
|
||||
if ((ch & 0x80) == 0)
|
||||
break;
|
||||
if ((ch & 0xE0) == 0xC0)
|
||||
{
|
||||
m_utf8_state.codepoint = ch & 0x1F;
|
||||
m_utf8_state.bytes_missing = 1;
|
||||
}
|
||||
else if ((ch & 0xF0) == 0xE0)
|
||||
{
|
||||
m_utf8_state.codepoint = ch & 0x0F;
|
||||
m_utf8_state.bytes_missing = 2;
|
||||
}
|
||||
else if ((ch & 0xF8) == 0xF0)
|
||||
{
|
||||
m_utf8_state.codepoint = ch & 0x07;
|
||||
m_utf8_state.bytes_missing = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset_ansi();
|
||||
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
||||
return;
|
||||
}
|
||||
m_state = State::WaitingUTF8;
|
||||
return;
|
||||
case State::WaitingAnsiEscape:
|
||||
if (ch == CSI)
|
||||
m_state = State::WaitingAnsiCSI;
|
||||
else
|
||||
{
|
||||
reset_ansi();
|
||||
dprintln_if(DEBUG_VTTY, "unsupported byte after ansi escape {2H}", (uint8_t)ch);
|
||||
}
|
||||
return;
|
||||
case State::WaitingAnsiCSI:
|
||||
handle_ansi_csi(ch);
|
||||
set_cursor_position(m_column, m_row);
|
||||
return;
|
||||
case State::WaitingUTF8:
|
||||
if ((ch & 0xC0) != 0x80)
|
||||
{
|
||||
m_state = State::Normal;
|
||||
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
||||
return;
|
||||
}
|
||||
m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F);
|
||||
m_utf8_state.bytes_missing--;
|
||||
if (m_utf8_state.bytes_missing)
|
||||
return;
|
||||
m_state = State::Normal;
|
||||
codepoint = m_utf8_state.codepoint;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
bool old_show_cursor = m_show_cursor;
|
||||
m_show_cursor = false;
|
||||
set_cursor_position(m_column, m_row);
|
||||
|
||||
switch (codepoint)
|
||||
{
|
||||
case BEL: // TODO
|
||||
|
@ -451,75 +523,9 @@ namespace Kernel
|
|||
m_column = 0;
|
||||
m_row--;
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualTTY::putchar_impl(uint8_t ch)
|
||||
{
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
|
||||
uint32_t codepoint = ch;
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case State::Normal:
|
||||
if ((ch & 0x80) == 0)
|
||||
break;
|
||||
if ((ch & 0xE0) == 0xC0)
|
||||
{
|
||||
m_utf8_state.codepoint = ch & 0x1F;
|
||||
m_utf8_state.bytes_missing = 1;
|
||||
}
|
||||
else if ((ch & 0xF0) == 0xE0)
|
||||
{
|
||||
m_utf8_state.codepoint = ch & 0x0F;
|
||||
m_utf8_state.bytes_missing = 2;
|
||||
}
|
||||
else if ((ch & 0xF8) == 0xF0)
|
||||
{
|
||||
m_utf8_state.codepoint = ch & 0x07;
|
||||
m_utf8_state.bytes_missing = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset_ansi();
|
||||
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
||||
return;
|
||||
}
|
||||
m_state = State::WaitingUTF8;
|
||||
return;
|
||||
case State::WaitingAnsiEscape:
|
||||
if (ch == CSI)
|
||||
m_state = State::WaitingAnsiCSI;
|
||||
else
|
||||
{
|
||||
reset_ansi();
|
||||
dprintln_if(DEBUG_VTTY, "unsupported byte after ansi escape {2H}", (uint8_t)ch);
|
||||
}
|
||||
return;
|
||||
case State::WaitingAnsiCSI:
|
||||
handle_ansi_csi(ch);
|
||||
return;
|
||||
case State::WaitingUTF8:
|
||||
if ((ch & 0xC0) != 0x80)
|
||||
{
|
||||
m_state = State::Normal;
|
||||
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
||||
return;
|
||||
}
|
||||
m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F);
|
||||
m_utf8_state.bytes_missing--;
|
||||
if (m_utf8_state.bytes_missing)
|
||||
return;
|
||||
m_state = State::Normal;
|
||||
codepoint = m_utf8_state.codepoint;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
putcodepoint(codepoint);
|
||||
|
||||
m_terminal_driver->set_cursor_position(m_column, m_row);
|
||||
m_show_cursor = old_show_cursor;
|
||||
set_cursor_position(m_column, m_row);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -107,6 +107,8 @@ static void parse_command_line()
|
|||
}
|
||||
}
|
||||
|
||||
Kernel::TerminalDriver* g_terminal_driver = nullptr;
|
||||
|
||||
static void init2(void*);
|
||||
|
||||
extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
|
||||
|
@ -161,10 +163,14 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
|
|||
DevFileSystem::initialize();
|
||||
dprintln("devfs initialized");
|
||||
|
||||
if (auto ret = TerminalDriver::initialize_from_boot_info(); ret.is_error())
|
||||
dprintln("failed to initialize terminal driver: {}", ret.error());
|
||||
else
|
||||
dprintln("terminal driver initialized");
|
||||
auto framebuffer_device = FramebufferDevice::create_from_boot_framebuffer();
|
||||
if (!framebuffer_device.is_error())
|
||||
{
|
||||
DevFileSystem::get().add_device(framebuffer_device.value());
|
||||
g_terminal_driver = FramebufferTerminalDriver::create(framebuffer_device.value());
|
||||
}
|
||||
if (g_terminal_driver)
|
||||
dprintln("Framebuffer terminal initialized");
|
||||
|
||||
if (!cmdline.disable_smp)
|
||||
InterruptController::get().initialize_multiprocessor();
|
||||
|
|
|
@ -147,10 +147,7 @@ char* strcat(char* __restrict__ dest, const char* __restrict__ src)
|
|||
|
||||
char* strncat(char* __restrict__ dest, const char* __restrict__ src, size_t n)
|
||||
{
|
||||
dest += strlen(dest);
|
||||
while (*src && n--)
|
||||
*dest++ = *src++;
|
||||
*dest = '\0';
|
||||
strncpy(dest + strlen(dest), src, n);
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
|
|
@ -211,27 +211,6 @@ namespace LibGUI
|
|||
set_pixel(x, dst_y + fill_y_off + i, fill_color);
|
||||
}
|
||||
|
||||
void Window::copy_rect(int32_t dst_x, int32_t dst_y, int32_t src_x, int32_t src_y, uint32_t width, uint32_t height, uint32_t fill_color)
|
||||
{
|
||||
fill_rect(dst_x, dst_y, width, height, fill_color);
|
||||
|
||||
if (!clamp_to_framebuffer(dst_x, dst_y, width, height))
|
||||
return;
|
||||
if (!clamp_to_framebuffer(src_x, src_y, width, height))
|
||||
return;
|
||||
|
||||
const bool copy_dir = dst_y < src_y;
|
||||
for (uint32_t i = 0; i < height; i++)
|
||||
{
|
||||
const uint32_t y_off = copy_dir ? i : height - i - 1;
|
||||
memmove(
|
||||
&m_framebuffer[(dst_y + y_off) * this->width()],
|
||||
&m_framebuffer[(src_y + y_off) * this->width()],
|
||||
width * 4
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool Window::clamp_to_framebuffer(int32_t& signed_x, int32_t& signed_y, uint32_t& width, uint32_t& height) const
|
||||
{
|
||||
int32_t min_x = BAN::Math::max<int32_t>(signed_x, 0);
|
||||
|
|
|
@ -59,10 +59,6 @@ namespace LibGUI
|
|||
// fill_color is used when copying data outside of window bounds
|
||||
void copy_horizontal_slice(int32_t dst_y, int32_t src_y, uint32_t amount, uint32_t fill_color);
|
||||
|
||||
// copy rect (src_x, src_y, width, height) to (dst_x, dst_y, width, height)
|
||||
// fill_color is used when copying data outside of window bounds
|
||||
void copy_rect(int32_t dst_x, int32_t dst_y, int32_t src_x, int32_t src_y, uint32_t width, uint32_t height, uint32_t fill_color);
|
||||
|
||||
void invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
void invalidate() { return invalidate(0, 0, width(), height()); }
|
||||
|
||||
|
|
|
@ -32,9 +32,6 @@ static constexpr uint32_t s_colors_bright[] {
|
|||
0xCC'FFFFFF,
|
||||
};
|
||||
|
||||
static constexpr auto s_default_bg_color = s_colors_dark[0];
|
||||
static constexpr auto s_default_fg_color = s_colors_bright[7];
|
||||
|
||||
void Terminal::start_shell()
|
||||
{
|
||||
int pts_master = posix_openpt(O_RDWR | O_NOCTTY);
|
||||
|
@ -111,8 +108,8 @@ void Terminal::run()
|
|||
signal(SIGCHLD, [](int) { s_shell_exited = true; });
|
||||
start_shell();
|
||||
|
||||
m_bg_color = s_default_bg_color;
|
||||
m_fg_color = s_default_fg_color;
|
||||
m_bg_color = s_colors_dark[0];
|
||||
m_fg_color = s_colors_bright[7];
|
||||
|
||||
auto attributes = LibGUI::Window::default_attributes;
|
||||
attributes.alpha_channel = true;
|
||||
|
@ -281,8 +278,8 @@ void Terminal::handle_sgr()
|
|||
switch (m_csi_info.fields[0])
|
||||
{
|
||||
case -1: case 0:
|
||||
m_bg_color = s_default_bg_color;
|
||||
m_fg_color = s_default_fg_color;
|
||||
m_bg_color = s_colors_dark[0];
|
||||
m_fg_color = s_colors_bright[7];
|
||||
break;
|
||||
case 1:
|
||||
// FIXME: bold
|
||||
|
@ -290,21 +287,12 @@ void Terminal::handle_sgr()
|
|||
case 7:
|
||||
BAN::swap(m_fg_color, m_bg_color);
|
||||
break;
|
||||
case 10:
|
||||
// default font
|
||||
break;
|
||||
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37:
|
||||
m_fg_color = s_colors_dark[m_csi_info.fields[0] - 30];
|
||||
break;
|
||||
case 39:
|
||||
m_fg_color = s_default_fg_color;
|
||||
break;
|
||||
case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
|
||||
m_bg_color = s_colors_dark[m_csi_info.fields[0] - 40];
|
||||
break;
|
||||
case 49:
|
||||
m_bg_color = s_default_bg_color;
|
||||
break;
|
||||
case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97:
|
||||
m_fg_color = s_colors_bright[m_csi_info.fields[0] - 90];
|
||||
break;
|
||||
|
@ -344,25 +332,15 @@ Rectangle Terminal::handle_csi(char ch)
|
|||
Rectangle should_invalidate;
|
||||
switch (ch)
|
||||
{
|
||||
case 'A':
|
||||
if (m_csi_info.fields[0] == -1)
|
||||
m_csi_info.fields[0] = 1;
|
||||
m_cursor.y = BAN::Math::max<int32_t>(m_cursor.y - m_csi_info.fields[0], 0);
|
||||
break;
|
||||
case 'B':
|
||||
if (m_csi_info.fields[0] == -1)
|
||||
m_csi_info.fields[0] = 1;
|
||||
m_cursor.y = BAN::Math::min<int32_t>(m_cursor.y + m_csi_info.fields[0], rows() - 1);
|
||||
break;
|
||||
case 'C':
|
||||
if (m_csi_info.fields[0] == -1)
|
||||
m_csi_info.fields[0] = 1;
|
||||
m_cursor.x = BAN::Math::min<int32_t>(m_cursor.x + m_csi_info.fields[0], cols() - 1);
|
||||
m_cursor.x = BAN::Math::clamp<int32_t>(m_cursor.x + m_csi_info.fields[0], 0, cols() - 1);
|
||||
break;
|
||||
case 'D':
|
||||
if (m_csi_info.fields[0] == -1)
|
||||
m_csi_info.fields[0] = 1;
|
||||
m_cursor.x = BAN::Math::max<int32_t>(m_cursor.x - m_csi_info.fields[0], 0);
|
||||
m_cursor.x = BAN::Math::clamp<int32_t>((int32_t)m_cursor.x - m_csi_info.fields[0], 0, cols() - 1);
|
||||
break;
|
||||
case 'G':
|
||||
m_cursor.x = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, cols()) - 1;
|
||||
|
@ -471,34 +449,6 @@ Rectangle Terminal::handle_csi(char ch)
|
|||
|
||||
break;
|
||||
}
|
||||
case '@':
|
||||
{
|
||||
const uint32_t count = (m_csi_info.fields[0] == -1) ? 1 : m_csi_info.fields[0];
|
||||
const uint32_t dst_x = (m_cursor.x + count) * m_font.width();
|
||||
const uint32_t src_x = m_cursor.x * m_font.width();
|
||||
const uint32_t y = m_cursor.y * m_font.height();
|
||||
|
||||
m_window->copy_rect(dst_x, y, src_x, y, m_window->width() - dst_x, m_font.height(), m_bg_color);
|
||||
m_window->fill_rect(src_x, y, count * m_font.width(), m_font.height(), m_bg_color);
|
||||
should_invalidate = {
|
||||
src_x,
|
||||
y,
|
||||
m_window->width() - src_x,
|
||||
m_font.height()
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
case 'b':
|
||||
if (m_csi_info.fields[0] == -1)
|
||||
m_csi_info.fields[0] = 1;
|
||||
if (m_last_graphic_char)
|
||||
for (int32_t i = 0; i < m_csi_info.fields[0]; i++)
|
||||
should_invalidate = should_invalidate.get_bounding_box(putcodepoint(m_last_graphic_char));
|
||||
break;
|
||||
case 'd':
|
||||
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
|
||||
break;
|
||||
case 'm':
|
||||
handle_sgr();
|
||||
break;
|
||||
|
@ -526,59 +476,6 @@ Rectangle Terminal::handle_csi(char ch)
|
|||
return should_invalidate;
|
||||
}
|
||||
|
||||
Rectangle Terminal::putcodepoint(uint32_t codepoint)
|
||||
{
|
||||
Rectangle should_invalidate;
|
||||
|
||||
switch (codepoint)
|
||||
{
|
||||
case '\e':
|
||||
m_state = State::ESC;
|
||||
break;
|
||||
case '\n':
|
||||
m_cursor.x = 0;
|
||||
m_cursor.y++;
|
||||
break;
|
||||
case '\r':
|
||||
m_cursor.x = 0;
|
||||
break;
|
||||
case '\b':
|
||||
if (m_cursor.x > 0)
|
||||
m_cursor.x--;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
const uint32_t cell_w = m_font.width();
|
||||
const uint32_t cell_h = m_font.height();
|
||||
const uint32_t cell_x = m_cursor.x * cell_w;
|
||||
const uint32_t cell_y = m_cursor.y * cell_h;
|
||||
|
||||
m_window->fill_rect(cell_x, cell_y, cell_w, cell_h, m_bg_color);
|
||||
m_window->draw_character(codepoint, m_font, cell_x, cell_y, m_fg_color);
|
||||
m_last_graphic_char = codepoint;
|
||||
should_invalidate = { cell_x, cell_y, cell_w, cell_h };
|
||||
m_cursor.x++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cursor.x >= cols())
|
||||
{
|
||||
m_cursor.x = 0;
|
||||
m_cursor.y++;
|
||||
}
|
||||
|
||||
if (m_cursor.y >= rows())
|
||||
{
|
||||
const uint32_t scroll = m_cursor.y - rows() + 1;
|
||||
m_cursor.y -= scroll;
|
||||
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
|
||||
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
|
||||
}
|
||||
|
||||
return should_invalidate;
|
||||
}
|
||||
|
||||
Rectangle Terminal::putchar(uint8_t ch)
|
||||
{
|
||||
if (m_state == State::ESC)
|
||||
|
@ -641,7 +538,54 @@ Rectangle Terminal::putchar(uint8_t ch)
|
|||
return {};
|
||||
}
|
||||
|
||||
return putcodepoint(codepoint);
|
||||
Rectangle should_invalidate;
|
||||
|
||||
switch (codepoint)
|
||||
{
|
||||
case '\e':
|
||||
m_state = State::ESC;
|
||||
break;
|
||||
case '\n':
|
||||
m_cursor.x = 0;
|
||||
m_cursor.y++;
|
||||
break;
|
||||
case '\r':
|
||||
m_cursor.x = 0;
|
||||
break;
|
||||
case '\b':
|
||||
if (m_cursor.x > 0)
|
||||
m_cursor.x--;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
const uint32_t cell_w = m_font.width();
|
||||
const uint32_t cell_h = m_font.height();
|
||||
const uint32_t cell_x = m_cursor.x * cell_w;
|
||||
const uint32_t cell_y = m_cursor.y * cell_h;
|
||||
|
||||
m_window->fill_rect(cell_x, cell_y, cell_w, cell_h, m_bg_color);
|
||||
m_window->draw_character(codepoint, m_font, cell_x, cell_y, m_fg_color);
|
||||
should_invalidate = { cell_x, cell_y, cell_w, cell_h };
|
||||
m_cursor.x++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cursor.x >= cols())
|
||||
{
|
||||
m_cursor.x = 0;
|
||||
m_cursor.y++;
|
||||
}
|
||||
|
||||
if (m_cursor.y >= rows())
|
||||
{
|
||||
const uint32_t scroll = m_cursor.y - rows() + 1;
|
||||
m_cursor.y -= scroll;
|
||||
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
|
||||
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
|
||||
}
|
||||
|
||||
return should_invalidate;
|
||||
}
|
||||
|
||||
void Terminal::on_key_event(LibGUI::EventPacket::KeyEvent::event_t event)
|
||||
|
|
|
@ -37,7 +37,6 @@ public:
|
|||
private:
|
||||
void handle_sgr();
|
||||
Rectangle handle_csi(char ch);
|
||||
Rectangle putcodepoint(uint32_t codepoint);
|
||||
Rectangle putchar(uint8_t ch);
|
||||
bool read_shell();
|
||||
|
||||
|
@ -92,8 +91,6 @@ private:
|
|||
uint8_t m_utf8_index { 0 };
|
||||
uint8_t m_utf8_bytes[4] { };
|
||||
|
||||
uint32_t m_last_graphic_char { 0 };
|
||||
|
||||
Cursor m_saved_cursor { 0, 0 };
|
||||
uint32_t m_fg_color { 0 };
|
||||
uint32_t m_bg_color { 0 };
|
||||
|
|
Loading…
Reference in New Issue