diff --git a/xbanan/Base.cpp b/xbanan/Base.cpp index 8885e8e..8b6e7f3 100644 --- a/xbanan/Base.cpp +++ b/xbanan/Base.cpp @@ -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(); + 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 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 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 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 handle_packet(Client& client_info, BAN::ConstByteSpan packet) .length = 0, .root = g_root.windowId, .child = static_cast(child_wid), - .rootX = static_cast(window.cursor_x), // FIXME - .rootY = static_cast(window.cursor_y), // FIXME + .rootX = static_cast(root_x + window.cursor_x), + .rootY = static_cast(root_y + window.cursor_y), .winX = static_cast(window.cursor_x), .winY = static_cast(window.cursor_y), .mask = static_cast(g_keymask | g_butmask), @@ -1977,14 +1994,20 @@ BAN::ErrorOr 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(src_x + request.srcX - dst_x), + .dstY = static_cast(src_y + request.srcY - dst_y), }; TRY(encode(client_info.output_buffer, reply)); diff --git a/xbanan/Base.h b/xbanan/Base.h index 10d060d..6765548 100644 --- a/xbanan/Base.h +++ b/xbanan/Base.h @@ -14,6 +14,8 @@ BAN::ErrorOr 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; diff --git a/xbanan/Events.cpp b/xbanan/Events.cpp index 74595c0..4dad86d 100644 --- a/xbanan/Events.cpp +++ b/xbanan/Events.cpp @@ -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(); - - { - 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(); + + { + 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(); + + 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(); - 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(); + const auto [root_x, root_y] = get_window_position(wid); xEvent event { .u = { .keyButtonPointer = { .time = static_cast(time(nullptr)), .root = g_root.windowId, .event = wid, .child = static_cast(child_wid == wid ? None : child_wid), - .rootX = static_cast(root_x), - .rootY = static_cast(root_y), + .rootX = static_cast(root_x + event_x), + .rootY = static_cast(root_y + event_y), .eventX = static_cast(event_x), .eventY = static_cast(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(); + const auto [root_x, root_y] = get_window_position(wid); xEvent event { .u = { .enterLeave = { .time = static_cast(time(nullptr)), .root = g_root.windowId, .event = wid, .child = first ? static_cast(None) : old_child_path.back(), - .rootX = static_cast(old_x), - .rootY = static_cast(old_y), + .rootX = static_cast(root_x + old_x), + .rootY = static_cast(root_y + old_y), .eventX = static_cast(old_x), .eventY = static_cast(old_y), .state = static_cast(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(); + const auto [root_x, root_y] = get_window_position(wid); xEvent event { .u = { .enterLeave = { .time = static_cast(time(nullptr)), .root = g_root.windowId, .event = wid, .child = last ? static_cast(None) : new_child_path.back(), - .rootX = static_cast(new_x), - .rootY = static_cast(new_y), + .rootX = static_cast(root_x + new_x), + .rootY = static_cast(root_y + new_y), .eventX = static_cast(new_x), .eventY = static_cast(new_y), .state = static_cast(g_keymask | g_butmask), diff --git a/xbanan/Events.h b/xbanan/Events.h index 1ae0a77..62c3f66 100644 --- a/xbanan/Events.h +++ b/xbanan/Events.h @@ -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); diff --git a/xbanan/Platform.h b/xbanan/Platform.h index 2297bfd..b3e1ad2 100644 --- a/xbanan/Platform.h +++ b/xbanan/Platform.h @@ -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 */ diff --git a/xbanan/SDL3/sdl3.cpp b/xbanan/SDL3/sdl3.cpp index 5db5605..ff2a10c 100644 --- a/xbanan/SDL3/sdl3.cpp +++ b/xbanan/SDL3/sdl3.cpp @@ -138,7 +138,11 @@ static BAN::ErrorOr> sdl3_create_window(PlatformWin else { auto& sdl_parent = *static_cast(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(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, diff --git a/xbanan/banan-os/banan-os.cpp b/xbanan/banan-os/banan-os.cpp index 0afc004..042974e 100644 --- a/xbanan/banan-os/banan-os.cpp +++ b/xbanan/banan-os/banan-os.cpp @@ -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(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(window); + banan_window.window->set_fullscreen(fullscreen); +} + static BAN::ErrorOr> 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(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,