Add stuff :)
This commit is contained in:
parent
971038fd4f
commit
301765a5bd
180
xbanan/main.cpp
180
xbanan/main.cpp
|
|
@ -1,3 +1,4 @@
|
|||
#include <BAN/Array.h>
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/Endianness.h>
|
||||
#include <BAN/Optional.h>
|
||||
|
|
@ -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<uint8_t> input_buffer;
|
||||
BAN::Vector<uint8_t> output_buffer;
|
||||
|
|
@ -331,6 +334,17 @@ struct Client
|
|||
BAN::HashMap<CARD32, BAN::UniqPtr<Object>> objects;
|
||||
};
|
||||
|
||||
struct Extension
|
||||
{
|
||||
BAN::StringView name;
|
||||
uint8_t major_opcode;
|
||||
uint8_t opcode_count;
|
||||
BAN::ErrorOr<void> (*handler)(Client&, BAN::ConstByteSpan);
|
||||
};
|
||||
|
||||
uint8_t g_extension_opcode { 128 };
|
||||
BAN::Array<Extension, 128> g_extensions;
|
||||
|
||||
BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
|
||||
BAN::HashMap<ATOM, BAN::String> 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<int32_t>(w - child_window.x, child_window.texture().width() - child_x);
|
||||
const auto child_h = BAN::Math::min<int32_t>(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<BAN::UniqPtr<LibGUI::Window>>())
|
||||
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<Object::Window>();
|
||||
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<BAN::UniqPtr<LibGUI::Window>>()->invalidate(x, y, w, h);
|
||||
window.window.get<BAN::UniqPtr<LibGUI::Window>>()->invalidate(min_x, min_y, max_x - min_x, max_y - min_y);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
||||
|
|
@ -753,10 +775,10 @@ BAN::ErrorOr<void> 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<void> 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<void> 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<void> 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<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||
auto& parent_window = parent_object->object.get<Object::Window>();
|
||||
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<Object>::create(Object {
|
||||
.type = Object::Type::Window,
|
||||
|
|
@ -1637,7 +1671,6 @@ BAN::ErrorOr<void> 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<void> 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<void> 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<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||
const int32_t min_x = BAN::Math::max<int32_t>(0, arc.x);
|
||||
const int32_t min_y = BAN::Math::max<int32_t>(0, arc.y);
|
||||
|
||||
const int32_t max_x = BAN::Math::max<int32_t>(texture.width(), arc.x + arc.width);
|
||||
const int32_t max_y = BAN::Math::max<int32_t>(texture.height(), arc.y + arc.height);
|
||||
const int32_t max_x = BAN::Math::min<int32_t>(texture.width(), arc.x + arc.width);
|
||||
const int32_t max_y = BAN::Math::min<int32_t>(texture.height(), arc.y + arc.height);
|
||||
|
||||
const auto rx = arc.width / 2;
|
||||
const auto ry = arc.height / 2;
|
||||
|
|
@ -2490,6 +2525,16 @@ BAN::ErrorOr<void> 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<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> 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<void> (*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 =
|
||||
|
|
@ -2774,6 +2865,12 @@ int main()
|
|||
|
||||
auto& client_info = epoll_thingy.value.get<Client>();
|
||||
|
||||
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<const uint16_t*>(client_info.input_buffer.data())[1];
|
||||
bool is_big_request = false;
|
||||
uint32_t byte_length = 4 * *reinterpret_cast<const uint16_t*>(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<const uint32_t*>(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<uint32_t*>(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<Client>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue