Compare commits

..

1 Commits

Author SHA1 Message Date
c0832cf240 Cleanup the build system and add porting instructions 2026-06-04 02:05:28 +03:00
8 changed files with 171 additions and 67 deletions

View File

@@ -42,4 +42,4 @@ To handle events, you have to hook an event receiver fd for your platform using
### Installation ### Installation
To install xbanan to sysroot, just copy the `build/xbanan/xbanan` to the destination. xbanan is statically linked against the libraries from this repository so you don't have to care about those. **DO NOT** use the cmake's install target, as that installs banan-os libraries to the root of the sysroot. You also need to have the x11 misc fonts at `FONT_PATH/misc` in your sysroot if you want server side font support. The fonts are shipped (public domain) with xbanan, so you can just copy `fonts/misc` into `FONT_PATH`. You can specify the `FONT_PATH` with cmake using `-DFONT_PATH=...` when configuring. To install xbanan to sysroot, just copy the `build/xbanan/xbanan` to the destination. xbanan is statically linked against the libraries from this repository so you don't have to care about those. **DO NOT** use the cmake's install target, as that installs banan-os libraries to the root of the sysroot.

View File

@@ -12,6 +12,7 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <time.h> #include <time.h>
#include <sys/epoll.h>
struct Selection struct Selection
{ {
@@ -1813,9 +1814,9 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
(void)TRY_REF(get_window(client_info, wid, X_SendEvent)); (void)TRY_REF(get_window(client_info, wid, X_SendEvent));
Client* target_client = nullptr; Client* target_client = nullptr;
for (auto& [_, thingy] : g_pollables) for (auto& [_, thingy] : g_epoll_thingies)
{ {
if (thingy.type != Pollable::Type::Client) if (thingy.type != EpollThingy::Type::Client)
continue; continue;
auto& other_client = thingy.value.get<Client>(); auto& other_client = thingy.value.get<Client>();
if (!other_client.objects.contains(wid)) if (!other_client.objects.contains(wid))
@@ -1937,11 +1938,47 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
case X_GrabServer: case X_GrabServer:
{ {
g_server_grabber_fd = client_info.fd; g_server_grabber_fd = client_info.fd;
for (const auto& [_, thingy] : g_epoll_thingies)
{
if (thingy.type != EpollThingy::Type::Client)
continue;
auto& other_client = thingy.value.get<Client>();
if (client_info.fd == other_client.fd)
continue;
uint32_t events = 0;
if (other_client.has_epollout)
events |= EPOLLOUT;
epoll_event event { .events = events, .data = { .fd = other_client.fd } };
epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, other_client.fd, &event);
}
break; break;
} }
case X_UngrabServer: case X_UngrabServer:
{ {
g_server_grabber_fd = -1; g_server_grabber_fd = -1;
for (const auto& [_, thingy] : g_epoll_thingies)
{
if (thingy.type != EpollThingy::Type::Client)
continue;
auto& other_client = thingy.value.get<Client>();
if (client_info.fd == other_client.fd)
continue;
uint32_t events = EPOLLIN;
if (other_client.has_epollout)
events |= EPOLLOUT;
epoll_event event { .events = events, .data = { .fd = other_client.fd } };
epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, other_client.fd, &event);
}
break; break;
} }
case X_QueryPointer: case X_QueryPointer:

View File

@@ -13,8 +13,6 @@ set(XBANAN_SOURCES
SafeGetters.cpp SafeGetters.cpp
) )
set(FONT_PATH ${CMAKE_SOURCE_DIR}/fonts CACHE STRING "path to X11 fonts")
option(ENABLE_GLX "enable glx extension" ON) option(ENABLE_GLX "enable glx extension" ON)
if(ENABLE_GLX) if(ENABLE_GLX)
list(APPEND XBANAN_SOURCES ExtGLX.cpp) list(APPEND XBANAN_SOURCES ExtGLX.cpp)
@@ -35,8 +33,6 @@ add_executable(xbanan ${XBANAN_SOURCES})
banan_link_library(xbanan ban) banan_link_library(xbanan ban)
banan_link_library(xbanan libdeflate) banan_link_library(xbanan libdeflate)
target_compile_definitions(xbanan PRIVATE FONT_PATH="${FONT_PATH}")
if(PLATFORM STREQUAL "banan-os") if(PLATFORM STREQUAL "banan-os")
banan_link_library(xbanan libgui) banan_link_library(xbanan libgui)
banan_link_library(xbanan libinput) banan_link_library(xbanan libinput)

View File

@@ -140,6 +140,7 @@ struct Client
}; };
int fd; int fd;
State state; State state;
bool has_epollout { false };
bool has_bigrequests { false }; bool has_bigrequests { false };
CARD16 sequence { 0 }; CARD16 sequence { 0 };
BAN::Optional<uint32_t> pid; BAN::Optional<uint32_t> pid;
@@ -148,7 +149,7 @@ struct Client
BAN::HashSet<CARD32> objects; BAN::HashSet<CARD32> objects;
}; };
struct Pollable struct EpollThingy
{ {
enum class Type enum class Type
{ {
@@ -171,6 +172,7 @@ extern BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
extern BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name; extern BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
extern ATOM g_atom_value; extern ATOM g_atom_value;
extern BAN::HashMap<int, Pollable> g_pollables; extern int g_epoll_fd;
extern BAN::HashMap<int, EpollThingy> g_epoll_thingies;
extern int g_server_grabber_fd; extern int g_server_grabber_fd;

View File

@@ -7,18 +7,23 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <time.h> #include <time.h>
#include <sys/epoll.h>
void register_event_fd(int fd, void* data) void register_event_fd(int fd, void* data)
{ {
MUST(g_pollables.insert(fd, { epoll_event event { .events = EPOLLIN, .data = { .fd = fd } };
.type = Pollable::Type::Event, epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &event);
MUST(g_epoll_thingies.insert(fd, {
.type = EpollThingy::Type::Event,
.value = data, .value = data,
})); }));
} }
void unregister_event_fd(int fd) void unregister_event_fd(int fd)
{ {
g_pollables.remove(fd); epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
g_epoll_thingies.remove(fd);
} }
void on_window_close_event(WINDOW wid) void on_window_close_event(WINDOW wid)

View File

@@ -7,9 +7,9 @@
template<typename F> template<typename F>
static BAN::ErrorOr<void> for_each_client(uint32_t target_spec, const F& callback) static BAN::ErrorOr<void> for_each_client(uint32_t target_spec, const F& callback)
{ {
for (auto [fd, thingy] : g_pollables) for (auto [fd, thingy] : g_epoll_thingies)
{ {
if (thingy.type != Pollable::Type::Client) if (thingy.type != EpollThingy::Type::Client)
continue; continue;
Client& client_info = thingy.value.get<Client>(); Client& client_info = thingy.value.get<Client>();
@@ -33,8 +33,8 @@ BAN::ErrorOr<void> extension_xres(Client& client_info, BAN::ConstByteSpan packet
auto request = decode<xXResQueryVersionReq>(packet).value(); auto request = decode<xXResQueryVersionReq>(packet).value();
dprintln("XResQueryVersion"); dprintln("XResQueryVersion");
dprintln(" clientMajor: {}", request.client_major); dprintln(" clientMajor: {}", reqType.client_major);
dprintln(" clientMinor: {}", request.client_minor); dprintln(" clientMinor: {}", reqType.client_minor);
xXResQueryVersionReply reply { xXResQueryVersionReply reply {
.type = X_Reply, .type = X_Reply,

View File

@@ -385,7 +385,7 @@ static BAN::ErrorOr<BAN::RefPtr<PCFFont>> parse_font(const BAN::String& path)
font->font_ascent = font->max_bounds.ascent; font->font_ascent = font->max_bounds.ascent;
font->font_descent = font->max_bounds.descent; font->font_descent = font->max_bounds.descent;
font->is_cursor_font = (path == FONT_PATH "/misc/cursor.pcf.gz"_sv); font->is_cursor_font = (path == "fonts/misc/cursor.pcf.gz"_sv);
return font; return font;
} }
@@ -393,7 +393,7 @@ static BAN::ErrorOr<BAN::RefPtr<PCFFont>> parse_font(const BAN::String& path)
__attribute__((constructor)) __attribute__((constructor))
static void initialize_fonts() static void initialize_fonts()
{ {
const char* font_path = FONT_PATH "/misc"; const char* font_path = "fonts/misc";
do do
{ {

View File

@@ -5,8 +5,8 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <locale.h> #include <locale.h>
#include <poll.h>
#include <signal.h> #include <signal.h>
#include <sys/epoll.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
@@ -92,7 +92,8 @@ BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name; BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
ATOM g_atom_value = XA_LAST_PREDEFINED + 1; ATOM g_atom_value = XA_LAST_PREDEFINED + 1;
BAN::HashMap<int, Pollable> g_pollables; int g_epoll_fd;
BAN::HashMap<int, EpollThingy> g_epoll_thingies;
int g_server_grabber_fd = -1; int g_server_grabber_fd = -1;
@@ -154,6 +155,22 @@ int main()
return 1; return 1;
} }
g_epoll_fd = epoll_create1(0);
if (g_epoll_fd == -1)
{
perror("xbanan: epoll_create1");
return 1;
}
{
epoll_event event { .events = EPOLLIN, .data = { .ptr = nullptr } };
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, server_sock, &event) == -1)
{
perror("xbanan: epoll_ctl");
return 1;
}
}
#define APPEND_ATOM(name) do { \ #define APPEND_ATOM(name) do { \
MUST(g_atoms_id_to_name.insert(name, #name##_sv.substring(3))); \ MUST(g_atoms_id_to_name.insert(name, #name##_sv.substring(3))); \
MUST(g_atoms_name_to_id.insert(#name##_sv.substring(3), name)); \ MUST(g_atoms_name_to_id.insert(#name##_sv.substring(3), name)); \
@@ -257,9 +274,9 @@ int main()
const auto close_client = const auto close_client =
[](int client_fd) [](int client_fd)
{ {
auto& pollable = g_pollables[client_fd]; auto& epoll_thingy = g_epoll_thingies[client_fd];
ASSERT(pollable.type == Pollable::Type::Client); ASSERT(epoll_thingy.type == EpollThingy::Type::Client);
auto& client_info = pollable.value.get<Client>(); auto& client_info = epoll_thingy.value.get<Client>();
dprintln("client {} disconnected", client_fd); dprintln("client {} disconnected", client_fd);
@@ -311,11 +328,29 @@ int main()
g_objects.remove(it); g_objects.remove(it);
} }
g_pollables.remove(client_fd); epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
g_epoll_thingies.remove(client_fd);
close(client_fd); close(client_fd);
if (g_server_grabber_fd == client_fd) if (client_fd == g_server_grabber_fd)
{
g_server_grabber_fd = -1; g_server_grabber_fd = -1;
for (const auto& [_, thingy] : g_epoll_thingies)
{
if (thingy.type != EpollThingy::Type::Client)
continue;
auto& other_client = thingy.value.get<Client>();
uint32_t events = EPOLLIN;
if (other_client.has_epollout)
events |= EPOLLOUT;
epoll_event event { .events = events, .data = { .fd = other_client.fd } };
epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, other_client.fd, &event);
}
}
}; };
Client dummy_client {}; Client dummy_client {};
@@ -342,37 +377,12 @@ int main()
for (;;) for (;;)
{ {
BAN::Vector<pollfd> pollfds; epoll_event events[16];
MUST(pollfds.reserve(g_pollables.size() + 1)); const int event_count = epoll_wait(g_epoll_fd, events, 16, -1);
MUST(pollfds.push_back({
.fd = server_sock, for (int i = 0; i < event_count; i++)
.events = POLLIN,
.revents = 0,
}));
for (auto& [fd, pollable] : g_pollables)
{ {
short events = 0; if (events[i].data.ptr == nullptr)
if (g_server_grabber_fd == -1 || g_server_grabber_fd == fd)
events |= POLLIN;
if (pollable.type == Pollable::Type::Client && !pollable.value.get<Client>().output_buffer.empty())
events |= POLLOUT;
if (events == 0)
continue;
MUST(pollfds.push_back(pollfd {
.fd = fd,
.events = events,
.revents = 0,
}));
}
const int event_count = poll(pollfds.data(), pollfds.size(), -1);
for (const auto& pollfd : pollfds)
{
if (pollfd.revents == 0)
continue;
if (pollfd.fd == server_sock)
{ {
int client_sock = accept(server_sock, nullptr, nullptr); int client_sock = accept(server_sock, nullptr, nullptr);
if (client_sock == -1) if (client_sock == -1)
@@ -390,8 +400,8 @@ int main()
client_pid = client_cred.pid; client_pid = client_cred.pid;
#endif #endif
MUST(g_pollables.insert(client_sock, { MUST(g_epoll_thingies.insert(client_sock, {
.type = Pollable::Type::Client, .type = EpollThingy::Type::Client,
.value = Client { .value = Client {
.fd = client_sock, .fd = client_sock,
.state = Client::State::ConnectionSetup, .state = Client::State::ConnectionSetup,
@@ -399,32 +409,44 @@ int main()
} }
})); }));
uint32_t events = 0;
if (g_server_grabber_fd == -1)
events |= EPOLLIN;
epoll_event event = { .events = events, .data = { .fd = client_sock } };
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, client_sock, &event) == -1)
{
perror("xbanan: epoll_ctl");
close(client_sock);
continue;
}
dprintln("client {} connected", client_sock); dprintln("client {} connected", client_sock);
continue; continue;
} }
auto it = g_pollables.find(pollfd.fd); auto it = g_epoll_thingies.find(events[i].data.fd);
if (it == g_pollables.end()) if (it == g_epoll_thingies.end())
continue; continue;
auto& pollable = it->value; auto& epoll_thingy = it->value;
if (pollable.type == Pollable::Type::Event) if (epoll_thingy.type == EpollThingy::Type::Event)
{ {
g_platform_ops.poll_events(pollable.value.get<void*>()); g_platform_ops.poll_events(epoll_thingy.value.get<void*>());
continue; continue;
} }
ASSERT(pollable.type == Pollable::Type::Client); ASSERT(epoll_thingy.type == EpollThingy::Type::Client);
auto& client_info = pollable.value.get<Client>(); auto& client_info = epoll_thingy.value.get<Client>();
if (pollfd.revents & POLLHUP) if (events[i].events & EPOLLHUP)
{ {
close_client(client_info.fd); close_client(client_info.fd);
continue; continue;
} }
if (pollfd.revents & POLLOUT) if (events[i].events & EPOLLOUT)
{ {
const ssize_t nsend = send( const ssize_t nsend = send(
client_info.fd, client_info.fd,
@@ -451,11 +473,28 @@ int main()
); );
MUST(client_info.output_buffer.resize(client_info.output_buffer.size() - nsend)); MUST(client_info.output_buffer.resize(client_info.output_buffer.size() - nsend));
if (client_info.output_buffer.empty())
{
uint32_t events = 0;
if (g_server_grabber_fd == -1 || g_server_grabber_fd == client_info.fd)
events |= EPOLLIN;
epoll_event event { .events = events, .data = { .fd = client_info.fd } };
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, client_info.fd, &event) == -1)
{
perror("xbanan: epoll_ctl");
close_client(client_info.fd);
continue;
}
client_info.has_epollout = false;
}
send_done: send_done:
(void)0; (void)0;
} }
if (!(pollfd.revents & POLLIN)) if (!(events[i].events & EPOLLIN))
continue; continue;
if (g_server_grabber_fd != -1 && g_server_grabber_fd != client_info.fd) if (g_server_grabber_fd != -1 && g_server_grabber_fd != client_info.fd)
@@ -567,5 +606,30 @@ int main()
} }
} }
} }
iterator_invalidated:
for (auto& [_, thingy] : g_epoll_thingies)
{
if (thingy.type != EpollThingy::Type::Client)
continue;
auto& client_info = thingy.value.get<Client>();
if (client_info.output_buffer.empty() || client_info.has_epollout)
continue;
uint32_t events = EPOLLOUT;
if (g_server_grabber_fd == -1 || g_server_grabber_fd == client_info.fd)
events |= EPOLLIN;
epoll_event event { .events = events, .data = { .fd = client_info.fd } };
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, client_info.fd, &event) == -1)
{
perror("xbanan: epoll_ctl");
close_client(client_info.fd);
goto iterator_invalidated;
}
client_info.has_epollout = true;
}
} }
} }