diff options
Diffstat (limited to 'applications/goldman/source/socket.cpp')
-rw-r--r-- | applications/goldman/source/socket.cpp | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/applications/goldman/source/socket.cpp b/applications/goldman/source/socket.cpp new file mode 100644 index 0000000..b175fe9 --- /dev/null +++ b/applications/goldman/source/socket.cpp @@ -0,0 +1,162 @@ +#include <daguerre/image.hpp> +#include "socket.hpp" +#include "window.hpp" +#include "main.hpp" +#include <memory> +#include <vector> + +struct socket_state { + + euler::syscall::stream_handle socket; + std::vector<window *> 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<daguerre::hilbert_color> 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<daguerre::hilbert_color> + 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); + +} |