Add support for global window position

This allows proper TranslateCoords and event root coordinate reporting
This commit is contained in:
2026-06-01 20:39:47 +03:00
parent b41d979dcb
commit 83af554e8c
7 changed files with 120 additions and 50 deletions

View File

@@ -719,6 +719,21 @@ WINDOW find_child_window(WINDOW wid, int32_t& x, int32_t& y)
return wid;
}
xPoint get_window_position(WINDOW wid)
{
xPoint result { .x = 0, .y = 0 };
while (wid != None)
{
const auto& window = g_objects[wid]->object.get<Object::Window>();
result.x += window.x;
result.y += window.y;
wid = window.parent;
}
return result;
}
static PlatformWindow* get_platform_window(const Object::Window& window)
{
if (window.platform_window)
@@ -1239,18 +1254,21 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
}
}
bool window_changed = false;
const int32_t min_x = BAN::Math::min(window.x, new_x);
const int32_t min_y = BAN::Math::min(window.y, new_y);
const int32_t max_x = BAN::Math::max(window.x + window.width, new_x + new_width);
const int32_t max_y = BAN::Math::max(window.y + window.height, new_y + new_height);
bool send_configure = false;
if (new_x != window.x || new_y != window.y)
{
window.x = new_x;
window.y = new_y;
window_changed = true;
if (window.platform_window)
{
if (g_platform_ops.request_reposition)
g_platform_ops.request_reposition(window.platform_window.ptr(), new_x, new_y);
}
else
{
window.x = new_x;
window.y = new_y;
send_configure = true;
}
}
if (new_width != window.width || new_height != window.height)
@@ -1259,22 +1277,20 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
{
if (g_platform_ops.request_resize)
g_platform_ops.request_resize(window.platform_window.ptr(), new_width, new_height);
window_changed = false;
}
else
{
window.width = new_width;
window.height = new_height;
TRY(window.pixels.resize(new_width * new_height));
for (auto& pixel : window.pixels)
pixel = window.background;
window_changed = true;
window.width = new_width;
window.height = new_height;
send_configure = true;
}
}
if (!window_changed)
if (!send_configure)
break;
{
@@ -1950,6 +1966,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
break;
}
const auto [root_x, root_y] = get_window_position(wid);
xQueryPointerReply reply {
.type = X_Reply,
.sameScreen = xTrue,
@@ -1957,8 +1974,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
.length = 0,
.root = g_root.windowId,
.child = static_cast<CARD32>(child_wid),
.rootX = static_cast<INT16>(window.cursor_x), // FIXME
.rootY = static_cast<INT16>(window.cursor_y), // FIXME
.rootX = static_cast<INT16>(root_x + window.cursor_x),
.rootY = static_cast<INT16>(root_y + window.cursor_y),
.winX = static_cast<INT16>(window.cursor_x),
.winY = static_cast<INT16>(window.cursor_y),
.mask = static_cast<KeyButMask>(g_keymask | g_butmask),
@@ -1977,14 +1994,20 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
dprintln(" src_x: {}", request.srcX);
dprintln(" src_y: {}", request.srcY);
(void)TRY_REF(get_window(client_info, request.dstWid, X_TranslateCoords));
(void)TRY_REF(get_window(client_info, request.srcWid, X_TranslateCoords));
const auto [src_x, src_y] = get_window_position(request.srcWid);
const auto [dst_x, dst_y] = get_window_position(request.dstWid);
xTranslateCoordsReply reply {
.type = X_Reply,
.sameScreen = xTrue,
.sequenceNumber = client_info.sequence,
.length = 0,
.child = None,
.dstX = request.srcX,
.dstY = request.srcY,
.child = None, // FIXME
.dstX = static_cast<INT16>(src_x + request.srcX - dst_x),
.dstY = static_cast<INT16>(src_y + request.srcY - dst_y),
};
TRY(encode(client_info.output_buffer, reply));

View File

@@ -14,6 +14,8 @@ BAN::ErrorOr<void> destroy_window(Client& client_info, WINDOW wid);
WINDOW find_child_window(WINDOW wid, int32_t& x, int32_t& y);
xPoint get_window_position(WINDOW wid);
static constexpr uint32_t COLOR_INVISIBLE = 0x69000000;
extern CARD16 g_keymask;

View File

@@ -75,21 +75,8 @@ void on_window_close_event(WINDOW wid)
}
}
void on_window_resize_event(WINDOW wid, uint32_t new_width, uint32_t new_height)
static void send_window_configure(WINDOW wid, Object::Window& window)
{
auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
{
window.width = new_width;
window.height = new_height;
MUST(window.pixels.resize(new_width * new_height));
for (auto& pixel : window.pixels)
pixel = window.background;
}
{
xEvent event = { .u = {
.configureNotify = {
@@ -129,12 +116,42 @@ void on_window_resize_event(WINDOW wid, uint32_t new_width, uint32_t new_height)
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)
{
auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
{
window.width = new_width;
window.height = new_height;
MUST(window.pixels.resize(new_width * new_height));
for (auto& pixel : window.pixels)
pixel = window.background;
}
send_window_configure(wid, window);
send_exposure_recursive(wid);
invalidate_window(wid, 0, 0, window.width, window.height);
}
void on_window_move_event(WINDOW wid, int32_t x, int32_t y)
{
auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
window.x = x;
window.y = y;
send_window_configure(wid, window);
}
void on_window_focus_event(WINDOW wid, bool focused)
{
if (focused)
@@ -219,15 +236,14 @@ void on_window_fullscreen_event(WINDOW wid, bool is_fullscreen)
static void send_key_button_pointer_event(WINDOW root_wid, BYTE detail, uint32_t event_mask, BYTE event_type, KeyButMask state)
{
int32_t root_x, root_y;
int32_t event_x, event_y;
{
auto& object = *g_objects[root_wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
root_x = event_x = window.cursor_x;
root_y = event_y = window.cursor_y;
event_x = window.cursor_x;
event_y = window.cursor_y;
}
const auto child_wid = find_child_window(root_wid, event_x, event_y);
@@ -257,14 +273,15 @@ static void send_key_button_pointer_event(WINDOW root_wid, BYTE detail, uint32_t
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
const auto [root_x, root_y] = get_window_position(wid);
xEvent event { .u = {
.keyButtonPointer = {
.time = static_cast<CARD32>(time(nullptr)),
.root = g_root.windowId,
.event = wid,
.child = static_cast<CARD32>(child_wid == wid ? None : child_wid),
.rootX = static_cast<INT16>(root_x),
.rootY = static_cast<INT16>(root_y),
.rootX = static_cast<INT16>(root_x + event_x),
.rootY = static_cast<INT16>(root_y + event_y),
.eventX = static_cast<INT16>(event_x),
.eventY = static_cast<INT16>(event_y),
.state = state,
@@ -389,14 +406,15 @@ static void send_enter_and_leave_events(WINDOW old_wid, int32_t old_x, int32_t o
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
const auto [root_x, root_y] = get_window_position(wid);
xEvent event { .u = {
.enterLeave = {
.time = static_cast<CARD32>(time(nullptr)),
.root = g_root.windowId,
.event = wid,
.child = first ? static_cast<WINDOW>(None) : old_child_path.back(),
.rootX = static_cast<INT16>(old_x),
.rootY = static_cast<INT16>(old_y),
.rootX = static_cast<INT16>(root_x + old_x),
.rootY = static_cast<INT16>(root_y + old_y),
.eventX = static_cast<INT16>(old_x),
.eventY = static_cast<INT16>(old_y),
.state = static_cast<KeyButMask>(g_keymask | g_butmask),
@@ -429,14 +447,15 @@ static void send_enter_and_leave_events(WINDOW old_wid, int32_t old_x, int32_t o
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
const auto [root_x, root_y] = get_window_position(wid);
xEvent event { .u = {
.enterLeave = {
.time = static_cast<CARD32>(time(nullptr)),
.root = g_root.windowId,
.event = wid,
.child = last ? static_cast<WINDOW>(None) : new_child_path.back(),
.rootX = static_cast<INT16>(new_x),
.rootY = static_cast<INT16>(new_y),
.rootX = static_cast<INT16>(root_x + new_x),
.rootY = static_cast<INT16>(root_y + new_y),
.eventX = static_cast<INT16>(new_x),
.eventY = static_cast<INT16>(new_y),
.state = static_cast<KeyButMask>(g_keymask | g_butmask),

View File

@@ -7,6 +7,7 @@ void unregister_event_fd(int fd);
void on_window_close_event(WINDOW wid);
void on_window_resize_event(WINDOW wid, uint32_t width, uint32_t height);
void on_window_move_event(WINDOW wid, int32_t x, int32_t y);
void on_window_focus_event(WINDOW wid, bool focused);
void on_window_fullscreen_event(WINDOW wid, bool is_fullscreen);
void on_window_leave_event(WINDOW wid);

View File

@@ -55,6 +55,8 @@ struct PlatformOps
void (*invalidate)(PlatformWindow*, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
/* Request resize of a window, can be async */
void (*request_resize)(PlatformWindow*, uint32_t width, uint32_t height);
/* Request window repositioning */
void (*request_reposition)(PlatformWindow*, int32_t x, int32_t y);
/* Request new fullscreen state, can be async */
void (*request_fullscreen)(PlatformWindow*, bool fullscreen);
/* Create a system cursor */

View File

@@ -138,7 +138,11 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(PlatformWin
else
{
auto& sdl_parent = *static_cast<SDLWindow*>(parent);
window->window = SDL_CreatePopupWindow(sdl_parent.window, x, y, width, height, flags | SDL_WINDOW_POPUP_MENU);
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)
@@ -172,6 +176,12 @@ static void sdl3_request_resize(PlatformWindow* window, uint32_t width, uint32_t
SDL_SetWindowSize(sdl_window.window, width, height);
}
static void sdl3_request_reposition(PlatformWindow* window, int32_t x, int32_t y)
{
auto& sdl_window = *static_cast<SDLWindow*>(window);
SDL_SetWindowPosition(sdl_window.window, x, y);
}
static void sdl3_poll_events(void*)
{
uint64_t dummy;
@@ -200,6 +210,10 @@ static void sdl3_poll_events(void*)
on_window_resize_event(window.wid, window.width, window.height);
}
break;
case SDL_EVENT_WINDOW_MOVED:
if (auto it = s_window_map.find(event.motion.windowID); it != s_window_map.end())
on_window_move_event(it->value->wid, event.window.data1, event.window.data2);
break;
case SDL_EVENT_WINDOW_FOCUS_GAINED:
case SDL_EVENT_WINDOW_FOCUS_LOST:
if (auto it = s_window_map.find(event.motion.windowID); it != s_window_map.end())
@@ -398,6 +412,7 @@ PlatformOps g_platform_ops = {
.create_window = sdl3_create_window,
.invalidate = sdl3_invalidate,
.request_resize = sdl3_request_resize,
.request_reposition = sdl3_request_reposition,
.request_fullscreen = sdl3_request_fullscreen,
.create_system_cursor = sdl3_create_system_cursor,
.create_bitmap_cursor = sdl3_create_bitmap_cursor,

View File

@@ -120,6 +120,13 @@ static void bananos_request_resize(PlatformWindow* window, uint32_t width, uint3
banan_window.window->request_resize(width, height);
}
static void bananos_request_reposition(PlatformWindow* window, int32_t x, int32_t y)
{
(void)window;
(void)x;
(void)y;
}
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);
@@ -134,6 +141,12 @@ static void bananos_invalidate(PlatformWindow* window, const uint32_t* pixels, u
banan_window.window->invalidate(x, y, width, height);
}
static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen)
{
auto& banan_window = *static_cast<BananWindow*>(window);
banan_window.window->set_fullscreen(fullscreen);
}
static BAN::ErrorOr<BAN::UniqPtr<PlatformCursor>> bananos_create_system_cursor(SystemCursorType type)
{
(void)type;
@@ -169,18 +182,13 @@ static void bananos_set_cursor(PlatformWindow* window, PlatformCursor* cursor)
}
}
static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen)
{
auto& banan_window = *static_cast<BananWindow*>(window);
banan_window.window->set_fullscreen(fullscreen);
}
PlatformOps g_platform_ops = {
.initialize = bananos_initialize,
.poll_events = bananos_poll_events,
.create_window = bananos_create_window,
.invalidate = bananos_invalidate,
.request_resize = bananos_request_resize,
.request_reposition = bananos_request_reposition,
.request_fullscreen = bananos_request_fullscreen,
.create_system_cursor = bananos_create_system_cursor,
.create_bitmap_cursor = bananos_create_bitmap_cursor,