apio
ac260d0397
All checks were successful
Build and test / build (push) Successful in 1m42s
This segments privileges more, making it so that any app connecting to wsys.sock can't just always access every single advanced feature in wind if they don't need to. Of course, apps have to restrict themselves, which is why only privileged apps have access to this feature in the first place. Normal apps' pledges are all empty and can't be changed. An example: taskbar uses the "ExtendedLayers" pledge to move its window to the background, but relinquishes it afterwards, and doesn't need any other advanced feature for now. If a pledge-capable app tries to use a pledge-protected function without having pledged anything, it can't. Pledges are mandatory if you want to access certain functionality, unlike the kernel's pledges which make every syscall available if you don't use pledge().
230 lines
8.2 KiB
C++
230 lines
8.2 KiB
C++
#include "IPC.h"
|
|
#include "Layer.h"
|
|
#include "Mouse.h"
|
|
#include "Screen.h"
|
|
#include <luna/Alignment.h>
|
|
#include <luna/RefString.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(RefString::from_cstring("Window"));
|
|
|
|
auto shm_path = TRY_OR_IPC_ERROR(RefString::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] {
|
|
window->layer->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 = TRY(RefString::from_string(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;
|
|
window->layer->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_window_layer_message(Client& client)
|
|
{
|
|
ui::SetWindowLayer request;
|
|
if (!TRY(client.conn->read_message(request))) return {};
|
|
|
|
if (request.layer != ui::Layer::Global && request.layer != ui::Layer::GlobalTop)
|
|
{
|
|
if (!client.check_pledge(ui::Pledge::ExtendedLayers)) return {};
|
|
}
|
|
|
|
CHECK_WINDOW_ID(request, "SetWindowLayer");
|
|
|
|
auto* window = client.windows[request.window];
|
|
|
|
window->layer->windows.remove(window);
|
|
|
|
switch (request.layer)
|
|
{
|
|
case ui::Layer::Background: window->layer = &l_background; break;
|
|
case ui::Layer::Global: window->layer = &l_global; break;
|
|
case ui::Layer::GlobalTop: window->layer = &l_global_top; break;
|
|
case ui::Layer::System: window->layer = &l_system; break;
|
|
case ui::Layer::Lock: window->layer = &l_lock; break;
|
|
default: {
|
|
window->layer->windows.append(window);
|
|
os::eprintln("wind: Client trying to set window layer to an invalid layer, disconnecting!");
|
|
client.should_be_disconnected = true;
|
|
return {};
|
|
}
|
|
}
|
|
|
|
window->layer->windows.append(window);
|
|
|
|
return {};
|
|
}
|
|
|
|
static Result<void> handle_update_pledge_request_message(Client& client)
|
|
{
|
|
ui::UpdatePledgeRequest request;
|
|
if (!TRY(client.conn->read_message(request))) return {};
|
|
|
|
client.update_pledges(request.pledges); // update_pledges does all the checking.
|
|
|
|
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_WINDOW_LAYER_ID: handle_set_window_layer_message(client); break;
|
|
case ui::UPDATE_PLEDGE_REQUEST_ID: handle_update_pledge_request_message(client); break;
|
|
default: os::eprintln("wind: Invalid IPC message from client!"); return;
|
|
}
|
|
}
|
|
}
|