Implement GrabServer and UngrabServer

These seem very scary but they are part of the spec :)
This commit is contained in:
Oskari Alaranta 2026-02-21 05:01:37 +02:00
parent 8a0f287d8c
commit a52181e140
3 changed files with 80 additions and 5 deletions

View File

@ -2297,12 +2297,48 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
}
case X_GrabServer:
{
dwarnln("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:
{
dwarnln("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:

View File

@ -194,3 +194,5 @@ extern ATOM g_atom_value;
extern int g_epoll_fd;
extern BAN::HashMap<int, EpollThingy> g_epoll_thingies;
extern int g_server_grabber_fd;

View File

@ -106,6 +106,8 @@ ATOM g_atom_value = XA_LAST_PREDEFINED + 1;
int g_epoll_fd;
BAN::HashMap<int, EpollThingy> g_epoll_thingies;
int g_server_grabber_fd = -1;
int main()
{
for (int sig = 1; sig < NSIG; sig++)
@ -292,6 +294,26 @@ int main()
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
close(client_fd);
g_epoll_thingies.remove(client_fd);
if (client_fd == g_server_grabber_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);
}
}
};
MUST(g_objects.insert(g_root.windowId,
@ -335,7 +357,11 @@ int main()
}
}));
epoll_event event = { .events = EPOLLIN, .data = { .fd = client_sock } };
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");
@ -398,7 +424,11 @@ int main()
if (client_info.output_buffer.empty())
{
epoll_event event { .events = EPOLLIN, .data = { .fd = client_info.fd } };
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");
@ -416,6 +446,9 @@ int main()
if (!(events[i].events & EPOLLIN))
continue;
if (g_server_grabber_fd != -1 && g_server_grabber_fd != client_info.fd)
continue;
switch (client_info.state)
{
case Client::State::ConnectionSetup:
@ -533,7 +566,11 @@ int main()
if (client_info.output_buffer.empty() || client_info.has_epollout)
continue;
epoll_event event { .events = EPOLLIN | EPOLLOUT, .data = { .fd = client_info.fd } };
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");