From 301765a5bdc4179a18f663df5fdbfe43749318f8 Mon Sep 17 00:00:00 2001 From: Oskari Alaranta Date: Sun, 8 Feb 2026 20:03:14 +0200 Subject: [PATCH] Add stuff :) --- xbanan/main.cpp | 182 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 154 insertions(+), 28 deletions(-) diff --git a/xbanan/main.cpp b/xbanan/main.cpp index a8ab231..8366897 100644 --- a/xbanan/main.cpp +++ b/xbanan/main.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -317,13 +318,15 @@ xVisualType visual { struct Client { - enum class State + enum class State : uint8_t { ConnectionSetup, Connected, }; int fd; State state; + bool has_epollout { false }; + bool has_bigrequests { false }; CARD16 sequence { 0 }; BAN::Vector input_buffer; BAN::Vector output_buffer; @@ -331,6 +334,17 @@ struct Client BAN::HashMap> objects; }; +struct Extension +{ + BAN::StringView name; + uint8_t major_opcode; + uint8_t opcode_count; + BAN::ErrorOr (*handler)(Client&, BAN::ConstByteSpan); +}; + +uint8_t g_extension_opcode { 128 }; +BAN::Array g_extensions; + BAN::HashMap g_atoms_name_to_id; BAN::HashMap g_atoms_id_to_name; ATOM atom_value = XA_LAST_PREDEFINED + 1; @@ -634,6 +648,8 @@ void _invalidate_window_recursive(Client& client_info, WINDOW wid, int32_t x, in { ASSERT(wid != root.windowId); + if (x + w <= 0 || y + h <= 0) + return; if (w <= 0 || h <= 0) return; @@ -653,16 +669,22 @@ void _invalidate_window_recursive(Client& client_info, WINDOW wid, int32_t x, in if (!child_window.mapped) continue; + const auto child_x = x - child_window.x; + const auto child_y = y - child_window.y; + + const auto child_w = BAN::Math::min(w - child_window.x, child_window.texture().width() - child_x); + const auto child_h = BAN::Math::min(h - child_window.y, child_window.texture().height() - child_y); + _invalidate_window_recursive( client_info, child_wid, - x - child_window.x, - y - child_window.y, - w - child_window.x, - h - child_window.y + child_x, child_y, + child_w, child_h ); } + dwarnln("invalidate {} {},{} -> {},{}", wid, x, y, x + w, y + h); + if (window.window.has>()) return; @@ -672,8 +694,8 @@ void _invalidate_window_recursive(Client& client_info, WINDOW wid, int32_t x, in auto& parent_window = parent_object.object.get(); parent_window.texture().copy_texture( window.texture(), - parent_window.x + x, - parent_window.y + y, + window.x + x, + window.y + y, x, y, w, @@ -728,7 +750,7 @@ void invalidate_window(Client& client_info, WINDOW wid, int32_t x, int32_t y, in } } - window.window.get>()->invalidate(x, y, w, h); + window.window.get>()->invalidate(min_x, min_y, max_x - min_x, max_y - min_y); } BAN::ErrorOr map_window(Client& client_info, WINDOW wid) @@ -753,10 +775,10 @@ BAN::ErrorOr map_window(Client& client_info, WINDOW wid) auto attributes = gui_window->get_attributes(); attributes.shown = true; gui_window->set_attributes(attributes); - } - if (is_visible(client_info, window.parent)) - TRY(send_visibility_events_recursively(client_info, wid, true)); + gui_window->texture().clear(); + gui_window->invalidate(); + } if (window.event_mask & StructureNotifyMask) { @@ -790,6 +812,9 @@ BAN::ErrorOr map_window(Client& client_info, WINDOW wid) TRY(encode(client_info.output_buffer, event)); } + if (is_visible(client_info, window.parent)) + TRY(send_visibility_events_recursively(client_info, wid, true)); + if (window.event_mask & ExposureMask) { xEvent event = { .u = { @@ -994,6 +1019,15 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) client_info.sequence++; + if (packet[0] >= 128) + { + const auto& extension = g_extensions[packet[0] - 128]; + if (extension.handler != nullptr) + return extension.handler(client_info, packet); + dwarnln("invalid opcode {}", packet[0]); + return BAN::Error::from_errno(EINVAL); + } + switch (packet[0]) { case X_CreateWindow: @@ -1014,7 +1048,7 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) dprintln(" mask: {8h}", request.mask); uint32_t event_mask { 0 }; - uint32_t background { 0x000000 }; + uint32_t background { 0xFF00FF }; for (size_t i = 0; i < 32; i++) { @@ -1077,7 +1111,7 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) auto& parent_window = parent_object->object.get(); TRY(parent_window.children.push_back(request.wid)); - auto it = TRY(client_info.objects.insert( + TRY(client_info.objects.insert( request.wid, TRY(BAN::UniqPtr::create(Object { .type = Object::Type::Window, @@ -1637,7 +1671,6 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) } auto& property = it->value; - ASSERT(property.type == request.type); ASSERT(property.format == request.format); const size_t bytes = (request.format / 8) * request.nUnits; @@ -1650,11 +1683,13 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) memcpy(property.data.data(), packet.data(), bytes); break; case PropModePrepend: + ASSERT(property.type == request.type); TRY(property.data.resize(old_bytes + bytes)); memmove(property.data.data() + old_bytes, property.data.data(), old_bytes); memcpy(property.data.data(), packet.data(), bytes); break; case PropModeAppend: + ASSERT(property.type == request.type); TRY(property.data.resize(old_bytes + bytes)); memcpy(property.data.data() + old_bytes, packet.data(), bytes); break; @@ -2223,7 +2258,7 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) data_u32[y * w + x] = foreground; if (object.type == Object::Type::Window) - invalidate_window(client_info, request.drawable, rect.x, rect.y, rect.width, rect.height); + invalidate_window(client_info, request.drawable, min_x, min_y, max_x - min_x, max_y - min_y); } break; @@ -2269,8 +2304,8 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) const int32_t min_x = BAN::Math::max(0, arc.x); const int32_t min_y = BAN::Math::max(0, arc.y); - const int32_t max_x = BAN::Math::max(texture.width(), arc.x + arc.width); - const int32_t max_y = BAN::Math::max(texture.height(), arc.y + arc.height); + const int32_t max_x = BAN::Math::min(texture.width(), arc.x + arc.width); + const int32_t max_y = BAN::Math::min(texture.height(), arc.y + arc.height); const auto rx = arc.width / 2; const auto ry = arc.height / 2; @@ -2490,6 +2525,16 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) .first_event = 0, .first_error = 0, }; + + for (const auto& extension : g_extensions) + { + if (extension.name != name) + continue; + reply.present = xTrue; + reply.major_opcode = extension.major_opcode; + break; + } + TRY(encode(client_info.output_buffer, reply)); break; @@ -2557,6 +2602,50 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) return {}; } +BAN::ErrorOr extension_bigrequests(Client& client_info, BAN::ConstByteSpan packet) +{ + switch (packet[1]) + { + case 0: + { + xGenericReply reply { + .type = X_Reply, + .sequenceNumber = client_info.sequence, + .length = 0, + .data00 = (16 << 20) / 4, // 16 MiB + }; + TRY(encode(client_info.output_buffer, reply)); + + client_info.has_bigrequests = true; + + dprintln("client enabled big requests"); + + break; + } + default: + dwarnln("invalid BIG-REQUESTS minor opcode {}", packet[1]); + return BAN::Error::from_errno(EINVAL); + } + + return {}; +} + +void install_extensions() +{ + const auto install_extension = + [](BAN::StringView name, BAN::ErrorOr (*handler)(Client&, BAN::ConstByteSpan)) + { + g_extensions[g_extension_opcode - 128] = { + .name = name, + .major_opcode = g_extension_opcode, + .handler = handler, + }; + g_extension_opcode++; + }; + + install_extension("BIG-REQUESTS"_sv, extension_bigrequests); +} + int main() { for (int sig = 1; sig < NSIG; sig++) @@ -2694,6 +2783,8 @@ int main() APPEND_ATOM(XA_WM_TRANSIENT_FOR); #undef APPEND_ATOM + install_extensions(); + printf("xbanan started\n"); const auto close_client = @@ -2773,7 +2864,13 @@ int main() ASSERT(epoll_thingy.type == EpollThingy::Type::Client); auto& client_info = epoll_thingy.value.get(); - + + if (events[i].events & EPOLLHUP) + { + close_client(client_info.fd); + continue; + } + if (events[i].events & EPOLLOUT) { const ssize_t nsend = send( @@ -2783,11 +2880,14 @@ int main() 0 ); + if (nsend == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + goto send_done; + if (nsend < 0) perror("xbanan: send"); if (nsend <= 0) { - close_client(events[i].data.fd); + close_client(client_info.fd); continue; } @@ -2804,10 +2904,15 @@ int main() if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, client_info.fd, &event) == -1) { perror("xbanan: epoll_ctl"); - close_client(events[i].data.fd); + close_client(client_info.fd); continue; } + + client_info.has_epollout = false; } + + send_done: + (void)0; } if (!(events[i].events & EPOLLIN)) @@ -2818,12 +2923,13 @@ int main() case Client::State::ConnectionSetup: { xConnClientPrefix client_prefix; - ssize_t nrecv = recv(client_info.fd, &client_prefix, sizeof(client_prefix), 0); + + const ssize_t nrecv = recv(client_info.fd, &client_prefix, sizeof(client_prefix), 0); if (nrecv < 0) perror("xbanan: recv"); if (nrecv <= 0) { - close_client(events[i].data.fd); + close_client(client_info.fd); continue; } @@ -2832,7 +2938,7 @@ int main() if (auto ret = setup_client_conneciton(client_info, client_prefix); ret.is_error()) { dwarnln("setup_client_connection: {}", ret.error()); - close_client(events[i].data.fd); + close_client(client_info.fd); continue; } @@ -2842,12 +2948,12 @@ int main() { char buffer[1024] {}; - ssize_t nrecv = recv(client_info.fd, buffer, sizeof(buffer), 0); + const ssize_t nrecv = recv(client_info.fd, buffer, sizeof(buffer), 0); if (nrecv < 0) perror("xbanan: recv"); if (nrecv <= 0) { - close_client(events[i].data.fd); + close_client(client_info.fd); continue; } @@ -2860,16 +2966,34 @@ int main() if (client_info.input_buffer.size() < 4) break; - const uint32_t byte_length = 4 * reinterpret_cast(client_info.input_buffer.data())[1]; + bool is_big_request = false; + uint32_t byte_length = 4 * *reinterpret_cast(client_info.input_buffer.data() + 2); + + if (byte_length == 0 && client_info.has_bigrequests) + { + if (client_info.input_buffer.size() < 8) + break; + byte_length = 4 * *reinterpret_cast(client_info.input_buffer.data() + 4); + is_big_request = true; + } + if (client_info.input_buffer.size() < byte_length) break; auto packet = BAN::ConstByteSpan(client_info.input_buffer.span()).slice(0, byte_length); + if (is_big_request) + { + auto* input_u32 = reinterpret_cast(client_info.input_buffer.data()); + input_u32[1] = input_u32[0]; + packet = packet.slice(4); + + dprintln("handling big request"); + } if (auto ret = handle_packet(client_info, packet); ret.is_error()) { dwarnln("handle_packet: {}", ret.error()); - close_client(events[i].data.fd); + close_client(client_info.fd); continue; } @@ -2889,7 +3013,7 @@ int main() continue; auto& client_info = thingy.value.get(); - if (client_info.output_buffer.empty()) + if (client_info.output_buffer.empty() || client_info.has_epollout) continue; epoll_event event { .events = EPOLLIN | EPOLLOUT, .data = { .fd = client_info.fd } }; @@ -2899,6 +3023,8 @@ int main() close_client(client_info.fd); goto iterator_invalidated; } + + client_info.has_epollout = true; } } }