Compare commits

..

No commits in common. "397ed396d89e06857a96125caea92cf1c304e5b5" and "c0ca99bc7cf0df1b6a7602f147d24f8b91b6cd54" have entirely different histories.

32 changed files with 26 additions and 566 deletions

View File

@ -1,23 +1,5 @@
#include <os/ArgumentParser.h>
#include <os/File.h>
#include <os/LocalClient.h>
#include <ui/ipc/Server.h>
#include <unistd.h>
Result<void> handle_ipc_client_event(os::LocalClient&, u8)
{
todo();
}
Result<int> create_window(os::LocalClient& client, ui::Rect rect, StringView name, ui::Color color)
{
ui::CreateWindowRequest request;
request.rect = rect;
SET_IPC_STRING(request.name, name.chars());
request.color = color;
auto response = TRY(os::IPC::send_sync<ui::CreateWindowResponse>(client, request));
return response.window;
}
Result<int> luna_main(int argc, char** argv)
{
@ -31,16 +13,8 @@ Result<int> luna_main(int argc, char** argv)
auto client = TRY(os::LocalClient::connect(socket_path, false));
int id = TRY(create_window(*client, ui::Rect { 200, 200, 400, 300 }, "My Window", ui::CYAN));
os::println("Created new window with id %d!", id);
sleep(3);
id =
TRY(create_window(*client, ui::Rect { 100, 100, 200, 150 }, "Super Long Name that is Way Too Long ", ui::BLUE));
os::println("Created new window with id %d!", id);
sleep(6);
StringView message = "hello";
TRY(client->send((const u8*)message.chars(), message.length()));
return 0;
}

View File

@ -69,8 +69,6 @@ class Socket : public VFS::FileInode
virtual bool can_read_data() const = 0;
virtual bool peer_disconnected() const = 0;
virtual ~Socket() = default;
protected:

View File

@ -27,11 +27,6 @@ class UnixSocket : public Socket
return !m_listen_queue.is_empty();
}
bool peer_disconnected() const override
{
return m_state == Reset;
}
Result<usize> send(const u8*, usize, int) override;
Result<usize> recv(u8*, usize, int) const override;

View File

@ -56,11 +56,6 @@ Result<u64> sys_poll(Registers*, SyscallArgs args)
fds_with_events++;
kfds[i].revents |= POLLIN;
}
if (socket->peer_disconnected())
{
fds_with_events++;
kfds[i].revents |= POLLHUP;
}
}
else
{

View File

@ -8,7 +8,6 @@
#define POLLIN (1 << 0)
#define POLLERR (1 << 1)
#define POLLNVAL (1 << 2)
#define POLLHUP (1 << 3)
typedef __u64_t nfds_t;

View File

@ -16,7 +16,6 @@ set(SOURCES
src/Security.cpp
src/LocalServer.cpp
src/LocalClient.cpp
src/IPC.cpp
)
add_library(os ${SOURCES})

View File

@ -1,157 +0,0 @@
/**
* @file IPC.h
* @author apio (cloudapio.eu)
* @brief Inter-process communication primitives.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <os/LocalClient.h>
#include <os/LocalServer.h>
#define IPC_ENUM_SERVER(name) __##name##_SERVER_ERROR = 0
#define IPC_ENUM_CLIENT(name) __##name##_CLIENT_ERROR = 0
/**
* @brief Called to handle IPC events (client-side).
*
* @param conn The connection object being used.
* @param id The ID of the message.
* @return Result<void> Whether the operation succeded.
*/
extern Result<void> handle_ipc_client_event(os::LocalClient& conn, u8 id);
/**
* @brief Called to handle IPC events (server-side).
*
* @param conn The connection object being used.
* @param id The ID of the message.
* @return Result<void> Whether the operation succeded.
*/
extern Result<void> handle_ipc_server_event(os::LocalServer::Client& conn, u8 id);
namespace os
{
namespace IPC
{
static constexpr usize IPC_STRING_LENGTH = 256;
#define IPC_STRING(name) char name[os::IPC::IPC_STRING_LENGTH];
#define COPY_IPC_STRING(name) \
TRY(String::from_string_view(StringView::from_fixed_size_cstring(name, os::IPC::IPC_STRING_LENGTH)))
#define SET_IPC_STRING(name, value) strlcpy(name, value, os::IPC::IPC_STRING_LENGTH)
/**
* @brief Sends an IPC message without waiting for a reply.
*
* @tparam Client The type of the client interface being used to communicate.
* @tparam T The type of the message.
* @param client The connection object being used to communicate.
* @param message The IPC message.
* @return Result<void> Whether the operation succeded.
*/
template <typename Client, typename T> Result<void> send_async(Client& client, const T& message)
{
u8 id = T::id;
TRY(client.send_typed(id));
TRY(client.send_typed(message));
return {};
}
/**
* @brief Sends an error result to the IPC connection, indicating that an operation could not be performed.
*
* @tparam Client The type of the client interface being used to communicate.
* @param client The connection object being used to communicate.
* @param error The error code.
* @return Result<void> Whether the operation succeded.
*/
template <typename Client> Result<void> send_error(Client& client, int error)
{
u8 id = 0;
TRY(client.send_typed(id));
TRY(client.send_typed(error));
return {};
}
/**
* @brief Sends an IPC message and waits for a reply (client-only).
*
* @tparam ResponseType The type of the response.
* @tparam T The type of the message.
* @param client The connection object being used to communicate.
* @param message The IPC message.
* @param handler The function used to handle messages that do not match the reply.
* @return Result<ResponseType> An error, or the response.
*/
template <typename ResponseType, typename T>
Result<ResponseType> send_sync(os::LocalClient& client, const T& message,
decltype(handle_ipc_client_event) handler = handle_ipc_client_event)
{
u8 id = T::id;
TRY(client.send_typed(id));
TRY(client.send_typed(message));
// We allow receiving 5 messages of different types, but if those have passed and we still don't have a
// reply, fail with ENOMSG.
int max_other_messages = 5;
while (max_other_messages)
{
u8 response_id;
auto rc = client.recv_typed(response_id);
if (rc.has_error() && rc.error() == EAGAIN) continue;
if (response_id == 0) // Error result
{
while (1)
{
int code;
rc = client.recv_typed(code);
if (rc.has_error() && rc.error() == EAGAIN) continue;
return err(code);
}
}
if (response_id != ResponseType::id)
{
TRY(handler(client, response_id));
max_other_messages--;
continue;
}
while (1)
{
ResponseType response;
rc = client.recv_typed(response);
if (rc.has_error() && rc.error() == EAGAIN) continue;
return response;
}
}
return err(ENOMSG);
}
/**
* @brief Check for new IPC messages on a connection and handle them appropriately.
*
* @param client The client connection.
* @param handler The function used to handle messages.
* @return Result<void> Whether the operation succeded.
*/
Result<void> check_for_messages(os::LocalClient& client,
decltype(handle_ipc_client_event) handler = handle_ipc_client_event);
/**
* @brief Check for new IPC messages on a connection and handle them appropriately.
*
* @param server The server connection.
* @param handler The function used to handle messages.
* @return Result<void> Whether the operation succeded.
*/
Result<void> check_for_messages(os::LocalServer::Client& server,
decltype(handle_ipc_server_event) handler = handle_ipc_server_event);
}
}

View File

@ -1,12 +1,3 @@
/**
* @file LocalClient.h
* @author apio (cloudapio.eu)
* @brief UNIX local domain client class.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <luna/OwnedPtr.h>
#include <luna/StringView.h>

View File

@ -1,12 +1,3 @@
/**
* @file LocalServer.h
* @author apio (cloudapio.eu)
* @brief UNIX local domain server class.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <luna/OwnedPtr.h>
#include <luna/Result.h>

View File

@ -1,39 +0,0 @@
/**
* @file IPC.cpp
* @author apio (cloudapio.eu)
* @brief Inter-process communication primitives.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <os/IPC.h>
namespace os::IPC
{
Result<void> check_for_messages(os::LocalClient& client, decltype(handle_ipc_client_event) handler)
{
u8 id;
auto rc = client.recv_typed(id);
if (rc.has_error())
{
if (rc.error() == EAGAIN) return {}; // No messages, and the caller does not want us to block.
return rc.release_error();
}
return handler(client, id);
}
Result<void> check_for_messages(os::LocalServer::Client& client, decltype(handle_ipc_server_event) handler)
{
u8 id;
auto rc = client.recv_typed(id);
if (rc.has_error())
{
if (rc.error() == EAGAIN) return {}; // No messages, and the caller does not want us to block.
return rc.release_error();
}
return handler(client, id);
}
}

View File

@ -1,12 +1,3 @@
/**
* @file LocalClient.cpp
* @author apio (cloudapio.eu)
* @brief UNIX local domain client class.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <errno.h>
#include <fcntl.h>
#include <os/LocalClient.h>

View File

@ -1,12 +1,3 @@
/**
* @file LocalServer.cpp
* @author apio (cloudapio.eu)
* @brief UNIX local domain server class.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <errno.h>
#include <fcntl.h>
#include <os/FileSystem.h>

View File

@ -4,8 +4,6 @@ file(GLOB HEADERS include/ui/*.h)
set(SOURCES
${HEADERS}
include/ui/ipc/Server.h
include/ui/ipc/Client.h
src/Canvas.cpp
src/Rect.cpp
src/Font.cpp

View File

@ -1,12 +1,3 @@
/**
* @file Canvas.h
* @author apio (cloudapio.eu)
* @brief Drawable surfaces.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <luna/Result.h>
#include <luna/Types.h>

View File

@ -1,12 +1,3 @@
/**
* @file Color.h
* @author apio (cloudapio.eu)
* @brief RGBA colors.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <luna/Types.h>

View File

@ -1,12 +1,3 @@
/**
* @file Font.h
* @author apio (cloudapio.eu)
* @brief PSF font loading and rendering.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <luna/Buffer.h>
#include <luna/SharedPtr.h>

View File

@ -1,12 +1,3 @@
/**
* @file Image.h
* @author apio (cloudapio.eu)
* @brief TGA image loading and rendering.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <luna/Buffer.h>
#include <luna/SharedPtr.h>

View File

@ -1,12 +1,3 @@
/**
* @file Point.h
* @author apio (cloudapio.eu)
* @brief 2D space points.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
namespace ui

View File

@ -1,12 +1,3 @@
/**
* @file Rect.h
* @author apio (cloudapio.eu)
* @brief A simple 2D rectangle representation.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <ui/Point.h>

View File

@ -1,27 +0,0 @@
/**
* @file ipc/Client.h
* @author apio (cloudapio.eu)
* @brief IPC message definitions for UI messages sent to the client.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <os/IPC.h>
namespace ui
{
enum ClientMessages : u8
{
IPC_ENUM_CLIENT(ui),
CREATE_WINDOW_RESPONSE_ID,
};
struct CreateWindowResponse
{
static constexpr u8 id = CREATE_WINDOW_RESPONSE_ID;
int window;
};
}

View File

@ -1,33 +0,0 @@
/**
* @file ipc/Server.h
* @author apio (cloudapio.eu)
* @brief IPC message definitions for UI messages sent to the server.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <os/IPC.h>
#include <ui/Color.h>
#include <ui/Rect.h>
#include <ui/ipc/Client.h>
namespace ui
{
enum ServerMessages : u8
{
IPC_ENUM_SERVER(ui),
CREATE_WINDOW_ID,
};
struct CreateWindowRequest
{
using ResponseType = CreateWindowResponse;
static constexpr u8 id = CREATE_WINDOW_ID;
ui::Rect rect;
IPC_STRING(name);
ui::Color color;
};
}

View File

@ -1,12 +1,3 @@
/**
* @file Canvas.cpp
* @author apio (cloudapio.eu)
* @brief Drawable surfaces.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <ui/Canvas.h>
namespace ui

View File

@ -1,12 +1,3 @@
/**
* @file Font.cpp
* @author apio (cloudapio.eu)
* @brief PSF font loading and rendering.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <luna/String.h>
#include <os/File.h>
#include <ui/Font.h>

View File

@ -1,12 +1,3 @@
/**
* @file Image.cpp
* @author apio (cloudapio.eu)
* @brief TGA image loading and rendering.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <os/File.h>
#include <ui/Image.h>

View File

@ -1,12 +1,3 @@
/**
* @file Rect.cpp
* @author apio (cloudapio.eu)
* @brief A simple 2D rectangle representation.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <ui/Rect.h>
namespace ui

View File

@ -6,9 +6,6 @@ set(SOURCES
Mouse.cpp
Window.h
Window.cpp
IPC.cpp
IPC.h
Client.h
)
add_executable(wind ${SOURCES})

View File

@ -1,11 +0,0 @@
#pragma once
#include "Window.h"
#include <os/LocalServer.h>
struct Client
{
os::LocalServer::Client conn;
Vector<Window*> windows;
bool rpc_in_progress { false };
u8 rpc_id { 0 };
};

View File

@ -1,75 +0,0 @@
#include "IPC.h"
#include <luna/String.h>
#include <os/File.h>
static Result<void> handle_create_window_message(Client& client)
{
ui::CreateWindowRequest request;
auto rc = client.conn.recv_typed(request);
if (rc.has_error())
{
if (rc.error() == EAGAIN)
{
client.rpc_in_progress = true;
client.rpc_id = ui::CREATE_WINDOW_ID;
return {};
}
else
return rc.release_error();
}
request.rect = request.rect.normalized();
request.rect.height += Window::titlebar_height(); // Make sure we provide the full contents rect that was asked for.
auto name = COPY_IPC_STRING(request.name);
auto* window = new (std::nothrow) Window(request.rect, request.color, move(name));
if (!window)
{
os::IPC::send_error(client.conn, ENOMEM);
return {};
}
int id = static_cast<int>(client.windows.size());
rc = client.windows.try_append(window);
if (rc.has_error())
{
delete window;
os::IPC::send_error(client.conn, rc.error());
return {};
}
ui::CreateWindowResponse response;
response.window = id;
os::IPC::send_async(client.conn, response);
return {};
}
namespace wind
{
Result<void> handle_ipc_message(Client& client, u8 id)
{
client.rpc_in_progress = false;
switch (id)
{
case ui::CREATE_WINDOW_ID: return handle_create_window_message(client);
default: os::eprintln("wind: Invalid IPC message from client!"); return err(EINVAL);
}
}
Result<void> handle_ipc(Client& client)
{
if (client.rpc_in_progress) return handle_ipc_message(client, client.rpc_id);
u8 id;
auto rc = client.conn.recv_typed(id);
if (rc.has_error())
{
if (rc.error() == EAGAIN) { return {}; }
else
return rc.release_error();
}
return handle_ipc_message(client, id);
}
}

View File

@ -1,10 +0,0 @@
#pragma once
#include "Client.h"
#include <ui/ipc/Server.h>
namespace wind
{
Result<void> handle_ipc_message(Client& client, u8 id);
Result<void> handle_ipc(Client& client);
}

View File

@ -38,7 +38,7 @@ void Window::focus()
g_windows.append(this);
}
Window::Window(ui::Rect r, ui::Color c, String&& n) : surface(r), color(c), name(move(n))
Window::Window(ui::Rect r, ui::Color c, StringView n) : surface(r), color(c), name(n)
{
auto font = ui::Font::default_font();
if (surface.width < 36) surface.width = 36;
@ -48,9 +48,3 @@ Window::Window(ui::Rect r, ui::Color c, String&& n) : surface(r), color(c), name
contents = ui::Rect { 0, font->height() + 20, surface.width, surface.height - (font->height() + 20) };
g_windows.append(this);
}
int Window::titlebar_height()
{
auto font = ui::Font::default_font();
return font->height() + 20;
}

View File

@ -1,6 +1,6 @@
#pragma once
#include <luna/LinkedList.h>
#include <luna/String.h>
#include <luna/StringView.h>
#include <ui/Canvas.h>
#include <ui/Color.h>
#include <ui/Rect.h>
@ -12,11 +12,9 @@ struct Window : public LinkedListNode<Window>
ui::Rect close_button;
ui::Rect contents;
ui::Color color;
String name;
StringView name;
static int titlebar_height();
Window(ui::Rect, ui::Color, String&&);
Window(ui::Rect, ui::Color, StringView);
void focus();

View File

@ -1,5 +1,3 @@
#include "Client.h"
#include "IPC.h"
#include "Mouse.h"
#include "Screen.h"
#include "Window.h"
@ -22,7 +20,7 @@ Result<int> luna_main(int argc, char** argv)
{
srand((unsigned)time(NULL));
TRY(os::Security::pledge("stdio rpath wpath cpath unix proc exec tty signal id", NULL));
TRY(os::Security::pledge("stdio rpath wpath cpath unix proc exec tty id", NULL));
StringView socket_path = "/tmp/wind.sock";
StringView user;
@ -84,13 +82,13 @@ Result<int> luna_main(int argc, char** argv)
ui::Color background = ui::BLACK;
Vector<Client> clients;
Vector<struct pollfd> fds;
TRY(fds.try_append({ .fd = mouse->fd(), .events = POLLIN, .revents = 0 }));
TRY(fds.try_append({ .fd = keyboard->fd(), .events = POLLIN, .revents = 0 }));
TRY(fds.try_append({ .fd = server->fd(), .events = POLLIN, .revents = 0 }));
TRY(make<Window>(ui::Rect { 200, 200, 600, 400 }, ui::GREEN, "Calculator"_sv));
TRY(make<Window>(ui::Rect { 100, 100, 300, 200 }, ui::RED, "Settings"_sv));
TRY(make<Window>(ui::Rect { 600, 130, 350, 250 }, ui::CYAN, "File Manager"_sv));
TRY(os::Security::pledge("stdio rpath unix signal proc", NULL));
Vector<os::LocalServer::Client> clients;
TRY(os::Security::pledge("stdio rpath unix", NULL));
while (1)
{
@ -99,9 +97,13 @@ Result<int> luna_main(int argc, char** argv)
mouse_pointer.draw(screen.canvas());
screen.sync();
for (auto& pfd : fds) { pfd.revents = 0; }
struct pollfd fds[] = {
{ .fd = mouse->fd(), .events = POLLIN, .revents = 0 },
{ .fd = keyboard->fd(), .events = POLLIN, .revents = 0 },
{ .fd = server->fd(), .events = POLLIN, .revents = 0 },
};
int rc = poll(fds.data(), fds.size(), 1000);
int rc = poll(fds, 3, 1000);
if (!rc) continue;
if (rc < 0 && errno != EINTR) { os::println("poll: error: %s", strerror(errno)); }
@ -115,31 +117,20 @@ Result<int> luna_main(int argc, char** argv)
{
moon::KeyboardPacket packet;
TRY(keyboard->read_typed(packet));
os::println("%s key %d", packet.released ? "Released" : "Pressed", packet.key);
}
for (usize i = 0; i < clients.size(); i++)
if (!packet.released)
{
if (fds[i + 3].revents & POLLIN) wind::handle_ipc(clients[i]);
if (fds[i + 3].revents & POLLHUP)
{
os::println("wind: Client %d disconnected", i);
fds.remove_at(i + 3);
auto client = clients.remove_at(i);
client.conn.disconnect();
for (auto& window : client.windows)
{
g_windows.remove(window);
delete window;
}
TRY(make<Window>(ui::Rect { rand() % screen.canvas().width, rand() % screen.canvas().height,
rand() % screen.canvas().width, rand() % screen.canvas().height },
ui::Color::from_rgb(static_cast<u8>(rand() % 256), static_cast<u8>(rand() % 256),
static_cast<u8>(rand() % 256)),
strerror(packet.key)));
}
}
if (fds[2].revents & POLLIN)
{
auto client = TRY(server->accept());
os::println("wind: New client connected!");
TRY(fds.try_append({ .fd = client.fd(), .events = POLLIN, .revents = 0 }));
Client c { move(client), {} };
TRY(clients.try_append(move(c)));
TRY(clients.try_append(move(client)));
}
}
}