152 lines
3.5 KiB
C++
152 lines
3.5 KiB
C++
#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;
|
|
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<daguerre::hilbert_color> 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");
|
|
|
|
int x, y;
|
|
r->get_cursor(x, y);
|
|
|
|
window *w = new window(x, y);
|
|
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);
|
|
|
|
}
|