Compare commits
3 Commits
c0832cf240
...
poll
| Author | SHA1 | Date | |
|---|---|---|---|
| d0f2b5e8a6 | |||
| a6a581347e | |||
| e843be0a1c |
@@ -42,4 +42,4 @@ To handle events, you have to hook an event receiver fd for your platform using
|
||||
|
||||
### 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.
|
||||
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.
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
struct Selection
|
||||
{
|
||||
@@ -1814,9 +1813,9 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
(void)TRY_REF(get_window(client_info, wid, X_SendEvent));
|
||||
|
||||
Client* target_client = nullptr;
|
||||
for (auto& [_, thingy] : g_epoll_thingies)
|
||||
for (auto& [_, thingy] : g_pollables)
|
||||
{
|
||||
if (thingy.type != EpollThingy::Type::Client)
|
||||
if (thingy.type != Pollable::Type::Client)
|
||||
continue;
|
||||
auto& other_client = thingy.value.get<Client>();
|
||||
if (!other_client.objects.contains(wid))
|
||||
@@ -1938,47 +1937,11 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
case X_GrabServer:
|
||||
{
|
||||
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;
|
||||
}
|
||||
case X_UngrabServer:
|
||||
{
|
||||
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;
|
||||
}
|
||||
case X_QueryPointer:
|
||||
|
||||
@@ -13,6 +13,8 @@ set(XBANAN_SOURCES
|
||||
SafeGetters.cpp
|
||||
)
|
||||
|
||||
set(FONT_PATH ${CMAKE_SOURCE_DIR}/fonts CACHE STRING "path to X11 fonts")
|
||||
|
||||
option(ENABLE_GLX "enable glx extension" ON)
|
||||
if(ENABLE_GLX)
|
||||
list(APPEND XBANAN_SOURCES ExtGLX.cpp)
|
||||
@@ -33,6 +35,8 @@ add_executable(xbanan ${XBANAN_SOURCES})
|
||||
banan_link_library(xbanan ban)
|
||||
banan_link_library(xbanan libdeflate)
|
||||
|
||||
target_compile_definitions(xbanan PRIVATE FONT_PATH="${FONT_PATH}")
|
||||
|
||||
if(PLATFORM STREQUAL "banan-os")
|
||||
banan_link_library(xbanan libgui)
|
||||
banan_link_library(xbanan libinput)
|
||||
|
||||
@@ -140,7 +140,6 @@ struct Client
|
||||
};
|
||||
int fd;
|
||||
State state;
|
||||
bool has_epollout { false };
|
||||
bool has_bigrequests { false };
|
||||
CARD16 sequence { 0 };
|
||||
BAN::Optional<uint32_t> pid;
|
||||
@@ -149,7 +148,7 @@ struct Client
|
||||
BAN::HashSet<CARD32> objects;
|
||||
};
|
||||
|
||||
struct EpollThingy
|
||||
struct Pollable
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
@@ -172,7 +171,6 @@ extern BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
|
||||
extern BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
|
||||
extern ATOM g_atom_value;
|
||||
|
||||
extern int g_epoll_fd;
|
||||
extern BAN::HashMap<int, EpollThingy> g_epoll_thingies;
|
||||
extern BAN::HashMap<int, Pollable> g_pollables;
|
||||
|
||||
extern int g_server_grabber_fd;
|
||||
|
||||
@@ -7,23 +7,18 @@
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
void register_event_fd(int fd, void* data)
|
||||
{
|
||||
epoll_event event { .events = EPOLLIN, .data = { .fd = fd } };
|
||||
epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &event);
|
||||
|
||||
MUST(g_epoll_thingies.insert(fd, {
|
||||
.type = EpollThingy::Type::Event,
|
||||
MUST(g_pollables.insert(fd, {
|
||||
.type = Pollable::Type::Event,
|
||||
.value = data,
|
||||
}));
|
||||
}
|
||||
|
||||
void unregister_event_fd(int fd)
|
||||
{
|
||||
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
|
||||
g_epoll_thingies.remove(fd);
|
||||
g_pollables.remove(fd);
|
||||
}
|
||||
|
||||
void on_window_close_event(WINDOW wid)
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
template<typename F>
|
||||
static BAN::ErrorOr<void> for_each_client(uint32_t target_spec, const F& callback)
|
||||
{
|
||||
for (auto [fd, thingy] : g_epoll_thingies)
|
||||
for (auto [fd, thingy] : g_pollables)
|
||||
{
|
||||
if (thingy.type != EpollThingy::Type::Client)
|
||||
if (thingy.type != Pollable::Type::Client)
|
||||
continue;
|
||||
|
||||
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();
|
||||
|
||||
dprintln("XResQueryVersion");
|
||||
dprintln(" clientMajor: {}", reqType.client_major);
|
||||
dprintln(" clientMinor: {}", reqType.client_minor);
|
||||
dprintln(" clientMajor: {}", request.client_major);
|
||||
dprintln(" clientMinor: {}", request.client_minor);
|
||||
|
||||
xXResQueryVersionReply reply {
|
||||
.type = X_Reply,
|
||||
|
||||
@@ -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_descent = font->max_bounds.descent;
|
||||
|
||||
font->is_cursor_font = (path == "fonts/misc/cursor.pcf.gz"_sv);
|
||||
font->is_cursor_font = (path == FONT_PATH "/misc/cursor.pcf.gz"_sv);
|
||||
|
||||
return font;
|
||||
}
|
||||
@@ -393,7 +393,7 @@ static BAN::ErrorOr<BAN::RefPtr<PCFFont>> parse_font(const BAN::String& path)
|
||||
__attribute__((constructor))
|
||||
static void initialize_fonts()
|
||||
{
|
||||
const char* font_path = "fonts/misc";
|
||||
const char* font_path = FONT_PATH "/misc";
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
162
xbanan/main.cpp
162
xbanan/main.cpp
@@ -5,8 +5,8 @@
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <locale.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@@ -92,8 +92,7 @@ BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
|
||||
BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
|
||||
ATOM g_atom_value = XA_LAST_PREDEFINED + 1;
|
||||
|
||||
int g_epoll_fd;
|
||||
BAN::HashMap<int, EpollThingy> g_epoll_thingies;
|
||||
BAN::HashMap<int, Pollable> g_pollables;
|
||||
|
||||
int g_server_grabber_fd = -1;
|
||||
|
||||
@@ -155,22 +154,6 @@ int main()
|
||||
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 { \
|
||||
MUST(g_atoms_id_to_name.insert(name, #name##_sv.substring(3))); \
|
||||
MUST(g_atoms_name_to_id.insert(#name##_sv.substring(3), name)); \
|
||||
@@ -274,9 +257,9 @@ int main()
|
||||
const auto close_client =
|
||||
[](int client_fd)
|
||||
{
|
||||
auto& epoll_thingy = g_epoll_thingies[client_fd];
|
||||
ASSERT(epoll_thingy.type == EpollThingy::Type::Client);
|
||||
auto& client_info = epoll_thingy.value.get<Client>();
|
||||
auto& pollable = g_pollables[client_fd];
|
||||
ASSERT(pollable.type == Pollable::Type::Client);
|
||||
auto& client_info = pollable.value.get<Client>();
|
||||
|
||||
dprintln("client {} disconnected", client_fd);
|
||||
|
||||
@@ -328,29 +311,11 @@ int main()
|
||||
g_objects.remove(it);
|
||||
}
|
||||
|
||||
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
|
||||
g_epoll_thingies.remove(client_fd);
|
||||
g_pollables.remove(client_fd);
|
||||
close(client_fd);
|
||||
|
||||
if (client_fd == g_server_grabber_fd)
|
||||
{
|
||||
if (g_server_grabber_fd == client_fd)
|
||||
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 {};
|
||||
@@ -377,12 +342,37 @@ int main()
|
||||
|
||||
for (;;)
|
||||
{
|
||||
epoll_event events[16];
|
||||
const int event_count = epoll_wait(g_epoll_fd, events, 16, -1);
|
||||
|
||||
for (int i = 0; i < event_count; i++)
|
||||
BAN::Vector<pollfd> pollfds;
|
||||
MUST(pollfds.reserve(g_pollables.size() + 1));
|
||||
MUST(pollfds.push_back({
|
||||
.fd = server_sock,
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
}));
|
||||
for (auto& [fd, pollable] : g_pollables)
|
||||
{
|
||||
if (events[i].data.ptr == nullptr)
|
||||
short events = 0;
|
||||
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);
|
||||
if (client_sock == -1)
|
||||
@@ -400,8 +390,8 @@ int main()
|
||||
client_pid = client_cred.pid;
|
||||
#endif
|
||||
|
||||
MUST(g_epoll_thingies.insert(client_sock, {
|
||||
.type = EpollThingy::Type::Client,
|
||||
MUST(g_pollables.insert(client_sock, {
|
||||
.type = Pollable::Type::Client,
|
||||
.value = Client {
|
||||
.fd = client_sock,
|
||||
.state = Client::State::ConnectionSetup,
|
||||
@@ -409,44 +399,32 @@ 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);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = g_epoll_thingies.find(events[i].data.fd);
|
||||
if (it == g_epoll_thingies.end())
|
||||
auto it = g_pollables.find(pollfd.fd);
|
||||
if (it == g_pollables.end())
|
||||
continue;
|
||||
auto& epoll_thingy = it->value;
|
||||
auto& pollable = it->value;
|
||||
|
||||
if (epoll_thingy.type == EpollThingy::Type::Event)
|
||||
if (pollable.type == Pollable::Type::Event)
|
||||
{
|
||||
g_platform_ops.poll_events(epoll_thingy.value.get<void*>());
|
||||
g_platform_ops.poll_events(pollable.value.get<void*>());
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT(epoll_thingy.type == EpollThingy::Type::Client);
|
||||
ASSERT(pollable.type == Pollable::Type::Client);
|
||||
|
||||
auto& client_info = epoll_thingy.value.get<Client>();
|
||||
auto& client_info = pollable.value.get<Client>();
|
||||
|
||||
if (events[i].events & EPOLLHUP)
|
||||
if (pollfd.revents & POLLHUP)
|
||||
{
|
||||
close_client(client_info.fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (events[i].events & EPOLLOUT)
|
||||
if (pollfd.revents & POLLOUT)
|
||||
{
|
||||
const ssize_t nsend = send(
|
||||
client_info.fd,
|
||||
@@ -473,28 +451,11 @@ int main()
|
||||
);
|
||||
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:
|
||||
(void)0;
|
||||
}
|
||||
|
||||
if (!(events[i].events & EPOLLIN))
|
||||
if (!(pollfd.revents & POLLIN))
|
||||
continue;
|
||||
|
||||
if (g_server_grabber_fd != -1 && g_server_grabber_fd != client_info.fd)
|
||||
@@ -606,30 +567,5 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user