Compare commits

1 Commits
main ... poll

Author SHA1 Message Date
d0f2b5e8a6 quick hack to replace epoll with poll 2026-06-04 03:32:31 +03:00
11 changed files with 596 additions and 750 deletions

View File

@@ -12,7 +12,6 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <time.h> #include <time.h>
#include <sys/epoll.h>
struct Selection struct Selection
{ {
@@ -159,16 +158,6 @@ static const char* s_opcode_to_name[] {
[X_NoOperation] = "X_NoOperation", [X_NoOperation] = "X_NoOperation",
}; };
void register_display(int32_t x, int32_t y, uint32_t width, uint32_t height)
{
MUST(g_displays.push_back({
.x = x,
.y = y,
.w = width,
.h = height,
}));
}
uint32_t Object::Window::full_event_mask() const uint32_t Object::Window::full_event_mask() const
{ {
uint32_t full_event_mask = 0; uint32_t full_event_mask = 0;
@@ -210,8 +199,8 @@ BAN::ErrorOr<void> setup_client_conneciton(Client& client_info, const xConnClien
xConnSetupPrefix setup_prefix { xConnSetupPrefix setup_prefix {
.success = 1, .success = 1,
.lengthReason = 0, // wtf is this .lengthReason = 0, // wtf is this
.majorVersion = 11, .majorVersion = client_prefix.majorVersion,
.minorVersion = 0, .minorVersion = client_prefix.minorVersion,
.length = 8 + 2*format_count + (8 + 0 + sz_xWindowRoot + sz_xDepth + sz_xVisualType) / 4, .length = 8 + 2*format_count + (8 + 0 + sz_xWindowRoot + sz_xDepth + sz_xVisualType) / 4,
}; };
TRY(encode(client_info.output_buffer, setup_prefix)); TRY(encode(client_info.output_buffer, setup_prefix));
@@ -296,182 +285,154 @@ static BAN::ErrorOr<void> send_visibility_events_recursively(Client& client_info
return {}; return {};
} }
static void invalidate_window_recursive(Object::Window& dst_window, int32_t dst_x, int32_t dst_y, const Object::Window& src_window, int32_t src_x, int32_t src_y, int32_t w, int32_t h) static void invalidate_window_recursive(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h)
{ {
ASSERT(src_window.mapped); ASSERT(wid != g_root.windowId);
if (src_window.c_class == InputOutput) if (x + w <= 0 || y + h <= 0)
{ return;
ASSERT(src_x >= 0); if (w <= 0 || h <= 0)
ASSERT(src_y >= 0); return;
ASSERT(src_x + w <= src_window.width);
ASSERT(src_y + h <= src_window.height);
ASSERT(dst_x + w <= dst_window.width);
ASSERT(dst_y + h <= dst_window.height);
for (int32_t y = 0; y < h; y++) auto& object = *g_objects[wid];
{ ASSERT(object.type == Object::Type::Window);
uint32_t* dst_u32 = &dst_window.double_buffer[(dst_y + y) * dst_window.width + dst_x];
const uint32_t* src_u32 = &src_window. pixels[(src_y + y) * src_window.width + src_x];
for (int32_t x = 0; x < w; x++)
{
if (src_u32[x] != COLOR_INVISIBLE)
dst_u32[x] = 0xFF000000 | src_u32[x];
else if (&dst_window == &src_window)
dst_u32[x] = 0x00000000;
}
}
}
for (auto child_wid : src_window.children) auto& window = object.object.get<Object::Window>();
if (!window.mapped)
return;
for (auto child_wid : window.children)
{ {
const auto& child = g_objects[child_wid]->object.get<Object::Window>(); const auto& child_object = *g_objects[child_wid];
if (!child.mapped) ASSERT(child_object.type == Object::Type::Window);
const auto& child_window = child_object.object.get<Object::Window>();
if (!child_window.mapped)
continue; continue;
const auto diff_x = src_x - child.x; const auto child_x = x - child_window.x;
const auto diff_y = src_y - child.y; const auto child_y = y - child_window.y;
const auto min_x = BAN::Math::max<int32_t>(diff_x, 0); const auto child_w = BAN::Math::min<int32_t>(w - child_window.x, child_window.width - child_x);
const auto min_y = BAN::Math::max<int32_t>(diff_y, 0); const auto child_h = BAN::Math::min<int32_t>(h - child_window.y, child_window.height - child_y);
const auto max_x = BAN::Math::min<int32_t>(diff_x + w, child.width);
const auto max_y = BAN::Math::min<int32_t>(diff_y + h, child.height);
if (max_x <= min_x || max_y <= min_y)
continue;
invalidate_window_recursive( invalidate_window_recursive(
dst_window, child_wid,
dst_x - (diff_x - min_x), child_x, child_y,
dst_y - (diff_y - min_y), child_w, child_h
child,
min_x,
min_y,
max_x - min_x,
max_y - min_y
); );
} }
if (window.platform_window || window.c_class == InputOnly)
return;
auto& parent_object = *g_objects[window.parent];
ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>();
const uint32_t* child_pix = window.pixels.data();
const int32_t child_w = window.width;
const int32_t child_h = window.height;
uint32_t* parent_pix = parent_window.pixels.data();
const int32_t parent_w = parent_window.width;
const int32_t parent_h = parent_window.height;
// FIXME: optimize this
for (int32_t y_off = 0; y_off < h; y_off++)
{
const int32_t child_y = y + y_off;
if (child_y < 0 || child_y >= child_h)
continue;
const int32_t parent_y = window.y + y + y_off;
if (parent_y < 0 || parent_y >= parent_h)
continue;
for (int32_t x_off = 0; x_off < w; x_off++)
{
const int32_t child_x = x + x_off;
if (child_x < 0 || child_x >= child_w)
continue;
const int32_t parent_x = window.x + x + x_off;
if (parent_x < 0 || parent_x >= parent_w)
continue;
const uint32_t color = child_pix[child_y * child_w + child_x];
if (color != COLOR_INVISIBLE)
parent_pix[parent_y * parent_w + parent_x] = color;
}
}
} }
void invalidate_window(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h) void invalidate_window(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h)
{ {
ASSERT(wid != g_root.windowId); ASSERT(wid != g_root.windowId);
int32_t min_x { x }, max_x { x + w };
int32_t min_y { y }, max_y { y + h };
for (;;) for (;;)
{ {
if (wid == g_root.windowId) if (wid == g_root.windowId)
return; return;
const auto& window = g_objects[wid]->object.get<Object::Window>(); auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
if (!window.mapped) if (!window.mapped)
return; return;
if (min_x < 0)
min_x = 0;
if (min_y < 0)
min_y = 0;
if (max_x > window.width)
max_x = window.width;
if (max_y > window.height)
max_y = window.height;
if (max_x <= min_x || max_y <= min_y)
return;
if (window.platform_window) if (window.platform_window)
break; break;
min_x += window.x; x += window.x;
min_y += window.y; y += window.y;
wid = window.parent; wid = window.parent;
} }
auto& window = g_objects[wid]->object.get<Object::Window>(); auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
invalidate_window_recursive( auto& window = object.object.get<Object::Window>();
window, min_x, min_y, ASSERT(window.platform_window);
window, min_x, min_y,
max_x - min_x,
max_y - min_y
);
if (!window.platform_window_invalidated && g_platform_ops.begin_frame) invalidate_window_recursive(wid, x, y, w, h);
g_platform_ops.begin_frame(window.platform_window.ptr());
window.platform_window_invalidated = true;
g_platform_ops.invalidate( const auto min_x = BAN::Math::max<int32_t>(x, 0);
window.platform_window.ptr(), const auto min_y = BAN::Math::max<int32_t>(y, 0);
&window.double_buffer[min_y * window.width + min_x], const auto max_x = BAN::Math::min<int32_t>(x + w, window.width);
window.width * sizeof(uint32_t), const auto max_y = BAN::Math::min<int32_t>(y + h, window.height);
min_x, min_y,
max_x - min_x,
max_y - min_y
);
}
BAN::ErrorOr<void> send_configure_notify(WINDOW wid) if (min_x >= max_x || min_y >= max_y)
return;
uint32_t* pixels = window.pixels.data();
for (auto y = min_y; y < max_y; y++)
{ {
auto& window = g_objects[wid]->object.get<Object::Window>(); for (auto x = min_x; x < max_x; x++)
{ {
xEvent event = { .u = { auto& pixel = pixels[y * window.width + x];
.configureNotify = { if (pixel == COLOR_INVISIBLE)
.event = wid, pixel = 0x00000000;
.window = wid, else
.aboveSibling = xFalse, pixel |= 0xFF000000;
.x = static_cast<INT16>(window.x),
.y = static_cast<INT16>(window.y),
.width = static_cast<CARD16>(window.width),
.height = static_cast<CARD16>(window.height),
.borderWidth = 0,
.override = xFalse,
} }
}};
event.u.u.type = ConfigureNotify;
TRY(window.send_event(event, StructureNotifyMask));
} }
auto& parent_object = *g_objects[window.parent]; g_platform_ops.invalidate(window.platform_window.ptr(), window.pixels.data(), min_x, min_y, max_x - min_x, max_y - min_y);
ASSERT(parent_object.type == Object::Type::Window); }
auto& parent_window = parent_object.object.get<Object::Window>();
void send_exposure_recursive(WINDOW wid)
{ {
xEvent event = { .u = { auto& object = *g_objects[wid];
.configureNotify = { ASSERT(object.type == Object::Type::Window);
.event = window.parent,
.window = wid,
.aboveSibling = xFalse,
.x = static_cast<INT16>(window.x),
.y = static_cast<INT16>(window.y),
.width = static_cast<CARD16>(window.width),
.height = static_cast<CARD16>(window.height),
.borderWidth = 0,
.override = xFalse,
}
}};
event.u.u.type = ConfigureNotify;
TRY(parent_window.send_event(event, SubstructureNotifyMask));
}
return {}; auto& window = object.object.get<Object::Window>();
}
BAN::ErrorOr<void> send_exposure_events_recursive(WINDOW wid)
{
auto& window = g_objects[wid]->object.get<Object::Window>();
if (!window.mapped) if (!window.mapped)
return {}; return;
for (auto child_wid : window.children) for (auto child_wid : window.children)
TRY(send_exposure_events_recursive(child_wid)); send_exposure_recursive(child_wid);
if (window.c_class == InputOnly)
return {};
xEvent event = { .u = { xEvent event = { .u = {
.expose = { .expose = {
@@ -483,32 +444,66 @@ BAN::ErrorOr<void> send_exposure_events_recursive(WINDOW wid)
} }
}}; }};
event.u.u.type = Expose; event.u.u.type = Expose;
TRY(window.send_event(event, ExposureMask)); MUST(window.send_event(event, ExposureMask));
return {};
} }
static WindowType get_plaform_window_info(const Object::Window& window) struct PlatformWindowInfo
{
PlatformWindow* parent;
WindowType type;
};
static PlatformWindowInfo get_plaform_window_info(const Object::Window& window)
{ {
static const CARD32 ATOM = g_atoms_name_to_id["ATOM"_sv]; static const CARD32 ATOM = g_atoms_name_to_id["ATOM"_sv];
static const CARD32 WINDOW = g_atoms_name_to_id["WINDOW"_sv];
static const CARD32 WM_TRANSIENT_FOR = g_atoms_name_to_id["WM_TRANSIENT_FOR"_sv];
static const CARD32 _NET_WM_WINDOW_TYPE = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE"_sv]; static const CARD32 _NET_WM_WINDOW_TYPE = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE"_sv];
static const CARD32 _NET_WM_WINDOW_TYPE_DIALOG = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_DIALOG"_sv]; static const CARD32 _NET_WM_WINDOW_TYPE_DIALOG = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_DIALOG"_sv];
static const CARD32 _NET_WM_WINDOW_TYPE_NORMAL = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_NORMAL"_sv]; static const CARD32 _NET_WM_WINDOW_TYPE_NORMAL = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_NORMAL"_sv];
static const CARD32 _NET_WM_WINDOW_TYPE_SPLASH = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_SPLASH"_sv]; static const CARD32 _NET_WM_WINDOW_TYPE_SPLASH = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_SPLASH"_sv];
static const CARD32 _NET_WM_WINDOW_TYPE_UTILITY = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_UTILITY"_sv];
auto it = window.properties.find(_NET_WM_WINDOW_TYPE); PlatformWindowInfo info {
if (it == window.properties.end()) .parent = nullptr,
return WindowType::Normal; .type = WindowType::Normal,
};
if (auto it = window.properties.find(_NET_WM_WINDOW_TYPE); it != window.properties.end())
{
if (it->value.type != ATOM || it->value.data.size() != sizeof(CARD32)) if (it->value.type != ATOM || it->value.data.size() != sizeof(CARD32))
return WindowType::Normal; goto wm_window_type_done;
const CARD32 type = *reinterpret_cast<const CARD32*>(it->value.data.data()); const CARD32 type = *reinterpret_cast<const CARD32*>(it->value.data.data());
if (type == _NET_WM_WINDOW_TYPE_NORMAL) if (type == _NET_WM_WINDOW_TYPE_NORMAL)
return WindowType::Normal; info.type = WindowType::Normal;
if (type == _NET_WM_WINDOW_TYPE_SPLASH || type == _NET_WM_WINDOW_TYPE_DIALOG) else if (type == _NET_WM_WINDOW_TYPE_SPLASH || type == _NET_WM_WINDOW_TYPE_DIALOG)
return WindowType::Utility; info.type = WindowType::Utility;
return WindowType::Popup; else
info.type = WindowType::Popup;
}
wm_window_type_done:
if (auto it = window.properties.find(WM_TRANSIENT_FOR); it != window.properties.end())
{
if (it->value.type != WINDOW || it->value.data.size() != sizeof(CARD32))
goto transitient_for_done;
const CARD32 wid = *reinterpret_cast<const CARD32*>(it->value.data.data());
auto it2 = g_objects.find(wid);
if (it2 == g_objects.end())
goto transitient_for_done;
if (it2->value->type != Object::Type::Window)
goto transitient_for_done;
// FIXME: support child windows
auto& window = it2->value->object.get<Object::Window>();
info.parent = window.platform_window.ptr();
}
transitient_for_done:
return info;
} }
static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid) static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
@@ -531,13 +526,10 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
if (window.width <= 10 || window.height <= 10) if (window.width <= 10 || window.height <= 10)
return {}; return {};
TRY(window.double_buffer.resize(window.width * window.height)); auto info = get_plaform_window_info(window);
for (auto& pixel : window.double_buffer)
pixel = window.background;
const auto type = get_plaform_window_info(window);
window.platform_window = TRY(g_platform_ops.create_window( window.platform_window = TRY(g_platform_ops.create_window(
type, info.parent,
info.type,
wid, wid,
window.x, window.x,
window.y, window.y,
@@ -581,7 +573,19 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
if (is_visible(window.parent)) if (is_visible(window.parent))
TRY(send_visibility_events_recursively(client_info, wid, true)); TRY(send_visibility_events_recursively(client_info, wid, true));
TRY(send_exposure_events_recursive(wid)); {
xEvent event = { .u = {
.expose = {
.window = wid,
.x = 0,
.y = 0,
.width = static_cast<CARD16>(window.width),
.height = static_cast<CARD16>(window.height),
}
}};
event.u.u.type = Expose;
TRY(window.send_event(event, ExposureMask));
}
return {}; return {};
} }
@@ -597,7 +601,7 @@ static BAN::ErrorOr<void> unmap_window(Client& client_info, WINDOW wid)
window.mapped = false; window.mapped = false;
window.double_buffer.clear(); if (window.platform_window)
window.platform_window.clear(); window.platform_window.clear();
if (is_visible(window.parent)) if (is_visible(window.parent))
@@ -1213,7 +1217,6 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
dprintln("ConfigureWindow"); dprintln("ConfigureWindow");
dprintln(" window: {}", request.window); dprintln(" window: {}", request.window);
dprintln(" mask: {4h}", request.mask);
auto& window = TRY_REF(get_window(client_info, request.window, opcode)); auto& window = TRY_REF(get_window(client_info, request.window, opcode));
@@ -1222,6 +1225,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
uint32_t new_width = window.width; uint32_t new_width = window.width;
uint32_t new_height = window.height; uint32_t new_height = window.height;
dprintln(" mask:");
for (size_t i = 0; i < 7; i++) for (size_t i = 0; i < 7; i++)
{ {
if (!(request.mask & (1 << i))) if (!(request.mask & (1 << i)))
@@ -1233,19 +1237,15 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
{ {
case 0: case 0:
new_x = value; new_x = value;
dprintln(" x: {}", value);
break; break;
case 1: case 1:
new_y = value; new_y = value;
dprintln(" y: {}", value);
break; break;
case 2: case 2:
new_width = value; new_width = value;
dprintln(" w: {}", value);
break; break;
case 3: case 3:
new_height = value; new_height = value;
dprintln(" h: {}", value);
break; break;
default: default:
dprintln(" {4h}: {4h}", 1 << i, value); dprintln(" {4h}: {4h}", 1 << i, value);
@@ -1253,7 +1253,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
} }
} }
bool should_send_configure_notify = false; bool send_configure = false;
if (new_x != window.x || new_y != window.y) if (new_x != window.x || new_y != window.y)
{ {
@@ -1266,7 +1266,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
{ {
window.x = new_x; window.x = new_x;
window.y = new_y; window.y = new_y;
should_send_configure_notify = true; send_configure = true;
} }
} }
@@ -1285,17 +1285,52 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
window.width = new_width; window.width = new_width;
window.height = new_height; window.height = new_height;
should_send_configure_notify = true; send_configure = true;
} }
} }
if (!should_send_configure_notify) if (!send_configure)
break; break;
TRY(send_configure_notify(request.window)); {
xEvent event = { .u = {
.configureNotify = {
.event = request.window,
.window = request.window,
.aboveSibling = xFalse,
.x = static_cast<INT16>(window.x),
.y = static_cast<INT16>(window.y),
.width = static_cast<CARD16>(window.width),
.height = static_cast<CARD16>(window.height),
.borderWidth = 0,
.override = xFalse,
}
}};
event.u.u.type = ConfigureNotify;
TRY(window.send_event(event, StructureNotifyMask));
}
if (is_visible(request.window)) auto& parent_object = *g_objects[window.parent];
TRY(send_exposure_events_recursive(request.window)); ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>();
{
xEvent event = { .u = {
.configureNotify = {
.event = window.parent,
.window = request.window,
.aboveSibling = xFalse,
.x = static_cast<INT16>(window.x),
.y = static_cast<INT16>(window.y),
.width = static_cast<CARD16>(window.width),
.height = static_cast<CARD16>(window.height),
.borderWidth = 0,
.override = xFalse,
}
}};
event.u.u.type = ConfigureNotify;
TRY(parent_window.send_event(event, SubstructureNotifyMask));
}
break; break;
} }
@@ -1327,7 +1362,15 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
CARD16 width, height; CARD16 width, height;
CARD8 depth; CARD8 depth;
if (drawable.type == Object::Type::Window) if (drawable_id == g_root.windowId)
{
width = g_root.pixWidth;
height = g_root.pixHeight;
depth = g_root.rootDepth;
x = 0;
y = 0;
}
else if (drawable.type == Object::Type::Window)
{ {
const auto& window = drawable.object.get<Object::Window>(); const auto& window = drawable.object.get<Object::Window>();
width = window.width; width = window.width;
@@ -1770,9 +1813,9 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
(void)TRY_REF(get_window(client_info, wid, X_SendEvent)); (void)TRY_REF(get_window(client_info, wid, X_SendEvent));
Client* target_client = nullptr; Client* target_client = nullptr;
for (auto& [_, thingy] : g_epoll_thingies) for (auto& [_, thingy] : g_pollables)
{ {
if (thingy.type != EpollThingy::Type::Client) if (thingy.type != Pollable::Type::Client)
continue; continue;
auto& other_client = thingy.value.get<Client>(); auto& other_client = thingy.value.get<Client>();
if (!other_client.objects.contains(wid)) if (!other_client.objects.contains(wid))
@@ -1894,47 +1937,11 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
case X_GrabServer: case X_GrabServer:
{ {
g_server_grabber_fd = client_info.fd; 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:
{ {
g_server_grabber_fd = -1; 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:
@@ -2148,7 +2155,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
// TODO: support invisible background // TODO: support invisible background
uint32_t foreground = 0x000000; uint32_t foreground = 0x000000;
uint32_t background = 0xFFFFFF; uint32_t background = 0x000000;
uint16_t line_width = 0; uint16_t line_width = 0;
uint32_t font = None; uint32_t font = None;
bool graphics_exposures = true; bool graphics_exposures = true;

View File

@@ -6,9 +6,7 @@ BAN::ErrorOr<void> setup_client_conneciton(Client& client_info, const xConnClien
BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet); BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet);
void invalidate_window(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h); void invalidate_window(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h);
void send_exposure_recursive(WINDOW wid);
BAN::ErrorOr<void> send_configure_notify(WINDOW wid);
BAN::ErrorOr<void> send_exposure_events_recursive(WINDOW wid);
void update_cursor(WINDOW wid, int32_t x, int32_t y); void update_cursor(WINDOW wid, int32_t x, int32_t y);
@@ -18,8 +16,7 @@ WINDOW find_child_window(WINDOW wid, int32_t& x, int32_t& y);
xPoint get_window_position(WINDOW wid); xPoint get_window_position(WINDOW wid);
// random number with alpha 0 :D static constexpr uint32_t COLOR_INVISIBLE = 0x69000000;
static constexpr uint32_t COLOR_INVISIBLE = 0x00b205AF;
extern CARD16 g_keymask; extern CARD16 g_keymask;
extern CARD16 g_butmask; extern CARD16 g_butmask;

View File

@@ -66,11 +66,8 @@ struct Object
uint32_t background { 0 }; uint32_t background { 0 };
bool platform_window_invalidated { false };
BAN::UniqPtr<PlatformWindow> platform_window; BAN::UniqPtr<PlatformWindow> platform_window;
BAN::Vector<uint32_t> double_buffer;
BAN::HashMap<Client*, uint32_t> event_masks; BAN::HashMap<Client*, uint32_t> event_masks;
BAN::HashMap<ATOM, Property> properties; BAN::HashMap<ATOM, Property> properties;
@@ -143,7 +140,6 @@ struct Client
}; };
int fd; int fd;
State state; State state;
bool has_epollout { false };
bool has_bigrequests { false }; bool has_bigrequests { false };
CARD16 sequence { 0 }; CARD16 sequence { 0 };
BAN::Optional<uint32_t> pid; BAN::Optional<uint32_t> pid;
@@ -152,7 +148,7 @@ struct Client
BAN::HashSet<CARD32> objects; BAN::HashSet<CARD32> objects;
}; };
struct EpollThingy struct Pollable
{ {
enum class Type enum class Type
{ {
@@ -164,12 +160,6 @@ struct EpollThingy
BAN::Variant<Client, void*> value; BAN::Variant<Client, void*> value;
}; };
struct DisplayInfo
{
int32_t x, y;
uint32_t w, h;
};
extern const xPixmapFormat g_formats[6]; extern const xPixmapFormat g_formats[6];
extern const xDepth g_depth; extern const xDepth g_depth;
extern const xVisualType g_visual; extern const xVisualType g_visual;
@@ -181,11 +171,6 @@ extern BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
extern BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name; extern BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
extern ATOM g_atom_value; extern ATOM g_atom_value;
extern int g_epoll_fd; extern BAN::HashMap<int, Pollable> g_pollables;
extern BAN::HashMap<int, EpollThingy> g_epoll_thingies;
extern int g_server_grabber_fd; extern int g_server_grabber_fd;
extern BAN::Vector<DisplayInfo> g_displays;
extern CARD32 g_next_global_id;

View File

@@ -107,7 +107,7 @@ BAN::ErrorOr<void> poly_line(Client& client_info, BAN::ConstByteSpan packet)
auto request = decode<xPolyLineReq>(packet).value(); auto request = decode<xPolyLineReq>(packet).value();
dprintln("PolyLine"); dprintln("PolyLine");
dprintln(" drawable: {h}", request.drawable); dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc); dprintln(" gc: {}", request.gc);
dprintln(" coordMode: {}", request.coordMode); dprintln(" coordMode: {}", request.coordMode);
@@ -161,7 +161,7 @@ BAN::ErrorOr<void> poly_segment(Client& client_info, BAN::ConstByteSpan packet)
auto request = decode<xPolySegmentReq>(packet).value(); auto request = decode<xPolySegmentReq>(packet).value();
dprintln("PolySegment"); dprintln("PolySegment");
dprintln(" drawable: {h}", request.drawable); dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc); dprintln(" gc: {}", request.gc);
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolySegment)); auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolySegment));
@@ -203,7 +203,7 @@ BAN::ErrorOr<void> fill_poly(Client& client_info, BAN::ConstByteSpan packet)
auto request = decode<xFillPolyReq>(packet).value(); auto request = decode<xFillPolyReq>(packet).value();
dprintln("FillPoly"); dprintln("FillPoly");
dprintln(" drawable: {h}", request.drawable); dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc); dprintln(" gc: {}", request.gc);
dprintln(" shape: {}", request.shape); dprintln(" shape: {}", request.shape);
dprintln(" coordMode: {}", request.coordMode); dprintln(" coordMode: {}", request.coordMode);
@@ -278,7 +278,7 @@ BAN::ErrorOr<void> poly_fill_rectangle(Client& client_info, BAN::ConstByteSpan p
auto request = decode<xPolyFillRectangleReq>(packet).value(); auto request = decode<xPolyFillRectangleReq>(packet).value();
dprintln("PolyFillRectangle"); dprintln("PolyFillRectangle");
dprintln(" drawable: {h}", request.drawable); dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc); dprintln(" gc: {}", request.gc);
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillRectangle)); auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillRectangle));
@@ -320,7 +320,7 @@ BAN::ErrorOr<void> poly_fill_arc(Client& client_info, BAN::ConstByteSpan packet)
auto request = decode<xPolyFillArcReq>(packet).value(); auto request = decode<xPolyFillArcReq>(packet).value();
dprintln("PolyFillArc"); dprintln("PolyFillArc");
dprintln(" drawable: {h}", request.drawable); dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc); dprintln(" gc: {}", request.gc);
auto [out_data_32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillArc)); auto [out_data_32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillArc));

View File

@@ -7,23 +7,18 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <time.h> #include <time.h>
#include <sys/epoll.h>
void register_event_fd(int fd, void* data) void register_event_fd(int fd, void* data)
{ {
epoll_event event { .events = EPOLLIN, .data = { .fd = fd } }; MUST(g_pollables.insert(fd, {
epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &event); .type = Pollable::Type::Event,
MUST(g_epoll_thingies.insert(fd, {
.type = EpollThingy::Type::Event,
.value = data, .value = data,
})); }));
} }
void unregister_event_fd(int fd) void unregister_event_fd(int fd)
{ {
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, nullptr); g_pollables.remove(fd);
g_epoll_thingies.remove(fd);
} }
void on_window_close_event(WINDOW wid) void on_window_close_event(WINDOW wid)
@@ -75,26 +70,69 @@ void on_window_close_event(WINDOW wid)
} }
} }
static void send_window_configure(WINDOW wid, Object::Window& window)
{
{
xEvent event = { .u = {
.configureNotify = {
.event = wid,
.window = wid,
.aboveSibling = xFalse,
.x = static_cast<INT16>(window.x),
.y = static_cast<INT16>(window.y),
.width = static_cast<CARD16>(window.width),
.height = static_cast<CARD16>(window.height),
.borderWidth = 0,
.override = xFalse,
}
}};
event.u.u.type = ConfigureNotify;
MUST(window.send_event(event, StructureNotifyMask));
}
auto& parent_object = *g_objects[window.parent];
ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>();
{
xEvent event = { .u = {
.configureNotify = {
.event = window.parent,
.window = wid,
.aboveSibling = xFalse,
.x = static_cast<INT16>(window.x),
.y = static_cast<INT16>(window.y),
.width = static_cast<CARD16>(window.width),
.height = static_cast<CARD16>(window.height),
.borderWidth = 0,
.override = xFalse,
}
}};
event.u.u.type = ConfigureNotify;
MUST(parent_window.send_event(event, SubstructureNotifyMask));
}
}
void on_window_resize_event(WINDOW wid, uint32_t new_width, uint32_t new_height) void on_window_resize_event(WINDOW wid, uint32_t new_width, uint32_t new_height)
{ {
auto& object = *g_objects[wid]; auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window); ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>(); auto& window = object.object.get<Object::Window>();
{
window.width = new_width; window.width = new_width;
window.height = new_height; window.height = new_height;
MUST(window.pixels.resize(new_width * new_height)); MUST(window.pixels.resize(new_width * new_height));
for (auto& pixel : window.pixels) for (auto& pixel : window.pixels)
pixel = window.background; pixel = window.background;
}
MUST(window.double_buffer.resize(new_width * new_height)); send_window_configure(wid, window);
for (auto& pixel : window.double_buffer)
pixel = window.background;
MUST(send_configure_notify(wid)); send_exposure_recursive(wid);
MUST(send_exposure_events_recursive(wid)); invalidate_window(wid, 0, 0, window.width, window.height);
} }
void on_window_move_event(WINDOW wid, int32_t x, int32_t y) void on_window_move_event(WINDOW wid, int32_t x, int32_t y)
@@ -106,7 +144,7 @@ void on_window_move_event(WINDOW wid, int32_t x, int32_t y)
window.x = x; window.x = x;
window.y = y; window.y = y;
MUST(send_configure_notify(wid)); send_window_configure(wid, window);
} }
void on_window_focus_event(WINDOW wid, bool focused) void on_window_focus_event(WINDOW wid, bool focused)

View File

@@ -6,64 +6,12 @@
#include <time.h> #include <time.h>
struct RANDRDisplay
{
CARD32 crtc_id;
CARD32 output_id;
CARD32 mode_id;
ATOM name_atom;
BAN::String output_str;
BAN::String mode_str;
const DisplayInfo& info;
};
static BAN::Vector<RANDRDisplay> s_randr_displays;
static CARD32 s_timestamp { 0 };
static void initialize_displays()
{
for (size_t i = 0; i < g_displays.size(); i++)
{
auto name = MUST(BAN::String::formatted("B-OUT-{}", i));
const auto name_atom = g_atom_value++;
MUST(g_atoms_name_to_id.insert(name, name_atom));
MUST(g_atoms_id_to_name.insert(name_atom, name));
MUST(s_randr_displays.push_back({
.crtc_id = g_next_global_id++,
.output_id = g_next_global_id++,
.mode_id = g_next_global_id++,
.name_atom = name_atom,
.output_str = BAN::move(name),
.mode_str = MUST(BAN::String::formatted("{}x{}", g_displays[i].w, g_displays[i].h)),
.info = g_displays[i],
}));
}
s_timestamp = time(nullptr);
}
static const RANDRDisplay& find_display_by_output(CARD32 output)
{
for (const auto& display : s_randr_displays)
if (display.output_id == output)
return display;
ASSERT_NOT_REACHED();
}
static const RANDRDisplay& find_display_by_crtc(CARD32 crtc)
{
for (const auto& display : s_randr_displays)
if (display.crtc_id == crtc)
return display;
ASSERT_NOT_REACHED();
}
static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpan packet) static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpan packet)
{ {
if (s_randr_displays.empty()) static CARD32 crtc_id = 5;
initialize_displays(); static CARD32 output_id = 6;
static CARD32 mode_id = 7;
static CARD32 timestamp = time(nullptr);
static xRenderTransform transform { static xRenderTransform transform {
1 << 16, 0, 0, 1 << 16, 0, 0,
@@ -114,8 +62,8 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = 3, .length = 3,
.root = g_root.windowId, .root = g_root.windowId,
.timestamp = s_timestamp, .timestamp = timestamp,
.configTimestamp = s_timestamp, .configTimestamp = timestamp,
.nSizes = 1, .nSizes = 1,
.sizeID = 0, .sizeID = 0,
.rotation = RR_Rotate_0, .rotation = RR_Rotate_0,
@@ -167,45 +115,39 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
dprintln("RRGetScreenResources{}", current ? "Current" : ""); dprintln("RRGetScreenResources{}", current ? "Current" : "");
dprintln(" window: {}", request.window); dprintln(" window: {}", request.window);
size_t mode_name_bytes = 0; const auto mode_name = TRY(BAN::String::formatted("{}x{}", g_root.pixWidth, g_root.pixHeight));
for (const auto& display : s_randr_displays)
mode_name_bytes += display.mode_str.size();
xRRGetScreenResourcesReply reply { xRRGetScreenResourcesReply reply {
.type = X_Reply, .type = X_Reply,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = static_cast<CARD32>(s_randr_displays.size() * (1 + 1 + 8) + (mode_name_bytes + 3) / 4), .length = static_cast<CARD32>(1 + 1 + 8 + (mode_name.size() + 3) / 4),
.timestamp = s_timestamp, .timestamp = timestamp,
.configTimestamp = s_timestamp, .configTimestamp = timestamp,
.nCrtcs = static_cast<CARD16>(s_randr_displays.size()), .nCrtcs = 1,
.nOutputs = static_cast<CARD16>(s_randr_displays.size()), .nOutputs = 1,
.nModes = static_cast<CARD16>(s_randr_displays.size()), .nModes = 1,
.nbytesNames = static_cast<CARD16>(mode_name_bytes), .nbytesNames = static_cast<CARD16>(mode_name.size()),
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
for (const auto& display : s_randr_displays) TRY(encode(client_info.output_buffer, crtc_id));
TRY(encode(client_info.output_buffer, display.crtc_id));
for (const auto& display : s_randr_displays) TRY(encode(client_info.output_buffer, output_id));
TRY(encode(client_info.output_buffer, display.output_id));
for (const auto& display : s_randr_displays) const CARD16 hsync_start = g_root.pixWidth;
{ const CARD16 hsync_end = g_root.pixWidth + 1;
const CARD16 hsync_start = display.info.w; const CARD16 htotal = g_root.pixWidth + 1;
const CARD16 hsync_end = display.info.w + 1;
const CARD16 htotal = display.info.w + 1;
const CARD16 vsync_start = display.info.h; const CARD16 vsync_start = g_root.pixHeight;
const CARD16 vsync_end = display.info.h + 1; const CARD16 vsync_end = g_root.pixHeight + 1;
const CARD16 vtotal = display.info.h + 1; const CARD16 vtotal = g_root.pixHeight + 1;
const CARD32 clock = htotal * vtotal * 60; const CARD32 clock = htotal * vtotal * 60;
xRRModeInfo mode_info { xRRModeInfo mode_info {
.id = display.mode_id, .id = mode_id,
.width = static_cast<CARD16>(display.info.w), .width = g_root.pixWidth,
.height = static_cast<CARD16>(display.info.h), .height = g_root.pixHeight,
.dotClock = clock, .dotClock = clock,
.hSyncStart = hsync_start, .hSyncStart = hsync_start,
.hSyncEnd = hsync_end, .hSyncEnd = hsync_end,
@@ -214,16 +156,14 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
.vSyncStart = vsync_start, .vSyncStart = vsync_start,
.vSyncEnd = vsync_end, .vSyncEnd = vsync_end,
.vTotal = vtotal, .vTotal = vtotal,
.nameLength = static_cast<CARD16>(display.mode_str.size()), .nameLength = static_cast<CARD16>(mode_name.size()),
.modeFlags = RR_HSyncPositive | RR_VSyncPositive, .modeFlags = RR_HSyncPositive | RR_VSyncPositive,
}; };
TRY(encode(client_info.output_buffer, mode_info)); TRY(encode(client_info.output_buffer, mode_info));
}
for (const auto& display : s_randr_displays) TRY(encode(client_info.output_buffer, mode_name));
TRY(encode(client_info.output_buffer, display.mode_str)); for (size_t i = 0; (mode_name.size() + i) % 4; i++)
while (client_info.output_buffer.size() % 4) TRY(encode(client_info.output_buffer, '\0'));
TRY(encode<BYTE>(client_info.output_buffer, 0));
break; break;
} }
@@ -235,31 +175,27 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
dprintln(" output: {}", request.output); dprintln(" output: {}", request.output);
dprintln(" configTimestamp: {}", request.configTimestamp); dprintln(" configTimestamp: {}", request.configTimestamp);
const auto& display = find_display_by_output(request.output);
xRRGetOutputInfoReply reply { xRRGetOutputInfoReply reply {
.type = X_Reply, .type = X_Reply,
.status = Success, .status = Success,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = static_cast<CARD32>(1 + 1 + 1 + (display.output_str.size() + 3) / 4), .length = 1 + 1 + 1 + 2,
.timestamp = s_timestamp, .timestamp = timestamp,
.crtc = display.crtc_id, .crtc = crtc_id,
.mmWidth = display.info.w * 254 / 960, // 96 DPI .mmWidth = g_root.mmWidth,
.mmHeight = display.info.h * 254 / 960, // 96 DPI .mmHeight = g_root.mmHeight,
.connection = RR_Connected, .connection = RR_Connected,
.subpixelOrder = SubPixelUnknown, .subpixelOrder = SubPixelUnknown,
.nCrtcs = 1, .nCrtcs = 1,
.nModes = 1, .nModes = 1,
.nPreferred = 1, .nPreferred = 1,
.nClones = 0, .nClones = 0,
.nameLength = static_cast<CARD16>(display.output_str.size()), .nameLength = 5,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
TRY(encode(client_info.output_buffer, display.crtc_id)); TRY(encode(client_info.output_buffer, crtc_id));
TRY(encode(client_info.output_buffer, display.mode_id)); TRY(encode(client_info.output_buffer, mode_id));
TRY(encode(client_info.output_buffer, display.output_str)); TRY(encode(client_info.output_buffer, "B-OUT\0\0\0"_sv));
while (client_info.output_buffer.size() % 4)
TRY(encode<BYTE>(client_info.output_buffer, 0));
break; break;
} }
@@ -314,27 +250,25 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
dprintln(" crtc: {}", request.crtc); dprintln(" crtc: {}", request.crtc);
dprintln(" configTimestamp: {}", request.configTimestamp); dprintln(" configTimestamp: {}", request.configTimestamp);
const auto& display = find_display_by_crtc(request.crtc);
xRRGetCrtcInfoReply reply { xRRGetCrtcInfoReply reply {
.type = X_Reply, .type = X_Reply,
.status = Success, .status = Success,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = 2, .length = 2,
.timestamp = s_timestamp, .timestamp = timestamp,
.x = static_cast<INT16>(display.info.x), .x = 0,
.y = static_cast<INT16>(display.info.y), .y = 0,
.width = static_cast<CARD16>(display.info.w), .width = g_root.pixWidth,
.height = static_cast<CARD16>(display.info.h), .height = g_root.pixHeight,
.mode = display.mode_id, .mode = mode_id,
.rotation = RR_Rotate_0, .rotation = RR_Rotate_0,
.rotations = RR_Rotate_0, .rotations = RR_Rotate_0,
.nOutput = 1, .nOutput = 1,
.nPossibleOutput = 1, .nPossibleOutput = 1,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
TRY(encode(client_info.output_buffer, display.output_id)); TRY(encode(client_info.output_buffer, output_id));
TRY(encode(client_info.output_buffer, display.output_id)); TRY(encode(client_info.output_buffer, output_id));
break; break;
} }
@@ -351,13 +285,13 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
dprintln(" mode: {}", request.mode); dprintln(" mode: {}", request.mode);
dprintln(" rotation: {}", request.rotation); dprintln(" rotation: {}", request.rotation);
s_timestamp = time(nullptr); timestamp = time(nullptr);
xRRSetCrtcConfigReply reply { xRRSetCrtcConfigReply reply {
.type = X_Reply, .type = X_Reply,
.status = Success, .status = Success,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = 0, .length = 0,
.newTimestamp = s_timestamp, .newTimestamp = timestamp,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
@@ -367,15 +301,15 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
{ {
auto request = decode<xRRGetCrtcGammaSizeReq>(packet).value(); auto request = decode<xRRGetCrtcGammaSizeReq>(packet).value();
dwarnln("RRGetCrtcGammaSize"); dprintln("RRGetCrtcGammaSize");
dwarnln(" crtc: {}", request.crtc); dprintln(" crtc: {}", request.crtc);
xRRGetCrtcGammaSizeReply reply { xRRGetCrtcGammaSizeReply reply {
.type = X_Reply, .type = X_Reply,
.status = Success, .status = Success,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = 0, .length = 0,
.size = 256, .size = 1,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
@@ -392,13 +326,14 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
.type = X_Reply, .type = X_Reply,
.status = Success, .status = Success,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = (6 * 256) / 4, .length = 2,
.size = 256, .size = 1,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
for (size_t i = 0; i < 3; i++) TRY(encode<CARD16>(client_info.output_buffer, 1));
for (size_t j = 0; j < 256; j++) TRY(encode<CARD16>(client_info.output_buffer, 1));
TRY(encode<CARD16>(client_info.output_buffer, j * 65535 / 255)); TRY(encode<CARD16>(client_info.output_buffer, 1));
TRY(encode<CARD16>(client_info.output_buffer, 0));
break; break;
} }
@@ -438,7 +373,7 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
.status = Success, .status = Success,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = 1, .length = 1,
.timestamp = s_timestamp, .timestamp = timestamp,
.left = 0, .left = 0,
.top = 0, .top = 0,
.width = 0, .width = 0,
@@ -467,7 +402,7 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
.type = X_Reply, .type = X_Reply,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = 0, .length = 0,
.output = s_randr_displays.front().output_id, .output = output_id,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
@@ -484,7 +419,7 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
.type = X_Reply, .type = X_Reply,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = 0, .length = 0,
.timestamp = s_timestamp, .timestamp = timestamp,
.nProviders = 0, .nProviders = 0,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
@@ -503,30 +438,28 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
.type = X_Reply, .type = X_Reply,
.status = Success, .status = Success,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = static_cast<CARD32>(6 * s_randr_displays.size() + s_randr_displays.size()), .length = 6 + 1,
.timestamp = s_timestamp, .timestamp = timestamp,
.nmonitors = static_cast<CARD32>(s_randr_displays.size()), .nmonitors = 1,
.noutputs = static_cast<CARD32>(s_randr_displays.size()), .noutputs = 1,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
for (const auto& display : s_randr_displays)
{
xRRMonitorInfo monitor { xRRMonitorInfo monitor {
.name = display.name_atom, .name = None,
.primary = (&display == &s_randr_displays.front()), .primary = xTrue,
.automatic = xTrue, .automatic = xTrue,
.noutput = 1, .noutput = 1,
.x = static_cast<INT16>(display.info.x), .x = 0,
.y = static_cast<INT16>(display.info.y), .y = 0,
.width = static_cast<CARD16>(display.info.w), .width = g_root.pixWidth,
.height = static_cast<CARD16>(display.info.h), .height = g_root.pixHeight,
.widthInMillimeters = display.info.w * 254 / 96, // 96 DPI .widthInMillimeters = g_root.mmWidth,
.heightInMillimeters = display.info.h * 254 / 96, // 96 DPI .heightInMillimeters = g_root.mmHeight,
}; };
TRY(encode(client_info.output_buffer, monitor)); TRY(encode(client_info.output_buffer, monitor));
TRY(encode(client_info.output_buffer, display.output_id));
} TRY(encode(client_info.output_buffer, output_id));
break; break;
} }

View File

@@ -7,12 +7,12 @@
template<typename F> template<typename F>
static BAN::ErrorOr<void> for_each_client(uint32_t target_spec, const F& callback) static BAN::ErrorOr<void> for_each_client(uint32_t target_spec, const F& callback)
{ {
for (const auto& [fd, thingy] : g_epoll_thingies) for (auto [fd, thingy] : g_pollables)
{ {
if (thingy.type != EpollThingy::Type::Client) if (thingy.type != Pollable::Type::Client)
continue; continue;
const auto& client_info = thingy.value.get<Client>(); Client& client_info = thingy.value.get<Client>();
if (target_spec && (target_spec >> 20) != client_info.fd) if (target_spec && (target_spec >> 20) != client_info.fd)
continue; continue;
@@ -61,7 +61,7 @@ BAN::ErrorOr<void> extension_xres(Client& client_info, BAN::ConstByteSpan packet
{ {
auto spec = decode<xXResClientIdSpec>(packet).value(); auto spec = decode<xXResClientIdSpec>(packet).value();
TRY(for_each_client(spec.client, [&](const Client& client_info, uint32_t client_spec) -> BAN::ErrorOr<void> { TRY(for_each_client(spec.client, [&](Client& client_info, uint32_t client_spec) -> BAN::ErrorOr<void> {
if (spec.mask == None || (spec.mask & X_XResClientXIDMask)) if (spec.mask == None || (spec.mask & X_XResClientXIDMask))
{ {
xXResClientIdValue value { xXResClientIdValue value {

View File

@@ -47,18 +47,13 @@ enum class SystemCursorType
struct PlatformOps struct PlatformOps
{ {
/* Do platform initialization */ /* Do platform initialization */
bool (*initialize)(); bool (*initialize)(uint32_t* width, uint32_t* height);
/* Handle pending events */ /* Handle pending events */
void (*poll_events)(void*); void (*poll_events)(void*);
/* Create a window with given size */ /* Create a window with given size */
BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> (*create_window)(WindowType, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height); BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> (*create_window)(PlatformWindow* parent, WindowType, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height);
/* All invalidate calls during one frame happen between calls to begin_frame and end_frame. pixels is in ARGB8888 /* Invaldate part of a window */
* invalidate should update the underlying textures void (*invalidate)(PlatformWindow*, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
* begin_frame should do any necessary preparations to update a frame
* end_frame should flush the updated texturee to the window */
void (*invalidate)(PlatformWindow*, const void* pixels, uint32_t pitch, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
void (*begin_frame)(PlatformWindow*);
void (*end_frame)(PlatformWindow*);
/* Request resize of a window, can be async */ /* Request resize of a window, can be async */
void (*request_resize)(PlatformWindow*, uint32_t width, uint32_t height); void (*request_resize)(PlatformWindow*, uint32_t width, uint32_t height);
/* Request window repositioning */ /* Request window repositioning */
@@ -79,5 +74,3 @@ struct PlatformOps
void (*set_cursor)(PlatformWindow*, PlatformCursor*); void (*set_cursor)(PlatformWindow*, PlatformCursor*);
}; };
extern PlatformOps g_platform_ops; extern PlatformOps g_platform_ops;
void register_display(int32_t x, int32_t y, uint32_t width, uint32_t height);

View File

@@ -69,7 +69,7 @@ static void* sdl3_thread(void*)
static void sdl3_initialize_keymap(); static void sdl3_initialize_keymap();
static bool sdl3_initialize() static bool sdl3_initialize(uint32_t* display_w, uint32_t* display_h)
{ {
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
{ {
@@ -77,16 +77,15 @@ static bool sdl3_initialize()
return false; return false;
} }
*display_w = *display_h = 0;
const SDL_DisplayID* display_ids = SDL_GetDisplays(nullptr); const SDL_DisplayID* display_ids = SDL_GetDisplays(nullptr);
for (int i = 0; display_ids[i]; i++) for (int i = 0; display_ids[i]; i++)
{ {
SDL_Rect rect; SDL_Rect rect;
if (!SDL_GetDisplayBounds(display_ids[i], &rect)) SDL_GetDisplayBounds(display_ids[i], &rect);
{ *display_w = BAN::Math::max<uint32_t>(*display_w, rect.x + rect.w);
dwarnln("Could not display {} bounds: {}", SDL_GetError()); *display_h = BAN::Math::max<uint32_t>(*display_h, rect.y + rect.h);
continue;
}
register_display(rect.x, rect.y, rect.w, rect.h);
} }
sdl3_initialize_keymap(); sdl3_initialize_keymap();
@@ -108,7 +107,7 @@ static bool sdl3_initialize()
return true; return true;
} }
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height) static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height)
{ {
auto window = TRY(BAN::UniqPtr<SDLWindow>::create()); auto window = TRY(BAN::UniqPtr<SDLWindow>::create());
@@ -120,19 +119,29 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(WindowType
switch (type) switch (type)
{ {
case WindowType::Normal: case WindowType::Normal:
case WindowType::Utility:
flags = SDL_WINDOW_RESIZABLE; flags = SDL_WINDOW_RESIZABLE;
break; break;
case WindowType::Utility:
flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY;
break;
case WindowType::Popup: case WindowType::Popup:
flags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_UTILITY; flags = SDL_WINDOW_BORDERLESS;
break; break;
} }
flags |= SDL_WINDOW_TRANSPARENT; if (parent == nullptr || type != WindowType::Popup)
{
if (type != WindowType::Normal)
flags |= SDL_WINDOW_UTILITY;
window->window = SDL_CreateWindow("", width, height, flags); window->window = SDL_CreateWindow("", width, height, flags);
}
else
{
auto& sdl_parent = *static_cast<SDLWindow*>(parent);
int parent_x, parent_y;
SDL_GetWindowPosition(sdl_parent.window, &parent_x, &parent_y);
window->window = SDL_CreatePopupWindow(sdl_parent.window, x - parent_x, y - parent_y, width, height, flags | SDL_WINDOW_POPUP_MENU);
}
if (window->window == nullptr) if (window->window == nullptr)
{ {
@@ -140,9 +149,6 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(WindowType
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EFAULT);
} }
if (x != 0 || y != 0)
SDL_SetWindowPosition(window->window, x, y);
window->renderer = SDL_CreateRenderer(window->window, nullptr); window->renderer = SDL_CreateRenderer(window->window, nullptr);
if (window->renderer == nullptr) if (window->renderer == nullptr)
{ {
@@ -150,8 +156,6 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(WindowType
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EFAULT);
} }
SDL_SetRenderDrawColor(window->renderer, 0, 0, 0, 0);
window->texture = SDL_CreateTexture(window->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); window->texture = SDL_CreateTexture(window->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
if (window->texture == nullptr) if (window->texture == nullptr)
{ {
@@ -287,7 +291,7 @@ static void sdl3_poll_events(void*)
} }
} }
static void sdl3_invalidate(PlatformWindow* window, const void* src_pixels, uint32_t src_pitch, uint32_t x, uint32_t y, uint32_t width, uint32_t height) static void sdl3_invalidate(PlatformWindow* window, const uint32_t* src_pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
{ {
auto& sdl_window = *static_cast<SDLWindow*>(window); auto& sdl_window = *static_cast<SDLWindow*>(window);
@@ -313,19 +317,15 @@ static void sdl3_invalidate(PlatformWindow* window, const void* src_pixels, uint
{ {
memcpy( memcpy(
static_cast<uint8_t*>(dst_pixels) + y_off * dst_pitch, static_cast<uint8_t*>(dst_pixels) + y_off * dst_pitch,
static_cast<const uint8_t*>(src_pixels) + y_off * src_pitch, &src_pixels[(rect.y + y_off) * sdl_window.width + rect.x],
rect.w * sizeof(uint32_t) rect.w * sizeof(uint32_t)
); );
} }
SDL_UnlockTexture(sdl_window.texture); SDL_UnlockTexture(sdl_window.texture);
}
static void sdl3_end_frame(PlatformWindow* window)
{
auto& sdl_window = *static_cast<SDLWindow*>(window);
SDL_RenderClear(sdl_window.renderer); SDL_RenderClear(sdl_window.renderer);
SDL_RenderTexture(sdl_window.renderer, sdl_window.texture, nullptr, nullptr); SDL_RenderTexture(sdl_window.renderer, sdl_window.texture, NULL, NULL);
SDL_RenderPresent(sdl_window.renderer); SDL_RenderPresent(sdl_window.renderer);
} }
@@ -438,8 +438,6 @@ PlatformOps g_platform_ops = {
.poll_events = sdl3_poll_events, .poll_events = sdl3_poll_events,
.create_window = sdl3_create_window, .create_window = sdl3_create_window,
.invalidate = sdl3_invalidate, .invalidate = sdl3_invalidate,
.begin_frame = nullptr,
.end_frame = sdl3_end_frame,
.request_resize = sdl3_request_resize, .request_resize = sdl3_request_resize,
.request_reposition = sdl3_request_reposition, .request_reposition = sdl3_request_reposition,
.request_fullscreen = sdl3_request_fullscreen, .request_fullscreen = sdl3_request_fullscreen,
@@ -507,9 +505,9 @@ static uint32_t sdl3_keycode_to_x_keysym(SDL_Keycode keycode)
{ {
if (iswprint(keycode)) if (iswprint(keycode))
{ {
if (keycode >= 0x100) if ((keycode >= 0x20 && keycode <= 0x7E) || (keycode >= 0xA0 && keycode <= 0xFF))
keycode |= 0x01000000;
return keycode; return keycode;
return 0x01000000 | keycode;
} }
switch (keycode) switch (keycode)

View File

@@ -28,7 +28,7 @@ struct BananCursor final : public PlatformCursor
static BAN::ErrorOr<void> bananos_initialize_keymap(); static BAN::ErrorOr<void> bananos_initialize_keymap();
static bool bananos_initialize() static bool bananos_initialize(uint32_t* display_w, uint32_t* display_h)
{ {
auto attributes = LibGUI::Window::default_attributes; auto attributes = LibGUI::Window::default_attributes;
attributes.shown = false; attributes.shown = false;
@@ -40,7 +40,8 @@ static bool bananos_initialize()
return false; return false;
} }
register_display(0, 0, dummy_or_error.value()->width(), dummy_or_error.value()->height()); *display_w = dummy_or_error.value()->width();
*display_h = dummy_or_error.value()->height();
if (auto ret = bananos_initialize_keymap(); ret.is_error()) if (auto ret = bananos_initialize_keymap(); ret.is_error())
{ {
@@ -57,9 +58,12 @@ static void bananos_poll_events(void* window)
banan_window.window->poll_events(); banan_window.window->poll_events();
} }
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height) static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height)
{ {
(void)parent;
(void)type; (void)type;
(void)x;
(void)y;
auto window = TRY(BAN::UniqPtr<BananWindow>::create()); auto window = TRY(BAN::UniqPtr<BananWindow>::create());
@@ -67,7 +71,6 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(WindowTy
attributes.shown = true; attributes.shown = true;
attributes.title_bar = false; attributes.title_bar = false;
attributes.resizable = true; attributes.resizable = true;
attributes.alpha_channel = true;
auto gui_window = TRY(LibGUI::Window::create(width, height, ""_sv, attributes)); auto gui_window = TRY(LibGUI::Window::create(width, height, ""_sv, attributes));
auto* winp = gui_window.ptr(); auto* winp = gui_window.ptr();
@@ -130,28 +133,18 @@ static void bananos_request_resize(PlatformWindow* window, uint32_t width, uint3
banan_window.window->request_resize(width, height); banan_window.window->request_resize(width, height);
} }
static void bananos_invalidate(PlatformWindow* window, const void* src_pixels, uint32_t src_pitch, uint32_t x, uint32_t y, uint32_t width, uint32_t height) static void bananos_invalidate(PlatformWindow* window, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
{ {
auto& banan_window = *static_cast<BananWindow*>(window); auto& banan_window = *static_cast<BananWindow*>(window);
auto& texture = banan_window.window->texture(); const uint32_t win_width = banan_window.window->width();
void* dst_pixels = &texture.pixels()[y * texture.width() + x];
const uint32_t dst_pitch = texture.width() * sizeof(uint32_t);
auto* out_pixels = banan_window.window->texture().pixels().data();
for (uint32_t y_off = 0; y_off < height; y_off++) for (uint32_t y_off = 0; y_off < height; y_off++)
{ for (uint32_t x_off = 0; x_off < width; x_off++)
memcpy( out_pixels[(y + y_off) * win_width + (x + x_off)] = pixels[(y + y_off) * win_width + (x + x_off)];
static_cast< uint8_t*>(dst_pixels) + y_off * dst_pitch,
static_cast<const uint8_t*>(src_pixels) + y_off * src_pitch,
width * sizeof(uint32_t)
);
}
}
static void bananos_end_frame(PlatformWindow* window) banan_window.window->invalidate(x, y, width, height);
{
auto& banan_window = *static_cast<BananWindow*>(window);
banan_window.window->invalidate();
} }
static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen) static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen)
@@ -194,8 +187,6 @@ PlatformOps g_platform_ops = {
.poll_events = bananos_poll_events, .poll_events = bananos_poll_events,
.create_window = bananos_create_window, .create_window = bananos_create_window,
.invalidate = bananos_invalidate, .invalidate = bananos_invalidate,
.begin_frame = nullptr,
.end_frame = bananos_end_frame,
.request_resize = bananos_request_resize, .request_resize = bananos_request_resize,
.request_reposition = nullptr, .request_reposition = nullptr,
.request_fullscreen = bananos_request_fullscreen, .request_fullscreen = bananos_request_fullscreen,
@@ -210,27 +201,29 @@ PlatformOps g_platform_ops = {
#include <LibInput/KeyboardLayout.h> #include <LibInput/KeyboardLayout.h>
#include <LibInput/KeyEvent.h> #include <LibInput/KeyEvent.h>
static uint32_t bananos_keyevent_to_x_keysym(LibInput::KeyEvent event); static uint32_t bananos_key_to_x_keysym(LibInput::Key, bool upper);
static BAN::ErrorOr<void> bananos_initialize_keymap() static BAN::ErrorOr<void> bananos_initialize_keymap()
{ {
static constexpr uint16_t modifier_map[] {
0,
LibInput::KeyEvent::LShift,
LibInput::KeyEvent::RAlt,
LibInput::KeyEvent::RAlt | LibInput::KeyEvent::LShift,
};
// FIXME: get this from somewhere (gui command? enviroment? tmp file?) // FIXME: get this from somewhere (gui command? enviroment? tmp file?)
const auto keymap_path = "./us.keymap"_sv; const auto keymap_path = "./us.keymap"_sv;
TRY(LibInput::KeyboardLayout::initialize()); TRY(LibInput::KeyboardLayout::initialize());
auto& keyboard_layout = LibInput::KeyboardLayout::get(); auto& keyboard_layout = LibInput::KeyboardLayout::get();
TRY(keyboard_layout.load_from_file(keymap_path)); TRY(keyboard_layout.load_from_file(keymap_path));
for (uint8_t scancode = 0; scancode < g_keymap_size; scancode++) const BAN::Span<const LibInput::Key> banan_keymaps[] {
keyboard_layout.keymap_normal(),
keyboard_layout.keymap_shift(),
keyboard_layout.keymap_altgr(),
keyboard_layout.keymap_altgr(), // add shift+altgr map?
};
for (size_t scancode = 0; scancode < g_keymap_size; scancode++)
for (size_t layer = 0; layer < g_keymap_layers; layer++) for (size_t layer = 0; layer < g_keymap_layers; layer++)
if (const auto event = keyboard_layout.key_event_from_raw({ .modifier = modifier_map[layer], .keycode = scancode }); event.key != LibInput::Key::None) if (const auto banan_key = banan_keymaps[layer][scancode]; banan_key != LibInput::Key::None)
g_keymap[scancode][layer] = bananos_keyevent_to_x_keysym(event); g_keymap[scancode][layer] = bananos_key_to_x_keysym(banan_key, layer % 2);
using LibInput::keycode_normal; using LibInput::keycode_normal;
using LibInput::keycode_numpad; using LibInput::keycode_numpad;
@@ -265,22 +258,22 @@ static BAN::ErrorOr<void> bananos_initialize_keymap()
#include <wctype.h> #include <wctype.h>
static uint32_t bananos_keyevent_to_x_keysym(LibInput::KeyEvent event) static uint32_t bananos_key_to_x_keysym(LibInput::Key key, bool upper)
{ {
using namespace LibInput; using namespace LibInput;
if (const char* utf8 = key_to_utf8(event.key, event.modifier)) if (const char* utf8 = key_to_utf8(key, upper ? KeyEvent::LShift : 0))
{ {
uint32_t codepoint = BAN::UTF8::to_codepoint(utf8); const uint32_t codepoint = BAN::UTF8::to_codepoint(utf8);
if (codepoint != BAN::UTF8::invalid && iswprint(codepoint)) if (codepoint != BAN::UTF8::invalid && iswprint(codepoint))
{ {
if (codepoint >= 0x100) if ((codepoint >= 0x20 && codepoint <= 0x7E) || (codepoint >= 0xA0 && codepoint <= 0xFF))
codepoint |= 0x01000000;
return codepoint; return codepoint;
return 0x01000000 | codepoint;
} }
} }
switch (event.key) switch (key)
{ {
case Key::F1: return XK_F1; case Key::F1: return XK_F1;
case Key::F2: return XK_F2; case Key::F2: return XK_F2;

View File

@@ -5,8 +5,8 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <locale.h> #include <locale.h>
#include <poll.h>
#include <signal.h> #include <signal.h>
#include <sys/epoll.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
@@ -19,8 +19,6 @@
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif
CARD32 g_next_global_id { 1 };
const xPixmapFormat g_formats[6] { const xPixmapFormat g_formats[6] {
{ {
.depth = 1, .depth = 1,
@@ -60,7 +58,7 @@ const xDepth g_depth {
}; };
const xVisualType g_visual { const xVisualType g_visual {
.visualID = g_next_global_id++, .visualID = 1,
.c_class = TrueColor, .c_class = TrueColor,
.bitsPerRGB = 8, .bitsPerRGB = 8,
.colormapEntries = 256, .colormapEntries = 256,
@@ -70,7 +68,7 @@ const xVisualType g_visual {
}; };
xWindowRoot g_root { xWindowRoot g_root {
.windowId = g_next_global_id++, .windowId = 2,
.defaultColormap = 0, .defaultColormap = 0,
.whitePixel = 0xFFFFFF, .whitePixel = 0xFFFFFF,
.blackPixel = 0x000000, .blackPixel = 0x000000,
@@ -84,20 +82,17 @@ xWindowRoot g_root {
.rootVisualID = g_visual.visualID, .rootVisualID = g_visual.visualID,
.backingStore = 0, .backingStore = 0,
.saveUnders = 0, .saveUnders = 0,
.rootDepth = g_depth.depth, .rootDepth = 24,
.nDepths = 1, .nDepths = 1,
}; };
BAN::Vector<DisplayInfo> g_displays;
BAN::HashMap<CARD32, BAN::UniqPtr<Object>> g_objects; BAN::HashMap<CARD32, BAN::UniqPtr<Object>> g_objects;
BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id; BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name; BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
ATOM g_atom_value = XA_LAST_PREDEFINED + 1; ATOM g_atom_value = XA_LAST_PREDEFINED + 1;
int g_epoll_fd; BAN::HashMap<int, Pollable> g_pollables;
BAN::HashMap<int, EpollThingy> g_epoll_thingies;
int g_server_grabber_fd = -1; int g_server_grabber_fd = -1;
@@ -159,22 +154,6 @@ int main()
return 1; return 1;
} }
g_epoll_fd = epoll_create1(0);
if (g_epoll_fd == -1)
{
perror("xbanan: epoll_create1");
return 1;
}
{
epoll_event event { .events = EPOLLIN, .data = { .ptr = nullptr } };
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, server_sock, &event) == -1)
{
perror("xbanan: epoll_ctl");
return 1;
}
}
#define APPEND_ATOM(name) do { \ #define APPEND_ATOM(name) do { \
MUST(g_atoms_id_to_name.insert(name, #name##_sv.substring(3))); \ MUST(g_atoms_id_to_name.insert(name, #name##_sv.substring(3))); \
MUST(g_atoms_name_to_id.insert(#name##_sv.substring(3), name)); \ MUST(g_atoms_name_to_id.insert(#name##_sv.substring(3), name)); \
@@ -265,62 +244,22 @@ int main()
APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE_UTILITY); APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE_UTILITY);
#undef APPEND_ATOM_CUSTOM #undef APPEND_ATOM_CUSTOM
if (!g_platform_ops.initialize()) uint32_t display_w, display_h;
if (!g_platform_ops.initialize(&display_w, &display_h))
return 1; return 1;
g_root.pixWidth = display_w;
if (g_displays.empty()) g_root.pixHeight = display_h;
{ g_root.mmWidth = static_cast<CARD16>(display_w * 254 / 960); // 96 DPI
dwarnln("No displays windows initilized"); g_root.mmHeight = static_cast<CARD16>(display_h * 254 / 960); // 96 DPI
return 1;
}
int32_t display_min_x { INT32_MAX }, display_min_y { INT32_MAX };
int32_t display_max_x { INT32_MIN }, display_max_y { INT32_MIN };
for (const auto& display : g_displays)
{
display_min_x = BAN::Math::min<int32_t>(display_min_x, display.x);
display_min_y = BAN::Math::min<int32_t>(display_min_y, display.y);
display_max_x = BAN::Math::max<int32_t>(display_max_x, display.x + display.w);
display_max_y = BAN::Math::max<int32_t>(display_max_y, display.y + display.h);
}
g_root.pixWidth = display_max_x - display_min_x;
g_root.pixHeight = display_max_y - display_min_y;
g_root.mmWidth = g_root.pixWidth * 254 / 960; // 96 DPI
g_root.mmHeight = g_root.pixHeight * 254 / 960; // 96 DPI
Client dummy_owner;
MUST(g_objects.insert(g_root.windowId, MUST(BAN::UniqPtr<Object>::create(Object {
.type = Object::Type::Window,
.object = Object::Window {
.owner = dummy_owner,
.depth = g_root.rootDepth,
.x = display_min_x,
.y = display_min_y,
.parent = None,
.cursor = None,
.c_class = InputOutput,
.width = g_root.pixWidth,
.height = g_root.pixHeight,
.background = None,
}
}))));
MUST(g_objects.insert(g_visual.visualID,
MUST(BAN::UniqPtr<Object>::create(Object {
.type = Object::Type::Visual,
}))
));
printf("xbanan started\n"); printf("xbanan started\n");
const auto close_client = const auto close_client =
[](int client_fd) [](int client_fd)
{ {
auto& epoll_thingy = g_epoll_thingies[client_fd]; auto& pollable = g_pollables[client_fd];
ASSERT(epoll_thingy.type == EpollThingy::Type::Client); ASSERT(pollable.type == Pollable::Type::Client);
auto& client_info = epoll_thingy.value.get<Client>(); auto& client_info = pollable.value.get<Client>();
dprintln("client {} disconnected", client_fd); dprintln("client {} disconnected", client_fd);
@@ -372,39 +311,68 @@ int main()
g_objects.remove(it); g_objects.remove(it);
} }
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr); g_pollables.remove(client_fd);
g_epoll_thingies.remove(client_fd);
close(client_fd); close(client_fd);
if (client_fd == g_server_grabber_fd) if (g_server_grabber_fd == client_fd)
{
g_server_grabber_fd = -1; 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);
}
}
}; };
Client dummy_client {};
MUST(g_objects.insert(g_root.windowId,
MUST(BAN::UniqPtr<Object>::create(Object {
.type = Object::Type::Window,
.object = Object::Window {
.owner = dummy_client,
.mapped = true,
.depth = g_root.rootDepth,
.parent = None,
.c_class = InputOutput,
.width = g_root.pixWidth,
.height = g_root.pixHeight,
}
}))
));
MUST(g_objects.insert(g_visual.visualID,
MUST(BAN::UniqPtr<Object>::create(Object {
.type = Object::Type::Visual,
}))
));
for (;;) for (;;)
{ {
epoll_event events[16]; BAN::Vector<pollfd> pollfds;
const int event_count = epoll_wait(g_epoll_fd, events, 16, -1); MUST(pollfds.reserve(g_pollables.size() + 1));
MUST(pollfds.push_back({
for (int i = 0; i < event_count; i++) .fd = server_sock,
.events = POLLIN,
.revents = 0,
}));
for (auto& [fd, pollable] : g_pollables)
{ {
if (events[i].data.ptr == nullptr) short events = 0;
if (g_server_grabber_fd == -1 || g_server_grabber_fd == fd)
events |= POLLIN;
if (pollable.type == Pollable::Type::Client && !pollable.value.get<Client>().output_buffer.empty())
events |= POLLOUT;
if (events == 0)
continue;
MUST(pollfds.push_back(pollfd {
.fd = fd,
.events = events,
.revents = 0,
}));
}
const int event_count = poll(pollfds.data(), pollfds.size(), -1);
for (const auto& pollfd : pollfds)
{
if (pollfd.revents == 0)
continue;
if (pollfd.fd == server_sock)
{ {
int client_sock = accept(server_sock, nullptr, nullptr); int client_sock = accept(server_sock, nullptr, nullptr);
if (client_sock == -1) if (client_sock == -1)
@@ -422,8 +390,8 @@ int main()
client_pid = client_cred.pid; client_pid = client_cred.pid;
#endif #endif
MUST(g_epoll_thingies.insert(client_sock, { MUST(g_pollables.insert(client_sock, {
.type = EpollThingy::Type::Client, .type = Pollable::Type::Client,
.value = Client { .value = Client {
.fd = client_sock, .fd = client_sock,
.state = Client::State::ConnectionSetup, .state = Client::State::ConnectionSetup,
@@ -431,44 +399,32 @@ int main()
} }
})); }));
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");
close(client_sock);
continue;
}
dprintln("client {} connected", client_sock); dprintln("client {} connected", client_sock);
continue; continue;
} }
auto it = g_epoll_thingies.find(events[i].data.fd); auto it = g_pollables.find(pollfd.fd);
if (it == g_epoll_thingies.end()) if (it == g_pollables.end())
continue; continue;
auto& epoll_thingy = it->value; auto& pollable = it->value;
if (epoll_thingy.type == EpollThingy::Type::Event) if (pollable.type == Pollable::Type::Event)
{ {
g_platform_ops.poll_events(epoll_thingy.value.get<void*>()); g_platform_ops.poll_events(pollable.value.get<void*>());
continue; continue;
} }
ASSERT(epoll_thingy.type == EpollThingy::Type::Client); ASSERT(pollable.type == Pollable::Type::Client);
auto& client_info = epoll_thingy.value.get<Client>(); auto& client_info = pollable.value.get<Client>();
if (events[i].events & EPOLLHUP) if (pollfd.revents & POLLHUP)
{ {
close_client(client_info.fd); close_client(client_info.fd);
continue; continue;
} }
if (events[i].events & EPOLLOUT) if (pollfd.revents & POLLOUT)
{ {
const ssize_t nsend = send( const ssize_t nsend = send(
client_info.fd, client_info.fd,
@@ -495,28 +451,11 @@ int main()
); );
MUST(client_info.output_buffer.resize(client_info.output_buffer.size() - nsend)); MUST(client_info.output_buffer.resize(client_info.output_buffer.size() - nsend));
if (client_info.output_buffer.empty())
{
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");
close_client(client_info.fd);
continue;
}
client_info.has_epollout = false;
}
send_done: send_done:
(void)0; (void)0;
} }
if (!(events[i].events & EPOLLIN)) if (!(pollfd.revents & POLLIN))
continue; continue;
if (g_server_grabber_fd != -1 && g_server_grabber_fd != client_info.fd) if (g_server_grabber_fd != -1 && g_server_grabber_fd != client_info.fd)
@@ -628,42 +567,5 @@ int main()
} }
} }
} }
for (auto& [_, object] : g_objects)
{
if (object->type != Object::Type::Window)
continue;
auto& window = object->object.get<Object::Window>();
if (!window.platform_window_invalidated)
continue;
if (g_platform_ops.end_frame)
g_platform_ops.end_frame(window.platform_window.ptr());
window.platform_window_invalidated = false;
}
iterator_invalidated:
for (auto& [_, thingy] : g_epoll_thingies)
{
if (thingy.type != EpollThingy::Type::Client)
continue;
auto& client_info = thingy.value.get<Client>();
if (client_info.output_buffer.empty() || client_info.has_epollout)
continue;
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");
close_client(client_info.fd);
goto iterator_invalidated;
}
client_info.has_epollout = true;
}
} }
} }