#include "IPC.h" #include "Mouse.h" #include "Screen.h" #include #include #include #include #include #include #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 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(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 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 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 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 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 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 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 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; } } }