Compare commits

...

13 Commits

Author SHA1 Message Date
Bananymous c2b6ba0d5a Userspace: Start work on GUI and WindowServer
Current implementation can create custom windows and each window has
its own framebuffer. When window wants to write its framebuffer to the
screen it will send a message to the WindowServer using unix sockets.
2024-05-29 16:00:54 +03:00
Bananymous d4d530e6c8 Kernel: Implement basic shared memory objects
These can allocate memory that can be shared between processes using
a global key. There is currenly no safety checks meaning anyone can
map any shared memory object just by trying to map every possible key.
2024-05-29 15:58:46 +03:00
Bananymous 99270e96a9 Kernel: Lock debug lock while printing fault details
This allows multiprocessor to dump clean output on concurrent faults
2024-05-29 15:49:24 +03:00
Bananymous 4bf7a08c80 Kernel: Allow SYS_PSELECT to work with timeout of zero 2024-05-29 15:32:18 +03:00
Bananymous 3823de6552 Kernel: Add templated get function for Random 2024-05-29 15:32:00 +03:00
Bananymous 30592b27ce BAN: Add comparison operators for RefPtr 2024-05-29 13:50:03 +03:00
Bananymous 8bc6c2eb20 Kernel: Move KeyEvent/MouseEvent from kernel to LibInput 2024-05-28 23:30:08 +03:00
Bananymous 87d52e5ebe Kernel: Fix timer early wake message
When printing early return message, current time was read twice. This
could lead to early return check failing, but when printing and reading
the time again subtraction overflow would happen.
2024-05-28 16:04:18 +03:00
Bananymous 598a09c13d Kernel: Allow select to work on any type of inode 2024-05-28 16:03:54 +03:00
Bananymous 54db4ab215 BAN: Increase BAN::Function storage size to 8 pointers 2024-05-28 16:01:41 +03:00
Bananymous 5b5ccba247 LibC: Define PATH_MAX in limits.h 2024-05-28 01:08:25 +03:00
Bananymous 18e2559b1e Kernel/LibC: Add SYS_TRUNCATE 2024-05-28 01:08:04 +03:00
Bananymous f5987b68ff BAN: Mark some class methods as constexpr 2024-05-28 01:07:29 +03:00
52 changed files with 1682 additions and 219 deletions

View File

@ -141,7 +141,7 @@ namespace BAN
};
private:
static constexpr size_t m_size = sizeof(void*) * 5;
static constexpr size_t m_size = sizeof(void*) * 8;
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
};

View File

@ -9,7 +9,7 @@ namespace BAN
{
template<typename It>
It next(It it, size_t count)
constexpr It next(It it, size_t count)
{
for (size_t i = 0; i < count; i++)
++it;
@ -18,13 +18,13 @@ namespace BAN
template<typename It>
requires requires(It it, size_t n) { requires is_same_v<decltype(it + n), It>; }
It next(It it, size_t count)
constexpr It next(It it, size_t count)
{
return it + count;
}
template<typename It>
It prev(It it, size_t count)
constexpr It prev(It it, size_t count)
{
for (size_t i = 0; i < count; i++)
--it;
@ -33,13 +33,13 @@ namespace BAN
template<typename It>
requires requires(It it, size_t n) { requires is_same_v<decltype(it - n), It>; }
It prev(It it, size_t count)
constexpr It prev(It it, size_t count)
{
return it - count;
}
template<typename It>
size_t distance(It it1, It it2)
constexpr size_t distance(It it1, It it2)
{
size_t dist = 0;
while (it1 != it2)
@ -52,7 +52,7 @@ namespace BAN
template<typename It>
requires requires(It it1, It it2) { requires is_integral_v<decltype(it2 - it1)>; }
size_t distance(It it1, It it2)
constexpr size_t distance(It it1, It it2)
{
return it2 - it1;
}
@ -64,109 +64,109 @@ namespace BAN
using value_type = T;
public:
IteratorSimpleGeneral() = default;
constexpr IteratorSimpleGeneral() = default;
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
constexpr IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
: m_pointer(other.m_pointer)
, m_valid(other.m_valid)
{
}
const T& operator*() const
constexpr const T& operator*() const
{
ASSERT(m_pointer);
return *m_pointer;
}
template<bool CONST2 = CONST>
enable_if_t<!CONST2, T&> operator*()
constexpr enable_if_t<!CONST2, T&> operator*()
{
ASSERT(*this);
ASSERT(m_pointer);
return *m_pointer;
}
const T* operator->() const
constexpr const T* operator->() const
{
ASSERT(*this);
ASSERT(m_pointer);
return m_pointer;
}
template<bool CONST2 = CONST>
enable_if_t<!CONST2, T*> operator->()
constexpr enable_if_t<!CONST2, T*> operator->()
{
ASSERT(*this);
ASSERT(m_pointer);
return m_pointer;
}
IteratorSimpleGeneral& operator++()
constexpr IteratorSimpleGeneral& operator++()
{
ASSERT(*this);
ASSERT(m_pointer);
++m_pointer;
return *this;
}
IteratorSimpleGeneral operator++(int)
constexpr IteratorSimpleGeneral operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
IteratorSimpleGeneral& operator--()
constexpr IteratorSimpleGeneral& operator--()
{
ASSERT(*this);
ASSERT(m_pointer);
--m_pointer;
return *this;
}
IteratorSimpleGeneral operator--(int)
constexpr IteratorSimpleGeneral operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
size_t operator-(const IteratorSimpleGeneral& other) const
constexpr size_t operator-(const IteratorSimpleGeneral& other) const
{
ASSERT(*this && other);
return m_pointer - other.m_pointer;
}
IteratorSimpleGeneral operator+(size_t offset) const
constexpr IteratorSimpleGeneral operator+(size_t offset) const
{
return IteratorSimpleGeneral(m_pointer + offset);
}
IteratorSimpleGeneral operator-(size_t offset) const
constexpr IteratorSimpleGeneral operator-(size_t offset) const
{
return IteratorSimpleGeneral(m_pointer - offset);
}
bool operator<(const IteratorSimpleGeneral& other) const
constexpr bool operator<(const IteratorSimpleGeneral& other) const
{
ASSERT(*this);
return m_pointer < other.m_pointer;
}
bool operator==(const IteratorSimpleGeneral& other) const
constexpr bool operator==(const IteratorSimpleGeneral& other) const
{
ASSERT(*this);
return m_pointer == other.m_pointer;
}
bool operator!=(const IteratorSimpleGeneral& other) const
constexpr bool operator!=(const IteratorSimpleGeneral& other) const
{
ASSERT(*this);
return !(*this == other);
}
explicit operator bool() const
constexpr explicit operator bool() const
{
return m_valid;
}
private:
IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
constexpr IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
: m_pointer(pointer)
, m_valid(true)
{
@ -193,16 +193,16 @@ namespace BAN
using value_type = T;
public:
IteratorDoubleGeneral() = default;
constexpr IteratorDoubleGeneral() = default;
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
constexpr IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
: m_outer_end(other.m_outer_end)
, m_outer_current(other.m_outer_current)
, m_inner_current(other.m_inner_current)
{
}
const T& operator*() const
constexpr const T& operator*() const
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -210,7 +210,7 @@ namespace BAN
return m_inner_current.operator*();
}
template<bool CONST2 = CONST>
enable_if_t<!CONST2, T&> operator*()
constexpr enable_if_t<!CONST2, T&> operator*()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -218,7 +218,7 @@ namespace BAN
return m_inner_current.operator*();
}
const T* operator->() const
constexpr const T* operator->() const
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -226,7 +226,7 @@ namespace BAN
return m_inner_current.operator->();
}
template<bool CONST2 = CONST>
enable_if_t<!CONST2, T*> operator->()
constexpr enable_if_t<!CONST2, T*> operator->()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -234,7 +234,7 @@ namespace BAN
return m_inner_current.operator->();
}
IteratorDoubleGeneral& operator++()
constexpr IteratorDoubleGeneral& operator++()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -243,14 +243,14 @@ namespace BAN
find_valid_or_end();
return *this;
}
IteratorDoubleGeneral operator++(int)
constexpr IteratorDoubleGeneral operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
bool operator==(const IteratorDoubleGeneral& other) const
constexpr bool operator==(const IteratorDoubleGeneral& other) const
{
ASSERT(*this && other);
if (m_outer_end != other.m_outer_end)
@ -262,18 +262,18 @@ namespace BAN
ASSERT(m_inner_current && other.m_inner_current);
return m_inner_current == other.m_inner_current;
}
bool operator!=(const IteratorDoubleGeneral& other) const
constexpr bool operator!=(const IteratorDoubleGeneral& other) const
{
return !(*this == other);
}
explicit operator bool() const
constexpr explicit operator bool() const
{
return !!m_outer_current;
}
private:
IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
: m_outer_end(outer_end)
, m_outer_current(outer_current)
{
@ -284,7 +284,7 @@ namespace BAN
}
}
IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current, const InnerIterator& inner_current)
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current, const InnerIterator& inner_current)
: m_outer_end(outer_end)
, m_outer_current(outer_current)
, m_inner_current(inner_current)
@ -292,7 +292,7 @@ namespace BAN
find_valid_or_end();
}
void find_valid_or_end()
constexpr void find_valid_or_end()
{
while (m_inner_current == m_outer_current->end())
{
@ -303,8 +303,8 @@ namespace BAN
}
}
OuterIterator outer_current() { return m_outer_current; }
InnerIterator inner_current() { return m_inner_current; }
constexpr OuterIterator outer_current() { return m_outer_current; }
constexpr InnerIterator inner_current() { return m_inner_current; }
private:
OuterIterator m_outer_end;

View File

@ -13,35 +13,35 @@ namespace BAN
class Optional
{
public:
Optional();
Optional(Optional&&);
Optional(const Optional&);
Optional(const T&);
Optional(T&&);
constexpr Optional();
constexpr Optional(Optional&&);
constexpr Optional(const Optional&);
constexpr Optional(const T&);
constexpr Optional(T&&);
template<typename... Args>
Optional(Args&&...);
constexpr Optional(Args&&...);
~Optional();
Optional& operator=(Optional&&);
Optional& operator=(const Optional&);
constexpr Optional& operator=(Optional&&);
constexpr Optional& operator=(const Optional&);
template<typename... Args>
Optional& emplace(Args&&...);
constexpr Optional& emplace(Args&&...);
T* operator->();
const T* operator->() const;
constexpr T* operator->();
constexpr const T* operator->() const;
T& operator*();
const T& operator*() const;
constexpr T& operator*();
constexpr const T& operator*() const;
bool has_value() const;
constexpr bool has_value() const;
T release_value();
T& value();
const T& value() const;
constexpr T release_value();
constexpr T& value();
constexpr const T& value() const;
void clear();
constexpr void clear();
private:
alignas(T) uint8_t m_storage[sizeof(T)];
@ -49,12 +49,12 @@ namespace BAN
};
template<typename T>
Optional<T>::Optional()
constexpr Optional<T>::Optional()
: m_has_value(false)
{}
template<typename T>
Optional<T>::Optional(Optional<T>&& other)
constexpr Optional<T>::Optional(Optional<T>&& other)
: m_has_value(other.has_value())
{
if (other.has_value())
@ -62,7 +62,7 @@ namespace BAN
}
template<typename T>
Optional<T>::Optional(const Optional<T>& other)
constexpr Optional<T>::Optional(const Optional<T>& other)
: m_has_value(other.has_value())
{
if (other.has_value())
@ -70,14 +70,14 @@ namespace BAN
}
template<typename T>
Optional<T>::Optional(const T& value)
constexpr Optional<T>::Optional(const T& value)
: m_has_value(true)
{
new (m_storage) T(value);
}
template<typename T>
Optional<T>::Optional(T&& value)
constexpr Optional<T>::Optional(T&& value)
: m_has_value(true)
{
new (m_storage) T(move(value));
@ -85,7 +85,7 @@ namespace BAN
template<typename T>
template<typename... Args>
Optional<T>::Optional(Args&&... args)
constexpr Optional<T>::Optional(Args&&... args)
: m_has_value(true)
{
new (m_storage) T(forward<Args>(args)...);
@ -98,7 +98,7 @@ namespace BAN
}
template<typename T>
Optional<T>& Optional<T>::operator=(Optional&& other)
constexpr Optional<T>& Optional<T>::operator=(Optional&& other)
{
clear();
m_has_value = other.has_value();
@ -108,7 +108,7 @@ namespace BAN
}
template<typename T>
Optional<T>& Optional<T>::operator=(const Optional& other)
constexpr Optional<T>& Optional<T>::operator=(const Optional& other)
{
clear();
m_has_value = other.has_value();
@ -119,7 +119,7 @@ namespace BAN
template<typename T>
template<typename... Args>
Optional<T>& Optional<T>::emplace(Args&&... args)
constexpr Optional<T>& Optional<T>::emplace(Args&&... args)
{
clear();
m_has_value = true;
@ -128,41 +128,41 @@ namespace BAN
}
template<typename T>
T* Optional<T>::operator->()
constexpr T* Optional<T>::operator->()
{
ASSERT(has_value());
return &value();
}
template<typename T>
const T* Optional<T>::operator->() const
constexpr const T* Optional<T>::operator->() const
{
ASSERT(has_value());
return &value();
}
template<typename T>
T& Optional<T>::operator*()
constexpr T& Optional<T>::operator*()
{
ASSERT(has_value());
return value();
}
template<typename T>
const T& Optional<T>::operator*() const
constexpr const T& Optional<T>::operator*() const
{
ASSERT(has_value());
return value();
}
template<typename T>
bool Optional<T>::has_value() const
constexpr bool Optional<T>::has_value() const
{
return m_has_value;
}
template<typename T>
T Optional<T>::release_value()
constexpr T Optional<T>::release_value()
{
ASSERT(has_value());
T released_value = move(value());
@ -172,21 +172,21 @@ namespace BAN
}
template<typename T>
T& Optional<T>::value()
constexpr T& Optional<T>::value()
{
ASSERT(has_value());
return (T&)m_storage;
}
template<typename T>
const T& Optional<T>::value() const
constexpr const T& Optional<T>::value() const
{
ASSERT(has_value());
return (const T&)m_storage;
}
template<typename T>
void Optional<T>::clear()
constexpr void Optional<T>::clear()
{
if (m_has_value)
value().~T();

View File

@ -124,6 +124,9 @@ namespace BAN
T* operator->() { return ptr(); }
const T* operator->() const { return ptr(); }
bool operator==(RefPtr other) const { return m_pointer == other.m_pointer; }
bool operator!=(RefPtr other) const { return m_pointer != other.m_pointer; }
bool empty() const { return m_pointer == nullptr; }
operator bool() const { return m_pointer; }

View File

@ -16,40 +16,44 @@ namespace BAN
using const_iterator = ConstIteratorSimple<char, StringView>;
public:
StringView() {}
StringView(const String&);
StringView(const char* string, size_type len = -1)
constexpr StringView() {}
constexpr StringView(const char* string, size_type len = -1)
{
if (len == size_type(-1))
len = strlen(string);
m_data = string;
m_size = len;
}
StringView(const String&);
const_iterator begin() const { return const_iterator(m_data); }
const_iterator end() const { return const_iterator(m_data + m_size); }
constexpr const_iterator begin() const { return const_iterator(m_data); }
constexpr const_iterator end() const { return const_iterator(m_data + m_size); }
char operator[](size_type index) const
constexpr char operator[](size_type index) const
{
ASSERT(index < m_size);
return m_data[index];
}
bool operator==(StringView other) const
constexpr bool operator==(StringView other) const
{
if (m_size != other.m_size)
return false;
return memcmp(m_data, other.m_data, m_size) == 0;
for (size_type i = 0; i < m_size; i++)
if (m_data[i] != other.m_data[i])
return false;
return true;
}
bool operator==(const char* other) const
constexpr bool operator==(const char* other) const
{
if (memcmp(m_data, other, m_size))
return false;
for (size_type i = 0; i < m_size; i++)
if (m_data[i] != other[i])
return false;
return other[m_size] == '\0';
}
StringView substring(size_type index, size_type len = -1) const
constexpr StringView substring(size_type index, size_type len = -1) const
{
ASSERT(index <= m_size);
if (len == size_type(-1))
@ -133,13 +137,13 @@ namespace BAN
return result;
}
char back() const
constexpr char back() const
{
ASSERT(m_size > 0);
return m_data[m_size - 1];
}
char front() const
constexpr char front() const
{
ASSERT(m_size > 0);
return m_data[0];
@ -161,7 +165,7 @@ namespace BAN
return {};
}
bool contains(char ch) const
constexpr bool contains(char ch) const
{
for (size_type i = 0; i < m_size; i++)
if (m_data[i] == ch)
@ -169,7 +173,7 @@ namespace BAN
return false;
}
size_type count(char ch) const
constexpr size_type count(char ch) const
{
size_type result = 0;
for (size_type i = 0; i < m_size; i++)
@ -178,9 +182,9 @@ namespace BAN
return result;
}
bool empty() const { return m_size == 0; }
size_type size() const { return m_size; }
const char* data() const { return m_data; }
constexpr bool empty() const { return m_size == 0; }
constexpr size_type size() const { return m_size; }
constexpr const char* data() const { return m_data; }
private:
const char* m_data = nullptr;
@ -189,7 +193,7 @@ namespace BAN
}
inline BAN::StringView operator""sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
inline constexpr BAN::StringView operator""sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
namespace BAN::Formatter
{

View File

@ -21,6 +21,8 @@ add_subdirectory(bootloader)
add_subdirectory(BAN)
add_subdirectory(libc)
add_subdirectory(LibELF)
add_subdirectory(LibGUI)
add_subdirectory(LibInput)
add_subdirectory(userspace)
add_custom_target(sysroot
@ -33,6 +35,8 @@ add_custom_target(headers
DEPENDS ban-headers
DEPENDS libc-headers
DEPENDS libelf-headers
DEPENDS libgui-headers
DEPENDS libinput-headers
)
add_custom_target(install-sysroot
@ -41,6 +45,8 @@ add_custom_target(install-sysroot
DEPENDS libc-install
DEPENDS userspace-install
DEPENDS libelf-install
DEPENDS libgui-install
DEPENDS libinput-install
)
add_custom_target(package-sysroot

24
LibGUI/CMakeLists.txt Normal file
View File

@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.26)
project(libgui CXX)
set(LIBGUI_SOURCES
Window.cpp
)
add_custom_target(libgui-headers
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
DEPENDS sysroot
)
add_library(libgui ${LIBGUI_SOURCES})
add_dependencies(libgui headers libc-install)
target_link_libraries(libgui PUBLIC libc)
add_custom_target(libgui-install
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libgui.a ${BANAN_LIB}/
DEPENDS libgui
BYPRODUCTS ${BANAN_LIB}/libgui.a
)
set(CMAKE_STATIC_LIBRARY_PREFIX "")

115
LibGUI/Window.cpp Normal file
View File

@ -0,0 +1,115 @@
#include "LibGUI/Window.h"
#include <fcntl.h>
#include <sys/banan-os.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
namespace LibGUI
{
Window::~Window()
{
munmap(m_framebuffer, m_width * m_height * 4);
close(m_server_fd);
}
BAN::ErrorOr<BAN::UniqPtr<Window>> Window::create(uint32_t width, uint32_t height)
{
int server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (server_fd == -1)
return BAN::Error::from_errno(errno);
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)) == -1)
{
close(server_fd);
return BAN::Error::from_errno(errno);
}
WindowCreatePacket packet;
packet.width = width;
packet.height = height;
if (send(server_fd, &packet, sizeof(packet), 0) != sizeof(packet))
{
close(server_fd);
return BAN::Error::from_errno(errno);
}
WindowCreateResponse response;
if (recv(server_fd, &response, sizeof(response), 0) != sizeof(response))
{
close(server_fd);
return BAN::Error::from_errno(errno);
}
void* framebuffer_addr = smo_map(response.framebuffer_smo_key);
if (framebuffer_addr == nullptr)
{
close(server_fd);
return BAN::Error::from_errno(errno);
}
return TRY(BAN::UniqPtr<Window>::create(
server_fd,
static_cast<uint32_t*>(framebuffer_addr),
width,
height
));
}
bool Window::invalidate()
{
WindowInvalidatePacket packet;
packet.x = 0;
packet.y = 0;
packet.width = m_width;
packet.height = m_height;
return send(m_server_fd, &packet, sizeof(packet), 0) == sizeof(packet);
}
void Window::poll_events()
{
for (;;)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_server_fd, &fds);
timeval timeout { .tv_sec = 0, .tv_usec = 0 };
select(m_server_fd + 1, &fds, nullptr, nullptr, &timeout);
if (!FD_ISSET(m_server_fd, &fds))
break;
EventPacket packet;
if (recv(m_server_fd, &packet, sizeof(packet), 0) <= 0)
break;
switch (packet.type)
{
case EventPacket::Type::KeyEvent:
if (m_key_event_callback)
m_key_event_callback(packet.key_event);
break;
case EventPacket::Type::MouseButtonEvent:
if (m_mouse_button_event_callback)
m_mouse_button_event_callback(packet.mouse_button_event);
break;
case EventPacket::Type::MouseMoveEvent:
if (m_mouse_move_event_callback)
m_mouse_move_event_callback(packet.mouse_move_event);
break;
case EventPacket::Type::MouseScrollEvent:
if (m_mouse_scroll_event_callback)
m_mouse_scroll_event_callback(packet.mouse_scroll_event);
break;
}
}
}
}

View File

@ -0,0 +1,142 @@
#pragma once
#include <BAN/Function.h>
#include <BAN/StringView.h>
#include <BAN/UniqPtr.h>
#include <LibInput/KeyEvent.h>
#include <LibInput/MouseEvent.h>
#include <limits.h>
#include <stdint.h>
namespace LibGUI
{
static constexpr BAN::StringView s_window_server_socket = "/tmp/window-server.socket"sv;
enum WindowPacketType : uint8_t
{
INVALID,
CreateWindow,
Invalidate,
};
struct WindowCreatePacket
{
WindowPacketType type = WindowPacketType::CreateWindow;
uint32_t width;
uint32_t height;
};
struct WindowInvalidatePacket
{
WindowPacketType type = WindowPacketType::Invalidate;
uint32_t x;
uint32_t y;
uint32_t width;
uint32_t height;
};
struct WindowCreateResponse
{
long framebuffer_smo_key;
};
struct WindowPacket
{
WindowPacket()
: type(WindowPacketType::INVALID)
{ }
union
{
WindowPacketType type;
WindowCreatePacket create;
WindowInvalidatePacket invalidate;
};
};
struct EventPacket
{
enum class Type : uint8_t
{
KeyEvent,
MouseButtonEvent,
MouseMoveEvent,
MouseScrollEvent,
};
using KeyEvent = LibInput::KeyEvent;
using MouseButton = LibInput::MouseButton;
struct MouseButtonEvent
{
MouseButton button;
bool pressed;
int32_t x;
int32_t y;
};
struct MouseMoveEvent
{
int32_t x;
int32_t y;
};
using MouseScrollEvent = LibInput::MouseScrollEvent;
Type type;
union
{
KeyEvent key_event;
MouseButtonEvent mouse_button_event;
MouseMoveEvent mouse_move_event;
MouseScrollEvent mouse_scroll_event;
};
};
class Window
{
public:
~Window();
static BAN::ErrorOr<BAN::UniqPtr<Window>> create(uint32_t width, uint32_t height);
void set_pixel(uint32_t x, uint32_t y, uint32_t color)
{
ASSERT(x < m_width);
ASSERT(y < m_height);
m_framebuffer[y * m_width + x] = color;
}
bool invalidate();
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
void poll_events();
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_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; }
private:
Window(int server_fd, uint32_t* framebuffer, uint32_t width, uint32_t height)
: m_server_fd(server_fd)
, m_framebuffer(framebuffer)
, m_width(width)
, m_height(height)
{ }
private:
int m_server_fd;
uint32_t* m_framebuffer;
uint32_t m_width;
uint32_t m_height;
BAN::Function<void(EventPacket::KeyEvent)> m_key_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::MouseScrollEvent)> m_mouse_scroll_event_callback;
friend class BAN::UniqPtr<Window>;
};
}

24
LibInput/CMakeLists.txt Normal file
View File

@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.26)
project(libinput CXX)
set(LIBINPUT_SOURCES
KeyEvent.cpp
KeyboardLayout.cpp
)
add_custom_target(libinput-headers
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
DEPENDS sysroot
)
add_library(libinput ${LIBINPUT_SOURCES})
target_link_libraries(libinput PUBLIC libc ban)
add_custom_target(libinput-install
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libinput.a ${BANAN_LIB}/
DEPENDS libinput
BYPRODUCTS ${BANAN_LIB}/libinput.a
)
set(CMAKE_STATIC_LIBRARY_PREFIX "")

View File

@ -1,15 +1,9 @@
#include <BAN/Array.h>
#include <kernel/Input/KeyboardLayout.h>
#include <kernel/Input/KeyEvent.h>
#include <LibInput/KeyEvent.h>
namespace Kernel::Input
namespace LibInput
{
Key key_event_to_key(KeyEvent event)
{
return KeyboardLayout::get().get_key_from_event(event);
}
const char* key_to_utf8(Key key, uint16_t modifier)
{
static constexpr const char* utf8_lower[] = {
@ -50,7 +44,7 @@ namespace Kernel::Input
};
static_assert((size_t)Key::Count == sizeof(utf8_upper) / sizeof(*utf8_lower));
KeyEvent event { .modifier = modifier, .keycode = 0x00 };
KeyEvent event { .modifier = modifier, .key = key };
return (event.shift() ^ event.caps_lock()) ? utf8_upper[static_cast<uint8_t>(key)] : utf8_lower[static_cast<uint8_t>(key)];
}

View File

@ -1,10 +1,20 @@
#include <BAN/Debug.h>
#include <BAN/HashMap.h>
#include <BAN/String.h>
#include <BAN/StringView.h>
#include <LibInput/KeyboardLayout.h>
#if __is_kernel
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Input/KeyboardLayout.h>
#else
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#endif
#include <ctype.h>
namespace Kernel::Input
namespace LibInput
{
struct StringViewLower
@ -71,14 +81,17 @@ namespace Kernel::Input
key = Key::None;
}
Key KeyboardLayout::get_key_from_event(KeyEvent event)
KeyEvent KeyboardLayout::key_event_from_raw(RawKeyEvent event)
{
SpinLockGuard _(m_lock);
if (event.shift())
return m_keycode_to_key_shift[event.keycode];
if (event.ralt())
return m_keycode_to_key_altgr[event.keycode];
return m_keycode_to_key_normal[event.keycode];
KeyEvent result;
result.modifier = event.modifier;
if (result.shift())
result.key = m_keycode_to_key_shift[event.keycode];
else if (result.ralt())
result.key = m_keycode_to_key_altgr[event.keycode];
else
result.key = m_keycode_to_key_normal[event.keycode];
return result;
}
static BAN::Optional<uint8_t> parse_keycode(BAN::StringView str)
@ -109,11 +122,36 @@ namespace Kernel::Input
static BAN::ErrorOr<BAN::Vector<BAN::String>> load_keymap_lines_and_parse_includes(BAN::StringView path)
{
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, 0));
BAN::String file_data;
TRY(file_data.resize(file.inode->size()));
TRY(file.inode->read(0, BAN::ByteSpan { reinterpret_cast<uint8_t*>(file_data.data()), file_data.size() }));
BAN::String canonical_path;
#if __is_kernel
{
auto file = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, 0));
TRY(file_data.resize(file.inode->size()));
TRY(file.inode->read(0, BAN::ByteSpan { reinterpret_cast<uint8_t*>(file_data.data()), file_data.size() }));
canonical_path = file.canonical_path;
}
#else
{
char null_path[PATH_MAX];
strncpy(null_path, path.data(), path.size());
null_path[path.size()] = '\0';
struct stat st;
if (stat(null_path, &st) == -1)
return BAN::Error::from_errno(errno);
TRY(file_data.resize(st.st_size));
int fd = open(null_path, O_RDONLY);
if (fd == -1)
return BAN::Error::from_errno(errno);
ssize_t nread = read(fd, file_data.data(), st.st_size);
close(fd);
if (nread != st.st_size)
return BAN::Error::from_errno(errno);
MUST(canonical_path.append(path));
}
#endif
BAN::Vector<BAN::String> result;
@ -142,7 +180,7 @@ namespace Kernel::Input
parts[1] = parts[1].substring(1, parts[1].size() - 2);
BAN::String include_path;
TRY(include_path.append(file.canonical_path));
TRY(include_path.append(canonical_path));
ASSERT(include_path.sv().contains('/'));
while (include_path.back() != '/')
include_path.pop_back();
@ -256,8 +294,6 @@ namespace Kernel::Input
}
}
SpinLockGuard _(m_lock);
for (size_t i = 0; i < new_layout->m_keycode_to_key_normal.size(); i++)
if (new_layout->m_keycode_to_key_normal[i] != Key::None)
m_keycode_to_key_normal[i] = new_layout->m_keycode_to_key_normal[i];

View File

@ -2,7 +2,7 @@
#include <stdint.h>
namespace Kernel::Input
namespace LibInput
{
/*
@ -53,6 +53,14 @@ namespace Kernel::Input
Count,
};
// KeyEvent with general keycode
struct RawKeyEvent
{
uint16_t modifier;
uint8_t keycode;
};
// KeyEvent with key parsed from keycode
struct KeyEvent
{
enum Modifier : uint16_t
@ -89,10 +97,9 @@ namespace Kernel::Input
bool released() const { return !pressed(); }
uint16_t modifier;
uint8_t keycode;
Key key;
};
Key key_event_to_key(KeyEvent);
const char* key_to_utf8(Key key, uint16_t modifier);
}

View File

@ -1,11 +1,11 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/StringView.h>
#include <BAN/UniqPtr.h>
#include <kernel/Input/KeyEvent.h>
#include <kernel/Lock/SpinLock.h>
#include <LibInput/KeyEvent.h>
namespace Kernel::Input
namespace LibInput
{
class KeyboardLayout
@ -14,7 +14,7 @@ namespace Kernel::Input
static BAN::ErrorOr<void> initialize();
static KeyboardLayout& get();
Key get_key_from_event(KeyEvent);
KeyEvent key_event_from_raw(RawKeyEvent);
BAN::ErrorOr<void> load_from_file(BAN::StringView path);
private:
@ -24,8 +24,6 @@ namespace Kernel::Input
BAN::Array<Key, 0xFF> m_keycode_to_key_normal;
BAN::Array<Key, 0xFF> m_keycode_to_key_shift;
BAN::Array<Key, 0xFF> m_keycode_to_key_altgr;
SpinLock m_lock;
friend class BAN::UniqPtr<KeyboardLayout>;
};

View File

@ -2,7 +2,7 @@
#include <stdint.h>
namespace Kernel::Input
namespace LibInput
{
enum class MouseButton

View File

@ -42,8 +42,6 @@ set(KERNEL_SOURCES
kernel/FS/VirtualFileSystem.cpp
kernel/GDT.cpp
kernel/IDT.cpp
kernel/Input/KeyboardLayout.cpp
kernel/Input/KeyEvent.cpp
kernel/Input/PS2/Controller.cpp
kernel/Input/PS2/Device.cpp
kernel/Input/PS2/Keyboard.cpp
@ -59,6 +57,7 @@ set(KERNEL_SOURCES
kernel/Memory/MemoryBackedRegion.cpp
kernel/Memory/MemoryRegion.cpp
kernel/Memory/PhysicalRange.cpp
kernel/Memory/SharedMemoryObject.cpp
kernel/Memory/VirtualRange.cpp
kernel/Networking/ARPTable.cpp
kernel/Networking/E1000/E1000.cpp
@ -150,12 +149,18 @@ set(LIBELF_SOURCES
../LibELF/LibELF/LoadableELF.cpp
)
set(LIBINPUT_SOURCE
../LibInput/KeyboardLayout.cpp
../LibInput/KeyEvent.cpp
)
set(KERNEL_SOURCES
${KERNEL_SOURCES}
${LAI_SOURCES}
${BAN_SOURCES}
${KLIBC_SOURCES}
${LIBELF_SOURCES}
${LIBINPUT_SOURCE}
)
add_executable(kernel ${KERNEL_SOURCES})

View File

@ -2,10 +2,10 @@
#include <BAN/Array.h>
#include <BAN/CircularQueue.h>
#include <kernel/Input/KeyEvent.h>
#include <kernel/Input/PS2/Device.h>
#include <kernel/Input/PS2/Keymap.h>
#include <kernel/Semaphore.h>
#include <LibInput/KeyEvent.h>
namespace Kernel::Input
{
@ -40,7 +40,7 @@ namespace Kernel::Input
uint16_t m_modifiers { 0 };
BAN::CircularQueue<KeyEvent, 50> m_event_queue;
BAN::CircularQueue<LibInput::RawKeyEvent, 50> m_event_queue;
SpinLock m_event_lock;
PS2Keymap m_keymap;

View File

@ -1,8 +1,8 @@
#pragma once
#include <kernel/Input/MouseEvent.h>
#include <kernel/Input/PS2/Device.h>
#include <kernel/Semaphore.h>
#include <LibInput/MouseEvent.h>
namespace Kernel::Input
{
@ -36,7 +36,7 @@ namespace Kernel::Input
uint8_t m_mouse_id { 0x00 };
uint8_t m_button_mask { 0x00 };
BAN::CircularQueue<MouseEvent, 128> m_event_queue;
BAN::CircularQueue<LibInput::MouseEvent, 128> m_event_queue;
SpinLock m_event_lock;
Semaphore m_semaphore;

View File

@ -0,0 +1,72 @@
#pragma once
#include <BAN/HashMap.h>
#include <BAN/UniqPtr.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Memory/MemoryRegion.h>
namespace Kernel
{
class SharedMemoryObject;
class SharedMemoryObjectManager
{
public:
using Key = uint32_t;
public:
static BAN::ErrorOr<void> initialize();
static SharedMemoryObjectManager& get();
BAN::ErrorOr<Key> create_object(size_t size, PageTable::flags_t);
BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> map_object(Key, PageTable&, AddressRange);
private:
SharedMemoryObjectManager() {}
private:
struct Object : public BAN::RefCounted<Object>
{
size_t size;
PageTable::flags_t flags;
BAN::Vector<paddr_t> paddrs;
SpinLock spin_lock;
};
private:
Mutex m_mutex;
BAN::HashMap<Key, BAN::RefPtr<Object>> m_objects;
friend class SharedMemoryObject;
friend class BAN::UniqPtr<SharedMemoryObjectManager>;
};
class SharedMemoryObject : public MemoryRegion
{
BAN_NON_COPYABLE(SharedMemoryObject);
BAN_NON_MOVABLE(SharedMemoryObject);
public:
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<void> msync(vaddr_t, size_t, int) override { return {}; }
protected:
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr) override;
private:
SharedMemoryObject(BAN::RefPtr<SharedMemoryObjectManager::Object> object, PageTable& page_table)
: MemoryRegion(page_table, object->size, MemoryRegion::Type::SHARED, object->flags)
, m_object(object)
{ }
private:
BAN::RefPtr<SharedMemoryObjectManager::Object> m_object;
friend class BAN::UniqPtr<SharedMemoryObject>;
};
}

View File

@ -36,6 +36,8 @@ namespace Kernel
BAN::ErrorOr<off_t> seek(int fd, off_t offset, int whence);
BAN::ErrorOr<off_t> tell(int) const;
BAN::ErrorOr<void> truncate(int fd, off_t length);
BAN::ErrorOr<void> fstat(int fd, struct stat*) const;
BAN::ErrorOr<void> fstatat(int fd, BAN::StringView path, struct stat* buf, int flag);
BAN::ErrorOr<void> stat(BAN::StringView absolute_path, struct stat* buf, int flag);

View File

@ -10,6 +10,7 @@
#include <kernel/Lock/Mutex.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/MemoryRegion.h>
#include <kernel/Memory/SharedMemoryObject.h>
#include <kernel/OpenFileDescriptorSet.h>
#include <kernel/Terminal/TTY.h>
#include <kernel/Thread.h>
@ -138,6 +139,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_seek(int fd, off_t offset, int whence);
BAN::ErrorOr<long> sys_tell(int fd);
BAN::ErrorOr<long> sys_truncate(int fd, off_t length);
BAN::ErrorOr<long> sys_fstat(int fd, struct stat*);
BAN::ErrorOr<long> sys_fstatat(int fd, const char* path, struct stat* buf, int flag);
BAN::ErrorOr<long> sys_stat(const char* path, struct stat* buf, int flag);
@ -155,6 +158,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
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_map(SharedMemoryObjectManager::Key);
BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags);
BAN::ErrorOr<long> sys_signal(int, void (*)(int));

View File

@ -11,6 +11,14 @@ namespace Kernel
static void initialize();
static uint32_t get_u32();
static uint64_t get_u64();
template<typename T>
static T get();
};
template<>
inline uint32_t Random::get<uint32_t>() { return Random::get_u32(); }
template<>
inline uint64_t Random::get<uint64_t>() { return Random::get_u64(); }
}

View File

@ -2,11 +2,11 @@
#include <BAN/Array.h>
#include <kernel/Device/Device.h>
#include <kernel/Input/KeyEvent.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Terminal/TerminalDriver.h>
#include <kernel/Terminal/termios.h>
#include <kernel/Semaphore.h>
#include <LibInput/KeyEvent.h>
namespace Kernel
{
@ -30,7 +30,7 @@ namespace Kernel
void set_as_current();
static void initialize_devices();
void on_key_event(Input::KeyEvent);
void on_key_event(LibInput::KeyEvent);
void handle_input_byte(uint8_t);
virtual bool is_tty() const override { return true; }

View File

@ -2,7 +2,6 @@
#include <BAN/Array.h>
#include <kernel/Device/Device.h>
#include <kernel/Input/KeyEvent.h>
#include <kernel/Terminal/TerminalDriver.h>
#include <kernel/Terminal/termios.h>
#include <kernel/Terminal/TTY.h>

View File

@ -245,6 +245,8 @@ namespace Kernel
#endif
}
Debug::s_debug_lock.lock();
if (PageTable::current().get_page_flags(interrupt_stack->ip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
{
auto* machine_code = (const uint8_t*)interrupt_stack->ip;
@ -293,6 +295,8 @@ namespace Kernel
PageTable::current().debug_dump();
Debug::dump_stack_trace();
Debug::s_debug_lock.unlock(InterruptState::Disabled);
if (tid && Thread::current().is_userspace())
{
// TODO: Confirm and fix the exception to signal mappings

View File

@ -1,9 +1,9 @@
#include <BAN/ScopeGuard.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/KeyboardLayout.h>
#include <kernel/Input/PS2/Config.h>
#include <kernel/Input/PS2/Keyboard.h>
#include <kernel/Thread.h>
#include <LibInput/KeyboardLayout.h>
namespace Kernel::Input
{
@ -44,6 +44,10 @@ namespace Kernel::Input
void PS2Keyboard::handle_byte(uint8_t byte)
{
using LibInput::Key;
using LibInput::RawKeyEvent;
using KeyModifier = LibInput::KeyEvent::Modifier;
if (byte == PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN1 || byte == PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN2)
{
dwarnln("Key detection error or internal buffer overrun");
@ -123,25 +127,24 @@ namespace Kernel::Input
if (!keycode.has_value())
return;
auto key = KeyboardLayout::get().get_key_from_event(KeyEvent { .modifier = 0, .keycode = keycode.value() });
if (key == Key::F1)
auto dummy_event = LibInput::KeyboardLayout::get().key_event_from_raw(RawKeyEvent { .modifier = 0, .keycode = keycode.value() });
if (dummy_event.key == Key::F1)
panic("OOF");
uint16_t modifier_mask = 0;
uint16_t toggle_mask = 0;
switch (key)
switch (dummy_event.key)
{
case Key::LeftShift: modifier_mask = KeyEvent::Modifier::LShift; break;
case Key::RightShift: modifier_mask = KeyEvent::Modifier::RShift; break;
case Key::LeftCtrl: modifier_mask = KeyEvent::Modifier::LCtrl; break;
case Key::RightCtrl: modifier_mask = KeyEvent::Modifier::RCtrl; break;
case Key::LeftAlt: modifier_mask = KeyEvent::Modifier::LAlt; break;
case Key::RightAlt: modifier_mask = KeyEvent::Modifier::RAlt; break;
case Key::LeftShift: modifier_mask = KeyModifier::LShift; break;
case Key::RightShift: modifier_mask = KeyModifier::RShift; break;
case Key::LeftCtrl: modifier_mask = KeyModifier::LCtrl; break;
case Key::RightCtrl: modifier_mask = KeyModifier::RCtrl; break;
case Key::LeftAlt: modifier_mask = KeyModifier::LAlt; break;
case Key::RightAlt: modifier_mask = KeyModifier::RAlt; break;
case Key::ScrollLock: toggle_mask = KeyEvent::Modifier::ScrollLock; break;
case Key::NumLock: toggle_mask = KeyEvent::Modifier::NumLock; break;
case Key::CapsLock: toggle_mask = KeyEvent::Modifier::CapsLock; break;
case Key::ScrollLock: toggle_mask = KeyModifier::ScrollLock; break;
case Key::NumLock: toggle_mask = KeyModifier::NumLock; break;
case Key::CapsLock: toggle_mask = KeyModifier::CapsLock; break;
default: break;
}
@ -160,8 +163,8 @@ namespace Kernel::Input
update_leds();
}
KeyEvent event;
event.modifier = m_modifiers | (released ? 0 : KeyEvent::Modifier::Pressed);
RawKeyEvent event;
event.modifier = m_modifiers | (released ? 0 : KeyModifier::Pressed);
event.keycode = keycode.value();
SpinLockGuard _(m_event_lock);
@ -178,19 +181,23 @@ namespace Kernel::Input
void PS2Keyboard::update_leds()
{
using KeyModifier = LibInput::KeyEvent::Modifier;
uint8_t new_leds = 0;
if (m_modifiers & +KeyEvent::Modifier::ScrollLock)
if (m_modifiers & +KeyModifier::ScrollLock)
new_leds |= PS2::KBLeds::SCROLL_LOCK;
if (m_modifiers & +KeyEvent::Modifier::NumLock)
if (m_modifiers & +KeyModifier::NumLock)
new_leds |= PS2::KBLeds::NUM_LOCK;
if (m_modifiers & +KeyEvent::Modifier::CapsLock)
if (m_modifiers & +KeyModifier::CapsLock)
new_leds |= PS2::KBLeds::CAPS_LOCK;
append_command_queue(Command::SET_LEDS, new_leds, 0);
}
BAN::ErrorOr<size_t> PS2Keyboard::read_impl(off_t, BAN::ByteSpan buffer)
{
if (buffer.size() < sizeof(KeyEvent))
using LibInput::RawKeyEvent;
if (buffer.size() < sizeof(RawKeyEvent))
return BAN::Error::from_errno(ENOBUFS);
auto state = m_event_lock.lock();
@ -201,12 +208,12 @@ namespace Kernel::Input
state = m_event_lock.lock();
}
buffer.as<KeyEvent>() = m_event_queue.front();
buffer.as<RawKeyEvent>() = m_event_queue.front();
m_event_queue.pop();
m_event_lock.unlock(state);
return sizeof(KeyEvent);
return sizeof(RawKeyEvent);
}
}

View File

@ -1,11 +1,14 @@
#include <kernel/Debug.h>
#include <kernel/Input/KeyEvent.h>
#include <kernel/Input/PS2/Keymap.h>
#include <LibInput/KeyEvent.h>
#include <string.h>
namespace Kernel::Input
{
using LibInput::keycode_function;
using LibInput::keycode_normal;
using LibInput::keycode_numpad;
void PS2Keymap::initialize(uint8_t scancode_set)
{

View File

@ -71,6 +71,10 @@ namespace Kernel::Input
void PS2Mouse::handle_byte(uint8_t byte)
{
using LibInput::MouseButton;
using LibInput::MouseEvent;
using LibInput::MouseEventType;
if (!m_enabled)
return initialize_extensions(byte);
@ -174,6 +178,8 @@ namespace Kernel::Input
BAN::ErrorOr<size_t> PS2Mouse::read_impl(off_t, BAN::ByteSpan buffer)
{
using LibInput::MouseEvent;
if (buffer.size() < sizeof(MouseEvent))
return BAN::Error::from_errno(ENOBUFS);

View File

@ -0,0 +1,88 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/SharedMemoryObject.h>
#include <kernel/Random.h>
namespace Kernel
{
static BAN::UniqPtr<SharedMemoryObjectManager> s_instance;
BAN::ErrorOr<void> SharedMemoryObjectManager::initialize()
{
ASSERT(!s_instance);
s_instance = TRY(BAN::UniqPtr<SharedMemoryObjectManager>::create());
return {};
}
SharedMemoryObjectManager& SharedMemoryObjectManager::get()
{
ASSERT(s_instance);
return *s_instance;
}
BAN::ErrorOr<SharedMemoryObjectManager::Key> SharedMemoryObjectManager::create_object(size_t size, PageTable::flags_t flags)
{
ASSERT(size % PAGE_SIZE == 0);
auto object = TRY(BAN::RefPtr<Object>::create());
object->size = size;
object->flags = flags;
TRY(object->paddrs.resize(size / PAGE_SIZE, 0));
LockGuard _(m_mutex);
Key key = Random::get<Key>();
while (m_objects.contains(key))
key = Random::get<Key>();
TRY(m_objects.insert(key, object));
return key;
}
BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> SharedMemoryObjectManager::map_object(Key key, PageTable& page_table, AddressRange address_range)
{
LockGuard _(m_mutex);
auto it = m_objects.find(key);
if (it == m_objects.end())
return BAN::Error::from_errno(ENOENT);
return TRY(SharedMemoryObject::create(it->value, page_table, address_range));
}
BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> SharedMemoryObject::create(BAN::RefPtr<SharedMemoryObjectManager::Object> object, PageTable& page_table, AddressRange address_range)
{
auto smo = TRY(BAN::UniqPtr<SharedMemoryObject>::create(object, page_table));
TRY(smo->initialize(address_range));
return BAN::move(smo);
}
BAN::ErrorOr<bool> SharedMemoryObject::allocate_page_containing_impl(vaddr_t address)
{
ASSERT(contains(address));
// Check if address is already mapped
vaddr_t vaddr = address & PAGE_ADDR_MASK;
if (m_page_table.physical_address_of(vaddr) != 0)
return false;
SpinLockGuard _(m_object->spin_lock);
paddr_t paddr = m_object->paddrs[(vaddr - m_vaddr) / PAGE_SIZE];
if (paddr == 0)
{
paddr = Heap::get().take_free_page();
if (paddr == 0)
return BAN::Error::from_errno(ENOMEM);
PageTable::with_fast_page(paddr, [&] {
memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE);
});
m_object->paddrs[(vaddr - m_vaddr) / PAGE_SIZE] = paddr;
}
m_page_table.map_page_at(paddr, vaddr, m_flags);
return true;
}
}

View File

@ -242,6 +242,12 @@ namespace Kernel
return m_open_files[fd]->offset;
}
BAN::ErrorOr<void> OpenFileDescriptorSet::truncate(int fd, off_t length)
{
TRY(validate_fd(fd));
return m_open_files[fd]->inode->truncate(length);
}
static void read_stat_from_inode(BAN::RefPtr<Inode> inode, struct stat* out)
{
out->st_dev = inode->dev();

View File

@ -5,7 +5,6 @@
#include <kernel/FS/ProcFS/FileSystem.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/IDT.h>
#include <kernel/Input/KeyboardLayout.h>
#include <kernel/InterruptController.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Memory/FileBackedRegion.h>
@ -17,6 +16,7 @@
#include <kernel/Timer/Timer.h>
#include <LibELF/LoadableELF.h>
#include <LibInput/KeyboardLayout.h>
#include <fcntl.h>
#include <stdio.h>
@ -1045,9 +1045,6 @@ namespace Kernel
int set_bits = 0;
for (;;)
{
if (arguments->timeout && SystemTimer::get().ms_since_boot() >= timedout_ms)
break;
auto update_fds =
[&](int fd, fd_set* source, fd_set* dest, bool (Inode::*func)() const)
{
@ -1062,10 +1059,6 @@ namespace Kernel
return;
auto inode = inode_or_error.release_value();
auto mode = inode->mode();
if (!mode.ifreg() && !mode.ififo() && !mode.ifsock() && !inode->is_pipe() && !inode->is_tty())
return;
if ((inode.ptr()->*func)())
{
FD_SET(fd, dest);
@ -1083,6 +1076,9 @@ namespace Kernel
if (set_bits > 0)
break;
if (arguments->timeout && SystemTimer::get().ms_since_boot() >= timedout_ms)
break;
LockFreeGuard free(m_process_lock);
SystemTimer::get().sleep(1);
}
@ -1145,6 +1141,13 @@ namespace Kernel
return TRY(m_open_file_descriptors.tell(fd));
}
BAN::ErrorOr<long> Process::sys_truncate(int fd, off_t length)
{
LockGuard _(m_process_lock);
TRY(m_open_file_descriptors.truncate(fd, length));
return 0;
}
BAN::ErrorOr<void> Process::mount(BAN::StringView source, BAN::StringView target)
{
BAN::String absolute_source, absolute_target;
@ -1389,6 +1392,41 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_smo_create(size_t len, int prot)
{
if (len == 0)
return BAN::Error::from_errno(EINVAL);
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_NONE))
return BAN::Error::from_errno(EINVAL);
if (auto rem = len % PAGE_SIZE)
len += PAGE_SIZE - rem;
PageTable::flags_t page_flags = 0;
if (prot & PROT_READ)
page_flags |= PageTable::Flags::Present;
if (prot & PROT_WRITE)
page_flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present;
if (prot & PROT_EXEC)
page_flags |= PageTable::Flags::Execute | PageTable::Flags::Present;
if (page_flags == 0)
page_flags |= PageTable::Flags::Reserved;
else
page_flags |= PageTable::Flags::UserSupervisor;
return TRY(SharedMemoryObjectManager::get().create_object(len, page_flags));
}
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 }));
LockGuard _(m_process_lock);
TRY(m_mapped_regions.push_back(BAN::move(region)));
return m_mapped_regions.back()->vaddr();
}
BAN::ErrorOr<long> Process::sys_tty_ctrl(int fildes, int command, int flags)
{
LockGuard _(m_process_lock);
@ -1457,7 +1495,7 @@ namespace Kernel
return BAN::Error::from_errno(EPERM);
auto absolute_path = TRY(absolute_path_of(path));
TRY(Input::KeyboardLayout::get().load_from_file(absolute_path));
TRY(LibInput::KeyboardLayout::get().load_from_file(absolute_path));
return 0;
}

View File

@ -7,6 +7,7 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Process.h>
#include <kernel/Terminal/TTY.h>
#include <LibInput/KeyboardLayout.h>
#include <fcntl.h>
#include <string.h>
@ -94,10 +95,11 @@ namespace Kernel
while (!TTY::current()->m_tty_ctrl.receive_input)
TTY::current()->m_tty_ctrl.semaphore.block_indefinite();
Input::KeyEvent event;
LibInput::RawKeyEvent event;
size_t read = MUST(inode->read(0, BAN::ByteSpan::from(event)));
ASSERT(read == sizeof(event));
TTY::current()->on_key_event(event);
TTY::current()->on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event));
}
}, nullptr
);
@ -120,71 +122,70 @@ namespace Kernel
return {};
}
void TTY::on_key_event(Input::KeyEvent event)
void TTY::on_key_event(LibInput::KeyEvent event)
{
LockGuard _(m_mutex);
if (event.released())
return;
Input::Key key = Input::key_event_to_key(event);
const char* ansi_c_str = Input::key_to_utf8(key, event.modifier);
const char* ansi_c_str = LibInput::key_to_utf8(event.key, event.modifier);
if (event.ctrl())
{
ansi_c_str = nullptr;
switch (key)
switch (event.key)
{
case Input::Key::A: ansi_c_str = "\x01"; break;
case Input::Key::B: ansi_c_str = "\x02"; break;
case Input::Key::C: ansi_c_str = "\x03"; break;
case Input::Key::D: ansi_c_str = "\x04"; break;
case Input::Key::E: ansi_c_str = "\x05"; break;
case Input::Key::F: ansi_c_str = "\x06"; break;
case Input::Key::G: ansi_c_str = "\x07"; break;
case Input::Key::H: ansi_c_str = "\x08"; break;
case Input::Key::I: ansi_c_str = "\x09"; break;
case Input::Key::J: ansi_c_str = "\x0A"; break;
case Input::Key::K: ansi_c_str = "\x0B"; break;
case Input::Key::L: ansi_c_str = "\x0C"; break;
case Input::Key::M: ansi_c_str = "\x0D"; break;
case Input::Key::N: ansi_c_str = "\x0E"; break;
case Input::Key::O: ansi_c_str = "\x0F"; break;
case Input::Key::P: ansi_c_str = "\x10"; break;
case Input::Key::Q: ansi_c_str = "\x11"; break;
case Input::Key::R: ansi_c_str = "\x12"; break;
case Input::Key::S: ansi_c_str = "\x13"; break;
case Input::Key::T: ansi_c_str = "\x14"; break;
case Input::Key::U: ansi_c_str = "\x15"; break;
case Input::Key::V: ansi_c_str = "\x16"; break;
case Input::Key::W: ansi_c_str = "\x17"; break;
case Input::Key::X: ansi_c_str = "\x18"; break;
case Input::Key::Y: ansi_c_str = "\x19"; break;
case Input::Key::Z: ansi_c_str = "\x1A"; break;
case LibInput::Key::A: ansi_c_str = "\x01"; break;
case LibInput::Key::B: ansi_c_str = "\x02"; break;
case LibInput::Key::C: ansi_c_str = "\x03"; break;
case LibInput::Key::D: ansi_c_str = "\x04"; break;
case LibInput::Key::E: ansi_c_str = "\x05"; break;
case LibInput::Key::F: ansi_c_str = "\x06"; break;
case LibInput::Key::G: ansi_c_str = "\x07"; break;
case LibInput::Key::H: ansi_c_str = "\x08"; break;
case LibInput::Key::I: ansi_c_str = "\x09"; break;
case LibInput::Key::J: ansi_c_str = "\x0A"; break;
case LibInput::Key::K: ansi_c_str = "\x0B"; break;
case LibInput::Key::L: ansi_c_str = "\x0C"; break;
case LibInput::Key::M: ansi_c_str = "\x0D"; break;
case LibInput::Key::N: ansi_c_str = "\x0E"; break;
case LibInput::Key::O: ansi_c_str = "\x0F"; break;
case LibInput::Key::P: ansi_c_str = "\x10"; break;
case LibInput::Key::Q: ansi_c_str = "\x11"; break;
case LibInput::Key::R: ansi_c_str = "\x12"; break;
case LibInput::Key::S: ansi_c_str = "\x13"; break;
case LibInput::Key::T: ansi_c_str = "\x14"; break;
case LibInput::Key::U: ansi_c_str = "\x15"; break;
case LibInput::Key::V: ansi_c_str = "\x16"; break;
case LibInput::Key::W: ansi_c_str = "\x17"; break;
case LibInput::Key::X: ansi_c_str = "\x18"; break;
case LibInput::Key::Y: ansi_c_str = "\x19"; break;
case LibInput::Key::Z: ansi_c_str = "\x1A"; break;
default: break;
}
}
else
{
switch (key)
switch (event.key)
{
case Input::Key::Enter:
case Input::Key::NumpadEnter:
case LibInput::Key::Enter:
case LibInput::Key::NumpadEnter:
ansi_c_str = "\n";
break;
case Input::Key::Backspace:
case LibInput::Key::Backspace:
ansi_c_str = "\b";
break;
case Input::Key::ArrowUp:
case LibInput::Key::ArrowUp:
ansi_c_str = "\e[A";
break;
case Input::Key::ArrowDown:
case LibInput::Key::ArrowDown:
ansi_c_str = "\e[B";
break;
case Input::Key::ArrowRight:
case LibInput::Key::ArrowRight:
ansi_c_str = "\e[C";
break;
case Input::Key::ArrowLeft:
case LibInput::Key::ArrowLeft:
ansi_c_str = "\e[D";
break;
default:

View File

@ -75,8 +75,9 @@ namespace Kernel
return;
uint64_t wake_time = ms_since_boot() + ms;
Scheduler::get().set_current_thread_sleeping(wake_time);
if (ms_since_boot() < wake_time)
dwarnln("sleep woke {} ms too soon", wake_time - ms_since_boot());
uint64_t current_time = ms_since_boot();
if (current_time < wake_time)
dwarnln("sleep woke {} ms too soon", wake_time - current_time);
}
timespec SystemTimer::real_time() const

View File

@ -8,13 +8,13 @@
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/GDT.h>
#include <kernel/IDT.h>
#include <kernel/Input/KeyboardLayout.h>
#include <kernel/Input/PS2/Controller.h>
#include <kernel/InterruptController.h>
#include <kernel/kprint.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/Memory/SharedMemoryObject.h>
#include <kernel/Networking/NetworkManager.h>
#include <kernel/PCI.h>
#include <kernel/PIC.h>
@ -28,6 +28,8 @@
#include <kernel/Terminal/VirtualTTY.h>
#include <kernel/Timer/Timer.h>
#include <LibInput/KeyboardLayout.h>
struct ParsedCommandLine
{
bool force_pic = false;
@ -142,6 +144,9 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
ProcFileSystem::initialize();
dprintln("procfs initialized");
MUST(SharedMemoryObjectManager::initialize());
dprintln("Shared memory object system initialized");
if (Serial::has_devices())
{
Serial::initialize_devices();
@ -194,7 +199,7 @@ static void init2(void*)
#endif
// Initialize empty keymap
MUST(Input::KeyboardLayout::initialize());
MUST(LibInput::KeyboardLayout::initialize());
if (auto res = PS2Controller::initialize(); res.is_error())
dprintln("{}", res.error());

View File

@ -59,6 +59,7 @@ __BEGIN_DECLS
#define OPEN_MAX 64
#define NAME_MAX 255
#define PATH_MAX 256
#define LOGIN_NAME_MAX 256
__END_DECLS

View File

@ -36,6 +36,11 @@ int poweroff(int command);
int load_keymap(const char* path);
// Create shared memory object and return its key or -1 on error
long smo_create(size_t size, int prot);
// Map shared memory object defined by its key and return address or null on error
void* smo_map(long key);
__END_DECLS
#endif

View File

@ -73,6 +73,9 @@ __BEGIN_DECLS
O(SYS_CONNECT, connect) \
O(SYS_LISTEN, listen) \
O(SYS_PSELECT, pselect) \
O(SYS_TRUNCATE, truncate) \
O(SYS_SMO_CREATE, smo_create) \
O(SYS_SMO_MAP, smo_map) \
enum Syscall
{

View File

@ -16,3 +16,16 @@ int load_keymap(const char* path)
{
return syscall(SYS_LOAD_KEYMAP, path);
}
long smo_create(size_t size, int prot)
{
return syscall(SYS_SMO_CREATE, size, prot);
}
void* smo_map(long key)
{
long ret = syscall(SYS_SMO_MAP, key);
if (ret < 0)
return nullptr;
return reinterpret_cast<void*>(ret);
}

View File

@ -99,6 +99,11 @@ off_t lseek(int fildes, off_t offset, int whence)
return syscall(SYS_SEEK, fildes, offset, whence);
}
int ftruncate(int fildes, off_t length)
{
return syscall(SYS_TRUNCATE, fildes, length);
}
int dup(int fildes)
{
return syscall(SYS_DUP, fildes);

View File

@ -39,9 +39,11 @@ set(USERSPACE_PROJECTS
test-tcp
test-udp
test-unix-socket
test-window
touch
u8sum
whoami
WindowServer
yes
)

View File

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.26)
project(WindowServer CXX)
set(SOURCES
main.cpp
Framebuffer.cpp
WindowServer.cpp
)
add_executable(WindowServer ${SOURCES})
target_compile_options(WindowServer PUBLIC -O2 -g)
target_link_libraries(WindowServer PUBLIC libc ban libgui libinput)
add_custom_target(WindowServer-install
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/WindowServer ${BANAN_BIN}/
DEPENDS WindowServer
)

View File

@ -0,0 +1,35 @@
/* GIMP header image file format (RGB) */
#include <stdint.h>
static int32_t s_cursor_width = 17;
static int32_t s_cursor_height = 26;
static const char* s_cursor_data =
"!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$`"
"`Q$`!!!!!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$`"
"`Q$``Q$`!!!!````!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$`"
"`Q$``Q$``Q$`!!!!````````!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$`"
"`Q$``Q$``Q$``Q$`!!!!````````````!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$`"
"`Q$``Q$``Q$``Q$``Q$`!!!!````````````````!!!!`Q$``Q$``Q$``Q$``Q$`"
"`Q$``Q$``Q$``Q$``Q$``Q$`!!!!````````````````````!!!!`Q$``Q$``Q$`"
"`Q$``Q$``Q$``Q$``Q$``Q$``Q$`!!!!````````````````````````!!!!`Q$`"
"`Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$`!!!!````````````````````````````"
"!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$`!!!!````````````````````````"
"````````!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$`!!!!````````````````````"
"````````````````!!!!`Q$``Q$``Q$``Q$``Q$``Q$`!!!!````````````````"
"````````````````````````!!!!`Q$``Q$``Q$``Q$``Q$`!!!!````````````"
"````````````````````````````````!!!!`Q$``Q$``Q$``Q$`!!!!````````"
"````````````````````````````````````````!!!!`Q$``Q$``Q$`!!!!````"
"````````````````````````````````````````````````!!!!`Q$``Q$`!!!!"
"````````````````````````````````````````````````````````!!!!`Q$`"
"!!!!````````````````````````````````!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!````````````````````````````````!!!!`Q$``Q$``Q$``Q$``Q$`"
"`Q$``Q$`!!!!````````````````!!!!````````````````!!!!`Q$``Q$``Q$`"
"`Q$``Q$``Q$`!!!!````````````!!!!`Q$`!!!!````````````!!!!`Q$``Q$`"
"`Q$``Q$``Q$``Q$`!!!!````````!!!!`Q$``Q$`!!!!````````````````!!!!"
"`Q$``Q$``Q$``Q$``Q$`!!!!````!!!!`Q$``Q$``Q$``Q$`!!!!````````````"
"!!!!`Q$``Q$``Q$``Q$``Q$`!!!!!!!!`Q$``Q$``Q$``Q$``Q$`!!!!````````"
"````````!!!!`Q$``Q$``Q$``Q$`!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$`!!!!"
"````````````!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$`"
"!!!!````````````!!!!`Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$``Q$`"
"`Q$``Q$`!!!!!!!!!!!!`Q$``Q$``Q$``Q$``Q$`";

View File

@ -0,0 +1,45 @@
#include "Framebuffer.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/framebuffer.h>
#include <sys/mman.h>
Framebuffer open_framebuffer()
{
int framebuffer_fd = open("/dev/fb0", O_RDWR);
if (framebuffer_fd == -1)
{
perror("open");
exit(1);
}
framebuffer_info_t framebuffer_info;
if (pread(framebuffer_fd, &framebuffer_info, sizeof(framebuffer_info), -1) == -1)
{
perror("pread");
exit(1);
}
const size_t framebuffer_bytes = framebuffer_info.width * framebuffer_info.height * (BANAN_FB_BPP / 8);
uint32_t* framebuffer_mmap = (uint32_t*)mmap(NULL, framebuffer_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, framebuffer_fd, 0);
if (framebuffer_mmap == MAP_FAILED)
{
perror("mmap");
exit(1);
}
memset(framebuffer_mmap, 0, framebuffer_bytes);
msync(framebuffer_mmap, framebuffer_bytes, MS_SYNC);
Framebuffer framebuffer;
framebuffer.fd = framebuffer_fd;
framebuffer.mmap = framebuffer_mmap;
framebuffer.width = framebuffer_info.width;
framebuffer.height = framebuffer_info.height;
framebuffer.bpp = BANAN_FB_BPP;
return framebuffer;
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "Utils.h"
struct Framebuffer
{
int fd;
uint32_t* mmap;
int32_t width;
int32_t height;
uint8_t bpp;
Rectangle area() const { return { 0, 0, width, height }; }
};
Framebuffer open_framebuffer();

View File

@ -0,0 +1,59 @@
#pragma once
#include <BAN/Math.h>
#include <BAN/Optional.h>
#include <stdint.h>
struct Position
{
int32_t x;
int32_t y;
};
struct Rectangle
{
int32_t x;
int32_t y;
int32_t width;
int32_t height;
bool contains(Position position) const
{
if (position.x < x || position.x >= x + width)
return false;
if (position.y < y || position.y >= y + height)
return false;
return true;
}
BAN::Optional<Rectangle> get_overlap(Rectangle other) const
{
const auto min_x = BAN::Math::max(x, other.x);
const auto min_y = BAN::Math::max(y, other.y);
const auto max_x = BAN::Math::min(x + width, other.x + other.width);
const auto max_y = BAN::Math::min(y + height, other.y + other.height);
if (min_x >= max_x || min_y >= max_y)
return {};
return Rectangle {
.x = min_x,
.y = min_y,
.width = max_x - min_x,
.height = max_y - min_y,
};
}
Rectangle get_bounding_box(Rectangle other) const
{
const auto min_x = BAN::Math::min(x, other.x);
const auto min_y = BAN::Math::min(y, other.y);
const auto max_x = BAN::Math::max(x + width, other.x + other.width);
const auto max_y = BAN::Math::max(y + height, other.y + other.height);
return Rectangle {
.x = min_x,
.y = min_y,
.width = max_x - min_x,
.height = max_y - min_y,
};
}
};

View File

@ -0,0 +1,45 @@
#pragma once
#include "Utils.h"
#include <BAN/RefPtr.h>
class Window : public BAN::RefCounted<Window>
{
public:
Window(int fd)
: m_client_fd(fd)
{ }
void set_position(Position position)
{
m_area.x = position.x;
m_area.y = position.y;
}
void set_size(Position size, uint32_t* fb_addr)
{
m_area.width = size.x;
m_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; }
int32_t x() const { return m_area.x; }
int32_t y() const { return m_area.y; }
uint32_t width() const { return m_area.width; }
uint32_t height() const { return m_area.height; }
Rectangle size() const { return { 0, 0, m_area.width, m_area.height }; }
const Rectangle& area() const { return m_area; }
const uint32_t* framebuffer() const { return m_fb_addr; }
private:
const int m_client_fd { -1 };
uint32_t* m_fb_addr { nullptr };
Rectangle m_area { 0, 0, 0, 0 };
bool m_deleted { false };
};

View File

@ -0,0 +1,224 @@
#include "Cursor.h"
#include "WindowServer.h"
#include <LibGUI/Window.h>
#include <LibInput/KeyboardLayout.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/socket.h>
void WindowServer::add_window(int fd, BAN::RefPtr<Window> window)
{
MUST(m_windows_ordered.insert(0, window));
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);
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)
{
m_windows_ordered.remove(i);
break;
}
}
}
}
void WindowServer::on_key_event(LibInput::KeyEvent event)
{
// Mod key is not passed to clients
if (event.key == LibInput::Key::Super)
{
m_is_mod_key_held = event.pressed();
return;
}
// Quick hack to stop the window server
if (event.pressed() && event.key == LibInput::Key::Escape)
exit(0);
if (m_focused_window)
{
LibGUI::EventPacket packet;
packet.type = LibGUI::EventPacket::Type::KeyEvent;
packet.key_event = event;
send(m_focused_window->client_fd(), &packet, sizeof(packet), 0);
}
}
void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
{
BAN::RefPtr<Window> target_window;
for (size_t i = m_windows_ordered.size(); i > 0; i--)
{
if (m_windows_ordered[i - 1]->area().contains(m_cursor))
{
target_window = m_windows_ordered[i - 1];
break;
}
}
// Ignore mouse button events which are not on top of a window
if (!target_window)
return;
set_focused_window(target_window);
// Handle window moving when mod key is held
if (m_is_mod_key_held && event.pressed && event.button == LibInput::MouseButton::Left && !m_is_moving_window)
m_is_moving_window = true;
else if (m_is_moving_window && !event.pressed)
m_is_moving_window = false;
else
{
// NOTE: we always have target window if code reaches here
LibGUI::EventPacket packet;
packet.type = LibGUI::EventPacket::Type::MouseButtonEvent;
packet.mouse_button_event.button = event.button;
packet.mouse_button_event.pressed = event.pressed;
packet.mouse_button_event.x = m_cursor.x - m_focused_window->x();
packet.mouse_button_event.y = m_cursor.y - m_focused_window->y();
send(m_focused_window->client_fd(), &packet, sizeof(packet), 0);
}
}
void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
{
Rectangle old_cursor { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height };
const int32_t new_x = BAN::Math::clamp(m_cursor.x + event.rel_x, 0, m_framebuffer.width);
const int32_t new_y = BAN::Math::clamp(m_cursor.y - event.rel_y, 0, m_framebuffer.height);
event.rel_x = new_x - m_cursor.x;
event.rel_y = new_y - m_cursor.y;
if (event.rel_x == 0 && event.rel_y == 0)
return;
m_cursor.x = new_x;
m_cursor.y = new_y;
Rectangle new_cursor { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height };
invalidate(old_cursor.get_bounding_box(old_cursor));
invalidate(new_cursor.get_bounding_box(old_cursor));
if (m_is_moving_window)
{
auto old_window = m_focused_window->area();
m_focused_window->set_position({
m_focused_window->x() + event.rel_x,
m_focused_window->y() + event.rel_y,
});
invalidate(old_window);
invalidate(m_focused_window->area());
return;
}
if (m_focused_window)
{
LibGUI::EventPacket packet;
packet.type = LibGUI::EventPacket::Type::MouseMoveEvent;
packet.mouse_move_event.x = m_cursor.x - m_focused_window->x();
packet.mouse_move_event.y = m_cursor.y - m_focused_window->y();
send(m_focused_window->client_fd(), &packet, sizeof(packet), 0);
}
}
void WindowServer::on_mouse_scroll(LibInput::MouseScrollEvent event)
{
if (m_focused_window)
{
LibGUI::EventPacket packet;
packet.type = LibGUI::EventPacket::Type::MouseScrollEvent;
packet.mouse_scroll_event = event;
send(m_focused_window->client_fd(), &packet, sizeof(packet), 0);
}
}
void WindowServer::set_focused_window(BAN::RefPtr<Window> window)
{
if (m_focused_window == window)
return;
for (size_t i = m_windows_ordered.size(); i > 0; i--)
{
if (m_windows_ordered[i - 1] == window)
{
m_focused_window = window;
m_windows_ordered.remove(i - 1);
MUST(m_windows_ordered.push_back(window));
invalidate(window->area());
break;
}
}
}
void WindowServer::invalidate(Rectangle area)
{
auto fb_overlap = area.get_overlap(m_framebuffer.area());
if (!fb_overlap.has_value())
return;
area = fb_overlap.release_value();
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);
for (auto& pwindow : m_windows_ordered)
{
auto& window = *pwindow;
auto overlap = window.area().get_overlap(area);
if (!overlap.has_value())
continue;
const int32_t src_x = overlap->x - window.x();
const int32_t src_y = overlap->y - window.y();
for (int32_t y_off = 0; y_off < overlap->height; y_off++)
memcpy(
&m_framebuffer.mmap[(overlap->y + y_off) * m_framebuffer.width + overlap->x],
&window.framebuffer()[(src_y + y_off) * window.width() + src_x],
overlap->width * 4
);
}
Rectangle cursor { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height };
auto overlap = cursor.get_overlap(area);
if (overlap.has_value())
{
for (int32_t dy = overlap->y - cursor.y; dy < overlap->height; dy++)
{
for (int32_t dx = overlap->x - cursor.x; dx < overlap->width; dx++)
{
const uint32_t offset = (dy * s_cursor_width + dx) * 4;
uint32_t r = (((s_cursor_data[offset + 0] - 33) << 2) | ((s_cursor_data[offset + 1] - 33) >> 4));
uint32_t g = ((((s_cursor_data[offset + 1] - 33) & 0xF) << 4) | ((s_cursor_data[offset + 2] - 33) >> 2));
uint32_t b = ((((s_cursor_data[offset + 2] - 33) & 0x3) << 6) | ((s_cursor_data[offset + 3] - 33)));
uint32_t color = (r << 16) | (g << 8) | b;
if (color != 0xFF00FF)
m_framebuffer.mmap[(overlap->y + dy) * m_framebuffer.width + (overlap->x + dx)] = color;
}
}
}
uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
mmap_start &= ~(uintptr_t)0xFFF;
msync(reinterpret_cast<void*>(mmap_start), mmap_end - mmap_start, MS_SYNC);
}

View File

@ -0,0 +1,44 @@
#pragma once
#include "Framebuffer.h"
#include "Window.h"
#include <BAN/Function.h>
#include <BAN/Iteration.h>
#include <BAN/Vector.h>
#include <BAN/HashMap.h>
#include <LibInput/KeyEvent.h>
#include <LibInput/MouseEvent.h>
class WindowServer
{
public:
WindowServer(Framebuffer& framebuffer)
: m_framebuffer(framebuffer)
, m_cursor({ framebuffer.width / 2, framebuffer.height / 2 })
{
invalidate(m_framebuffer.area());
}
void add_window(int fd, BAN::RefPtr<Window> window);
void for_each_window(const BAN::Function<BAN::Iteration(int, Window&)>& callback);
void on_key_event(LibInput::KeyEvent event);
void on_mouse_button(LibInput::MouseButtonEvent event);
void on_mouse_move(LibInput::MouseMoveEvent event);
void on_mouse_scroll(LibInput::MouseScrollEvent event);
void set_focused_window(BAN::RefPtr<Window> window);
void invalidate(Rectangle area);
private:
Framebuffer& m_framebuffer;
BAN::Vector<BAN::RefPtr<Window>> m_windows_ordered;
BAN::HashMap<int, BAN::RefPtr<Window>> m_windows;
bool m_is_mod_key_held { false };
bool m_is_moving_window { false };
BAN::RefPtr<Window> m_focused_window;
Position m_cursor;
};

View File

@ -0,0 +1,267 @@
#include "WindowServer.h"
#include <BAN/Debug.h>
#include <LibGUI/Window.h>
#include <LibInput/KeyboardLayout.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/banan-os.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
int open_server_fd()
{
struct stat st;
if (stat(LibGUI::s_window_server_socket.data(), &st) != -1)
unlink(LibGUI::s_window_server_socket.data());
int server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (server_fd == -1)
{
perror("socket");
exit(1);
}
sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, LibGUI::s_window_server_socket.data());
if (bind(server_fd, (sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
perror("bind");
exit(1);
}
if (chmod("/tmp/resolver.sock", 0777) == -1)
{
perror("chmod");
exit(1);
}
if (listen(server_fd, SOMAXCONN) == -1)
{
perror("listen");
exit(1);
}
return server_fd;
}
int main()
{
srand(time(nullptr));
int server_fd = open_server_fd();
auto framebuffer = open_framebuffer();
if (framebuffer.bpp != 32)
{
dwarnln("Window server requires 32 bpp");
return 1;
}
if (tty_ctrl(STDIN_FILENO, TTY_CMD_UNSET, TTY_FLAG_ENABLE_INPUT) == -1)
{
perror("tty_ctrl");
exit(1);
}
atexit([]() { tty_ctrl(STDIN_FILENO, TTY_CMD_SET, TTY_FLAG_ENABLE_INPUT); });
MUST(LibInput::KeyboardLayout::initialize());
MUST(LibInput::KeyboardLayout::get().load_from_file("/usr/share/keymaps/us.keymap"sv));
int keyboard_fd = open("/dev/input0", O_RDONLY);
if (keyboard_fd == -1)
perror("open");
int mouse_fd = open("/dev/input1", O_RDONLY);
if (mouse_fd == -1)
perror("open");
dprintln("Window server started");
for (int i = 0; i < 2; i++)
{
if (fork() == 0)
{
execl("/bin/test-window", "test-window", NULL);
exit(1);
}
}
WindowServer window_server(framebuffer);
for (;;)
{
int max_socket = server_fd;
fd_set fds;
FD_ZERO(&fds);
FD_SET(server_fd, &fds);
if (keyboard_fd != -1)
{
FD_SET(keyboard_fd, &fds);
max_socket = BAN::Math::max(max_socket, keyboard_fd);
}
if (mouse_fd != -1)
{
FD_SET(mouse_fd, &fds);
max_socket = BAN::Math::max(max_socket, mouse_fd);
}
window_server.for_each_window(
[&](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)
{
dwarnln("select: {}", strerror(errno));
break;
}
if (FD_ISSET(server_fd, &fds))
{
int window_fd = accept(server_fd, nullptr, nullptr);
if (window_fd == -1)
{
dwarnln("accept: {}", strerror(errno));
continue;
}
auto window = MUST(BAN::RefPtr<Window>::create(window_fd));
window_server.add_window(window_fd, window);
}
if (keyboard_fd != -1 && FD_ISSET(keyboard_fd, &fds))
{
LibInput::RawKeyEvent event;
if (read(keyboard_fd, &event, sizeof(event)) == -1)
{
perror("read");
continue;
}
window_server.on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event));
}
if (mouse_fd != -1 && FD_ISSET(mouse_fd, &fds))
{
LibInput::MouseEvent event;
if (read(mouse_fd, &event, sizeof(event)) == -1)
{
perror("read");
continue;
}
switch (event.type)
{
case LibInput::MouseEventType::MouseButtonEvent:
window_server.on_mouse_button(event.button_event);
break;
case LibInput::MouseEventType::MouseMoveEvent:
window_server.on_mouse_move(event.move_event);
break;
case LibInput::MouseEventType::MouseScrollEvent:
window_server.on_mouse_scroll(event.scroll_event);
break;
}
}
window_server.for_each_window(
[&](int fd, Window& window) -> BAN::Iteration
{
if (!FD_ISSET(fd, &fds))
return BAN::Iteration::Continue;
LibGUI::WindowPacket packet;
ssize_t nrecv = recv(fd, &packet, sizeof(packet), 0);
if (nrecv < 0)
dwarnln("recv: {}", strerror(errno));
if (nrecv <= 0)
{
window.mark_deleted();
return BAN::Iteration::Continue;
}
switch (packet.type)
{
case LibGUI::WindowPacketType::CreateWindow:
{
if (nrecv != sizeof(LibGUI::WindowCreatePacket))
{
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>(window.width() / 2),
static_cast<int32_t>(window.height() / 2)
});
break;
}
case LibGUI::WindowPacketType::Invalidate:
{
if (nrecv != sizeof(LibGUI::WindowInvalidatePacket))
{
dwarnln("Invalid Invalidate packet size");
break;
}
if (packet.invalidate.x + packet.invalidate.width > window.width() || packet.invalidate.y + packet.invalidate.height > window.height())
{
dwarnln("Invalid Invalidate packet parameters");
break;
}
window_server.invalidate({
window.x() + static_cast<int32_t>(packet.invalidate.x),
window.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;
}
);
}
}

View File

@ -7,7 +7,7 @@
#include <sys/mman.h>
#include <termios.h>
#include <kernel/Input/MouseEvent.h>
#include <LibInput/MouseEvent.h>
framebuffer_info_t fb_info;
void* fb_mmap = nullptr;
@ -137,7 +137,7 @@ int main(int argc, char** argv)
while (true)
{
using namespace Kernel::Input;
using namespace LibInput;
MouseEvent event;
if (read(mouse_fd, &event, sizeof(event)) == -1)

View File

@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.26)
project(test-window CXX)
set(SOURCES
main.cpp
)
add_executable(test-window ${SOURCES})
target_compile_options(test-window PUBLIC -O2 -g)
target_link_libraries(test-window PUBLIC libc ban libgui)
add_custom_target(test-window-install
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/test-window ${BANAN_BIN}/
DEPENDS test-window
)

View File

@ -0,0 +1,61 @@
#include <BAN/Debug.h>
#include <LibGUI/Window.h>
#include <stdlib.h>
#include <unistd.h>
void randomize_color(BAN::UniqPtr<LibGUI::Window>& window)
{
uint32_t color = ((rand() % 255) << 16) | ((rand() % 255) << 8) | ((rand() % 255) << 0);
for (uint32_t y = 0; y < window->height(); y++)
for (uint32_t x = 0; x < window->width(); x++)
window->set_pixel(x, y, color);
window->invalidate();
}
int main()
{
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
srand(ts.tv_nsec);
auto window_or_error = LibGUI::Window::create(300, 200);
if (window_or_error.is_error())
{
dprintln("{}", window_or_error.error());
return 1;
}
auto window = window_or_error.release_value();
window->set_mouse_button_event_callback(
[&](LibGUI::EventPacket::MouseButtonEvent event)
{
if (event.pressed && event.button == LibGUI::EventPacket::MouseButton::Left)
randomize_color(window);
const char* button;
switch (event.button)
{
case LibGUI::EventPacket::MouseButton::Left: button = "left"; break;
case LibGUI::EventPacket::MouseButton::Right: button = "right"; break;
case LibGUI::EventPacket::MouseButton::Middle: button = "middle"; break;
case LibGUI::EventPacket::MouseButton::Extra1: button = "extra1"; break;
case LibGUI::EventPacket::MouseButton::Extra2: button = "extra2"; break;
}
dprintln("mouse button '{}' {} at {}, {}", button, event.pressed ? "pressed" : "released", event.x, event.y);
}
);
randomize_color(window);
for (;;)
{
window->poll_events();
timespec duration;
duration.tv_sec = 0;
duration.tv_nsec = 16'666'666;
nanosleep(&duration, nullptr);
}
}