Compare commits
21 Commits
ae3ae6fd0e
...
530c259e71
Author | SHA1 | Date |
---|---|---|
Bananymous | 530c259e71 | |
Bananymous | 843a6851c4 | |
Bananymous | 234051d6bc | |
Bananymous | 981c0eb8bc | |
Bananymous | 1066855532 | |
Bananymous | f2d6518311 | |
Bananymous | 765ccfa18c | |
Bananymous | 201aee3119 | |
Bananymous | 65f299038d | |
Bananymous | bd1290706a | |
Bananymous | 939cbf46e4 | |
Bananymous | aec5a09caf | |
Bananymous | 6346d1b6c7 | |
Bananymous | 05ee242b80 | |
Bananymous | 64be3f05a3 | |
Bananymous | cfdce9be61 | |
Bananymous | 446220494e | |
Bananymous | f12ffa92a0 | |
Bananymous | b2a4797d16 | |
Bananymous | 8bfacb0091 | |
Bananymous | 0501f3bd99 |
BAN/include/BAN
CMakeLists.txtLibFont
LibGUI
LibInput
kernel
CMakeLists.txt
include/kernel
kernel
libc
userspace
|
@ -18,18 +18,20 @@
|
||||||
fflush(stddbg); \
|
fflush(stddbg); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define dwarnln(...) \
|
#define dwarnln(...) \
|
||||||
do { \
|
do { \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
||||||
dprintln(__VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[m"); \
|
||||||
|
fflush(stddbg); \
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
#define derrorln(...) \
|
#define derrorln(...) \
|
||||||
do { \
|
do { \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
||||||
dprintln(__VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[m"); \
|
||||||
|
fflush(stddbg); \
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace BAN
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RefCounted() = default;
|
RefCounted() = default;
|
||||||
~RefCounted() { ASSERT(m_ref_count == 0); }
|
virtual ~RefCounted() { ASSERT(m_ref_count == 0); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable uint32_t m_ref_count = 1;
|
mutable uint32_t m_ref_count = 1;
|
||||||
|
|
|
@ -34,8 +34,10 @@ namespace BAN
|
||||||
template<typename T1, typename T2> struct either_or<true, T1, T2> { using type = T1; };
|
template<typename T1, typename T2> struct either_or<true, T1, T2> { using type = T1; };
|
||||||
template<bool B, typename T1, typename T2> using either_or_t = typename either_or<B, T1, T2>::type;
|
template<bool B, typename T1, typename T2> using either_or_t = typename either_or<B, T1, T2>::type;
|
||||||
|
|
||||||
struct true_type { static constexpr bool value = true; };
|
template<typename T, T V> struct integral_constant { static constexpr T value = V; };
|
||||||
struct false_type { static constexpr bool value = false; };
|
template<typename T, T V > inline constexpr T integral_constant_v = integral_constant<T, V>::value;
|
||||||
|
using true_type = integral_constant<bool, true>;
|
||||||
|
using false_type = integral_constant<bool, false>;
|
||||||
|
|
||||||
template<typename T, typename S> struct is_same : false_type {};
|
template<typename T, typename S> struct is_same : false_type {};
|
||||||
template<typename T> struct is_same<T, T> : true_type {};
|
template<typename T> struct is_same<T, T> : true_type {};
|
||||||
|
@ -87,9 +89,6 @@ namespace BAN
|
||||||
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
|
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
|
||||||
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
||||||
|
|
||||||
template<typename T, T V> struct integral_constant { static constexpr T value = V; };
|
|
||||||
template<typename T, T V > inline constexpr T integral_constant_v = integral_constant<T, V>::value;
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
|
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
|
||||||
|
|
|
@ -21,20 +21,21 @@ namespace BAN::UTF8
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint32_t to_codepoint(uint8_t* bytes)
|
template<typename T> requires (sizeof(T) == 1)
|
||||||
|
constexpr uint32_t to_codepoint(const T* bytes)
|
||||||
{
|
{
|
||||||
uint32_t length = byte_length(bytes[0]);
|
uint32_t length = byte_length(bytes[0]);
|
||||||
|
|
||||||
for (uint32_t i = 1; i < length; i++)
|
for (uint32_t i = 1; i < length; i++)
|
||||||
if ((bytes[i] & 0xC0) != 0x80)
|
if (((uint8_t)bytes[i] & 0xC0) != 0x80)
|
||||||
return UTF8::invalid;
|
return UTF8::invalid;
|
||||||
|
|
||||||
switch (length)
|
switch (length)
|
||||||
{
|
{
|
||||||
case 1: return ((bytes[0] & 0x80) != 0x00) ? UTF8::invalid : bytes[0];
|
case 1: return (((uint8_t)bytes[0] & 0x80) != 0x00) ? UTF8::invalid : (uint8_t)bytes[0];
|
||||||
case 2: return ((bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : ((bytes[0] & 0x1F) << 6) | (bytes[1] & 0x3F);
|
case 2: return (((uint8_t)bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x1F) << 6) | ((uint8_t)bytes[1] & 0x3F);
|
||||||
case 3: return ((bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : ((bytes[0] & 0x0F) << 12) | ((bytes[1] & 0x3F) << 6) | (bytes[2] & 0x3F);
|
case 3: return (((uint8_t)bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x0F) << 12) | (((uint8_t)bytes[1] & 0x3F) << 6) | ((uint8_t)bytes[2] & 0x3F);
|
||||||
case 4: return ((bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : ((bytes[0] & 0x07) << 18) | ((bytes[1] & 0x3F) << 12) | ((bytes[2] & 0x3F) << 6) | (bytes[3] & 0x3F);
|
case 4: return (((uint8_t)bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x07) << 18) | (((uint8_t)bytes[1] & 0x3F) << 12) | (((uint8_t)bytes[2] & 0x3F) << 6) | ((uint8_t)bytes[3] & 0x3F);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UTF8::invalid;
|
return UTF8::invalid;
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace BAN
|
||||||
class Weakable
|
class Weakable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~Weakable()
|
virtual ~Weakable()
|
||||||
{
|
{
|
||||||
if (m_link)
|
if (m_link)
|
||||||
m_link->invalidate();
|
m_link->invalidate();
|
||||||
|
@ -82,7 +82,7 @@ namespace BAN
|
||||||
|
|
||||||
RefPtr<T> lock()
|
RefPtr<T> lock()
|
||||||
{
|
{
|
||||||
if (m_link->valid())
|
if (valid())
|
||||||
return m_link->lock();
|
return m_link->lock();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ add_subdirectory(bootloader)
|
||||||
add_subdirectory(BAN)
|
add_subdirectory(BAN)
|
||||||
add_subdirectory(libc)
|
add_subdirectory(libc)
|
||||||
add_subdirectory(LibELF)
|
add_subdirectory(LibELF)
|
||||||
|
add_subdirectory(LibFont)
|
||||||
add_subdirectory(LibGUI)
|
add_subdirectory(LibGUI)
|
||||||
add_subdirectory(LibInput)
|
add_subdirectory(LibInput)
|
||||||
add_subdirectory(userspace)
|
add_subdirectory(userspace)
|
||||||
|
@ -35,6 +36,7 @@ add_custom_target(headers
|
||||||
DEPENDS ban-headers
|
DEPENDS ban-headers
|
||||||
DEPENDS libc-headers
|
DEPENDS libc-headers
|
||||||
DEPENDS libelf-headers
|
DEPENDS libelf-headers
|
||||||
|
DEPENDS libfont-headers
|
||||||
DEPENDS libgui-headers
|
DEPENDS libgui-headers
|
||||||
DEPENDS libinput-headers
|
DEPENDS libinput-headers
|
||||||
)
|
)
|
||||||
|
@ -45,6 +47,7 @@ add_custom_target(install-sysroot
|
||||||
DEPENDS libc-install
|
DEPENDS libc-install
|
||||||
DEPENDS userspace-install
|
DEPENDS userspace-install
|
||||||
DEPENDS libelf-install
|
DEPENDS libelf-install
|
||||||
|
DEPENDS libfont-install
|
||||||
DEPENDS libgui-install
|
DEPENDS libgui-install
|
||||||
DEPENDS libinput-install
|
DEPENDS libinput-install
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
|
project(libfont CXX)
|
||||||
|
|
||||||
|
set(LIBGUI_SOURCES
|
||||||
|
Font.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(libfont-headers
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
||||||
|
DEPENDS sysroot
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(libfont ${LIBGUI_SOURCES})
|
||||||
|
add_dependencies(libfont headers libc-install)
|
||||||
|
target_link_libraries(libfont PUBLIC libc)
|
||||||
|
|
||||||
|
add_custom_target(libfont-install
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libfont.a ${BANAN_LIB}/
|
||||||
|
DEPENDS libfont
|
||||||
|
BYPRODUCTS ${BANAN_LIB}/libfont.a
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
|
@ -1,9 +1,13 @@
|
||||||
|
#include <BAN/Debug.h>
|
||||||
#include <BAN/Endianness.h>
|
#include <BAN/Endianness.h>
|
||||||
#include <BAN/ScopeGuard.h>
|
#include <BAN/ScopeGuard.h>
|
||||||
#include <BAN/UTF8.h>
|
#include <BAN/UTF8.h>
|
||||||
#include <kernel/Font.h>
|
|
||||||
|
#include <LibFont/Font.h>
|
||||||
|
|
||||||
|
#if __is_kernel
|
||||||
#include <kernel/FS/VirtualFileSystem.h>
|
#include <kernel/FS/VirtualFileSystem.h>
|
||||||
#include <kernel/Process.h>
|
#endif
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
@ -23,59 +27,86 @@
|
||||||
#define PSF2_STARTSEQ 0xFE
|
#define PSF2_STARTSEQ 0xFE
|
||||||
#define PSF2_SEPARATOR 0xFF
|
#define PSF2_SEPARATOR 0xFF
|
||||||
|
|
||||||
|
#if __is_kernel
|
||||||
extern uint8_t _binary_font_prefs_psf_start[];
|
extern uint8_t _binary_font_prefs_psf_start[];
|
||||||
extern uint8_t _binary_font_prefs_psf_end[];
|
extern uint8_t _binary_font_prefs_psf_end[];
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Kernel
|
namespace LibFont
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if __is_kernel
|
||||||
BAN::ErrorOr<Font> Font::prefs()
|
BAN::ErrorOr<Font> Font::prefs()
|
||||||
{
|
{
|
||||||
size_t font_data_size = _binary_font_prefs_psf_end - _binary_font_prefs_psf_start;
|
size_t font_data_size = _binary_font_prefs_psf_end - _binary_font_prefs_psf_start;
|
||||||
BAN::Span<const uint8_t> font_data(_binary_font_prefs_psf_start, font_data_size);
|
return parse_psf1(BAN::ConstByteSpan(_binary_font_prefs_psf_start, font_data_size));
|
||||||
return parse_psf1(font_data);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
BAN::ErrorOr<Font> Font::load(BAN::StringView path)
|
BAN::ErrorOr<Font> Font::load(BAN::StringView path)
|
||||||
{
|
{
|
||||||
auto inode = TRY(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
|
|
||||||
|
|
||||||
BAN::Vector<uint8_t> file_data;
|
BAN::Vector<uint8_t> file_data;
|
||||||
TRY(file_data.resize(inode->size()));
|
|
||||||
|
|
||||||
TRY(inode->read(0, file_data.span()));
|
#if __is_kernel
|
||||||
|
auto inode = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
|
||||||
|
TRY(file_data.resize(inode->size()));
|
||||||
|
TRY(inode->read(0, BAN::ByteSpan(file_data.span())));
|
||||||
|
#else
|
||||||
|
char path_buffer[PATH_MAX];
|
||||||
|
strncpy(path_buffer, path.data(), path.size());
|
||||||
|
path_buffer[path.size()] = '\0';
|
||||||
|
|
||||||
|
int fd = open(path_buffer, O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
return BAN::Error::from_errno(errno);
|
||||||
|
BAN::ScopeGuard file_closer([fd] { close(fd); });
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) == -1)
|
||||||
|
return BAN::Error::from_errno(errno);
|
||||||
|
TRY(file_data.resize(st.st_size));
|
||||||
|
|
||||||
|
ssize_t total_read = 0;
|
||||||
|
while (total_read < st.st_size)
|
||||||
|
{
|
||||||
|
ssize_t nread = read(fd, file_data.data() + total_read, st.st_size - total_read);
|
||||||
|
if (nread == -1)
|
||||||
|
return BAN::Error::from_errno(errno);
|
||||||
|
total_read += nread;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (file_data.size() < 4)
|
if (file_data.size() < 4)
|
||||||
return BAN::Error::from_error_code(ErrorCode::Font_FileTooSmall);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
if (file_data[0] == PSF1_MAGIC0 && file_data[1] == PSF1_MAGIC1)
|
if (file_data[0] == PSF1_MAGIC0 && file_data[1] == PSF1_MAGIC1)
|
||||||
return TRY(parse_psf1(file_data.span()));
|
return TRY(parse_psf1(BAN::ConstByteSpan(file_data.span())));
|
||||||
|
|
||||||
if (file_data[0] == PSF2_MAGIC0 && file_data[1] == PSF2_MAGIC1 && file_data[2] == PSF2_MAGIC2 && file_data[3] == PSF2_MAGIC3)
|
if (file_data[0] == PSF2_MAGIC0 && file_data[1] == PSF2_MAGIC1 && file_data[2] == PSF2_MAGIC2 && file_data[3] == PSF2_MAGIC3)
|
||||||
return TRY(parse_psf2(file_data.span()));
|
return TRY(parse_psf2(BAN::ConstByteSpan(file_data.span())));
|
||||||
|
|
||||||
return BAN::Error::from_error_code(ErrorCode::Font_Unsupported);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<Font> Font::parse_psf1(BAN::Span<const uint8_t> font_data)
|
BAN::ErrorOr<Font> Font::parse_psf1(BAN::ConstByteSpan font_data)
|
||||||
{
|
{
|
||||||
if (font_data.size() < 4)
|
|
||||||
return BAN::Error::from_error_code(ErrorCode::Font_FileTooSmall);
|
|
||||||
|
|
||||||
struct PSF1Header
|
struct PSF1Header
|
||||||
{
|
{
|
||||||
uint8_t magic[2];
|
uint8_t magic[2];
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
uint8_t char_size;
|
uint8_t char_size;
|
||||||
};
|
};
|
||||||
const PSF1Header& header = *(const PSF1Header*)font_data.data();
|
|
||||||
|
if (font_data.size() < sizeof(PSF1Header))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
const auto& header = font_data.as<const PSF1Header>();
|
||||||
|
|
||||||
uint32_t glyph_count = header.mode & PSF1_MODE512 ? 512 : 256;
|
uint32_t glyph_count = header.mode & PSF1_MODE512 ? 512 : 256;
|
||||||
uint32_t glyph_size = header.char_size;
|
uint32_t glyph_size = header.char_size;
|
||||||
uint32_t glyph_data_size = glyph_size * glyph_count;
|
uint32_t glyph_data_size = glyph_size * glyph_count;
|
||||||
|
|
||||||
if (font_data.size() < sizeof(PSF1Header) + glyph_data_size)
|
if (font_data.size() < sizeof(PSF1Header) + glyph_data_size)
|
||||||
return BAN::Error::from_error_code(ErrorCode::Font_FileTooSmall);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
BAN::Vector<uint8_t> glyph_data;
|
BAN::Vector<uint8_t> glyph_data;
|
||||||
TRY(glyph_data.resize(glyph_data_size));
|
TRY(glyph_data.resize(glyph_data_size));
|
||||||
|
@ -125,7 +156,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codepoint_redef)
|
if (codepoint_redef)
|
||||||
dwarnln("Font contsins multiple definitions for same codepoint(s)");
|
dwarnln("Font contains multiple definitions for same codepoint(s)");
|
||||||
if (codepoint_sequence)
|
if (codepoint_sequence)
|
||||||
dwarnln("Font contains codepoint sequences (not supported)");
|
dwarnln("Font contains codepoint sequences (not supported)");
|
||||||
|
|
||||||
|
@ -138,7 +169,7 @@ namespace Kernel
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<Font> Font::parse_psf2(BAN::Span<const uint8_t> font_data)
|
BAN::ErrorOr<Font> Font::parse_psf2(BAN::ConstByteSpan font_data)
|
||||||
{
|
{
|
||||||
struct PSF2Header
|
struct PSF2Header
|
||||||
{
|
{
|
||||||
|
@ -153,14 +184,13 @@ namespace Kernel
|
||||||
};
|
};
|
||||||
|
|
||||||
if (font_data.size() < sizeof(PSF2Header))
|
if (font_data.size() < sizeof(PSF2Header))
|
||||||
return BAN::Error::from_error_code(ErrorCode::Font_FileTooSmall);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
const auto& header = font_data.as<const PSF2Header>();
|
||||||
const PSF2Header& header = *(const PSF2Header*)font_data.data();
|
|
||||||
|
|
||||||
uint32_t glyph_data_size = header.glyph_count * header.glyph_size;
|
uint32_t glyph_data_size = header.glyph_count * header.glyph_size;
|
||||||
|
|
||||||
if (font_data.size() < glyph_data_size + header.header_size)
|
if (font_data.size() < glyph_data_size + header.header_size)
|
||||||
return BAN::Error::from_error_code(ErrorCode::Font_FileTooSmall);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
BAN::Vector<uint8_t> glyph_data;
|
BAN::Vector<uint8_t> glyph_data;
|
||||||
TRY(glyph_data.resize(glyph_data_size));
|
TRY(glyph_data.resize(glyph_data_size));
|
||||||
|
@ -244,14 +274,4 @@ namespace Kernel
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Font::has_glyph(uint32_t codepoint) const
|
|
||||||
{
|
|
||||||
return m_glyph_offsets.contains(codepoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t* Font::glyph(uint32_t codepoint) const
|
|
||||||
{
|
|
||||||
return m_glyph_data.data() + m_glyph_offsets[codepoint];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/HashMap.h>
|
||||||
|
#include <BAN/StringView.h>
|
||||||
|
|
||||||
|
namespace LibFont
|
||||||
|
{
|
||||||
|
|
||||||
|
class Font
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<Font> load(BAN::StringView path);
|
||||||
|
#if __is_kernel
|
||||||
|
static BAN::ErrorOr<Font> prefs();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t width() const { return m_width; }
|
||||||
|
uint32_t height() const { return m_height; }
|
||||||
|
uint32_t pitch() const { return m_pitch; }
|
||||||
|
|
||||||
|
bool has_glyph(uint32_t codepoint) const { return glyph(codepoint) != nullptr; }
|
||||||
|
const uint8_t* glyph(uint32_t codepoint) const
|
||||||
|
{
|
||||||
|
auto it = m_glyph_offsets.find(codepoint);
|
||||||
|
if (it == m_glyph_offsets.end())
|
||||||
|
return nullptr;
|
||||||
|
return m_glyph_data.data() + it->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static BAN::ErrorOr<Font> parse_psf1(BAN::ConstByteSpan);
|
||||||
|
static BAN::ErrorOr<Font> parse_psf2(BAN::ConstByteSpan);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::HashMap<uint32_t, uint32_t> m_glyph_offsets;
|
||||||
|
BAN::Vector<uint8_t> m_glyph_data;
|
||||||
|
uint32_t m_width = 0;
|
||||||
|
uint32_t m_height = 0;
|
||||||
|
uint32_t m_pitch = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ add_custom_target(libgui-headers
|
||||||
|
|
||||||
add_library(libgui ${LIBGUI_SOURCES})
|
add_library(libgui ${LIBGUI_SOURCES})
|
||||||
add_dependencies(libgui headers libc-install)
|
add_dependencies(libgui headers libc-install)
|
||||||
target_link_libraries(libgui PUBLIC libc)
|
target_link_libraries(libgui PUBLIC libc libfont)
|
||||||
|
|
||||||
add_custom_target(libgui-install
|
add_custom_target(libgui-install
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libgui.a ${BANAN_LIB}/
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libgui.a ${BANAN_LIB}/
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#include "LibGUI/Window.h"
|
#include "LibGUI/Window.h"
|
||||||
|
|
||||||
|
#include <LibFont/Font.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/banan-os.h>
|
#include <sys/banan-os.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
@ -17,24 +20,49 @@ namespace LibGUI
|
||||||
close(m_server_fd);
|
close(m_server_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<Window>> Window::create(uint32_t width, uint32_t height)
|
BAN::ErrorOr<BAN::UniqPtr<Window>> Window::create(uint32_t width, uint32_t height, BAN::StringView title)
|
||||||
{
|
{
|
||||||
|
if (title.size() >= sizeof(WindowCreatePacket::title))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
int server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
int server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||||
if (server_fd == -1)
|
if (server_fd == -1)
|
||||||
return BAN::Error::from_errno(errno);
|
return BAN::Error::from_errno(errno);
|
||||||
|
|
||||||
sockaddr_un server_address;
|
if (fcntl(server_fd, F_SETFL, fcntl(server_fd, F_GETFL) | O_CLOEXEC) == -1)
|
||||||
server_address.sun_family = AF_UNIX;
|
|
||||||
strcpy(server_address.sun_path, s_window_server_socket.data());
|
|
||||||
if (connect(server_fd, (sockaddr*)&server_address, sizeof(server_address)) == -1)
|
|
||||||
{
|
|
||||||
close(server_fd);
|
|
||||||
return BAN::Error::from_errno(errno);
|
return BAN::Error::from_errno(errno);
|
||||||
|
|
||||||
|
timespec start_time;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
sockaddr_un server_address;
|
||||||
|
server_address.sun_family = AF_UNIX;
|
||||||
|
strcpy(server_address.sun_path, s_window_server_socket.data());
|
||||||
|
if (connect(server_fd, (sockaddr*)&server_address, sizeof(server_address)) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
timespec current_time;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, ¤t_time);
|
||||||
|
time_t duration_s = (current_time.tv_sec - start_time.tv_sec) + (current_time.tv_nsec >= start_time.tv_nsec);
|
||||||
|
if (duration_s > 10)
|
||||||
|
{
|
||||||
|
close(server_fd);
|
||||||
|
return BAN::Error::from_errno(ETIMEDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
timespec sleep_time;
|
||||||
|
sleep_time.tv_sec = 0;
|
||||||
|
sleep_time.tv_nsec = 1'000'000;
|
||||||
|
nanosleep(&sleep_time, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowCreatePacket packet;
|
WindowCreatePacket packet;
|
||||||
packet.width = width;
|
packet.width = width;
|
||||||
packet.height = height;
|
packet.height = height;
|
||||||
|
strncpy(packet.title, title.data(), title.size());
|
||||||
|
packet.title[title.size()] = '\0';
|
||||||
if (send(server_fd, &packet, sizeof(packet), 0) != sizeof(packet))
|
if (send(server_fd, &packet, sizeof(packet), 0) != sizeof(packet))
|
||||||
{
|
{
|
||||||
close(server_fd);
|
close(server_fd);
|
||||||
|
@ -63,13 +91,92 @@ namespace LibGUI
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Window::invalidate()
|
void Window::fill_rect(int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t color)
|
||||||
{
|
{
|
||||||
|
if (!clamp_to_framebuffer(x, y, width, height))
|
||||||
|
return;
|
||||||
|
for (uint32_t y_off = 0; y_off < height; y_off++)
|
||||||
|
for (uint32_t x_off = 0; x_off < width; x_off++)
|
||||||
|
set_pixel(x + x_off, y + y_off, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::draw_character(uint32_t codepoint, const LibFont::Font& font, int32_t tl_x, int32_t tl_y, uint32_t color)
|
||||||
|
{
|
||||||
|
if (tl_y + (int32_t)font.height() < 0 || tl_y >= (int32_t)height())
|
||||||
|
return;
|
||||||
|
if (tl_x + (int32_t)font.width() < 0 || tl_x >= (int32_t)width())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto glyph = font.glyph(codepoint);
|
||||||
|
if (glyph == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int32_t off_y = 0; off_y < (int32_t)font.height(); off_y++)
|
||||||
|
{
|
||||||
|
if (tl_y + off_y < 0)
|
||||||
|
continue;
|
||||||
|
uint32_t abs_y = tl_y + off_y;
|
||||||
|
if (abs_y >= height())
|
||||||
|
break;
|
||||||
|
for (int32_t off_x = 0; off_x < (int32_t)font.width(); off_x++)
|
||||||
|
{
|
||||||
|
if (tl_x + off_x < 0)
|
||||||
|
continue;
|
||||||
|
uint32_t abs_x = tl_x + off_x;
|
||||||
|
if (abs_x >= width())
|
||||||
|
break;
|
||||||
|
const uint8_t bitmask = 1 << (font.width() - off_x - 1);
|
||||||
|
if (glyph[off_y * font.pitch()] & bitmask)
|
||||||
|
set_pixel(abs_x, abs_y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::draw_text(BAN::StringView text, const LibFont::Font& font, int32_t tl_x, int32_t tl_y, uint32_t color)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < text.size(); i++)
|
||||||
|
draw_character(text[i], font, tl_x + (int32_t)(i * font.width()), tl_y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::shift_vertical(int32_t amount)
|
||||||
|
{
|
||||||
|
uint32_t amount_abs = BAN::Math::abs(amount);
|
||||||
|
if (amount_abs == 0 || amount_abs >= height())
|
||||||
|
return;
|
||||||
|
uint32_t* dst = (amount > 0) ? m_framebuffer + width() * amount_abs : m_framebuffer;
|
||||||
|
uint32_t* src = (amount < 0) ? m_framebuffer + width() * amount_abs : m_framebuffer;
|
||||||
|
memmove(dst, src, width() * (height() - amount_abs) * 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);
|
||||||
|
int32_t min_y = BAN::Math::max<int32_t>(signed_y, 0);
|
||||||
|
int32_t max_x = BAN::Math::min<int32_t>(this->width(), signed_x + (int32_t)width);
|
||||||
|
int32_t max_y = BAN::Math::min<int32_t>(this->height(), signed_y + (int32_t)height);
|
||||||
|
|
||||||
|
if (min_x >= max_x)
|
||||||
|
return false;
|
||||||
|
if (min_y >= max_y)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
signed_x = min_x;
|
||||||
|
signed_y = min_y;
|
||||||
|
width = max_x - min_x;
|
||||||
|
height = max_y - min_y;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
if (!clamp_to_framebuffer(x, y, width, height))
|
||||||
|
return true;
|
||||||
|
|
||||||
WindowInvalidatePacket packet;
|
WindowInvalidatePacket packet;
|
||||||
packet.x = 0;
|
packet.x = x;
|
||||||
packet.y = 0;
|
packet.y = y;
|
||||||
packet.width = m_width;
|
packet.width = width;
|
||||||
packet.height = m_height;
|
packet.height = height;
|
||||||
return send(m_server_fd, &packet, sizeof(packet), 0) == sizeof(packet);
|
return send(m_server_fd, &packet, sizeof(packet), 0) == sizeof(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +199,14 @@ namespace LibGUI
|
||||||
|
|
||||||
switch (packet.type)
|
switch (packet.type)
|
||||||
{
|
{
|
||||||
|
case EventPacket::Type::DestroyWindow:
|
||||||
|
exit(1);
|
||||||
|
case EventPacket::Type::CloseWindow:
|
||||||
|
if (m_close_window_event_callback)
|
||||||
|
m_close_window_event_callback();
|
||||||
|
else
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
case EventPacket::Type::KeyEvent:
|
case EventPacket::Type::KeyEvent:
|
||||||
if (m_key_event_callback)
|
if (m_key_event_callback)
|
||||||
m_key_event_callback(packet.key_event);
|
m_key_event_callback(packet.key_event);
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace LibFont { class Font; }
|
||||||
|
|
||||||
namespace LibGUI
|
namespace LibGUI
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ namespace LibGUI
|
||||||
INVALID,
|
INVALID,
|
||||||
CreateWindow,
|
CreateWindow,
|
||||||
Invalidate,
|
Invalidate,
|
||||||
|
COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WindowCreatePacket
|
struct WindowCreatePacket
|
||||||
|
@ -27,6 +30,7 @@ namespace LibGUI
|
||||||
WindowPacketType type = WindowPacketType::CreateWindow;
|
WindowPacketType type = WindowPacketType::CreateWindow;
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
|
char title[52];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WindowInvalidatePacket
|
struct WindowInvalidatePacket
|
||||||
|
@ -61,6 +65,8 @@ namespace LibGUI
|
||||||
{
|
{
|
||||||
enum class Type : uint8_t
|
enum class Type : uint8_t
|
||||||
{
|
{
|
||||||
|
DestroyWindow,
|
||||||
|
CloseWindow,
|
||||||
KeyEvent,
|
KeyEvent,
|
||||||
MouseButtonEvent,
|
MouseButtonEvent,
|
||||||
MouseMoveEvent,
|
MouseMoveEvent,
|
||||||
|
@ -97,7 +103,7 @@ namespace LibGUI
|
||||||
public:
|
public:
|
||||||
~Window();
|
~Window();
|
||||||
|
|
||||||
static BAN::ErrorOr<BAN::UniqPtr<Window>> create(uint32_t width, uint32_t height);
|
static BAN::ErrorOr<BAN::UniqPtr<Window>> create(uint32_t width, uint32_t height, BAN::StringView title);
|
||||||
|
|
||||||
void set_pixel(uint32_t x, uint32_t y, uint32_t color)
|
void set_pixel(uint32_t x, uint32_t y, uint32_t color)
|
||||||
{
|
{
|
||||||
|
@ -106,17 +112,29 @@ namespace LibGUI
|
||||||
m_framebuffer[y * m_width + x] = color;
|
m_framebuffer[y * m_width + x] = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool invalidate();
|
void fill_rect(int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t color);
|
||||||
|
void fill(uint32_t color) { return fill_rect(0, 0, width(), height(), color); }
|
||||||
|
|
||||||
|
void draw_character(uint32_t codepoint, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color);
|
||||||
|
void draw_text(BAN::StringView text, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color);
|
||||||
|
|
||||||
|
void shift_vertical(int32_t amount);
|
||||||
|
|
||||||
|
bool invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||||
|
bool invalidate() { return invalidate(0, 0, width(), height()); }
|
||||||
|
|
||||||
uint32_t width() const { return m_width; }
|
uint32_t width() const { return m_width; }
|
||||||
uint32_t height() const { return m_height; }
|
uint32_t height() const { return m_height; }
|
||||||
|
|
||||||
void poll_events();
|
void poll_events();
|
||||||
|
void set_close_window_event_callback(BAN::Function<void()> callback) { m_close_window_event_callback = callback; }
|
||||||
void set_key_event_callback(BAN::Function<void(EventPacket::KeyEvent)> callback) { m_key_event_callback = callback; }
|
void set_key_event_callback(BAN::Function<void(EventPacket::KeyEvent)> callback) { m_key_event_callback = callback; }
|
||||||
void set_mouse_button_event_callback(BAN::Function<void(EventPacket::MouseButtonEvent)> callback) { m_mouse_button_event_callback = callback; }
|
void set_mouse_button_event_callback(BAN::Function<void(EventPacket::MouseButtonEvent)> callback) { m_mouse_button_event_callback = callback; }
|
||||||
void set_mouse_move_event_callback(BAN::Function<void(EventPacket::MouseMoveEvent)> callback) { m_mouse_move_event_callback = callback; }
|
void set_mouse_move_event_callback(BAN::Function<void(EventPacket::MouseMoveEvent)> callback) { m_mouse_move_event_callback = callback; }
|
||||||
void set_mouse_scroll_event_callback(BAN::Function<void(EventPacket::MouseScrollEvent)> callback) { m_mouse_scroll_event_callback = callback; }
|
void set_mouse_scroll_event_callback(BAN::Function<void(EventPacket::MouseScrollEvent)> callback) { m_mouse_scroll_event_callback = callback; }
|
||||||
|
|
||||||
|
int server_fd() const { return m_server_fd; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Window(int server_fd, uint32_t* framebuffer, uint32_t width, uint32_t height)
|
Window(int server_fd, uint32_t* framebuffer, uint32_t width, uint32_t height)
|
||||||
: m_server_fd(server_fd)
|
: m_server_fd(server_fd)
|
||||||
|
@ -125,12 +143,15 @@ namespace LibGUI
|
||||||
, m_height(height)
|
, m_height(height)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
bool clamp_to_framebuffer(int32_t& x, int32_t& y, uint32_t& width, uint32_t& height) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_server_fd;
|
int m_server_fd;
|
||||||
uint32_t* m_framebuffer;
|
uint32_t* m_framebuffer;
|
||||||
uint32_t m_width;
|
uint32_t m_width;
|
||||||
uint32_t m_height;
|
uint32_t m_height;
|
||||||
|
|
||||||
|
BAN::Function<void()> m_close_window_event_callback;
|
||||||
BAN::Function<void(EventPacket::KeyEvent)> m_key_event_callback;
|
BAN::Function<void(EventPacket::KeyEvent)> m_key_event_callback;
|
||||||
BAN::Function<void(EventPacket::MouseButtonEvent)> m_mouse_button_event_callback;
|
BAN::Function<void(EventPacket::MouseButtonEvent)> m_mouse_button_event_callback;
|
||||||
BAN::Function<void(EventPacket::MouseMoveEvent)> m_mouse_move_event_callback;
|
BAN::Function<void(EventPacket::MouseMoveEvent)> m_mouse_move_event_callback;
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#include <BAN/Array.h>
|
#include <BAN/Array.h>
|
||||||
#include <LibInput/KeyEvent.h>
|
#include <LibInput/KeyEvent.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
namespace LibInput
|
namespace LibInput
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -48,4 +51,71 @@ namespace LibInput
|
||||||
return (event.shift() ^ event.caps_lock()) ? utf8_upper[static_cast<uint8_t>(key)] : utf8_lower[static_cast<uint8_t>(key)];
|
return (event.shift() ^ event.caps_lock()) ? utf8_upper[static_cast<uint8_t>(key)] : utf8_lower[static_cast<uint8_t>(key)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* key_to_utf8_ansi(Key key, uint16_t modifier)
|
||||||
|
{
|
||||||
|
static constexpr const char* utf8_lower[] = {
|
||||||
|
nullptr, nullptr,
|
||||||
|
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||||
|
"å", "ä", "ö",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "\n", " ",
|
||||||
|
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
|
||||||
|
"(", ")", "[", "]", "{", "}",
|
||||||
|
"=", "?", "+", "\\", "´", "`", "¨", "¸", "\b \b", "@", "£", "$", "€",
|
||||||
|
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
"'", "*", "^", "~", "\e[A", "\e[B", "\e[D", "\e[C",
|
||||||
|
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", "¬", "¦",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
"+", "-", "*", "/", "\n", ",",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
};
|
||||||
|
static_assert((size_t)Key::Count == sizeof(utf8_lower) / sizeof(*utf8_lower));
|
||||||
|
|
||||||
|
static constexpr const char* utf8_upper[] = {
|
||||||
|
nullptr, nullptr,
|
||||||
|
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||||
|
"Å", "Ä", "Ö",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "\n", " ",
|
||||||
|
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
|
||||||
|
"(", ")", "[", "]", "{", "}",
|
||||||
|
"=", "?", "+", "\\", "´", "`", "¨", "¸", "\b \b", "@", "£", "$", "€",
|
||||||
|
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
"'", "*", "^", "~", "\e[A", "\e[B", "\e[D", "\e[C",
|
||||||
|
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", "¬", "¦",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
"+", "-", "*", "/", "\n", ",",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
};
|
||||||
|
static_assert((size_t)Key::Count == sizeof(utf8_upper) / sizeof(*utf8_upper));
|
||||||
|
|
||||||
|
static constexpr const char* utf8_ctrl[] = {
|
||||||
|
nullptr, nullptr,
|
||||||
|
"\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0A", "\x0B", "\x0C", "\x0D", "\x0E", "\x0F", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1A",
|
||||||
|
"Å", "Ä", "Ö",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "\n", " ",
|
||||||
|
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
|
||||||
|
"(", ")", "[", "]", "{", "}",
|
||||||
|
"=", "?", "+", "\\", "´", "`", "¨", "¸", "\b \b", "@", "£", "$", "€",
|
||||||
|
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
"'", "*", "^", "~", "\e[A", "\e[B", "\e[D", "\e[C",
|
||||||
|
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", "¬", "¦",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
"+", "-", "*", "/", "\n", ",",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
};
|
||||||
|
static_assert((size_t)Key::Count == sizeof(utf8_upper) / sizeof(*utf8_upper));
|
||||||
|
|
||||||
|
KeyEvent event { .modifier = modifier, .key = key };
|
||||||
|
if (event.ctrl())
|
||||||
|
return utf8_ctrl[static_cast<uint8_t>(key)];
|
||||||
|
if (event.shift() ^ event.caps_lock())
|
||||||
|
return utf8_upper[static_cast<uint8_t>(key)];
|
||||||
|
return utf8_lower[static_cast<uint8_t>(key)];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,5 +101,6 @@ namespace LibInput
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* key_to_utf8(Key key, uint16_t modifier);
|
const char* key_to_utf8(Key key, uint16_t modifier);
|
||||||
|
const char* key_to_utf8_ansi(Key key, uint16_t modifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ set(KERNEL_SOURCES
|
||||||
kernel/Device/NullDevice.cpp
|
kernel/Device/NullDevice.cpp
|
||||||
kernel/Device/ZeroDevice.cpp
|
kernel/Device/ZeroDevice.cpp
|
||||||
kernel/Errors.cpp
|
kernel/Errors.cpp
|
||||||
kernel/Font.cpp
|
|
||||||
kernel/FS/DevFS/FileSystem.cpp
|
kernel/FS/DevFS/FileSystem.cpp
|
||||||
kernel/FS/Ext2/FileSystem.cpp
|
kernel/FS/Ext2/FileSystem.cpp
|
||||||
kernel/FS/Ext2/Inode.cpp
|
kernel/FS/Ext2/Inode.cpp
|
||||||
|
@ -149,6 +148,10 @@ set(LIBELF_SOURCES
|
||||||
../LibELF/LibELF/LoadableELF.cpp
|
../LibELF/LibELF/LoadableELF.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(LIBFONT_SOURCES
|
||||||
|
../LibFont/Font.cpp
|
||||||
|
)
|
||||||
|
|
||||||
set(LIBINPUT_SOURCE
|
set(LIBINPUT_SOURCE
|
||||||
../LibInput/KeyboardLayout.cpp
|
../LibInput/KeyboardLayout.cpp
|
||||||
../LibInput/KeyEvent.cpp
|
../LibInput/KeyEvent.cpp
|
||||||
|
@ -160,6 +163,7 @@ set(KERNEL_SOURCES
|
||||||
${BAN_SOURCES}
|
${BAN_SOURCES}
|
||||||
${KLIBC_SOURCES}
|
${KLIBC_SOURCES}
|
||||||
${LIBELF_SOURCES}
|
${LIBELF_SOURCES}
|
||||||
|
${LIBFONT_SOURCES}
|
||||||
${LIBINPUT_SOURCE}
|
${LIBINPUT_SOURCE}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/HashMap.h>
|
|
||||||
#include <BAN/Span.h>
|
|
||||||
#include <BAN/StringView.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
class Font
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static BAN::ErrorOr<Font> load(BAN::StringView);
|
|
||||||
static BAN::ErrorOr<Font> prefs();
|
|
||||||
|
|
||||||
uint32_t width() const { return m_width; }
|
|
||||||
uint32_t height() const { return m_height; }
|
|
||||||
uint32_t pitch() const { return m_pitch; }
|
|
||||||
|
|
||||||
bool has_glyph(uint32_t) const;
|
|
||||||
const uint8_t* glyph(uint32_t) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static BAN::ErrorOr<Font> parse_psf1(BAN::Span<const uint8_t>);
|
|
||||||
static BAN::ErrorOr<Font> parse_psf2(BAN::Span<const uint8_t>);
|
|
||||||
|
|
||||||
private:
|
|
||||||
BAN::HashMap<uint32_t, uint32_t> m_glyph_offsets;
|
|
||||||
BAN::Vector<uint8_t> m_glyph_data;
|
|
||||||
uint32_t m_width = 0;
|
|
||||||
uint32_t m_height = 0;
|
|
||||||
uint32_t m_pitch = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -21,6 +21,7 @@ namespace Kernel
|
||||||
static SharedMemoryObjectManager& get();
|
static SharedMemoryObjectManager& get();
|
||||||
|
|
||||||
BAN::ErrorOr<Key> create_object(size_t size, PageTable::flags_t);
|
BAN::ErrorOr<Key> create_object(size_t size, PageTable::flags_t);
|
||||||
|
BAN::ErrorOr<void> delete_object(Key);
|
||||||
BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> map_object(Key, PageTable&, AddressRange);
|
BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> map_object(Key, PageTable&, AddressRange);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -29,6 +30,9 @@ namespace Kernel
|
||||||
private:
|
private:
|
||||||
struct Object : public BAN::RefCounted<Object>
|
struct Object : public BAN::RefCounted<Object>
|
||||||
{
|
{
|
||||||
|
~Object();
|
||||||
|
|
||||||
|
Key key;
|
||||||
size_t size;
|
size_t size;
|
||||||
PageTable::flags_t flags;
|
PageTable::flags_t flags;
|
||||||
BAN::Vector<paddr_t> paddrs;
|
BAN::Vector<paddr_t> paddrs;
|
||||||
|
@ -51,7 +55,7 @@ namespace Kernel
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> create(BAN::RefPtr<SharedMemoryObjectManager::Object>, PageTable&, AddressRange);
|
static BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> create(BAN::RefPtr<SharedMemoryObjectManager::Object>, PageTable&, AddressRange);
|
||||||
|
|
||||||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
|
||||||
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
|
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace Kernel
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UnixDomainSocket(SocketType, ino_t, const TmpInodeInfo&);
|
UnixDomainSocket(SocketType, ino_t, const TmpInodeInfo&);
|
||||||
|
~UnixDomainSocket() { on_close_impl(); }
|
||||||
|
|
||||||
BAN::ErrorOr<void> add_packet(BAN::ConstByteSpan);
|
BAN::ErrorOr<void> add_packet(BAN::ConstByteSpan);
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
bool listening { false };
|
bool listening { false };
|
||||||
BAN::Atomic<bool> connection_done { false };
|
BAN::Atomic<bool> connection_done { false };
|
||||||
|
mutable BAN::Atomic<bool> target_closed { false };
|
||||||
BAN::WeakPtr<UnixDomainSocket> connection;
|
BAN::WeakPtr<UnixDomainSocket> connection;
|
||||||
BAN::Queue<BAN::RefPtr<UnixDomainSocket>> pending_connections;
|
BAN::Queue<BAN::RefPtr<UnixDomainSocket>> pending_connections;
|
||||||
Semaphore pending_semaphore;
|
Semaphore pending_semaphore;
|
||||||
|
|
|
@ -159,8 +159,11 @@ namespace Kernel
|
||||||
BAN::ErrorOr<long> sys_msync(void* addr, size_t len, int flags);
|
BAN::ErrorOr<long> sys_msync(void* addr, size_t len, int flags);
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_smo_create(size_t len, int prot);
|
BAN::ErrorOr<long> sys_smo_create(size_t len, int prot);
|
||||||
|
BAN::ErrorOr<long> sys_smo_delete(SharedMemoryObjectManager::Key);
|
||||||
BAN::ErrorOr<long> sys_smo_map(SharedMemoryObjectManager::Key);
|
BAN::ErrorOr<long> sys_smo_map(SharedMemoryObjectManager::Key);
|
||||||
|
|
||||||
|
BAN::ErrorOr<long> sys_isatty(int fildes);
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags);
|
BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags);
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_signal(int, void (*)(int));
|
BAN::ErrorOr<long> sys_signal(int, void (*)(int));
|
||||||
|
@ -217,6 +220,11 @@ namespace Kernel
|
||||||
ASSERT(signal >= _SIGMIN);
|
ASSERT(signal >= _SIGMIN);
|
||||||
ASSERT(signal <= _SIGMAX);
|
ASSERT(signal <= _SIGMAX);
|
||||||
ASSERT(signal < 64);
|
ASSERT(signal < 64);
|
||||||
|
vaddr_t handler = m_signal_handlers[signal];
|
||||||
|
if (handler == (vaddr_t)SIG_IGN)
|
||||||
|
return;
|
||||||
|
if (handler == (vaddr_t)SIG_DFL && (signal == SIGCHLD || signal == SIGURG))
|
||||||
|
return;
|
||||||
if (signal < 32)
|
if (signal < 32)
|
||||||
m_signal_pending_mask[0] |= (uint32_t)1 << signal;
|
m_signal_pending_mask[0] |= (uint32_t)1 << signal;
|
||||||
else
|
else
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Kernel
|
||||||
public:
|
public:
|
||||||
void set_termios(const termios& termios) { m_termios = termios; }
|
void set_termios(const termios& termios) { m_termios = termios; }
|
||||||
termios get_termios() const { return m_termios; }
|
termios get_termios() const { return m_termios; }
|
||||||
virtual void set_font(const Font&) {};
|
virtual void set_font(const LibFont::Font&) {};
|
||||||
|
|
||||||
void set_foreground_pgrp(pid_t pgrp) { m_foreground_pgrp = pgrp; }
|
void set_foreground_pgrp(pid_t pgrp) { m_foreground_pgrp = pgrp; }
|
||||||
pid_t foreground_pgrp() const { return m_foreground_pgrp; }
|
pid_t foreground_pgrp() const { return m_foreground_pgrp; }
|
||||||
|
|
|
@ -1,61 +1,66 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/Font.h>
|
#include <LibFont/Font.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
class TerminalDriver
|
namespace Kernel
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
struct Color
|
class TerminalDriver
|
||||||
{
|
{
|
||||||
constexpr Color(uint32_t rgb)
|
public:
|
||||||
: rgb(rgb)
|
struct Color
|
||||||
{ }
|
{
|
||||||
constexpr Color(uint8_t r, uint8_t g, uint8_t b)
|
constexpr Color(uint32_t rgb)
|
||||||
: rgb(((uint32_t)r << 16) | ((uint32_t)g << 8) | b)
|
: rgb(rgb)
|
||||||
{ }
|
{ }
|
||||||
uint8_t red() const { return (rgb >> 0x10) & 0xFF; }
|
constexpr Color(uint8_t r, uint8_t g, uint8_t b)
|
||||||
uint8_t green() const { return (rgb >> 0x08) & 0xFF; }
|
: rgb(((uint32_t)r << 16) | ((uint32_t)g << 8) | b)
|
||||||
uint8_t blue() const { return (rgb >> 0x00) & 0xFF; }
|
{ }
|
||||||
uint32_t rgb;
|
uint8_t red() const { return (rgb >> 0x10) & 0xFF; }
|
||||||
|
uint8_t green() const { return (rgb >> 0x08) & 0xFF; }
|
||||||
|
uint8_t blue() const { return (rgb >> 0x00) & 0xFF; }
|
||||||
|
uint32_t rgb;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
TerminalDriver() : m_font(MUST(LibFont::Font::prefs())) {}
|
||||||
|
virtual ~TerminalDriver() {}
|
||||||
|
virtual uint32_t width() const = 0;
|
||||||
|
virtual uint32_t height() const = 0;
|
||||||
|
|
||||||
|
virtual void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) = 0;
|
||||||
|
virtual void clear(Color) = 0;
|
||||||
|
|
||||||
|
virtual void set_cursor_position(uint32_t, uint32_t) = 0;
|
||||||
|
|
||||||
|
void set_font(const LibFont::Font& font) { m_font = font; };
|
||||||
|
const LibFont::Font& font() const { return m_font; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
LibFont::Font m_font;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
namespace TerminalColor
|
||||||
TerminalDriver() : m_font(MUST(Kernel::Font::prefs())) {}
|
{
|
||||||
virtual ~TerminalDriver() {}
|
static constexpr TerminalDriver::Color BLACK = 0x000000;
|
||||||
virtual uint32_t width() const = 0;
|
static constexpr TerminalDriver::Color BLUE = 0x0000AA;
|
||||||
virtual uint32_t height() const = 0;
|
static constexpr TerminalDriver::Color GREEN = 0x00AA00;
|
||||||
|
static constexpr TerminalDriver::Color CYAN = 0x00AAAA;
|
||||||
|
static constexpr TerminalDriver::Color RED = 0xAA0000;
|
||||||
|
static constexpr TerminalDriver::Color MAGENTA = 0xAA00AA;
|
||||||
|
static constexpr TerminalDriver::Color YELLOW = 0xAA5500;
|
||||||
|
static constexpr TerminalDriver::Color WHITE = 0xAAAAAA;
|
||||||
|
|
||||||
virtual void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) = 0;
|
static constexpr TerminalDriver::Color BRIGHT_BLACK = 0x555555;
|
||||||
virtual void clear(Color) = 0;
|
static constexpr TerminalDriver::Color BRIGHT_BLUE = 0x5555FF;
|
||||||
|
static constexpr TerminalDriver::Color BRIGHT_GREEN = 0x55FF55;
|
||||||
|
static constexpr TerminalDriver::Color BRIGHT_CYAN = 0x55FFFF;
|
||||||
|
static constexpr TerminalDriver::Color BRIGHT_RED = 0xFF5555;
|
||||||
|
static constexpr TerminalDriver::Color BRIGHT_MAGENTA = 0xFF55FF;
|
||||||
|
static constexpr TerminalDriver::Color BRIGHT_YELLOW = 0xFFFF55;
|
||||||
|
static constexpr TerminalDriver::Color BRIGHT_WHITE = 0xFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void set_cursor_position(uint32_t, uint32_t) = 0;
|
|
||||||
|
|
||||||
void set_font(const Kernel::Font& font) { m_font = font; };
|
|
||||||
const Kernel::Font& font() const { return m_font; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Kernel::Font m_font;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace TerminalColor
|
|
||||||
{
|
|
||||||
static constexpr TerminalDriver::Color BLACK = 0x000000;
|
|
||||||
static constexpr TerminalDriver::Color BLUE = 0x0000AA;
|
|
||||||
static constexpr TerminalDriver::Color GREEN = 0x00AA00;
|
|
||||||
static constexpr TerminalDriver::Color CYAN = 0x00AAAA;
|
|
||||||
static constexpr TerminalDriver::Color RED = 0xAA0000;
|
|
||||||
static constexpr TerminalDriver::Color MAGENTA = 0xAA00AA;
|
|
||||||
static constexpr TerminalDriver::Color YELLOW = 0xAA5500;
|
|
||||||
static constexpr TerminalDriver::Color WHITE = 0xAAAAAA;
|
|
||||||
|
|
||||||
static constexpr TerminalDriver::Color BRIGHT_BLACK = 0x555555;
|
|
||||||
static constexpr TerminalDriver::Color BRIGHT_BLUE = 0x5555FF;
|
|
||||||
static constexpr TerminalDriver::Color BRIGHT_GREEN = 0x55FF55;
|
|
||||||
static constexpr TerminalDriver::Color BRIGHT_CYAN = 0x55FFFF;
|
|
||||||
static constexpr TerminalDriver::Color BRIGHT_RED = 0xFF5555;
|
|
||||||
static constexpr TerminalDriver::Color BRIGHT_MAGENTA = 0xFF55FF;
|
|
||||||
static constexpr TerminalDriver::Color BRIGHT_YELLOW = 0xFFFF55;
|
|
||||||
static constexpr TerminalDriver::Color BRIGHT_WHITE = 0xFFFFFF;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Kernel
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(TerminalDriver*);
|
static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(TerminalDriver*);
|
||||||
|
|
||||||
virtual void set_font(const Font&) override;
|
virtual void set_font(const LibFont::Font&) override;
|
||||||
|
|
||||||
virtual uint32_t height() const override { return m_height; }
|
virtual uint32_t height() const override { return m_height; }
|
||||||
virtual uint32_t width() const override { return m_width; }
|
virtual uint32_t width() const override { return m_width; }
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
extern TerminalDriver* g_terminal_driver;
|
extern Kernel::TerminalDriver* g_terminal_driver;
|
||||||
|
|
||||||
namespace Debug
|
namespace Debug
|
||||||
{
|
{
|
||||||
|
@ -68,6 +68,8 @@ namespace Debug
|
||||||
|
|
||||||
void putchar(char ch)
|
void putchar(char ch)
|
||||||
{
|
{
|
||||||
|
using namespace Kernel;
|
||||||
|
|
||||||
if (Kernel::Serial::has_devices())
|
if (Kernel::Serial::has_devices())
|
||||||
return Kernel::Serial::putchar_any(ch);
|
return Kernel::Serial::putchar_any(ch);
|
||||||
if (Kernel::TTY::is_initialized())
|
if (Kernel::TTY::is_initialized())
|
||||||
|
|
|
@ -21,6 +21,13 @@ namespace Kernel
|
||||||
return *s_instance;
|
return *s_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedMemoryObjectManager::Object::~Object()
|
||||||
|
{
|
||||||
|
for (auto paddr : paddrs)
|
||||||
|
if (paddr)
|
||||||
|
Heap::get().release_page(paddr);
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<SharedMemoryObjectManager::Key> SharedMemoryObjectManager::create_object(size_t size, PageTable::flags_t flags)
|
BAN::ErrorOr<SharedMemoryObjectManager::Key> SharedMemoryObjectManager::create_object(size_t size, PageTable::flags_t flags)
|
||||||
{
|
{
|
||||||
ASSERT(size % PAGE_SIZE == 0);
|
ASSERT(size % PAGE_SIZE == 0);
|
||||||
|
@ -38,11 +45,24 @@ namespace Kernel
|
||||||
Key key = generate_key();
|
Key key = generate_key();
|
||||||
while (m_objects.contains(key))
|
while (m_objects.contains(key))
|
||||||
key = generate_key();
|
key = generate_key();
|
||||||
|
object->key = key;
|
||||||
|
|
||||||
TRY(m_objects.insert(key, object));
|
TRY(m_objects.insert(key, object));
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> SharedMemoryObjectManager::delete_object(Key key)
|
||||||
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
|
auto it = m_objects.find(key);
|
||||||
|
if (it == m_objects.end())
|
||||||
|
return BAN::Error::from_errno(ENOENT);
|
||||||
|
|
||||||
|
m_objects.remove(it);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> SharedMemoryObjectManager::map_object(Key key, PageTable& page_table, AddressRange address_range)
|
BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> SharedMemoryObjectManager::map_object(Key key, PageTable& page_table, AddressRange address_range)
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
|
@ -61,6 +81,12 @@ namespace Kernel
|
||||||
return BAN::move(smo);
|
return BAN::move(smo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> SharedMemoryObject::clone(PageTable& new_page_table)
|
||||||
|
{
|
||||||
|
auto region = TRY(SharedMemoryObjectManager::get().map_object(m_object->key, new_page_table, { .start = vaddr(), .end = vaddr() + size() }));
|
||||||
|
return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<bool> SharedMemoryObject::allocate_page_containing_impl(vaddr_t address)
|
BAN::ErrorOr<bool> SharedMemoryObject::allocate_page_containing_impl(vaddr_t address)
|
||||||
{
|
{
|
||||||
ASSERT(contains(address));
|
ASSERT(contains(address));
|
||||||
|
|
|
@ -55,7 +55,15 @@ namespace Kernel
|
||||||
auto it = s_bound_sockets.find(m_bound_path);
|
auto it = s_bound_sockets.find(m_bound_path);
|
||||||
if (it != s_bound_sockets.end())
|
if (it != s_bound_sockets.end())
|
||||||
s_bound_sockets.remove(it);
|
s_bound_sockets.remove(it);
|
||||||
|
m_bound_path.clear();
|
||||||
}
|
}
|
||||||
|
if (m_info.has<ConnectionInfo>())
|
||||||
|
{
|
||||||
|
auto& connection_info = m_info.get<ConnectionInfo>();
|
||||||
|
if (auto connection = connection_info.connection.lock(); connection && connection->m_info.has<ConnectionInfo>())
|
||||||
|
connection->m_info.get<ConnectionInfo>().target_closed = true;
|
||||||
|
}
|
||||||
|
m_info.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> UnixDomainSocket::accept_impl(sockaddr* address, socklen_t* address_len)
|
BAN::ErrorOr<long> UnixDomainSocket::accept_impl(sockaddr* address, socklen_t* address_len)
|
||||||
|
@ -256,6 +264,8 @@ namespace Kernel
|
||||||
if (m_info.has<ConnectionInfo>())
|
if (m_info.has<ConnectionInfo>())
|
||||||
{
|
{
|
||||||
auto& connection_info = m_info.get<ConnectionInfo>();
|
auto& connection_info = m_info.get<ConnectionInfo>();
|
||||||
|
if (connection_info.target_closed)
|
||||||
|
return true;
|
||||||
if (!connection_info.pending_connections.empty())
|
if (!connection_info.pending_connections.empty())
|
||||||
return true;
|
return true;
|
||||||
if (!connection_info.connection)
|
if (!connection_info.connection)
|
||||||
|
@ -338,6 +348,8 @@ namespace Kernel
|
||||||
if (m_info.has<ConnectionInfo>())
|
if (m_info.has<ConnectionInfo>())
|
||||||
{
|
{
|
||||||
auto& connection_info = m_info.get<ConnectionInfo>();
|
auto& connection_info = m_info.get<ConnectionInfo>();
|
||||||
|
if (connection_info.target_closed.compare_exchange(true, false))
|
||||||
|
return 0;
|
||||||
if (!connection_info.connection)
|
if (!connection_info.connection)
|
||||||
return BAN::Error::from_errno(ENOTCONN);
|
return BAN::Error::from_errno(ENOTCONN);
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,8 +195,12 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
SpinLockGuard _(s_process_lock);
|
SpinLockGuard _(s_process_lock);
|
||||||
for (size_t i = 0; i < s_processes.size(); i++)
|
for (size_t i = 0; i < s_processes.size(); i++)
|
||||||
|
{
|
||||||
|
if (m_parent && s_processes[i]->pid() == m_parent)
|
||||||
|
s_processes[i]->add_pending_signal(SIGCHLD);
|
||||||
if (s_processes[i] == this)
|
if (s_processes[i] == this)
|
||||||
s_processes.remove(i);
|
s_processes.remove(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcFileSystem::get().on_process_delete(*this);
|
ProcFileSystem::get().on_process_delete(*this);
|
||||||
|
@ -1418,6 +1422,12 @@ namespace Kernel
|
||||||
return TRY(SharedMemoryObjectManager::get().create_object(len, page_flags));
|
return TRY(SharedMemoryObjectManager::get().create_object(len, page_flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<long> Process::sys_smo_delete(SharedMemoryObjectManager::Key key)
|
||||||
|
{
|
||||||
|
TRY(SharedMemoryObjectManager::get().delete_object(key));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_smo_map(SharedMemoryObjectManager::Key key)
|
BAN::ErrorOr<long> Process::sys_smo_map(SharedMemoryObjectManager::Key key)
|
||||||
{
|
{
|
||||||
auto region = TRY(SharedMemoryObjectManager::get().map_object(key, page_table(), { .start = 0x400000, .end = KERNEL_OFFSET }));
|
auto region = TRY(SharedMemoryObjectManager::get().map_object(key, page_table(), { .start = 0x400000, .end = KERNEL_OFFSET }));
|
||||||
|
@ -1427,6 +1437,15 @@ namespace Kernel
|
||||||
return m_mapped_regions.back()->vaddr();
|
return m_mapped_regions.back()->vaddr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<long> Process::sys_isatty(int fildes)
|
||||||
|
{
|
||||||
|
LockGuard _(m_process_lock);
|
||||||
|
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
|
||||||
|
if (!inode->is_tty())
|
||||||
|
return BAN::Error::from_errno(ENOTTY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_tty_ctrl(int fildes, int command, int flags)
|
BAN::ErrorOr<long> Process::sys_tty_ctrl(int fildes, int command, int flags)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
|
|
|
@ -62,7 +62,7 @@ namespace Kernel
|
||||||
m_terminal_driver->clear(m_background);
|
m_terminal_driver->clear(m_background);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualTTY::set_font(const Kernel::Font& font)
|
void VirtualTTY::set_font(const LibFont::Font& font)
|
||||||
{
|
{
|
||||||
m_terminal_driver->set_font(font);
|
m_terminal_driver->set_font(font);
|
||||||
|
|
||||||
|
|
|
@ -279,8 +279,21 @@ namespace Kernel
|
||||||
auto& interrupt_stack = *reinterpret_cast<InterruptStack*>(kernel_stack_top() - sizeof(InterruptStack));
|
auto& interrupt_stack = *reinterpret_cast<InterruptStack*>(kernel_stack_top() - sizeof(InterruptStack));
|
||||||
if (!GDT::is_user_segment(interrupt_stack.cs))
|
if (!GDT::is_user_segment(interrupt_stack.cs))
|
||||||
return false;
|
return false;
|
||||||
uint64_t full_pending_mask = m_signal_pending_mask | process().signal_pending_mask();;
|
|
||||||
return full_pending_mask & ~m_signal_block_mask;
|
uint64_t full_pending_mask = m_signal_pending_mask | process().signal_pending_mask();
|
||||||
|
uint64_t signals = full_pending_mask & ~m_signal_block_mask;
|
||||||
|
for (uint8_t i = 0; i < _SIGMAX; i++)
|
||||||
|
{
|
||||||
|
if (!(signals & ((uint64_t)1 << i)))
|
||||||
|
continue;
|
||||||
|
vaddr_t handler = m_process->m_signal_handlers[i];
|
||||||
|
if (handler == (vaddr_t)SIG_IGN)
|
||||||
|
continue;
|
||||||
|
if (handler == (vaddr_t)SIG_DFL && (i == SIGCHLD || i == SIGURG))
|
||||||
|
continue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::can_add_signal_to_execute() const
|
bool Thread::can_add_signal_to_execute() const
|
||||||
|
@ -395,7 +408,14 @@ namespace Kernel
|
||||||
bool Thread::add_signal(int signal)
|
bool Thread::add_signal(int signal)
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_signal_lock);
|
SpinLockGuard _(m_signal_lock);
|
||||||
|
if (m_process)
|
||||||
|
{
|
||||||
|
vaddr_t handler = m_process->m_signal_handlers[signal];
|
||||||
|
if (handler == (vaddr_t)SIG_IGN)
|
||||||
|
return false;
|
||||||
|
if (handler == (vaddr_t)SIG_DFL && (signal == SIGCHLD || signal == SIGURG))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
uint64_t mask = 1ull << signal;
|
uint64_t mask = 1ull << signal;
|
||||||
if (!(m_signal_block_mask & mask))
|
if (!(m_signal_block_mask & mask))
|
||||||
{
|
{
|
||||||
|
|
|
@ -77,7 +77,7 @@ static void parse_command_line()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminalDriver* g_terminal_driver = nullptr;
|
Kernel::TerminalDriver* g_terminal_driver = nullptr;
|
||||||
|
|
||||||
static void init2(void*);
|
static void init2(void*);
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,9 @@ int load_keymap(const char* path);
|
||||||
|
|
||||||
// Create shared memory object and return its key or -1 on error
|
// Create shared memory object and return its key or -1 on error
|
||||||
long smo_create(size_t size, int prot);
|
long smo_create(size_t size, int prot);
|
||||||
// Map shared memory object defined by its key and return address or null on error
|
// Delete shared memory object such that it will be no longer accessible with smo_map(). Existing mappings are still valid
|
||||||
|
int smo_delete(long key);
|
||||||
|
// Map shared memory object defined by its key and return address or null on error. Mappings can be unmapped using munmap()
|
||||||
void* smo_map(long key);
|
void* smo_map(long key);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
|
@ -75,7 +75,9 @@ __BEGIN_DECLS
|
||||||
O(SYS_PSELECT, pselect) \
|
O(SYS_PSELECT, pselect) \
|
||||||
O(SYS_TRUNCATE, truncate) \
|
O(SYS_TRUNCATE, truncate) \
|
||||||
O(SYS_SMO_CREATE, smo_create) \
|
O(SYS_SMO_CREATE, smo_create) \
|
||||||
|
O(SYS_SMO_DELETE, smo_delete) \
|
||||||
O(SYS_SMO_MAP, smo_map) \
|
O(SYS_SMO_MAP, smo_map) \
|
||||||
|
O(SYS_ISATTY, isatty) \
|
||||||
|
|
||||||
enum Syscall
|
enum Syscall
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,11 @@ long smo_create(size_t size, int prot)
|
||||||
return syscall(SYS_SMO_CREATE, size, prot);
|
return syscall(SYS_SMO_CREATE, size, prot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int smo_delete(long key)
|
||||||
|
{
|
||||||
|
return syscall(SYS_SMO_DELETE, key);
|
||||||
|
}
|
||||||
|
|
||||||
void* smo_map(long key)
|
void* smo_map(long key)
|
||||||
{
|
{
|
||||||
long ret = syscall(SYS_SMO_MAP, key);
|
long ret = syscall(SYS_SMO_MAP, key);
|
||||||
|
|
|
@ -114,6 +114,11 @@ int dup2(int fildes, int fildes2)
|
||||||
return syscall(SYS_DUP2, fildes, fildes2);
|
return syscall(SYS_DUP2, fildes, fildes2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int isatty(int fildes)
|
||||||
|
{
|
||||||
|
return syscall(SYS_ISATTY, fildes) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
int execl(const char* pathname, const char* arg0, ...)
|
int execl(const char* pathname, const char* arg0, ...)
|
||||||
{
|
{
|
||||||
if (arg0 == nullptr)
|
if (arg0 == nullptr)
|
||||||
|
|
|
@ -30,6 +30,7 @@ set(USERSPACE_PROJECTS
|
||||||
sudo
|
sudo
|
||||||
sync
|
sync
|
||||||
tee
|
tee
|
||||||
|
Terminal
|
||||||
test
|
test
|
||||||
test-framebuffer
|
test-framebuffer
|
||||||
test-globals
|
test-globals
|
||||||
|
|
|
@ -331,6 +331,15 @@ BAN::Optional<int> execute_builtin(BAN::Vector<BAN::String>& args, int fd_in, in
|
||||||
while (*current)
|
while (*current)
|
||||||
fprintf(fout, "%s\n", *current++);
|
fprintf(fout, "%s\n", *current++);
|
||||||
}
|
}
|
||||||
|
else if (args.front() == "start-gui"sv)
|
||||||
|
{
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == 0)
|
||||||
|
execl("/bin/WindowServer", "WindowServer", NULL);
|
||||||
|
if (fork() == 0)
|
||||||
|
execl("/bin/Terminal", "Terminal", NULL);
|
||||||
|
waitpid(pid, nullptr, 0);
|
||||||
|
}
|
||||||
else if (args.front() == "page-fault-test"sv)
|
else if (args.front() == "page-fault-test"sv)
|
||||||
{
|
{
|
||||||
volatile int* ptr = nullptr;
|
volatile int* ptr = nullptr;
|
||||||
|
@ -601,7 +610,7 @@ pid_t execute_command_no_wait(BAN::Vector<BAN::String>& args, int fd_in, int fd_
|
||||||
perror("setpgid");
|
perror("setpgid");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (tcsetpgrp(0, getpgrp()) == -1)
|
if (isatty(0) && tcsetpgrp(0, getpgrp()) == -1)
|
||||||
{
|
{
|
||||||
perror("tcsetpgrp");
|
perror("tcsetpgrp");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -633,7 +642,7 @@ int execute_command(BAN::Vector<BAN::String>& args, int fd_in, int fd_out)
|
||||||
if (waitpid(pid, &status, 0) == -1)
|
if (waitpid(pid, &status, 0) == -1)
|
||||||
ERROR_RETURN("waitpid", 1);
|
ERROR_RETURN("waitpid", 1);
|
||||||
|
|
||||||
if (tcsetpgrp(0, getpgrp()) == -1)
|
if (isatty(0) && tcsetpgrp(0, getpgrp()) == -1)
|
||||||
ERROR_RETURN("tcsetpgrp", 1);
|
ERROR_RETURN("tcsetpgrp", 1);
|
||||||
|
|
||||||
if (WIFSIGNALED(status))
|
if (WIFSIGNALED(status))
|
||||||
|
@ -711,7 +720,7 @@ int execute_piped_commands(BAN::Vector<BAN::Vector<BAN::String>>& commands)
|
||||||
exit_codes[i] = WEXITSTATUS(status);
|
exit_codes[i] = WEXITSTATUS(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tcsetpgrp(0, getpgrp()) == -1)
|
if (isatty(0) && tcsetpgrp(0, getpgrp()) == -1)
|
||||||
ERROR_RETURN("tcsetpgrp", 1);
|
ERROR_RETURN("tcsetpgrp", 1);
|
||||||
|
|
||||||
return exit_codes.back();
|
return exit_codes.back();
|
||||||
|
@ -1053,7 +1062,7 @@ int main(int argc, char** argv)
|
||||||
buffers[index].clear();
|
buffers[index].clear();
|
||||||
col = 0;
|
col = 0;
|
||||||
break;
|
break;
|
||||||
case '\x04':
|
case '\x04': // ^D
|
||||||
fprintf(stdout, "\n");
|
fprintf(stdout, "\n");
|
||||||
clean_exit();
|
clean_exit();
|
||||||
break;
|
break;
|
||||||
|
@ -1075,7 +1084,10 @@ int main(int argc, char** argv)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
MUST(buffers[index].insert(ch, col++));
|
MUST(buffers[index].insert(ch, col++));
|
||||||
fprintf(stdout, "%c\e[s%s\e[u", ch, buffers[index].data() + col);
|
if (col == buffers[index].size())
|
||||||
|
fputc(ch, stdout);
|
||||||
|
else
|
||||||
|
fprintf(stdout, "%c\e[s%s\e[u", ch, buffers[index].data() + col);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
|
project(Terminal CXX)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
main.cpp
|
||||||
|
Terminal.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(Terminal ${SOURCES})
|
||||||
|
target_compile_options(Terminal PUBLIC -O2 -g)
|
||||||
|
target_link_libraries(Terminal PUBLIC libc ban libfont libgui libinput)
|
||||||
|
|
||||||
|
add_custom_target(Terminal-install
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/Terminal ${BANAN_BIN}/
|
||||||
|
DEPENDS Terminal
|
||||||
|
)
|
|
@ -0,0 +1,380 @@
|
||||||
|
#include "Terminal.h"
|
||||||
|
|
||||||
|
#include <BAN/Debug.h>
|
||||||
|
#include <BAN/UTF8.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void Terminal::start_shell()
|
||||||
|
{
|
||||||
|
int shell_stdin[2];
|
||||||
|
if (pipe(shell_stdin) == -1)
|
||||||
|
{
|
||||||
|
dwarnln("pipe: {}", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int shell_stdout[2];
|
||||||
|
if (pipe(shell_stdout) == -1)
|
||||||
|
{
|
||||||
|
dwarnln("pipe: {}", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int shell_stderr[2];
|
||||||
|
if (pipe(shell_stderr) == -1)
|
||||||
|
{
|
||||||
|
dwarnln("pipe: {}", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t shell_pid = fork();
|
||||||
|
if (shell_pid == 0)
|
||||||
|
{
|
||||||
|
if (dup2(shell_stdin[0], STDIN_FILENO) == -1)
|
||||||
|
{
|
||||||
|
dwarnln("dup2: {}", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close(shell_stdin[0]);
|
||||||
|
close(shell_stdin[1]);
|
||||||
|
|
||||||
|
if (dup2(shell_stdout[1], STDOUT_FILENO) == -1)
|
||||||
|
{
|
||||||
|
dwarnln("dup2: {}", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close(shell_stdout[0]);
|
||||||
|
close(shell_stdout[1]);
|
||||||
|
|
||||||
|
if (dup2(shell_stderr[1], STDERR_FILENO) == -1)
|
||||||
|
{
|
||||||
|
dwarnln("dup2: {}", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close(shell_stderr[0]);
|
||||||
|
close(shell_stderr[1]);
|
||||||
|
|
||||||
|
execl("/bin/Shell", "Shell", NULL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell_pid == -1)
|
||||||
|
{
|
||||||
|
dwarnln("fork: {}", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(shell_stdin[0]);
|
||||||
|
close(shell_stdout[1]);
|
||||||
|
close(shell_stderr[1]);
|
||||||
|
|
||||||
|
m_shell_info = {
|
||||||
|
.in = shell_stdin[1],
|
||||||
|
.out = shell_stdout[0],
|
||||||
|
.err = shell_stderr[0],
|
||||||
|
.pid = shell_pid
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static volatile bool s_shell_exited = false;
|
||||||
|
|
||||||
|
void Terminal::run()
|
||||||
|
{
|
||||||
|
signal(SIGCHLD, [](int) { s_shell_exited = true; });
|
||||||
|
start_shell();
|
||||||
|
|
||||||
|
m_window = MUST(LibGUI::Window::create(600, 400, "Terminal"sv));
|
||||||
|
m_window->fill(m_bg_color);
|
||||||
|
m_window->invalidate();
|
||||||
|
|
||||||
|
m_font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"sv));
|
||||||
|
|
||||||
|
m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent event) { on_key_event(event); });
|
||||||
|
|
||||||
|
const int max_fd = BAN::Math::max(BAN::Math::max(m_shell_info.out, m_shell_info.err), m_window->server_fd());
|
||||||
|
while (!s_shell_exited)
|
||||||
|
{
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(m_shell_info.out, &fds);
|
||||||
|
FD_SET(m_shell_info.err, &fds);
|
||||||
|
FD_SET(m_window->server_fd(), &fds);
|
||||||
|
|
||||||
|
select(max_fd + 1, &fds, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (FD_ISSET(m_shell_info.out, &fds))
|
||||||
|
if (!read_shell(m_shell_info.out))
|
||||||
|
break;
|
||||||
|
if (FD_ISSET(m_shell_info.err, &fds))
|
||||||
|
if (!read_shell(m_shell_info.err))
|
||||||
|
break;
|
||||||
|
if (FD_ISSET(m_window->server_fd(), &fds))
|
||||||
|
m_window->poll_events();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Terminal::read_shell(int fd)
|
||||||
|
{
|
||||||
|
char buffer[128];
|
||||||
|
ssize_t nread = read(fd, buffer, sizeof(buffer) - 1);
|
||||||
|
if (nread < 0)
|
||||||
|
dwarnln("read: {}", strerror(errno));
|
||||||
|
if (nread <= 0)
|
||||||
|
return false;
|
||||||
|
for (ssize_t i = 0; i < nread; i++)
|
||||||
|
putchar(buffer[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::handle_sgr()
|
||||||
|
{
|
||||||
|
constexpr uint32_t colors_default[] {
|
||||||
|
0x555555,
|
||||||
|
0xFF5555,
|
||||||
|
0x55FF55,
|
||||||
|
0xFFFF55,
|
||||||
|
0x5555FF,
|
||||||
|
0xFF55FF,
|
||||||
|
0x55FFFF,
|
||||||
|
0xFFFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t colors_bright[] {
|
||||||
|
0xAAAAAA,
|
||||||
|
0xFFAAAA,
|
||||||
|
0xAAFFAA,
|
||||||
|
0xFFFFAA,
|
||||||
|
0xAAAAFF,
|
||||||
|
0xFFAAFF,
|
||||||
|
0xAAFFFF,
|
||||||
|
0xFFFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (m_csi_info.fields[0])
|
||||||
|
{
|
||||||
|
case -1: case 0:
|
||||||
|
m_fg_color = 0xFFFFFF;
|
||||||
|
m_bg_color = 0x000000;
|
||||||
|
break;
|
||||||
|
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37:
|
||||||
|
m_fg_color = colors_default[m_csi_info.fields[0] - 30];
|
||||||
|
break;
|
||||||
|
case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
|
||||||
|
m_bg_color = colors_default[m_csi_info.fields[0] - 40];
|
||||||
|
break;
|
||||||
|
case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97:
|
||||||
|
m_fg_color = colors_bright[m_csi_info.fields[0] - 90];
|
||||||
|
break;
|
||||||
|
case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107:
|
||||||
|
m_bg_color = colors_bright[m_csi_info.fields[0] - 100];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintln("TODO: SGR {}", m_csi_info.fields[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::handle_csi(char ch)
|
||||||
|
{
|
||||||
|
if (ch == ';')
|
||||||
|
{
|
||||||
|
m_csi_info.index++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '?')
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isdigit(ch))
|
||||||
|
{
|
||||||
|
if (m_csi_info.index <= 1)
|
||||||
|
{
|
||||||
|
auto& field = m_csi_info.fields[m_csi_info.index];
|
||||||
|
field = (BAN::Math::max(field, 0) * 10) + (ch - '0');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ch)
|
||||||
|
{
|
||||||
|
case 'C':
|
||||||
|
if (m_csi_info.fields[0] == -1)
|
||||||
|
m_csi_info.fields[0] = 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::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;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
|
||||||
|
m_cursor.x = BAN::Math::clamp<int32_t>(m_csi_info.fields[1], 1, cols()) - 1;
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
{
|
||||||
|
uint32_t rects[2][4] { { (uint32_t)-1 }, { (uint32_t)-1 } };
|
||||||
|
|
||||||
|
if (m_csi_info.fields[0] == -1 || m_csi_info.fields[0] == 0)
|
||||||
|
{
|
||||||
|
rects[0][0] = m_cursor.x * m_font.width();
|
||||||
|
rects[0][1] = m_cursor.y * m_font.height();
|
||||||
|
rects[0][2] = m_window->width() - rects[0][0];
|
||||||
|
rects[0][3] = m_font.height();
|
||||||
|
|
||||||
|
rects[1][0] = 0;
|
||||||
|
rects[1][1] = (m_cursor.y + 1) * m_font.height();
|
||||||
|
rects[1][2] = m_window->width();
|
||||||
|
rects[1][3] = m_window->height() - rects[1][1];
|
||||||
|
}
|
||||||
|
else if (m_csi_info.fields[0] == 1)
|
||||||
|
{
|
||||||
|
rects[0][0] = 0;
|
||||||
|
rects[0][1] = m_cursor.y * m_font.height();
|
||||||
|
rects[0][2] = m_cursor.x * m_font.width();
|
||||||
|
rects[0][3] = m_font.height();
|
||||||
|
|
||||||
|
rects[1][0] = 0;
|
||||||
|
rects[1][1] = 0;
|
||||||
|
rects[1][2] = m_window->width();
|
||||||
|
rects[1][3] = m_cursor.y * m_font.height();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rects[0][0] = 0;
|
||||||
|
rects[0][1] = 0;
|
||||||
|
rects[0][2] = m_window->width();
|
||||||
|
rects[0][3] = m_window->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
if (rects[i][0] == (uint32_t)-1)
|
||||||
|
continue;
|
||||||
|
m_window->fill_rect(rects[i][0], rects[i][1], rects[i][2], rects[i][3], m_bg_color);
|
||||||
|
m_window->invalidate(rects[i][0], rects[i][1], rects[i][2], rects[i][3]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'K':
|
||||||
|
{
|
||||||
|
m_csi_info.fields[0] = BAN::Math::max(m_csi_info.fields[0], 0);
|
||||||
|
|
||||||
|
uint32_t rect[4];
|
||||||
|
rect[0] = (m_csi_info.fields[0] == 0) ? m_cursor.x * m_font.width() : 0;
|
||||||
|
rect[1] = m_cursor.y * m_font.height();
|
||||||
|
rect[2] = (m_csi_info.fields[0] == 1) ? m_cursor.x * m_font.width() : m_window->width() - rect[0];
|
||||||
|
rect[3] = m_font.height();
|
||||||
|
|
||||||
|
m_window->fill_rect(rect[0], rect[1], rect[2], rect[3], m_bg_color);
|
||||||
|
m_window->invalidate(rect[0], rect[1], rect[2], rect[3]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'm':
|
||||||
|
handle_sgr();
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
m_saved_cursor = m_cursor;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
m_cursor = m_saved_cursor;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintln("TODO: CSI {}", ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_state = State::Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::putchar(uint32_t codepoint)
|
||||||
|
{
|
||||||
|
if (m_state == State::ESC)
|
||||||
|
{
|
||||||
|
if (codepoint != '[')
|
||||||
|
{
|
||||||
|
dprintln("unknown escape character 0x{H}", codepoint);
|
||||||
|
m_state = State::Normal;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_state = State::CSI;
|
||||||
|
m_csi_info.index = 0;
|
||||||
|
m_csi_info.fields[0] = -1;
|
||||||
|
m_csi_info.fields[1] = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == State::CSI)
|
||||||
|
{
|
||||||
|
if (codepoint < 0x20 || codepoint > 0xFE)
|
||||||
|
{
|
||||||
|
dprintln("invalid CSI 0x{H}", codepoint);
|
||||||
|
m_state = State::Normal;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handle_csi(codepoint);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_window->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())
|
||||||
|
{
|
||||||
|
uint32_t scroll = m_cursor.y - rows() + 1;
|
||||||
|
m_cursor.y -= scroll;
|
||||||
|
m_window->shift_vertical(-scroll * (int32_t)m_font.height());
|
||||||
|
m_window->fill_rect(0, m_window->height() - scroll * m_font.height(), m_window->width(), scroll * m_font.height(), m_bg_color);
|
||||||
|
m_window->invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::on_key_event(LibGUI::EventPacket::KeyEvent event)
|
||||||
|
{
|
||||||
|
if (event.released())
|
||||||
|
return;
|
||||||
|
if (const char* text = LibInput::key_to_utf8_ansi(event.key, event.modifier))
|
||||||
|
write(m_shell_info.in, text, strlen(text));
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibFont/Font.h>
|
||||||
|
|
||||||
|
#include <LibGUI/Window.h>
|
||||||
|
|
||||||
|
class Terminal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void run();
|
||||||
|
|
||||||
|
uint32_t cols() const { return m_window->width() / m_font.width(); }
|
||||||
|
uint32_t rows() const { return m_window->height() / m_font.height(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handle_csi(char ch);
|
||||||
|
void handle_sgr();
|
||||||
|
void putchar(uint32_t codepoint);
|
||||||
|
bool read_shell(int fd);
|
||||||
|
|
||||||
|
void on_key_event(LibGUI::EventPacket::KeyEvent);
|
||||||
|
|
||||||
|
void start_shell();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Cursor
|
||||||
|
{
|
||||||
|
uint32_t x;
|
||||||
|
uint32_t y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShellInfo
|
||||||
|
{
|
||||||
|
int in;
|
||||||
|
int out;
|
||||||
|
int err;
|
||||||
|
pid_t pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class State
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
ESC,
|
||||||
|
CSI,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CSIInfo
|
||||||
|
{
|
||||||
|
int32_t fields[2];
|
||||||
|
size_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::UniqPtr<LibGUI::Window> m_window;
|
||||||
|
LibFont::Font m_font;
|
||||||
|
Cursor m_cursor { 0, 0 };
|
||||||
|
ShellInfo m_shell_info;
|
||||||
|
State m_state { State::Normal };
|
||||||
|
CSIInfo m_csi_info;
|
||||||
|
|
||||||
|
Cursor m_saved_cursor { 0, 0 };
|
||||||
|
uint32_t m_fg_color { 0xFFFFFF };
|
||||||
|
uint32_t m_bg_color { 0x000000 };
|
||||||
|
};
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "Terminal.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Terminal terminal;
|
||||||
|
terminal.run();
|
||||||
|
}
|
|
@ -5,12 +5,13 @@ project(WindowServer CXX)
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
main.cpp
|
main.cpp
|
||||||
Framebuffer.cpp
|
Framebuffer.cpp
|
||||||
|
Window.cpp
|
||||||
WindowServer.cpp
|
WindowServer.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(WindowServer ${SOURCES})
|
add_executable(WindowServer ${SOURCES})
|
||||||
target_compile_options(WindowServer PUBLIC -O2 -g)
|
target_compile_options(WindowServer PUBLIC -O2 -g)
|
||||||
target_link_libraries(WindowServer PUBLIC libc ban libgui libinput)
|
target_link_libraries(WindowServer PUBLIC libc ban libfont libgui libinput)
|
||||||
|
|
||||||
add_custom_target(WindowServer-install
|
add_custom_target(WindowServer-install
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/WindowServer ${BANAN_BIN}/
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/WindowServer ${BANAN_BIN}/
|
||||||
|
|
|
@ -63,3 +63,18 @@ struct Rectangle
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Circle
|
||||||
|
{
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
int32_t radius;
|
||||||
|
|
||||||
|
bool contains(Position position) const
|
||||||
|
{
|
||||||
|
int32_t dx = position.x - x;
|
||||||
|
int32_t dy = position.y - y;
|
||||||
|
return dx * dx + dy * dy <= radius * radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
#include "Window.h"
|
||||||
|
|
||||||
|
#include <BAN/Debug.h>
|
||||||
|
|
||||||
|
#include <LibGUI/Window.h>
|
||||||
|
|
||||||
|
#include <sys/banan-os.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
Window::Window(int fd, Rectangle area, long smo_key, BAN::StringView title, const LibFont::Font& font)
|
||||||
|
: m_client_fd(fd)
|
||||||
|
, m_client_area(area)
|
||||||
|
, m_smo_key(smo_key)
|
||||||
|
{
|
||||||
|
MUST(m_title.append(title));
|
||||||
|
prepare_title_bar(font);
|
||||||
|
|
||||||
|
m_fb_addr = static_cast<uint32_t*>(smo_map(smo_key));
|
||||||
|
ASSERT(m_fb_addr);
|
||||||
|
memset(m_fb_addr, 0, client_width() * client_height() * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::~Window()
|
||||||
|
{
|
||||||
|
munmap(m_fb_addr, client_width() * client_height() * 4);
|
||||||
|
smo_delete(m_smo_key);
|
||||||
|
|
||||||
|
LibGUI::EventPacket event;
|
||||||
|
event.type = LibGUI::EventPacket::Type::DestroyWindow;
|
||||||
|
send(m_client_fd, &event, sizeof(event), 0);
|
||||||
|
close(m_client_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::prepare_title_bar(const LibFont::Font& font)
|
||||||
|
{
|
||||||
|
const size_t title_bar_bytes = title_bar_width() * title_bar_height() * 4;
|
||||||
|
uint32_t* title_bar_data = new uint32_t[title_bar_bytes];
|
||||||
|
ASSERT(title_bar_data);
|
||||||
|
for (size_t i = 0; i < title_bar_bytes; i++)
|
||||||
|
title_bar_data[i] = 0xFFFFFF;
|
||||||
|
|
||||||
|
const auto text_area = title_text_area();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_title.size() && (i + 1) * font.width() < static_cast<uint32_t>(text_area.width); i++)
|
||||||
|
{
|
||||||
|
const auto* glyph = font.glyph(m_title[i]);
|
||||||
|
if (glyph == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int32_t y_off = (font.height() < (uint32_t)title_bar_height()) ? (title_bar_height() - font.height()) / 2 : 0;
|
||||||
|
const int32_t x_off = y_off + i * font.width();
|
||||||
|
for (int32_t y = 0; (uint32_t)y < font.height(); y++)
|
||||||
|
{
|
||||||
|
if (y + y_off >= title_bar_height())
|
||||||
|
break;
|
||||||
|
for (int32_t x = 0; (uint32_t)x < font.width(); x++)
|
||||||
|
{
|
||||||
|
if (x + x_off >= text_area.width)
|
||||||
|
break;
|
||||||
|
const uint8_t bitmask = 1 << (font.width() - x - 1);
|
||||||
|
if (glyph[y * font.pitch()] & bitmask)
|
||||||
|
title_bar_data[(y_off + y) * title_bar_width() + (x_off + x)] = 0x000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_title_bar_data)
|
||||||
|
delete[] m_title_bar_data;
|
||||||
|
m_title_bar_data = title_bar_data;
|
||||||
|
}
|
|
@ -3,13 +3,15 @@
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
#include <BAN/RefPtr.h>
|
#include <BAN/RefPtr.h>
|
||||||
|
#include <BAN/String.h>
|
||||||
|
|
||||||
|
#include <LibFont/Font.h>
|
||||||
|
|
||||||
class Window : public BAN::RefCounted<Window>
|
class Window : public BAN::RefCounted<Window>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Window(int fd)
|
Window(int fd, Rectangle area, long smo_key, BAN::StringView title, const LibFont::Font& font);
|
||||||
: m_client_fd(fd)
|
~Window();
|
||||||
{ }
|
|
||||||
|
|
||||||
void set_position(Position position)
|
void set_position(Position position)
|
||||||
{
|
{
|
||||||
|
@ -17,16 +19,6 @@ public:
|
||||||
m_client_area.y = position.y;
|
m_client_area.y = position.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_size(Position size, uint32_t* fb_addr)
|
|
||||||
{
|
|
||||||
m_client_area.width = size.x;
|
|
||||||
m_client_area.height = size.y;
|
|
||||||
m_fb_addr = fb_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_deleted() const { return m_deleted; }
|
|
||||||
void mark_deleted() { m_deleted = true; }
|
|
||||||
|
|
||||||
int client_fd() const { return m_client_fd; }
|
int client_fd() const { return m_client_fd; }
|
||||||
|
|
||||||
int32_t client_x() const { return m_client_area.x; }
|
int32_t client_x() const { return m_client_area.x; }
|
||||||
|
@ -56,24 +48,29 @@ public:
|
||||||
{
|
{
|
||||||
ASSERT(title_bar_area().contains({ abs_x, abs_y }));
|
ASSERT(title_bar_area().contains({ abs_x, abs_y }));
|
||||||
|
|
||||||
Rectangle close_button = {
|
if (auto close_button = close_button_area(); close_button.contains({ abs_x, abs_y }))
|
||||||
title_bar_x() + title_bar_width() - title_bar_height() + 1,
|
return close_button.contains(cursor) ? 0xFF0000 : 0xD00000;
|
||||||
title_bar_y() + 1,
|
|
||||||
title_bar_height() - 2,
|
|
||||||
title_bar_height() - 2
|
|
||||||
};
|
|
||||||
|
|
||||||
if (close_button.contains({ abs_x, abs_y }))
|
int32_t rel_x = abs_x - title_bar_x();
|
||||||
return close_button.contains(cursor) ? 0xFF0000 : 0xA00000;
|
int32_t rel_y = abs_y - title_bar_y();
|
||||||
|
return m_title_bar_data[rel_y * title_bar_width() + rel_x];
|
||||||
return 0xFFFFFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Circle close_button_area() const { return { title_bar_x() + title_bar_width() - title_bar_height() / 2, title_bar_y() + title_bar_height() / 2, title_bar_height() * 3 / 8 }; }
|
||||||
|
Rectangle title_text_area() const { return { title_bar_x(), title_bar_y(), title_bar_width() - title_bar_height(), title_bar_height() }; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void prepare_title_bar(const LibFont::Font& font);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr int32_t m_title_bar_height { 20 };
|
static constexpr int32_t m_title_bar_height { 20 };
|
||||||
|
|
||||||
const int m_client_fd { -1 };
|
const int m_client_fd { -1 };
|
||||||
uint32_t* m_fb_addr { nullptr };
|
|
||||||
Rectangle m_client_area { 0, 0, 0, 0 };
|
Rectangle m_client_area { 0, 0, 0, 0 };
|
||||||
bool m_deleted { false };
|
long m_smo_key { 0 };
|
||||||
|
uint32_t* m_fb_addr { nullptr };
|
||||||
|
uint32_t* m_title_bar_data { nullptr };
|
||||||
|
BAN::String m_title;
|
||||||
|
|
||||||
|
friend class BAN::RefPtr<Window>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,44 +1,110 @@
|
||||||
#include "Cursor.h"
|
#include "Cursor.h"
|
||||||
#include "WindowServer.h"
|
#include "WindowServer.h"
|
||||||
|
|
||||||
|
#include <BAN/Debug.h>
|
||||||
|
|
||||||
#include <LibGUI/Window.h>
|
#include <LibGUI/Window.h>
|
||||||
#include <LibInput/KeyboardLayout.h>
|
#include <LibInput/KeyboardLayout.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/banan-os.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
void WindowServer::add_window(int fd, BAN::RefPtr<Window> window)
|
void WindowServer::on_window_packet(int fd, LibGUI::WindowPacket packet)
|
||||||
{
|
{
|
||||||
MUST(m_windows_ordered.insert(0, window));
|
switch (packet.type)
|
||||||
MUST(m_windows.insert(fd, window));
|
|
||||||
set_focused_window(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowServer::for_each_window(const BAN::Function<BAN::Iteration(int, Window&)>& callback)
|
|
||||||
{
|
|
||||||
BAN::Vector<int> deleted_windows;
|
|
||||||
for (auto it = m_windows.begin(); it != m_windows.end(); it++)
|
|
||||||
{
|
{
|
||||||
auto ret = callback(it->key, *it->value);
|
case LibGUI::WindowPacketType::CreateWindow:
|
||||||
if (it->value->is_deleted())
|
|
||||||
MUST(deleted_windows.push_back(it->key));
|
|
||||||
if (ret == BAN::Iteration::Break)
|
|
||||||
break;
|
|
||||||
ASSERT(ret == BAN::Iteration::Continue);
|
|
||||||
}
|
|
||||||
for (int fd : deleted_windows)
|
|
||||||
{
|
|
||||||
auto window = m_windows[fd];
|
|
||||||
m_windows.remove(fd);
|
|
||||||
for (size_t i = 0; i < m_windows_ordered.size(); i++)
|
|
||||||
{
|
{
|
||||||
if (m_windows_ordered[i] == window)
|
// FIXME: This should be probably allowed
|
||||||
|
for (auto& window : m_client_windows)
|
||||||
{
|
{
|
||||||
m_windows_ordered.remove(i);
|
if (window->client_fd() == fd)
|
||||||
|
{
|
||||||
|
dwarnln("client {} tried to create window while already owning a window", fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t window_fb_bytes = packet.create.width * packet.create.height * 4;
|
||||||
|
|
||||||
|
long smo_key = smo_create(window_fb_bytes, PROT_READ | PROT_WRITE);
|
||||||
|
if (smo_key == -1)
|
||||||
|
{
|
||||||
|
dwarnln("smo_create: {}", strerror(errno));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle window_area {
|
||||||
|
static_cast<int32_t>((m_framebuffer.width - packet.create.width) / 2),
|
||||||
|
static_cast<int32_t>((m_framebuffer.height - packet.create.height) / 2),
|
||||||
|
static_cast<int32_t>(packet.create.width),
|
||||||
|
static_cast<int32_t>(packet.create.height)
|
||||||
|
};
|
||||||
|
|
||||||
|
packet.create.title[sizeof(packet.create.title) - 1] = '\0';
|
||||||
|
|
||||||
|
// Window::Window(int fd, Rectangle area, long smo_key, BAN::StringView title, const LibFont::Font& font)
|
||||||
|
auto window = MUST(BAN::RefPtr<Window>::create(
|
||||||
|
fd,
|
||||||
|
window_area,
|
||||||
|
smo_key,
|
||||||
|
packet.create.title,
|
||||||
|
m_font
|
||||||
|
));
|
||||||
|
MUST(m_client_windows.push_back(window));
|
||||||
|
set_focused_window(window);
|
||||||
|
|
||||||
|
LibGUI::WindowCreateResponse response;
|
||||||
|
response.framebuffer_smo_key = smo_key;
|
||||||
|
if (send(window->client_fd(), &response, sizeof(response), 0) != sizeof(response))
|
||||||
|
{
|
||||||
|
dwarnln("send: {}", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case LibGUI::WindowPacketType::Invalidate:
|
||||||
|
{
|
||||||
|
if (packet.invalidate.width == 0 || packet.invalidate.height == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
BAN::RefPtr<Window> target_window;
|
||||||
|
for (auto& window : m_client_windows)
|
||||||
|
{
|
||||||
|
if (window->client_fd() == fd)
|
||||||
|
{
|
||||||
|
target_window = window;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!target_window)
|
||||||
|
{
|
||||||
|
dwarnln("client {} tried to invalidate window while not owning a window", fd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int32_t br_x = packet.invalidate.x + packet.invalidate.width - 1;
|
||||||
|
const int32_t br_y = packet.invalidate.y + packet.invalidate.height - 1;
|
||||||
|
if (!target_window->client_size().contains({ br_x, br_y }))
|
||||||
|
{
|
||||||
|
dwarnln("Invalid Invalidate packet parameters");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate({
|
||||||
|
target_window->client_x() + static_cast<int32_t>(packet.invalidate.x),
|
||||||
|
target_window->client_y() + static_cast<int32_t>(packet.invalidate.y),
|
||||||
|
static_cast<int32_t>(packet.invalidate.width),
|
||||||
|
static_cast<int32_t>(packet.invalidate.height),
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +119,18 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||||
|
|
||||||
// Quick hack to stop the window server
|
// Quick hack to stop the window server
|
||||||
if (event.pressed() && event.key == LibInput::Key::Escape)
|
if (event.pressed() && event.key == LibInput::Key::Escape)
|
||||||
exit(0);
|
{
|
||||||
|
m_is_stopped = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill window with mod+Q
|
||||||
|
if (m_is_mod_key_held && event.pressed() && event.key == LibInput::Key::Q)
|
||||||
|
{
|
||||||
|
if (m_focused_window)
|
||||||
|
remove_client_fd(m_focused_window->client_fd());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_focused_window)
|
if (m_focused_window)
|
||||||
{
|
{
|
||||||
|
@ -67,11 +144,11 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||||
void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
||||||
{
|
{
|
||||||
BAN::RefPtr<Window> target_window;
|
BAN::RefPtr<Window> target_window;
|
||||||
for (size_t i = m_windows_ordered.size(); i > 0; i--)
|
for (size_t i = m_client_windows.size(); i > 0; i--)
|
||||||
{
|
{
|
||||||
if (m_windows_ordered[i - 1]->full_area().contains(m_cursor))
|
if (m_client_windows[i - 1]->full_area().contains(m_cursor))
|
||||||
{
|
{
|
||||||
target_window = m_windows_ordered[i - 1];
|
target_window = m_client_windows[i - 1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,10 +160,18 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
||||||
set_focused_window(target_window);
|
set_focused_window(target_window);
|
||||||
|
|
||||||
// Handle window moving when mod key is held or mouse press on title bar
|
// Handle window moving when mod key is held or mouse press on title bar
|
||||||
if (event.pressed && event.button == LibInput::MouseButton::Left && !m_is_moving_window && (target_window->title_bar_area().contains(m_cursor) || m_is_mod_key_held))
|
const bool can_start_move = m_is_mod_key_held || target_window->title_text_area().contains(m_cursor);
|
||||||
|
if (event.pressed && event.button == LibInput::MouseButton::Left && !m_is_moving_window && can_start_move)
|
||||||
m_is_moving_window = true;
|
m_is_moving_window = true;
|
||||||
else if (m_is_moving_window && !event.pressed)
|
else if (m_is_moving_window && !event.pressed)
|
||||||
m_is_moving_window = false;
|
m_is_moving_window = false;
|
||||||
|
else if (!event.pressed && event.button == LibInput::MouseButton::Left && target_window->close_button_area().contains(m_cursor))
|
||||||
|
{
|
||||||
|
// NOTE: we always have target window if code reaches here
|
||||||
|
LibGUI::EventPacket packet;
|
||||||
|
packet.type = LibGUI::EventPacket::Type::CloseWindow;
|
||||||
|
send(m_focused_window->client_fd(), &packet, sizeof(packet), 0);
|
||||||
|
}
|
||||||
else if (target_window->client_area().contains(m_cursor))
|
else if (target_window->client_area().contains(m_cursor))
|
||||||
{
|
{
|
||||||
// NOTE: we always have target window if code reaches here
|
// NOTE: we always have target window if code reaches here
|
||||||
|
@ -119,7 +204,7 @@ void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
|
||||||
invalidate(new_cursor);
|
invalidate(new_cursor);
|
||||||
|
|
||||||
// TODO: Really no need to loop over every window
|
// TODO: Really no need to loop over every window
|
||||||
for (auto& window : m_windows_ordered)
|
for (auto& window : m_client_windows)
|
||||||
{
|
{
|
||||||
auto title_bar = window->title_bar_area();
|
auto title_bar = window->title_bar_area();
|
||||||
if (title_bar.get_overlap(old_cursor).has_value() || title_bar.get_overlap(new_cursor).has_value())
|
if (title_bar.get_overlap(old_cursor).has_value() || title_bar.get_overlap(new_cursor).has_value())
|
||||||
|
@ -165,13 +250,13 @@ void WindowServer::set_focused_window(BAN::RefPtr<Window> window)
|
||||||
if (m_focused_window == window)
|
if (m_focused_window == window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (size_t i = m_windows_ordered.size(); i > 0; i--)
|
for (size_t i = m_client_windows.size(); i > 0; i--)
|
||||||
{
|
{
|
||||||
if (m_windows_ordered[i - 1] == window)
|
if (m_client_windows[i - 1] == window)
|
||||||
{
|
{
|
||||||
m_focused_window = window;
|
m_focused_window = window;
|
||||||
m_windows_ordered.remove(i - 1);
|
m_client_windows.remove(i - 1);
|
||||||
MUST(m_windows_ordered.push_back(window));
|
MUST(m_client_windows.push_back(window));
|
||||||
invalidate(window->full_area());
|
invalidate(window->full_area());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -186,9 +271,9 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
area = fb_overlap.release_value();
|
area = fb_overlap.release_value();
|
||||||
|
|
||||||
for (int32_t y = area.y; y < area.y + area.height; y++)
|
for (int32_t y = area.y; y < area.y + area.height; y++)
|
||||||
memset(&m_framebuffer.mmap[y * m_framebuffer.width + area.x], 0, area.width * 4);
|
memset(&m_framebuffer.mmap[y * m_framebuffer.width + area.x], 0x10, area.width * 4);
|
||||||
|
|
||||||
for (auto& pwindow : m_windows_ordered)
|
for (auto& pwindow : m_client_windows)
|
||||||
{
|
{
|
||||||
auto& window = *pwindow;
|
auto& window = *pwindow;
|
||||||
|
|
||||||
|
@ -255,3 +340,65 @@ Rectangle WindowServer::cursor_area() const
|
||||||
{
|
{
|
||||||
return { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height };
|
return { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WindowServer::add_client_fd(int fd)
|
||||||
|
{
|
||||||
|
MUST(m_client_fds.push_back(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowServer::remove_client_fd(int fd)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_client_fds.size(); i++)
|
||||||
|
{
|
||||||
|
if (m_client_fds[i] == fd)
|
||||||
|
{
|
||||||
|
m_client_fds.remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_client_windows.size(); i++)
|
||||||
|
{
|
||||||
|
auto window = m_client_windows[i];
|
||||||
|
if (window->client_fd() == fd)
|
||||||
|
{
|
||||||
|
auto window_area = window->full_area();
|
||||||
|
m_client_windows.remove(i);
|
||||||
|
invalidate(window_area);
|
||||||
|
|
||||||
|
if (window == m_focused_window)
|
||||||
|
{
|
||||||
|
m_focused_window = nullptr;
|
||||||
|
if (!m_client_windows.empty())
|
||||||
|
set_focused_window(m_client_windows.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_deleted_window = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WindowServer::get_client_fds(fd_set& fds) const
|
||||||
|
{
|
||||||
|
int max_fd = 0;
|
||||||
|
for (int fd : m_client_fds)
|
||||||
|
{
|
||||||
|
FD_SET(fd, &fds);
|
||||||
|
max_fd = BAN::Math::max(max_fd, fd);
|
||||||
|
}
|
||||||
|
return max_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowServer::for_each_client_fd(const BAN::Function<BAN::Iteration(int)>& callback)
|
||||||
|
{
|
||||||
|
m_deleted_window = false;
|
||||||
|
for (int fd : m_client_fds)
|
||||||
|
{
|
||||||
|
if (m_deleted_window)
|
||||||
|
break;
|
||||||
|
callback(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,21 +8,25 @@
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <BAN/HashMap.h>
|
#include <BAN/HashMap.h>
|
||||||
|
|
||||||
|
#include <LibFont/Font.h>
|
||||||
|
#include <LibGUI/Window.h>
|
||||||
#include <LibInput/KeyEvent.h>
|
#include <LibInput/KeyEvent.h>
|
||||||
#include <LibInput/MouseEvent.h>
|
#include <LibInput/MouseEvent.h>
|
||||||
|
|
||||||
|
#include <sys/select.h>
|
||||||
|
|
||||||
class WindowServer
|
class WindowServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WindowServer(Framebuffer& framebuffer)
|
WindowServer(Framebuffer& framebuffer)
|
||||||
: m_framebuffer(framebuffer)
|
: m_framebuffer(framebuffer)
|
||||||
, m_cursor({ framebuffer.width / 2, framebuffer.height / 2 })
|
, m_cursor({ framebuffer.width / 2, framebuffer.height / 2 })
|
||||||
|
, m_font(MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"sv)))
|
||||||
{
|
{
|
||||||
invalidate(m_framebuffer.area());
|
invalidate(m_framebuffer.area());
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_window(int fd, BAN::RefPtr<Window> window);
|
void on_window_packet(int fd, LibGUI::WindowPacket);
|
||||||
void for_each_window(const BAN::Function<BAN::Iteration(int, Window&)>& callback);
|
|
||||||
|
|
||||||
void on_key_event(LibInput::KeyEvent event);
|
void on_key_event(LibInput::KeyEvent event);
|
||||||
void on_mouse_button(LibInput::MouseButtonEvent event);
|
void on_mouse_button(LibInput::MouseButtonEvent event);
|
||||||
|
@ -34,13 +38,25 @@ public:
|
||||||
|
|
||||||
Rectangle cursor_area() const;
|
Rectangle cursor_area() const;
|
||||||
|
|
||||||
|
void add_client_fd(int fd);
|
||||||
|
void remove_client_fd(int fd);
|
||||||
|
int get_client_fds(fd_set& fds) const;
|
||||||
|
void for_each_client_fd(const BAN::Function<BAN::Iteration(int)>& callback);
|
||||||
|
|
||||||
|
bool is_stopped() const { return m_is_stopped; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Framebuffer& m_framebuffer;
|
Framebuffer& m_framebuffer;
|
||||||
BAN::Vector<BAN::RefPtr<Window>> m_windows_ordered;
|
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
|
||||||
BAN::HashMap<int, BAN::RefPtr<Window>> m_windows;
|
BAN::Vector<int> m_client_fds;
|
||||||
|
|
||||||
bool m_is_mod_key_held { false };
|
bool m_is_mod_key_held { false };
|
||||||
bool m_is_moving_window { false };
|
bool m_is_moving_window { false };
|
||||||
BAN::RefPtr<Window> m_focused_window;
|
BAN::RefPtr<Window> m_focused_window;
|
||||||
Position m_cursor;
|
Position m_cursor;
|
||||||
|
|
||||||
|
bool m_deleted_window { false };
|
||||||
|
bool m_is_stopped { false };
|
||||||
|
|
||||||
|
LibFont::Font m_font;
|
||||||
};
|
};
|
||||||
|
|
|
@ -85,19 +85,16 @@ int main()
|
||||||
|
|
||||||
dprintln("Window server started");
|
dprintln("Window server started");
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
size_t window_packet_sizes[LibGUI::WindowPacketType::COUNT] {};
|
||||||
{
|
window_packet_sizes[LibGUI::WindowPacketType::INVALID] = 0;
|
||||||
if (fork() == 0)
|
window_packet_sizes[LibGUI::WindowPacketType::CreateWindow] = sizeof(LibGUI::WindowCreatePacket);
|
||||||
{
|
window_packet_sizes[LibGUI::WindowPacketType::Invalidate] = sizeof(LibGUI::WindowInvalidatePacket);
|
||||||
execl("/bin/test-window", "test-window", NULL);
|
static_assert(LibGUI::WindowPacketType::COUNT == 3);
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowServer window_server(framebuffer);
|
WindowServer window_server(framebuffer);
|
||||||
for (;;)
|
while (!window_server.is_stopped())
|
||||||
{
|
{
|
||||||
int max_socket = server_fd;
|
int max_fd = server_fd;
|
||||||
|
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
|
@ -105,23 +102,16 @@ int main()
|
||||||
if (keyboard_fd != -1)
|
if (keyboard_fd != -1)
|
||||||
{
|
{
|
||||||
FD_SET(keyboard_fd, &fds);
|
FD_SET(keyboard_fd, &fds);
|
||||||
max_socket = BAN::Math::max(max_socket, keyboard_fd);
|
max_fd = BAN::Math::max(max_fd, keyboard_fd);
|
||||||
}
|
}
|
||||||
if (mouse_fd != -1)
|
if (mouse_fd != -1)
|
||||||
{
|
{
|
||||||
FD_SET(mouse_fd, &fds);
|
FD_SET(mouse_fd, &fds);
|
||||||
max_socket = BAN::Math::max(max_socket, mouse_fd);
|
max_fd = BAN::Math::max(max_fd, mouse_fd);
|
||||||
}
|
}
|
||||||
window_server.for_each_window(
|
max_fd = BAN::Math::max(max_fd, window_server.get_client_fds(fds));
|
||||||
[&](int fd, Window&) -> BAN::Iteration
|
|
||||||
{
|
|
||||||
FD_SET(fd, &fds);
|
|
||||||
max_socket = BAN::Math::max(max_socket, fd);
|
|
||||||
return BAN::Iteration::Continue;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (select(max_socket + 1, &fds, nullptr, nullptr, nullptr) == -1)
|
if (select(max_fd + 1, &fds, nullptr, nullptr, nullptr) == -1)
|
||||||
{
|
{
|
||||||
dwarnln("select: {}", strerror(errno));
|
dwarnln("select: {}", strerror(errno));
|
||||||
break;
|
break;
|
||||||
|
@ -135,8 +125,7 @@ int main()
|
||||||
dwarnln("accept: {}", strerror(errno));
|
dwarnln("accept: {}", strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto window = MUST(BAN::RefPtr<Window>::create(window_fd));
|
window_server.add_client_fd(window_fd);
|
||||||
window_server.add_window(window_fd, window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyboard_fd != -1 && FD_ISSET(keyboard_fd, &fds))
|
if (keyboard_fd != -1 && FD_ISSET(keyboard_fd, &fds))
|
||||||
|
@ -172,8 +161,8 @@ int main()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window_server.for_each_window(
|
window_server.for_each_client_fd(
|
||||||
[&](int fd, Window& window) -> BAN::Iteration
|
[&](int fd) -> BAN::Iteration
|
||||||
{
|
{
|
||||||
if (!FD_ISSET(fd, &fds))
|
if (!FD_ISSET(fd, &fds))
|
||||||
return BAN::Iteration::Continue;
|
return BAN::Iteration::Continue;
|
||||||
|
@ -184,89 +173,16 @@ int main()
|
||||||
dwarnln("recv: {}", strerror(errno));
|
dwarnln("recv: {}", strerror(errno));
|
||||||
if (nrecv <= 0)
|
if (nrecv <= 0)
|
||||||
{
|
{
|
||||||
window.mark_deleted();
|
window_server.remove_client_fd(fd);
|
||||||
return BAN::Iteration::Continue;
|
return BAN::Iteration::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (packet.type)
|
if (packet.type == LibGUI::WindowPacketType::INVALID || packet.type >= LibGUI::WindowPacketType::COUNT)
|
||||||
{
|
dwarnln("Invalid WindowPacket (type {})", (int)packet.type);
|
||||||
case LibGUI::WindowPacketType::CreateWindow:
|
if (static_cast<size_t>(nrecv) != window_packet_sizes[packet.type])
|
||||||
{
|
dwarnln("Invalid WindowPacket size (type {}, size {})", (int)packet.type, nrecv);
|
||||||
if (nrecv != sizeof(LibGUI::WindowCreatePacket))
|
else
|
||||||
{
|
window_server.on_window_packet(fd, packet);
|
||||||
dwarnln("Invalid WindowCreate packet size");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t window_fb_bytes = packet.create.width * packet.create.height * 4;
|
|
||||||
|
|
||||||
long smo_key = smo_create(window_fb_bytes, PROT_READ | PROT_WRITE);
|
|
||||||
if (smo_key == -1)
|
|
||||||
{
|
|
||||||
dwarnln("smo_create: {}", strerror(errno));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* smo_address = smo_map(smo_key);
|
|
||||||
if (smo_address == nullptr)
|
|
||||||
{
|
|
||||||
dwarnln("smo_map: {}", strerror(errno));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
memset(smo_address, 0, window_fb_bytes);
|
|
||||||
|
|
||||||
LibGUI::WindowCreateResponse response;
|
|
||||||
response.framebuffer_smo_key = smo_key;
|
|
||||||
if (send(fd, &response, sizeof(response), 0) != sizeof(response))
|
|
||||||
{
|
|
||||||
dwarnln("send: {}", strerror(errno));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.set_size({
|
|
||||||
static_cast<int32_t>(packet.create.width),
|
|
||||||
static_cast<int32_t>(packet.create.height)
|
|
||||||
}, reinterpret_cast<uint32_t*>(smo_address));
|
|
||||||
window.set_position({
|
|
||||||
static_cast<int32_t>((framebuffer.width - window.client_width()) / 2),
|
|
||||||
static_cast<int32_t>((framebuffer.height - window.client_height()) / 2)
|
|
||||||
});
|
|
||||||
window_server.invalidate(window.full_area());
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LibGUI::WindowPacketType::Invalidate:
|
|
||||||
{
|
|
||||||
if (nrecv != sizeof(LibGUI::WindowInvalidatePacket))
|
|
||||||
{
|
|
||||||
dwarnln("Invalid Invalidate packet size");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet.invalidate.width == 0 || packet.invalidate.height == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const int32_t br_x = packet.invalidate.x + packet.invalidate.width - 1;
|
|
||||||
const int32_t br_y = packet.invalidate.y + packet.invalidate.height - 1;
|
|
||||||
if (!window.client_size().contains({ br_x, br_y }))
|
|
||||||
{
|
|
||||||
dwarnln("Invalid Invalidate packet parameters");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_server.invalidate({
|
|
||||||
window.client_x() + static_cast<int32_t>(packet.invalidate.x),
|
|
||||||
window.client_y() + static_cast<int32_t>(packet.invalidate.y),
|
|
||||||
static_cast<int32_t>(packet.invalidate.width),
|
|
||||||
static_cast<int32_t>(packet.invalidate.height),
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
dwarnln("Invalid window packet from {}", fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return BAN::Iteration::Continue;
|
return BAN::Iteration::Continue;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,14 +20,17 @@ int main()
|
||||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
srand(ts.tv_nsec);
|
srand(ts.tv_nsec);
|
||||||
|
|
||||||
auto window_or_error = LibGUI::Window::create(300, 200);
|
auto window_or_error = LibGUI::Window::create(300, 200, "test-window");
|
||||||
if (window_or_error.is_error())
|
if (window_or_error.is_error())
|
||||||
{
|
{
|
||||||
dprintln("{}", window_or_error.error());
|
dprintln("{}", window_or_error.error());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
|
||||||
auto window = window_or_error.release_value();
|
auto window = window_or_error.release_value();
|
||||||
|
window->set_close_window_event_callback([&] { running = false; });
|
||||||
window->set_mouse_button_event_callback(
|
window->set_mouse_button_event_callback(
|
||||||
[&](LibGUI::EventPacket::MouseButtonEvent event)
|
[&](LibGUI::EventPacket::MouseButtonEvent event)
|
||||||
{
|
{
|
||||||
|
@ -49,7 +52,7 @@ int main()
|
||||||
|
|
||||||
randomize_color(window);
|
randomize_color(window);
|
||||||
|
|
||||||
for (;;)
|
while (running)
|
||||||
{
|
{
|
||||||
window->poll_events();
|
window->poll_events();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue