Add very basic X-Resource extension

This only supports XResQueryVersion and XResQueryClientIds but it is
enough to get steam running
This commit is contained in:
2026-06-04 01:29:32 +03:00
parent e4bbc31c7b
commit 421e0a6897
2 changed files with 120 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ set(XBANAN_SOURCES
Extensions.cpp
ExtBigReg.cpp
ExtRANDR.cpp
ExtXRes.cpp
Font.cpp
Image.cpp
Keymap.cpp

119
xbanan/ExtXRes.cpp Normal file
View File

@@ -0,0 +1,119 @@
#include "Extensions.h"
#include "Utils.h"
#include <X11/X.h>
#include <X11/extensions/XResproto.h>
template<typename F>
static BAN::ErrorOr<void> for_each_client(uint32_t target_spec, const F& callback)
{
for (auto [fd, thingy] : g_epoll_thingies)
{
if (thingy.type != EpollThingy::Type::Client)
continue;
Client& client_info = thingy.value.get<Client>();
if (target_spec && (target_spec >> 20) != client_info.fd)
continue;
TRY(callback(client_info, target_spec ? target_spec : (client_info.fd << 20)));
}
return {};
}
BAN::ErrorOr<void> extension_xres(Client& client_info, BAN::ConstByteSpan packet)
{
const uint8_t major_opcode = packet[0];
const uint8_t minor_opcode = packet[1];
switch (minor_opcode)
{
case X_XResQueryVersion:
{
auto request = decode<xXResQueryVersionReq>(packet).value();
dprintln("XResQueryVersion");
dprintln(" clientMajor: {}", reqType.client_major);
dprintln(" clientMinor: {}", reqType.client_minor);
xXResQueryVersionReply reply {
.type = X_Reply,
.sequenceNumber = client_info.sequence,
.length = 0,
.server_major = 1,
.server_minor = 2,
};
TRY(encode(client_info.output_buffer, reply));
break;
}
case X_XResQueryClientIds:
{
auto request = decode<xXResQueryClientIdsReq>(packet).value();
dprintln("XResQueryClientIds");
dprintln(" numSpecs: {}", request.numSpecs);
uint32_t num_ids { 0 };
BAN::Vector<uint8_t> query_result;
for (size_t i = 0; i < request.numSpecs; i++)
{
auto spec = decode<xXResClientIdSpec>(packet).value();
TRY(for_each_client(spec.client, [&](Client& client_info, uint32_t client_spec) -> BAN::ErrorOr<void> {
if (spec.mask == None || (spec.mask & X_XResClientXIDMask))
{
xXResClientIdValue value {
.spec = {
.client = client_spec,
.mask = X_XResClientXIDMask,
},
.length = 0,
};
TRY(encode(query_result, value));
num_ids++;
}
if ((spec.mask == None || (spec.mask & X_XResLocalClientPIDMask)) && client_info.pid.has_value())
{
xXResClientIdValue value {
.spec = {
.client = client_spec,
.mask = X_XResLocalClientPIDMask,
},
.length = 4,
};
TRY(encode(query_result, value));
TRY(encode(query_result, client_info.pid.value()));
num_ids++;
}
return {};
}));
}
xXResQueryClientIdsReply reply {
.type = X_Reply,
.sequenceNumber = client_info.sequence,
.length = static_cast<uint32_t>(query_result.size() / 4),
.numIds = num_ids,
};
TRY(encode(client_info.output_buffer, reply));
TRY(encode(client_info.output_buffer, query_result));
break;
}
default:
dwarnln("unsupported opcode XRes minor opcode {}", minor_opcode);
break;
}
return {};
}
static struct XResInstaller
{
XResInstaller()
{
install_extension(XRES_NAME, 6, 0, extension_xres);
}
} installer;