From aa70815f5fa60b1203922b584e77bc5f7c33d6fd Mon Sep 17 00:00:00 2001 From: Oskari Alaranta Date: Mon, 1 Jun 2026 22:03:13 +0300 Subject: [PATCH] Implement very basic grab pointer This is definitely not correct with child windows but works with single window apps (minecraft) --- xbanan/Base.cpp | 50 +++++++++++++++++++++++++++++++----- xbanan/Platform.h | 2 ++ xbanan/SDL3/sdl3.cpp | 7 +++++ xbanan/banan-os/banan-os.cpp | 7 +++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/xbanan/Base.cpp b/xbanan/Base.cpp index 9c08ebc..bbe1810 100644 --- a/xbanan/Base.cpp +++ b/xbanan/Base.cpp @@ -28,6 +28,8 @@ CARD16 g_keymask { 0 }; CARD16 g_butmask { 0 }; WINDOW g_focus_window { None }; +static WINDOW s_pointer_grab_wid = None; + static const char* s_opcode_to_name[] { [0] = "none", [X_CreateWindow] = "X_CreateWindow", @@ -1852,13 +1854,37 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) dprintln(" cursor: {}", request.cursor); dprintln(" time: {}", request.time); - xGrabPointerReply reply { - .type = X_Reply, - .status = Success, - .sequenceNumber = client_info.sequence, - .length = 0, - }; - TRY(encode(client_info.output_buffer, reply)); + auto& window = TRY_REF(get_window(client_info, request.grabWindow, X_GrabPointer)); + + if (s_pointer_grab_wid != None && !g_objects.contains(s_pointer_grab_wid)) + s_pointer_grab_wid = None; + + if (s_pointer_grab_wid == None) + { + xGrabPointerReply reply { + .type = X_Reply, + .status = Success, + .sequenceNumber = client_info.sequence, + .length = 0, + }; + TRY(encode(client_info.output_buffer, reply)); + + if (g_platform_ops.set_pointer_grab) + if (auto* platform_window = get_platform_window(window)) + g_platform_ops.set_pointer_grab(platform_window, true); + + s_pointer_grab_wid = request.grabWindow; + } + else + { + xGrabPointerReply reply { + .type = X_Reply, + .status = AlreadyGrabbed, + .sequenceNumber = client_info.sequence, + .length = 0, + }; + TRY(encode(client_info.output_buffer, reply)); + } break; } @@ -1869,6 +1895,16 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) dprintln("UngrabPointer"); dprintln(" time: {}", time); + if (s_pointer_grab_wid == None) + break; + + auto it = g_objects.find(s_pointer_grab_wid); + if (it != g_objects.end() && g_platform_ops.set_pointer_grab) + if (auto* platform_window = get_platform_window(it->value->object.get())) + g_platform_ops.set_pointer_grab(platform_window, false); + + s_pointer_grab_wid = None; + break; } case X_GrabKeyboard: diff --git a/xbanan/Platform.h b/xbanan/Platform.h index e018b1b..ce8813e 100644 --- a/xbanan/Platform.h +++ b/xbanan/Platform.h @@ -63,6 +63,8 @@ struct PlatformOps void (*warp_pointer)(int32_t x, int32_t y, bool relative); /* Get global position of the pointer */ void (*query_pointer)(int32_t* x, int32_t* y); + /* Grab pointer events on window */ + void (*set_pointer_grab)(PlatformWindow*, bool grabbed); /* Create a system cursor */ BAN::ErrorOr> (*create_system_cursor)(SystemCursorType); /* Create cursor from custom bitmap */ diff --git a/xbanan/SDL3/sdl3.cpp b/xbanan/SDL3/sdl3.cpp index 1dfc3fd..1896e4b 100644 --- a/xbanan/SDL3/sdl3.cpp +++ b/xbanan/SDL3/sdl3.cpp @@ -356,6 +356,12 @@ static void sdl3_query_pointer(int32_t* x, int32_t* y) *y = cy; } +static void sdl3_set_pointer_grab(PlatformWindow* window, bool grabbed) +{ + auto& sdl_window = *static_cast(window); + SDL_SetWindowMouseGrab(sdl_window.window, grabbed); +} + static BAN::ErrorOr> sdl3_create_system_cursor(SystemCursorType type) { static constexpr SDL_SystemCursor cursor_type_map[] { @@ -437,6 +443,7 @@ PlatformOps g_platform_ops = { .request_fullscreen = sdl3_request_fullscreen, .warp_pointer = sdl3_warp_pointer, .query_pointer = sdl3_query_pointer, + .set_pointer_grab = sdl3_set_pointer_grab, .create_system_cursor = sdl3_create_system_cursor, .create_bitmap_cursor = sdl3_create_bitmap_cursor, .set_cursor = sdl3_set_cursor, diff --git a/xbanan/banan-os/banan-os.cpp b/xbanan/banan-os/banan-os.cpp index 77d0f15..091726a 100644 --- a/xbanan/banan-os/banan-os.cpp +++ b/xbanan/banan-os/banan-os.cpp @@ -160,6 +160,12 @@ static void bananos_query_pointer(int32_t* x, int32_t* y) (void)y; } +static void bananos_set_pointer_grab(PlatformWindow* window, bool grabbed) +{ + (void)window; + (void)grabbed; +} + static BAN::ErrorOr> bananos_create_system_cursor(SystemCursorType type) { (void)type; @@ -205,6 +211,7 @@ PlatformOps g_platform_ops = { .request_fullscreen = bananos_request_fullscreen, .warp_pointer = bananos_warp_pointer, .query_pointer = nullptr, /* bananos_query_pointer */ + .set_pointer_grab = bananos_set_pointer_grab, .create_system_cursor = bananos_create_system_cursor, .create_bitmap_cursor = bananos_create_bitmap_cursor, .set_cursor = bananos_set_cursor,