Add support for system cursors

When a client creates a cursor from the default cursor font, we try to
detect which cursor it is and create a native system cursor based on
that.
This commit is contained in:
2026-05-30 04:21:41 +03:00
parent 7fe5b0174f
commit f6a87f064f
11 changed files with 336 additions and 110 deletions

View File

@@ -711,6 +711,46 @@ WINDOW find_child_window(WINDOW wid, int32_t& x, int32_t& y)
return wid;
}
static PlatformWindow* get_platform_window(const Object::Window& window)
{
if (window.platform_window)
return const_cast<PlatformWindow*>(window.platform_window.ptr());
if (window.parent == None)
return nullptr;
auto& object = *g_objects[window.parent];
ASSERT(object.type == Object::Type::Window);
return get_platform_window(object.object.get<Object::Window>());
}
void update_cursor(WINDOW wid, int32_t x, int32_t y)
{
if (g_platform_ops.set_cursor == nullptr)
return;
wid = find_child_window(wid, x, y);
if (wid == None)
return;
const CURSOR cid = [&wid]() -> CURSOR {
for (;;)
{
const auto& window = g_objects[wid]->object.get<Object::Window>();
if (window.cursor != None || window.parent == None)
return window.cursor;
wid = window.parent;
}
}();
static CURSOR active_cid = None;
if (cid == active_cid)
return;
const auto& window = g_objects[wid]->object.get<Object::Window>();
g_platform_ops.set_cursor(get_platform_window(window), get_cursor_safe(cid));
active_cid = cid;
}
static void on_root_client_message(const xEvent& event)
{
@@ -930,7 +970,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
auto& window = TRY_REF(get_window(client_info, request.window, opcode));
CURSOR cursor_id = None;
BAN::Optional<CURSOR> cursor_id = None;
BAN::Optional<uint32_t> background;
for (size_t i = 0; i < 32; i++)
@@ -967,25 +1007,11 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
}
}
if (window.cursor != cursor_id)
if (cursor_id.has_value())
{
// FIXME: show cursor if wid is hovered
if (window.platform_window)
{
if (g_platform_ops.set_cursor)
{
const auto& cursor = get_cursor_safe(cursor_id);
g_platform_ops.set_cursor(
window.platform_window.ptr(),
cursor.pixels.data(),
cursor.width, cursor.height,
cursor.origin_x, cursor.origin_y
);
}
}
window.cursor = cursor_id;
window.cursor = cursor_id.value();
if (window.hovered)
update_cursor(request.window, window.cursor_x, window.cursor_y);
}
if (background.has_value())
@@ -2613,17 +2639,12 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
static_cast<uint32_t>(request.backBlue >> 8) << 8 |
static_cast<uint32_t>(request.backGreen >> 8) << 0;
Object::Cursor cursor {
.width = source.width,
.height = source.height,
.origin_x = request.x,
.origin_y = request.y,
};
TRY(cursor.pixels.resize(cursor.width * cursor.height));
BAN::Vector<uint32_t> pixels;
TRY(pixels.resize(source.width * source.height));
auto* source_data_u32 = reinterpret_cast<const uint32_t*>(source.data.data());
for (size_t i = 0; i < cursor.width * cursor.height; i++)
cursor.pixels[i] = 0xFF000000 | (source_data_u32[i] ? foreground : background);
for (size_t i = 0; i < source.width * source.height; i++)
pixels[i] = 0xFF000000 | (source_data_u32[i] ? foreground : background);
if (request.mask != None)
{
@@ -2633,9 +2654,17 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
ASSERT(mask.height == source.height);
auto* mask_data_u32 = reinterpret_cast<const uint32_t*>(mask.data.data());
for (size_t i = 0; i < cursor.width * cursor.height; i++)
for (size_t i = 0; i < source.width * source.height; i++)
if (!mask_data_u32[i])
cursor.pixels[i] = 0;
pixels[i] = 0;
}
BAN::UniqPtr<PlatformCursor> cursor;
if (g_platform_ops.create_bitmap_cursor)
{
auto cursor_or_error = g_platform_ops.create_bitmap_cursor(pixels.data(), source.width, source.height, request.x, request.y);
if (!cursor_or_error.is_error())
cursor = cursor_or_error.release_value();
}
TRY(client_info.objects.insert(request.cid));