#include #include "socket.hpp" #include "window.hpp" #include "main.hpp" #include #include struct socket_state { euler::syscall::stream_handle socket; std::vector windows; daguerre::hilbert_color window_bg = euler::syscall::encode_color(0, 0, 0); bool try_open_window() { struct [[gnu::packed]] { uint32_t width; uint32_t height; } body; if (euler::syscall::read_from_stream(socket, sizeof(body), &body) != euler::syscall::stream_result::success) return false; window *w = new window(body.width, body.height); w->contents.fill(window_bg); uint16_t wid = 0; while (wid < windows.size()) if (windows[wid] != 0) ++wid; else break; if (wid == windows.size()) windows.push_back(w); else windows[wid] = w; r->lock(); r->add_window(w); r->unlock(); struct [[gnu::packed]] { uint8_t type; uint16_t the_window; } response { .type = 0x00, .the_window = wid }; return euler::syscall::write_to_stream(socket, sizeof(response), &response) == euler::syscall::stream_result::success; } bool try_update_window_region() { struct [[gnu::packed]] { uint16_t window; uint32_t start_x; uint32_t start_y; uint32_t width; uint32_t height; } body_head; if (euler::syscall::read_from_stream(socket, sizeof(body_head), &body_head) != euler::syscall::stream_result::success) return false; std::vector data(body_head.width * body_head.height); if (euler::syscall::read_from_stream(socket, data.size() * 4, data.data()) != euler::syscall::stream_result::success) return false; daguerre::image data_as_image(body_head.width, body_head.height, data.data(), body_head.width, false); if (body_head.window >= windows.size() || !windows[body_head.window]) return false; window *w = windows[body_head.window]; r->lock(); if ((int)body_head.start_x + data_as_image.width > w->contents.width || (int)body_head.start_y + data_as_image.height > w->contents.height) { r->unlock(); return false; } w->contents.copy_from(data_as_image, body_head.start_x, body_head.start_y); r->unlock(); r->dispatch_render(); return true; } bool try_close_window() { uint16_t wid; if (euler::syscall::read_from_stream(socket, 2, &wid) != euler::syscall::stream_result::success) return false; if (wid >= windows.size() || !windows[wid]) return false; r->lock(); r->remove_window(windows[wid]); windows[wid] = 0; 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_open_window(); case 0x01: return try_update_window_region(); case 0x02: return try_close_window(); default: return false; } } }; [[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket) { euler::syscall::set_thread_name("socket thread"); socket_state *state = new socket_state { .socket = socket, .windows = {} }; while (state->try_process_request()) ; r->lock(); for (unsigned i = 0; i < state->windows.size(); ++i) { r->remove_window(state->windows[i]); delete state->windows[i]; } r->unlock(); delete state; euler::syscall::close_stream(socket); euler::syscall::end_this_thread(0); }