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: 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; break;
} }
case X_UngrabServer: 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; break;
} }
case X_QueryPointer: case X_QueryPointer:

View File

@ -194,3 +194,5 @@ extern ATOM g_atom_value;
extern int g_epoll_fd; extern int g_epoll_fd;
extern BAN::HashMap<int, EpollThingy> g_epoll_thingies; 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; int g_epoll_fd;
BAN::HashMap<int, EpollThingy> g_epoll_thingies; BAN::HashMap<int, EpollThingy> g_epoll_thingies;
int g_server_grabber_fd = -1;
int main() int main()
{ {
for (int sig = 1; sig < NSIG; sig++) for (int sig = 1; sig < NSIG; sig++)
@ -292,6 +294,26 @@ int main()
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr); epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
close(client_fd); close(client_fd);
g_epoll_thingies.remove(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, 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) if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, client_sock, &event) == -1)
{ {
perror("xbanan: epoll_ctl"); perror("xbanan: epoll_ctl");
@ -398,7 +424,11 @@ int main()
if (client_info.output_buffer.empty()) 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) if (epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, client_info.fd, &event) == -1)
{ {
perror("xbanan: epoll_ctl"); perror("xbanan: epoll_ctl");
@ -416,6 +446,9 @@ int main()
if (!(events[i].events & EPOLLIN)) if (!(events[i].events & EPOLLIN))
continue; continue;
if (g_server_grabber_fd != -1 && g_server_grabber_fd != client_info.fd)
continue;
switch (client_info.state) switch (client_info.state)
{ {
case Client::State::ConnectionSetup: case Client::State::ConnectionSetup:
@ -533,7 +566,11 @@ int main()
if (client_info.output_buffer.empty() || client_info.has_epollout) if (client_info.output_buffer.empty() || client_info.has_epollout)
continue; 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) if (epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, client_info.fd, &event) == -1)
{ {
perror("xbanan: epoll_ctl"); perror("xbanan: epoll_ctl");