#include #include "socket.hpp" #include "window.hpp" #include "main.hpp" #include #include struct socket_state { euler::syscall::stream_handle socket; window *w; bool try_show_window() { if (w->is_shown) return false; r->lock(); r->add_window(w); r->unlock(); r->dispatch_render(); return true; } bool try_hide_window() { if (!w->is_shown) return false; r->lock(); r->remove_window(w); r->unlock(); r->dispatch_render(); return true; } bool try_set_window_dimensions() { struct [[gnu::packed]] { uint32_t width; uint32_t height; } packet; if (euler::syscall::read_from_stream(socket, sizeof(packet), &packet) != euler::syscall::stream_result::success) return false; if (packet. width > __INT_MAX__ - window::decorations_extra_width || packet.height > __INT_MAX__ - window::decorations_extra_height) return false; r->lock(); w->set_size(packet.width, packet.height); w->draw_decorations(r->is_top(w)); r->unlock(); return true; } bool try_set_window_title() { uint32_t length; if (euler::syscall::read_from_stream(socket, 4, &length) != euler::syscall::stream_result::success) return false; std::string title; title.resize(length); if (euler::syscall::read_from_stream(socket, length, title.data()) != euler::syscall::stream_result::success) return false; r->lock(); w->title = std::move(title); w->draw_decorations(r->is_top(w)); r->unlock(); r->dispatch_render(); return true; } bool try_update_window_region() { struct [[gnu::packed]] { uint32_t start_x; uint32_t start_y; uint32_t width; uint32_t height; } packet; if (euler::syscall::read_from_stream(socket, sizeof(packet), &packet) != euler::syscall::stream_result::success) return false; static_assert(__INT_MAX__ <= __UINT64_MAX__); if ((uint64_t)packet.start_x + packet. width > (uint64_t)w->contents. width || (uint64_t)packet.start_y + packet.height > (uint64_t)w->contents.height) return false; daguerre::image content(packet.width, packet.height); if (euler::syscall::read_from_stream( socket, packet.width * packet.height * 4, content.buffer) != euler::syscall::stream_result::success) return false; r->lock(); w->contents.copy_from(content, packet.start_x, packet.start_y); r->unlock(); r->dispatch_render(); return true; } bool try_process_request() { uint8_t type; if (euler::syscall::read_from_stream(socket, 1, &type) != euler::syscall::stream_result::success) return false; switch (type) { case 0x00: return try_show_window(); case 0x01: return try_hide_window(); case 0x02: return try_set_window_dimensions(); case 0x03: return try_set_window_title(); case 0x04: return try_update_window_region(); default: return false; } } }; [[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket) { euler::syscall::set_thread_name("socket thread"); window *w = new window(); socket_state *state = new socket_state { .socket = socket, .w = w }; while (state->try_process_request()) ; if (w->is_shown) { r->lock(); r->remove_window(w); r->unlock(); } delete state; delete w; euler::syscall::close_stream(socket); euler::syscall::end_this_thread(0); }