Compare commits
6 Commits
cf21eb4b39
...
bda2c663da
Author | SHA1 | Date |
---|---|---|
Bananymous | bda2c663da | |
Bananymous | 5e041e6e5a | |
Bananymous | d19264eea8 | |
Bananymous | 64c52012df | |
Bananymous | 7542e55cb2 | |
Bananymous | 6bd51ac345 |
|
@ -40,7 +40,7 @@ namespace Kernel
|
|||
|
||||
bool MemoryRegion::overlaps(vaddr_t address, size_t size) const
|
||||
{
|
||||
if (address + size < m_vaddr)
|
||||
if (address + size <= m_vaddr)
|
||||
return false;
|
||||
if (address >= m_vaddr + m_size)
|
||||
return false;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <BAN/Debug.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -6,6 +8,8 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DEBUG_MALLOC 0
|
||||
|
||||
static consteval size_t log_size_t(size_t value, size_t base)
|
||||
{
|
||||
size_t result = 0;
|
||||
|
@ -174,6 +178,8 @@ static malloc_pool_t& pool_from_node(malloc_node_t* node)
|
|||
|
||||
void* malloc(size_t size)
|
||||
{
|
||||
dprintln_if(DEBUG_MALLOC, "malloc({})", size);
|
||||
|
||||
// align size to s_malloc_default_align boundary
|
||||
if (size_t ret = size % s_malloc_default_align)
|
||||
size += s_malloc_default_align - ret;
|
||||
|
@ -207,6 +213,8 @@ void* malloc(size_t size)
|
|||
|
||||
void* realloc(void* ptr, size_t size)
|
||||
{
|
||||
dprintln_if(DEBUG_MALLOC, "realloc({}, {})", ptr, size);
|
||||
|
||||
if (ptr == nullptr)
|
||||
return malloc(size);
|
||||
|
||||
|
@ -237,6 +245,8 @@ void* realloc(void* ptr, size_t size)
|
|||
|
||||
void free(void* ptr)
|
||||
{
|
||||
dprintln_if(DEBUG_MALLOC, "free({})", ptr);
|
||||
|
||||
if (ptr == nullptr)
|
||||
return;
|
||||
|
||||
|
@ -265,6 +275,8 @@ void free(void* ptr)
|
|||
|
||||
void* calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
dprintln_if(DEBUG_MALLOC, "calloc({}, {})", nmemb, size);
|
||||
|
||||
size_t total = nmemb * size;
|
||||
if (size != 0 && total / size != nmemb)
|
||||
{
|
||||
|
|
|
@ -59,8 +59,7 @@ namespace LibGUI
|
|||
|
||||
Window::~Window()
|
||||
{
|
||||
munmap(m_framebuffer_smo, m_width * m_height * 4);
|
||||
close(m_server_fd);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<Window>> Window::create(uint32_t width, uint32_t height, BAN::StringView title)
|
||||
|
@ -102,27 +101,13 @@ namespace LibGUI
|
|||
TRY(create_packet.title.append(title));
|
||||
TRY(create_packet.send_serialized(server_fd));
|
||||
|
||||
const auto [response_type, response_data ] = TRY(recv_packet(server_fd));
|
||||
if (response_type != PacketType::WindowCreateResponse)
|
||||
return BAN::Error::from_literal("Server responded with invalid packet");
|
||||
auto window = TRY(BAN::UniqPtr<Window>::create(server_fd));
|
||||
|
||||
const auto create_response = TRY(WindowPacket::WindowCreateResponse::deserialize(response_data.span()));
|
||||
void* framebuffer_addr = smo_map(create_response.smo_key);
|
||||
if (framebuffer_addr == nullptr)
|
||||
return BAN::Error::from_errno(errno);
|
||||
width = create_response.width;
|
||||
height = create_response.height;
|
||||
|
||||
BAN::Vector<uint32_t> framebuffer;
|
||||
TRY(framebuffer.resize(width * height, 0xFFFFFFFF));
|
||||
|
||||
auto window = TRY(BAN::UniqPtr<Window>::create(
|
||||
server_fd,
|
||||
static_cast<uint32_t*>(framebuffer_addr),
|
||||
BAN::move(framebuffer),
|
||||
width,
|
||||
height
|
||||
));
|
||||
bool resized = false;
|
||||
window->set_resize_window_event_callback([&]() { resized = true; });
|
||||
while (!resized)
|
||||
window->poll_events();
|
||||
window->set_resize_window_event_callback({});
|
||||
|
||||
server_closer.disable();
|
||||
|
||||
|
@ -244,10 +229,10 @@ namespace LibGUI
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Window::invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||
void Window::invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||
{
|
||||
if (!clamp_to_framebuffer(x, y, width, height))
|
||||
return true;
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < height; i++)
|
||||
memcpy(&m_framebuffer_smo[(y + i) * m_width + x], &m_framebuffer[(y + i) * m_width + x], width * sizeof(uint32_t));
|
||||
|
@ -259,56 +244,106 @@ namespace LibGUI
|
|||
packet.height = height;
|
||||
|
||||
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
||||
{
|
||||
dprintln("failed to invalidate window: {}", ret.error());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return on_socket_error(__FUNCTION__);
|
||||
}
|
||||
|
||||
bool Window::set_mouse_capture(bool captured)
|
||||
void Window::set_mouse_capture(bool captured)
|
||||
{
|
||||
WindowPacket::WindowSetMouseCapture packet;
|
||||
packet.captured = captured;
|
||||
|
||||
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
||||
{
|
||||
dprintln("failed to set mouse capture: {}", ret.error());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return on_socket_error(__FUNCTION__);
|
||||
}
|
||||
|
||||
bool Window::set_position(int32_t x, int32_t y)
|
||||
void Window::set_fullscreen(bool fullscreen)
|
||||
{
|
||||
WindowPacket::WindowSetFullscreen packet;
|
||||
packet.fullscreen = fullscreen;
|
||||
|
||||
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
||||
return on_socket_error(__FUNCTION__);
|
||||
}
|
||||
|
||||
void Window::set_position(int32_t x, int32_t y)
|
||||
{
|
||||
WindowPacket::WindowSetPosition packet;
|
||||
packet.x = x;
|
||||
packet.y = y;
|
||||
|
||||
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
||||
{
|
||||
dprintln("failed to set window position: {}", ret.error());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return on_socket_error(__FUNCTION__);
|
||||
}
|
||||
|
||||
bool Window::set_attributes(Attributes attributes)
|
||||
void Window::set_attributes(Attributes attributes)
|
||||
{
|
||||
WindowPacket::WindowSetAttributes packet;
|
||||
packet.attributes = attributes;
|
||||
|
||||
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
||||
{
|
||||
dprintln("failed to set window attributes: {}", ret.error());
|
||||
return false;
|
||||
}
|
||||
return on_socket_error(__FUNCTION__);
|
||||
|
||||
m_attributes = attributes;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window::request_resize(uint32_t width, uint32_t height)
|
||||
{
|
||||
WindowPacket::WindowSetSize packet;
|
||||
packet.width = width;
|
||||
packet.height = height;
|
||||
|
||||
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
||||
return on_socket_error(__FUNCTION__);
|
||||
}
|
||||
|
||||
void Window::on_socket_error(BAN::StringView function)
|
||||
{
|
||||
if (m_handling_socket_error)
|
||||
return;
|
||||
m_handling_socket_error = true;
|
||||
|
||||
dprintln("Socket error while running Window::{}", function);
|
||||
|
||||
if (!m_socket_error_callback)
|
||||
exit(1);
|
||||
|
||||
m_socket_error_callback();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Window::cleanup()
|
||||
{
|
||||
munmap(m_framebuffer_smo, m_width * m_height * 4);
|
||||
close(m_server_fd);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Window::handle_resize_event(const EventPacket::ResizeWindowEvent& event)
|
||||
{
|
||||
if (m_framebuffer_smo)
|
||||
munmap(m_framebuffer_smo, m_width * m_height * 4);
|
||||
m_framebuffer_smo = nullptr;
|
||||
|
||||
BAN::Vector<uint32_t> framebuffer;
|
||||
TRY(framebuffer.resize(event.width * event.height, 0xFFFFFFFF));
|
||||
|
||||
void* framebuffer_addr = smo_map(event.smo_key);
|
||||
if (framebuffer_addr == nullptr)
|
||||
return BAN::Error::from_errno(errno);
|
||||
|
||||
const uint32_t min_x = BAN::Math::min(m_width, event.width);
|
||||
const uint32_t min_y = BAN::Math::min(m_height, event.height);
|
||||
for (uint32_t y = 0; y < min_y; y++)
|
||||
for (uint32_t x = 0; x < min_x; x++)
|
||||
framebuffer[y * event.width + x] = m_framebuffer[y * m_width + x];
|
||||
|
||||
m_framebuffer_smo = static_cast<uint32_t*>(framebuffer_addr);
|
||||
m_framebuffer = BAN::move(framebuffer);
|
||||
m_width = event.width;
|
||||
m_height = event.height;
|
||||
|
||||
invalidate();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#define TRY_OR_BREAK(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) break; e.release_value(); })
|
||||
|
@ -328,7 +363,7 @@ namespace LibGUI
|
|||
|
||||
auto packet_or_error = recv_packet(m_server_fd);
|
||||
if (packet_or_error.is_error())
|
||||
break;
|
||||
return on_socket_error(__FUNCTION__);
|
||||
|
||||
const auto [packet_type, packet_data] = packet_or_error.release_value();
|
||||
switch (packet_type)
|
||||
|
@ -341,6 +376,13 @@ namespace LibGUI
|
|||
else
|
||||
exit(0);
|
||||
break;
|
||||
case PacketType::ResizeWindowEvent:
|
||||
{
|
||||
MUST(handle_resize_event(TRY_OR_BREAK(EventPacket::ResizeWindowEvent::deserialize(packet_data.span()))));
|
||||
if (m_resize_window_event_callback)
|
||||
m_resize_window_event_callback();
|
||||
break;
|
||||
}
|
||||
case PacketType::KeyEvent:
|
||||
if (m_key_event_callback)
|
||||
m_key_event_callback(TRY_OR_BREAK(EventPacket::KeyEvent::deserialize(packet_data.span())).event);
|
||||
|
|
|
@ -163,9 +163,12 @@ namespace LibGUI
|
|||
WindowSetPosition,
|
||||
WindowSetAttributes,
|
||||
WindowSetMouseCapture,
|
||||
WindowSetSize,
|
||||
WindowSetFullscreen,
|
||||
|
||||
DestroyWindowEvent,
|
||||
CloseWindowEvent,
|
||||
ResizeWindowEvent,
|
||||
KeyEvent,
|
||||
MouseButtonEvent,
|
||||
MouseMoveEvent,
|
||||
|
@ -182,13 +185,6 @@ namespace LibGUI
|
|||
BAN::String, title
|
||||
);
|
||||
|
||||
DEFINE_PACKET(
|
||||
WindowCreateResponse,
|
||||
uint32_t, width,
|
||||
uint32_t, height,
|
||||
long, smo_key
|
||||
);
|
||||
|
||||
DEFINE_PACKET(
|
||||
WindowInvalidate,
|
||||
uint32_t, x,
|
||||
|
@ -220,6 +216,17 @@ namespace LibGUI
|
|||
bool, captured
|
||||
);
|
||||
|
||||
DEFINE_PACKET(
|
||||
WindowSetSize,
|
||||
uint32_t, width,
|
||||
uint32_t, height
|
||||
);
|
||||
|
||||
DEFINE_PACKET(
|
||||
WindowSetFullscreen,
|
||||
bool, fullscreen
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
namespace EventPacket
|
||||
|
@ -233,6 +240,13 @@ namespace LibGUI
|
|||
CloseWindowEvent
|
||||
);
|
||||
|
||||
DEFINE_PACKET(
|
||||
ResizeWindowEvent,
|
||||
uint32_t, width,
|
||||
uint32_t, height,
|
||||
long, smo_key
|
||||
);
|
||||
|
||||
DEFINE_PACKET_EXTRA(
|
||||
KeyEvent,
|
||||
using event_t = LibInput::KeyEvent,
|
||||
|
|
|
@ -57,21 +57,28 @@ namespace LibGUI
|
|||
// fill_color is used when copying data outside of window bounds
|
||||
void copy_horizontal_slice(int32_t dst_y, int32_t src_y, uint32_t amount, uint32_t fill_color);
|
||||
|
||||
bool invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
bool invalidate() { return invalidate(0, 0, width(), height()); }
|
||||
void invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
void invalidate() { return invalidate(0, 0, width(), height()); }
|
||||
|
||||
bool set_mouse_capture(bool captured);
|
||||
void set_mouse_capture(bool captured);
|
||||
void set_fullscreen(bool fullscreen);
|
||||
|
||||
bool set_position(int32_t x, int32_t y);
|
||||
void set_position(int32_t x, int32_t y);
|
||||
|
||||
Attributes get_attributes() const { return m_attributes; }
|
||||
bool set_attributes(Attributes attributes);
|
||||
void set_attributes(Attributes attributes);
|
||||
|
||||
// send resize request to window server
|
||||
// actual resize is only done after resize callback is called
|
||||
void request_resize(uint32_t width, uint32_t height);
|
||||
|
||||
uint32_t width() const { return m_width; }
|
||||
uint32_t height() const { return m_height; }
|
||||
|
||||
void poll_events();
|
||||
void set_socket_error_callback(BAN::Function<void()> callback) { m_socket_error_callback = callback; }
|
||||
void set_close_window_event_callback(BAN::Function<void()> callback) { m_close_window_event_callback = callback; }
|
||||
void set_resize_window_event_callback(BAN::Function<void()> callback) { m_resize_window_event_callback = callback; }
|
||||
void set_key_event_callback(BAN::Function<void(EventPacket::KeyEvent::event_t)> callback) { m_key_event_callback = callback; }
|
||||
void set_mouse_button_event_callback(BAN::Function<void(EventPacket::MouseButtonEvent::event_t)> callback) { m_mouse_button_event_callback = callback; }
|
||||
void set_mouse_move_event_callback(BAN::Function<void(EventPacket::MouseMoveEvent::event_t)> callback) { m_mouse_move_event_callback = callback; }
|
||||
|
@ -80,27 +87,32 @@ namespace LibGUI
|
|||
int server_fd() const { return m_server_fd; }
|
||||
|
||||
private:
|
||||
Window(int server_fd, uint32_t* framebuffer_smo, BAN::Vector<uint32_t>&& framebuffer, uint32_t width, uint32_t height)
|
||||
Window(int server_fd)
|
||||
: m_server_fd(server_fd)
|
||||
, m_framebuffer(framebuffer)
|
||||
, m_framebuffer_smo(framebuffer_smo)
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
{ }
|
||||
|
||||
bool clamp_to_framebuffer(int32_t& x, int32_t& y, uint32_t& width, uint32_t& height) const;
|
||||
|
||||
void on_socket_error(BAN::StringView function);
|
||||
void cleanup();
|
||||
|
||||
BAN::ErrorOr<void> handle_resize_event(const EventPacket::ResizeWindowEvent&);
|
||||
|
||||
private:
|
||||
int m_server_fd;
|
||||
const int m_server_fd;
|
||||
|
||||
bool m_handling_socket_error { false };
|
||||
|
||||
Attributes m_attributes;
|
||||
|
||||
BAN::Vector<uint32_t> m_framebuffer;
|
||||
uint32_t* m_framebuffer_smo;
|
||||
uint32_t m_width;
|
||||
uint32_t m_height;
|
||||
uint32_t* m_framebuffer_smo { nullptr };
|
||||
uint32_t m_width { 0 };
|
||||
uint32_t m_height { 0 };
|
||||
|
||||
BAN::Function<void()> m_socket_error_callback;
|
||||
BAN::Function<void()> m_close_window_event_callback;
|
||||
BAN::Function<void()> m_resize_window_event_callback;
|
||||
BAN::Function<void(EventPacket::KeyEvent::event_t)> m_key_event_callback;
|
||||
BAN::Function<void(EventPacket::MouseButtonEvent::event_t)> m_mouse_button_event_callback;
|
||||
BAN::Function<void(EventPacket::MouseMoveEvent::event_t)> m_mouse_move_event_callback;
|
||||
|
|
|
@ -53,8 +53,7 @@ int main()
|
|||
|
||||
window->fill_rect(text_x, text_y, text_w, text_h, bg_color);
|
||||
window->draw_text(text, font, text_x, text_y, fg_color);
|
||||
if (!window->invalidate(text_x, text_y, text_w, text_h))
|
||||
is_running = false;
|
||||
window->invalidate(text_x, text_y, text_w, text_h);
|
||||
};
|
||||
|
||||
while (is_running)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "Window.h"
|
||||
|
||||
#include <BAN/Debug.h>
|
||||
#include <BAN/ScopeGuard.h>
|
||||
|
||||
#include <LibGUI/Window.h>
|
||||
|
||||
|
@ -9,20 +10,6 @@
|
|||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
Window::Window(int fd, Rectangle area, long smo_key, BAN::StringView title, const LibFont::Font& font)
|
||||
: m_client_fd(fd)
|
||||
, m_client_area(area)
|
||||
, m_smo_key(smo_key)
|
||||
{
|
||||
MUST(m_title.append(title));
|
||||
prepare_title_bar(font);
|
||||
|
||||
m_fb_addr = static_cast<uint32_t*>(smo_map(smo_key));
|
||||
ASSERT(m_fb_addr);
|
||||
|
||||
memset(m_fb_addr, 0xFF, client_width() * client_height() * 4);
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
munmap(m_fb_addr, client_width() * client_height() * 4);
|
||||
|
@ -33,40 +20,91 @@ Window::~Window()
|
|||
close(m_client_fd);
|
||||
}
|
||||
|
||||
void Window::prepare_title_bar(const LibFont::Font& font)
|
||||
BAN::ErrorOr<void> Window::initialize(BAN::StringView title, uint32_t width, uint32_t height)
|
||||
{
|
||||
const size_t title_bar_bytes = title_bar_width() * title_bar_height() * 4;
|
||||
uint32_t* title_bar_data = new uint32_t[title_bar_bytes];
|
||||
ASSERT(title_bar_data);
|
||||
for (size_t i = 0; i < title_bar_bytes; i++)
|
||||
title_bar_data[i] = 0xFFFFFFFF;
|
||||
m_title.clear();
|
||||
TRY(m_title.append(title));
|
||||
TRY(resize(width, height));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Window::resize(uint32_t width, uint32_t height)
|
||||
{
|
||||
const size_t fb_bytes = width * height * 4;
|
||||
|
||||
long smo_key = smo_create(fb_bytes, PROT_READ | PROT_WRITE);
|
||||
if (smo_key == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
BAN::ScopeGuard smo_deleter([&]() { smo_delete(smo_key); });
|
||||
|
||||
uint32_t* fb_addr = static_cast<uint32_t*>(smo_map(smo_key));
|
||||
if (fb_addr == nullptr)
|
||||
return BAN::Error::from_errno(errno);
|
||||
memset(fb_addr, 0xFF, fb_bytes);
|
||||
BAN::ScopeGuard smo_unmapper([&]() { munmap(fb_addr, fb_bytes); });
|
||||
|
||||
{
|
||||
const auto old_area = m_client_area;
|
||||
|
||||
m_client_area.width = width;
|
||||
m_client_area.height = height;
|
||||
auto title_bar_ret = prepare_title_bar();
|
||||
m_client_area = old_area;
|
||||
|
||||
if (title_bar_ret.is_error())
|
||||
return title_bar_ret.release_error();
|
||||
}
|
||||
|
||||
smo_deleter.disable();
|
||||
smo_unmapper.disable();
|
||||
|
||||
if (m_fb_addr)
|
||||
munmap(m_fb_addr, client_width() * client_height() * 4);
|
||||
if (m_smo_key)
|
||||
smo_delete(m_smo_key);
|
||||
|
||||
m_fb_addr = fb_addr;
|
||||
m_smo_key = smo_key;
|
||||
m_client_area.width = width;
|
||||
m_client_area.height = height;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Window::prepare_title_bar()
|
||||
{
|
||||
const uint32_t font_w = m_font.width();
|
||||
const uint32_t font_h = m_font.height();
|
||||
const uint32_t font_p = m_font.pitch();
|
||||
|
||||
TRY(m_title_bar_data.resize(title_bar_width() * title_bar_height()));
|
||||
for (auto& pixel : m_title_bar_data)
|
||||
pixel = 0xFFFFFFFF;
|
||||
|
||||
const auto text_area = title_text_area();
|
||||
|
||||
for (size_t i = 0; i < m_title.size() && (i + 1) * font.width() < static_cast<uint32_t>(text_area.width); i++)
|
||||
for (size_t i = 0; i < m_title.size() && (i + 1) * font_w < static_cast<uint32_t>(text_area.width); i++)
|
||||
{
|
||||
const auto* glyph = font.glyph(m_title[i]);
|
||||
const auto* glyph = m_font.glyph(m_title[i]);
|
||||
if (glyph == nullptr)
|
||||
continue;
|
||||
|
||||
const int32_t y_off = (font.height() < (uint32_t)title_bar_height()) ? (title_bar_height() - font.height()) / 2 : 0;
|
||||
const int32_t x_off = y_off + i * font.width();
|
||||
for (int32_t y = 0; (uint32_t)y < font.height(); y++)
|
||||
const int32_t y_off = (font_h < (uint32_t)title_bar_height()) ? (title_bar_height() - font_h) / 2 : 0;
|
||||
const int32_t x_off = y_off + i * font_w;
|
||||
for (int32_t y = 0; (uint32_t)y < font_h; y++)
|
||||
{
|
||||
if (y + y_off >= title_bar_height())
|
||||
break;
|
||||
for (int32_t x = 0; (uint32_t)x < font.width(); x++)
|
||||
for (int32_t x = 0; (uint32_t)x < font_w; x++)
|
||||
{
|
||||
if (x + x_off >= text_area.width)
|
||||
break;
|
||||
const uint8_t bitmask = 1 << (font.width() - x - 1);
|
||||
if (glyph[y * font.pitch()] & bitmask)
|
||||
title_bar_data[(y_off + y) * title_bar_width() + (x_off + x)] = 0xFF000000;
|
||||
const uint8_t bitmask = 1 << (font_w - x - 1);
|
||||
if (glyph[y * font_p] & bitmask)
|
||||
m_title_bar_data[(y_off + y) * title_bar_width() + (x_off + x)] = 0xFF000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_title_bar_data)
|
||||
delete[] m_title_bar_data;
|
||||
m_title_bar_data = title_bar_data;
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <BAN/RefPtr.h>
|
||||
#include <BAN/String.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <LibFont/Font.h>
|
||||
#include <LibGUI/Window.h>
|
||||
|
@ -11,7 +12,11 @@
|
|||
class Window : public BAN::RefCounted<Window>
|
||||
{
|
||||
public:
|
||||
Window(int fd, Rectangle area, long smo_key, BAN::StringView title, const LibFont::Font& font);
|
||||
Window(int fd, const LibFont::Font& font)
|
||||
: m_font(font)
|
||||
, m_client_fd(fd)
|
||||
{ }
|
||||
|
||||
~Window();
|
||||
|
||||
void set_position(Position position)
|
||||
|
@ -21,6 +26,7 @@ public:
|
|||
}
|
||||
|
||||
int client_fd() const { return m_client_fd; }
|
||||
long smo_key() const { return m_smo_key; }
|
||||
|
||||
int32_t client_x() const { return m_client_area.x; }
|
||||
int32_t client_y() const { return m_client_area.y; }
|
||||
|
@ -63,19 +69,25 @@ public:
|
|||
Circle close_button_area() const { return { title_bar_x() + title_bar_width() - title_bar_height() / 2, title_bar_y() + title_bar_height() / 2, title_bar_height() * 3 / 8 }; }
|
||||
Rectangle title_text_area() const { return { title_bar_x(), title_bar_y(), title_bar_width() - title_bar_height(), title_bar_height() }; }
|
||||
|
||||
BAN::ErrorOr<void> initialize(BAN::StringView title, uint32_t width, uint32_t height);
|
||||
BAN::ErrorOr<void> resize(uint32_t width, uint32_t height);
|
||||
|
||||
private:
|
||||
void prepare_title_bar(const LibFont::Font& font);
|
||||
BAN::ErrorOr<void> prepare_title_bar();
|
||||
|
||||
private:
|
||||
static constexpr int32_t m_title_bar_height { 20 };
|
||||
|
||||
const LibFont::Font& m_font;
|
||||
|
||||
const int m_client_fd { -1 };
|
||||
Rectangle m_client_area { 0, 0, 0, 0 };
|
||||
long m_smo_key { 0 };
|
||||
uint32_t* m_fb_addr { nullptr };
|
||||
uint32_t* m_title_bar_data { nullptr };
|
||||
BAN::String m_title;
|
||||
|
||||
BAN::Vector<uint32_t> m_title_bar_data;
|
||||
|
||||
LibGUI::Window::Attributes m_attributes { LibGUI::Window::default_attributes };
|
||||
|
||||
friend class BAN::RefPtr<Window>;
|
||||
|
|
|
@ -43,34 +43,10 @@ void WindowServer::on_window_create(int fd, const LibGUI::WindowPacket::WindowCr
|
|||
return;
|
||||
}
|
||||
|
||||
const uint32_t width = packet.width ? packet.width : m_framebuffer.width;
|
||||
const uint32_t width = packet.width ? packet.width : m_framebuffer.width;
|
||||
const uint32_t height = packet.height ? packet.height : m_framebuffer.height;
|
||||
|
||||
const size_t window_fb_bytes = width * height * 4;
|
||||
|
||||
long smo_key = smo_create(window_fb_bytes, PROT_READ | PROT_WRITE);
|
||||
if (smo_key == -1)
|
||||
{
|
||||
dwarnln("smo_create: {}", strerror(errno));
|
||||
return;
|
||||
}
|
||||
BAN::ScopeGuard smo_deleter([smo_key] { smo_delete(smo_key); });
|
||||
|
||||
Rectangle window_area {
|
||||
static_cast<int32_t>((m_framebuffer.width - width) / 2),
|
||||
static_cast<int32_t>((m_framebuffer.height - height) / 2),
|
||||
static_cast<int32_t>(width),
|
||||
static_cast<int32_t>(height)
|
||||
};
|
||||
|
||||
// Window::Window(int fd, Rectangle area, long smo_key, BAN::StringView title, const LibFont::Font& font)
|
||||
auto window_or_error = (BAN::RefPtr<Window>::create(
|
||||
fd,
|
||||
window_area,
|
||||
smo_key,
|
||||
packet.title,
|
||||
m_font
|
||||
));
|
||||
auto window_or_error = BAN::RefPtr<Window>::create(fd, m_font);
|
||||
if (window_or_error.is_error())
|
||||
{
|
||||
dwarnln("could not create window for client: {}", window_or_error.error());
|
||||
|
@ -85,17 +61,27 @@ void WindowServer::on_window_create(int fd, const LibGUI::WindowPacket::WindowCr
|
|||
}
|
||||
BAN::ScopeGuard window_popper([&] { m_client_windows.pop_back(); });
|
||||
|
||||
LibGUI::WindowPacket::WindowCreateResponse response;
|
||||
response.width = width;
|
||||
response.height = height;
|
||||
response.smo_key = smo_key;
|
||||
if (auto ret = window->initialize(packet.title, width, height); ret.is_error())
|
||||
{
|
||||
dwarnln("could not create window for client: {}", ret.error());
|
||||
return;
|
||||
}
|
||||
|
||||
window->set_position({
|
||||
static_cast<int32_t>((m_framebuffer.width - window->client_width()) / 2),
|
||||
static_cast<int32_t>((m_framebuffer.height - window->client_height()) / 2),
|
||||
});
|
||||
|
||||
LibGUI::EventPacket::ResizeWindowEvent response;
|
||||
response.width = window->client_width();
|
||||
response.height = window->client_height();
|
||||
response.smo_key = window->smo_key();
|
||||
if (auto ret = response.send_serialized(fd); ret.is_error())
|
||||
{
|
||||
dwarnln("could not respond to window create request: {}", ret.error());
|
||||
return;
|
||||
}
|
||||
|
||||
smo_deleter.disable();
|
||||
window_popper.disable();
|
||||
|
||||
set_focused_window(window);
|
||||
|
@ -139,6 +125,9 @@ void WindowServer::on_window_invalidate(int fd, const LibGUI::WindowPacket::Wind
|
|||
|
||||
void WindowServer::on_window_set_position(int fd, const LibGUI::WindowPacket::WindowSetPosition& packet)
|
||||
{
|
||||
if (m_is_fullscreen_window && m_focused_window->client_fd() == fd)
|
||||
return;
|
||||
|
||||
BAN::RefPtr<Window> target_window;
|
||||
for (auto& window : m_client_windows)
|
||||
{
|
||||
|
@ -232,6 +221,86 @@ void WindowServer::on_window_set_mouse_capture(int fd, const LibGUI::WindowPacke
|
|||
invalidate(cursor_area());
|
||||
}
|
||||
|
||||
void WindowServer::on_window_set_size(int fd, const LibGUI::WindowPacket::WindowSetSize& packet)
|
||||
{
|
||||
BAN::RefPtr<Window> target_window;
|
||||
for (auto& window : m_client_windows)
|
||||
{
|
||||
if (window->client_fd() != fd)
|
||||
continue;
|
||||
target_window = window;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!target_window)
|
||||
{
|
||||
dwarnln("client tried to set window size while not owning a window");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto old_area = target_window->full_area();
|
||||
|
||||
const uint32_t width = packet.width ? packet.width : m_framebuffer.width;
|
||||
const uint32_t height = packet.height ? packet.height : m_framebuffer.height;
|
||||
|
||||
if (auto ret = target_window->resize(width, height); ret.is_error())
|
||||
{
|
||||
dwarnln("could not resize client window {}", ret.error());
|
||||
return;
|
||||
}
|
||||
|
||||
LibGUI::EventPacket::ResizeWindowEvent response;
|
||||
response.width = target_window->client_width();
|
||||
response.height = target_window->client_height();
|
||||
response.smo_key = target_window->smo_key();
|
||||
if (auto ret = response.send_serialized(fd); ret.is_error())
|
||||
{
|
||||
dwarnln("could not respond to window resize request: {}", ret.error());
|
||||
return;
|
||||
}
|
||||
|
||||
invalidate(target_window->full_area().get_bounding_box(old_area));
|
||||
}
|
||||
|
||||
void WindowServer::on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::WindowSetFullscreen& packet)
|
||||
{
|
||||
if (m_is_fullscreen_window)
|
||||
{
|
||||
ASSERT(m_focused_window);
|
||||
if (m_focused_window->client_fd() != fd)
|
||||
dwarnln("client tried to set fullscreen window size while another window is already fullscreen");
|
||||
else if (!packet.fullscreen)
|
||||
{
|
||||
m_is_fullscreen_window = false;
|
||||
invalidate(m_framebuffer.area());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packet.fullscreen)
|
||||
return;
|
||||
|
||||
BAN::RefPtr<Window> target_window;
|
||||
for (auto& window : m_client_windows)
|
||||
{
|
||||
if (window->client_fd() != fd)
|
||||
continue;
|
||||
target_window = window;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!target_window)
|
||||
{
|
||||
dwarnln("client tried to set window size while not owning a window");
|
||||
return;
|
||||
}
|
||||
|
||||
m_is_fullscreen_window = true;
|
||||
set_focused_window(target_window);
|
||||
target_window->set_position({ 0, 0 });
|
||||
invalidate(m_framebuffer.area());
|
||||
}
|
||||
|
||||
void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||
{
|
||||
// Mod key is not passed to clients
|
||||
|
@ -274,7 +343,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
|||
}
|
||||
|
||||
// Toggle window bounce with F2
|
||||
if (event.pressed() && event.key == LibInput::Key::F2)
|
||||
if (!m_is_fullscreen_window && event.pressed() && event.key == LibInput::Key::F2)
|
||||
m_is_bouncing_window = !m_is_bouncing_window;
|
||||
|
||||
if (m_focused_window)
|
||||
|
@ -349,6 +418,9 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_is_fullscreen_window)
|
||||
m_is_moving_window = false;
|
||||
}
|
||||
|
||||
void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
|
||||
|
@ -470,6 +542,47 @@ static uint32_t alpha_blend(uint32_t color_a, uint32_t color_b)
|
|||
|
||||
void WindowServer::invalidate(Rectangle area)
|
||||
{
|
||||
if (m_is_fullscreen_window)
|
||||
{
|
||||
ASSERT(m_focused_window);
|
||||
|
||||
auto focused_overlap = area.get_overlap(m_focused_window->client_area());
|
||||
if (!focused_overlap.has_value())
|
||||
return;
|
||||
area = focused_overlap.release_value();
|
||||
|
||||
if (m_focused_window->client_area() == m_framebuffer.area())
|
||||
{
|
||||
for (int32_t y = area.y; y < area.y + area.height; y++)
|
||||
for (int32_t x = area.x; x < area.x + area.width; x++)
|
||||
m_framebuffer.mmap[y * m_framebuffer.width + x] = m_focused_window->framebuffer()[y * m_focused_window->client_width() + x];
|
||||
mark_pending_sync(area);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Rectangle dst_area {
|
||||
.x = area.x * m_framebuffer.width / m_focused_window->client_width(),
|
||||
.y = area.y * m_framebuffer.height / m_focused_window->client_height(),
|
||||
.width = BAN::Math::div_round_up(area.width * m_framebuffer.width, m_focused_window->client_width()),
|
||||
.height = BAN::Math::div_round_up(area.height * m_framebuffer.height, m_focused_window->client_height())
|
||||
};
|
||||
|
||||
for (int32_t dst_y = dst_area.y; dst_y < dst_area.y + dst_area.height; dst_y++)
|
||||
{
|
||||
for (int32_t dst_x = dst_area.x; dst_x < dst_area.x + dst_area.width; dst_x++)
|
||||
{
|
||||
const int32_t src_x = dst_x * m_focused_window->client_width() / m_framebuffer.width;
|
||||
const int32_t src_y = dst_y * m_focused_window->client_height() / m_framebuffer.height;
|
||||
m_framebuffer.mmap[dst_y * m_framebuffer.width + dst_x] = m_focused_window->framebuffer()[src_y * m_focused_window->client_width() + src_x];
|
||||
}
|
||||
}
|
||||
|
||||
mark_pending_sync(dst_area);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto fb_overlap = area.get_overlap(m_framebuffer.area());
|
||||
if (!fb_overlap.has_value())
|
||||
return;
|
||||
|
@ -686,6 +799,13 @@ void WindowServer::invalidate(Rectangle area)
|
|||
}
|
||||
}
|
||||
|
||||
mark_pending_sync(area);
|
||||
}
|
||||
|
||||
void WindowServer::mark_pending_sync(Rectangle area)
|
||||
{
|
||||
// FIXME: this marks too many pages
|
||||
|
||||
const uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
|
||||
const uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
|
||||
|
||||
|
@ -774,6 +894,12 @@ void WindowServer::remove_client_fd(int fd)
|
|||
return;
|
||||
m_client_data.remove(it);
|
||||
|
||||
if (m_is_fullscreen_window && m_focused_window->client_fd() == fd)
|
||||
{
|
||||
m_is_fullscreen_window = false;
|
||||
invalidate(m_framebuffer.area());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_client_windows.size(); i++)
|
||||
{
|
||||
auto window = m_client_windows[i];
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
void on_window_set_position(int fd, const LibGUI::WindowPacket::WindowSetPosition&);
|
||||
void on_window_set_attributes(int fd, const LibGUI::WindowPacket::WindowSetAttributes&);
|
||||
void on_window_set_mouse_capture(int fd, const LibGUI::WindowPacket::WindowSetMouseCapture&);
|
||||
void on_window_set_size(int fd, const LibGUI::WindowPacket::WindowSetSize&);
|
||||
void on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::WindowSetFullscreen&);
|
||||
|
||||
void on_key_event(LibInput::KeyEvent event);
|
||||
void on_mouse_button(LibInput::MouseButtonEvent event);
|
||||
|
@ -54,6 +56,9 @@ public:
|
|||
|
||||
bool is_stopped() const { return m_is_stopped; }
|
||||
|
||||
private:
|
||||
void mark_pending_sync(Rectangle area);
|
||||
|
||||
private:
|
||||
Framebuffer& m_framebuffer;
|
||||
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
|
||||
|
@ -68,6 +73,7 @@ private:
|
|||
|
||||
bool m_is_mod_key_held { false };
|
||||
bool m_is_moving_window { false };
|
||||
bool m_is_fullscreen_window { false };
|
||||
BAN::RefPtr<Window> m_focused_window;
|
||||
Position m_cursor;
|
||||
|
||||
|
|
|
@ -165,6 +165,19 @@ int main()
|
|||
|
||||
atexit([]() { tty_ctrl(STDIN_FILENO, TTY_CMD_SET, TTY_FLAG_ENABLE_INPUT); });
|
||||
|
||||
constexpr int non_terminating_signals[] {
|
||||
SIGCHLD,
|
||||
SIGCONT,
|
||||
SIGSTOP,
|
||||
SIGTSTP,
|
||||
SIGTTIN,
|
||||
SIGTTOU,
|
||||
};
|
||||
for (int sig = _SIGMIN; sig <= _SIGMAX; sig++)
|
||||
signal(sig, exit);
|
||||
for (int sig : non_terminating_signals)
|
||||
signal(sig, SIG_DFL);
|
||||
|
||||
MUST(LibInput::KeyboardLayout::initialize());
|
||||
MUST(LibInput::KeyboardLayout::get().load_from_file("/usr/share/keymaps/us.keymap"_sv));
|
||||
|
||||
|
@ -354,6 +367,14 @@ int main()
|
|||
if (auto ret = LibGUI::WindowPacket::WindowSetMouseCapture::deserialize(client_data.packet_buffer.span()); !ret.is_error())
|
||||
window_server.on_window_set_mouse_capture(fd, ret.release_value());
|
||||
break;
|
||||
case LibGUI::PacketType::WindowSetSize:
|
||||
if (auto ret = LibGUI::WindowPacket::WindowSetSize::deserialize(client_data.packet_buffer.span()); !ret.is_error())
|
||||
window_server.on_window_set_size(fd, ret.release_value());
|
||||
break;
|
||||
case LibGUI::PacketType::WindowSetFullscreen:
|
||||
if (auto ret = LibGUI::WindowPacket::WindowSetFullscreen::deserialize(client_data.packet_buffer.span()); !ret.is_error())
|
||||
window_server.on_window_set_fullscreen(fd, ret.release_value());
|
||||
break;
|
||||
default:
|
||||
dprintln("unhandled packet type: {}", *reinterpret_cast<uint32_t*>(client_data.packet_buffer.data()));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue