Compare commits
13 Commits
a1ab44d39f
...
c2b6ba0d5a
Author | SHA1 | Date |
---|---|---|
Bananymous | c2b6ba0d5a | |
Bananymous | d4d530e6c8 | |
Bananymous | 99270e96a9 | |
Bananymous | 4bf7a08c80 | |
Bananymous | 3823de6552 | |
Bananymous | 30592b27ce | |
Bananymous | 8bc6c2eb20 | |
Bananymous | 87d52e5ebe | |
Bananymous | 598a09c13d | |
Bananymous | 54db4ab215 | |
Bananymous | 5b5ccba247 | |
Bananymous | 18e2559b1e | |
Bananymous | f5987b68ff |
|
@ -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 };
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "")
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -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 "")
|
|
@ -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)];
|
||||
}
|
||||
|
|
@ -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];
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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>;
|
||||
};
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Kernel::Input
|
||||
namespace LibInput
|
||||
{
|
||||
|
||||
enum class MouseButton
|
|
@ -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})
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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(); }
|
||||
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -39,9 +39,11 @@ set(USERSPACE_PROJECTS
|
|||
test-tcp
|
||||
test-udp
|
||||
test-unix-socket
|
||||
test-window
|
||||
touch
|
||||
u8sum
|
||||
whoami
|
||||
WindowServer
|
||||
yes
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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$`";
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
};
|
|
@ -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 };
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue