202 lines
7.2 KiB
C++
202 lines
7.2 KiB
C++
#include "IPC.h"
|
|
#include "Mouse.h"
|
|
#include "Screen.h"
|
|
#include <luna/Alignment.h>
|
|
#include <luna/String.h>
|
|
#include <os/File.h>
|
|
#include <os/SharedMemory.h>
|
|
#include <sys/mman.h>
|
|
#include <time.h>
|
|
|
|
#define TRY_OR_IPC_ERROR(expr) \
|
|
({ \
|
|
auto _expr_rc = (expr); \
|
|
if (!_expr_rc.has_value()) \
|
|
{ \
|
|
client.conn->send_error(_expr_rc.error()); \
|
|
return {}; \
|
|
} \
|
|
_expr_rc.release_value(); \
|
|
})
|
|
|
|
#define CHECK_WINDOW_ID(request, context) \
|
|
do { \
|
|
if ((usize)request.window >= client.windows.size() || !client.windows[request.window]) \
|
|
{ \
|
|
os::eprintln("wind: Window id is invalid! (%s)", context); \
|
|
return {}; \
|
|
} \
|
|
} while (0)
|
|
|
|
static Result<void> handle_create_window_message(Client& client)
|
|
{
|
|
ui::CreateWindowRequest request;
|
|
if (!TRY(client.conn->read_message(request))) return {};
|
|
|
|
request.rect = request.rect.normalized();
|
|
|
|
auto name = TRY_OR_IPC_ERROR(String::from_cstring("Window"));
|
|
|
|
auto shm_path = TRY_OR_IPC_ERROR(String::format("/wind-shm-%d-%lu"_sv, client.conn->fd(), time(NULL)));
|
|
|
|
auto* window = new (std::nothrow) Window(request.rect, move(name));
|
|
if (!window)
|
|
{
|
|
client.conn->send_error(ENOMEM);
|
|
return {};
|
|
}
|
|
|
|
auto guard = make_scope_guard([window] {
|
|
g_windows.remove(window);
|
|
delete window;
|
|
});
|
|
|
|
window->pixels = (u32*)TRY_OR_IPC_ERROR(
|
|
os::SharedMemory::create(shm_path.view(), window->surface.height * window->surface.width * 4));
|
|
|
|
TRY_OR_IPC_ERROR(client.windows.try_append(window));
|
|
int id = static_cast<int>(client.windows.size() - 1);
|
|
|
|
// No more fallible operations, this operation is guaranteed to succeed now.
|
|
guard.deactivate();
|
|
|
|
window->client = &client;
|
|
window->id = id;
|
|
|
|
ui::CreateWindowResponse response;
|
|
response.window = id;
|
|
SET_IPC_STRING(response.shm_path, shm_path.chars());
|
|
window->shm_path = move(shm_path);
|
|
client.conn->send_async(response);
|
|
return {};
|
|
}
|
|
|
|
static Result<void> handle_remove_shm_message(Client& client)
|
|
{
|
|
ui::RemoveSharedMemoryRequest request;
|
|
if (!TRY(client.conn->read_message(request))) return {};
|
|
|
|
CHECK_WINDOW_ID(request, "RemoveShm");
|
|
|
|
shm_unlink(client.windows[request.window]->shm_path.chars());
|
|
|
|
return {};
|
|
}
|
|
|
|
static Result<void> handle_set_window_title_message(Client& client)
|
|
{
|
|
ui::SetWindowTitleRequest request;
|
|
if (!TRY(client.conn->read_message(request))) return {};
|
|
|
|
auto name = COPY_IPC_STRING(request.title);
|
|
|
|
os::println("wind: SetWindowTitle(\"%s\") for window %d", name.chars(), request.window);
|
|
|
|
CHECK_WINDOW_ID(request, "SetWindowTitle");
|
|
|
|
client.windows[request.window]->name = move(name);
|
|
|
|
return {};
|
|
}
|
|
|
|
static Result<void> handle_invalidate_message(Client& client)
|
|
{
|
|
ui::InvalidateRequest request;
|
|
if (!TRY(client.conn->read_message(request))) return {};
|
|
|
|
CHECK_WINDOW_ID(request, "Invalidate");
|
|
|
|
client.windows[request.window]->dirty = true;
|
|
|
|
return {};
|
|
}
|
|
|
|
static Result<void> handle_close_window_message(Client& client)
|
|
{
|
|
ui::CloseWindowRequest request;
|
|
if (!TRY(client.conn->read_message(request))) return {};
|
|
|
|
CHECK_WINDOW_ID(request, "CloseWindow");
|
|
|
|
auto* window = client.windows[request.window];
|
|
client.windows[request.window] = nullptr;
|
|
g_windows.remove(window);
|
|
Mouse::the().window_did_close(window);
|
|
delete window;
|
|
|
|
return {};
|
|
}
|
|
|
|
static Result<void> handle_get_screen_rect_message(Client& client)
|
|
{
|
|
ui::GetScreenRectRequest request;
|
|
if (!TRY(client.conn->read_message(request))) return {}; // Kinda pointless, but required.
|
|
|
|
ui::GetScreenRectResponse response;
|
|
response.rect = Screen::the().canvas().rect();
|
|
client.conn->send_async(response);
|
|
|
|
return {};
|
|
}
|
|
|
|
static Result<void> handle_set_titlebar_height_message(Client& client)
|
|
{
|
|
ui::SetTitlebarHeightRequest request;
|
|
if (!TRY(client.conn->read_message(request))) return {};
|
|
|
|
if (request.height < 0) request.height = 0;
|
|
|
|
CHECK_WINDOW_ID(request, "SetTitlebarHeight");
|
|
|
|
auto* window = client.windows[request.window];
|
|
|
|
if (request.height > window->surface.height)
|
|
{
|
|
os::eprintln("wind: SetTitlebarHeight: titlebar height bigger than window!");
|
|
return {};
|
|
}
|
|
|
|
window->titlebar = ui::Rect { 0, 0, window->surface.width, request.height };
|
|
return {};
|
|
}
|
|
|
|
static Result<void> handle_set_special_window_attributes_message(Client& client)
|
|
{
|
|
ui::SetSpecialWindowAttributesRequest request;
|
|
if (!TRY(client.conn->read_message(request))) return {};
|
|
|
|
if (!client.privileged)
|
|
{
|
|
os::eprintln(
|
|
"wind: Unprivileged client trying to call privileged request (SetSpecialWindowAttributes), disconnecting!");
|
|
client.should_be_disconnected = true;
|
|
return {};
|
|
}
|
|
|
|
CHECK_WINDOW_ID(request, "SetSpecialWindowAttributes");
|
|
|
|
client.windows[request.window]->attributes = request.attributes;
|
|
|
|
return {};
|
|
}
|
|
|
|
namespace wind
|
|
{
|
|
void handle_ipc_message(os::IPC::ClientConnection&, u8 id, void* c)
|
|
{
|
|
Client& client = *(Client*)c;
|
|
switch (id)
|
|
{
|
|
case ui::CREATE_WINDOW_ID: handle_create_window_message(client); break;
|
|
case ui::REMOVE_SHM_ID: handle_remove_shm_message(client); break;
|
|
case ui::SET_WINDOW_TITLE_ID: handle_set_window_title_message(client); break;
|
|
case ui::INVALIDATE_ID: handle_invalidate_message(client); break;
|
|
case ui::CLOSE_WINDOW_ID: handle_close_window_message(client); break;
|
|
case ui::GET_SCREEN_RECT_ID: handle_get_screen_rect_message(client); break;
|
|
case ui::SET_TITLEBAR_HEIGHT_ID: handle_set_titlebar_height_message(client); break;
|
|
case ui::SET_SPECIAL_WINDOW_ATTRIBUTES_ID: handle_set_special_window_attributes_message(client); break;
|
|
default: os::eprintln("wind: Invalid IPC message from client!"); return;
|
|
}
|
|
}
|
|
}
|