summaryrefslogtreecommitdiff
path: root/applications/goldman/source/socket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'applications/goldman/source/socket.cpp')
-rw-r--r--applications/goldman/source/socket.cpp162
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);
+
+}